package terraform import ( "fmt" "strings" "testing" ) func TestContext2Validate_badCount(t *testing.T) { p := testProvider("aws") m := testModule(t, "validate-bad-count") c := testContext2(t, &ContextOpts{ Module: m, Providers: map[string]ResourceProviderFactory{ "aws": testProviderFuncFixed(p), }, }) w, e := c.Validate() if len(w) > 0 { t.Fatalf("bad: %#v", w) } if len(e) == 0 { t.Fatalf("bad: %#v", e) } } func TestContext2Validate_badVar(t *testing.T) { p := testProvider("aws") m := testModule(t, "validate-bad-var") c := testContext2(t, &ContextOpts{ Module: m, Providers: map[string]ResourceProviderFactory{ "aws": testProviderFuncFixed(p), }, }) w, e := c.Validate() if len(w) > 0 { t.Fatalf("bad: %#v", w) } if len(e) == 0 { t.Fatalf("bad: %#v", e) } } func TestContext2Validate_varMapOverrideOld(t *testing.T) { m := testModule(t, "validate-module-pc-vars") p := testProvider("aws") c := testContext2(t, &ContextOpts{ Module: m, Providers: map[string]ResourceProviderFactory{ "aws": testProviderFuncFixed(p), }, Variables: map[string]interface{}{ "foo.foo": "bar", }, }) w, e := c.Validate() if len(w) > 0 { t.Fatalf("bad: %#v", w) } if len(e) == 0 { t.Fatalf("bad: %s", e) } } func TestContext2Validate_varNoDefaultExplicitType(t *testing.T) { m := testModule(t, "validate-var-no-default-explicit-type") c := testContext2(t, &ContextOpts{ Module: m, }) w, e := c.Validate() if len(w) > 0 { t.Fatalf("bad: %#v", w) } if len(e) == 0 { t.Fatalf("bad: %#v", e) } } func TestContext2Validate_computedVar(t *testing.T) { p := testProvider("aws") m := testModule(t, "validate-computed-var") c := testContext2(t, &ContextOpts{ Module: m, Providers: map[string]ResourceProviderFactory{ "aws": testProviderFuncFixed(p), "test": testProviderFuncFixed(testProvider("test")), }, }) p.ValidateFn = func(c *ResourceConfig) ([]string, []error) { if !c.IsComputed("value") { return nil, []error{fmt.Errorf("value isn't computed")} } return nil, c.CheckSet([]string{"value"}) } p.ConfigureFn = func(c *ResourceConfig) error { return fmt.Errorf("Configure should not be called for provider") } w, e := c.Validate() if len(w) > 0 { t.Fatalf("bad: %#v", w) } if len(e) > 0 { for _, err := range e { t.Errorf("bad: %s", err) } } } // Test that validate allows through computed counts. We do this and allow // them to fail during "plan" since we can't know if the computed values // can be realized during a plan. func TestContext2Validate_countComputed(t *testing.T) { p := testProvider("aws") m := testModule(t, "validate-count-computed") c := testContext2(t, &ContextOpts{ Module: m, Providers: map[string]ResourceProviderFactory{ "aws": testProviderFuncFixed(p), }, }) w, e := c.Validate() if len(w) > 0 { t.Fatalf("bad: %#v", w) } if len(e) > 0 { t.Fatalf("bad: %s", e) } } func TestContext2Validate_countNegative(t *testing.T) { p := testProvider("aws") m := testModule(t, "validate-count-negative") c := testContext2(t, &ContextOpts{ Module: m, Providers: map[string]ResourceProviderFactory{ "aws": testProviderFuncFixed(p), }, }) w, e := c.Validate() if len(w) > 0 { t.Fatalf("bad: %#v", w) } if len(e) == 0 { t.Fatalf("bad: %#v", e) } } func TestContext2Validate_countVariable(t *testing.T) { p := testProvider("aws") m := testModule(t, "apply-count-variable") c := testContext2(t, &ContextOpts{ Module: m, Providers: map[string]ResourceProviderFactory{ "aws": testProviderFuncFixed(p), }, }) w, e := c.Validate() if len(w) > 0 { t.Fatalf("bad: %#v", w) } if len(e) > 0 { t.Fatalf("bad: %s", e) } } func TestContext2Validate_countVariableNoDefault(t *testing.T) { p := testProvider("aws") m := testModule(t, "validate-count-variable") c := testContext2(t, &ContextOpts{ Module: m, Providers: map[string]ResourceProviderFactory{ "aws": testProviderFuncFixed(p), }, }) w, e := c.Validate() if len(w) > 0 { t.Fatalf("bad: %#v", w) } if len(e) != 1 { t.Fatalf("bad: %s", e) } } /* TODO: What should we do here? func TestContext2Validate_cycle(t *testing.T) { p := testProvider("aws") m := testModule(t, "validate-cycle") c := testContext2(t, &ContextOpts{ Module: m, Providers: map[string]ResourceProviderFactory{ "aws": testProviderFuncFixed(p), }, }) w, e := c.Validate() if len(w) > 0 { t.Fatalf("expected no warns, got: %#v", w) } if len(e) != 1 { t.Fatalf("expected 1 err, got: %s", e) } } */ func TestContext2Validate_moduleBadOutput(t *testing.T) { p := testProvider("aws") m := testModule(t, "validate-bad-module-output") c := testContext2(t, &ContextOpts{ Module: m, Providers: map[string]ResourceProviderFactory{ "aws": testProviderFuncFixed(p), }, }) w, e := c.Validate() if len(w) > 0 { t.Fatalf("bad: %#v", w) } if len(e) == 0 { t.Fatalf("bad: %s", e) } } func TestContext2Validate_moduleGood(t *testing.T) { p := testProvider("aws") m := testModule(t, "validate-good-module") c := testContext2(t, &ContextOpts{ Module: m, Providers: map[string]ResourceProviderFactory{ "aws": testProviderFuncFixed(p), }, }) w, e := c.Validate() if len(w) > 0 { t.Fatalf("bad: %#v", w) } if len(e) > 0 { t.Fatalf("bad: %#v", e) } } func TestContext2Validate_moduleBadResource(t *testing.T) { m := testModule(t, "validate-module-bad-rc") p := testProvider("aws") c := testContext2(t, &ContextOpts{ Module: m, Providers: map[string]ResourceProviderFactory{ "aws": testProviderFuncFixed(p), }, }) p.ValidateResourceReturnErrors = []error{fmt.Errorf("bad")} w, e := c.Validate() if len(w) > 0 { t.Fatalf("bad: %#v", w) } if len(e) == 0 { t.Fatalf("bad: %#v", e) } } func TestContext2Validate_moduleDepsShouldNotCycle(t *testing.T) { m := testModule(t, "validate-module-deps-cycle") p := testProvider("aws") ctx := testContext2(t, &ContextOpts{ Module: m, Providers: map[string]ResourceProviderFactory{ "aws": testProviderFuncFixed(p), }, }) w, e := ctx.Validate() if len(w) > 0 { t.Fatalf("expected no warnings, got: %s", w) } if len(e) > 0 { t.Fatalf("expected no errors, got: %s", e) } } func TestContext2Validate_moduleProviderInherit(t *testing.T) { m := testModule(t, "validate-module-pc-inherit") p := testProvider("aws") c := testContext2(t, &ContextOpts{ Module: m, Providers: map[string]ResourceProviderFactory{ "aws": testProviderFuncFixed(p), }, }) p.ValidateFn = func(c *ResourceConfig) ([]string, []error) { return nil, c.CheckSet([]string{"set"}) } w, e := c.Validate() if len(w) > 0 { t.Fatalf("bad: %#v", w) } if len(e) > 0 { t.Fatalf("bad: %s", e) } } func TestContext2Validate_moduleProviderInheritOrphan(t *testing.T) { m := testModule(t, "validate-module-pc-inherit-orphan") p := testProvider("aws") c := testContext2(t, &ContextOpts{ Module: m, Providers: map[string]ResourceProviderFactory{ "aws": testProviderFuncFixed(p), }, State: &State{ Modules: []*ModuleState{ &ModuleState{ Path: []string{"root", "child"}, Resources: map[string]*ResourceState{ "aws_instance.bar": &ResourceState{ Type: "aws_instance", Primary: &InstanceState{ ID: "bar", }, }, }, }, }, }, }) p.ValidateFn = func(c *ResourceConfig) ([]string, []error) { v, ok := c.Get("set") if !ok { return nil, []error{fmt.Errorf("not set")} } if v != "bar" { return nil, []error{fmt.Errorf("bad: %#v", v)} } return nil, nil } w, e := c.Validate() if len(w) > 0 { t.Fatalf("bad: %#v", w) } if len(e) > 0 { t.Fatalf("bad: %s", e) } } func TestContext2Validate_moduleProviderVar(t *testing.T) { m := testModule(t, "validate-module-pc-vars") p := testProvider("aws") c := testContext2(t, &ContextOpts{ Module: m, Providers: map[string]ResourceProviderFactory{ "aws": testProviderFuncFixed(p), }, Variables: map[string]interface{}{ "provider_var": "bar", }, }) p.ValidateFn = func(c *ResourceConfig) ([]string, []error) { return nil, c.CheckSet([]string{"foo"}) } w, e := c.Validate() if len(w) > 0 { t.Fatalf("bad: %#v", w) } if len(e) > 0 { t.Fatalf("bad: %s", e) } } func TestContext2Validate_moduleProviderInheritUnused(t *testing.T) { m := testModule(t, "validate-module-pc-inherit-unused") p := testProvider("aws") c := testContext2(t, &ContextOpts{ Module: m, Providers: map[string]ResourceProviderFactory{ "aws": testProviderFuncFixed(p), }, }) p.ValidateFn = func(c *ResourceConfig) ([]string, []error) { return nil, c.CheckSet([]string{"foo"}) } w, e := c.Validate() if len(w) > 0 { t.Fatalf("bad: %#v", w) } if len(e) > 0 { t.Fatalf("bad: %s", e) } } func TestContext2Validate_orphans(t *testing.T) { p := testProvider("aws") m := testModule(t, "validate-good") state := &State{ Modules: []*ModuleState{ &ModuleState{ Path: rootModulePath, Resources: map[string]*ResourceState{ "aws_instance.web": &ResourceState{ Type: "aws_instance", Primary: &InstanceState{ ID: "bar", }, }, }, }, }, } c := testContext2(t, &ContextOpts{ Module: m, Providers: map[string]ResourceProviderFactory{ "aws": testProviderFuncFixed(p), }, State: state, }) p.ValidateResourceFn = func( t string, c *ResourceConfig) ([]string, []error) { return nil, c.CheckSet([]string{"foo"}) } w, e := c.Validate() if len(w) > 0 { t.Fatalf("bad: %#v", w) } if len(e) > 0 { t.Fatalf("bad: %s", e) } } func TestContext2Validate_providerConfig_bad(t *testing.T) { m := testModule(t, "validate-bad-pc") p := testProvider("aws") c := testContext2(t, &ContextOpts{ Module: m, Providers: map[string]ResourceProviderFactory{ "aws": testProviderFuncFixed(p), }, }) p.ValidateReturnErrors = []error{fmt.Errorf("bad")} w, e := c.Validate() if len(w) > 0 { t.Fatalf("bad: %#v", w) } if len(e) == 0 { t.Fatalf("bad: %s", e) } if !strings.Contains(fmt.Sprintf("%s", e), "bad") { t.Fatalf("bad: %s", e) } } func TestContext2Validate_providerConfig_badEmpty(t *testing.T) { m := testModule(t, "validate-bad-pc-empty") p := testProvider("aws") c := testContext2(t, &ContextOpts{ Module: m, Providers: map[string]ResourceProviderFactory{ "aws": testProviderFuncFixed(p), }, }) p.ValidateReturnErrors = []error{fmt.Errorf("bad")} w, e := c.Validate() if len(w) > 0 { t.Fatalf("bad: %#v", w) } if len(e) == 0 { t.Fatalf("bad: %#v", e) } } func TestContext2Validate_providerConfig_good(t *testing.T) { m := testModule(t, "validate-bad-pc") p := testProvider("aws") c := testContext2(t, &ContextOpts{ Module: m, Providers: map[string]ResourceProviderFactory{ "aws": testProviderFuncFixed(p), }, }) w, e := c.Validate() if len(w) > 0 { t.Fatalf("bad: %#v", w) } if len(e) > 0 { t.Fatalf("bad: %#v", e) } } func TestContext2Validate_provisionerConfig_bad(t *testing.T) { m := testModule(t, "validate-bad-prov-conf") p := testProvider("aws") pr := testProvisioner() c := testContext2(t, &ContextOpts{ Module: m, Providers: map[string]ResourceProviderFactory{ "aws": testProviderFuncFixed(p), }, Provisioners: map[string]ResourceProvisionerFactory{ "shell": testProvisionerFuncFixed(pr), }, }) pr.ValidateReturnErrors = []error{fmt.Errorf("bad")} w, e := c.Validate() if len(w) > 0 { t.Fatalf("bad: %#v", w) } if len(e) == 0 { t.Fatalf("bad: %#v", e) } } func TestContext2Validate_provisionerConfig_good(t *testing.T) { m := testModule(t, "validate-bad-prov-conf") p := testProvider("aws") pr := testProvisioner() pr.ValidateFn = func(c *ResourceConfig) ([]string, []error) { if c == nil { t.Fatalf("missing resource config for provisioner") } return nil, c.CheckSet([]string{"command"}) } c := testContext2(t, &ContextOpts{ Module: m, Providers: map[string]ResourceProviderFactory{ "aws": testProviderFuncFixed(p), }, Provisioners: map[string]ResourceProvisionerFactory{ "shell": testProvisionerFuncFixed(pr), }, }) w, e := c.Validate() if len(w) > 0 { t.Fatalf("bad: %#v", w) } if len(e) > 0 { t.Fatalf("bad: %#v", e) } } func TestContext2Validate_requiredVar(t *testing.T) { m := testModule(t, "validate-required-var") p := testProvider("aws") c := testContext2(t, &ContextOpts{ Module: m, Providers: map[string]ResourceProviderFactory{ "aws": testProviderFuncFixed(p), }, }) w, e := c.Validate() if len(w) > 0 { t.Fatalf("bad: %#v", w) } if len(e) == 0 { t.Fatalf("bad: %s", e) } } func TestContext2Validate_resourceConfig_bad(t *testing.T) { m := testModule(t, "validate-bad-rc") p := testProvider("aws") c := testContext2(t, &ContextOpts{ Module: m, Providers: map[string]ResourceProviderFactory{ "aws": testProviderFuncFixed(p), }, }) p.ValidateResourceReturnErrors = []error{fmt.Errorf("bad")} w, e := c.Validate() if len(w) > 0 { t.Fatalf("bad: %#v", w) } if len(e) == 0 { t.Fatalf("bad: %s", e) } } func TestContext2Validate_resourceConfig_good(t *testing.T) { m := testModule(t, "validate-bad-rc") p := testProvider("aws") c := testContext2(t, &ContextOpts{ Module: m, Providers: map[string]ResourceProviderFactory{ "aws": testProviderFuncFixed(p), }, }) w, e := c.Validate() if len(w) > 0 { t.Fatalf("bad: %#v", w) } if len(e) > 0 { t.Fatalf("bad: %#v", e) } } func TestContext2Validate_resourceNameSymbol(t *testing.T) { p := testProvider("aws") m := testModule(t, "validate-resource-name-symbol") c := testContext2(t, &ContextOpts{ Module: m, Providers: map[string]ResourceProviderFactory{ "aws": testProviderFuncFixed(p), }, }) w, e := c.Validate() if len(w) > 0 { t.Fatalf("bad: %#v", w) } if len(e) == 0 { t.Fatalf("bad: %s", e) } } func TestContext2Validate_selfRef(t *testing.T) { p := testProvider("aws") m := testModule(t, "validate-self-ref") c := testContext2(t, &ContextOpts{ Module: m, Providers: map[string]ResourceProviderFactory{ "aws": testProviderFuncFixed(p), }, }) w, e := c.Validate() if len(w) > 0 { t.Fatalf("bad: %#v", w) } if len(e) == 0 { t.Fatalf("bad: %s", e) } } func TestContext2Validate_selfRefMulti(t *testing.T) { p := testProvider("aws") m := testModule(t, "validate-self-ref-multi") c := testContext2(t, &ContextOpts{ Module: m, Providers: map[string]ResourceProviderFactory{ "aws": testProviderFuncFixed(p), }, }) w, e := c.Validate() if len(w) > 0 { t.Fatalf("bad: %#v", w) } if len(e) == 0 { t.Fatalf("bad: %#v", e) } } func TestContext2Validate_selfRefMultiAll(t *testing.T) { p := testProvider("aws") m := testModule(t, "validate-self-ref-multi-all") c := testContext2(t, &ContextOpts{ Module: m, Providers: map[string]ResourceProviderFactory{ "aws": testProviderFuncFixed(p), }, }) w, e := c.Validate() if len(w) > 0 { t.Fatalf("bad: %#v", w) } if len(e) == 0 { t.Fatalf("bad: %#v", e) } } func TestContext2Validate_tainted(t *testing.T) { p := testProvider("aws") m := testModule(t, "validate-good") state := &State{ Modules: []*ModuleState{ &ModuleState{ Path: rootModulePath, Resources: map[string]*ResourceState{ "aws_instance.foo": &ResourceState{ Type: "aws_instance", Primary: &InstanceState{ ID: "bar", Tainted: true, }, }, }, }, }, } c := testContext2(t, &ContextOpts{ Module: m, Providers: map[string]ResourceProviderFactory{ "aws": testProviderFuncFixed(p), }, State: state, }) p.ValidateResourceFn = func( t string, c *ResourceConfig) ([]string, []error) { return nil, c.CheckSet([]string{"foo"}) } w, e := c.Validate() if len(w) > 0 { t.Fatalf("bad: %#v", w) } if len(e) > 0 { t.Fatalf("bad: %#v", e) } } func TestContext2Validate_targetedDestroy(t *testing.T) { m := testModule(t, "validate-targeted") p := testProvider("aws") pr := testProvisioner() p.ApplyFn = testApplyFn p.DiffFn = testDiffFn ctx := testContext2(t, &ContextOpts{ Module: m, Providers: map[string]ResourceProviderFactory{ "aws": testProviderFuncFixed(p), }, Provisioners: map[string]ResourceProvisionerFactory{ "shell": testProvisionerFuncFixed(pr), }, State: &State{ Modules: []*ModuleState{ &ModuleState{ Path: rootModulePath, Resources: map[string]*ResourceState{ "aws_instance.foo": resourceState("aws_instance", "i-bcd345"), "aws_instance.bar": resourceState("aws_instance", "i-abc123"), }, }, }, }, Targets: []string{"aws_instance.foo"}, Destroy: true, }) w, e := ctx.Validate() if len(w) > 0 { warnStr := "" for _, v := range w { warnStr = warnStr + " " + v } t.Fatalf("bad: %s", warnStr) } if len(e) > 0 { t.Fatalf("bad: %s", e) } } func TestContext2Validate_varRefFilled(t *testing.T) { m := testModule(t, "validate-variable-ref") p := testProvider("aws") c := testContext2(t, &ContextOpts{ Module: m, Providers: map[string]ResourceProviderFactory{ "aws": testProviderFuncFixed(p), }, Variables: map[string]interface{}{ "foo": "bar", }, }) var value interface{} p.ValidateResourceFn = func(t string, c *ResourceConfig) ([]string, []error) { value, _ = c.Get("foo") return nil, nil } c.Validate() if value != "bar" { t.Fatalf("bad: %#v", value) } } // Module variables weren't being interpolated during Validate phase. // related to https://github.com/hashicorp/terraform/issues/5322 func TestContext2Validate_interpolateVar(t *testing.T) { input := new(MockUIInput) m := testModule(t, "input-interpolate-var") p := testProvider("null") p.ApplyFn = testApplyFn p.DiffFn = testDiffFn ctx := testContext2(t, &ContextOpts{ Module: m, Providers: map[string]ResourceProviderFactory{ "template": testProviderFuncFixed(p), }, UIInput: input, }) w, e := ctx.Validate() if w != nil { t.Log("warnings:", w) } if e != nil { t.Fatal("err:", e) } } // When module vars reference something that is actually computed, this // shouldn't cause validation to fail. func TestContext2Validate_interpolateComputedModuleVarDef(t *testing.T) { input := new(MockUIInput) m := testModule(t, "validate-computed-module-var-ref") p := testProvider("aws") p.ApplyFn = testApplyFn p.DiffFn = testDiffFn ctx := testContext2(t, &ContextOpts{ Module: m, Providers: map[string]ResourceProviderFactory{ "aws": testProviderFuncFixed(p), }, UIInput: input, }) w, e := ctx.Validate() if w != nil { t.Log("warnings:", w) } if e != nil { t.Fatal("err:", e) } } // Computed values are lost when a map is output from a module func TestContext2Validate_interpolateMap(t *testing.T) { input := new(MockUIInput) m := testModule(t, "issue-9549") p := testProvider("null") p.ApplyFn = testApplyFn p.DiffFn = testDiffFn ctx := testContext2(t, &ContextOpts{ Module: m, Providers: map[string]ResourceProviderFactory{ "template": testProviderFuncFixed(p), }, UIInput: input, }) w, e := ctx.Validate() if w != nil { t.Log("warnings:", w) } if e != nil { t.Fatal("err:", e) } } // Manually validate using the new PlanGraphBuilder func TestContext2Validate_PlanGraphBuilder(t *testing.T) { m := testModule(t, "apply-vars") p := testProvider("aws") p.ApplyFn = testApplyFn p.DiffFn = testDiffFn c := testContext2(t, &ContextOpts{ Module: m, Providers: map[string]ResourceProviderFactory{ "aws": testProviderFuncFixed(p), }, Variables: map[string]interface{}{ "foo": "us-west-2", "test_list": []interface{}{"Hello", "World"}, "test_map": map[string]interface{}{ "Hello": "World", "Foo": "Bar", "Baz": "Foo", }, "amis": []map[string]interface{}{ map[string]interface{}{ "us-east-1": "override", }, }, }, }) graph, err := (&PlanGraphBuilder{ Module: c.module, State: NewState(), Providers: c.components.ResourceProviders(), Targets: c.targets, }).Build(RootModulePath) defer c.acquireRun("validate-test")() walker, err := c.walk(graph, graph, walkValidate) if err != nil { t.Fatal(err) } if len(walker.ValidationErrors) > 0 { t.Fatal(walker.ValidationErrors) } }