001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.test.runners;
016    
017    import com.liferay.portal.kernel.util.ReflectionUtil;
018    import com.liferay.portal.log.CaptureAppender;
019    import com.liferay.portal.test.log.ConcurrentAssertUtil;
020    import com.liferay.portal.test.log.ExpectedLogsUtil;
021    import com.liferay.portal.test.log.LogAssertionUtil;
022    
023    import java.lang.reflect.Field;
024    import java.lang.reflect.Method;
025    
026    import java.util.Collections;
027    import java.util.List;
028    
029    import org.junit.rules.TestRule;
030    import org.junit.runner.Description;
031    import org.junit.runner.notification.RunNotifier;
032    import org.junit.runners.model.FrameworkMethod;
033    import org.junit.runners.model.InitializationError;
034    import org.junit.runners.model.Statement;
035    
036    /**
037     * @author Miguel Pastor
038     * @author Carlos Sierra
039     * @author Shuyang Zhou
040     */
041    public class LiferayIntegrationJUnitTestRunner
042            extends CustomizableSpringContextJUnitTestRunner {
043    
044            public LiferayIntegrationJUnitTestRunner(Class<?> clazz)
045                    throws InitializationError {
046    
047                    super(clazz);
048            }
049    
050            @Override
051            public void afterApplicationContextInit() {
052            }
053    
054            @Override
055            public List<String> getExtraConfigLocations() {
056                    return Collections.emptyList();
057            }
058    
059            protected static Statement logAssertStatement(
060                    final Statement statement, final Method method) {
061    
062                    return new Statement() {
063    
064                            @Override
065                            public void evaluate() throws Throwable {
066                                    ConcurrentAssertUtil.startAssert();
067    
068                                    CaptureAppender captureAppender = ExpectedLogsUtil.startAssert(
069                                            method);
070    
071                                    try {
072                                            LogAssertionUtil.enableLogAssertion();
073    
074                                            statement.evaluate();
075                                    }
076                                    finally {
077                                            ExpectedLogsUtil.endAssert(method, captureAppender);
078    
079                                            ConcurrentAssertUtil.endAssert();
080                                    }
081                            }
082    
083                    };
084            }
085    
086            @Override
087            protected Statement classBlock(RunNotifier notifier) {
088                    final Statement statement = super.classBlock(notifier);
089    
090                    return new Statement() {
091    
092                            @Override
093                            public void evaluate() throws Throwable {
094                                    Thread currentThread = Thread.currentThread();
095    
096                                    Object inheritableThreadLocals =
097                                            _INHERITABLE_THREAD_LOCALS_FIELD.get(currentThread);
098    
099                                    if (inheritableThreadLocals != null) {
100                                            _INHERITABLE_THREAD_LOCALS_FIELD.set(
101                                                    currentThread,
102                                                    _CREATE_INHERITED_MAP_METHOD.invoke(
103                                                            null, inheritableThreadLocals));
104                                    }
105    
106                                    Object threadLocals = _THREAD_LOCALS_FIELD.get(currentThread);
107    
108                                    _THREAD_LOCALS_FIELD.set(currentThread, null);
109    
110                                    try {
111                                            statement.evaluate();
112                                    }
113                                    finally {
114                                            _INHERITABLE_THREAD_LOCALS_FIELD.set(
115                                                    currentThread, inheritableThreadLocals);
116                                            _THREAD_LOCALS_FIELD.set(currentThread, threadLocals);
117                                    }
118                            }
119    
120                    };
121            }
122    
123            @Override
124            protected List<TestRule> classRules() {
125                    List<TestRule> testRules = super.classRules();
126    
127                    testRules.add(_testRule);
128    
129                    return testRules;
130            }
131    
132            @Override
133            protected Statement methodBlock(FrameworkMethod frameworkMethod) {
134                    return logAssertStatement(
135                            super.methodBlock(frameworkMethod), frameworkMethod.getMethod());
136            }
137    
138            private static final Method _CREATE_INHERITED_MAP_METHOD;
139    
140            private static final Field _INHERITABLE_THREAD_LOCALS_FIELD;
141    
142            private static final Class<?> _THREAD_LOCAL_MAP_CLASS;
143    
144            private static final Field _THREAD_LOCALS_FIELD;
145    
146            static {
147                    try {
148                            _THREAD_LOCAL_MAP_CLASS = Class.forName(
149                                    ThreadLocal.class.getName().concat("$ThreadLocalMap"));
150    
151                            _CREATE_INHERITED_MAP_METHOD = ReflectionUtil.getDeclaredMethod(
152                                    ThreadLocal.class, "createInheritedMap",
153                                    _THREAD_LOCAL_MAP_CLASS);
154    
155                            _INHERITABLE_THREAD_LOCALS_FIELD = ReflectionUtil.getDeclaredField(
156                                    Thread.class, "inheritableThreadLocals");
157                            _THREAD_LOCALS_FIELD = ReflectionUtil.getDeclaredField(
158                                    Thread.class, "threadLocals");
159                    }
160                    catch (Exception e) {
161                            throw new ExceptionInInitializerError(e);
162                    }
163            }
164    
165            private final TestRule _testRule = new TestRule() {
166    
167                    @Override
168                    public Statement apply(Statement statement, Description description) {
169                            return logAssertStatement(statement, null);
170                    }
171    
172            };
173    
174    }