mirror of https://github.com/pulumi/pulumi.git
693 lines
18 KiB
Go
693 lines
18 KiB
Go
// Copyright 2016-2023, Pulumi Corporation.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package edit
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/pulumi/pulumi/pkg/v3/secrets/b64"
|
|
|
|
"github.com/pulumi/pulumi/pkg/v3/resource/deploy"
|
|
"github.com/pulumi/pulumi/pkg/v3/resource/deploy/providers"
|
|
"github.com/pulumi/pulumi/pkg/v3/version"
|
|
"github.com/pulumi/pulumi/sdk/v3/go/common/apitype"
|
|
"github.com/pulumi/pulumi/sdk/v3/go/common/resource"
|
|
"github.com/pulumi/pulumi/sdk/v3/go/common/tokens"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
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("a:b:c")
|
|
return &resource.State{
|
|
Type: t,
|
|
URN: resource.NewURN("test", "test", "", t, name),
|
|
Inputs: resource.PropertyMap{},
|
|
Outputs: resource.PropertyMap{},
|
|
Dependencies: deps,
|
|
Provider: prov,
|
|
}
|
|
}
|
|
|
|
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 NewSnapshot(resources []*resource.State) *deploy.Snapshot {
|
|
return deploy.NewSnapshot(deploy.Manifest{
|
|
Time: time.Now(),
|
|
Version: version.Version,
|
|
Plugins: nil,
|
|
}, b64.NewBase64SecretsManager(), resources, nil, deploy.SnapshotMetadata{})
|
|
}
|
|
|
|
func TestDeletion(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
pA := NewProviderResource("a", "p1", "0")
|
|
a := NewResource("a", pA)
|
|
b := NewResource("b", pA)
|
|
c := NewResource("c", pA)
|
|
snap := NewSnapshot([]*resource.State{
|
|
pA,
|
|
a,
|
|
b,
|
|
c,
|
|
})
|
|
|
|
err := DeleteResource(snap, b, nil, false)
|
|
assert.NoError(t, err)
|
|
assert.Len(t, snap.Resources, 3)
|
|
assert.Equal(t, []*resource.State{pA, a, c}, snap.Resources)
|
|
}
|
|
|
|
func TestDeletingDuplicateURNs(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
pA := NewProviderResource("a", "p1", "0")
|
|
a := NewResource("a", pA)
|
|
|
|
// Create duplicate resources.
|
|
b1 := NewResource("b", pA)
|
|
b2 := NewResource("b", pA)
|
|
b3 := NewResource("b", pA)
|
|
|
|
// ensure b1, b2, and b3 must have the same URN.
|
|
bURN := b1.URN
|
|
assert.Equal(t, bURN, b1.URN)
|
|
assert.Equal(t, bURN, b2.URN)
|
|
assert.Equal(t, bURN, b3.URN)
|
|
|
|
// c exists to check behavior on b's dependents.
|
|
c := NewResource("c", pA, bURN)
|
|
|
|
// This test ensures that when targeting dependent resources, deleting a
|
|
// resource with a redundant URN will not delete dependent resources in
|
|
// state as it's ambiguous since another URN can satisfy the dependency.
|
|
t.Run("do-target-dependents", func(t *testing.T) {
|
|
t.Parallel()
|
|
snap := NewSnapshot([]*resource.State{
|
|
pA, a, b1, b2, b3, c,
|
|
})
|
|
|
|
err := DeleteResource(snap, b1, nil, true /* targetDependents */)
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, []*resource.State{
|
|
pA, a, b2, b3, c,
|
|
}, snap.Resources)
|
|
|
|
// Ensure that a pointer to b1 is not in the list.
|
|
for _, s := range snap.Resources {
|
|
assert.False(t, s == b1)
|
|
}
|
|
})
|
|
|
|
// This test ensures that when targeting a resource with a redundant URN,
|
|
// dependency checks should not block the resource from being deleted from state.
|
|
t.Run("do-not-target-dependents", func(t *testing.T) {
|
|
t.Parallel()
|
|
snap := NewSnapshot([]*resource.State{
|
|
pA, a, b1, b2, b3, c,
|
|
})
|
|
|
|
err := DeleteResource(snap, b1, nil, false /* targetDependents */)
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, []*resource.State{
|
|
pA, a, b2, b3, c,
|
|
}, snap.Resources)
|
|
|
|
// Ensure that a pointer to b1 is not in the list.
|
|
for _, s := range snap.Resources {
|
|
assert.False(t, s == b1)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestDeletingDuplicateProviderURN(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
// Create duplicate provider resources
|
|
pA0 := NewProviderResource("a", "p1", "0")
|
|
pA1 := NewProviderResource("a", "p1", "1")
|
|
|
|
// Create a resource that depends on the duplicate Provider.
|
|
b0 := NewResource("b", pA0)
|
|
b1 := NewResource("b", pA1)
|
|
assert.Equal(t, b0.URN, b1.URN)
|
|
|
|
c := NewResource("c", pA1, b0.URN)
|
|
|
|
t.Run("do-target-dependents", func(t *testing.T) {
|
|
t.Parallel()
|
|
snap := NewSnapshot([]*resource.State{
|
|
pA0, pA1, b0, b1, c,
|
|
})
|
|
|
|
err := DeleteResource(snap, pA0, nil, true /* targetDependents */)
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, []*resource.State{
|
|
pA1, b1, c,
|
|
}, snap.Resources)
|
|
})
|
|
|
|
t.Run("do-not-target-dependents", func(t *testing.T) {
|
|
t.Parallel()
|
|
snap := NewSnapshot([]*resource.State{
|
|
pA0, pA1, b0, b1, c,
|
|
})
|
|
|
|
err := DeleteResource(snap, pA0, nil, false /* targetDependents */)
|
|
require.ErrorContains(t, err,
|
|
"Can't delete resource \"urn:pulumi:test::test::pulumi:providers:a::p1\" due to dependent resources")
|
|
})
|
|
|
|
t.Run("do-target-dependents-one-intermediate", func(t *testing.T) {
|
|
t.Parallel()
|
|
snap := NewSnapshot([]*resource.State{
|
|
pA0, pA1, b0, c,
|
|
})
|
|
|
|
err := DeleteResource(snap, pA0, nil, true /* targetDependents */)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, []*resource.State{
|
|
pA1,
|
|
}, snap.Resources)
|
|
})
|
|
|
|
t.Run("do-target-dependents-one-intermediate", func(t *testing.T) {
|
|
t.Parallel()
|
|
snap := NewSnapshot([]*resource.State{
|
|
pA0, pA1, b0, c,
|
|
})
|
|
|
|
err := DeleteResource(snap, pA0, nil, false /* targetDependents */)
|
|
require.ErrorContains(t, err,
|
|
"Can't delete resource \"urn:pulumi:test::test::pulumi:providers:a::p1\" due to dependent resources")
|
|
})
|
|
}
|
|
|
|
func TestDeletingDuplicateProviderURNWithDependents(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
// Create duplicate provider resources
|
|
pA0 := NewProviderResource("a", "p1", "0")
|
|
pA1 := NewProviderResource("a", "p1", "1")
|
|
|
|
// Create a resource that depends on the duplicate Provider.
|
|
b0 := NewResource("b", pA0)
|
|
|
|
c0 := NewProviderResource("c", "p1", "0", b0.URN)
|
|
c1 := NewProviderResource("c", "p1", "1")
|
|
|
|
d0 := NewResource("d", c0)
|
|
d1 := NewResource("d", c1)
|
|
|
|
t.Run("do-target-dependents", func(t *testing.T) {
|
|
t.Parallel()
|
|
snap := NewSnapshot([]*resource.State{
|
|
pA0, pA1, b0, c0, c1, d0, d1,
|
|
})
|
|
|
|
err := DeleteResource(snap, pA0, nil, true /* targetDependents */)
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, []*resource.State{
|
|
pA1, c1, d1,
|
|
}, snap.Resources)
|
|
})
|
|
|
|
t.Run("do-not-target-dependents", func(t *testing.T) {
|
|
t.Parallel()
|
|
snap := NewSnapshot([]*resource.State{
|
|
pA0, pA1, b0, c0, c1, d0, d1,
|
|
})
|
|
|
|
err := DeleteResource(snap, pA0, nil, false /* targetDependents */)
|
|
require.ErrorContains(t, err,
|
|
"Can't delete resource \"urn:pulumi:test::test::pulumi:providers:a::p1\" due to dependent resources")
|
|
})
|
|
}
|
|
|
|
func TestDeletingDependencies(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
pA := NewProviderResource("a", "p1", "0")
|
|
a := NewResource("a", pA)
|
|
b := NewResource("b", pA)
|
|
c := NewResource("c", pA, a.URN)
|
|
d := NewResource("d", pA, c.URN)
|
|
snap := NewSnapshot([]*resource.State{
|
|
pA, a, b, c, d,
|
|
})
|
|
|
|
err := DeleteResource(snap, a, nil, true)
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, snap.Resources, []*resource.State{pA, b})
|
|
}
|
|
|
|
func TestFailedDeletionProviderDependency(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
pA := NewProviderResource("a", "p1", "0")
|
|
a := NewResource("a", pA)
|
|
b := NewResource("b", pA)
|
|
c := NewResource("c", pA)
|
|
snap := NewSnapshot([]*resource.State{
|
|
pA,
|
|
a,
|
|
b,
|
|
c,
|
|
})
|
|
|
|
err := DeleteResource(snap, pA, nil, false)
|
|
assert.Error(t, err)
|
|
depErr, ok := err.(ResourceHasDependenciesError)
|
|
if !assert.True(t, ok) {
|
|
t.FailNow()
|
|
}
|
|
|
|
assert.Contains(t, depErr.Dependencies, a)
|
|
assert.Contains(t, depErr.Dependencies, b)
|
|
assert.Contains(t, depErr.Dependencies, c)
|
|
assert.Len(t, snap.Resources, 4)
|
|
assert.Equal(t, []*resource.State{pA, a, b, c}, snap.Resources)
|
|
}
|
|
|
|
func TestFailedDeletionRegularDependency(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
pA := NewProviderResource("a", "p1", "0")
|
|
a := NewResource("a", pA)
|
|
b := NewResource("b", pA, a.URN)
|
|
c := NewResource("c", pA)
|
|
snap := NewSnapshot([]*resource.State{
|
|
pA,
|
|
a,
|
|
b,
|
|
c,
|
|
})
|
|
|
|
err := DeleteResource(snap, a, nil, false)
|
|
assert.Error(t, err)
|
|
depErr, ok := err.(ResourceHasDependenciesError)
|
|
if !assert.True(t, ok) {
|
|
t.FailNow()
|
|
}
|
|
|
|
assert.NotContains(t, depErr.Dependencies, pA)
|
|
assert.NotContains(t, depErr.Dependencies, a)
|
|
assert.Contains(t, depErr.Dependencies, b)
|
|
assert.NotContains(t, depErr.Dependencies, c)
|
|
assert.Len(t, snap.Resources, 4)
|
|
assert.Equal(t, []*resource.State{pA, a, b, c}, snap.Resources)
|
|
}
|
|
|
|
func TestFailedDeletionProtected(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
pA := NewProviderResource("a", "p1", "0")
|
|
a := NewResource("a", pA)
|
|
a.Protect = true
|
|
snap := NewSnapshot([]*resource.State{
|
|
pA,
|
|
a,
|
|
})
|
|
|
|
err := DeleteResource(snap, a, nil, false)
|
|
assert.Error(t, err)
|
|
_, ok := err.(ResourceProtectedError)
|
|
assert.True(t, ok)
|
|
}
|
|
|
|
func TestDeleteProtected(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
name string
|
|
test func(t *testing.T, pA, a, b, c *resource.State, snap *deploy.Snapshot)
|
|
}{
|
|
{
|
|
"root-protected",
|
|
func(t *testing.T, pA, a, b, c *resource.State, snap *deploy.Snapshot) {
|
|
a.Protect = true
|
|
protectedCount := 0
|
|
err := DeleteResource(snap, a, func(s *resource.State) error {
|
|
s.Protect = false
|
|
protectedCount++
|
|
return nil
|
|
}, false)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, protectedCount, 1)
|
|
assert.Equal(t, snap.Resources, []*resource.State{pA, b, c})
|
|
},
|
|
},
|
|
{
|
|
"root-and-branch",
|
|
func(t *testing.T, pA, a, b, c *resource.State, snap *deploy.Snapshot) {
|
|
a.Protect = true
|
|
b.Protect = true
|
|
c.Protect = true
|
|
protectedCount := 0
|
|
err := DeleteResource(snap, b, func(s *resource.State) error {
|
|
s.Protect = false
|
|
protectedCount++
|
|
return nil
|
|
}, true)
|
|
assert.NoError(t, err)
|
|
// 2 because we only plan to delete b and c. a is protected but not
|
|
// scheduled for deletion, so we don't call the onProtect handler.
|
|
assert.Equal(t, protectedCount, 2)
|
|
assert.Equal(t, snap.Resources, []*resource.State{pA, a})
|
|
},
|
|
},
|
|
{
|
|
"branch",
|
|
func(t *testing.T, pA, a, b, c *resource.State, snap *deploy.Snapshot) {
|
|
b.Protect = true
|
|
c.Protect = true
|
|
protectedCount := 0
|
|
err := DeleteResource(snap, c, func(s *resource.State) error {
|
|
s.Protect = false
|
|
protectedCount++
|
|
return nil
|
|
}, false)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, protectedCount, 1)
|
|
assert.Equal(t, snap.Resources, []*resource.State{pA, a, b})
|
|
},
|
|
},
|
|
{
|
|
"no-permission-root",
|
|
func(t *testing.T, pA, a, b, c *resource.State, snap *deploy.Snapshot) {
|
|
c.Protect = true
|
|
err := DeleteResource(snap, c, nil, false).(ResourceProtectedError)
|
|
assert.Equal(t, ResourceProtectedError{
|
|
Condemned: c,
|
|
}, err)
|
|
},
|
|
},
|
|
{
|
|
"no-permission-branch",
|
|
func(t *testing.T, pA, a, b, c *resource.State, snap *deploy.Snapshot) {
|
|
c.Protect = true
|
|
err := DeleteResource(snap, b, nil, true).(ResourceProtectedError)
|
|
assert.Equal(t, ResourceProtectedError{
|
|
Condemned: c,
|
|
}, err)
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
tt := tt
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
pA := NewProviderResource("a", "p1", "0")
|
|
a := NewResource("a", pA)
|
|
b := NewResource("b", pA)
|
|
c := NewResource("c", pA, b.URN)
|
|
snap := NewSnapshot([]*resource.State{
|
|
pA,
|
|
a,
|
|
b,
|
|
c,
|
|
})
|
|
|
|
tt.test(t, pA, a, b, c, snap)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestFailedDeletionParentDependency(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
pA := NewProviderResource("a", "p1", "0")
|
|
a := NewResource("a", pA)
|
|
b := NewResource("b", pA)
|
|
b.Parent = a.URN
|
|
c := NewResource("c", pA)
|
|
c.Parent = a.URN
|
|
snap := NewSnapshot([]*resource.State{
|
|
pA,
|
|
a,
|
|
b,
|
|
c,
|
|
})
|
|
|
|
err := DeleteResource(snap, a, nil, false)
|
|
assert.Error(t, err)
|
|
depErr, ok := err.(ResourceHasDependenciesError)
|
|
if !assert.True(t, ok) {
|
|
t.FailNow()
|
|
}
|
|
|
|
assert.NotContains(t, depErr.Dependencies, pA)
|
|
assert.NotContains(t, depErr.Dependencies, a)
|
|
assert.Contains(t, depErr.Dependencies, b)
|
|
assert.Contains(t, depErr.Dependencies, c)
|
|
assert.Len(t, snap.Resources, 4)
|
|
assert.Equal(t, []*resource.State{pA, a, b, c}, snap.Resources)
|
|
}
|
|
|
|
func TestUnprotectResource(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
pA := NewProviderResource("a", "p1", "0")
|
|
a := NewResource("a", pA)
|
|
a.Protect = true
|
|
b := NewResource("b", pA)
|
|
c := NewResource("c", pA)
|
|
snap := NewSnapshot([]*resource.State{
|
|
pA,
|
|
a,
|
|
b,
|
|
c,
|
|
})
|
|
|
|
err := UnprotectResource(snap, a)
|
|
assert.NoError(t, err)
|
|
assert.Len(t, snap.Resources, 4)
|
|
assert.Equal(t, []*resource.State{pA, a, b, c}, snap.Resources)
|
|
assert.False(t, a.Protect)
|
|
}
|
|
|
|
func TestLocateResourceNotFound(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
pA := NewProviderResource("a", "p1", "0")
|
|
a := NewResource("a", pA)
|
|
b := NewResource("b", pA)
|
|
c := NewResource("c", pA)
|
|
snap := NewSnapshot([]*resource.State{
|
|
pA,
|
|
a,
|
|
b,
|
|
c,
|
|
})
|
|
|
|
ty := tokens.Type("a:b:c")
|
|
urn := resource.NewURN("test", "test", "", ty, "not-present")
|
|
resList := LocateResource(snap, urn)
|
|
assert.Nil(t, resList)
|
|
}
|
|
|
|
func TestLocateResourceAmbiguous(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
pA := NewProviderResource("a", "p1", "0")
|
|
a := NewResource("a", pA)
|
|
b := NewResource("b", pA)
|
|
aPending := NewResource("a", pA)
|
|
aPending.Delete = true
|
|
snap := NewSnapshot([]*resource.State{
|
|
pA,
|
|
a,
|
|
b,
|
|
aPending,
|
|
})
|
|
|
|
resList := LocateResource(snap, a.URN)
|
|
assert.Len(t, resList, 2)
|
|
assert.Contains(t, resList, a)
|
|
assert.Contains(t, resList, aPending)
|
|
assert.NotContains(t, resList, pA)
|
|
assert.NotContains(t, resList, b)
|
|
}
|
|
|
|
func TestLocateResourceExact(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
pA := NewProviderResource("a", "p1", "0")
|
|
a := NewResource("a", pA)
|
|
b := NewResource("b", pA)
|
|
c := NewResource("c", pA)
|
|
snap := NewSnapshot([]*resource.State{
|
|
pA,
|
|
a,
|
|
b,
|
|
c,
|
|
})
|
|
|
|
resList := LocateResource(snap, a.URN)
|
|
assert.Len(t, resList, 1)
|
|
assert.Contains(t, resList, a)
|
|
}
|
|
|
|
func TestRenameStack(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
locateResource := func(deployment *apitype.DeploymentV3, urn resource.URN) []apitype.ResourceV3 {
|
|
if deployment == nil {
|
|
return nil
|
|
}
|
|
|
|
var resources []apitype.ResourceV3
|
|
for _, res := range deployment.Resources {
|
|
if res.URN == urn {
|
|
resources = append(resources, res)
|
|
}
|
|
}
|
|
|
|
return resources
|
|
}
|
|
|
|
newResource := func(name string, provider *apitype.ResourceV3, deps ...resource.URN) apitype.ResourceV3 {
|
|
prov := ""
|
|
if provider != nil {
|
|
p, err := providers.NewReference(provider.URN, provider.ID)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
prov = p.String()
|
|
}
|
|
|
|
t := tokens.Type("a:b:c")
|
|
return apitype.ResourceV3{
|
|
Type: t,
|
|
URN: resource.NewURN("test", "test", "", t, name),
|
|
Inputs: map[string]interface{}{},
|
|
Outputs: map[string]interface{}{},
|
|
Dependencies: deps,
|
|
Provider: prov,
|
|
}
|
|
}
|
|
|
|
newProviderResource := func(pkg, name, id string, deps ...resource.URN) apitype.ResourceV3 {
|
|
t := providers.MakeProviderType(tokens.Package(pkg))
|
|
return apitype.ResourceV3{
|
|
Type: t,
|
|
URN: resource.NewURN("test", "test", "", t, name),
|
|
ID: resource.ID(id),
|
|
Inputs: map[string]interface{}{},
|
|
Outputs: map[string]interface{}{},
|
|
Dependencies: deps,
|
|
}
|
|
}
|
|
|
|
newDeployment := func(resources []apitype.ResourceV3) *apitype.DeploymentV3 {
|
|
return &apitype.DeploymentV3{
|
|
Manifest: apitype.ManifestV1{
|
|
Time: time.Now(),
|
|
Version: version.Version,
|
|
Plugins: nil,
|
|
},
|
|
Resources: resources,
|
|
}
|
|
}
|
|
|
|
pA := newProviderResource("a", "p1", "0")
|
|
a := newResource("a", &pA)
|
|
b := newResource("b", &pA)
|
|
c := newResource("c", &pA)
|
|
deployment := newDeployment([]apitype.ResourceV3{
|
|
pA,
|
|
a,
|
|
b,
|
|
c,
|
|
})
|
|
|
|
// Baseline. Can locate resource A.
|
|
resList := locateResource(deployment, a.URN)
|
|
assert.Len(t, resList, 1)
|
|
assert.Contains(t, resList, a)
|
|
if t.Failed() {
|
|
t.Fatal("Unable to find expected resource in initial checkpoint.")
|
|
}
|
|
baselineResourceURN := resList[0].URN
|
|
|
|
// The stack name and project are hard-coded in NewResource(...)
|
|
assert.EqualValues(t, "test", baselineResourceURN.Stack())
|
|
assert.EqualValues(t, "test", baselineResourceURN.Project())
|
|
|
|
// Rename just the stack.
|
|
//nolint:paralleltest // uses shared stack
|
|
t.Run("JustTheStack", func(t *testing.T) {
|
|
err := RenameStack(deployment, tokens.MustParseStackName("new-stack"), tokens.PackageName(""))
|
|
if err != nil {
|
|
t.Fatalf("Error renaming stack: %v", err)
|
|
}
|
|
|
|
// Confirm the previous resource by URN isn't found.
|
|
assert.Len(t, locateResource(deployment, baselineResourceURN), 0)
|
|
|
|
// Confirm the resource has been renamed.
|
|
updatedResourceURN := resource.NewURN(
|
|
tokens.QName("new-stack"),
|
|
"test", // project name stayed the same
|
|
"" /*parent type*/, baselineResourceURN.Type(),
|
|
baselineResourceURN.Name())
|
|
assert.Len(t, locateResource(deployment, updatedResourceURN), 1)
|
|
})
|
|
|
|
// Rename the stack and project.
|
|
//nolint:paralleltest // uses shared stack
|
|
t.Run("StackAndProject", func(t *testing.T) {
|
|
err := RenameStack(deployment, tokens.MustParseStackName("new-stack2"), tokens.PackageName("new-project"))
|
|
if err != nil {
|
|
t.Fatalf("Error renaming stack: %v", err)
|
|
}
|
|
|
|
// Lookup the resource by URN, with both stack and project updated.
|
|
updatedResourceURN := resource.NewURN(
|
|
tokens.QName("new-stack2"),
|
|
"new-project",
|
|
"" /*parent type*/, baselineResourceURN.Type(),
|
|
baselineResourceURN.Name())
|
|
assert.Len(t, locateResource(deployment, updatedResourceURN), 1)
|
|
})
|
|
}
|