github.com/opentofu/opentofu@v1.7.1/internal/command/views/plan_test.go (about) 1 // Copyright (c) The OpenTofu Authors 2 // SPDX-License-Identifier: MPL-2.0 3 // Copyright (c) 2023 HashiCorp, Inc. 4 // SPDX-License-Identifier: MPL-2.0 5 6 package views 7 8 import ( 9 "testing" 10 11 "github.com/opentofu/opentofu/internal/addrs" 12 "github.com/opentofu/opentofu/internal/command/arguments" 13 "github.com/opentofu/opentofu/internal/configs/configschema" 14 "github.com/opentofu/opentofu/internal/plans" 15 "github.com/opentofu/opentofu/internal/providers" 16 "github.com/opentofu/opentofu/internal/terminal" 17 "github.com/opentofu/opentofu/internal/tofu" 18 "github.com/zclconf/go-cty/cty" 19 ) 20 21 // Ensure that the correct view type and in-automation settings propagate to the 22 // Operation view. 23 func TestPlanHuman_operation(t *testing.T) { 24 streams, done := terminal.StreamsForTesting(t) 25 defer done(t) 26 v := NewPlan(arguments.ViewHuman, NewView(streams).SetRunningInAutomation(true)).Operation() 27 if hv, ok := v.(*OperationHuman); !ok { 28 t.Fatalf("unexpected return type %t", v) 29 } else if hv.inAutomation != true { 30 t.Fatalf("unexpected inAutomation value on Operation view") 31 } 32 } 33 34 // Verify that Hooks includes a UI hook 35 func TestPlanHuman_hooks(t *testing.T) { 36 streams, done := terminal.StreamsForTesting(t) 37 defer done(t) 38 v := NewPlan(arguments.ViewHuman, NewView(streams).SetRunningInAutomation((true))) 39 hooks := v.Hooks() 40 41 var uiHook *UiHook 42 for _, hook := range hooks { 43 if ch, ok := hook.(*UiHook); ok { 44 uiHook = ch 45 } 46 } 47 if uiHook == nil { 48 t.Fatalf("expected Hooks to include a UiHook: %#v", hooks) 49 } 50 } 51 52 // Helper functions to build a trivial test plan, to exercise the plan 53 // renderer. 54 func testPlan(t *testing.T) *plans.Plan { 55 t.Helper() 56 57 plannedVal := cty.ObjectVal(map[string]cty.Value{ 58 "id": cty.UnknownVal(cty.String), 59 "foo": cty.StringVal("bar"), 60 }) 61 priorValRaw, err := plans.NewDynamicValue(cty.NullVal(plannedVal.Type()), plannedVal.Type()) 62 if err != nil { 63 t.Fatal(err) 64 } 65 plannedValRaw, err := plans.NewDynamicValue(plannedVal, plannedVal.Type()) 66 if err != nil { 67 t.Fatal(err) 68 } 69 70 changes := plans.NewChanges() 71 addr := addrs.Resource{ 72 Mode: addrs.ManagedResourceMode, 73 Type: "test_resource", 74 Name: "foo", 75 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance) 76 77 changes.SyncWrapper().AppendResourceInstanceChange(&plans.ResourceInstanceChangeSrc{ 78 Addr: addr, 79 PrevRunAddr: addr, 80 ProviderAddr: addrs.AbsProviderConfig{ 81 Provider: addrs.NewDefaultProvider("test"), 82 Module: addrs.RootModule, 83 }, 84 ChangeSrc: plans.ChangeSrc{ 85 Action: plans.Create, 86 Before: priorValRaw, 87 After: plannedValRaw, 88 }, 89 }) 90 91 return &plans.Plan{ 92 Changes: changes, 93 } 94 } 95 96 func testPlanWithDatasource(t *testing.T) *plans.Plan { 97 plan := testPlan(t) 98 99 addr := addrs.Resource{ 100 Mode: addrs.DataResourceMode, 101 Type: "test_data_source", 102 Name: "bar", 103 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance) 104 105 dataVal := cty.ObjectVal(map[string]cty.Value{ 106 "id": cty.StringVal("C6743020-40BD-4591-81E6-CD08494341D3"), 107 "bar": cty.StringVal("foo"), 108 }) 109 priorValRaw, err := plans.NewDynamicValue(cty.NullVal(dataVal.Type()), dataVal.Type()) 110 if err != nil { 111 t.Fatal(err) 112 } 113 plannedValRaw, err := plans.NewDynamicValue(dataVal, dataVal.Type()) 114 if err != nil { 115 t.Fatal(err) 116 } 117 118 plan.Changes.SyncWrapper().AppendResourceInstanceChange(&plans.ResourceInstanceChangeSrc{ 119 Addr: addr, 120 PrevRunAddr: addr, 121 ProviderAddr: addrs.AbsProviderConfig{ 122 Provider: addrs.NewDefaultProvider("test"), 123 Module: addrs.RootModule, 124 }, 125 ChangeSrc: plans.ChangeSrc{ 126 Action: plans.Read, 127 Before: priorValRaw, 128 After: plannedValRaw, 129 }, 130 }) 131 132 return plan 133 } 134 135 func testSchemas() *tofu.Schemas { 136 provider := testProvider() 137 return &tofu.Schemas{ 138 Providers: map[addrs.Provider]providers.ProviderSchema{ 139 addrs.NewDefaultProvider("test"): provider.GetProviderSchema(), 140 }, 141 } 142 } 143 144 func testProvider() *tofu.MockProvider { 145 p := new(tofu.MockProvider) 146 p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse { 147 return providers.ReadResourceResponse{NewState: req.PriorState} 148 } 149 150 p.GetProviderSchemaResponse = testProviderSchema() 151 152 return p 153 } 154 155 func testProviderSchema() *providers.GetProviderSchemaResponse { 156 return &providers.GetProviderSchemaResponse{ 157 Provider: providers.Schema{ 158 Block: &configschema.Block{}, 159 }, 160 ResourceTypes: map[string]providers.Schema{ 161 "test_resource": { 162 Block: &configschema.Block{ 163 Attributes: map[string]*configschema.Attribute{ 164 "id": {Type: cty.String, Computed: true}, 165 "foo": {Type: cty.String, Optional: true}, 166 }, 167 }, 168 }, 169 }, 170 DataSources: map[string]providers.Schema{ 171 "test_data_source": { 172 Block: &configschema.Block{ 173 Attributes: map[string]*configschema.Attribute{ 174 "id": {Type: cty.String, Required: true}, 175 "bar": {Type: cty.String, Optional: true}, 176 }, 177 }, 178 }, 179 }, 180 } 181 }