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.Iterator;
027import java.util.List;
028import java.util.Map;
029
030import junit.framework.TestCase;
031
032import org.apache.maven.model.Build;
033import org.apache.maven.model.Dependency;
034import org.apache.maven.model.Plugin;
035import org.apache.maven.model.PluginContainer;
036import org.apache.maven.model.PluginExecution;
037import org.codehaus.plexus.util.xml.Xpp3Dom;
038import org.codehaus.plexus.util.xml.Xpp3DomBuilder;
039import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
040
041public class ModelUtilsTest
042    extends TestCase
043{
044
045    public void testShouldUseMainPluginDependencyVersionOverManagedDepVersion()
046    {
047        Plugin mgtPlugin = createPlugin( "group", "artifact", "1", Collections.EMPTY_MAP );
048        Dependency mgtDep = createDependency( "g", "a", "2" );
049        mgtPlugin.addDependency( mgtDep );
050
051        Plugin plugin = createPlugin( "group", "artifact", "1", Collections.EMPTY_MAP );
052        Dependency dep = createDependency( "g", "a", "1" );
053        plugin.addDependency( dep );
054
055        ModelUtils.mergePluginDefinitions( plugin, mgtPlugin, false );
056
057        assertEquals( dep.getVersion(), plugin.getDependencies().get( 0 ).getVersion() );
058    }
059
060    private Dependency createDependency( String gid,
061                                         String aid,
062                                         String ver )
063    {
064        Dependency dep = new Dependency();
065        dep.setGroupId( gid );
066        dep.setArtifactId( aid );
067        dep.setVersion( ver );
068
069        return dep;
070    }
071
072    public void testShouldNotInheritPluginWithInheritanceSetToFalse()
073    {
074        PluginContainer parent = new PluginContainer();
075
076        Plugin parentPlugin = createPlugin( "group", "artifact", "1.0", Collections.EMPTY_MAP );
077        parentPlugin.setInherited( "false" );
078
079        parent.addPlugin( parentPlugin );
080
081        PluginContainer child = new PluginContainer();
082
083        child.addPlugin( createPlugin( "group3", "artifact3", "1.0", Collections.EMPTY_MAP ) );
084
085        ModelUtils.mergePluginLists( child, parent, true );
086
087        List results = child.getPlugins();
088
089        assertEquals( 1, results.size() );
090
091        Plugin result1 = (Plugin) results.get( 0 );
092        assertEquals( "group3", result1.getGroupId() );
093        assertEquals( "artifact3", result1.getArtifactId() );
094    }
095
096    /**
097     * Test that this is the resulting ordering of plugins after merging:
098     *
099     * 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 ( Object o : configuration.entrySet() )
161            {
162                Map.Entry entry = (Map.Entry) o;
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 = 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}