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.junit.platform.commons.util.StringUtils.isBlank;
31 import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass;
32 import static org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder.request;
33
34 import java.io.IOException;
35 import java.io.StringReader;
36 import java.io.UncheckedIOException;
37 import java.util.ArrayList;
38 import java.util.HashMap;
39 import java.util.List;
40 import java.util.Map;
41 import java.util.Optional;
42 import java.util.Properties;
43 import java.util.logging.Logger;
44
45 import org.apache.maven.surefire.providerapi.AbstractProvider;
46 import org.apache.maven.surefire.providerapi.ProviderParameters;
47 import org.apache.maven.surefire.report.ConsoleOutputCapture;
48 import org.apache.maven.surefire.report.ConsoleOutputReceiver;
49 import org.apache.maven.surefire.report.ReporterException;
50 import org.apache.maven.surefire.report.ReporterFactory;
51 import org.apache.maven.surefire.report.RunListener;
52 import org.apache.maven.surefire.suite.RunResult;
53 import org.apache.maven.surefire.testset.TestListResolver;
54 import org.apache.maven.surefire.testset.TestSetFailedException;
55 import org.apache.maven.surefire.util.ScanResult;
56 import org.apache.maven.surefire.util.TestsToRun;
57 import org.junit.platform.commons.util.StringUtils;
58 import org.junit.platform.engine.Filter;
59 import org.junit.platform.launcher.Launcher;
60 import org.junit.platform.launcher.LauncherDiscoveryRequest;
61 import org.junit.platform.launcher.TagFilter;
62 import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder;
63 import org.junit.platform.launcher.core.LauncherFactory;
64
65
66
67
68
69
70 public class JUnitPlatformProvider
71 extends AbstractProvider
72 {
73 static final String CONFIGURATION_PARAMETERS = "configurationParameters";
74
75 private final ProviderParameters parameters;
76
77 private final Launcher launcher;
78
79 private final Filter<?>[] filters;
80
81 private final Map<String, String> configurationParameters;
82
83 public JUnitPlatformProvider( ProviderParameters parameters )
84 {
85 this( parameters, LauncherFactory.create() );
86 }
87
88 JUnitPlatformProvider( ProviderParameters parameters, Launcher launcher )
89 {
90 this.parameters = parameters;
91 this.launcher = launcher;
92 filters = newFilters();
93 configurationParameters = newConfigurationParameters();
94 Logger.getLogger( "org.junit" ).setLevel( WARNING );
95 }
96
97 @Override
98 public Iterable<Class<?>> getSuites()
99 {
100 return scanClasspath();
101 }
102
103 @Override
104 public RunResult invoke( Object forkTestSet )
105 throws TestSetFailedException, ReporterException
106 {
107 if ( forkTestSet instanceof TestsToRun )
108 {
109 return invokeAllTests( (TestsToRun) forkTestSet );
110 }
111 else if ( forkTestSet instanceof Class )
112 {
113 return invokeAllTests( TestsToRun.fromClass( (Class<?>) forkTestSet ) );
114 }
115 else if ( forkTestSet == null )
116 {
117 return invokeAllTests( scanClasspath() );
118 }
119 else
120 {
121 throw new IllegalArgumentException( "Unexpected value of forkTestSet: " + forkTestSet );
122 }
123 }
124
125 private TestsToRun scanClasspath()
126 {
127 TestPlanScannerFilter filter = new TestPlanScannerFilter( launcher, filters );
128 ScanResult scanResult = parameters.getScanResult();
129 TestsToRun scannedClasses = scanResult.applyFilter( filter, parameters.getTestClassLoader() );
130 return parameters.getRunOrderCalculator().orderTestClasses( scannedClasses );
131 }
132
133 private RunResult invokeAllTests( TestsToRun testsToRun )
134 {
135 RunResult runResult;
136 ReporterFactory reporterFactory = parameters.getReporterFactory();
137 try
138 {
139 RunListener runListener = reporterFactory.createReporter();
140 ConsoleOutputCapture.startCapture( (ConsoleOutputReceiver) runListener );
141 LauncherDiscoveryRequest discoveryRequest = buildLauncherDiscoveryRequest( testsToRun );
142 launcher.execute( discoveryRequest, new RunListenerAdapter( runListener ) );
143 }
144 finally
145 {
146 runResult = reporterFactory.close();
147 }
148 return runResult;
149 }
150
151 private LauncherDiscoveryRequest buildLauncherDiscoveryRequest( TestsToRun testsToRun )
152 {
153 LauncherDiscoveryRequestBuilder builder =
154 request().filters( filters ).configurationParameters( configurationParameters );
155 for ( Class<?> testClass : testsToRun )
156 {
157 builder.selectors( selectClass( testClass ) );
158 }
159 return builder.build();
160 }
161
162 private Filter<?>[] newFilters()
163 {
164 List<Filter<?>> filters = new ArrayList<>();
165
166 getPropertiesList( TESTNG_GROUPS_PROP )
167 .map( TagFilter::includeTags )
168 .ifPresent( filters::add );
169
170 getPropertiesList( TESTNG_EXCLUDEDGROUPS_PROP )
171 .map( TagFilter::excludeTags )
172 .ifPresent( filters::add );
173
174 TestListResolver testListResolver = parameters.getTestRequest().getTestListResolver();
175 if ( !testListResolver.isEmpty() )
176 {
177 filters.add( new TestMethodFilter( testListResolver ) );
178 }
179
180 return filters.toArray( new Filter<?>[ filters.size() ] );
181 }
182
183 Filter<?>[] getFilters()
184 {
185 return filters;
186 }
187
188 private Map<String, String> newConfigurationParameters()
189 {
190 String content = parameters.getProviderProperties().get( CONFIGURATION_PARAMETERS );
191 if ( content == null )
192 {
193 return emptyMap();
194 }
195 try ( StringReader reader = new StringReader( content ) )
196 {
197 Map<String, String> result = new HashMap<>();
198 Properties props = new Properties();
199 props.load( reader );
200 props.stringPropertyNames()
201 .forEach( key -> result.put( key, props.getProperty( key ) ) );
202 return result;
203 }
204 catch ( IOException e )
205 {
206 throw new UncheckedIOException( "Error reading " + CONFIGURATION_PARAMETERS, e );
207 }
208 }
209
210 Map<String, String> getConfigurationParameters()
211 {
212 return configurationParameters;
213 }
214
215 private Optional<List<String>> getPropertiesList( String key )
216 {
217 String property = parameters.getProviderProperties().get( key );
218 return isBlank( property ) ? empty()
219 : of( stream( property.split( "[,]+" ) )
220 .filter( StringUtils::isNotBlank )
221 .map( String::trim )
222 .collect( toList() ) );
223 }
224 }