context test demonstrating replace_triggered_by

This commit is contained in:
James Bardin 2022-04-12 16:03:45 -04:00
parent 7598665c90
commit 6670b71a2e
2 changed files with 76 additions and 0 deletions

View File

@ -2964,6 +2964,73 @@ output "a" {
}
}
func TestContext2Plan_triggeredBy(t *testing.T) {
m := testModuleInline(t, map[string]string{
"main.tf": `
resource "test_object" "a" {
count = 1
test_string = "new"
}
resource "test_object" "b" {
count = 1
test_string = test_object.a[count.index].test_string
lifecycle {
# the change to test_string in the other resource should trigger replacement
replace_triggered_by = [ test_object.a[count.index].test_string ]
}
}
`,
})
p := simpleMockProvider()
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
})
state := states.BuildState(func(s *states.SyncState) {
s.SetResourceInstanceCurrent(
mustResourceInstanceAddr("test_object.a[0]"),
&states.ResourceInstanceObjectSrc{
AttrsJSON: []byte(`{"test_string":"old"}`),
Status: states.ObjectReady,
},
mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
)
s.SetResourceInstanceCurrent(
mustResourceInstanceAddr("test_object.b[0]"),
&states.ResourceInstanceObjectSrc{
AttrsJSON: []byte(`{}`),
Status: states.ObjectReady,
},
mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
)
})
plan, diags := ctx.Plan(m, state, &PlanOpts{
Mode: plans.NormalMode,
})
if diags.HasErrors() {
t.Fatalf("unexpected errors\n%s", diags.Err().Error())
}
for _, c := range plan.Changes.Resources {
switch c.Addr.String() {
case "test_object.a[0]":
if c.Action != plans.Update {
t.Fatalf("unexpected %s change for %s\n", c.Action, c.Addr)
}
case "test_object.b[0]":
if c.Action != plans.DeleteThenCreate {
t.Fatalf("unexpected %s change for %s\n", c.Action, c.Addr)
}
default:
t.Fatal("unexpected change", c.Addr, c.Action)
}
}
}
func TestContext2Plan_dataSchemaChange(t *testing.T) {
// We can't decode the prior state when a data source upgrades the schema
// in an incompatible way. Since prior state for data sources is purely

View File

@ -349,6 +349,15 @@ func (ctx *BuiltinEvalContext) EvaluateReplaceTriggeredBy(expr hcl.Expression, r
// single change.
change := changes[0]
// Make sure the change is actionable. A create or delete action will have
// a change in value, but are not valid for our purposes here.
switch change.ChangeSrc.Action {
case plans.Update, plans.DeleteThenCreate, plans.CreateThenDelete:
// OK
default:
return nil, false, diags
}
// Since we have a traversal after the resource reference, we will need to
// decode the changes, which means we need a schema.
providerAddr := change.ProviderAddr