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  }