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.project;
20  
21  import java.io.File;
22  import java.nio.file.Path;
23  import java.util.ArrayList;
24  import java.util.Collections;
25  import java.util.List;
26  import java.util.Properties;
27  import java.util.concurrent.atomic.AtomicInteger;
28  
29  import org.apache.commons.io.FileUtils;
30  import org.apache.maven.AbstractCoreMavenComponentTestCase;
31  import org.apache.maven.execution.MavenSession;
32  import org.apache.maven.model.Dependency;
33  import org.apache.maven.model.InputLocation;
34  import org.apache.maven.model.Plugin;
35  import org.apache.maven.model.building.FileModelSource;
36  import org.apache.maven.model.building.ModelBuildingRequest;
37  import org.apache.maven.model.building.ModelProblem;
38  import org.apache.maven.model.building.ModelSource;
39  import org.junit.jupiter.api.Test;
40  import org.junit.jupiter.api.io.TempDir;
41  
42  import static org.apache.maven.project.ProjectBuildingResultWithLocationMatcher.projectBuildingResultWithLocation;
43  import static org.apache.maven.project.ProjectBuildingResultWithProblemMessageMatcher.projectBuildingResultWithProblemMessage;
44  import static org.hamcrest.MatcherAssert.assertThat;
45  import static org.hamcrest.Matchers.contains;
46  import static org.hamcrest.Matchers.containsString;
47  import static org.hamcrest.Matchers.empty;
48  import static org.hamcrest.Matchers.greaterThan;
49  import static org.hamcrest.Matchers.hasKey;
50  import static org.hamcrest.Matchers.is;
51  import static org.junit.jupiter.api.Assertions.assertEquals;
52  import static org.junit.jupiter.api.Assertions.assertNotNull;
53  import static org.junit.jupiter.api.Assertions.assertThrows;
54  import static org.junit.jupiter.api.Assertions.assertTrue;
55  
56  public class ProjectBuilderTest extends AbstractCoreMavenComponentTestCase {
57      @Override
58      protected String getProjectsDirectory() {
59          return "src/test/projects/project-builder";
60      }
61  
62      @Test
63      public void testSystemScopeDependencyIsPresentInTheCompileClasspathElements() throws Exception {
64          File pom = getProject("it0063");
65  
66          Properties eps = new Properties();
67          eps.setProperty("jre.home", new File(pom.getParentFile(), "jdk/jre").getPath());
68  
69          MavenSession session = createMavenSession(pom, eps);
70          MavenProject project = session.getCurrentProject();
71  
72          // Here we will actually not have any artifacts because the ProjectDependenciesResolver is not involved here. So
73          // right now it's not valid to ask for artifacts unless plugins require the artifacts.
74  
75          project.getCompileClasspathElements();
76      }
77  
78      @Test
79      public void testBuildFromModelSource() throws Exception {
80          File pomFile = new File("src/test/resources/projects/modelsource/module01/pom.xml");
81          MavenSession mavenSession = createMavenSession(pomFile);
82          ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
83          configuration.setRepositorySession(mavenSession.getRepositorySession());
84          ModelSource modelSource = new FileModelSource(pomFile);
85          ProjectBuildingResult result = getContainer()
86                  .lookup(org.apache.maven.project.ProjectBuilder.class)
87                  .build(modelSource, configuration);
88  
89          assertNotNull(result.getProject().getParentFile());
90      }
91  
92      @Test
93      public void testVersionlessManagedDependency() throws Exception {
94          File pomFile = new File("src/test/resources/projects/versionless-managed-dependency.xml");
95          MavenSession mavenSession = createMavenSession(null);
96          ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
97          configuration.setRepositorySession(mavenSession.getRepositorySession());
98  
99          ProjectBuildingException e = assertThrows(ProjectBuildingException.class, () -> getContainer()
100                 .lookup(org.apache.maven.project.ProjectBuilder.class)
101                 .build(pomFile, configuration));
102         assertThat(
103                 e.getResults(),
104                 contains(projectBuildingResultWithProblemMessage(
105                         "'dependencies.dependency.version' for org.apache.maven.its:a:jar is missing")));
106         assertThat(e.getResults(), contains(projectBuildingResultWithLocation(17, 9)));
107     }
108 
109     @Test
110     public void testResolveDependencies() throws Exception {
111         File pomFile = new File("src/test/resources/projects/basic-resolveDependencies.xml");
112         MavenSession mavenSession = createMavenSession(null);
113         ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
114         configuration.setRepositorySession(mavenSession.getRepositorySession());
115         configuration.setResolveDependencies(true);
116 
117         // single project build entry point
118         ProjectBuildingResult result = getContainer()
119                 .lookup(org.apache.maven.project.ProjectBuilder.class)
120                 .build(pomFile, configuration);
121         assertEquals(1, result.getProject().getArtifacts().size());
122         // multi projects build entry point
123         List<ProjectBuildingResult> results = getContainer()
124                 .lookup(org.apache.maven.project.ProjectBuilder.class)
125                 .build(Collections.singletonList(pomFile), false, configuration);
126         assertEquals(1, results.size());
127         MavenProject mavenProject = results.get(0).getProject();
128         assertEquals(1, mavenProject.getArtifacts().size());
129 
130         final MavenProject project = mavenProject;
131         final AtomicInteger artifactsResultInAnotherThread = new AtomicInteger();
132         Thread t = new Thread(new Runnable() {
133             @Override
134             public void run() {
135                 artifactsResultInAnotherThread.set(project.getArtifacts().size());
136             }
137         });
138         t.start();
139         t.join();
140         assertEquals(project.getArtifacts().size(), artifactsResultInAnotherThread.get());
141     }
142 
143     @Test
144     public void testDontResolveDependencies() throws Exception {
145         File pomFile = new File("src/test/resources/projects/basic-resolveDependencies.xml");
146         MavenSession mavenSession = createMavenSession(null);
147         ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
148         configuration.setRepositorySession(mavenSession.getRepositorySession());
149         configuration.setResolveDependencies(false);
150 
151         // single project build entry point
152         ProjectBuildingResult result = getContainer()
153                 .lookup(org.apache.maven.project.ProjectBuilder.class)
154                 .build(pomFile, configuration);
155         assertEquals(0, result.getProject().getArtifacts().size());
156         // multi projects build entry point
157         List<ProjectBuildingResult> results = getContainer()
158                 .lookup(org.apache.maven.project.ProjectBuilder.class)
159                 .build(Collections.singletonList(pomFile), false, configuration);
160         assertEquals(1, results.size());
161         MavenProject mavenProject = results.get(0).getProject();
162         assertEquals(0, mavenProject.getArtifacts().size());
163     }
164 
165     @Test
166     public void testReadModifiedPoms(@TempDir Path tempDir) throws Exception {
167         // TODO a similar test should be created to test the dependency management (basically all usages
168         // of DefaultModelBuilder.getCache() are affected by MNG-6530
169 
170         FileUtils.copyDirectory(new File("src/test/resources/projects/grandchild-check"), tempDir.toFile());
171         MavenSession mavenSession = createMavenSession(null);
172         ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
173         configuration.setRepositorySession(mavenSession.getRepositorySession());
174         org.apache.maven.project.ProjectBuilder projectBuilder =
175                 getContainer().lookup(org.apache.maven.project.ProjectBuilder.class);
176         File child = new File(tempDir.toFile(), "child/pom.xml");
177         // build project once
178         projectBuilder.build(child, configuration);
179         // modify parent
180         File parent = new File(tempDir.toFile(), "pom.xml");
181         String parentContent = FileUtils.readFileToString(parent, "UTF-8");
182         parentContent = parentContent.replaceAll(
183                 "<packaging>pom</packaging>",
184                 "<packaging>pom</packaging><properties><addedProperty>addedValue</addedProperty></properties>");
185         FileUtils.write(parent, parentContent, "UTF-8");
186         // re-build pom with modified parent
187         ProjectBuildingResult result = projectBuilder.build(child, configuration);
188         assertThat(result.getProject().getProperties(), hasKey((Object) "addedProperty"));
189     }
190 
191     @Test
192     public void testReadErroneousMavenProjectContainsReference() throws Exception {
193         File pomFile = new File("src/test/resources/projects/artifactMissingVersion.xml").getAbsoluteFile();
194         MavenSession mavenSession = createMavenSession(null);
195         ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
196         configuration.setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL);
197         configuration.setRepositorySession(mavenSession.getRepositorySession());
198         org.apache.maven.project.ProjectBuilder projectBuilder =
199                 getContainer().lookup(org.apache.maven.project.ProjectBuilder.class);
200 
201         // single project build entry point
202         ProjectBuildingException ex1 =
203                 assertThrows(ProjectBuildingException.class, () -> projectBuilder.build(pomFile, configuration));
204 
205         assertEquals(1, ex1.getResults().size());
206         MavenProject project1 = ex1.getResults().get(0).getProject();
207         assertNotNull(project1);
208         assertEquals("testArtifactMissingVersion", project1.getArtifactId());
209         assertEquals(pomFile, project1.getFile());
210 
211         // multi projects build entry point
212         ProjectBuildingException ex2 = assertThrows(
213                 ProjectBuildingException.class,
214                 () -> projectBuilder.build(Collections.singletonList(pomFile), false, configuration));
215 
216         assertEquals(1, ex2.getResults().size());
217         MavenProject project2 = ex2.getResults().get(0).getProject();
218         assertNotNull(project2);
219         assertEquals("testArtifactMissingVersion", project2.getArtifactId());
220         assertEquals(pomFile, project2.getFile());
221     }
222 
223     @Test
224     public void testReadInvalidPom() throws Exception {
225         File pomFile = new File("src/test/resources/projects/badPom.xml").getAbsoluteFile();
226         MavenSession mavenSession = createMavenSession(null);
227         ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
228         configuration.setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL);
229         configuration.setRepositorySession(mavenSession.getRepositorySession());
230         org.apache.maven.project.ProjectBuilder projectBuilder =
231                 getContainer().lookup(org.apache.maven.project.ProjectBuilder.class);
232 
233         // single project build entry point
234         Exception ex = assertThrows(Exception.class, () -> projectBuilder.build(pomFile, configuration));
235         assertThat(ex.getMessage(), containsString("expected START_TAG or END_TAG not TEXT"));
236 
237         // multi projects build entry point
238         ProjectBuildingException pex = assertThrows(
239                 ProjectBuildingException.class,
240                 () -> projectBuilder.build(Collections.singletonList(pomFile), false, configuration));
241         assertEquals(1, pex.getResults().size());
242         assertNotNull(pex.getResults().get(0).getPomFile());
243         assertThat(pex.getResults().get(0).getProblems().size(), greaterThan(0));
244         assertThat(
245                 pex.getResults(),
246                 contains(projectBuildingResultWithProblemMessage("expected START_TAG or END_TAG not TEXT")));
247     }
248 
249     @Test
250     public void testReadParentAndChildWithRegularVersionSetParentFile() throws Exception {
251         List<File> toRead = new ArrayList<>(2);
252         File parentPom = getProject("MNG-6723");
253         toRead.add(parentPom);
254         toRead.add(new File(parentPom.getParentFile(), "child/pom.xml"));
255         MavenSession mavenSession = createMavenSession(null);
256         ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
257         configuration.setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL);
258         configuration.setRepositorySession(mavenSession.getRepositorySession());
259         org.apache.maven.project.ProjectBuilder projectBuilder =
260                 getContainer().lookup(org.apache.maven.project.ProjectBuilder.class);
261 
262         // read poms separately
263         boolean parentFileWasFoundOnChild = false;
264         for (File file : toRead) {
265             List<ProjectBuildingResult> results =
266                     projectBuilder.build(Collections.singletonList(file), false, configuration);
267             assertResultShowNoError(results);
268             MavenProject project = findChildProject(results);
269             if (project != null) {
270                 assertEquals(parentPom, project.getParentFile());
271                 parentFileWasFoundOnChild = true;
272             }
273         }
274         assertTrue(parentFileWasFoundOnChild);
275 
276         // read projects together
277         List<ProjectBuildingResult> results = projectBuilder.build(toRead, false, configuration);
278         assertResultShowNoError(results);
279         assertEquals(parentPom, findChildProject(results).getParentFile());
280         Collections.reverse(toRead);
281         results = projectBuilder.build(toRead, false, configuration);
282         assertResultShowNoError(results);
283         assertEquals(parentPom, findChildProject(results).getParentFile());
284     }
285 
286     private MavenProject findChildProject(List<ProjectBuildingResult> results) {
287         for (ProjectBuildingResult result : results) {
288             if (result.getPomFile().getParentFile().getName().equals("child")) {
289                 return result.getProject();
290             }
291         }
292         return null;
293     }
294 
295     private void assertResultShowNoError(List<ProjectBuildingResult> results) {
296         for (ProjectBuildingResult result : results) {
297             assertThat(result.getProblems(), is(empty()));
298             assertNotNull(result.getProject());
299         }
300     }
301 
302     @Test
303     public void testBuildProperties() throws Exception {
304         File file = new File(getProject("MNG-6716").getParentFile(), "project/pom.xml");
305         MavenSession mavenSession = createMavenSession(null);
306         ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
307         configuration.setRepositorySession(mavenSession.getRepositorySession());
308         configuration.setResolveDependencies(true);
309         List<ProjectBuildingResult> result = projectBuilder.build(Collections.singletonList(file), true, configuration);
310         MavenProject project = result.get(0).getProject();
311         // verify a few typical parameters are not duplicated
312         assertEquals(1, project.getTestCompileSourceRoots().size());
313         assertEquals(1, project.getCompileSourceRoots().size());
314         assertEquals(1, project.getMailingLists().size());
315         assertEquals(1, project.getResources().size());
316     }
317 
318     @Test
319     public void testPropertyInPluginManagementGroupId() throws Exception {
320         File pom = getProject("MNG-6983");
321 
322         MavenSession session = createMavenSession(pom);
323         MavenProject project = session.getCurrentProject();
324 
325         for (Plugin buildPlugin : project.getBuildPlugins()) {
326             assertNotNull(buildPlugin.getVersion(), "Missing version for build plugin " + buildPlugin.getKey());
327         }
328     }
329 
330     @Test
331     public void testBuildFromModelSourceResolvesBasedir() throws Exception {
332         File pomFile = new File("src/test/resources/projects/modelsourcebasedir/pom.xml");
333         MavenSession mavenSession = createMavenSession(null);
334         ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
335         configuration.setRepositorySession(mavenSession.getRepositorySession());
336         ModelSource modelSource = new FileModelSource(pomFile);
337         ProjectBuildingResult result = getContainer()
338                 .lookup(org.apache.maven.project.ProjectBuilder.class)
339                 .build(modelSource, configuration);
340 
341         assertEquals(
342                 pomFile.getAbsoluteFile(),
343                 result.getProject().getModel().getPomFile().getAbsoluteFile());
344         int errors = 0;
345         for (ModelProblem p : result.getProblems()) {
346             if (p.getSeverity() == ModelProblem.Severity.ERROR) {
347                 errors++;
348             }
349         }
350         assertEquals(0, errors);
351     }
352 
353     @Test
354     public void testLocationTrackingResolution() throws Exception {
355         File pom = getProject("MNG-7648");
356 
357         MavenSession session = createMavenSession(pom);
358         MavenProject project = session.getCurrentProject();
359 
360         InputLocation dependencyLocation = null;
361         for (Dependency dependency : project.getDependencies()) {
362             if (dependency.getManagementKey().equals("org.apache.maven.its:a:jar")) {
363                 dependencyLocation = dependency.getLocation("version");
364             }
365         }
366         assertNotNull(dependencyLocation, "missing dependency");
367         assertEquals(
368                 "org.apache.maven.its:bom:0.1", dependencyLocation.getSource().getModelId());
369 
370         InputLocation pluginLocation = null;
371         for (Plugin plugin : project.getBuildPlugins()) {
372             if (plugin.getKey().equals("org.apache.maven.plugins:maven-clean-plugin")) {
373                 pluginLocation = plugin.getLocation("version");
374             }
375         }
376         assertNotNull(pluginLocation, "missing build plugin");
377         assertEquals(
378                 "org.apache.maven.its:parent:0.1", pluginLocation.getSource().getModelId());
379     }
380 }