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.util.graph.transformer;
20  
21  import java.util.List;
22  
23  import org.eclipse.aether.collection.UnsolvableVersionConflictException;
24  import org.eclipse.aether.graph.DependencyNode;
25  import org.eclipse.aether.internal.test.util.DependencyGraphParser;
26  import org.junit.jupiter.api.Test;
27  
28  import static org.junit.jupiter.api.Assertions.assertEquals;
29  import static org.junit.jupiter.api.Assertions.assertSame;
30  import static org.junit.jupiter.api.Assertions.assertThrows;
31  import static org.junit.jupiter.api.Assertions.assertTrue;
32  
33  /**
34   */
35  public class ConfigurableVersionSelectorTest extends AbstractDependencyGraphTransformerTest {
36      @Override
37      protected ConflictResolver newTransformer() {
38          return new ConflictResolver(
39                  new ConfigurableVersionSelector(new ConfigurableVersionSelector.MajorVersionConvergence(
40                          new ConfigurableVersionSelector.Nearest())),
41                  new JavaScopeSelector(),
42                  new SimpleOptionalitySelector(),
43                  new JavaScopeDeriver());
44      }
45  
46      @Override
47      protected DependencyGraphParser newParser() {
48          return new DependencyGraphParser("transformer/version-resolver/");
49      }
50  
51      @Test
52      void testSelectHighestVersionFromMultipleVersionsAtSameLevel() throws Exception {
53          DependencyNode root = parseResource("sibling-versions.txt");
54          assertSame(root, transform(root));
55  
56          assertEquals(1, root.getChildren().size());
57          assertEquals("3", root.getChildren().get(0).getArtifact().getVersion());
58      }
59  
60      @Test
61      void testSelectHighestVersionFromMultipleVersionsAtSameLevelIncompatibleMajors() {
62          assertThrows(UnsolvableVersionConflictException.class, () -> {
63              DependencyNode root = parseResource("sibling-major-versions.txt");
64              transform(root);
65          });
66      }
67  
68      @Test
69      void testSelectedVersionAtDeeperLevelThanOriginallySeen() throws Exception {
70          DependencyNode root = parseResource("nearest-underneath-loser-a.txt");
71  
72          assertSame(root, transform(root));
73  
74          List<DependencyNode> trail = find(root, "j");
75          assertEquals(5, trail.size());
76      }
77  
78      @Test
79      void testNearestDirtyVersionUnderneathRemovedNode() throws Exception {
80          DependencyNode root = parseResource("nearest-underneath-loser-b.txt");
81  
82          assertSame(root, transform(root));
83  
84          List<DependencyNode> trail = find(root, "j");
85          assertEquals(5, trail.size());
86      }
87  
88      @Test
89      void testViolationOfHardConstraintFallsBackToNearestSeenNotFirstSeenIncompatibleMajors() throws Exception {
90          assertThrows(UnsolvableVersionConflictException.class, () -> {
91              DependencyNode root = parseResource("range-major-backtracking.txt");
92              transform(root);
93          });
94      }
95  
96      @Test
97      void testViolationOfHardConstraintFallsBackToNearestSeenNotFirstSeen() throws Exception {
98          DependencyNode root = parseResource("range-backtracking.txt");
99  
100         assertSame(root, transform(root));
101 
102         List<DependencyNode> trail = find(root, "x");
103         assertEquals(3, trail.size());
104         assertEquals("2", trail.get(0).getArtifact().getVersion());
105     }
106 
107     @Test
108     void testCyclicConflictIdGraph() throws Exception {
109         DependencyNode root = parseResource("conflict-id-cycle.txt");
110 
111         assertSame(root, transform(root));
112 
113         assertEquals(2, root.getChildren().size());
114         assertEquals("a", root.getChildren().get(0).getArtifact().getArtifactId());
115         assertEquals("b", root.getChildren().get(1).getArtifact().getArtifactId());
116         assertTrue(root.getChildren().get(0).getChildren().isEmpty());
117         assertTrue(root.getChildren().get(1).getChildren().isEmpty());
118     }
119 
120     @Test
121     void testUnsolvableRangeConflictBetweenHardConstraints() {
122         assertThrows(UnsolvableVersionConflictException.class, () -> {
123             DependencyNode root = parseResource("unsolvable.txt");
124             transform(root);
125         });
126     }
127 
128     @Test
129     void testUnsolvableRangeConflictWithUnrelatedCycle() throws Exception {
130         assertThrows(UnsolvableVersionConflictException.class, () -> {
131             DependencyNode root = parseResource("unsolvable-with-cycle.txt");
132             assertSame(root, transform(root));
133         });
134     }
135 
136     @Test
137     void testSolvableConflictBetweenHardConstraints() throws Exception {
138         DependencyNode root = parseResource("ranges.txt");
139 
140         assertSame(root, transform(root));
141     }
142 
143     @Test
144     void testConflictGroupCompletelyDroppedFromResolvedTree() throws Exception {
145         DependencyNode root = parseResource("dead-conflict-group.txt");
146 
147         assertSame(root, transform(root));
148 
149         assertEquals(2, root.getChildren().size());
150         assertEquals("a", root.getChildren().get(0).getArtifact().getArtifactId());
151         assertEquals("b", root.getChildren().get(1).getArtifact().getArtifactId());
152         assertTrue(root.getChildren().get(0).getChildren().isEmpty());
153         assertTrue(root.getChildren().get(1).getChildren().isEmpty());
154     }
155 
156     @Test
157     void testNearestSoftVersionPrunedByFartherRange() throws Exception {
158         DependencyNode root = parseResource("soft-vs-range.txt");
159 
160         assertSame(root, transform(root));
161 
162         assertEquals(2, root.getChildren().size());
163         assertEquals("a", root.getChildren().get(0).getArtifact().getArtifactId());
164         assertEquals(0, root.getChildren().get(0).getChildren().size());
165         assertEquals("b", root.getChildren().get(1).getArtifact().getArtifactId());
166         assertEquals(1, root.getChildren().get(1).getChildren().size());
167     }
168 
169     @Test
170     void testCyclicGraph() throws Exception {
171         DependencyNode root = parseResource("cycle.txt");
172 
173         assertSame(root, transform(root));
174 
175         assertEquals(2, root.getChildren().size());
176         assertEquals(1, root.getChildren().get(0).getChildren().size());
177         assertEquals(
178                 0, root.getChildren().get(0).getChildren().get(0).getChildren().size());
179         assertEquals(0, root.getChildren().get(1).getChildren().size());
180     }
181 
182     @Test
183     void testLoop() throws Exception {
184         DependencyNode root = parseResource("loop.txt");
185 
186         assertSame(root, transform(root));
187 
188         assertEquals(0, root.getChildren().size());
189     }
190 
191     @Test
192     void testOverlappingCycles() throws Exception {
193         DependencyNode root = parseResource("overlapping-cycles.txt");
194 
195         assertSame(root, transform(root));
196 
197         assertEquals(2, root.getChildren().size());
198     }
199 
200     @Test
201     void testScopeDerivationAndConflictResolutionCantHappenForAllNodesBeforeVersionSelection() throws Exception {
202         DependencyNode root = parseResource("scope-vs-version.txt");
203 
204         assertSame(root, transform(root));
205 
206         DependencyNode[] nodes = find(root, "y").toArray(new DependencyNode[0]);
207         assertEquals(3, nodes.length);
208         assertEquals("test", nodes[1].getDependency().getScope());
209         assertEquals("test", nodes[0].getDependency().getScope());
210     }
211 
212     @Test
213     void testVerboseMode() throws Exception {
214         DependencyNode root = parseResource("verbose.txt");
215 
216         session.setConfigProperty(ConflictResolver.CONFIG_PROP_VERBOSE, Boolean.TRUE);
217         assertSame(root, transform(root));
218 
219         assertEquals(2, root.getChildren().size());
220         assertEquals(1, root.getChildren().get(0).getChildren().size());
221         DependencyNode winner = root.getChildren().get(0).getChildren().get(0);
222         assertEquals("test", winner.getDependency().getScope());
223         assertEquals("compile", winner.getData().get(ConflictResolver.NODE_DATA_ORIGINAL_SCOPE));
224         assertEquals(false, winner.getData().get(ConflictResolver.NODE_DATA_ORIGINAL_OPTIONALITY));
225         assertEquals(1, root.getChildren().get(1).getChildren().size());
226         DependencyNode loser = root.getChildren().get(1).getChildren().get(0);
227         assertEquals("test", loser.getDependency().getScope());
228         assertEquals(0, loser.getChildren().size());
229         assertSame(winner, loser.getData().get(ConflictResolver.NODE_DATA_WINNER));
230         assertEquals("compile", loser.getData().get(ConflictResolver.NODE_DATA_ORIGINAL_SCOPE));
231         assertEquals(false, loser.getData().get(ConflictResolver.NODE_DATA_ORIGINAL_OPTIONALITY));
232     }
233 }