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.io.InputStream;
23  import java.nio.file.Files;
24  import java.nio.file.Path;
25  import java.nio.file.StandardCopyOption;
26  import java.util.List;
27  
28  import org.apache.maven.artifact.Artifact;
29  import org.apache.maven.artifact.repository.ArtifactRepository;
30  import org.junit.jupiter.api.BeforeEach;
31  import org.junit.jupiter.api.Disabled;
32  import org.junit.jupiter.api.Test;
33  import org.junit.jupiter.api.io.TempDir;
34  
35  import static org.apache.maven.project.ProjectBuildingResultWithProblemMessageMatcher.projectBuildingResultWithProblemMessage;
36  import static org.codehaus.plexus.testing.PlexusExtension.getTestFile;
37  import static org.hamcrest.MatcherAssert.assertThat;
38  import static org.hamcrest.Matchers.contains;
39  import static org.hamcrest.Matchers.containsString;
40  import static org.hamcrest.Matchers.is;
41  import static org.junit.jupiter.api.Assertions.assertEquals;
42  import static org.junit.jupiter.api.Assertions.assertFalse;
43  import static org.junit.jupiter.api.Assertions.assertNotNull;
44  import static org.junit.jupiter.api.Assertions.assertNull;
45  import static org.junit.jupiter.api.Assertions.assertThrows;
46  import static org.junit.jupiter.api.Assertions.assertTrue;
47  import static org.junit.jupiter.api.Assertions.fail;
48  
49  class DefaultMavenProjectBuilderTest extends AbstractMavenProjectTestCase {
50      @TempDir
51      File localRepoDir;
52  
53      // only use by reread()
54      @TempDir
55      Path projectRoot;
56  
57      @Override
58      @BeforeEach
59      public void setUp() throws Exception {
60          projectBuilder = getContainer().lookup(ProjectBuilder.class);
61      }
62  
63      protected MavenProject getProject(Artifact pom, boolean allowStub) throws Exception {
64          ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
65          configuration.setLocalRepository(getLocalRepository());
66          initRepoSession(configuration);
67  
68          return projectBuilder.build(pom, allowStub, configuration).getProject();
69      }
70  
71      /**
72       * Check that we can build ok from the middle pom of a (parent,child,grandchild) hierarchy
73       *
74       * @throws Exception in case of issue
75       */
76      @Test
77      void testBuildFromMiddlePom() throws Exception {
78          File f1 = getTestFile("src/test/resources/projects/grandchild-check/child/pom.xml");
79          File f2 = getTestFile("src/test/resources/projects/grandchild-check/child/grandchild/pom.xml");
80  
81          getProject(f1);
82  
83          // it's the building of the grandchild project, having already cached the child project
84          // (but not the parent project), which causes the problem.
85          getProject(f2);
86      }
87  
88      @Disabled("Maven 4 does not allow duplicate plugin declarations")
89      @Test
90      void testDuplicatePluginDefinitionsMerged() throws Exception {
91          File f1 = getTestFile("src/test/resources/projects/duplicate-plugins-merged-pom.xml");
92  
93          MavenProject project = getProject(f1);
94          assertEquals(2, project.getBuildPlugins().get(0).getDependencies().size());
95          assertEquals(2, project.getBuildPlugins().get(0).getExecutions().size());
96          assertEquals(
97                  "first", project.getBuildPlugins().get(0).getExecutions().get(0).getId());
98      }
99  
100     @Test
101     void testFutureModelVersion() throws Exception {
102         File f1 = getTestFile("src/test/resources/projects/future-model-version-pom.xml");
103 
104         ProjectBuildingException e = assertThrows(
105                 ProjectBuildingException.class, () -> getProject(f1), "Expected to fail for future versions");
106         assertThat(e.getMessage(), containsString("Building this project requires a newer version of Maven"));
107     }
108 
109     @Test
110     void testPastModelVersion() throws Exception {
111         // a Maven 1.x pom will not even
112         // update the resource if we stop supporting modelVersion 4.0.0
113         File f1 = getTestFile("src/test/resources/projects/past-model-version-pom.xml");
114 
115         ProjectBuildingException e = assertThrows(
116                 ProjectBuildingException.class, () -> getProject(f1), "Expected to fail for past versions");
117         assertThat(e.getMessage(), containsString("Building this project requires an older version of Maven"));
118     }
119 
120     @Test
121     void testFutureSchemaModelVersion() throws Exception {
122         File f1 = getTestFile("src/test/resources/projects/future-schema-model-version-pom.xml");
123 
124         ProjectBuildingException e = assertThrows(
125                 ProjectBuildingException.class, () -> getProject(f1), "Expected to fail for future versions");
126         assertThat(e.getMessage(), containsString("Building this project requires a newer version of Maven"));
127     }
128 
129     @Test
130     void testBuildStubModelForMissingRemotePom() throws Exception {
131         Artifact pom = repositorySystem.createProjectArtifact("org.apache.maven.its", "missing", "0.1");
132         MavenProject project = getProject(pom, true);
133 
134         assertNotNull(project.getArtifactId());
135 
136         assertNotNull(project.getRemoteArtifactRepositories());
137         assertTrue(project.getRemoteArtifactRepositories().isEmpty());
138 
139         assertNotNull(project.getPluginArtifactRepositories());
140         assertTrue(project.getPluginArtifactRepositories().isEmpty());
141 
142         assertNull(project.getParent());
143         assertNull(project.getParentArtifact());
144 
145         assertFalse(project.isExecutionRoot());
146     }
147 
148     @Override
149     protected ArtifactRepository getLocalRepository() throws Exception {
150         return repositorySystem.createLocalRepository(getLocalRepositoryPath());
151     }
152 
153     @Test
154     void testPartialResultUponBadDependencyDeclaration() throws Exception {
155         File pomFile = getTestFile("src/test/resources/projects/bad-dependency.xml");
156 
157         ProjectBuildingRequest request = newBuildingRequest();
158         request.setProcessPlugins(false);
159         request.setResolveDependencies(true);
160         ProjectBuildingException e = assertThrows(
161                 ProjectBuildingException.class,
162                 () -> projectBuilder.build(pomFile, request),
163                 "Project building did not fail despite invalid POM");
164         List<ProjectBuildingResult> results = e.getResults();
165         assertNotNull(results);
166         assertEquals(1, results.size());
167         ProjectBuildingResult result = results.get(0);
168         assertNotNull(result);
169         assertNotNull(result.getProject());
170         assertEquals(1, result.getProblems().size());
171         assertEquals(1, result.getProject().getArtifacts().size());
172         assertNotNull(result.getDependencyResolutionResult());
173     }
174 
175     /**
176      * Tests whether local version range parent references are build correctly.
177      *
178      * @throws Exception in case of issue
179      */
180     @Test
181     void testBuildValidParentVersionRangeLocally() throws Exception {
182         File f1 = getTestFile("src/test/resources/projects/parent-version-range-local-valid/child/pom.xml");
183 
184         final MavenProject childProject = getProject(f1);
185 
186         assertNotNull(childProject.getParentArtifact());
187         assertEquals(childProject.getParentArtifact().getVersion(), "1");
188         assertNotNull(childProject.getParent());
189         assertEquals(childProject.getParent().getVersion(), "1");
190         assertNotNull(childProject.getModel().getParent());
191         assertEquals(childProject.getModel().getParent().getVersion(), "[1,10]");
192     }
193 
194     /**
195      * Tests whether local version range parent references are build correctly.
196      *
197      * @throws Exception in case of issue
198      */
199     @Test
200     void testBuildParentVersionRangeLocallyWithoutChildVersion() throws Exception {
201         File f1 = getTestFile(
202                 "src/test/resources/projects/parent-version-range-local-child-without-version/child/pom.xml");
203 
204         ProjectBuildingException e = assertThrows(
205                 ProjectBuildingException.class,
206                 () -> getProject(f1),
207                 "Expected 'ProjectBuildingException' not thrown.");
208         assertThat(e.getResults(), contains(projectBuildingResultWithProblemMessage("Version must be a constant")));
209     }
210 
211     /**
212      * Tests whether local version range parent references are build correctly.
213      *
214      * @throws Exception in case of issue
215      */
216     @Test
217     void testBuildParentVersionRangeLocallyWithChildProjectVersionExpression() throws Exception {
218         File f1 = getTestFile(
219                 "src/test/resources/projects/parent-version-range-local-child-project-version-expression/child/pom.xml");
220 
221         ProjectBuildingException e = assertThrows(
222                 ProjectBuildingException.class,
223                 () -> getProject(f1),
224                 "Expected 'ProjectBuildingException' not thrown.");
225         assertThat(e.getResults(), contains(projectBuildingResultWithProblemMessage("Version must be a constant")));
226     }
227 
228     /**
229      * Tests whether local version range parent references are build correctly.
230      *
231      * @throws Exception
232      */
233     public void testBuildParentVersionRangeLocallyWithChildProjectParentVersionExpression() throws Exception {
234         File f1 = getTestFile(
235                 "src/test/resources/projects/parent-version-range-local-child-project-parent-version-expression/child/pom.xml");
236 
237         try {
238             getProject(f1);
239             fail("Expected 'ProjectBuildingException' not thrown.");
240         } catch (final ProjectBuildingException e) {
241             assertNotNull(e.getMessage());
242             assertThat(e.getMessage(), containsString("Version must be a constant"));
243         }
244     }
245 
246     /**
247      * Tests whether local version range parent references are build correctly.
248      *
249      * @throws Exception
250      */
251     public void testBuildParentVersionRangeLocallyWithChildRevisionExpression() throws Exception {
252         File f1 = getTestFile(
253                 "src/test/resources/projects/parent-version-range-local-child-revision-expression/child/pom.xml");
254 
255         MavenProject mp = this.getProjectFromRemoteRepository(f1);
256 
257         assertEquals("1.0-SNAPSHOT", mp.getVersion());
258     }
259 
260     /**
261      * Tests whether external version range parent references are build correctly.
262      *
263      * @throws Exception in case of issue
264      */
265     @Test
266     void testBuildParentVersionRangeExternally() throws Exception {
267         File f1 = getTestFile("src/test/resources/projects/parent-version-range-external-valid/pom.xml");
268 
269         final MavenProject childProject = this.getProjectFromRemoteRepository(f1);
270 
271         assertNotNull(childProject.getParentArtifact());
272         assertEquals(childProject.getParentArtifact().getVersion(), "1");
273         assertNotNull(childProject.getParent());
274         assertEquals(childProject.getParent().getVersion(), "1");
275         assertNotNull(childProject.getModel().getParent());
276         assertEquals(childProject.getModel().getParent().getVersion(), "[1,1]");
277     }
278 
279     /**
280      * Tests whether external version range parent references are build correctly.
281      *
282      * @throws Exception in case of issue
283      */
284     @Test
285     void testBuildParentVersionRangeExternallyWithoutChildVersion() throws Exception {
286         File f1 =
287                 getTestFile("src/test/resources/projects/parent-version-range-external-child-without-version/pom.xml");
288 
289         ProjectBuildingException e = assertThrows(
290                 ProjectBuildingException.class,
291                 () -> getProjectFromRemoteRepository(f1),
292                 "Expected 'ProjectBuildingException' not thrown.");
293         assertThat(e.getResults(), contains(projectBuildingResultWithProblemMessage("Version must be a constant")));
294     }
295 
296     /**
297      * Tests whether external version range parent references are build correctly.
298      *
299      * @throws Exception in case of issue
300      */
301     @Test
302     void testBuildParentVersionRangeExternallyWithChildProjectVersionExpression() throws Exception {
303         File f1 = getTestFile(
304                 "src/test/resources/projects/parent-version-range-external-child-project-version-expression/pom.xml");
305 
306         ProjectBuildingException e = assertThrows(
307                 ProjectBuildingException.class,
308                 () -> getProjectFromRemoteRepository(f1),
309                 "Expected 'ProjectBuildingException' not thrown.");
310         assertThat(e.getResults(), contains(projectBuildingResultWithProblemMessage("Version must be a constant")));
311     }
312 
313     /**
314      * Ensure that when re-reading a pom, it should not use the cached Model
315      *
316      * @throws Exception in case of issue
317      */
318     @Test
319     void rereadPom_mng7063() throws Exception {
320         final Path pom = projectRoot.resolve("pom.xml");
321         final ProjectBuildingRequest buildingRequest = newBuildingRequest();
322 
323         try (InputStream pomResource =
324                 DefaultMavenProjectBuilderTest.class.getResourceAsStream("/projects/reread/pom1.xml")) {
325             Files.copy(pomResource, pom, StandardCopyOption.REPLACE_EXISTING);
326         }
327 
328         MavenProject project =
329                 projectBuilder.build(pom.toFile(), buildingRequest).getProject();
330         assertThat(project.getName(), is("aid")); // inherited from artifactId
331 
332         try (InputStream pomResource =
333                 DefaultMavenProjectBuilderTest.class.getResourceAsStream("/projects/reread/pom2.xml")) {
334             Files.copy(pomResource, pom, StandardCopyOption.REPLACE_EXISTING);
335         }
336 
337         project = projectBuilder.build(pom.toFile(), buildingRequest).getProject();
338         assertThat(project.getName(), is("PROJECT NAME"));
339     }
340 
341     /**
342      * Tests whether external version range parent references are build correctly.
343      *
344      * @throws Exception
345      */
346     public void testBuildParentVersionRangeExternallyWithChildPomVersionExpression() throws Exception {
347         File f1 = getTestFile(
348                 "src/test/resources/projects/parent-version-range-external-child-pom-version-expression/pom.xml");
349 
350         try {
351             this.getProjectFromRemoteRepository(f1);
352             fail("Expected 'ProjectBuildingException' not thrown.");
353         } catch (final ProjectBuildingException e) {
354             assertNotNull(e.getMessage());
355             assertThat(e.getMessage(), containsString("Version must be a constant"));
356         }
357     }
358 
359     /**
360      * Tests whether external version range parent references are build correctly.
361      *
362      * @throws Exception
363      */
364     public void testBuildParentVersionRangeExternallyWithChildPomParentVersionExpression() throws Exception {
365         File f1 = getTestFile(
366                 "src/test/resources/projects/parent-version-range-external-child-pom-parent-version-expression/pom.xml");
367 
368         try {
369             this.getProjectFromRemoteRepository(f1);
370             fail("Expected 'ProjectBuildingException' not thrown.");
371         } catch (final ProjectBuildingException e) {
372             assertNotNull(e.getMessage());
373             assertThat(e.getMessage(), containsString("Version must be a constant"));
374         }
375     }
376 
377     /**
378      * Tests whether external version range parent references are build correctly.
379      *
380      * @throws Exception
381      */
382     public void testBuildParentVersionRangeExternallyWithChildProjectParentVersionExpression() throws Exception {
383         File f1 = getTestFile(
384                 "src/test/resources/projects/parent-version-range-external-child-project-parent-version-expression/pom.xml");
385 
386         try {
387             this.getProjectFromRemoteRepository(f1);
388             fail("Expected 'ProjectBuildingException' not thrown.");
389         } catch (final ProjectBuildingException e) {
390             assertNotNull(e.getMessage());
391             assertThat(e.getMessage(), containsString("Version must be a constant"));
392         }
393     }
394 
395     /**
396      * Tests whether external version range parent references are build correctly.
397      *
398      * @throws Exception
399      */
400     public void testBuildParentVersionRangeExternallyWithChildRevisionExpression() throws Exception {
401         File f1 = getTestFile(
402                 "src/test/resources/projects/parent-version-range-external-child-revision-expression/pom.xml");
403 
404         MavenProject mp = this.getProjectFromRemoteRepository(f1);
405 
406         assertEquals("1.0-SNAPSHOT", mp.getVersion());
407     }
408 }