1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.plugin.surefire.booterclient;
20
21 import javax.annotation.Nonnull;
22
23 import java.io.File;
24 import java.io.IOException;
25 import java.nio.file.Path;
26 import java.nio.file.Paths;
27 import java.util.ArrayList;
28 import java.util.Collections;
29 import java.util.HashMap;
30 import java.util.List;
31 import java.util.Map;
32 import java.util.Properties;
33
34 import org.apache.maven.plugin.surefire.JdkAttributes;
35 import org.apache.maven.plugin.surefire.booterclient.lazytestprovider.Commandline;
36 import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
37 import org.apache.maven.plugin.surefire.log.api.NullConsoleLogger;
38 import org.apache.maven.surefire.booter.ClassLoaderConfiguration;
39 import org.apache.maven.surefire.booter.Classpath;
40 import org.apache.maven.surefire.booter.ClasspathConfiguration;
41 import org.apache.maven.surefire.booter.ModularClasspath;
42 import org.apache.maven.surefire.booter.ModularClasspathConfiguration;
43 import org.apache.maven.surefire.booter.StartupConfiguration;
44 import org.apache.maven.surefire.booter.SurefireBooterForkException;
45 import org.apache.maven.surefire.extensions.ForkNodeFactory;
46 import org.apache.maven.surefire.shared.io.FileUtils;
47 import org.junit.After;
48 import org.junit.Before;
49 import org.junit.Test;
50
51 import static java.lang.String.join;
52 import static java.nio.file.Files.readAllBytes;
53 import static java.util.Collections.singletonList;
54 import static org.apache.commons.io.FileUtils.getTempDirectory;
55 import static org.apache.maven.surefire.api.util.internal.StringUtils.NL;
56 import static org.apache.maven.surefire.booter.Classpath.emptyClasspath;
57 import static org.apache.maven.surefire.booter.ProcessCheckerType.ALL;
58 import static org.apache.maven.surefire.shared.lang3.SystemUtils.IS_OS_WINDOWS;
59 import static org.assertj.core.api.Assertions.assertThat;
60 import static org.junit.Assert.assertEquals;
61 import static org.junit.Assert.assertTrue;
62 import static org.junit.Assert.fail;
63 import static org.mockito.Mockito.mock;
64
65
66
67
68 public class ForkConfigurationTest {
69 private static final StartupConfiguration STARTUP_CONFIG = new StartupConfiguration(
70 "",
71 new ClasspathConfiguration(true, true),
72 new ClassLoaderConfiguration(true, true),
73 ALL,
74 Collections.<String[]>emptyList());
75
76 private static int idx = 0;
77
78 private File basedir;
79
80 @Before
81 public void setupDirectories() throws IOException {
82 File target = new File(System.getProperty("user.dir"), "target");
83 basedir = new File(target, "SUREFIRE-1136-" + ++idx);
84 FileUtils.deleteDirectory(basedir);
85 assertTrue(basedir.mkdirs());
86 }
87
88 @After
89 public void deleteDirectories() throws IOException {
90 FileUtils.deleteDirectory(basedir);
91 }
92
93 @Test
94 public void testEnv() throws Exception {
95 Map<String, String> env = new HashMap<>();
96 env.put("key1", "val1");
97 env.put("key2", "val2");
98 env.put("key3", "val3");
99 String[] exclEnv = {"PATH"};
100
101 String jvm = new File(new File(System.getProperty("java.home"), "bin"), "java").getCanonicalPath();
102 Platform platform = new Platform().withJdkExecAttributesForTests(new JdkAttributes(jvm, false));
103
104 ForkConfiguration config =
105 new DefaultForkConfiguration(
106 emptyClasspath(),
107 basedir,
108 "",
109 basedir,
110 new Properties(),
111 "",
112 env,
113 exclEnv,
114 false,
115 1,
116 true,
117 platform,
118 new NullConsoleLogger(),
119 mock(ForkNodeFactory.class)) {
120
121 @Override
122 protected void resolveClasspath(
123 @Nonnull Commandline cli,
124 @Nonnull String booterThatHasMainMethod,
125 @Nonnull StartupConfiguration config,
126 @Nonnull File dumpLogDirectory) {}
127 };
128
129 List<String[]> providerJpmsArgs = new ArrayList<>();
130 providerJpmsArgs.add(new String[] {"arg2", "arg3"});
131
132 File cpElement = getTempClasspathFile();
133 List<String> cp = singletonList(cpElement.getAbsolutePath());
134
135 ClasspathConfiguration cpConfig =
136 new ClasspathConfiguration(new Classpath(cp), emptyClasspath(), emptyClasspath(), true, true);
137 ClassLoaderConfiguration clc = new ClassLoaderConfiguration(true, true);
138 StartupConfiguration startup = new StartupConfiguration("cls", cpConfig, clc, ALL, providerJpmsArgs);
139
140 org.apache.maven.surefire.shared.utils.cli.Commandline cli =
141 config.createCommandLine(startup, 1, getTempDirectory());
142
143 assertThat(cli.getEnvironmentVariables())
144 .contains("key1=val1", "key2=val2", "key3=val3")
145 .doesNotContain("PATH=")
146 .doesNotHaveDuplicates();
147 }
148
149 @Test
150 public void testCliArgs() throws Exception {
151 String jvm = new File(new File(System.getProperty("java.home"), "bin"), "java").getCanonicalPath();
152 Platform platform = new Platform().withJdkExecAttributesForTests(new JdkAttributes(jvm, false));
153
154 ModularClasspathForkConfiguration config = new ModularClasspathForkConfiguration(
155 emptyClasspath(),
156 basedir,
157 "",
158 basedir,
159 new Properties(),
160 "arg1",
161 Collections.<String, String>emptyMap(),
162 new String[0],
163 false,
164 1,
165 true,
166 platform,
167 new NullConsoleLogger(),
168 mock(ForkNodeFactory.class));
169
170 assertThat(config.isDebug()).isFalse();
171
172 List<String[]> providerJpmsArgs = new ArrayList<>();
173 providerJpmsArgs.add(new String[] {"arg2", "arg3"});
174
175 ModularClasspath modulepath = new ModularClasspath(
176 "test.module", Collections.<String>emptyList(), Collections.<String>emptyList(), null, false);
177 ModularClasspathConfiguration cpConfig = new ModularClasspathConfiguration(
178 modulepath, emptyClasspath(), emptyClasspath(), emptyClasspath(), false, true);
179 ClassLoaderConfiguration clc = new ClassLoaderConfiguration(true, true);
180 StartupConfiguration startup = new StartupConfiguration("cls", cpConfig, clc, ALL, providerJpmsArgs);
181
182 org.apache.maven.surefire.shared.utils.cli.Commandline cli =
183 config.createCommandLine(startup, 1, getTempDirectory());
184 String cliAsString = cli.toString();
185
186 assertThat(cliAsString).contains("arg1");
187
188
189 int beginOfFileArg = cliAsString.indexOf('@', cliAsString.lastIndexOf("arg1"));
190 assertThat(beginOfFileArg).isPositive();
191 int endOfFileArg = cliAsString.indexOf(IS_OS_WINDOWS ? '"' : '\'', beginOfFileArg);
192 assertThat(endOfFileArg).isPositive();
193 Path argFile = Paths.get(cliAsString.substring(beginOfFileArg + 1, endOfFileArg));
194 String argFileText = new String(readAllBytes(argFile));
195 assertThat(argFileText).contains("arg2").contains("arg3").contains("--add-modules" + NL + "test.module");
196 }
197
198 @Test
199 public void testDebugLine() throws Exception {
200 String jvm = new File(new File(System.getProperty("java.home"), "bin"), "java").getCanonicalPath();
201 Platform platform = new Platform().withJdkExecAttributesForTests(new JdkAttributes(jvm, false));
202
203 ConsoleLogger logger = mock(ConsoleLogger.class);
204 ForkNodeFactory forkNodeFactory = mock(ForkNodeFactory.class);
205
206 ForkConfiguration config =
207 new DefaultForkConfiguration(
208 emptyClasspath(),
209 basedir,
210 "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005",
211 basedir,
212 new Properties(),
213 "",
214 Collections.<String, String>emptyMap(),
215 new String[0],
216 true,
217 1,
218 true,
219 platform,
220 logger,
221 forkNodeFactory) {
222
223 @Override
224 protected void resolveClasspath(
225 @Nonnull Commandline cli,
226 @Nonnull String booterThatHasMainMethod,
227 @Nonnull StartupConfiguration config,
228 @Nonnull File dumpLogDirectory) {}
229 };
230
231 assertThat(config.isDebug()).isTrue();
232
233 assertThat(config.getDebugLine())
234 .isEqualTo("-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005");
235
236 assertThat(config.getForkCount()).isEqualTo(1);
237
238 assertThat(config.isReuseForks()).isTrue();
239
240 assertThat(config.getForkNodeFactory()).isSameAs(forkNodeFactory);
241
242 File cpElement = getTempClasspathFile();
243 List<String> cp = singletonList(cpElement.getAbsolutePath());
244
245 ClasspathConfiguration cpConfig =
246 new ClasspathConfiguration(new Classpath(cp), emptyClasspath(), emptyClasspath(), true, true);
247 ClassLoaderConfiguration clc = new ClassLoaderConfiguration(true, true);
248 StartupConfiguration startup = new StartupConfiguration(
249 "org.apache.maven.surefire.JUnitProvider#main", cpConfig, clc, ALL, Collections.<String[]>emptyList());
250
251 assertThat(startup.isProviderMainClass()).isTrue();
252
253 assertThat(startup.getProviderClassName()).isEqualTo("org.apache.maven.surefire.JUnitProvider#main");
254
255 assertThat(startup.isShadefire()).isFalse();
256
257 org.apache.maven.surefire.shared.utils.cli.Commandline cli =
258 config.createCommandLine(startup, 1, getTempDirectory());
259
260 assertThat(cli.toString()).contains("-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005");
261 }
262
263 @Test
264 @SuppressWarnings({"checkstyle:methodname", "checkstyle:magicnumber"})
265 public void testCreateCommandLine_UseSystemClassLoaderForkOnce_ShouldConstructManifestOnlyJar()
266 throws IOException, SurefireBooterForkException {
267 ForkConfiguration config = getForkConfiguration(basedir, null);
268 File cpElement = getTempClasspathFile();
269
270 List<String> cp = singletonList(cpElement.getAbsolutePath());
271 ClasspathConfiguration cpConfig =
272 new ClasspathConfiguration(new Classpath(cp), emptyClasspath(), emptyClasspath(), true, true);
273 ClassLoaderConfiguration clc = new ClassLoaderConfiguration(true, true);
274 StartupConfiguration startup =
275 new StartupConfiguration("", cpConfig, clc, ALL, Collections.<String[]>emptyList());
276
277 org.apache.maven.surefire.shared.utils.cli.Commandline cli =
278 config.createCommandLine(startup, 1, getTempDirectory());
279
280 String line = join(" ", cli.getCommandline());
281 assertTrue(line.contains("-jar"));
282 }
283
284 @Test
285 public void testArglineWithNewline() throws IOException, SurefireBooterForkException {
286
287 ForkConfiguration config = getForkConfiguration(basedir, "abc\ndef");
288 File cpElement = getTempClasspathFile();
289
290 List<String> cp = singletonList(cpElement.getAbsolutePath());
291 ClasspathConfiguration cpConfig =
292 new ClasspathConfiguration(new Classpath(cp), emptyClasspath(), emptyClasspath(), true, true);
293 ClassLoaderConfiguration clc = new ClassLoaderConfiguration(true, true);
294 StartupConfiguration startup =
295 new StartupConfiguration("", cpConfig, clc, ALL, Collections.<String[]>emptyList());
296
297 org.apache.maven.surefire.shared.utils.cli.Commandline commandLine =
298 config.createCommandLine(startup, 1, getTempDirectory());
299 assertThat(commandLine.toString()).contains(IS_OS_WINDOWS ? "abc def" : "'abc' 'def'");
300 }
301
302 @Test
303 public void testCurrentWorkingDirectoryPropagationIncludingForkNumberExpansion()
304 throws IOException, SurefireBooterForkException {
305 File cwd = new File(basedir, "fork_${surefire.forkNumber}");
306
307 ClasspathConfiguration cpConfig =
308 new ClasspathConfiguration(emptyClasspath(), emptyClasspath(), emptyClasspath(), true, true);
309 ClassLoaderConfiguration clc = new ClassLoaderConfiguration(true, true);
310 StartupConfiguration startup =
311 new StartupConfiguration("", cpConfig, clc, ALL, Collections.<String[]>emptyList());
312 ForkConfiguration config = getForkConfiguration(cwd.getCanonicalFile());
313 org.apache.maven.surefire.shared.utils.cli.Commandline commandLine =
314 config.createCommandLine(startup, 1, getTempDirectory());
315
316 File forkDirectory = new File(basedir, "fork_1");
317
318 String shellWorkDir = commandLine.getShell().getWorkingDirectory().getCanonicalPath();
319 assertEquals(shellWorkDir, forkDirectory.getCanonicalPath());
320 }
321
322 @Test
323 public void testExceptionWhenCurrentDirectoryIsNotRealDirectory() throws IOException {
324 File cwd = new File(basedir, "cwd.txt");
325 FileUtils.touch(cwd);
326
327 try {
328 ForkConfiguration config = getForkConfiguration(cwd.getCanonicalFile());
329 config.createCommandLine(STARTUP_CONFIG, 1, getTempDirectory());
330 } catch (SurefireBooterForkException e) {
331
332 String absolutePath = cwd.getCanonicalPath();
333 assertEquals("WorkingDirectory " + absolutePath + " exists and is not a directory", e.getMessage());
334 return;
335 } finally {
336 assertTrue(cwd.delete());
337 }
338
339 fail();
340 }
341
342 @Test
343 public void testExceptionWhenCurrentDirectoryCannotBeCreated() throws IOException {
344
345
346
347 File cwd = new File(basedir, "?\u0000InvalidDirectoryName");
348
349 try {
350 ForkConfiguration config = getForkConfiguration(cwd.getAbsoluteFile());
351 config.createCommandLine(STARTUP_CONFIG, 1, getTempDirectory());
352 } catch (SurefireBooterForkException sbfe) {
353 assertEquals("Cannot create workingDirectory " + cwd.getAbsolutePath(), sbfe.getMessage());
354 return;
355 } finally {
356 FileUtils.deleteDirectory(cwd);
357 }
358
359 if (IS_OS_WINDOWS || isJavaVersionAtLeast7u60()) {
360 fail();
361 }
362 }
363
364 private File getTempClasspathFile() throws IOException {
365 File cpElement = new File(basedir, "ForkConfigurationTest." + idx + ".file");
366 FileUtils.deleteDirectory(cpElement);
367 return cpElement;
368 }
369
370 static ForkConfiguration getForkConfiguration(File basedir, String argLine) throws IOException {
371 File jvm = new File(new File(System.getProperty("java.home"), "bin"), "java");
372 return getForkConfiguration(basedir, argLine, jvm.getAbsolutePath(), new File(".").getCanonicalFile());
373 }
374
375 private ForkConfiguration getForkConfiguration(File cwd) throws IOException {
376 File jvm = new File(new File(System.getProperty("java.home"), "bin"), "java");
377 return getForkConfiguration(basedir, null, jvm.getAbsolutePath(), cwd);
378 }
379
380 private static ForkConfiguration getForkConfiguration(File basedir, String argLine, String jvm, File cwd)
381 throws IOException {
382 Platform platform = new Platform().withJdkExecAttributesForTests(new JdkAttributes(jvm, false));
383 File tmpDir = new File(new File(basedir, "target"), "surefire");
384 FileUtils.deleteDirectory(tmpDir);
385 assertTrue(tmpDir.mkdirs());
386 return new JarManifestForkConfiguration(
387 emptyClasspath(),
388 tmpDir,
389 null,
390 cwd,
391 new Properties(),
392 argLine,
393 Collections.<String, String>emptyMap(),
394 new String[0],
395 false,
396 1,
397 false,
398 platform,
399 new NullConsoleLogger(),
400 mock(ForkNodeFactory.class));
401 }
402
403
404 @SuppressWarnings("checkstyle:magicnumber")
405 private static boolean isJavaVersionAtLeast7u60() {
406 String[] javaVersionElements =
407 System.getProperty("java.runtime.version").split("\\.|_|-b");
408 return Integer.parseInt(javaVersionElements[1]) >= 7 && Integer.parseInt(javaVersionElements[3]) >= 60;
409 }
410 }