View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.plugins.assembly.archive.task;
20  
21  import java.io.File;
22  import java.io.IOException;
23  import java.util.Arrays;
24  import java.util.Collections;
25  import java.util.HashSet;
26  import java.util.Properties;
27  import java.util.Set;
28  
29  import org.apache.maven.artifact.Artifact;
30  import org.apache.maven.artifact.handler.ArtifactHandler;
31  import org.apache.maven.execution.MavenSession;
32  import org.apache.maven.model.Model;
33  import org.apache.maven.plugins.assembly.AssemblerConfigurationSource;
34  import org.apache.maven.plugins.assembly.InvalidAssemblerConfigurationException;
35  import org.apache.maven.plugins.assembly.archive.ArchiveCreationException;
36  import org.apache.maven.plugins.assembly.archive.DefaultAssemblyArchiverTest;
37  import org.apache.maven.plugins.assembly.format.AssemblyFormattingException;
38  import org.apache.maven.plugins.assembly.model.DependencySet;
39  import org.apache.maven.plugins.assembly.model.UnpackOptions;
40  import org.apache.maven.project.DefaultProjectBuildingRequest;
41  import org.apache.maven.project.MavenProject;
42  import org.apache.maven.project.ProjectBuilder;
43  import org.apache.maven.project.ProjectBuildingException;
44  import org.apache.maven.project.ProjectBuildingRequest;
45  import org.apache.maven.project.ProjectBuildingResult;
46  import org.codehaus.plexus.archiver.ArchivedFileSet;
47  import org.codehaus.plexus.archiver.Archiver;
48  import org.codehaus.plexus.archiver.ArchiverException;
49  import org.codehaus.plexus.archiver.FileSet;
50  import org.junit.jupiter.api.Test;
51  import org.junit.jupiter.api.extension.ExtendWith;
52  import org.junit.jupiter.api.io.TempDir;
53  import org.mockito.ArgumentCaptor;
54  import org.mockito.junit.jupiter.MockitoExtension;
55  import org.mockito.junit.jupiter.MockitoSettings;
56  import org.mockito.quality.Strictness;
57  
58  import static org.hamcrest.MatcherAssert.assertThat;
59  import static org.hamcrest.Matchers.is;
60  import static org.junit.jupiter.api.Assertions.assertEquals;
61  import static org.junit.jupiter.api.Assertions.assertNotNull;
62  import static org.junit.jupiter.api.Assertions.assertSame;
63  import static org.mockito.ArgumentMatchers.any;
64  import static org.mockito.ArgumentMatchers.isNull;
65  import static org.mockito.Mockito.atLeastOnce;
66  import static org.mockito.Mockito.mock;
67  import static org.mockito.Mockito.times;
68  import static org.mockito.Mockito.verify;
69  import static org.mockito.Mockito.when;
70  
71  @MockitoSettings(strictness = Strictness.WARN)
72  @ExtendWith(MockitoExtension.class)
73  public class AddDependencySetsTaskTest {
74      @TempDir
75      private File temporaryFolder;
76  
77      @Test
78      public void testAddDependencySetShouldInterpolateDefaultOutputFileNameMapping() throws Exception {
79          final String outDir = "tmp/";
80          final String mainAid = "main";
81          final String mainGid = "org.maingrp";
82          final String mainVer = "9";
83          final String depAid = "dep";
84          final String depGid = "org.depgrp";
85          final String depVer = "1";
86          final String depExt = "war";
87  
88          final DependencySet ds = new DependencySet();
89          ds.setOutputDirectory(outDir);
90          ds.setDirectoryMode(Integer.toString(10, 8));
91          ds.setFileMode(Integer.toString(10, 8));
92  
93          final Model mainModel = new Model();
94          mainModel.setArtifactId(mainAid);
95          mainModel.setGroupId(mainGid);
96          mainModel.setVersion(mainVer);
97  
98          final MavenProject mainProject = new MavenProject(mainModel);
99  
100         Artifact mainArtifact = mock(Artifact.class);
101         mainProject.setArtifact(mainArtifact);
102 
103         final Model depModel = new Model();
104         depModel.setArtifactId(depAid);
105         depModel.setGroupId(depGid);
106         depModel.setVersion(depVer);
107         depModel.setPackaging(depExt);
108 
109         final MavenProject depProject = new MavenProject(depModel);
110 
111         Artifact depArtifact = mock(Artifact.class);
112         ArtifactHandler artifactHandler = mock(ArtifactHandler.class);
113         when(artifactHandler.getExtension()).thenReturn(depExt);
114         when(depArtifact.getArtifactHandler()).thenReturn(artifactHandler);
115         final File newFile = File.createTempFile("junit", null, temporaryFolder);
116         when(depArtifact.getFile()).thenReturn(newFile);
117         when(depArtifact.getGroupId()).thenReturn("GROUPID");
118 
119         depProject.setArtifact(depArtifact);
120 
121         ProjectBuildingResult pbr = mock(ProjectBuildingResult.class);
122         when(pbr.getProject()).thenReturn(depProject);
123 
124         final ProjectBuilder projectBuilder = mock(ProjectBuilder.class);
125         when(projectBuilder.build(any(Artifact.class), any(ProjectBuildingRequest.class)))
126                 .thenReturn(pbr);
127 
128         final MavenSession session = mock(MavenSession.class);
129         when(session.getProjectBuildingRequest()).thenReturn(new DefaultProjectBuildingRequest());
130         when(session.getUserProperties()).thenReturn(new Properties());
131         when(session.getSystemProperties()).thenReturn(new Properties());
132 
133         final AssemblerConfigurationSource configSource = mock(AssemblerConfigurationSource.class);
134         when(configSource.getFinalName()).thenReturn(mainAid + "-" + mainVer);
135         when(configSource.getProject()).thenReturn(mainProject);
136         when(configSource.getMavenSession()).thenReturn(session);
137 
138         final Archiver archiver = mock(Archiver.class);
139         when(archiver.getDestFile()).thenReturn(new File("junk"));
140         when(archiver.getOverrideDirectoryMode()).thenReturn(0222);
141         when(archiver.getOverrideFileMode()).thenReturn(0222);
142 
143         DefaultAssemblyArchiverTest.setupInterpolators(configSource, mainProject);
144 
145         final AddDependencySetsTask task = new AddDependencySetsTask(
146                 Collections.singletonList(ds), Collections.singleton(depArtifact), depProject, projectBuilder);
147 
148         task.addDependencySet(ds, archiver, configSource);
149 
150         // result of easymock migration, should be assert of expected result instead of verifying methodcalls
151         verify(configSource).getFinalName();
152         verify(configSource, atLeastOnce()).getMavenSession();
153         verify(configSource, atLeastOnce()).getProject();
154 
155         verify(archiver, atLeastOnce()).getDestFile();
156         verify(archiver).addFile(newFile, outDir + depAid + "-" + depVer + "." + depExt, 10);
157         verify(archiver).getOverrideDirectoryMode();
158         verify(archiver).getOverrideFileMode();
159         verify(archiver).setDirectoryMode(10);
160         verify(archiver).setDirectoryMode(146);
161         verify(archiver).setFileMode(10);
162         verify(archiver).setFileMode(146);
163 
164         verify(session).getProjectBuildingRequest();
165         verify(session, times(2)).getUserProperties();
166         verify(session, times(2)).getSystemProperties();
167 
168         verify(projectBuilder).build(any(Artifact.class), any(ProjectBuildingRequest.class));
169     }
170 
171     @Test
172     public void testAddDependencySetShouldNotAddDependenciesWhenProjectHasNone() throws Exception {
173         final MavenProject project = new MavenProject(new Model());
174 
175         final DependencySet ds = new DependencySet();
176         ds.setOutputDirectory("/out");
177 
178         final AddDependencySetsTask task =
179                 new AddDependencySetsTask(Collections.singletonList(ds), null, project, null);
180 
181         task.addDependencySet(ds, null, null);
182     }
183 
184     // TODO: Find a better way of testing the project-stubbing behavior when a ProjectBuildingException takes place.
185     @Test
186     public void testAddDependencySetShouldNotAddDependenciesWhenProjectIsStubbed() throws Exception {
187         final MavenProject project = new MavenProject(new Model());
188 
189         final ProjectBuildingException pbe = new ProjectBuildingException("test", "Test error.", new Throwable());
190 
191         final String aid = "test-dep";
192         final String version = "2.0-SNAPSHOT";
193         final String type = "jar";
194 
195         final File file = new File("dep-artifact.jar");
196 
197         Artifact depArtifact = mock(Artifact.class);
198         when(depArtifact.getGroupId()).thenReturn("GROUPID");
199         when(depArtifact.getArtifactId()).thenReturn(aid);
200         when(depArtifact.getBaseVersion()).thenReturn(version);
201         when(depArtifact.getFile()).thenReturn(file);
202         ArtifactHandler artifactHandler = mock(ArtifactHandler.class);
203         when(artifactHandler.getExtension()).thenReturn(type);
204         when(depArtifact.getArtifactHandler()).thenReturn(artifactHandler);
205 
206         final File destFile = new File("assembly-dep-set.zip");
207 
208         final Archiver archiver = mock(Archiver.class);
209         when(archiver.getDestFile()).thenReturn(destFile);
210         when(archiver.getOverrideDirectoryMode()).thenReturn(0222);
211         when(archiver.getOverrideFileMode()).thenReturn(0222);
212 
213         final ProjectBuilder projectBuilder = mock(ProjectBuilder.class);
214         when(projectBuilder.build(any(Artifact.class), any(ProjectBuildingRequest.class)))
215                 .thenThrow(pbe);
216 
217         final MavenSession session = mock(MavenSession.class);
218         when(session.getProjectBuildingRequest()).thenReturn(new DefaultProjectBuildingRequest());
219         when(session.getUserProperties()).thenReturn(new Properties());
220         when(session.getSystemProperties()).thenReturn(new Properties());
221 
222         final AssemblerConfigurationSource configSource = mock(AssemblerConfigurationSource.class);
223         when(configSource.getFinalName()).thenReturn("final-name");
224         when(configSource.getMavenSession()).thenReturn(session);
225         when(configSource.getProject()).thenReturn(project);
226 
227         final DependencySet ds = new DependencySet();
228         ds.setOutputDirectory("/out");
229         DefaultAssemblyArchiverTest.setupInterpolators(configSource, project);
230 
231         final AddDependencySetsTask task = new AddDependencySetsTask(
232                 Collections.singletonList(ds), Collections.singleton(depArtifact), project, projectBuilder);
233 
234         task.addDependencySet(ds, archiver, configSource);
235 
236         // result of easymock migration, should be assert of expected result instead of verifying methodcalls
237         verify(configSource).getFinalName();
238         verify(configSource, atLeastOnce()).getMavenSession();
239         verify(configSource, atLeastOnce()).getProject();
240 
241         verify(archiver).addFile(file, "out/" + aid + "-" + version + "." + type);
242         verify(archiver, atLeastOnce()).getDestFile();
243         verify(archiver).getOverrideDirectoryMode();
244         verify(archiver).getOverrideFileMode();
245 
246         verify(session).getProjectBuildingRequest();
247         verify(session, times(2)).getUserProperties();
248         verify(session, times(2)).getSystemProperties();
249 
250         verify(projectBuilder).build(any(Artifact.class), any(ProjectBuildingRequest.class));
251     }
252 
253     @Test
254     public void testAddDependencySetShouldAddOneDependencyFromProjectWithoutUnpacking() throws Exception {
255         verifyOneDependencyAdded("out", false);
256     }
257 
258     @Test
259     public void testAddDependencySetShouldAddOneDependencyFromProjectUnpacked() throws Exception {
260         verifyOneDependencyAdded("out", true);
261     }
262 
263     private void verifyOneDependencyAdded(final String outputLocation, final boolean unpack)
264             throws AssemblyFormattingException, ArchiverException, ArchiveCreationException, IOException,
265                     InvalidAssemblerConfigurationException, ProjectBuildingException {
266         final MavenProject project = new MavenProject(new Model());
267 
268         final DependencySet ds = new DependencySet();
269         ds.setOutputDirectory(outputLocation);
270         ds.setOutputFileNameMapping("artifact");
271         ds.setUnpack(unpack);
272         ds.setScope(Artifact.SCOPE_COMPILE);
273 
274         ds.setDirectoryMode(Integer.toString(10, 8));
275         ds.setFileMode(Integer.toString(10, 8));
276 
277         final MavenSession session = mock(MavenSession.class);
278         when(session.getProjectBuildingRequest()).thenReturn(new DefaultProjectBuildingRequest());
279         when(session.getUserProperties()).thenReturn(new Properties());
280         when(session.getSystemProperties()).thenReturn(new Properties());
281 
282         final AssemblerConfigurationSource configSource = mock(AssemblerConfigurationSource.class);
283         when(configSource.getMavenSession()).thenReturn(session);
284         when(configSource.getFinalName()).thenReturn("final-name");
285 
286         Artifact artifact = mock(Artifact.class);
287         final File artifactFile = File.createTempFile("junit", null, temporaryFolder);
288         when(artifact.getFile()).thenReturn(artifactFile);
289         when(artifact.getGroupId()).thenReturn("GROUPID");
290 
291         final Archiver archiver = mock(Archiver.class);
292         when(archiver.getDestFile()).thenReturn(new File("junk"));
293         when(archiver.getOverrideDirectoryMode()).thenReturn(0222);
294         when(archiver.getOverrideFileMode()).thenReturn(0222);
295 
296         if (!unpack) {
297             when(configSource.getProject()).thenReturn(project);
298         }
299 
300         final MavenProject depProject = new MavenProject(new Model());
301         depProject.setGroupId("GROUPID");
302 
303         ProjectBuildingResult pbr = mock(ProjectBuildingResult.class);
304         when(pbr.getProject()).thenReturn(depProject);
305 
306         final ProjectBuilder projectBuilder = mock(ProjectBuilder.class);
307         when(projectBuilder.build(any(Artifact.class), any(ProjectBuildingRequest.class)))
308                 .thenReturn(pbr);
309 
310         final AddDependencySetsTask task = new AddDependencySetsTask(
311                 Collections.singletonList(ds), Collections.singleton(artifact), project, projectBuilder);
312         DefaultAssemblyArchiverTest.setupInterpolators(configSource, project);
313 
314         task.addDependencySet(ds, archiver, configSource);
315 
316         // result of easymock migration, should be assert of expected result instead of verifying methodcalls
317         verify(configSource).getFinalName();
318         verify(configSource, atLeastOnce()).getMavenSession();
319 
320         verify(archiver, atLeastOnce()).getDestFile();
321         verify(archiver).getOverrideDirectoryMode();
322         verify(archiver).getOverrideFileMode();
323         verify(archiver).setFileMode(10);
324         verify(archiver).setFileMode(146);
325         verify(archiver).setDirectoryMode(10);
326         verify(archiver).setDirectoryMode(146);
327 
328         verify(session).getProjectBuildingRequest();
329         verify(session, atLeastOnce()).getUserProperties();
330         verify(session, atLeastOnce()).getSystemProperties();
331 
332         verify(projectBuilder).build(any(Artifact.class), any(ProjectBuildingRequest.class));
333 
334         if (unpack) {
335             verify(archiver).addArchivedFileSet(any(ArchivedFileSet.class), isNull());
336         } else {
337             verify(archiver).addFile(artifactFile, outputLocation + "/artifact", 10);
338             verify(configSource, atLeastOnce()).getProject();
339         }
340     }
341 
342     @Test
343     public void testGetDependencyArtifactsShouldGetOneDependencyArtifact() throws Exception {
344         final MavenProject project = new MavenProject(new Model());
345 
346         Artifact artifact = mock(Artifact.class);
347         project.setArtifacts(Collections.singleton(artifact));
348 
349         final DependencySet dependencySet = new DependencySet();
350 
351         final AddDependencySetsTask task = new AddDependencySetsTask(
352                 Collections.singletonList(dependencySet), Collections.singleton(artifact), project, null);
353 
354         final Set<Artifact> result = task.resolveDependencyArtifacts(dependencySet);
355 
356         assertNotNull(result);
357         assertEquals(1, result.size());
358         assertSame(artifact, result.iterator().next());
359     }
360 
361     @Test
362     public void testGetDependencyArtifactsShouldFilterOneDependencyArtifactViaInclude() throws Exception {
363         final MavenProject project = new MavenProject(new Model());
364 
365         final Set<Artifact> artifacts = new HashSet<>();
366 
367         Artifact am1 = mock(Artifact.class);
368         when(am1.getGroupId()).thenReturn("group");
369         when(am1.getArtifactId()).thenReturn("artifact");
370         artifacts.add(am1);
371 
372         Artifact am2 = mock(Artifact.class);
373         when(am2.getGroupId()).thenReturn("group2");
374         when(am2.getId()).thenReturn("group2:artifact2:1.0:jar");
375         artifacts.add(am2);
376 
377         final DependencySet dependencySet = new DependencySet();
378 
379         dependencySet.addInclude("group:artifact");
380         dependencySet.setUseTransitiveFiltering(true);
381 
382         final AddDependencySetsTask task =
383                 new AddDependencySetsTask(Collections.singletonList(dependencySet), artifacts, project, null);
384 
385         final Set<Artifact> result = task.resolveDependencyArtifacts(dependencySet);
386 
387         assertNotNull(result);
388         assertEquals(1, result.size());
389         assertSame(am1, result.iterator().next());
390     }
391 
392     @Test
393     public void testGetDependencyArtifactsShouldIgnoreTransitivePathFilteringWhenIncludeNotTransitive()
394             throws Exception {
395         final MavenProject project = new MavenProject(new Model());
396 
397         final Set<Artifact> artifacts = new HashSet<>();
398 
399         Artifact am1 = mock(Artifact.class);
400         when(am1.getGroupId()).thenReturn("group");
401         when(am1.getArtifactId()).thenReturn("artifact");
402         artifacts.add(am1);
403 
404         Artifact am2 = mock(Artifact.class);
405         when(am2.getGroupId()).thenReturn("group2");
406         when(am2.getId()).thenReturn("group2:artifact2:1.0:jar");
407         artifacts.add(am2);
408 
409         final DependencySet dependencySet = new DependencySet();
410 
411         dependencySet.addInclude("group:artifact");
412         dependencySet.setUseTransitiveFiltering(false);
413 
414         final AddDependencySetsTask task =
415                 new AddDependencySetsTask(Collections.singletonList(dependencySet), artifacts, project, null);
416 
417         final Set<Artifact> result = task.resolveDependencyArtifacts(dependencySet);
418 
419         assertNotNull(result);
420         assertEquals(1, result.size());
421         assertSame(am1, result.iterator().next());
422     }
423 
424     // MASSEMBLY-879
425     @Test
426     public void useDefaultExcludes() throws Exception {
427         Artifact zipArtifact = mock(Artifact.class);
428         when(zipArtifact.getGroupId()).thenReturn("some-artifact");
429         when(zipArtifact.getArtifactId()).thenReturn("of-type-zip");
430         when(zipArtifact.getId()).thenReturn("some-artifact:of-type-zip:1.0:zip");
431         when(zipArtifact.getFile()).thenReturn(newFile(temporaryFolder, "of-type-zip.zip"));
432 
433         Artifact dirArtifact = mock(Artifact.class);
434         when(dirArtifact.getGroupId()).thenReturn("some-artifact");
435         when(dirArtifact.getArtifactId()).thenReturn("of-type-zip");
436         when(dirArtifact.getId()).thenReturn("some-artifact:of-type-zip:1.0:dir");
437         when(dirArtifact.getFile()).thenReturn(newFolder(temporaryFolder, "of-type-zip"));
438 
439         final Set<Artifact> artifacts = new HashSet<>(Arrays.asList(zipArtifact, dirArtifact));
440 
441         final DependencySet dependencySet = new DependencySet();
442         dependencySet.setUseProjectArtifact(false);
443         dependencySet.setIncludes(Collections.singletonList("some-artifact:of-type-zip"));
444         dependencySet.setOutputDirectory("MyOutputDir");
445         dependencySet.setUnpack(true);
446         UnpackOptions unpackOptions = new UnpackOptions();
447         unpackOptions.setUseDefaultExcludes(false);
448         dependencySet.setUnpackOptions(unpackOptions);
449 
450         final MavenProject project = new MavenProject(new Model());
451         project.setGroupId("GROUPID");
452 
453         ProjectBuildingRequest pbReq = new DefaultProjectBuildingRequest();
454         ProjectBuildingResult pbRes = mock(ProjectBuildingResult.class);
455         when(pbRes.getProject()).thenReturn(project);
456 
457         final ProjectBuilder projectBuilder = mock(ProjectBuilder.class);
458         when(projectBuilder.build(any(Artifact.class), any(ProjectBuildingRequest.class)))
459                 .thenReturn(pbRes);
460 
461         final AddDependencySetsTask task =
462                 new AddDependencySetsTask(Collections.singletonList(dependencySet), artifacts, project, projectBuilder);
463 
464         final MavenSession session = mock(MavenSession.class);
465         when(session.getProjectBuildingRequest()).thenReturn(pbReq);
466 
467         final AssemblerConfigurationSource configSource = mock(AssemblerConfigurationSource.class);
468         when(configSource.getMavenSession()).thenReturn(session);
469         DefaultAssemblyArchiverTest.setupInterpolators(configSource, project);
470 
471         final Archiver archiver = mock(Archiver.class);
472 
473         task.addDependencySet(dependencySet, archiver, configSource);
474 
475         ArgumentCaptor<ArchivedFileSet> archivedFileSet = ArgumentCaptor.forClass(ArchivedFileSet.class);
476         verify(archiver).addArchivedFileSet(archivedFileSet.capture(), isNull());
477         assertThat(archivedFileSet.getValue().isUsingDefaultExcludes(), is(false));
478 
479         ArgumentCaptor<FileSet> fileSet = ArgumentCaptor.forClass(FileSet.class);
480         verify(archiver).addFileSet(fileSet.capture());
481         assertThat(fileSet.getValue().isUsingDefaultExcludes(), is(false));
482     }
483 
484     private static File newFile(File parent, String child) throws IOException {
485         File result = new File(parent, child);
486         result.createNewFile();
487         return result;
488     }
489 
490     private static File newFolder(File root, String... subDirs) throws IOException {
491         String subFolder = String.join("/", subDirs);
492         File result = new File(root, subFolder);
493         if (!result.mkdirs()) {
494             throw new IOException("Couldn't create folders " + root);
495         }
496         return result;
497     }
498 }