github.com/myhau/pulumi/pkg/v3@v3.70.2-0.20221116134521-f2775972e587/resource/graph/dependency_graph_test.go (about) 1 // Copyright 2016-2021, Pulumi Corporation. All rights reserved. 2 3 package graph 4 5 import ( 6 "testing" 7 8 "github.com/pulumi/pulumi/pkg/v3/resource/deploy/providers" 9 "github.com/pulumi/pulumi/sdk/v3/go/common/resource" 10 "github.com/pulumi/pulumi/sdk/v3/go/common/tokens" 11 "github.com/stretchr/testify/assert" 12 ) 13 14 func NewProviderResource(pkg, name, id string, deps ...resource.URN) *resource.State { 15 t := providers.MakeProviderType(tokens.Package(pkg)) 16 return &resource.State{ 17 Type: t, 18 URN: resource.NewURN("test", "test", "", t, tokens.QName(name)), 19 ID: resource.ID(id), 20 Inputs: resource.PropertyMap{}, 21 Outputs: resource.PropertyMap{}, 22 Dependencies: deps, 23 } 24 } 25 26 func NewResource(name string, provider *resource.State, deps ...resource.URN) *resource.State { 27 prov := "" 28 if provider != nil { 29 p, err := providers.NewReference(provider.URN, provider.ID) 30 if err != nil { 31 panic(err) 32 } 33 prov = p.String() 34 } 35 36 t := tokens.Type("test:test:test") 37 return &resource.State{ 38 Type: t, 39 URN: resource.NewURN("test", "test", "", t, tokens.QName(name)), 40 Inputs: resource.PropertyMap{}, 41 Outputs: resource.PropertyMap{}, 42 Dependencies: deps, 43 Provider: prov, 44 } 45 } 46 func TestBasicGraph(t *testing.T) { 47 t.Parallel() 48 49 pA := NewProviderResource("test", "pA", "0") 50 a := NewResource("a", pA) 51 b := NewResource("b", pA, a.URN) 52 pB := NewProviderResource("test", "pB", "1", a.URN, b.URN) 53 c := NewResource("c", pB, a.URN) 54 d := NewResource("d", nil, b.URN) 55 56 dg := NewDependencyGraph([]*resource.State{ 57 pA, 58 a, 59 b, 60 pB, 61 c, 62 d, 63 }) 64 65 assert.Equal(t, []*resource.State{ 66 a, b, pB, c, d, 67 }, dg.DependingOn(pA, nil, false)) 68 69 assert.Equal(t, []*resource.State{ 70 b, pB, c, d, 71 }, dg.DependingOn(a, nil, false)) 72 73 assert.Equal(t, []*resource.State{ 74 pB, c, d, 75 }, dg.DependingOn(b, nil, false)) 76 77 assert.Equal(t, []*resource.State{ 78 c, 79 }, dg.DependingOn(pB, nil, false)) 80 81 assert.Nil(t, dg.DependingOn(c, nil, false)) 82 assert.Nil(t, dg.DependingOn(d, nil, false)) 83 84 assert.Nil(t, dg.DependingOn(pA, map[resource.URN]bool{ 85 a.URN: true, 86 b.URN: true, 87 }, false)) 88 89 assert.Equal(t, []*resource.State{ 90 a, pB, c, 91 }, dg.DependingOn(pA, map[resource.URN]bool{ 92 b.URN: true, 93 }, false)) 94 95 assert.Equal(t, []*resource.State{ 96 b, pB, c, d, 97 }, dg.DependingOn(pA, map[resource.URN]bool{ 98 a.URN: true, 99 }, false)) 100 101 assert.Equal(t, []*resource.State{ 102 c, 103 }, dg.DependingOn(a, map[resource.URN]bool{ 104 b.URN: true, 105 pB.URN: true, 106 }, false)) 107 108 assert.Equal(t, []*resource.State{ 109 pB, c, 110 }, dg.DependingOn(a, map[resource.URN]bool{ 111 b.URN: true, 112 }, false)) 113 114 assert.Equal(t, []*resource.State{ 115 d, 116 }, dg.DependingOn(b, map[resource.URN]bool{ 117 pB.URN: true, 118 }, false)) 119 } 120 121 // Tests that we don't add the same node to the DependingOn set twice. 122 func TestGraphNoDuplicates(t *testing.T) { 123 t.Parallel() 124 125 a := NewResource("a", nil) 126 b := NewResource("b", nil, a.URN) 127 c := NewResource("c", nil, a.URN) 128 d := NewResource("d", nil, b.URN, c.URN) 129 130 dg := NewDependencyGraph([]*resource.State{ 131 a, 132 b, 133 c, 134 d, 135 }) 136 137 assert.Equal(t, []*resource.State{ 138 b, c, d, 139 }, dg.DependingOn(a, nil, false)) 140 } 141 142 func TestDependenciesOf(t *testing.T) { 143 t.Parallel() 144 145 pA := NewProviderResource("test", "pA", "0") 146 a := NewResource("a", pA) 147 b := NewResource("b", pA, a.URN) 148 c := NewResource("c", pA) 149 d := NewResource("d", pA) 150 d.Parent = a.URN 151 152 dg := NewDependencyGraph([]*resource.State{ 153 pA, 154 a, 155 b, 156 c, 157 d, 158 }) 159 160 aDepends := dg.DependenciesOf(a) 161 assert.True(t, aDepends[pA]) 162 assert.False(t, aDepends[a]) 163 assert.False(t, aDepends[b]) 164 165 bDepends := dg.DependenciesOf(b) 166 assert.True(t, bDepends[pA]) 167 assert.True(t, bDepends[a]) 168 assert.False(t, bDepends[b]) 169 170 cDepends := dg.DependenciesOf(c) 171 assert.True(t, cDepends[pA]) 172 assert.False(t, cDepends[a]) 173 assert.False(t, cDepends[b]) 174 175 dDepends := dg.DependenciesOf(d) 176 assert.True(t, dDepends[pA]) 177 assert.True(t, dDepends[a]) // due to A being the parent of D 178 assert.False(t, dDepends[b]) 179 assert.False(t, dDepends[c]) 180 } 181 182 func TestDependenciesOfRemoteComponents(t *testing.T) { 183 t.Parallel() 184 185 aws := NewProviderResource("aws", "default", "0") 186 xyz := NewProviderResource("xyz", "default", "0") 187 first := NewResource("first", xyz) 188 firstNested := NewResource("firstNested", xyz) 189 firstNested.Parent = first.URN 190 sg := NewResource("sg", aws) 191 sg.Parent = firstNested.URN 192 second := NewResource("second", xyz) 193 rule := NewResource("rule", aws, first.URN) 194 rule.Parent = second.URN 195 196 dg := NewDependencyGraph([]*resource.State{ 197 aws, 198 xyz, 199 first, 200 firstNested, 201 sg, 202 second, 203 rule, 204 }) 205 206 ruleDepends := dg.DependenciesOf(rule) 207 assert.True(t, ruleDepends[first], "direct dependency") 208 assert.True(t, ruleDepends[firstNested], "child of dependency") 209 assert.True(t, ruleDepends[sg], "transitive child of dependency") 210 assert.True(t, ruleDepends[second], "parent") 211 assert.True(t, ruleDepends[aws], "provider") 212 assert.False(t, ruleDepends[xyz], "unrelated") 213 } 214 215 func TestDependenciesOfRemoteComponentsNoCycle(t *testing.T) { 216 t.Parallel() 217 218 aws := NewProviderResource("aws", "default", "0") 219 parent := NewResource("parent", aws) 220 r := NewResource("r", aws, parent.URN) 221 child := NewResource("child", aws, r.URN) 222 child.Parent = parent.URN 223 224 dg := NewDependencyGraph([]*resource.State{ 225 aws, 226 parent, 227 r, 228 child, 229 }) 230 231 childDependencies := dg.DependenciesOf(child) 232 assert.True(t, childDependencies[aws]) 233 assert.True(t, childDependencies[parent]) 234 assert.True(t, childDependencies[r]) 235 236 rDependencies := dg.DependenciesOf(r) 237 assert.True(t, rDependencies[aws]) 238 assert.True(t, rDependencies[parent]) 239 assert.False(t, rDependencies[child]) 240 } 241 242 func TestTransitiveDependenciesOf(t *testing.T) { 243 t.Parallel() 244 245 aws := NewProviderResource("aws", "default", "0") 246 parent := NewResource("parent", aws) 247 greatUncle := NewResource("greatUncle", aws) 248 uncle := NewResource("r", aws) 249 uncle.Parent = greatUncle.URN 250 child := NewResource("child", aws, uncle.URN) 251 child.Parent = parent.URN 252 baby := NewResource("baby", aws) 253 baby.Parent = child.URN 254 255 dg := NewDependencyGraph([]*resource.State{ 256 aws, 257 parent, 258 greatUncle, 259 uncle, 260 child, 261 baby, 262 }) 263 // <(relation)- as an alias for depends on via relation 264 // baby <(Parent)- child <(Dependency)- uncle <(Parent)- greatUncle <(Provider)- aws 265 set := dg.TransitiveDependenciesOf(baby) 266 assert.True(t, set[aws], "everything should depend on the provider") 267 assert.True(t, set[greatUncle], "child depends on greatUncle") 268 }