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;
20
21 import java.io.File;
22 import java.lang.reflect.Method;
23 import java.nio.file.Path;
24 import java.nio.file.Paths;
25 import java.util.Collections;
26 import java.util.List;
27 import java.util.Map;
28
29 import org.apache.commons.io.FilenameUtils;
30 import org.apache.maven.execution.MavenSession;
31 import org.apache.maven.plugin.MojoFailureException;
32 import org.apache.maven.toolchain.Toolchain;
33 import org.apache.maven.toolchain.ToolchainManager;
34 import org.apache.maven.toolchain.java.DefaultJavaToolChain;
35 import org.junit.jupiter.api.Disabled;
36 import org.junit.jupiter.api.Test;
37 import org.mockito.ArgumentCaptor;
38 import org.slf4j.Logger;
39
40 import static java.io.File.separatorChar;
41 import static java.util.Collections.singletonList;
42 import static java.util.Collections.singletonMap;
43 import static org.apache.maven.surefire.booter.SystemUtils.toJdkHomeFromJre;
44 import static org.assertj.core.api.Assertions.assertThat;
45 import static org.junit.jupiter.api.Assertions.assertThrows;
46 import static org.mockito.Mockito.mock;
47 import static org.mockito.Mockito.times;
48 import static org.mockito.Mockito.verify;
49 import static org.mockito.Mockito.when;
50
51
52
53
54 public class AbstractSurefireMojoToolchainsTest {
55
56
57
58
59
60 @Test
61 public void shouldCallMethodWhenSpecSet() throws Exception {
62 AbstractSurefireMojoTest.Mojo mojo = new AbstractSurefireMojoTest.Mojo();
63 Toolchain expectedMethod = mock(Toolchain.class);
64 MockToolchainManager toolchainManager = new MockToolchainManager(expectedMethod, null);
65 mojo.setToolchainManager(toolchainManager);
66 mojo.setJdkToolchain(singletonMap("version", "1.8"));
67 Toolchain actual = invokeMethod(mojo, "getToolchain");
68 assertThat(actual).isSameAs(expectedMethod);
69 }
70
71
72
73
74
75
76 @Test
77 public void shouldFallthroughToBuildContextWhenNoSpecSet() throws Exception {
78 AbstractSurefireMojoTest.Mojo mojo = new AbstractSurefireMojoTest.Mojo();
79 Toolchain expectedFromContext = mock(Toolchain.class);
80 Toolchain expectedFromSpec = mock(Toolchain.class);
81 mojo.setToolchainManager(new MockToolchainManager(expectedFromSpec, expectedFromContext));
82 Toolchain actual = invokeMethod(mojo, "getToolchain");
83 assertThat(actual).isSameAs(expectedFromContext);
84 }
85
86
87 @Test
88 @Disabled
89 public void shouldThrowToolchain() throws Exception {
90 assertThrows(MojoFailureException.class, () -> invokeMethod(AbstractSurefireMojo.class, "getToolchain"));
91 }
92
93
94 @Test
95 @Disabled
96 public void shouldGetToolchain() throws Exception {
97 Toolchain expected = mock(Toolchain.class);
98 Toolchain actual = invokeMethod(AbstractSurefireMojo.class, "getToolchain");
99
100 assertThat(actual).isSameAs(expected);
101 }
102
103
104
105
106
107 @Test
108 public void shouldChangeJavaHomeFromToolchain() throws Exception {
109 AbstractSurefireMojoTest.Mojo mojo = new AbstractSurefireMojoTest.Mojo();
110 DefaultJavaToolChain toolchain = mock(DefaultJavaToolChain.class);
111 when(toolchain.findTool("java")).thenReturn("/path/from/toolchain");
112 when(toolchain.getJavaHome()).thenReturn("/some/path");
113 mojo.setToolchain(toolchain);
114
115 assertThat(mojo.getEnvironmentVariables()).isEmpty();
116 JdkAttributes effectiveJvm = invokeMethod(mojo, "getEffectiveJvm");
117 assertThat(mojo.getEnvironmentVariables()).containsEntry("JAVA_HOME", "/some/path");
118 assertThat(effectiveJvm.getJvmExecutable().getPath())
119 .contains("/path/from/toolchain".replace('/', separatorChar));
120 }
121
122 @Test
123 public void shouldNotChangeJavaHomeFromToolchainIfAlreadySet() throws Exception {
124 AbstractSurefireMojoTest.Mojo mojo = new AbstractSurefireMojoTest.Mojo();
125 mojo.setEnvironmentVariables(singletonMap("JAVA_HOME", "/already/set/path"));
126
127 DefaultJavaToolChain toolchain = mock(DefaultJavaToolChain.class);
128 when(toolchain.findTool("java")).thenReturn("/path/from/toolchain");
129 when(toolchain.getJavaHome()).thenReturn("/some/path");
130 mojo.setToolchain(toolchain);
131
132 JdkAttributes effectiveJvm = invokeMethod(mojo, "getEffectiveJvm");
133 assertThat(mojo.getEnvironmentVariables()).containsEntry("JAVA_HOME", "/already/set/path");
134 assertThat(effectiveJvm.getJvmExecutable().getPath())
135 .contains("/path/from/toolchain".replace('/', separatorChar));
136 }
137
138
139
140
141
142 @Test
143 public void shouldChangeJavaHomeFromJvm() throws Exception {
144 AbstractSurefireMojoTest.Mojo mojo = new AbstractSurefireMojoTest.Mojo();
145
146 File currentJdkHome = toJdkHomeFromJre();
147 String javaExecutablePath = FilenameUtils.concat(currentJdkHome.getAbsolutePath(), "bin/java");
148
149 mojo.setJvm(javaExecutablePath);
150
151 assertThat(mojo.getEnvironmentVariables()).isEmpty();
152 JdkAttributes effectiveJvm = invokeMethod(mojo, "getEffectiveJvm");
153 assertThat(mojo.getEnvironmentVariables()).containsEntry("JAVA_HOME", currentJdkHome.getAbsolutePath());
154 assertThat(effectiveJvm.getJvmExecutable().getPath()).contains(javaExecutablePath);
155 }
156
157
158
159
160
161 @Test
162 public void shouldNotChangeJavaHomeFromJvmIfAlreadySet() throws Exception {
163 AbstractSurefireMojoTest.Mojo mojo = new AbstractSurefireMojoTest.Mojo();
164 mojo.setEnvironmentVariables(singletonMap("JAVA_HOME", "/already/set/path"));
165
166 File currentJdkHome = toJdkHomeFromJre();
167 String javaExecutablePath = FilenameUtils.concat(currentJdkHome.getAbsolutePath(), "bin/java");
168
169 mojo.setJvm(javaExecutablePath);
170
171 JdkAttributes effectiveJvm = invokeMethod(mojo, "getEffectiveJvm");
172 assertThat(mojo.getEnvironmentVariables()).containsEntry("JAVA_HOME", "/already/set/path");
173 assertThat(effectiveJvm.getJvmExecutable().getPath()).contains(javaExecutablePath);
174 }
175
176 @Test
177 public void withoutJvmAndToolchain() throws Exception {
178 AbstractSurefireMojoTest.Mojo mojo = new AbstractSurefireMojoTest.Mojo();
179 Logger logger = mock(Logger.class);
180 mojo.setLogger(logger);
181 ArgumentCaptor<String> argument = ArgumentCaptor.forClass(String.class);
182 JdkAttributes effectiveJvm = invokeMethod(mojo, "getEffectiveJvm");
183
184 assertThat(mojo.getJvm()).isNull();
185
186 assertThat(mojo.getEnvironmentVariables()).isEmpty();
187
188 assertThat(effectiveJvm).isNotNull();
189
190 assertThat(effectiveJvm.getJvmExecutable()).isNotNull();
191
192 Path javaHome = Paths.get(System.getProperty("java.home")).normalize();
193 boolean isLocalJvm =
194 effectiveJvm.getJvmExecutable().toPath().normalize().startsWith(javaHome);
195 assertThat(isLocalJvm).isTrue();
196
197 verify(logger, times(1)).debug(argument.capture());
198
199 assertThat(argument.getValue()).startsWith("Using JVM: " + System.getProperty("java.home"));
200 }
201
202 @Test
203 public void shouldFailWithWrongJvmExecPath() throws Exception {
204 AbstractSurefireMojoTest.Mojo mojo = new AbstractSurefireMojoTest.Mojo();
205 mojo.setLogger(mock(Logger.class));
206 mojo.setJvm(System.getProperty("user.dir"));
207
208 MojoFailureException ex = assertThrows(MojoFailureException.class, () -> invokeMethod(mojo, "getEffectiveJvm"));
209 assertThat(ex.getMessage()).startsWith("Given path does not end with java executor");
210 }
211
212 @SuppressWarnings("unchecked")
213 private static <T> T invokeMethod(Object target, String methodName, Object... args) throws Exception {
214 Class<?> clazz = target instanceof Class ? (Class<?>) target : target.getClass();
215 while (clazz != null) {
216 for (Method method : clazz.getDeclaredMethods()) {
217 if (method.getName().equals(methodName) && method.getParameterCount() == args.length) {
218 method.setAccessible(true);
219 try {
220 return (T) method.invoke(target instanceof Class ? null : target, args);
221 } catch (java.lang.reflect.InvocationTargetException e) {
222 Throwable cause = e.getCause();
223 if (cause instanceof Exception) {
224 throw (Exception) cause;
225 }
226 throw e;
227 }
228 }
229 }
230 clazz = clazz.getSuperclass();
231 }
232 throw new NoSuchMethodException(methodName);
233 }
234
235
236
237
238 public static final class MockToolchainManager implements ToolchainManager {
239
240 private final Toolchain specToolchain;
241 private final Toolchain buildContextToolchain;
242
243 public MockToolchainManager(Toolchain specToolchain, Toolchain buildContextToolchain) {
244 this.specToolchain = specToolchain;
245 this.buildContextToolchain = buildContextToolchain;
246 }
247
248 @Override
249 public Toolchain getToolchainFromBuildContext(String type, MavenSession context) {
250 return buildContextToolchain;
251 }
252
253 @Override
254 public List<Toolchain> getToolchains(MavenSession session, String type, Map<String, String> requirements) {
255 return specToolchain == null ? Collections.<Toolchain>emptyList() : singletonList(specToolchain);
256 }
257 }
258 }