1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.buildcache;
20
21 import java.util.ArrayList;
22 import java.util.Arrays;
23 import java.util.List;
24
25 import org.apache.maven.buildcache.xml.Build;
26 import org.apache.maven.execution.ExecutionEvent;
27 import org.apache.maven.execution.MavenSession;
28 import org.apache.maven.lifecycle.DefaultLifecycles;
29 import org.apache.maven.lifecycle.Lifecycle;
30 import org.apache.maven.lifecycle.internal.stub.LifecyclesTestUtils;
31 import org.apache.maven.plugin.MojoExecution;
32 import org.apache.maven.project.MavenProject;
33 import org.jetbrains.annotations.NotNull;
34 import org.junit.jupiter.api.BeforeEach;
35 import org.junit.jupiter.api.Test;
36 import org.junit.jupiter.params.ParameterizedTest;
37 import org.junit.jupiter.params.provider.ValueSource;
38
39 import static java.util.Collections.emptyList;
40 import static java.util.Collections.singletonList;
41 import static org.assertj.core.api.Assertions.assertThat;
42 import static org.junit.jupiter.api.Assertions.assertEquals;
43 import static org.junit.jupiter.api.Assertions.assertFalse;
44 import static org.junit.jupiter.api.Assertions.assertThrows;
45 import static org.junit.jupiter.api.Assertions.assertTrue;
46 import static org.junit.jupiter.api.Assumptions.assumeTrue;
47 import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
48 import static org.mockito.Mockito.mock;
49 import static org.mockito.Mockito.when;
50
51 class LifecyclePhasesHelperTest {
52
53 private LifecyclePhasesHelper lifecyclePhasesHelper;
54 private MavenProject projectMock;
55 private DefaultLifecycles defaultLifecycles;
56 private Lifecycle cleanLifecycle;
57
58 @BeforeEach
59 void setUp() {
60
61 defaultLifecycles = LifecyclesTestUtils.createDefaultLifecycles();
62 cleanLifecycle = defaultLifecycles.getLifeCycles().stream()
63 .filter(lifecycle -> lifecycle.getId().equals("clean"))
64 .findFirst()
65 .orElseThrow(() -> new RuntimeException("Clean phase not found"));
66
67 MavenSession session = mock(MavenSession.class, RETURNS_DEEP_STUBS);
68 lifecyclePhasesHelper = new LifecyclePhasesHelper(session, defaultLifecycles, cleanLifecycle);
69
70 projectMock = mock(MavenProject.class);
71 }
72
73
74
75
76 @Test
77 void resolveHighestLifecyclePhaseNormal() {
78 String phase = lifecyclePhasesHelper.resolveHighestLifecyclePhase(
79 projectMock,
80 Arrays.asList(
81 mockedMojoExecution("clean"), mockedMojoExecution("compile"), mockedMojoExecution("install")));
82 assertEquals("install", phase);
83 }
84
85
86
87
88 @Test
89 void resolveHighestLifecyclePhaseForked() {
90
91 MojoExecution origin = mockedMojoExecution("install");
92 publishForkedProjectEvent(origin);
93
94 String phase = lifecyclePhasesHelper.resolveHighestLifecyclePhase(
95 projectMock, Arrays.asList(mockedMojoExecution(null)));
96
97 assertEquals("install", phase);
98 }
99
100
101
102
103 @Test
104 void isLaterPhaseThanClean() {
105 List<Lifecycle> afterClean = new ArrayList<>(defaultLifecycles.getLifeCycles());
106
107 assumeTrue(afterClean.remove(cleanLifecycle));
108 assumeTrue(afterClean.size() > 0);
109
110 assertTrue(afterClean.stream()
111 .flatMap(it -> it.getPhases().stream())
112 .allMatch(lifecyclePhasesHelper::isLaterPhaseThanClean));
113 }
114
115
116
117
118 @Test
119 void isLaterPhaseThanCleanNegative() {
120 assertTrue(cleanLifecycle.getPhases().stream().noneMatch(lifecyclePhasesHelper::isLaterPhaseThanClean));
121 }
122
123 @Test
124 void isLaterPhaseThanBuild() {
125 List<Lifecycle> afterClean = new ArrayList<>(defaultLifecycles.getLifeCycles());
126
127 assumeTrue(afterClean.remove(cleanLifecycle));
128 assumeTrue(afterClean.size() > 0);
129
130 Build buildMock = mock(Build.class);
131 when(buildMock.getHighestCompletedGoal()).thenReturn("clean");
132
133 assertTrue(afterClean.stream()
134 .flatMap(it -> it.getPhases().stream())
135 .allMatch(phase -> lifecyclePhasesHelper.isLaterPhaseThanBuild(phase, buildMock)));
136 }
137
138 @Test
139 void isLaterPhaseThanBuildNegative() {
140 List<Lifecycle> afterClean = new ArrayList<>(defaultLifecycles.getLifeCycles());
141
142 assumeTrue(afterClean.remove(cleanLifecycle));
143 assumeTrue(afterClean.size() > 0);
144
145 Build buildMock = mock(Build.class);
146 when(buildMock.getHighestCompletedGoal()).thenReturn("install");
147
148 assertFalse(afterClean.stream()
149 .flatMap(it -> it.getPhases().stream())
150 .allMatch(phase -> lifecyclePhasesHelper.isLaterPhaseThanBuild(phase, buildMock)));
151 }
152
153 @Test
154 void isLaterPhase() {
155 assertTrue(lifecyclePhasesHelper.isLaterPhase("install", "compile"));
156 assertTrue(lifecyclePhasesHelper.isLaterPhase("package", "clean"));
157 assertTrue(lifecyclePhasesHelper.isLaterPhase("site", "install"));
158 assertFalse(lifecyclePhasesHelper.isLaterPhase("test", "site"));
159 assertFalse(lifecyclePhasesHelper.isLaterPhase("clean", "site"));
160
161 assertThrows(IllegalArgumentException.class, () -> lifecyclePhasesHelper.isLaterPhase("install", null));
162
163 assertThrows(
164 IllegalArgumentException.class, () -> lifecyclePhasesHelper.isLaterPhase("install", "unknown phase"));
165
166 assertThrows(
167 IllegalArgumentException.class, () -> lifecyclePhasesHelper.isLaterPhase("unknown phase", "install"));
168 }
169
170 @Test
171 void getCleanSegment() {
172 MojoExecution clean = mockedMojoExecution("clean");
173 List<MojoExecution> cleanSegment = lifecyclePhasesHelper.getCleanSegment(
174 projectMock, Arrays.asList(clean, mockedMojoExecution("compile"), mockedMojoExecution("install")));
175 assertEquals(singletonList(clean), cleanSegment);
176 }
177
178
179
180
181 @Test
182 void getEmptyCleanSegment() {
183 List<MojoExecution> cleanSegment = lifecyclePhasesHelper.getCleanSegment(
184 projectMock, Arrays.asList(mockedMojoExecution("compile"), mockedMojoExecution("install")));
185 assertEquals(emptyList(), cleanSegment);
186 }
187
188
189
190
191 @Test
192 void getEmptyCleanSegmentIfForked() {
193
194 MojoExecution origin = mockedMojoExecution("install");
195 publishForkedProjectEvent(origin);
196
197 List<MojoExecution> cleanSegment = lifecyclePhasesHelper.getCleanSegment(
198 projectMock,
199 Arrays.asList(
200
201 mockedMojoExecution(null), mockedMojoExecution(null)));
202
203 assertEquals(emptyList(), cleanSegment);
204 }
205
206
207
208
209 @Test
210 void getCleanSegmentForkedAnyLifecyclePhase() {
211 MojoExecution origin = mockedMojoExecution("install");
212 publishForkedProjectEvent(origin);
213
214 List<MojoExecution> cleanSegment = lifecyclePhasesHelper.getCleanSegment(
215 projectMock,
216 Arrays.asList(
217
218 mockedMojoExecution("clean")));
219
220 assertEquals(emptyList(), cleanSegment);
221 }
222
223 @Test
224 void testCachedSegment() {
225 MojoExecution compile = mockedMojoExecution("compile");
226 MojoExecution test = mockedMojoExecution("test");
227 List<MojoExecution> mojoExecutions = Arrays.asList(compile, test, mockedMojoExecution("install"));
228
229 Build build = mock(Build.class);
230 when(build.getHighestCompletedGoal()).thenReturn("test");
231
232 List<MojoExecution> cachedSegment = lifecyclePhasesHelper.getCachedSegment(projectMock, mojoExecutions, build);
233
234 assertThat(cachedSegment).containsExactly(compile, test);
235 }
236
237 @Test
238 void testEmptyCachedSegment() {
239 MojoExecution compile = mockedMojoExecution("compile");
240 MojoExecution test = mockedMojoExecution("test");
241 MojoExecution install = mockedMojoExecution("install");
242 List<MojoExecution> mojoExecutions = Arrays.asList(compile, test, install);
243
244 Build build = mock(Build.class);
245 when(build.getHighestCompletedGoal()).thenReturn("clean");
246
247 List<MojoExecution> cachedSegment = lifecyclePhasesHelper.getCachedSegment(projectMock, mojoExecutions, build);
248
249 assertThat(cachedSegment).isEmpty();
250 }
251
252 @Test
253 void testCachedSegmentForked() {
254 MojoExecution me1 = mockedMojoExecution(null);
255 MojoExecution me2 = mockedMojoExecution(null);
256
257 List<MojoExecution> mojoExecutions = Arrays.asList(me1, me2);
258
259 MojoExecution origin = mockedMojoExecution("install");
260 publishForkedProjectEvent(origin);
261
262 Build build = mock(Build.class);
263 when(build.getHighestCompletedGoal()).thenReturn("site");
264
265 List<MojoExecution> cachedSegment = lifecyclePhasesHelper.getCachedSegment(projectMock, mojoExecutions, build);
266
267 assertEquals(mojoExecutions, cachedSegment);
268 }
269
270 @ParameterizedTest
271 @ValueSource(strings = {"install", "site"})
272 void testAllInCachedSegment() {
273 MojoExecution compile = mockedMojoExecution("compile");
274 MojoExecution test = mockedMojoExecution("test");
275 MojoExecution install = mockedMojoExecution("install");
276 List<MojoExecution> mojoExecutions = Arrays.asList(compile, test, install);
277
278 Build build = mock(Build.class);
279 when(build.getHighestCompletedGoal()).thenReturn("site");
280
281 List<MojoExecution> cachedSegment = lifecyclePhasesHelper.getCachedSegment(projectMock, mojoExecutions, build);
282
283 assertEquals(mojoExecutions, cachedSegment);
284 }
285
286 @Test
287 void testPostCachedSegment() {
288 MojoExecution compile = mockedMojoExecution("compile");
289 MojoExecution test = mockedMojoExecution("test");
290 MojoExecution install = mockedMojoExecution("install");
291 List<MojoExecution> mojoExecutions = Arrays.asList(compile, test, install);
292
293 Build build = mock(Build.class);
294 when(build.getHighestCompletedGoal()).thenReturn("compile");
295
296 List<MojoExecution> notCachedSegment =
297 lifecyclePhasesHelper.getPostCachedSegment(projectMock, mojoExecutions, build);
298
299 assertThat(notCachedSegment).containsExactly(test, install);
300 }
301
302 @Test
303 void testAllPostCachedSegment() {
304 MojoExecution compile = mockedMojoExecution("compile");
305 MojoExecution test = mockedMojoExecution("test");
306 MojoExecution install = mockedMojoExecution("install");
307 List<MojoExecution> mojoExecutions = Arrays.asList(compile, test, install);
308
309 Build build = mock(Build.class);
310 when(build.getHighestCompletedGoal()).thenReturn("clean");
311
312 List<MojoExecution> notCachedSegment =
313 lifecyclePhasesHelper.getPostCachedSegment(projectMock, mojoExecutions, build);
314
315 assertThat(notCachedSegment).isEqualTo(mojoExecutions);
316 }
317
318 @Test
319 void testPostCachedSegmentForked() {
320 MojoExecution me1 = mockedMojoExecution(null);
321 MojoExecution me2 = mockedMojoExecution(null);
322
323 List<MojoExecution> mojoExecutions = Arrays.asList(me1, me2);
324
325 MojoExecution origin = mockedMojoExecution("install");
326 publishForkedProjectEvent(origin);
327
328 Build build = mock(Build.class);
329 when(build.getHighestCompletedGoal()).thenReturn("package");
330
331 List<MojoExecution> cachedSegment =
332 lifecyclePhasesHelper.getPostCachedSegment(projectMock, mojoExecutions, build);
333
334 assertThat(cachedSegment).isEqualTo(mojoExecutions);
335 }
336
337 @ParameterizedTest
338 @ValueSource(strings = {"install", "site"})
339 void testEmptyPostCachedSegmentInclusive() {
340 MojoExecution compile = mockedMojoExecution("compile");
341 MojoExecution test = mockedMojoExecution("test");
342 MojoExecution install = mockedMojoExecution("install");
343 List<MojoExecution> mojoExecutions = Arrays.asList(compile, test, install);
344
345 Build cachedBuild = mock(Build.class);
346 when(cachedBuild.getHighestCompletedGoal()).thenReturn("install");
347
348 List<MojoExecution> notCachedSegment =
349 lifecyclePhasesHelper.getPostCachedSegment(projectMock, mojoExecutions, cachedBuild);
350
351 assertThat(notCachedSegment).isEmpty();
352 }
353
354 private void publishForkedProjectEvent(MojoExecution origin) {
355
356 ExecutionEvent eventMock = mock(ExecutionEvent.class);
357
358 when(eventMock.getProject()).thenReturn(projectMock);
359 when(eventMock.getMojoExecution()).thenReturn(origin);
360 when(eventMock.getType()).thenReturn(ExecutionEvent.Type.ForkedProjectStarted);
361
362 lifecyclePhasesHelper.forkedProjectStarted(eventMock);
363 }
364
365 @NotNull
366 private static MojoExecution mockedMojoExecution(String phase) {
367 MojoExecution mojoExecution = mock(MojoExecution.class);
368 when(mojoExecution.getLifecyclePhase()).thenReturn(phase);
369 when(mojoExecution.toString()).thenReturn(phase);
370 return mojoExecution;
371 }
372 }