From 8ceff6f4dd59ba5b95a5ea26711e873f7d1313ec Mon Sep 17 00:00:00 2001 From: James Bardin Date: Wed, 19 Feb 2025 12:58:48 -0500 Subject: [PATCH] additional write-only tests Add context tests for write-only on destroy, and with a provider error. --- internal/terraform/context_apply2_test.go | 136 ++++++++++++++++++++++ 1 file changed, 136 insertions(+) diff --git a/internal/terraform/context_apply2_test.go b/internal/terraform/context_apply2_test.go index 7b15ae07d2..99157adb36 100644 --- a/internal/terraform/context_apply2_test.go +++ b/internal/terraform/context_apply2_test.go @@ -3766,3 +3766,139 @@ resource "test_object" "c" { } t.Fatal("failed to find destroy destroy dependency between test_object.a(destroy) and test_object.c(destroy)") } + +func TestContext2Apply_writeOnlyDestroy(t *testing.T) { + m := testModuleInline(t, map[string]string{ + "main.tf": ` +resource "test_object" "x" { + test_string = "ok" + test_wo = "secret" +}`, + }) + + p := &testing_provider.MockProvider{} + p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{ + Provider: providers.Schema{Block: simpleTestSchema()}, + ResourceTypes: map[string]providers.Schema{ + "test_object": providers.Schema{ + Block: &configschema.Block{ + Attributes: map[string]*configschema.Attribute{ + "test_string": { + Type: cty.String, + Optional: true, + }, + "test_wo": { + Type: cty.Number, + Optional: true, + WriteOnly: true, + }, + }, + }, + }, + }, + } + + state := states.NewState() + root := state.EnsureModule(addrs.RootModuleInstance) + root.SetResourceInstanceCurrent( + mustResourceInstanceAddr("test_object.x").Resource, + &states.ResourceInstanceObjectSrc{ + Status: states.ObjectReady, + AttrsJSON: []byte(`{"test_string":"ok", "test_wo": null}`), + }, + mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), + ) + + ctx := testContext2(t, &ContextOpts{ + Providers: map[addrs.Provider]providers.Factory{ + addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), + }, + }) + + plan, diags := ctx.Plan(m, state, &PlanOpts{ + Mode: plans.DestroyMode, + // we don't want to refresh, because that actually runs a normal plan + SkipRefresh: true, + }) + if diags.HasErrors() { + t.Fatalf("plan: %s", diags.Err()) + } + + _, diags = ctx.Apply(plan, m, nil) + if diags.HasErrors() { + t.Fatalf("apply: %s", diags.Err()) + } +} + +func TestContext2Apply_writeOnlyApplyError(t *testing.T) { + m := testModuleInline(t, map[string]string{ + "main.tf": ` +resource "test_object" "x" { + test_string = "ok" + test_wo = "secret" +}`, + }) + + p := &testing_provider.MockProvider{} + p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{ + Provider: providers.Schema{Block: simpleTestSchema()}, + ResourceTypes: map[string]providers.Schema{ + "test_object": providers.Schema{ + Block: &configschema.Block{ + Attributes: map[string]*configschema.Attribute{ + "test_string": { + Type: cty.String, + Optional: true, + }, + "test_wo": { + Type: cty.Number, + Optional: true, + WriteOnly: true, + }, + }, + }, + }, + }, + } + + p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) { + resp.Diagnostics = resp.Diagnostics.Append(errors.New("provider oops")) + return resp + } + + state := states.NewState() + root := state.EnsureModule(addrs.RootModuleInstance) + root.SetResourceInstanceCurrent( + mustResourceInstanceAddr("test_object.x").Resource, + &states.ResourceInstanceObjectSrc{ + Status: states.ObjectReady, + AttrsJSON: []byte(`{"test_string":"ok", "test_wo": null}`), + }, + mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), + ) + + ctx := testContext2(t, &ContextOpts{ + Providers: map[addrs.Provider]providers.Factory{ + addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), + }, + }) + + plan, diags := ctx.Plan(m, state, &PlanOpts{ + Mode: plans.DestroyMode, + // we don't want to refresh, because that actually runs a normal plan + SkipRefresh: true, + }) + if diags.HasErrors() { + t.Fatalf("plan: %s", diags.Err()) + } + + _, diags = ctx.Apply(plan, m, nil) + if !diags.HasErrors() { + t.Fatal("expected error") + } + + msg := diags.ErrWithWarnings().Error() + if len(diags) != 1 && !strings.Contains(msg, "provider oops") { + t.Fatalf("expected only 'provider oops', but got: %s", msg) + } +}