mirror of https://github.com/pulumi/pulumi.git
326 lines
7.9 KiB
Go
326 lines
7.9 KiB
Go
// Copyright 2016-2021, Pulumi Corporation. All rights reserved.
|
|
|
|
package graph
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/pulumi/pulumi/pkg/v3/resource/deploy/providers"
|
|
"github.com/pulumi/pulumi/sdk/v3/go/common/resource"
|
|
"github.com/pulumi/pulumi/sdk/v3/go/common/tokens"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func NewProviderResource(pkg, name, id string, deps ...resource.URN) *resource.State {
|
|
t := providers.MakeProviderType(tokens.Package(pkg))
|
|
return &resource.State{
|
|
Type: t,
|
|
URN: resource.NewURN("test", "test", "", t, name),
|
|
ID: resource.ID(id),
|
|
Inputs: resource.PropertyMap{},
|
|
Outputs: resource.PropertyMap{},
|
|
Dependencies: deps,
|
|
}
|
|
}
|
|
|
|
func NewResource(name string, provider *resource.State, deps ...resource.URN) *resource.State {
|
|
prov := ""
|
|
if provider != nil {
|
|
p, err := providers.NewReference(provider.URN, provider.ID)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
prov = p.String()
|
|
}
|
|
|
|
t := tokens.Type("test:test:test")
|
|
return &resource.State{
|
|
Type: t,
|
|
URN: resource.NewURN("test", "test", "", t, name),
|
|
Inputs: resource.PropertyMap{},
|
|
Outputs: resource.PropertyMap{},
|
|
Dependencies: deps,
|
|
Provider: prov,
|
|
}
|
|
}
|
|
|
|
func TestBasicGraph(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
pA := NewProviderResource("test", "pA", "0")
|
|
a := NewResource("a", pA)
|
|
b := NewResource("b", pA, a.URN)
|
|
pB := NewProviderResource("test", "pB", "1", a.URN, b.URN)
|
|
c := NewResource("c", pB, a.URN)
|
|
d := NewResource("d", nil, b.URN)
|
|
|
|
dg := NewDependencyGraph([]*resource.State{
|
|
pA,
|
|
a,
|
|
b,
|
|
pB,
|
|
c,
|
|
d,
|
|
})
|
|
|
|
assert.Equal(t, []*resource.State{
|
|
a, b, pB, c, d,
|
|
}, dg.DependingOn(pA, nil, false))
|
|
|
|
assert.Equal(t, []*resource.State{
|
|
b, pB, c, d,
|
|
}, dg.DependingOn(a, nil, false))
|
|
|
|
assert.Equal(t, []*resource.State{
|
|
pB, c, d,
|
|
}, dg.DependingOn(b, nil, false))
|
|
|
|
assert.Equal(t, []*resource.State{
|
|
c,
|
|
}, dg.DependingOn(pB, nil, false))
|
|
|
|
assert.Nil(t, dg.DependingOn(c, nil, false))
|
|
assert.Nil(t, dg.DependingOn(d, nil, false))
|
|
|
|
assert.Nil(t, dg.DependingOn(pA, map[resource.URN]bool{
|
|
a.URN: true,
|
|
b.URN: true,
|
|
}, false))
|
|
|
|
assert.Equal(t, []*resource.State{
|
|
a, pB, c,
|
|
}, dg.DependingOn(pA, map[resource.URN]bool{
|
|
b.URN: true,
|
|
}, false))
|
|
|
|
assert.Equal(t, []*resource.State{
|
|
b, pB, c, d,
|
|
}, dg.DependingOn(pA, map[resource.URN]bool{
|
|
a.URN: true,
|
|
}, false))
|
|
|
|
assert.Equal(t, []*resource.State{
|
|
c,
|
|
}, dg.DependingOn(a, map[resource.URN]bool{
|
|
b.URN: true,
|
|
pB.URN: true,
|
|
}, false))
|
|
|
|
assert.Equal(t, []*resource.State{
|
|
pB, c,
|
|
}, dg.DependingOn(a, map[resource.URN]bool{
|
|
b.URN: true,
|
|
}, false))
|
|
|
|
assert.Equal(t, []*resource.State{
|
|
d,
|
|
}, dg.DependingOn(b, map[resource.URN]bool{
|
|
pB.URN: true,
|
|
}, false))
|
|
}
|
|
|
|
// Tests that we don't add the same node to the DependingOn set twice.
|
|
func TestGraphNoDuplicates(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
a := NewResource("a", nil)
|
|
b := NewResource("b", nil, a.URN)
|
|
c := NewResource("c", nil, a.URN)
|
|
d := NewResource("d", nil, b.URN, c.URN)
|
|
|
|
dg := NewDependencyGraph([]*resource.State{
|
|
a,
|
|
b,
|
|
c,
|
|
d,
|
|
})
|
|
|
|
assert.Equal(t, []*resource.State{
|
|
b, c, d,
|
|
}, dg.DependingOn(a, nil, false))
|
|
}
|
|
|
|
func TestDependenciesOf(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
pA := NewProviderResource("test", "pA", "0")
|
|
a := NewResource("a", pA)
|
|
b := NewResource("b", pA, a.URN)
|
|
c := NewResource("c", pA)
|
|
d := NewResource("d", pA)
|
|
d.Parent = a.URN
|
|
|
|
dg := NewDependencyGraph([]*resource.State{
|
|
pA,
|
|
a,
|
|
b,
|
|
c,
|
|
d,
|
|
})
|
|
|
|
aDepends := dg.DependenciesOf(a)
|
|
assert.True(t, aDepends.Contains(pA))
|
|
assert.False(t, aDepends.Contains(a))
|
|
assert.False(t, aDepends.Contains(b))
|
|
|
|
bDepends := dg.DependenciesOf(b)
|
|
assert.True(t, bDepends.Contains(pA))
|
|
assert.True(t, bDepends.Contains(a))
|
|
assert.False(t, bDepends.Contains(b))
|
|
|
|
cDepends := dg.DependenciesOf(c)
|
|
assert.True(t, cDepends.Contains(pA))
|
|
assert.False(t, cDepends.Contains(a))
|
|
assert.False(t, cDepends.Contains(b))
|
|
|
|
dDepends := dg.DependenciesOf(d)
|
|
assert.True(t, dDepends.Contains(pA))
|
|
assert.True(t, dDepends.Contains(a)) // due to A being the parent of D
|
|
assert.False(t, dDepends.Contains(b))
|
|
assert.False(t, dDepends.Contains(c))
|
|
}
|
|
|
|
func TestDependenciesOfRemoteComponents(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
aws := NewProviderResource("aws", "default", "0")
|
|
xyz := NewProviderResource("xyz", "default", "0")
|
|
first := NewResource("first", xyz)
|
|
firstNested := NewResource("firstNested", xyz)
|
|
firstNested.Parent = first.URN
|
|
sg := NewResource("sg", aws)
|
|
sg.Parent = firstNested.URN
|
|
second := NewResource("second", xyz)
|
|
rule := NewResource("rule", aws, first.URN)
|
|
rule.Parent = second.URN
|
|
|
|
dg := NewDependencyGraph([]*resource.State{
|
|
aws,
|
|
xyz,
|
|
first,
|
|
firstNested,
|
|
sg,
|
|
second,
|
|
rule,
|
|
})
|
|
|
|
ruleDepends := dg.DependenciesOf(rule)
|
|
assert.True(t, ruleDepends.Contains(first), "direct dependency")
|
|
assert.True(t, ruleDepends.Contains(firstNested), "child of dependency")
|
|
assert.True(t, ruleDepends.Contains(sg), "transitive child of dependency")
|
|
assert.True(t, ruleDepends.Contains(second), "parent")
|
|
assert.True(t, ruleDepends.Contains(aws), "provider")
|
|
assert.False(t, ruleDepends.Contains(xyz), "unrelated")
|
|
}
|
|
|
|
func TestDependenciesOfRemoteComponentsNoCycle(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
aws := NewProviderResource("aws", "default", "0")
|
|
parent := NewResource("parent", aws)
|
|
r := NewResource("r", aws, parent.URN)
|
|
child := NewResource("child", aws, r.URN)
|
|
child.Parent = parent.URN
|
|
|
|
dg := NewDependencyGraph([]*resource.State{
|
|
aws,
|
|
parent,
|
|
r,
|
|
child,
|
|
})
|
|
|
|
childDependencies := dg.DependenciesOf(child)
|
|
assert.True(t, childDependencies.Contains(aws))
|
|
assert.True(t, childDependencies.Contains(parent))
|
|
assert.True(t, childDependencies.Contains(r))
|
|
|
|
rDependencies := dg.DependenciesOf(r)
|
|
assert.True(t, rDependencies.Contains(aws))
|
|
assert.True(t, rDependencies.Contains(parent))
|
|
assert.False(t, rDependencies.Contains(child))
|
|
}
|
|
|
|
func TestTransitiveDependenciesOf(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
aws := NewProviderResource("aws", "default", "0")
|
|
parent := NewResource("parent", aws)
|
|
greatUncle := NewResource("greatUncle", aws)
|
|
uncle := NewResource("r", aws)
|
|
uncle.Parent = greatUncle.URN
|
|
child := NewResource("child", aws, uncle.URN)
|
|
child.Parent = parent.URN
|
|
baby := NewResource("baby", aws)
|
|
baby.Parent = child.URN
|
|
|
|
dg := NewDependencyGraph([]*resource.State{
|
|
aws,
|
|
parent,
|
|
greatUncle,
|
|
uncle,
|
|
child,
|
|
baby,
|
|
})
|
|
// <(relation)- as an alias for depends on via relation
|
|
// baby <(Parent)- child <(Dependency)- uncle <(Parent)- greatUncle <(Provider)- aws
|
|
set := dg.TransitiveDependenciesOf(baby)
|
|
assert.True(t, set.Contains(aws), "everything should depend on the provider")
|
|
assert.True(t, set.Contains(greatUncle), "child depends on greatUncle")
|
|
}
|
|
|
|
func TestOnlyDependsOn(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
aws0 := NewProviderResource("aws", "default", "0")
|
|
aws1 := NewProviderResource("aws", "default", "1")
|
|
aws2 := NewProviderResource("aws", "default", "2")
|
|
|
|
b0 := NewResource("b", aws0)
|
|
b1 := NewResource("b", aws1)
|
|
|
|
c0 := NewResource("c0", aws2, b0.URN)
|
|
|
|
dg := NewDependencyGraph([]*resource.State{
|
|
aws0,
|
|
aws1,
|
|
aws2,
|
|
b0,
|
|
b1,
|
|
c0,
|
|
})
|
|
|
|
assert.Equal(t, []*resource.State{b1}, dg.OnlyDependsOn(aws1))
|
|
assert.Equal(t, []*resource.State{c0}, dg.OnlyDependsOn(aws2))
|
|
assert.Equal(t, []*resource.State(nil), dg.OnlyDependsOn(b0))
|
|
}
|
|
|
|
func TestOnlyDependsOnMultipleProviders(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
aws0 := NewProviderResource("aws", "default", "0")
|
|
aws1 := NewProviderResource("aws", "default", "1")
|
|
|
|
b0 := NewResource("b", aws0)
|
|
|
|
c0 := NewProviderResource("aws", "non-default", "0", b0.URN)
|
|
c1 := NewProviderResource("aws", "non-default", "1")
|
|
|
|
d0 := NewResource("d", c0)
|
|
d1 := NewResource("d", c1)
|
|
|
|
dg := NewDependencyGraph([]*resource.State{
|
|
aws0,
|
|
aws1,
|
|
b0,
|
|
c0,
|
|
c1,
|
|
d0,
|
|
d1,
|
|
})
|
|
|
|
assert.Equal(t, []*resource.State{b0, c0, d0}, dg.OnlyDependsOn(aws0))
|
|
assert.Equal(t, []*resource.State(nil), dg.OnlyDependsOn(aws1))
|
|
assert.Equal(t, []*resource.State{c0, d0}, dg.OnlyDependsOn(b0))
|
|
assert.Equal(t, []*resource.State{d1}, dg.OnlyDependsOn(c1))
|
|
}
|