github.com/rstandt/terraform@v0.12.32-0.20230710220336-b1063613405c/backend/local/backend_refresh_test.go (about) 1 package local 2 3 import ( 4 "context" 5 "fmt" 6 "testing" 7 8 "github.com/hashicorp/terraform/providers" 9 10 "github.com/hashicorp/terraform/backend" 11 "github.com/hashicorp/terraform/configs/configschema" 12 "github.com/hashicorp/terraform/internal/initwd" 13 "github.com/hashicorp/terraform/terraform" 14 "github.com/zclconf/go-cty/cty" 15 ) 16 17 func TestLocal_refresh(t *testing.T) { 18 b, cleanup := TestLocal(t) 19 defer cleanup() 20 21 p := TestLocalProvider(t, b, "test", refreshFixtureSchema()) 22 terraform.TestStateFile(t, b.StatePath, testRefreshState()) 23 24 p.ReadResourceFn = nil 25 p.ReadResourceResponse = providers.ReadResourceResponse{NewState: cty.ObjectVal(map[string]cty.Value{ 26 "id": cty.StringVal("yes"), 27 })} 28 29 op, configCleanup := testOperationRefresh(t, "./testdata/refresh") 30 defer configCleanup() 31 32 run, err := b.Operation(context.Background(), op) 33 if err != nil { 34 t.Fatalf("bad: %s", err) 35 } 36 <-run.Done() 37 38 if !p.ReadResourceCalled { 39 t.Fatal("ReadResource should be called") 40 } 41 42 checkState(t, b.StateOutPath, ` 43 test_instance.foo: 44 ID = yes 45 provider = provider.test 46 `) 47 } 48 49 func TestLocal_refreshNoConfig(t *testing.T) { 50 b, cleanup := TestLocal(t) 51 defer cleanup() 52 p := TestLocalProvider(t, b, "test", refreshFixtureSchema()) 53 terraform.TestStateFile(t, b.StatePath, testRefreshState()) 54 p.ReadResourceFn = nil 55 p.ReadResourceResponse = providers.ReadResourceResponse{NewState: cty.ObjectVal(map[string]cty.Value{ 56 "id": cty.StringVal("yes"), 57 })} 58 59 op, configCleanup := testOperationRefresh(t, "./testdata/empty") 60 defer configCleanup() 61 62 run, err := b.Operation(context.Background(), op) 63 if err != nil { 64 t.Fatalf("bad: %s", err) 65 } 66 <-run.Done() 67 68 if !p.ReadResourceCalled { 69 t.Fatal("ReadResource should be called") 70 } 71 72 checkState(t, b.StateOutPath, ` 73 test_instance.foo: 74 ID = yes 75 provider = provider.test 76 `) 77 } 78 79 // GH-12174 80 func TestLocal_refreshNilModuleWithInput(t *testing.T) { 81 b, cleanup := TestLocal(t) 82 defer cleanup() 83 p := TestLocalProvider(t, b, "test", refreshFixtureSchema()) 84 terraform.TestStateFile(t, b.StatePath, testRefreshState()) 85 p.ReadResourceFn = nil 86 p.ReadResourceResponse = providers.ReadResourceResponse{NewState: cty.ObjectVal(map[string]cty.Value{ 87 "id": cty.StringVal("yes"), 88 })} 89 90 b.OpInput = true 91 92 op, configCleanup := testOperationRefresh(t, "./testdata/empty") 93 defer configCleanup() 94 95 run, err := b.Operation(context.Background(), op) 96 if err != nil { 97 t.Fatalf("bad: %s", err) 98 } 99 <-run.Done() 100 101 if !p.ReadResourceCalled { 102 t.Fatal("ReadResource should be called") 103 } 104 105 checkState(t, b.StateOutPath, ` 106 test_instance.foo: 107 ID = yes 108 provider = provider.test 109 `) 110 } 111 112 func TestLocal_refreshInput(t *testing.T) { 113 b, cleanup := TestLocal(t) 114 defer cleanup() 115 p := TestLocalProvider(t, b, "test", refreshFixtureSchema()) 116 terraform.TestStateFile(t, b.StatePath, testRefreshState()) 117 118 p.GetSchemaReturn = &terraform.ProviderSchema{ 119 Provider: &configschema.Block{ 120 Attributes: map[string]*configschema.Attribute{ 121 "value": {Type: cty.String, Optional: true}, 122 }, 123 }, 124 ResourceTypes: map[string]*configschema.Block{ 125 "test_instance": { 126 Attributes: map[string]*configschema.Attribute{ 127 "foo": {Type: cty.String, Optional: true}, 128 "id": {Type: cty.String, Optional: true}, 129 }, 130 }, 131 }, 132 } 133 p.ReadResourceFn = nil 134 p.ReadResourceResponse = providers.ReadResourceResponse{NewState: cty.ObjectVal(map[string]cty.Value{ 135 "id": cty.StringVal("yes"), 136 })} 137 p.ConfigureFn = func(c *terraform.ResourceConfig) error { 138 if v, ok := c.Get("value"); !ok || v != "bar" { 139 return fmt.Errorf("no value set") 140 } 141 142 return nil 143 } 144 145 // Enable input asking since it is normally disabled by default 146 b.OpInput = true 147 b.ContextOpts.UIInput = &terraform.MockUIInput{InputReturnString: "bar"} 148 149 op, configCleanup := testOperationRefresh(t, "./testdata/refresh-var-unset") 150 defer configCleanup() 151 op.UIIn = b.ContextOpts.UIInput 152 153 run, err := b.Operation(context.Background(), op) 154 if err != nil { 155 t.Fatalf("bad: %s", err) 156 } 157 <-run.Done() 158 159 if !p.ReadResourceCalled { 160 t.Fatal("ReadResource should be called") 161 } 162 163 checkState(t, b.StateOutPath, ` 164 test_instance.foo: 165 ID = yes 166 provider = provider.test 167 `) 168 } 169 170 func TestLocal_refreshValidate(t *testing.T) { 171 b, cleanup := TestLocal(t) 172 defer cleanup() 173 p := TestLocalProvider(t, b, "test", refreshFixtureSchema()) 174 terraform.TestStateFile(t, b.StatePath, testRefreshState()) 175 p.ReadResourceFn = nil 176 p.ReadResourceResponse = providers.ReadResourceResponse{NewState: cty.ObjectVal(map[string]cty.Value{ 177 "id": cty.StringVal("yes"), 178 })} 179 180 // Enable validation 181 b.OpValidation = true 182 183 op, configCleanup := testOperationRefresh(t, "./testdata/refresh") 184 defer configCleanup() 185 186 run, err := b.Operation(context.Background(), op) 187 if err != nil { 188 t.Fatalf("bad: %s", err) 189 } 190 <-run.Done() 191 192 if !p.PrepareProviderConfigCalled { 193 t.Fatal("Prepare provider config should be called") 194 } 195 196 checkState(t, b.StateOutPath, ` 197 test_instance.foo: 198 ID = yes 199 provider = provider.test 200 `) 201 } 202 203 func testOperationRefresh(t *testing.T, configDir string) (*backend.Operation, func()) { 204 t.Helper() 205 206 _, configLoader, configCleanup := initwd.MustLoadConfigForTests(t, configDir) 207 208 return &backend.Operation{ 209 Type: backend.OperationTypeRefresh, 210 ConfigDir: configDir, 211 ConfigLoader: configLoader, 212 }, configCleanup 213 } 214 215 // testRefreshState is just a common state that we use for testing refresh. 216 func testRefreshState() *terraform.State { 217 return &terraform.State{ 218 Version: 2, 219 Modules: []*terraform.ModuleState{ 220 &terraform.ModuleState{ 221 Path: []string{"root"}, 222 Resources: map[string]*terraform.ResourceState{ 223 "test_instance.foo": &terraform.ResourceState{ 224 Type: "test_instance", 225 Primary: &terraform.InstanceState{ 226 ID: "bar", 227 }, 228 }, 229 }, 230 Outputs: map[string]*terraform.OutputState{}, 231 }, 232 }, 233 } 234 } 235 236 // refreshFixtureSchema returns a schema suitable for processing the 237 // configuration in testdata/refresh . This schema should be 238 // assigned to a mock provider named "test". 239 func refreshFixtureSchema() *terraform.ProviderSchema { 240 return &terraform.ProviderSchema{ 241 ResourceTypes: map[string]*configschema.Block{ 242 "test_instance": { 243 Attributes: map[string]*configschema.Attribute{ 244 "ami": {Type: cty.String, Optional: true}, 245 "id": {Type: cty.String, Computed: true}, 246 }, 247 }, 248 }, 249 } 250 }