View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.eclipse.aether.internal.impl.collect.bf;
20  
21  import java.util.ArrayList;
22  import java.util.Arrays;
23  import java.util.List;
24  import java.util.Map;
25  import java.util.stream.Collectors;
26  
27  import org.eclipse.aether.artifact.DefaultArtifact;
28  import org.eclipse.aether.graph.DefaultDependencyNode;
29  import org.eclipse.aether.graph.Dependency;
30  import org.eclipse.aether.graph.DependencyNode;
31  import org.eclipse.aether.internal.test.util.TestVersion;
32  import org.eclipse.aether.internal.test.util.TestVersionConstraint;
33  import org.junit.jupiter.api.Test;
34  
35  import static org.junit.jupiter.api.Assertions.*;
36  
37  public class DependencyResolutionSkipperTest {
38      private static DependencyNode makeDependencyNode(String groupId, String artifactId, String version) {
39          return makeDependencyNode(groupId, artifactId, version, "compile");
40      }
41  
42      private static List<DependencyNode> mutableList(DependencyNode... nodes) {
43          return new ArrayList<>(Arrays.asList(nodes));
44      }
45  
46      private static DependencyNode makeDependencyNode(String groupId, String artifactId, String version, String scope) {
47          DefaultDependencyNode node = new DefaultDependencyNode(
48                  new Dependency(new DefaultArtifact(groupId + ':' + artifactId + ':' + version), scope));
49          node.setVersion(new TestVersion(version));
50          node.setVersionConstraint(new TestVersionConstraint(node.getVersion()));
51          return node;
52      }
53  
54      @Test
55      void testSkipVersionConflict() {
56          // A -> B -> C 3.0 -> D   => C3.0 SHOULD BE SKIPPED
57          // | -> E -> F -> G
58          // | -> C 2.0 -> H  => C2.0 is the winner
59          DependencyNode aNode = makeDependencyNode("some-group", "A", "1.0");
60          DependencyNode bNode = makeDependencyNode("some-group", "B", "1.0");
61          DependencyNode c3Node = makeDependencyNode("some-group", "C", "3.0");
62          DependencyNode dNode = makeDependencyNode("some-group", "D", "1.0");
63          DependencyNode eNode = makeDependencyNode("some-group", "E", "1.0");
64          DependencyNode fNode = makeDependencyNode("some-group", "F", "1.0");
65          DependencyNode c2Node = makeDependencyNode("some-group", "C", "2.0");
66          DependencyNode gNode = makeDependencyNode("some-group", "G", "1.0");
67          DependencyNode hNode = makeDependencyNode("some-group", "H", "1.0");
68  
69          aNode.setChildren(mutableList(bNode, eNode, c2Node));
70          bNode.setChildren(mutableList(c3Node));
71          c3Node.setChildren(mutableList(dNode));
72          eNode.setChildren(mutableList(fNode));
73          fNode.setChildren(mutableList(gNode));
74          c2Node.setChildren(mutableList(hNode));
75  
76          // follow the BFS resolve sequence
77          try (DependencyResolutionSkipper.DefaultDependencyResolutionSkipper skipper =
78                  DependencyResolutionSkipper.defaultSkipper()) {
79              assertFalse(skipper.skipResolution(aNode, new ArrayList<>()));
80              skipper.cache(aNode, new ArrayList<>());
81              assertFalse(skipper.skipResolution(bNode, mutableList(aNode)));
82              skipper.cache(bNode, mutableList(aNode));
83              assertFalse(skipper.skipResolution(eNode, mutableList(aNode)));
84              skipper.cache(eNode, mutableList(aNode));
85              assertFalse(skipper.skipResolution(c2Node, mutableList(aNode)));
86              skipper.cache(c2Node, mutableList(aNode));
87              assertTrue(skipper.skipResolution(c3Node, mutableList(aNode, bNode))); // version conflict
88              assertFalse(skipper.skipResolution(fNode, mutableList(aNode, eNode)));
89              skipper.cache(fNode, mutableList(aNode, eNode));
90              assertFalse(skipper.skipResolution(gNode, mutableList(aNode, eNode, fNode)));
91              skipper.cache(gNode, mutableList(aNode, eNode, fNode));
92  
93              Map<DependencyNode, DependencyResolutionSkipper.DependencyResolutionResult> results = skipper.getResults();
94              assertEquals(results.size(), 7);
95  
96              List<DependencyResolutionSkipper.DependencyResolutionResult> skipped = results.values().stream()
97                      .filter(dependencyResolutionResult -> dependencyResolutionResult.skippedAsVersionConflict)
98                      .collect(Collectors.toList());
99              assertEquals(skipped.size(), 1);
100             assertSame(skipped.get(0).current, c3Node);
101         }
102     }
103 
104     @Test
105     void testSkipDeeperDuplicateNode() {
106         // A -> B
107         // |--> C -> B  => B here will be skipped
108         // |--> D -> C  => C here will be skipped
109         DependencyNode aNode = makeDependencyNode("some-group", "A", "1.0");
110         DependencyNode bNode = makeDependencyNode("some-group", "B", "1.0");
111         DependencyNode cNode = makeDependencyNode("some-group", "C", "1.0");
112         DependencyNode dNode = makeDependencyNode("some-group", "D", "1.0");
113         DependencyNode b1Node = new DefaultDependencyNode(bNode);
114         DependencyNode c1Node = new DefaultDependencyNode(cNode);
115 
116         aNode.setChildren(mutableList(bNode, cNode, dNode));
117         bNode.setChildren(new ArrayList<>());
118         cNode.setChildren(mutableList(b1Node));
119         dNode.setChildren(mutableList(c1Node));
120 
121         // follow the BFS resolve sequence
122         try (DependencyResolutionSkipper.DefaultDependencyResolutionSkipper skipper =
123                 DependencyResolutionSkipper.defaultSkipper()) {
124             assertFalse(skipper.skipResolution(aNode, new ArrayList<>()));
125             skipper.cache(aNode, new ArrayList<>());
126             assertFalse(skipper.skipResolution(bNode, mutableList(aNode)));
127             skipper.cache(bNode, mutableList(aNode));
128             assertFalse(skipper.skipResolution(cNode, mutableList(aNode)));
129             skipper.cache(cNode, mutableList(aNode));
130             assertFalse(skipper.skipResolution(dNode, mutableList(aNode)));
131             skipper.cache(dNode, mutableList(aNode));
132 
133             assertTrue(skipper.skipResolution(b1Node, mutableList(aNode, cNode)));
134             skipper.cache(b1Node, mutableList(aNode, cNode));
135 
136             assertTrue(skipper.skipResolution(c1Node, mutableList(aNode, dNode)));
137             skipper.cache(c1Node, mutableList(aNode, dNode));
138 
139             Map<DependencyNode, DependencyResolutionSkipper.DependencyResolutionResult> results = skipper.getResults();
140             assertEquals(results.size(), 6);
141 
142             List<DependencyResolutionSkipper.DefaultDependencyResolutionSkipper.DependencyResolutionResult> skipped =
143                     results.values().stream()
144                             .filter(dependencyResolutionResult -> dependencyResolutionResult.skippedAsDuplicate)
145                             .collect(Collectors.toList());
146             assertEquals(skipped.size(), 2);
147             assertSame(skipped.get(0).current, b1Node);
148             assertSame(skipped.get(1).current, c1Node);
149         }
150     }
151 
152     @Test
153     void testForceResolution() {
154         // A -> B -> C -> D => 3rd D here will be force-resolved
155         // |--> C -> D => 2nd D will be force-resolved
156         // |--> D => 1st D to resolve
157         DependencyNode aNode = makeDependencyNode("some-group", "A", "1.0");
158         DependencyNode bNode = makeDependencyNode("some-group", "B", "1.0");
159         DependencyNode cNode = makeDependencyNode("some-group", "C", "1.0");
160         DependencyNode dNode = makeDependencyNode("some-group", "D", "1.0");
161         DependencyNode c1Node = new DefaultDependencyNode(cNode);
162         DependencyNode d1Node = new DefaultDependencyNode(dNode);
163         DependencyNode d2Node = new DefaultDependencyNode(dNode);
164 
165         aNode.setChildren(mutableList(bNode, cNode, dNode));
166         bNode.setChildren(mutableList(c1Node));
167         c1Node.setChildren(mutableList(d2Node));
168         cNode.setChildren(mutableList(d1Node));
169         dNode.setChildren(new ArrayList<>());
170 
171         // follow the BFS resolve sequence
172         try (DependencyResolutionSkipper.DefaultDependencyResolutionSkipper skipper =
173                 DependencyResolutionSkipper.defaultSkipper()) {
174             assertFalse(skipper.skipResolution(aNode, new ArrayList<>()));
175             skipper.cache(aNode, new ArrayList<>());
176             assertFalse(skipper.skipResolution(bNode, mutableList(aNode)));
177             skipper.cache(bNode, mutableList(aNode));
178             assertFalse(skipper.skipResolution(cNode, mutableList(aNode)));
179             skipper.cache(cNode, mutableList(aNode));
180             assertFalse(skipper.skipResolution(dNode, mutableList(aNode)));
181             skipper.cache(dNode, mutableList(aNode));
182 
183             assertFalse(skipper.skipResolution(c1Node, mutableList(aNode, bNode)));
184             skipper.cache(c1Node, mutableList(aNode, bNode));
185 
186             assertFalse(skipper.skipResolution(d1Node, mutableList(aNode, cNode)));
187             skipper.cache(d1Node, mutableList(aNode, cNode));
188 
189             assertFalse(skipper.skipResolution(d2Node, mutableList(aNode, bNode, c1Node)));
190             skipper.cache(d2Node, mutableList(aNode, bNode, c1Node));
191 
192             Map<DependencyNode, DependencyResolutionSkipper.DependencyResolutionResult> results = skipper.getResults();
193             assertEquals(results.size(), 7);
194 
195             List<DependencyResolutionSkipper.DefaultDependencyResolutionSkipper.DependencyResolutionResult>
196                     forceResolved = results.values().stream()
197                             .filter(dependencyResolutionResult -> dependencyResolutionResult.forceResolution)
198                             .collect(Collectors.toList());
199             assertEquals(forceResolved.size(), 3);
200             assertSame(forceResolved.get(0).current, c1Node);
201             assertSame(forceResolved.get(1).current, d1Node);
202             assertSame(forceResolved.get(2).current, d2Node);
203         }
204     }
205 }