View Javadoc
1   package org.apache.maven.model.validation;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.InputStream;
23  import java.util.List;
24  
25  import org.apache.maven.model.Model;
26  import org.apache.maven.model.building.DefaultModelBuildingRequest;
27  import org.apache.maven.model.building.ModelBuildingRequest;
28  import org.apache.maven.model.building.SimpleProblemCollector;
29  import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
30  import org.codehaus.plexus.PlexusTestCase;
31  
32  /**
33   * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
34   */
35  public class DefaultModelValidatorTest
36      extends PlexusTestCase
37  {
38  
39      private ModelValidator validator;
40  
41      private Model read( String pom )
42          throws Exception
43      {
44          String resource = "/poms/validation/" + pom;
45          InputStream is = getClass().getResourceAsStream( resource );
46          assertNotNull( "missing resource: " + resource, is );
47          return new MavenXpp3Reader().read( is );
48      }
49  
50      private SimpleProblemCollector validate( String pom )
51          throws Exception
52      {
53          return validateEffective( pom, ModelBuildingRequest.VALIDATION_LEVEL_STRICT );
54      }
55  
56      private SimpleProblemCollector validateRaw( String pom )
57          throws Exception
58      {
59          return validateRaw( pom, ModelBuildingRequest.VALIDATION_LEVEL_STRICT );
60      }
61  
62      private SimpleProblemCollector validateEffective( String pom, int level )
63          throws Exception
64      {
65          ModelBuildingRequest request = new DefaultModelBuildingRequest().setValidationLevel( level );
66  
67          SimpleProblemCollector problems = new SimpleProblemCollector( read( pom ) );
68  
69          validator.validateEffectiveModel( problems.getModel(), request, problems );
70  
71          return problems;
72      }
73  
74      private SimpleProblemCollector validateRaw( String pom, int level )
75          throws Exception
76      {
77          ModelBuildingRequest request = new DefaultModelBuildingRequest().setValidationLevel( level );
78  
79          SimpleProblemCollector problems = new SimpleProblemCollector( read( pom ) );
80  
81          validator.validateRawModel( problems.getModel(), request, problems );
82  
83          return problems;
84      }
85  
86      private void assertContains( String msg, String substring )
87      {
88          assertTrue( "\"" + substring + "\" was not found in: " + msg, msg.contains( substring ) );
89      }
90  
91      @Override
92      protected void setUp()
93          throws Exception
94      {
95          super.setUp();
96  
97          validator = lookup( ModelValidator.class );
98      }
99  
100     @Override
101     protected void tearDown()
102         throws Exception
103     {
104         this.validator = null;
105 
106         super.tearDown();
107     }
108 
109     private void assertViolations( SimpleProblemCollector result, int fatals, int errors, int warnings )
110     {
111         assertEquals( String.valueOf( result.getFatals() ), fatals, result.getFatals().size() );
112         assertEquals( String.valueOf( result.getErrors() ), errors, result.getErrors().size() );
113         assertEquals( String.valueOf( result.getWarnings() ), warnings, result.getWarnings().size() );
114     }
115 
116     public void testMissingModelVersion()
117         throws Exception
118     {
119         SimpleProblemCollector result = validate( "missing-modelVersion-pom.xml" );
120 
121         assertViolations( result, 0, 1, 0 );
122 
123         assertEquals( "'modelVersion' is missing.", result.getErrors().get( 0 ) );
124     }
125 
126     public void testBadModelVersion()
127         throws Exception
128     {
129         SimpleProblemCollector result =
130             validateRaw( "bad-modelVersion.xml", ModelBuildingRequest.VALIDATION_LEVEL_STRICT );
131 
132         assertViolations( result, 0, 1, 0 );
133 
134         assertTrue( result.getErrors().get( 0 ).contains( "modelVersion" ) );
135     }
136 
137     public void testMissingArtifactId()
138         throws Exception
139     {
140         SimpleProblemCollector result = validate( "missing-artifactId-pom.xml" );
141 
142         assertViolations( result, 0, 1, 0 );
143 
144         assertEquals( "'artifactId' is missing.", result.getErrors().get( 0 ) );
145     }
146 
147     public void testMissingGroupId()
148         throws Exception
149     {
150         SimpleProblemCollector result = validate( "missing-groupId-pom.xml" );
151 
152         assertViolations( result, 0, 1, 0 );
153 
154         assertEquals( "'groupId' is missing.", result.getErrors().get( 0 ) );
155     }
156 
157     public void testInvalidIds()
158         throws Exception
159     {
160         SimpleProblemCollector result = validate( "invalid-ids-pom.xml" );
161 
162         assertViolations( result, 0, 2, 0 );
163 
164         assertEquals( "'groupId' with value 'o/a/m' does not match a valid id pattern.", result.getErrors().get( 0 ) );
165 
166         assertEquals( "'artifactId' with value 'm$-do$' does not match a valid id pattern.", result.getErrors().get( 1 ) );
167     }
168 
169     public void testMissingType()
170         throws Exception
171     {
172         SimpleProblemCollector result = validate( "missing-type-pom.xml" );
173 
174         assertViolations( result, 0, 1, 0 );
175 
176         assertEquals( "'packaging' is missing.", result.getErrors().get( 0 ) );
177     }
178 
179     public void testMissingVersion()
180         throws Exception
181     {
182         SimpleProblemCollector result = validate( "missing-version-pom.xml" );
183 
184         assertViolations( result, 0, 1, 0 );
185 
186         assertEquals( "'version' is missing.", result.getErrors().get( 0 ) );
187     }
188 
189     public void testInvalidAggregatorPackaging()
190         throws Exception
191     {
192         SimpleProblemCollector result = validate( "invalid-aggregator-packaging-pom.xml" );
193 
194         assertViolations( result, 0, 1, 0 );
195 
196         assertTrue( result.getErrors().get( 0 ).contains( "Aggregator projects require 'pom' as packaging." ) );
197     }
198 
199     public void testMissingDependencyArtifactId()
200         throws Exception
201     {
202         SimpleProblemCollector result = validate( "missing-dependency-artifactId-pom.xml" );
203 
204         assertViolations( result, 0, 1, 0 );
205 
206         assertTrue( result.getErrors().get( 0 ).contains(
207             "'dependencies.dependency.artifactId' for groupId:null:jar is missing" ) );
208     }
209 
210     public void testMissingDependencyGroupId()
211         throws Exception
212     {
213         SimpleProblemCollector result = validate( "missing-dependency-groupId-pom.xml" );
214 
215         assertViolations( result, 0, 1, 0 );
216 
217         assertTrue( result.getErrors().get( 0 ).contains(
218             "'dependencies.dependency.groupId' for null:artifactId:jar is missing" ) );
219     }
220 
221     public void testMissingDependencyVersion()
222         throws Exception
223     {
224         SimpleProblemCollector result = validate( "missing-dependency-version-pom.xml" );
225 
226         assertViolations( result, 0, 1, 0 );
227 
228         assertTrue( result.getErrors().get( 0 ).contains(
229             "'dependencies.dependency.version' for groupId:artifactId:jar is missing" ) );
230     }
231 
232     public void testMissingDependencyManagementArtifactId()
233         throws Exception
234     {
235         SimpleProblemCollector result = validate( "missing-dependency-mgmt-artifactId-pom.xml" );
236 
237         assertViolations( result, 0, 1, 0 );
238 
239         assertTrue( result.getErrors().get( 0 ).contains(
240             "'dependencyManagement.dependencies.dependency.artifactId' for groupId:null:jar is missing" ) );
241     }
242 
243     public void testMissingDependencyManagementGroupId()
244         throws Exception
245     {
246         SimpleProblemCollector result = validate( "missing-dependency-mgmt-groupId-pom.xml" );
247 
248         assertViolations( result, 0, 1, 0 );
249 
250         assertTrue( result.getErrors().get( 0 ).contains(
251             "'dependencyManagement.dependencies.dependency.groupId' for null:artifactId:jar is missing" ) );
252     }
253 
254     public void testMissingAll()
255         throws Exception
256     {
257         SimpleProblemCollector result = validate( "missing-1-pom.xml" );
258 
259         assertViolations( result, 0, 4, 0 );
260 
261         List<String> messages = result.getErrors();
262 
263         assertTrue( messages.contains( "\'modelVersion\' is missing." ) );
264         assertTrue( messages.contains( "\'groupId\' is missing." ) );
265         assertTrue( messages.contains( "\'artifactId\' is missing." ) );
266         assertTrue( messages.contains( "\'version\' is missing." ) );
267         // type is inherited from the super pom
268     }
269 
270     public void testMissingPluginArtifactId()
271         throws Exception
272     {
273         SimpleProblemCollector result = validate( "missing-plugin-artifactId-pom.xml" );
274 
275         assertViolations( result, 0, 1, 0 );
276 
277         assertEquals( "'build.plugins.plugin.artifactId' is missing.", result.getErrors().get( 0 ) );
278     }
279 
280     public void testEmptyPluginVersion()
281         throws Exception
282     {
283         SimpleProblemCollector result = validate( "empty-plugin-version.xml" );
284 
285         assertViolations( result, 0, 1, 0 );
286 
287         assertEquals( "'build.plugins.plugin.version' for org.apache.maven.plugins:maven-it-plugin"
288             + " must be a valid version but is ''.", result.getErrors().get( 0 ) );
289     }
290 
291     public void testMissingRepositoryId()
292         throws Exception
293     {
294         SimpleProblemCollector result =
295             validateRaw( "missing-repository-id-pom.xml", ModelBuildingRequest.VALIDATION_LEVEL_STRICT );
296 
297         assertViolations( result, 0, 4, 0 );
298 
299         assertEquals( "'repositories.repository.id' is missing.", result.getErrors().get( 0 ) );
300 
301         assertEquals( "'repositories.repository[null].url' is missing.", result.getErrors().get( 1 ) );
302 
303         assertEquals( "'pluginRepositories.pluginRepository.id' is missing.", result.getErrors().get( 2 ) );
304 
305         assertEquals( "'pluginRepositories.pluginRepository[null].url' is missing.", result.getErrors().get( 3 ) );
306     }
307 
308     public void testMissingResourceDirectory()
309         throws Exception
310     {
311         SimpleProblemCollector result = validate( "missing-resource-directory-pom.xml" );
312 
313         assertViolations( result, 0, 2, 0 );
314 
315         assertEquals( "'build.resources.resource.directory' is missing.", result.getErrors().get( 0 ) );
316 
317         assertEquals( "'build.testResources.testResource.directory' is missing.", result.getErrors().get( 1 ) );
318     }
319 
320     public void testBadPluginDependencyScope()
321         throws Exception
322     {
323         SimpleProblemCollector result = validate( "bad-plugin-dependency-scope.xml" );
324 
325         assertViolations( result, 0, 3, 0 );
326 
327         assertTrue( result.getErrors().get( 0 ).contains( "test:d" ) );
328 
329         assertTrue( result.getErrors().get( 1 ).contains( "test:e" ) );
330 
331         assertTrue( result.getErrors().get( 2 ).contains( "test:f" ) );
332     }
333 
334     public void testBadDependencyScope()
335         throws Exception
336     {
337         SimpleProblemCollector result = validate( "bad-dependency-scope.xml" );
338 
339         assertViolations( result, 0, 0, 2 );
340 
341         assertTrue( result.getWarnings().get( 0 ).contains( "test:f" ) );
342 
343         assertTrue( result.getWarnings().get( 1 ).contains( "test:g" ) );
344     }
345 
346     public void testBadDependencyVersion()
347         throws Exception
348     {
349         SimpleProblemCollector result = validate( "bad-dependency-version.xml" );
350 
351         assertViolations( result, 0, 2, 0 );
352 
353         assertContains( result.getErrors().get( 0 ),
354                         "'dependencies.dependency.version' for test:b:jar must be a valid version" );
355         assertContains( result.getErrors().get( 1 ),
356                         "'dependencies.dependency.version' for test:c:jar must not contain any of these characters" );
357     }
358 
359     public void testDuplicateModule()
360         throws Exception
361     {
362         SimpleProblemCollector result = validate( "duplicate-module.xml" );
363 
364         assertViolations( result, 0, 1, 0 );
365 
366         assertTrue( result.getErrors().get( 0 ).contains( "child" ) );
367     }
368 
369     public void testDuplicateProfileId()
370         throws Exception
371     {
372         SimpleProblemCollector result = validateRaw( "duplicate-profile-id.xml" );
373 
374         assertViolations( result, 0, 1, 0 );
375 
376         assertTrue( result.getErrors().get( 0 ).contains( "non-unique-id" ) );
377     }
378 
379     public void testBadPluginVersion()
380         throws Exception
381     {
382         SimpleProblemCollector result = validate( "bad-plugin-version.xml" );
383 
384         assertViolations( result, 0, 4, 0 );
385 
386         assertContains( result.getErrors().get( 0 ),
387                         "'build.plugins.plugin.version' for test:mip must be a valid version" );
388         assertContains( result.getErrors().get( 1 ),
389                         "'build.plugins.plugin.version' for test:rmv must be a valid version" );
390         assertContains( result.getErrors().get( 2 ),
391                         "'build.plugins.plugin.version' for test:lmv must be a valid version" );
392         assertContains( result.getErrors().get( 3 ),
393                         "'build.plugins.plugin.version' for test:ifsc must not contain any of these characters" );
394     }
395 
396     public void testDistributionManagementStatus()
397         throws Exception
398     {
399         SimpleProblemCollector result = validate( "distribution-management-status.xml" );
400 
401         assertViolations( result, 0, 1, 0 );
402 
403         assertTrue( result.getErrors().get( 0 ).contains( "distributionManagement.status" ) );
404     }
405 
406     public void testIncompleteParent()
407         throws Exception
408     {
409         SimpleProblemCollector result = validateRaw( "incomplete-parent.xml" );
410 
411         assertViolations( result, 3, 0, 0 );
412 
413         assertTrue( result.getFatals().get( 0 ).contains( "parent.groupId" ) );
414         assertTrue( result.getFatals().get( 1 ).contains( "parent.artifactId" ) );
415         assertTrue( result.getFatals().get( 2 ).contains( "parent.version" ) );
416     }
417 
418     public void testHardCodedSystemPath()
419         throws Exception
420     {
421         SimpleProblemCollector result = validateRaw( "hard-coded-system-path.xml" );
422 
423         assertViolations( result, 0, 0, 1 );
424 
425         assertTrue( result.getWarnings().get( 0 ).contains( "test:a:jar" ) );
426     }
427 
428     public void testEmptyModule()
429         throws Exception
430     {
431         SimpleProblemCollector result = validate( "empty-module.xml" );
432 
433         assertViolations( result, 0, 0, 1 );
434 
435         assertTrue( result.getWarnings().get( 0 ).contains( "'modules.module[0]' has been specified without a path" ) );
436     }
437 
438     public void testDuplicatePlugin()
439         throws Exception
440     {
441         SimpleProblemCollector result = validateRaw( "duplicate-plugin.xml" );
442 
443         assertViolations( result, 0, 0, 4 );
444 
445         assertTrue( result.getWarnings().get( 0 ).contains( "duplicate declaration of plugin test:duplicate" ) );
446         assertTrue( result.getWarnings().get( 1 ).contains( "duplicate declaration of plugin test:managed-duplicate" ) );
447         assertTrue( result.getWarnings().get( 2 ).contains( "duplicate declaration of plugin profile:duplicate" ) );
448         assertTrue( result.getWarnings().get( 3 ).contains( "duplicate declaration of plugin profile:managed-duplicate" ) );
449     }
450 
451     public void testDuplicatePluginExecution()
452         throws Exception
453     {
454         SimpleProblemCollector result = validateRaw( "duplicate-plugin-execution.xml" );
455 
456         assertViolations( result, 0, 4, 0 );
457 
458         assertContains( result.getErrors().get( 0 ), "duplicate execution with id a" );
459         assertContains( result.getErrors().get( 1 ), "duplicate execution with id default" );
460         assertContains( result.getErrors().get( 2 ), "duplicate execution with id c" );
461         assertContains( result.getErrors().get( 3 ), "duplicate execution with id b" );
462     }
463 
464     public void testReservedRepositoryId()
465         throws Exception
466     {
467         SimpleProblemCollector result = validate( "reserved-repository-id.xml" );
468 
469         assertViolations( result, 0, 0, 4 );
470 
471         assertContains( result.getWarnings().get( 0 ), "'repositories.repository.id'" + " must not be 'local'" );
472         assertContains( result.getWarnings().get( 1 ), "'pluginRepositories.pluginRepository.id' must not be 'local'" );
473         assertContains( result.getWarnings().get( 2 ), "'distributionManagement.repository.id' must not be 'local'" );
474         assertContains( result.getWarnings().get( 3 ),
475                         "'distributionManagement.snapshotRepository.id' must not be 'local'" );
476     }
477 
478     public void testMissingPluginDependencyGroupId()
479         throws Exception
480     {
481         SimpleProblemCollector result = validate( "missing-plugin-dependency-groupId.xml" );
482 
483         assertViolations( result, 0, 1, 0 );
484 
485         assertTrue( result.getErrors().get( 0 ).contains( ":a:" ) );
486     }
487 
488     public void testMissingPluginDependencyArtifactId()
489         throws Exception
490     {
491         SimpleProblemCollector result = validate( "missing-plugin-dependency-artifactId.xml" );
492 
493         assertViolations( result, 0, 1, 0 );
494 
495         assertTrue( result.getErrors().get( 0 ).contains( "test:" ) );
496     }
497 
498     public void testMissingPluginDependencyVersion()
499         throws Exception
500     {
501         SimpleProblemCollector result = validate( "missing-plugin-dependency-version.xml" );
502 
503         assertViolations( result, 0, 1, 0 );
504 
505         assertTrue( result.getErrors().get( 0 ).contains( "test:a" ) );
506     }
507 
508     public void testBadPluginDependencyVersion()
509         throws Exception
510     {
511         SimpleProblemCollector result = validate( "bad-plugin-dependency-version.xml" );
512 
513         assertViolations( result, 0, 1, 0 );
514 
515         assertTrue( result.getErrors().get( 0 ).contains( "test:b" ) );
516     }
517 
518     public void testBadVersion()
519         throws Exception
520     {
521         SimpleProblemCollector result = validate( "bad-version.xml" );
522 
523         assertViolations( result, 0, 0, 1 );
524 
525         assertContains( result.getWarnings().get( 0 ), "'version' must not contain any of these characters" );
526     }
527 
528     public void testBadSnapshotVersion()
529         throws Exception
530     {
531         SimpleProblemCollector result = validate( "bad-snapshot-version.xml" );
532 
533         assertViolations( result, 0, 0, 1 );
534 
535         assertContains( result.getWarnings().get( 0 ), "'version' uses an unsupported snapshot version format" );
536     }
537 
538     public void testBadRepositoryId()
539         throws Exception
540     {
541         SimpleProblemCollector result = validate( "bad-repository-id.xml" );
542 
543         assertViolations( result, 0, 0, 4 );
544 
545         assertContains( result.getWarnings().get( 0 ),
546                         "'repositories.repository.id' must not contain any of these characters" );
547         assertContains( result.getWarnings().get( 1 ),
548                         "'pluginRepositories.pluginRepository.id' must not contain any of these characters" );
549         assertContains( result.getWarnings().get( 2 ),
550                         "'distributionManagement.repository.id' must not contain any of these characters" );
551         assertContains( result.getWarnings().get( 3 ),
552                         "'distributionManagement.snapshotRepository.id' must not contain any of these characters" );
553     }
554 
555     public void testBadDependencyExclusionId()
556         throws Exception
557     {
558         SimpleProblemCollector result = validateEffective( "bad-dependency-exclusion-id.xml", ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0 );
559 
560         assertViolations( result, 0, 0, 2 );
561 
562         assertContains( result.getWarnings().get( 0 ),
563                         "'dependencies.dependency.exclusions.exclusion.groupId' for gid:aid:jar" );
564         assertContains( result.getWarnings().get( 1 ),
565                         "'dependencies.dependency.exclusions.exclusion.artifactId' for gid:aid:jar" );
566 
567         // MNG-3832: Aether (part of M3+) supports wildcard expressions for exclusions
568 
569         SimpleProblemCollector result_30 = validate( "bad-dependency-exclusion-id.xml" );
570 
571         assertViolations( result_30, 0, 0, 0 );
572 
573     }
574 
575     public void testMissingDependencyExclusionId()
576         throws Exception
577     {
578         SimpleProblemCollector result = validate( "missing-dependency-exclusion-id.xml" );
579 
580         assertViolations( result, 0, 0, 2 );
581 
582         assertContains( result.getWarnings().get( 0 ),
583                         "'dependencies.dependency.exclusions.exclusion.groupId' for gid:aid:jar is missing" );
584         assertContains( result.getWarnings().get( 1 ),
585                         "'dependencies.dependency.exclusions.exclusion.artifactId' for gid:aid:jar is missing" );
586     }
587 
588     public void testBadImportScopeType()
589         throws Exception
590     {
591         SimpleProblemCollector result = validateRaw( "bad-import-scope-type.xml" );
592 
593         assertViolations( result, 0, 0, 1 );
594 
595         assertContains( result.getWarnings().get( 0 ),
596                         "'dependencyManagement.dependencies.dependency.type' for test:a:jar must be 'pom'" );
597     }
598 
599     public void testBadImportScopeClassifier()
600         throws Exception
601     {
602         SimpleProblemCollector result = validateRaw( "bad-import-scope-classifier.xml" );
603 
604         assertViolations( result, 0, 1, 0 );
605 
606         assertContains( result.getErrors().get( 0 ),
607                         "'dependencyManagement.dependencies.dependency.classifier' for test:a:pom:cls must be empty" );
608     }
609 
610     public void testSystemPathRefersToProjectBasedir()
611         throws Exception
612     {
613         SimpleProblemCollector result = validateRaw( "basedir-system-path.xml" );
614 
615         assertViolations( result, 0, 0, 2 );
616 
617         assertContains( result.getWarnings().get( 0 ), "'dependencies.dependency.systemPath' for test:a:jar "
618             + "should not point at files within the project directory" );
619         assertContains( result.getWarnings().get( 1 ), "'dependencies.dependency.systemPath' for test:b:jar "
620             + "should not point at files within the project directory" );
621     }
622 
623     public void testMissingReportPluginVersion()
624         throws Exception
625     {
626         SimpleProblemCollector result = validate( "missing-report-version-pom.xml" );
627 
628         assertViolations( result, 0, 0, 0 );
629     }
630 }