From f8978632889457546de90c6c45e96a1a654ac4cf Mon Sep 17 00:00:00 2001 From: Martin Atkins Date: Thu, 7 May 2020 10:48:45 -0700 Subject: [PATCH] providers/terraform: test that validation does not configure backend --- .../providers/terraform/data_source_state.go | 16 ++++- .../terraform/data_source_state_test.go | 65 +++++++++++++++++++ 2 files changed, 80 insertions(+), 1 deletion(-) diff --git a/builtin/providers/terraform/data_source_state.go b/builtin/providers/terraform/data_source_state.go index d245954f40..f73a0a2313 100644 --- a/builtin/providers/terraform/data_source_state.go +++ b/builtin/providers/terraform/data_source_state.go @@ -171,7 +171,7 @@ func getBackend(cfg cty.Value) (backend.Backend, cty.Value, tfdiags.Diagnostics) // Create the client to access our remote state log.Printf("[DEBUG] Initializing remote state backend: %s", backendType) - f := backendInit.Backend(backendType) + f := getBackendFactory(backendType) if f == nil { diags = diags.Append(tfdiags.AttributeValue( tfdiags.Error, @@ -216,3 +216,17 @@ func getBackend(cfg cty.Value) (backend.Backend, cty.Value, tfdiags.Diagnostics) return b, newVal, diags } + +// overrideBackendFactories allows test cases to control the set of available +// backends to allow for more self-contained tests. This should never be set +// in non-test code. +var overrideBackendFactories map[string]backend.InitFn + +func getBackendFactory(backendType string) backend.InitFn { + if len(overrideBackendFactories) > 0 { + // Tests may override the set of backend factories. + return overrideBackendFactories[backendType] + } + + return backendInit.Backend(backendType) +} diff --git a/builtin/providers/terraform/data_source_state_test.go b/builtin/providers/terraform/data_source_state_test.go index 7123ef1ed0..fca8c98349 100644 --- a/builtin/providers/terraform/data_source_state_test.go +++ b/builtin/providers/terraform/data_source_state_test.go @@ -1,10 +1,14 @@ package terraform import ( + "fmt" + "log" "testing" "github.com/apparentlymart/go-dump/dump" "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/states/statemgr" "github.com/hashicorp/terraform/tfdiags" "github.com/zclconf/go-cty/cty" ) @@ -283,3 +287,64 @@ func TestState_basic(t *testing.T) { }) } } + +func TestState_validation(t *testing.T) { + // The main test TestState_basic covers both validation and reading of + // state snapshots, so this additional test is here only to verify that + // the validation step in isolation does not attempt to configure + // the backend. + overrideBackendFactories = map[string]backend.InitFn{ + "failsconfigure": func() backend.Backend { + return backendFailsConfigure{} + }, + } + defer func() { + // undo our overrides so we won't affect other tests + overrideBackendFactories = nil + }() + + schema := dataSourceRemoteStateGetSchema().Block + config, err := schema.CoerceValue(cty.ObjectVal(map[string]cty.Value{ + "backend": cty.StringVal("failsconfigure"), + "config": cty.EmptyObjectVal, + })) + if err != nil { + t.Fatalf("unexpected error: %s", err) + } + + diags := dataSourceRemoteStateValidate(config) + if diags.HasErrors() { + t.Fatalf("unexpected errors\n%s", diags.Err().Error()) + } +} + +type backendFailsConfigure struct{} + +func (b backendFailsConfigure) ConfigSchema() *configschema.Block { + log.Printf("[TRACE] backendFailsConfigure.ConfigSchema") + return &configschema.Block{} // intentionally empty configuration schema +} + +func (b backendFailsConfigure) PrepareConfig(given cty.Value) (cty.Value, tfdiags.Diagnostics) { + // No special actions to take here + return given, nil +} + +func (b backendFailsConfigure) Configure(config cty.Value) tfdiags.Diagnostics { + log.Printf("[TRACE] backendFailsConfigure.Configure(%#v)", config) + var diags tfdiags.Diagnostics + diags = diags.Append(fmt.Errorf("Configure should never be called")) + return diags +} + +func (b backendFailsConfigure) StateMgr(workspace string) (statemgr.Full, error) { + return nil, fmt.Errorf("StateMgr not implemented") +} + +func (b backendFailsConfigure) DeleteWorkspace(name string) error { + return fmt.Errorf("DeleteWorkspace not implemented") +} + +func (b backendFailsConfigure) Workspaces() ([]string, error) { + return nil, fmt.Errorf("Workspaces not implemented") +}