001    package org.apache.maven.model.validation;
002    
003    /*
004     * Licensed to the Apache Software Foundation (ASF) under one
005     * or more contributor license agreements.  See the NOTICE file
006     * distributed with this work for additional information
007     * regarding copyright ownership.  The ASF licenses this file
008     * to you under the Apache License, Version 2.0 (the
009     * "License"); you may not use this file except in compliance
010     * with the License.  You may obtain a copy of the License at
011     *
012     *  http://www.apache.org/licenses/LICENSE-2.0
013     *
014     * Unless required by applicable law or agreed to in writing,
015     * software distributed under the License is distributed on an
016     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017     * KIND, either express or implied.  See the License for the
018     * specific language governing permissions and limitations
019     * under the License.
020     */
021    
022    import java.io.InputStream;
023    import java.util.List;
024    
025    import org.apache.maven.model.Model;
026    import org.apache.maven.model.building.DefaultModelBuildingRequest;
027    import org.apache.maven.model.building.ModelBuildingRequest;
028    import org.apache.maven.model.building.SimpleProblemCollector;
029    import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
030    import org.codehaus.plexus.PlexusTestCase;
031    
032    /**
033     * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
034     */
035    public class DefaultModelValidatorTest
036        extends PlexusTestCase
037    {
038    
039        private ModelValidator validator;
040    
041        private Model read( String pom )
042            throws Exception
043        {
044            String resource = "/poms/validation/" + pom;
045            InputStream is = getClass().getResourceAsStream( resource );
046            assertNotNull( "missing resource: " + resource, is );
047            return new MavenXpp3Reader().read( is );
048        }
049    
050        private SimpleProblemCollector validate( String pom )
051            throws Exception
052        {
053            return validateEffective( pom, ModelBuildingRequest.VALIDATION_LEVEL_STRICT );
054        }
055    
056        private SimpleProblemCollector validateRaw( String pom )
057            throws Exception
058        {
059            return validateRaw( pom, ModelBuildingRequest.VALIDATION_LEVEL_STRICT );
060        }
061    
062        private SimpleProblemCollector validateEffective( String pom, int level )
063            throws Exception
064        {
065            ModelBuildingRequest request = new DefaultModelBuildingRequest().setValidationLevel( level );
066    
067            SimpleProblemCollector problems = new SimpleProblemCollector();
068    
069            validator.validateEffectiveModel( read( pom ), request, problems );
070    
071            return problems;
072        }
073    
074        private SimpleProblemCollector validateRaw( String pom, int level )
075            throws Exception
076        {
077            ModelBuildingRequest request = new DefaultModelBuildingRequest().setValidationLevel( level );
078    
079            SimpleProblemCollector problems = new SimpleProblemCollector();
080    
081            validator.validateRawModel( read( pom ), request, problems );
082    
083            return problems;
084        }
085    
086        private void assertContains( String msg, String substring )
087        {
088            assertTrue( "\"" + substring + "\" was not found in: " + msg, msg.contains( substring ) );
089        }
090    
091        @Override
092        protected void setUp()
093            throws Exception
094        {
095            super.setUp();
096    
097            validator = lookup( ModelValidator.class );
098        }
099    
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 ).indexOf( "modelVersion" ) > -1 );
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 ).indexOf( "Aggregator projects require 'pom' as packaging." ) > -1 );
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 ).indexOf(
207                                                             "'dependencies.dependency.artifactId' for groupId:null:jar is missing" ) > -1 );
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 ).indexOf(
218                                                             "'dependencies.dependency.groupId' for null:artifactId:jar is missing" ) > -1 );
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 ).indexOf(
229                                                             "'dependencies.dependency.version' for groupId:artifactId:jar is missing" ) > -1 );
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 ).indexOf(
240                                                             "'dependencyManagement.dependencies.dependency.artifactId' for groupId:null:jar is missing" ) > -1 );
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 ).indexOf(
251                                                             "'dependencyManagement.dependencies.dependency.groupId' for null:artifactId:jar is missing" ) > -1 );
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 = validate( "bad-dependency-exclusion-id.xml" );
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    
568        public void testMissingDependencyExclusionId()
569            throws Exception
570        {
571            SimpleProblemCollector result = validate( "missing-dependency-exclusion-id.xml" );
572    
573            assertViolations( result, 0, 0, 2 );
574    
575            assertContains( result.getWarnings().get( 0 ),
576                            "'dependencies.dependency.exclusions.exclusion.groupId' for gid:aid:jar is missing" );
577            assertContains( result.getWarnings().get( 1 ),
578                            "'dependencies.dependency.exclusions.exclusion.artifactId' for gid:aid:jar is missing" );
579        }
580    
581        public void testBadImportScopeType()
582            throws Exception
583        {
584            SimpleProblemCollector result = validateRaw( "bad-import-scope-type.xml" );
585    
586            assertViolations( result, 0, 0, 1 );
587    
588            assertContains( result.getWarnings().get( 0 ),
589                            "'dependencyManagement.dependencies.dependency.type' for test:a:jar must be 'pom'" );
590        }
591    
592        public void testBadImportScopeClassifier()
593            throws Exception
594        {
595            SimpleProblemCollector result = validateRaw( "bad-import-scope-classifier.xml" );
596    
597            assertViolations( result, 0, 1, 0 );
598    
599            assertContains( result.getErrors().get( 0 ),
600                            "'dependencyManagement.dependencies.dependency.classifier' for test:a:pom:cls must be empty" );
601        }
602    
603        public void testSystemPathRefersToProjectBasedir()
604            throws Exception
605        {
606            SimpleProblemCollector result = validateRaw( "basedir-system-path.xml" );
607    
608            assertViolations( result, 0, 0, 2 );
609    
610            assertContains( result.getWarnings().get( 0 ), "'dependencies.dependency.systemPath' for test:a:jar "
611                + "should not point at files within the project directory" );
612            assertContains( result.getWarnings().get( 1 ), "'dependencies.dependency.systemPath' for test:b:jar "
613                + "should not point at files within the project directory" );
614        }
615    
616    }