// Copyright (c) The OpenTofu Authors // SPDX-License-Identifier: MPL-2.0 // Copyright (c) 2023 HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package views import ( "context" "testing" "github.com/opentofu/opentofu/internal/addrs" "github.com/opentofu/opentofu/internal/command/arguments" "github.com/opentofu/opentofu/internal/configs/configschema" "github.com/opentofu/opentofu/internal/plans" "github.com/opentofu/opentofu/internal/providers" "github.com/opentofu/opentofu/internal/terminal" "github.com/opentofu/opentofu/internal/tofu" "github.com/zclconf/go-cty/cty" ) // Ensure that the correct view type and in-automation settings propagate to the // Operation view. func TestPlanHuman_operation(t *testing.T) { streams, done := terminal.StreamsForTesting(t) defer done(t) v := NewPlan(arguments.ViewHuman, NewView(streams).SetRunningInAutomation(true)).Operation() if hv, ok := v.(*OperationHuman); !ok { t.Fatalf("unexpected return type %t", v) } else if hv.inAutomation != true { t.Fatalf("unexpected inAutomation value on Operation view") } } // Verify that Hooks includes a UI hook func TestPlanHuman_hooks(t *testing.T) { streams, done := terminal.StreamsForTesting(t) defer done(t) v := NewPlan(arguments.ViewHuman, NewView(streams).SetRunningInAutomation((true))) hooks := v.Hooks() var uiHook *UiHook for _, hook := range hooks { if ch, ok := hook.(*UiHook); ok { uiHook = ch } } if uiHook == nil { t.Fatalf("expected Hooks to include a UiHook: %#v", hooks) } } // Helper functions to build a trivial test plan, to exercise the plan // renderer. func testPlan(t *testing.T) *plans.Plan { t.Helper() plannedVal := cty.ObjectVal(map[string]cty.Value{ "id": cty.UnknownVal(cty.String), "foo": cty.StringVal("bar"), }) priorValRaw, err := plans.NewDynamicValue(cty.NullVal(plannedVal.Type()), plannedVal.Type()) if err != nil { t.Fatal(err) } plannedValRaw, err := plans.NewDynamicValue(plannedVal, plannedVal.Type()) if err != nil { t.Fatal(err) } changes := plans.NewChanges() addr := addrs.Resource{ Mode: addrs.ManagedResourceMode, Type: "test_resource", Name: "foo", }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance) changes.SyncWrapper().AppendResourceInstanceChange(&plans.ResourceInstanceChangeSrc{ Addr: addr, PrevRunAddr: addr, ProviderAddr: addrs.AbsProviderConfig{ Provider: addrs.NewDefaultProvider("test"), Module: addrs.RootModule, }, ChangeSrc: plans.ChangeSrc{ Action: plans.Create, Before: priorValRaw, After: plannedValRaw, }, }) return &plans.Plan{ Changes: changes, } } func testPlanWithDatasource(t *testing.T) *plans.Plan { plan := testPlan(t) addr := addrs.Resource{ Mode: addrs.DataResourceMode, Type: "test_data_source", Name: "bar", }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance) dataVal := cty.ObjectVal(map[string]cty.Value{ "id": cty.StringVal("C6743020-40BD-4591-81E6-CD08494341D3"), "bar": cty.StringVal("foo"), }) priorValRaw, err := plans.NewDynamicValue(cty.NullVal(dataVal.Type()), dataVal.Type()) if err != nil { t.Fatal(err) } plannedValRaw, err := plans.NewDynamicValue(dataVal, dataVal.Type()) if err != nil { t.Fatal(err) } plan.Changes.SyncWrapper().AppendResourceInstanceChange(&plans.ResourceInstanceChangeSrc{ Addr: addr, PrevRunAddr: addr, ProviderAddr: addrs.AbsProviderConfig{ Provider: addrs.NewDefaultProvider("test"), Module: addrs.RootModule, }, ChangeSrc: plans.ChangeSrc{ Action: plans.Read, Before: priorValRaw, After: plannedValRaw, }, }) return plan } func testSchemas() *tofu.Schemas { provider := testProvider() return &tofu.Schemas{ Providers: map[addrs.Provider]providers.ProviderSchema{ addrs.NewDefaultProvider("test"): provider.GetProviderSchema(context.TODO()), }, } } func testProvider() *tofu.MockProvider { p := new(tofu.MockProvider) p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse { return providers.ReadResourceResponse{NewState: req.PriorState} } p.GetProviderSchemaResponse = testProviderSchema() return p } func testProviderSchema() *providers.GetProviderSchemaResponse { return &providers.GetProviderSchemaResponse{ Provider: providers.Schema{ Block: &configschema.Block{}, }, ResourceTypes: map[string]providers.Schema{ "test_resource": { Block: &configschema.Block{ Attributes: map[string]*configschema.Attribute{ "id": {Type: cty.String, Computed: true}, "foo": {Type: cty.String, Optional: true}, }, }, }, }, DataSources: map[string]providers.Schema{ "test_data_source": { Block: &configschema.Block{ Attributes: map[string]*configschema.Attribute{ "id": {Type: cty.String, Required: true}, "bar": {Type: cty.String, Optional: true}, }, }, }, }, } }