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