1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.surefire.junitcore;
20
21 import java.util.Map;
22 import java.util.Set;
23 import java.util.concurrent.ConcurrentHashMap;
24
25 import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
26 import org.apache.maven.surefire.api.booter.Command;
27 import org.apache.maven.surefire.api.provider.AbstractProvider;
28 import org.apache.maven.surefire.api.provider.CommandChainReader;
29 import org.apache.maven.surefire.api.provider.CommandListener;
30 import org.apache.maven.surefire.api.provider.ProviderParameters;
31 import org.apache.maven.surefire.api.report.ReporterFactory;
32 import org.apache.maven.surefire.api.suite.RunResult;
33 import org.apache.maven.surefire.api.testset.TestListResolver;
34 import org.apache.maven.surefire.api.testset.TestSetFailedException;
35 import org.apache.maven.surefire.api.util.RunOrderCalculator;
36 import org.apache.maven.surefire.api.util.ScanResult;
37 import org.apache.maven.surefire.api.util.ScannerFilter;
38 import org.apache.maven.surefire.api.util.TestsToRun;
39 import org.apache.maven.surefire.common.junit4.JUnit4RunListener;
40 import org.apache.maven.surefire.common.junit4.JUnitTestFailureListener;
41 import org.apache.maven.surefire.common.junit4.Notifier;
42 import org.apache.maven.surefire.common.junit48.FilterFactory;
43 import org.apache.maven.surefire.common.junit48.JUnit48Reflector;
44 import org.apache.maven.surefire.common.junit48.JUnit48TestChecker;
45 import org.junit.runner.Description;
46 import org.junit.runner.manipulation.Filter;
47
48 import static org.apache.maven.surefire.api.report.ConsoleOutputCapture.startCapture;
49 import static org.apache.maven.surefire.api.report.RunMode.NORMAL_RUN;
50 import static org.apache.maven.surefire.api.report.RunMode.RERUN_TEST_AFTER_FAILURE;
51 import static org.apache.maven.surefire.api.testset.TestListResolver.optionallyWildcardFilter;
52 import static org.apache.maven.surefire.api.util.TestsToRun.fromClass;
53 import static org.apache.maven.surefire.common.junit4.JUnit4ProviderUtil.generateFailingTestDescriptions;
54 import static org.apache.maven.surefire.common.junit4.JUnit4RunListenerFactory.createCustomListeners;
55 import static org.apache.maven.surefire.common.junit4.Notifier.pureNotifier;
56 import static org.apache.maven.surefire.junitcore.ConcurrentRunListener.createInstance;
57
58
59
60
61 @SuppressWarnings({"UnusedDeclaration"})
62 public class JUnitCoreProvider extends AbstractProvider {
63 private final ClassLoader testClassLoader;
64
65 private final JUnitCoreParameters jUnitCoreParameters;
66
67 private final ScannerFilter scannerFilter;
68
69 private final String customRunListeners;
70
71 private final ProviderParameters providerParameters;
72
73 private final ScanResult scanResult;
74
75 private final int rerunFailingTestsCount;
76
77 private final JUnit48Reflector jUnit48Reflector;
78
79 private final RunOrderCalculator runOrderCalculator;
80
81 private final TestListResolver testResolver;
82
83 private final CommandChainReader commandsReader;
84
85 private TestsToRun testsToRun;
86
87 public JUnitCoreProvider(ProviderParameters bootParams) {
88
89 commandsReader = bootParams.isInsideFork() ? bootParams.getCommandReader() : null;
90 providerParameters = bootParams;
91 testClassLoader = bootParams.getTestClassLoader();
92 scanResult = bootParams.getScanResult();
93 runOrderCalculator = bootParams.getRunOrderCalculator();
94 jUnitCoreParameters = new JUnitCoreParameters(bootParams.getProviderProperties());
95 scannerFilter = new JUnit48TestChecker(testClassLoader);
96 testResolver = bootParams.getTestRequest().getTestListResolver();
97 rerunFailingTestsCount = bootParams.getTestRequest().getRerunFailingTestsCount();
98 customRunListeners = bootParams.getProviderProperties().get("listener");
99 jUnit48Reflector = new JUnit48Reflector(testClassLoader);
100 }
101
102 @Override
103 public Iterable<Class<?>> getSuites() {
104 testsToRun = scanClassPath();
105 return testsToRun;
106 }
107
108 private boolean isSingleThreaded() {
109 return jUnitCoreParameters.isNoThreading();
110 }
111
112 @Override
113 public RunResult invoke(Object forkTestSet) throws TestSetFailedException {
114 ReporterFactory reporterFactory = providerParameters.getReporterFactory();
115 JUnit4RunListener listener = createRunListener(reporterFactory);
116 listener.setRunMode(NORMAL_RUN);
117 ConsoleLogger logger = listener.getConsoleLogger();
118 Notifier notifier = new Notifier(listener, getSkipAfterFailureCount());
119
120
121 Filter filter = jUnit48Reflector.isJUnit48Available() ? createJUnit48Filter() : null;
122
123 if (testsToRun == null) {
124 setTestsToRun(forkTestSet);
125 }
126
127
128 JUnitTestFailureListener testFailureListener = new JUnitTestFailureListener();
129 notifier.addListener(testFailureListener);
130
131 if (isFailFast() && commandsReader != null) {
132 registerPleaseStopJUnitListener(notifier);
133 }
134
135 final RunResult runResult;
136
137 try {
138 JUnitCoreWrapper core = new JUnitCoreWrapper(notifier, jUnitCoreParameters, logger);
139
140 if (commandsReader != null) {
141 registerShutdownListener(testsToRun);
142 commandsReader.awaitStarted();
143 }
144
145 notifier.asFailFast(isFailFast());
146 core.execute(testsToRun, createCustomListeners(customRunListeners), filter);
147 notifier.asFailFast(false);
148
149
150 if (isRerunFailingTests()) {
151 listener.setRunMode(RERUN_TEST_AFTER_FAILURE);
152 Notifier rerunNotifier = pureNotifier();
153 notifier.copyListenersTo(rerunNotifier);
154 JUnitCoreWrapper rerunCore = new JUnitCoreWrapper(rerunNotifier, jUnitCoreParameters, logger);
155 for (int i = 0;
156 i < rerunFailingTestsCount
157 && !testFailureListener.getAllFailures().isEmpty();
158 i++) {
159 Set<Description> failures = generateFailingTestDescriptions(testFailureListener.getAllFailures());
160 testFailureListener.reset();
161 FilterFactory filterFactory = new FilterFactory(testClassLoader);
162 Filter failureDescriptionFilter = filterFactory.createMatchAnyDescriptionFilter(failures);
163 rerunCore.execute(testsToRun, failureDescriptionFilter);
164 }
165 }
166 } finally {
167 runResult = reporterFactory.close();
168 notifier.removeListeners();
169 }
170 return runResult;
171 }
172
173 private void setTestsToRun(Object forkTestSet) throws TestSetFailedException {
174 if (forkTestSet instanceof TestsToRun) {
175 testsToRun = (TestsToRun) forkTestSet;
176 } else if (forkTestSet instanceof Class) {
177 Class<?> theClass = (Class<?>) forkTestSet;
178 testsToRun = fromClass(theClass);
179 } else {
180 testsToRun = scanClassPath();
181 }
182 }
183
184 private boolean isRerunFailingTests() {
185 return rerunFailingTestsCount > 0;
186 }
187
188 private boolean isFailFast() {
189 return providerParameters.getSkipAfterFailureCount() > 0;
190 }
191
192 private int getSkipAfterFailureCount() {
193 return isFailFast() ? providerParameters.getSkipAfterFailureCount() : 0;
194 }
195
196 private void registerShutdownListener(final TestsToRun testsToRun) {
197 commandsReader.addShutdownListener(new CommandListener() {
198 @Override
199 public void update(Command command) {
200 testsToRun.markTestSetFinished();
201 }
202 });
203 }
204
205 private void registerPleaseStopJUnitListener(final Notifier stoppable) {
206 commandsReader.addSkipNextTestsListener(new CommandListener() {
207 @Override
208 public void update(Command command) {
209 stoppable.pleaseStop();
210 }
211 });
212 }
213
214 private JUnit4RunListener createRunListener(ReporterFactory reporterFactory) {
215 final JUnit4RunListener listener;
216 if (isSingleThreaded()) {
217 listener = new NonConcurrentRunListener(reporterFactory.createTestReportListener());
218 } else {
219 Map<String, TestSet> testSetMap = new ConcurrentHashMap<>();
220 boolean parallelClasses = isParallelTypes();
221 boolean parallelBoth = isParallelMethodsAndTypes();
222 ConcurrentRunListener concurrentListener =
223 createInstance(testSetMap, reporterFactory, parallelClasses, parallelBoth);
224 listener = new JUnitCoreRunListener(concurrentListener, testSetMap);
225 }
226
227 startCapture(listener);
228 return listener;
229 }
230
231 private boolean isParallelMethodsAndTypes() {
232 return jUnitCoreParameters.isParallelMethods() && isParallelTypes();
233 }
234
235 private boolean isParallelTypes() {
236 return jUnitCoreParameters.isParallelClasses() || jUnitCoreParameters.isParallelSuites();
237 }
238
239 private Filter createJUnit48Filter() {
240 final FilterFactory factory = new FilterFactory(testClassLoader);
241 Map<String, String> props = providerParameters.getProviderProperties();
242 Filter groupFilter = factory.canCreateGroupFilter(props) ? factory.createGroupFilter(props) : null;
243 TestListResolver methodFilter = optionallyWildcardFilter(testResolver);
244 boolean onlyGroups = methodFilter.isEmpty() || methodFilter.isWildcard();
245 if (onlyGroups) {
246 return groupFilter;
247 } else {
248 Filter jUnitMethodFilter = factory.createMethodFilter(methodFilter);
249 return groupFilter == null ? jUnitMethodFilter : factory.and(groupFilter, jUnitMethodFilter);
250 }
251 }
252
253 private TestsToRun scanClassPath() {
254 TestsToRun scanned = scanResult.applyFilter(scannerFilter, testClassLoader);
255 return runOrderCalculator.orderTestClasses(scanned);
256 }
257 }