001package org.eclipse.aether.internal.impl.collect.bf; 002/* 003 * Licensed to the Apache Software Foundation (ASF) under one 004 * or more contributor license agreements. See the NOTICE file 005 * distributed with this work for additional information 006 * regarding copyright ownership. The ASF licenses this file 007 * to you under the Apache License, Version 2.0 (the 008 * "License"); you may not use this file except in compliance 009 * with the License. You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, 014 * software distributed under the License is distributed on an 015 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 016 * KIND, either express or implied. See the License for the 017 * specific language governing permissions and limitations 018 * under the License. 019 */ 020 021import java.util.ArrayList; 022import java.util.Arrays; 023import java.util.List; 024import java.util.Map; 025import java.util.stream.Collectors; 026 027import org.eclipse.aether.artifact.DefaultArtifact; 028import org.eclipse.aether.graph.DefaultDependencyNode; 029import org.eclipse.aether.graph.Dependency; 030import org.eclipse.aether.graph.DependencyNode; 031import org.eclipse.aether.internal.test.util.TestVersion; 032import org.eclipse.aether.internal.test.util.TestVersionConstraint; 033import org.junit.Test; 034 035import static org.junit.Assert.assertEquals; 036import static org.junit.Assert.assertFalse; 037import static org.junit.Assert.assertTrue; 038 039 040public class DependencyResolutionSkipperTest 041{ 042 private static DependencyNode makeDependencyNode( String groupId, String artifactId, String version ) 043 { 044 return makeDependencyNode( groupId, artifactId, version, "compile" ); 045 } 046 047 private static List<DependencyNode> mutableList( DependencyNode... nodes ) 048 { 049 return new ArrayList<>( Arrays.asList( nodes ) ); 050 } 051 052 private static DependencyNode makeDependencyNode( String groupId, String artifactId, String version, String scope ) 053 { 054 DefaultDependencyNode node = new DefaultDependencyNode( 055 new Dependency( new DefaultArtifact( groupId + ':' + artifactId + ':' + version ), scope ) 056 ); 057 node.setVersion( new TestVersion( version ) ); 058 node.setVersionConstraint( new TestVersionConstraint( node.getVersion() ) ); 059 return node; 060 } 061 062 @Test 063 public void testSkipVersionConflict() 064 { 065 // A -> B -> C 3.0 -> D => C3.0 SHOULD BE SKIPPED 066 // | -> E -> F -> G 067 // | -> C 2.0 -> H => C2.0 is the winner 068 DependencyNode aNode = makeDependencyNode( "some-group", "A", "1.0" ); 069 DependencyNode bNode = makeDependencyNode( "some-group", "B", "1.0" ); 070 DependencyNode c3Node = makeDependencyNode( "some-group", "C", "3.0" ); 071 DependencyNode dNode = makeDependencyNode( "some-group", "D", "1.0" ); 072 DependencyNode eNode = makeDependencyNode( "some-group", "E", "1.0" ); 073 DependencyNode fNode = makeDependencyNode( "some-group", "F", "1.0" ); 074 DependencyNode c2Node = makeDependencyNode( "some-group", "C", "2.0" ); 075 DependencyNode gNode = makeDependencyNode( "some-group", "G", "1.0" ); 076 DependencyNode hNode = makeDependencyNode( "some-group", "H", "1.0" ); 077 078 aNode.setChildren( mutableList( bNode, eNode, c2Node ) ); 079 bNode.setChildren( mutableList( c3Node ) ); 080 c3Node.setChildren( mutableList( dNode ) ); 081 eNode.setChildren( mutableList( fNode ) ); 082 fNode.setChildren( mutableList( gNode ) ); 083 c2Node.setChildren( mutableList( hNode ) ); 084 085 //follow the BFS resolve sequence 086 DependencyResolutionSkipper.DefaultDependencyResolutionSkipper skipper = DependencyResolutionSkipper.defaultSkipper(); 087 assertFalse( skipper.skipResolution( aNode, new ArrayList<>() ) ); 088 skipper.cache( aNode, new ArrayList<>() ); 089 assertFalse( skipper.skipResolution( bNode, mutableList( aNode ) ) ); 090 skipper.cache( bNode, mutableList( aNode ) ); 091 assertFalse( skipper.skipResolution( eNode, mutableList( aNode ) ) ); 092 skipper.cache( eNode, mutableList( aNode ) ); 093 assertFalse( skipper.skipResolution( c2Node, mutableList( aNode ) ) ); 094 skipper.cache( c2Node, mutableList( aNode ) ); 095 assertTrue( skipper.skipResolution( c3Node, mutableList( aNode, bNode ) ) );//version conflict 096 assertFalse( skipper.skipResolution( fNode, mutableList( aNode, eNode ) ) ); 097 skipper.cache( fNode, mutableList( aNode, eNode ) ); 098 assertFalse( skipper.skipResolution( gNode, mutableList( aNode, eNode, fNode ) ) ); 099 skipper.cache( gNode, mutableList( aNode, eNode, fNode ) ); 100 101 Map<DependencyNode, DependencyResolutionSkipper.DependencyResolutionResult> results = skipper.getResults(); 102 assertEquals( results.size(), 7 ); 103 104 List<DependencyResolutionSkipper.DependencyResolutionResult> skipped = 105 results.values().stream() 106 .filter( dependencyResolutionResult -> dependencyResolutionResult.skippedAsVersionConflict ) 107 .collect( Collectors.toList() ); 108 assertEquals( skipped.size(), 1 ); 109 assertTrue( skipped.get( 0 ).current == c3Node ); 110 } 111 112 @Test 113 public void testSkipDeeperDuplicateNode() 114 { 115 // A -> B 116 // |--> C -> B => B here will be skipped 117 // |--> D -> C => C here will be skipped 118 DependencyNode aNode = makeDependencyNode( "some-group", "A", "1.0" ); 119 DependencyNode bNode = makeDependencyNode( "some-group", "B", "1.0" ); 120 DependencyNode cNode = makeDependencyNode( "some-group", "C", "1.0" ); 121 DependencyNode dNode = makeDependencyNode( "some-group", "D", "1.0" ); 122 DependencyNode b1Node = new DefaultDependencyNode( bNode ); 123 DependencyNode c1Node = new DefaultDependencyNode( cNode ); 124 125 aNode.setChildren( mutableList( bNode, cNode, dNode ) ); 126 bNode.setChildren( new ArrayList<>() ); 127 cNode.setChildren( mutableList( b1Node ) ); 128 dNode.setChildren( mutableList( c1Node ) ); 129 130 //follow the BFS resolve sequence 131 DependencyResolutionSkipper.DefaultDependencyResolutionSkipper skipper = DependencyResolutionSkipper.defaultSkipper(); 132 assertFalse( skipper.skipResolution( aNode, new ArrayList<>() ) ); 133 skipper.cache( aNode, new ArrayList<>() ); 134 assertFalse( skipper.skipResolution( bNode, mutableList( aNode ) ) ); 135 skipper.cache( bNode, mutableList( aNode ) ); 136 assertFalse( skipper.skipResolution( cNode, mutableList( aNode ) ) ); 137 skipper.cache( cNode, mutableList( aNode ) ); 138 assertFalse( skipper.skipResolution( dNode, mutableList( aNode ) ) ); 139 skipper.cache( dNode, mutableList( aNode ) ); 140 141 assertTrue( skipper.skipResolution( b1Node, mutableList( aNode, cNode ) ) ); 142 skipper.cache( b1Node, mutableList( aNode, cNode ) ); 143 144 assertTrue( skipper.skipResolution( c1Node, mutableList( aNode, dNode ) ) ); 145 skipper.cache( c1Node, mutableList( aNode, dNode ) ); 146 147 Map<DependencyNode, DependencyResolutionSkipper.DependencyResolutionResult> results = skipper.getResults(); 148 assertEquals( results.size(), 6 ); 149 150 List<DependencyResolutionSkipper.DefaultDependencyResolutionSkipper.DependencyResolutionResult> skipped = 151 results.values().stream() 152 .filter( dependencyResolutionResult -> dependencyResolutionResult.skippedAsDuplicate ) 153 .collect( Collectors.toList() ); 154 assertEquals( skipped.size(), 2 ); 155 assertTrue( skipped.get( 0 ).current == b1Node ); 156 assertTrue( skipped.get( 1 ).current == c1Node ); 157 } 158 159 160 @Test 161 public void testForceResolution() 162 { 163 // A -> B -> C -> D => 3rd D here will be force-resolved 164 // |--> C -> D => 2nd D will be force-resolved 165 // |--> D => 1st D to resolve 166 DependencyNode aNode = makeDependencyNode( "some-group", "A", "1.0" ); 167 DependencyNode bNode = makeDependencyNode( "some-group", "B", "1.0" ); 168 DependencyNode cNode = makeDependencyNode( "some-group", "C", "1.0" ); 169 DependencyNode dNode = makeDependencyNode( "some-group", "D", "1.0" ); 170 DependencyNode c1Node = new DefaultDependencyNode( cNode ); 171 DependencyNode d1Node = new DefaultDependencyNode( dNode ); 172 DependencyNode d2Node = new DefaultDependencyNode( dNode ); 173 174 aNode.setChildren( mutableList( bNode, cNode, dNode ) ); 175 bNode.setChildren( mutableList( c1Node ) ); 176 c1Node.setChildren( mutableList( d2Node ) ); 177 cNode.setChildren( mutableList( d1Node ) ); 178 dNode.setChildren( new ArrayList<>() ); 179 180 //follow the BFS resolve sequence 181 DependencyResolutionSkipper.DefaultDependencyResolutionSkipper skipper = DependencyResolutionSkipper.defaultSkipper(); 182 assertFalse( skipper.skipResolution( aNode, new ArrayList<>() ) ); 183 skipper.cache( aNode, new ArrayList<>() ); 184 assertFalse( skipper.skipResolution( bNode, mutableList( aNode ) ) ); 185 skipper.cache( bNode, mutableList( aNode ) ); 186 assertFalse( skipper.skipResolution( cNode, mutableList( aNode ) ) ); 187 skipper.cache( cNode, mutableList( aNode ) ); 188 assertFalse( skipper.skipResolution( dNode, mutableList( aNode ) ) ); 189 skipper.cache( dNode, mutableList( aNode ) ); 190 191 assertFalse( skipper.skipResolution( c1Node, mutableList( aNode, bNode ) ) ); 192 skipper.cache( c1Node, mutableList( aNode, bNode ) ); 193 194 assertFalse( skipper.skipResolution( d1Node, mutableList( aNode, cNode ) ) ); 195 skipper.cache( d1Node, mutableList( aNode, cNode ) ); 196 197 assertFalse( skipper.skipResolution( d2Node, mutableList( aNode, bNode, c1Node ) ) ); 198 skipper.cache( d2Node, mutableList( aNode, bNode, c1Node ) ); 199 200 Map<DependencyNode, DependencyResolutionSkipper.DependencyResolutionResult> results = skipper.getResults(); 201 assertEquals( results.size(), 7 ); 202 203 List<DependencyResolutionSkipper.DefaultDependencyResolutionSkipper.DependencyResolutionResult> forceResolved = 204 results.values().stream() 205 .filter( dependencyResolutionResult -> dependencyResolutionResult.forceResolution ) 206 .collect( Collectors.toList() ); 207 assertEquals( forceResolved.size(), 3 ); 208 assertTrue( forceResolved.get( 0 ).current == c1Node ); 209 assertTrue( forceResolved.get( 1 ).current == d1Node ); 210 assertTrue( forceResolved.get( 2 ).current == d2Node ); 211 } 212 213}