1 package org.apache.maven.surefire.junitplatform;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import static java.util.Arrays.stream;
23 import static java.util.Collections.emptyMap;
24 import static java.util.Optional.empty;
25 import static java.util.Optional.of;
26 import static java.util.logging.Level.WARNING;
27 import static java.util.stream.Collectors.toList;
28 import static org.apache.maven.surefire.booter.ProviderParameterNames.TESTNG_EXCLUDEDGROUPS_PROP;
29 import static org.apache.maven.surefire.booter.ProviderParameterNames.TESTNG_GROUPS_PROP;
30 import static org.apache.maven.surefire.report.ConsoleOutputCapture.startCapture;
31 import static org.apache.maven.surefire.util.TestsToRun.fromClass;
32 import static org.junit.platform.commons.util.StringUtils.isBlank;
33 import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass;
34 import static org.junit.platform.engine.discovery.DiscoverySelectors.selectUniqueId;
35 import static org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder.request;
36
37 import java.io.IOException;
38 import java.io.StringReader;
39 import java.io.UncheckedIOException;
40 import java.util.ArrayList;
41 import java.util.HashMap;
42 import java.util.List;
43 import java.util.Map;
44 import java.util.Optional;
45 import java.util.Properties;
46 import java.util.HashSet;
47 import java.util.logging.Logger;
48
49 import org.apache.maven.surefire.providerapi.AbstractProvider;
50 import org.apache.maven.surefire.providerapi.ProviderParameters;
51 import org.apache.maven.surefire.report.ConsoleOutputReceiver;
52 import org.apache.maven.surefire.report.ReporterException;
53 import org.apache.maven.surefire.report.ReporterFactory;
54 import org.apache.maven.surefire.report.RunListener;
55 import org.apache.maven.surefire.suite.RunResult;
56 import org.apache.maven.surefire.testset.TestListResolver;
57 import org.apache.maven.surefire.testset.TestSetFailedException;
58 import org.apache.maven.surefire.util.ScanResult;
59 import org.apache.maven.surefire.util.TestsToRun;
60 import org.junit.platform.commons.util.StringUtils;
61 import org.junit.platform.engine.Filter;
62 import org.junit.platform.launcher.Launcher;
63 import org.junit.platform.launcher.LauncherDiscoveryRequest;
64 import org.junit.platform.launcher.TagFilter;
65 import org.junit.platform.launcher.TestIdentifier;
66 import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder;
67 import org.junit.platform.launcher.core.LauncherFactory;
68
69
70
71
72
73
74 public class JUnitPlatformProvider
75 extends AbstractProvider
76 {
77 static final String CONFIGURATION_PARAMETERS = "configurationParameters";
78
79 private final ProviderParameters parameters;
80
81 private final Launcher launcher;
82
83 private final Filter<?>[] filters;
84
85 private final Map<String, String> configurationParameters;
86
87 public JUnitPlatformProvider( ProviderParameters parameters )
88 {
89 this( parameters, LauncherFactory.create() );
90 }
91
92 JUnitPlatformProvider( ProviderParameters parameters, Launcher launcher )
93 {
94 this.parameters = parameters;
95 this.launcher = launcher;
96 filters = newFilters();
97 configurationParameters = newConfigurationParameters();
98 Logger.getLogger( "org.junit" ).setLevel( WARNING );
99 }
100
101 @Override
102 public Iterable<Class<?>> getSuites()
103 {
104 return scanClasspath();
105 }
106
107 @Override
108 public RunResult invoke( Object forkTestSet )
109 throws TestSetFailedException, ReporterException
110 {
111 ReporterFactory reporterFactory = parameters.getReporterFactory();
112 final RunResult runResult;
113 try
114 {
115 RunListener runListener = reporterFactory.createReporter();
116 startCapture( ( ConsoleOutputReceiver ) runListener );
117 if ( forkTestSet instanceof TestsToRun )
118 {
119 invokeAllTests( (TestsToRun) forkTestSet, runListener );
120 }
121 else if ( forkTestSet instanceof Class )
122 {
123 invokeAllTests( fromClass( ( Class<?> ) forkTestSet ), runListener );
124 }
125 else if ( forkTestSet == null )
126 {
127 invokeAllTests( scanClasspath(), runListener );
128 }
129 else
130 {
131 throw new IllegalArgumentException(
132 "Unexpected value of forkTestSet: " + forkTestSet );
133 }
134 }
135 finally
136 {
137 runResult = reporterFactory.close();
138 }
139 return runResult;
140 }
141
142 private TestsToRun scanClasspath()
143 {
144 TestPlanScannerFilter filter = new TestPlanScannerFilter( launcher, filters );
145 ScanResult scanResult = parameters.getScanResult();
146 TestsToRun scannedClasses = scanResult.applyFilter( filter, parameters.getTestClassLoader() );
147 return parameters.getRunOrderCalculator().orderTestClasses( scannedClasses );
148 }
149
150 private void invokeAllTests( TestsToRun testsToRun, RunListener runListener )
151 {
152 LauncherDiscoveryRequest discoveryRequest = buildLauncherDiscoveryRequest( testsToRun );
153 RunListenerAdapter adapter = new RunListenerAdapter( runListener );
154 launcher.execute( discoveryRequest, adapter );
155
156 int count = parameters.getTestRequest().getRerunFailingTestsCount();
157 if ( count > 0 && adapter.hasFailingTests() )
158 {
159 for ( int i = 0; i < count; i++ )
160 {
161
162 discoveryRequest = buildLauncherDiscoveryRequestForRerunFailures( adapter );
163
164 adapter.reset();
165 launcher.execute( discoveryRequest, adapter );
166
167 if ( !adapter.hasFailingTests() )
168 {
169 break;
170 }
171 }
172 }
173 }
174
175 private LauncherDiscoveryRequest buildLauncherDiscoveryRequest( TestsToRun testsToRun )
176 {
177 LauncherDiscoveryRequestBuilder builder =
178 request().filters( filters ).configurationParameters( configurationParameters );
179 for ( Class<?> testClass : testsToRun )
180 {
181 builder.selectors( selectClass( testClass.getName() ) );
182 }
183 return builder.build();
184 }
185
186 private LauncherDiscoveryRequest buildLauncherDiscoveryRequestForRerunFailures( RunListenerAdapter adapter )
187 {
188 LauncherDiscoveryRequestBuilder builder = request().filters( filters ).configurationParameters(
189 configurationParameters );
190
191 for ( TestIdentifier identifier : new HashSet<>( adapter.getFailures().keySet() ) )
192 {
193 builder.selectors( selectUniqueId( identifier.getUniqueId() ) );
194 }
195 return builder.build();
196 }
197
198 private Filter<?>[] newFilters()
199 {
200 List<Filter<?>> filters = new ArrayList<>();
201
202 getPropertiesList( TESTNG_GROUPS_PROP )
203 .map( TagFilter::includeTags )
204 .ifPresent( filters::add );
205
206 getPropertiesList( TESTNG_EXCLUDEDGROUPS_PROP )
207 .map( TagFilter::excludeTags )
208 .ifPresent( filters::add );
209
210 TestListResolver testListResolver = parameters.getTestRequest().getTestListResolver();
211 if ( !testListResolver.isEmpty() )
212 {
213 filters.add( new TestMethodFilter( testListResolver ) );
214 }
215
216 return filters.toArray( new Filter<?>[ filters.size() ] );
217 }
218
219 Filter<?>[] getFilters()
220 {
221 return filters;
222 }
223
224 private Map<String, String> newConfigurationParameters()
225 {
226 String content = parameters.getProviderProperties().get( CONFIGURATION_PARAMETERS );
227 if ( content == null )
228 {
229 return emptyMap();
230 }
231 try ( StringReader reader = new StringReader( content ) )
232 {
233 Map<String, String> result = new HashMap<>();
234 Properties props = new Properties();
235 props.load( reader );
236 props.stringPropertyNames()
237 .forEach( key -> result.put( key, props.getProperty( key ) ) );
238 return result;
239 }
240 catch ( IOException e )
241 {
242 throw new UncheckedIOException( "Error reading " + CONFIGURATION_PARAMETERS, e );
243 }
244 }
245
246 Map<String, String> getConfigurationParameters()
247 {
248 return configurationParameters;
249 }
250
251 private Optional<List<String>> getPropertiesList( String key )
252 {
253 String property = parameters.getProviderProperties().get( key );
254 return isBlank( property ) ? empty()
255 : of( stream( property.split( "[,]+" ) )
256 .filter( StringUtils::isNotBlank )
257 .map( String::trim )
258 .collect( toList() ) );
259 }
260 }