1   package org.apache.maven.project;
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.IOException;
23  import java.io.StringReader;
24  import java.util.Arrays;
25  import java.util.Collections;
26  import java.util.Iterator;
27  import java.util.List;
28  import java.util.Map;
29  
30  import junit.framework.TestCase;
31  
32  import org.apache.maven.model.Build;
33  import org.apache.maven.model.Dependency;
34  import org.apache.maven.model.Plugin;
35  import org.apache.maven.model.PluginContainer;
36  import org.apache.maven.model.PluginExecution;
37  import org.codehaus.plexus.util.xml.Xpp3Dom;
38  import org.codehaus.plexus.util.xml.Xpp3DomBuilder;
39  import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
40  
41  public class ModelUtilsTest
42      extends TestCase
43  {
44  
45      public void testShouldUseMainPluginDependencyVersionOverManagedDepVersion()
46      {
47          Plugin mgtPlugin = createPlugin( "group", "artifact", "1", Collections.EMPTY_MAP );
48          Dependency mgtDep = createDependency( "g", "a", "2" );
49          mgtPlugin.addDependency( mgtDep );
50  
51          Plugin plugin = createPlugin( "group", "artifact", "1", Collections.EMPTY_MAP );
52          Dependency dep = createDependency( "g", "a", "1" );
53          plugin.addDependency( dep );
54  
55          ModelUtils.mergePluginDefinitions( plugin, mgtPlugin, false );
56  
57          assertEquals( dep.getVersion(), ((Dependency) plugin.getDependencies().get( 0 ) ).getVersion() );
58      }
59  
60      private Dependency createDependency( String gid,
61                                           String aid,
62                                           String ver )
63      {
64          Dependency dep = new Dependency();
65          dep.setGroupId( gid );
66          dep.setArtifactId( aid );
67          dep.setVersion( ver );
68  
69          return dep;
70      }
71  
72      public void testShouldNotInheritPluginWithInheritanceSetToFalse()
73      {
74          PluginContainer parent = new PluginContainer();
75  
76          Plugin parentPlugin = createPlugin( "group", "artifact", "1.0", Collections.EMPTY_MAP );
77          parentPlugin.setInherited( "false" );
78  
79          parent.addPlugin( parentPlugin );
80  
81          PluginContainer child = new PluginContainer();
82  
83          child.addPlugin( createPlugin( "group3", "artifact3", "1.0", Collections.EMPTY_MAP ) );
84  
85          ModelUtils.mergePluginLists( child, parent, true );
86  
87          List results = child.getPlugins();
88  
89          assertEquals( 1, results.size() );
90  
91          Plugin result1 = (Plugin) results.get( 0 );
92          assertEquals( "group3", result1.getGroupId() );
93          assertEquals( "artifact3", result1.getArtifactId() );
94      }
95  
96      /**
97       * Test that this is the resulting ordering of plugins after merging:
98       *
99       * Given:
100      *
101      *   parent: X -> A -> B -> D -> E
102      *   child: Y -> A -> C -> D -> F
103      *
104      * Result:
105      *
106      *   X -> Y -> A -> B -> C -> D -> E -> F
107      */
108     public void testShouldPreserveChildOrderingOfPluginsAfterParentMerge()
109     {
110         PluginContainer parent = new PluginContainer();
111 
112         parent.addPlugin( createPlugin( "group", "artifact", "1.0", Collections.EMPTY_MAP ) );
113         parent.addPlugin( createPlugin( "group2", "artifact2", "1.0", Collections.singletonMap( "key", "value" ) ) );
114 
115         PluginContainer child = new PluginContainer();
116 
117         child.addPlugin( createPlugin( "group3", "artifact3", "1.0", Collections.EMPTY_MAP ) );
118         child.addPlugin( createPlugin( "group2", "artifact2", "1.0", Collections.singletonMap( "key2", "value2" ) ) );
119 
120         ModelUtils.mergePluginLists( child, parent, true );
121 
122         List results = child.getPlugins();
123 
124         assertEquals( 3, results.size() );
125 
126         Plugin result1 = (Plugin) results.get( 0 );
127 
128         assertEquals( "group", result1.getGroupId() );
129         assertEquals( "artifact", result1.getArtifactId() );
130 
131         Plugin result2 = (Plugin) results.get( 1 );
132 
133         assertEquals( "group3", result2.getGroupId() );
134         assertEquals( "artifact3", result2.getArtifactId() );
135 
136         Plugin result3 = (Plugin) results.get( 2 );
137 
138         assertEquals( "group2", result3.getGroupId() );
139         assertEquals( "artifact2", result3.getArtifactId() );
140 
141         Xpp3Dom result3Config = (Xpp3Dom) result3.getConfiguration();
142 
143         assertNotNull( result3Config );
144 
145         assertEquals( "value", result3Config.getChild( "key" ).getValue() );
146         assertEquals( "value2", result3Config.getChild( "key2" ).getValue() );
147     }
148 
149     private Plugin createPlugin( String groupId, String artifactId, String version, Map configuration )
150     {
151         Plugin plugin = new Plugin();
152         plugin.setGroupId( groupId );
153         plugin.setArtifactId( artifactId );
154         plugin.setVersion( version );
155 
156         Xpp3Dom config = new Xpp3Dom( "configuration" );
157 
158         if( configuration != null )
159         {
160             for ( Iterator it = configuration.entrySet().iterator(); it.hasNext(); )
161             {
162                 Map.Entry entry = (Map.Entry) it.next();
163 
164                 Xpp3Dom param = new Xpp3Dom( String.valueOf( entry.getKey() ) );
165                 param.setValue( String.valueOf( entry.getValue() ) );
166 
167                 config.addChild( param );
168             }
169         }
170 
171         plugin.setConfiguration( config );
172 
173         return plugin;
174     }
175 
176     public void testShouldInheritOnePluginWithExecution()
177     {
178         Plugin parent = new Plugin();
179         parent.setArtifactId( "testArtifact" );
180         parent.setGroupId( "testGroup" );
181         parent.setVersion( "1.0" );
182 
183         PluginExecution parentExecution = new PluginExecution();
184         parentExecution.setId( "testExecution" );
185 
186         parent.addExecution( parentExecution );
187 
188         Plugin child = new Plugin();
189         child.setArtifactId( "testArtifact" );
190         child.setGroupId( "testGroup" );
191         child.setVersion( "1.0" );
192 
193         ModelUtils.mergePluginDefinitions( child, parent, false );
194 
195         assertEquals( 1, child.getExecutions().size() );
196     }
197 
198     public void testShouldMergeInheritedPluginHavingExecutionWithLocalPlugin()
199     {
200         Plugin parent = new Plugin();
201         parent.setArtifactId( "testArtifact" );
202         parent.setGroupId( "testGroup" );
203         parent.setVersion( "1.0" );
204 
205         PluginExecution parentExecution = new PluginExecution();
206         parentExecution.setId( "testExecution" );
207 
208         parent.addExecution( parentExecution );
209 
210         Plugin child = new Plugin();
211         child.setArtifactId( "testArtifact" );
212         child.setGroupId( "testGroup" );
213         child.setVersion( "1.0" );
214 
215         PluginExecution childExecution = new PluginExecution();
216         childExecution.setId( "testExecution2" );
217 
218         child.addExecution( childExecution );
219 
220         ModelUtils.mergePluginDefinitions( child, parent, false );
221 
222         assertEquals( 2, child.getExecutions().size() );
223     }
224 
225     public void testShouldMergeOnePluginWithInheritExecutionWithoutDuplicatingPluginInList()
226     {
227         Plugin parent = new Plugin();
228         parent.setArtifactId( "testArtifact" );
229         parent.setGroupId( "testGroup" );
230         parent.setVersion( "1.0" );
231 
232         PluginExecution parentExecution = new PluginExecution();
233         parentExecution.setId( "testExecution" );
234 
235         parent.addExecution( parentExecution );
236 
237         Build parentContainer = new Build();
238         parentContainer.addPlugin( parent );
239 
240         Plugin child = new Plugin();
241         child.setArtifactId( "testArtifact" );
242         child.setGroupId( "testGroup" );
243         child.setVersion( "1.0" );
244 
245         Build childContainer = new Build();
246         childContainer.addPlugin( child );
247 
248         ModelUtils.mergePluginLists( childContainer, parentContainer, true );
249 
250         List plugins = childContainer.getPlugins();
251 
252         assertEquals( 1, plugins.size() );
253 
254         Plugin plugin = (Plugin) plugins.get( 0 );
255 
256         assertEquals( 1, plugin.getExecutions().size() );
257     }
258 
259     public void testShouldMergePluginWithDifferentExecutionFromParentWithoutDuplicatingPluginInList()
260     {
261         Plugin parent = new Plugin();
262         parent.setArtifactId( "testArtifact" );
263         parent.setGroupId( "testGroup" );
264         parent.setVersion( "1.0" );
265 
266         PluginExecution parentExecution = new PluginExecution();
267         parentExecution.setId( "testExecution" );
268 
269         parent.addExecution( parentExecution );
270 
271         Build parentContainer = new Build();
272         parentContainer.addPlugin( parent );
273 
274         Plugin child = new Plugin();
275         child.setArtifactId( "testArtifact" );
276         child.setGroupId( "testGroup" );
277         child.setVersion( "1.0" );
278 
279         PluginExecution childExecution = new PluginExecution();
280         childExecution.setId( "testExecution2" );
281 
282         child.addExecution( childExecution );
283 
284 
285         Build childContainer = new Build();
286         childContainer.addPlugin( child );
287 
288         ModelUtils.mergePluginLists( childContainer, parentContainer, true );
289 
290         List plugins = childContainer.getPlugins();
291 
292         assertEquals( 1, plugins.size() );
293 
294         Plugin plugin = (Plugin) plugins.get( 0 );
295 
296         assertEquals( 2, plugin.getExecutions().size() );
297     }
298 
299     public void testShouldNOTMergeInheritedPluginHavingInheritEqualFalse()
300     {
301         Plugin parent = new Plugin();
302         parent.setArtifactId( "testArtifact" );
303         parent.setGroupId( "testGroup" );
304         parent.setVersion( "1.0" );
305         parent.setInherited( "false" );
306 
307         PluginExecution parentExecution = new PluginExecution();
308         parentExecution.setId( "testExecution" );
309 
310         parent.addExecution( parentExecution );
311 
312         Plugin child = new Plugin();
313         child.setArtifactId( "testArtifact" );
314         child.setGroupId( "testGroup" );
315         child.setVersion( "1.0" );
316 
317         ModelUtils.mergePluginDefinitions( child, parent, true );
318 
319         assertEquals( 0, child.getExecutions().size() );
320     }
321 
322     /**
323      * Verifies MNG-1499: The order of the merged list should be the plugins specified by the parent followed by the
324      * child list.
325      */
326     public void testShouldKeepOriginalPluginOrdering()
327     {
328         Plugin parentPlugin1 = new Plugin();
329         parentPlugin1.setArtifactId( "testArtifact" );
330         parentPlugin1.setGroupId( "zzz" );  // This will put this plugin last in the sorted map
331         parentPlugin1.setVersion( "1.0" );
332 
333         PluginExecution parentExecution1 = new PluginExecution();
334         parentExecution1.setId( "testExecution" );
335 
336         parentPlugin1.addExecution( parentExecution1 );
337 
338         Plugin parentPlugin2 = new Plugin();
339         parentPlugin2.setArtifactId( "testArtifact" );
340         parentPlugin2.setGroupId( "yyy" );
341         parentPlugin2.setVersion( "1.0" );
342 
343         PluginExecution parentExecution2 = new PluginExecution();
344         parentExecution2.setId( "testExecution" );
345 
346         parentPlugin2.addExecution( parentExecution2 );
347 
348         PluginContainer parentContainer = new PluginContainer();
349         parentContainer.addPlugin(parentPlugin1);
350         parentContainer.addPlugin(parentPlugin2);
351 
352 
353         Plugin childPlugin1 = new Plugin();
354         childPlugin1.setArtifactId( "testArtifact" );
355         childPlugin1.setGroupId( "bbb" );
356         childPlugin1.setVersion( "1.0" );
357 
358         PluginExecution childExecution1 = new PluginExecution();
359         childExecution1.setId( "testExecution" );
360 
361         childPlugin1.addExecution( childExecution1 );
362 
363         Plugin childPlugin2 = new Plugin();
364         childPlugin2.setArtifactId( "testArtifact" );
365         childPlugin2.setGroupId( "aaa" );
366         childPlugin2.setVersion( "1.0" );
367 
368         PluginExecution childExecution2 = new PluginExecution();
369         childExecution2.setId( "testExecution" );
370 
371         childPlugin2.addExecution( childExecution2 );
372 
373         PluginContainer childContainer = new PluginContainer();
374         childContainer.addPlugin(childPlugin1);
375         childContainer.addPlugin(childPlugin2);
376 
377 
378         ModelUtils.mergePluginLists(childContainer, parentContainer, true);
379 
380         assertEquals( 4, childContainer.getPlugins().size() );
381         assertSame(parentPlugin1, childContainer.getPlugins().get(0));
382         assertSame(parentPlugin2, childContainer.getPlugins().get(1));
383         assertSame(childPlugin1, childContainer.getPlugins().get(2));
384         assertSame(childPlugin2, childContainer.getPlugins().get(3));
385     }
386 
387     /**
388      * Verifies MNG-1499: The ordering of plugin executions should also be in the specified order.
389      */
390     public void testShouldKeepOriginalPluginExecutionOrdering()
391     {
392         Plugin parent = new Plugin();
393         parent.setArtifactId( "testArtifact" );
394         parent.setGroupId( "testGroup" );
395         parent.setVersion( "1.0" );
396 
397         PluginExecution parentExecution1 = new PluginExecution();
398         parentExecution1.setId( "zzz" );  // Will show up last in the sorted map
399         PluginExecution parentExecution2 = new PluginExecution();
400         parentExecution2.setId( "yyy" );  // Will show up last in the sorted map
401 
402         parent.addExecution( parentExecution1 );
403         parent.addExecution( parentExecution2 );
404 
405         // this block verifies MNG-1703
406         Dependency dep = new Dependency();
407         dep.setGroupId( "depGroupId" );
408         dep.setArtifactId( "depArtifactId" );
409         dep.setVersion( "depVersion" );
410         parent.setDependencies( Collections.singletonList( dep ) );
411 
412         Plugin child = new Plugin();
413         child.setArtifactId( "testArtifact" );
414         child.setGroupId( "testGroup" );
415         child.setVersion( "1.0" );
416 
417         PluginExecution childExecution1 = new PluginExecution();
418         childExecution1.setId( "bbb" );
419         PluginExecution childExecution2 = new PluginExecution();
420         childExecution2.setId( "aaa" );
421 
422         child.addExecution( childExecution1 );
423         child.addExecution( childExecution2 );
424 
425         ModelUtils.mergePluginDefinitions( child, parent, false );
426 
427         assertEquals( 4, child.getExecutions().size() );
428         assertSame(parentExecution1, child.getExecutions().get(0));
429         assertSame(parentExecution2, child.getExecutions().get(1));
430         assertSame(childExecution1, child.getExecutions().get(2));
431         assertSame(childExecution2, child.getExecutions().get(3));
432 
433         // this block prevents MNG-1703
434         assertEquals( 1, child.getDependencies().size() );
435         Dependency dep2 = (Dependency) child.getDependencies().get( 0 );
436         assertEquals( dep.getManagementKey(), dep2.getManagementKey() );
437     }
438 
439     public void testShouldOverwritePluginConfigurationSubItemsByDefault()
440         throws XmlPullParserException, IOException
441     {
442         String parentConfigStr = "<configuration><items><item>one</item><item>two</item></items></configuration>";
443         Xpp3Dom parentConfig = Xpp3DomBuilder.build( new StringReader( parentConfigStr ) );
444 
445         Plugin parentPlugin = createPlugin( "group", "artifact", "1", null );
446         parentPlugin.setConfiguration( parentConfig );
447 
448         String childConfigStr = "<configuration><items><item>three</item></items></configuration>";
449         Xpp3Dom childConfig = Xpp3DomBuilder.build( new StringReader( childConfigStr ) );
450 
451         Plugin childPlugin = createPlugin( "group", "artifact", "1", null );
452         childPlugin.setConfiguration( childConfig );
453 
454         ModelUtils.mergePluginDefinitions( childPlugin, parentPlugin, true );
455 
456         Xpp3Dom result = (Xpp3Dom) childPlugin.getConfiguration();
457         Xpp3Dom items = result.getChild( "items" );
458 
459         assertEquals( 1, items.getChildCount() );
460 
461         Xpp3Dom item = items.getChild( 0 );
462         assertEquals( "three", item.getValue() );
463     }
464 
465     public void testShouldMergePluginConfigurationSubItemsWithMergeAttributeSet()
466         throws XmlPullParserException, IOException
467     {
468         String parentConfigStr = "<configuration><items><item>one</item><item>two</item></items></configuration>";
469         Xpp3Dom parentConfig = Xpp3DomBuilder.build( new StringReader( parentConfigStr ) );
470 
471         Plugin parentPlugin = createPlugin( "group", "artifact", "1", null );
472         parentPlugin.setConfiguration( parentConfig );
473 
474         String childConfigStr = "<configuration><items combine.children=\"append\"><item>three</item></items></configuration>";
475         Xpp3Dom childConfig = Xpp3DomBuilder.build( new StringReader( childConfigStr ) );
476 
477         Plugin childPlugin = createPlugin( "group", "artifact", "1", null );
478         childPlugin.setConfiguration( childConfig );
479 
480         ModelUtils.mergePluginDefinitions( childPlugin, parentPlugin, true );
481 
482         Xpp3Dom result = (Xpp3Dom) childPlugin.getConfiguration();
483         Xpp3Dom items = result.getChild( "items" );
484 
485         assertEquals( 3, items.getChildCount() );
486 
487         Xpp3Dom[] item = items.getChildren();
488 
489         List<String> actual = Arrays.asList( item[0].getValue(), item[1].getValue(), item[2].getValue() );
490         List<String> expected = Arrays.asList( "one", "two", "three" );
491         Collections.sort( actual );
492         Collections.sort( expected );
493         assertEquals( expected, actual );
494     }
495 
496     public void testShouldNotMergePluginExecutionWhenExecInheritedIsFalseAndTreatAsInheritanceIsTrue()
497     {
498         String gid = "group";
499         String aid = "artifact";
500         String ver = "1";
501 
502         PluginContainer parent = new PluginContainer();
503         Plugin pParent = createPlugin( gid, aid, ver, Collections.EMPTY_MAP );
504 
505         pParent.setInherited( Boolean.toString( true ) );
506 
507         PluginExecution eParent = new PluginExecution();
508 
509         String testId = "test";
510 
511         eParent.setId( testId );
512         eParent.addGoal( "run" );
513         eParent.setPhase( "initialize" );
514         eParent.setInherited( Boolean.toString( false ) );
515 
516         pParent.addExecution( eParent );
517         parent.addPlugin( pParent );
518 
519         PluginContainer child = new PluginContainer();
520         Plugin pChild = createPlugin( gid, aid, ver, Collections.EMPTY_MAP );
521         PluginExecution eChild = new PluginExecution();
522 
523         eChild.setId( "child-specified" );
524         eChild.addGoal( "child" );
525         eChild.setPhase( "compile" );
526 
527         pChild.addExecution( eChild );
528         child.addPlugin( pChild );
529 
530         ModelUtils.mergePluginDefinitions( pChild, pParent, true );
531 
532         Map executionMap = pChild.getExecutionsAsMap();
533         assertNull( "test execution should not be inherited from parent.", executionMap.get( testId ) );
534     }
535 
536     public void testShouldNotMergePluginExecutionWhenPluginInheritedIsFalseAndTreatAsInheritanceIsTrue()
537     {
538         String gid = "group";
539         String aid = "artifact";
540         String ver = "1";
541 
542         PluginContainer parent = new PluginContainer();
543         Plugin pParent = createPlugin( gid, aid, ver, Collections.EMPTY_MAP );
544 
545         pParent.setInherited( Boolean.toString( false ) );
546 
547         PluginExecution eParent = new PluginExecution();
548 
549         String testId = "test";
550 
551         eParent.setId( testId );
552         eParent.addGoal( "run" );
553         eParent.setPhase( "initialize" );
554         eParent.setInherited( Boolean.toString( true ) );
555 
556         pParent.addExecution( eParent );
557         parent.addPlugin( pParent );
558 
559         PluginContainer child = new PluginContainer();
560         Plugin pChild = createPlugin( gid, aid, ver, Collections.EMPTY_MAP );
561         PluginExecution eChild = new PluginExecution();
562 
563         eChild.setId( "child-specified" );
564         eChild.addGoal( "child" );
565         eChild.setPhase( "compile" );
566 
567         pChild.addExecution( eChild );
568         child.addPlugin( pChild );
569 
570         ModelUtils.mergePluginDefinitions( pChild, pParent, true );
571 
572         Map executionMap = pChild.getExecutionsAsMap();
573         assertNull( "test execution should not be inherited from parent.", executionMap.get( testId ) );
574     }
575 
576     public void testShouldMergePluginExecutionWhenExecInheritedIsTrueAndTreatAsInheritanceIsTrue()
577     {
578         String gid = "group";
579         String aid = "artifact";
580         String ver = "1";
581 
582         PluginContainer parent = new PluginContainer();
583         Plugin pParent = createPlugin( gid, aid, ver, Collections.EMPTY_MAP );
584 
585         pParent.setInherited( Boolean.toString( true ) );
586 
587         PluginExecution eParent = new PluginExecution();
588 
589         String testId = "test";
590 
591         eParent.setId( testId );
592         eParent.addGoal( "run" );
593         eParent.setPhase( "initialize" );
594         eParent.setInherited( Boolean.toString( true ) );
595 
596         pParent.addExecution( eParent );
597         parent.addPlugin( pParent );
598 
599         PluginContainer child = new PluginContainer();
600         Plugin pChild = createPlugin( gid, aid, ver, Collections.EMPTY_MAP );
601         PluginExecution eChild = new PluginExecution();
602 
603         eChild.setId( "child-specified" );
604         eChild.addGoal( "child" );
605         eChild.setPhase( "compile" );
606 
607         pChild.addExecution( eChild );
608         child.addPlugin( pChild );
609 
610         ModelUtils.mergePluginDefinitions( pChild, pParent, true );
611 
612         Map executionMap = pChild.getExecutionsAsMap();
613         assertNotNull( "test execution should be inherited from parent.", executionMap.get( testId ) );
614     }
615 
616 }