github.com/graywolf-at-work-2/terraform-vendor@v1.4.5/internal/command/jsonformat/state_test.go (about) 1 package jsonformat 2 3 import ( 4 "fmt" 5 "testing" 6 7 "github.com/google/go-cmp/cmp" 8 "github.com/mitchellh/colorstring" 9 10 "github.com/hashicorp/terraform/internal/command/format" 11 "github.com/hashicorp/terraform/internal/command/jsonprovider" 12 "github.com/hashicorp/terraform/internal/command/jsonstate" 13 "github.com/hashicorp/terraform/internal/states/statefile" 14 "github.com/hashicorp/terraform/internal/terminal" 15 16 "github.com/zclconf/go-cty/cty" 17 18 "github.com/hashicorp/terraform/internal/addrs" 19 "github.com/hashicorp/terraform/internal/configs/configschema" 20 "github.com/hashicorp/terraform/internal/providers" 21 "github.com/hashicorp/terraform/internal/states" 22 "github.com/hashicorp/terraform/internal/terraform" 23 ) 24 25 func TestState(t *testing.T) { 26 color := &colorstring.Colorize{Colors: colorstring.DefaultColors, Disable: true} 27 28 tests := []struct { 29 State *format.StateOpts 30 Want string 31 }{ 32 { 33 &format.StateOpts{ 34 State: &states.State{}, 35 Color: color, 36 Schemas: &terraform.Schemas{}, 37 }, 38 "The state file is empty. No resources are represented.\n", 39 }, 40 { 41 &format.StateOpts{ 42 State: basicState(t), 43 Color: color, 44 Schemas: testSchemas(), 45 }, 46 basicStateOutput, 47 }, 48 { 49 &format.StateOpts{ 50 State: nestedState(t), 51 Color: color, 52 Schemas: testSchemas(), 53 }, 54 nestedStateOutput, 55 }, 56 { 57 &format.StateOpts{ 58 State: deposedState(t), 59 Color: color, 60 Schemas: testSchemas(), 61 }, 62 deposedNestedStateOutput, 63 }, 64 { 65 &format.StateOpts{ 66 State: onlyDeposedState(t), 67 Color: color, 68 Schemas: testSchemas(), 69 }, 70 onlyDeposedOutput, 71 }, 72 { 73 &format.StateOpts{ 74 State: stateWithMoreOutputs(t), 75 Color: color, 76 Schemas: testSchemas(), 77 }, 78 stateWithMoreOutputsOutput, 79 }, 80 } 81 82 for i, tt := range tests { 83 t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { 84 85 root, outputs, err := jsonstate.MarshalForRenderer(&statefile.File{ 86 State: tt.State.State, 87 }, tt.State.Schemas) 88 89 if err != nil { 90 t.Errorf("found err: %v", err) 91 return 92 } 93 94 streams, done := terminal.StreamsForTesting(t) 95 renderer := Renderer{ 96 Colorize: color, 97 Streams: streams, 98 } 99 100 renderer.RenderHumanState(State{ 101 StateFormatVersion: jsonstate.FormatVersion, 102 RootModule: root, 103 RootModuleOutputs: outputs, 104 ProviderFormatVersion: jsonprovider.FormatVersion, 105 ProviderSchemas: jsonprovider.MarshalForRenderer(tt.State.Schemas), 106 }) 107 108 result := done(t).All() 109 if diff := cmp.Diff(result, tt.Want); diff != "" { 110 t.Errorf("wrong output\nexpected:\n%s\nactual:\n%s\ndiff:\n%s\n", tt.Want, result, diff) 111 } 112 }) 113 } 114 } 115 116 func testProvider() *terraform.MockProvider { 117 p := new(terraform.MockProvider) 118 p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse { 119 return providers.ReadResourceResponse{NewState: req.PriorState} 120 } 121 122 p.GetProviderSchemaResponse = testProviderSchema() 123 124 return p 125 } 126 127 func testProviderSchema() *providers.GetProviderSchemaResponse { 128 return &providers.GetProviderSchemaResponse{ 129 Provider: providers.Schema{ 130 Block: &configschema.Block{ 131 Attributes: map[string]*configschema.Attribute{ 132 "region": {Type: cty.String, Optional: true}, 133 }, 134 }, 135 }, 136 ResourceTypes: map[string]providers.Schema{ 137 "test_resource": { 138 Block: &configschema.Block{ 139 Attributes: map[string]*configschema.Attribute{ 140 "id": {Type: cty.String, Computed: true}, 141 "foo": {Type: cty.String, Optional: true}, 142 "woozles": {Type: cty.String, Optional: true}, 143 }, 144 BlockTypes: map[string]*configschema.NestedBlock{ 145 "nested": { 146 Nesting: configschema.NestingList, 147 Block: configschema.Block{ 148 Attributes: map[string]*configschema.Attribute{ 149 "compute": {Type: cty.String, Optional: true}, 150 "value": {Type: cty.String, Optional: true}, 151 }, 152 }, 153 }, 154 }, 155 }, 156 }, 157 }, 158 DataSources: map[string]providers.Schema{ 159 "test_data_source": { 160 Block: &configschema.Block{ 161 Attributes: map[string]*configschema.Attribute{ 162 "compute": {Type: cty.String, Optional: true}, 163 "value": {Type: cty.String, Computed: true}, 164 }, 165 }, 166 }, 167 }, 168 } 169 } 170 171 func testSchemas() *terraform.Schemas { 172 provider := testProvider() 173 return &terraform.Schemas{ 174 Providers: map[addrs.Provider]*terraform.ProviderSchema{ 175 addrs.NewDefaultProvider("test"): provider.ProviderSchema(), 176 }, 177 } 178 } 179 180 const basicStateOutput = `# data.test_data_source.data: 181 data "test_data_source" "data" { 182 compute = "sure" 183 } 184 185 # test_resource.baz[0]: 186 resource "test_resource" "baz" { 187 woozles = "confuzles" 188 } 189 190 191 Outputs: 192 193 bar = "bar value" 194 ` 195 196 const nestedStateOutput = `# test_resource.baz[0]: 197 resource "test_resource" "baz" { 198 woozles = "confuzles" 199 200 nested { 201 value = "42" 202 } 203 } 204 ` 205 206 const deposedNestedStateOutput = `# test_resource.baz[0]: 207 resource "test_resource" "baz" { 208 woozles = "confuzles" 209 210 nested { 211 value = "42" 212 } 213 } 214 215 # test_resource.baz[0]: (deposed object 1234) 216 resource "test_resource" "baz" { 217 woozles = "confuzles" 218 219 nested { 220 value = "42" 221 } 222 } 223 ` 224 225 const onlyDeposedOutput = `# test_resource.baz[0]: (deposed object 1234) 226 resource "test_resource" "baz" { 227 woozles = "confuzles" 228 229 nested { 230 value = "42" 231 } 232 } 233 234 # test_resource.baz[0]: (deposed object 5678) 235 resource "test_resource" "baz" { 236 woozles = "confuzles" 237 238 nested { 239 value = "42" 240 } 241 } 242 ` 243 244 const stateWithMoreOutputsOutput = `# test_resource.baz[0]: 245 resource "test_resource" "baz" { 246 woozles = "confuzles" 247 } 248 249 250 Outputs: 251 252 bool_var = true 253 int_var = 42 254 map_var = { 255 "first" = "foo" 256 "second" = "bar" 257 } 258 sensitive_var = (sensitive value) 259 string_var = "string value" 260 ` 261 262 func basicState(t *testing.T) *states.State { 263 state := states.NewState() 264 265 rootModule := state.RootModule() 266 if rootModule == nil { 267 t.Errorf("root module is nil; want valid object") 268 } 269 270 rootModule.SetLocalValue("foo", cty.StringVal("foo value")) 271 rootModule.SetOutputValue("bar", cty.StringVal("bar value"), false) 272 rootModule.SetResourceInstanceCurrent( 273 addrs.Resource{ 274 Mode: addrs.ManagedResourceMode, 275 Type: "test_resource", 276 Name: "baz", 277 }.Instance(addrs.IntKey(0)), 278 &states.ResourceInstanceObjectSrc{ 279 Status: states.ObjectReady, 280 SchemaVersion: 0, 281 AttrsJSON: []byte(`{"woozles":"confuzles"}`), 282 }, 283 addrs.AbsProviderConfig{ 284 Provider: addrs.NewDefaultProvider("test"), 285 Module: addrs.RootModule, 286 }, 287 ) 288 rootModule.SetResourceInstanceCurrent( 289 addrs.Resource{ 290 Mode: addrs.DataResourceMode, 291 Type: "test_data_source", 292 Name: "data", 293 }.Instance(addrs.NoKey), 294 &states.ResourceInstanceObjectSrc{ 295 Status: states.ObjectReady, 296 SchemaVersion: 0, 297 AttrsJSON: []byte(`{"compute":"sure"}`), 298 }, 299 addrs.AbsProviderConfig{ 300 Provider: addrs.NewDefaultProvider("test"), 301 Module: addrs.RootModule, 302 }, 303 ) 304 return state 305 } 306 307 func stateWithMoreOutputs(t *testing.T) *states.State { 308 state := states.NewState() 309 310 rootModule := state.RootModule() 311 if rootModule == nil { 312 t.Errorf("root module is nil; want valid object") 313 } 314 315 rootModule.SetOutputValue("string_var", cty.StringVal("string value"), false) 316 rootModule.SetOutputValue("int_var", cty.NumberIntVal(42), false) 317 rootModule.SetOutputValue("bool_var", cty.BoolVal(true), false) 318 rootModule.SetOutputValue("sensitive_var", cty.StringVal("secret!!!"), true) 319 rootModule.SetOutputValue("map_var", cty.MapVal(map[string]cty.Value{ 320 "first": cty.StringVal("foo"), 321 "second": cty.StringVal("bar"), 322 }), false) 323 324 rootModule.SetResourceInstanceCurrent( 325 addrs.Resource{ 326 Mode: addrs.ManagedResourceMode, 327 Type: "test_resource", 328 Name: "baz", 329 }.Instance(addrs.IntKey(0)), 330 &states.ResourceInstanceObjectSrc{ 331 Status: states.ObjectReady, 332 SchemaVersion: 0, 333 AttrsJSON: []byte(`{"woozles":"confuzles"}`), 334 }, 335 addrs.AbsProviderConfig{ 336 Provider: addrs.NewDefaultProvider("test"), 337 Module: addrs.RootModule, 338 }, 339 ) 340 return state 341 } 342 343 func nestedState(t *testing.T) *states.State { 344 state := states.NewState() 345 346 rootModule := state.RootModule() 347 if rootModule == nil { 348 t.Errorf("root module is nil; want valid object") 349 } 350 351 rootModule.SetResourceInstanceCurrent( 352 addrs.Resource{ 353 Mode: addrs.ManagedResourceMode, 354 Type: "test_resource", 355 Name: "baz", 356 }.Instance(addrs.IntKey(0)), 357 &states.ResourceInstanceObjectSrc{ 358 Status: states.ObjectReady, 359 SchemaVersion: 0, 360 AttrsJSON: []byte(`{"woozles":"confuzles","nested": [{"value": "42"}]}`), 361 }, 362 addrs.AbsProviderConfig{ 363 Provider: addrs.NewDefaultProvider("test"), 364 Module: addrs.RootModule, 365 }, 366 ) 367 return state 368 } 369 370 func deposedState(t *testing.T) *states.State { 371 state := nestedState(t) 372 rootModule := state.RootModule() 373 rootModule.SetResourceInstanceDeposed( 374 addrs.Resource{ 375 Mode: addrs.ManagedResourceMode, 376 Type: "test_resource", 377 Name: "baz", 378 }.Instance(addrs.IntKey(0)), 379 states.DeposedKey("1234"), 380 &states.ResourceInstanceObjectSrc{ 381 Status: states.ObjectReady, 382 SchemaVersion: 0, 383 AttrsJSON: []byte(`{"woozles":"confuzles","nested": [{"value": "42"}]}`), 384 }, 385 addrs.AbsProviderConfig{ 386 Provider: addrs.NewDefaultProvider("test"), 387 Module: addrs.RootModule, 388 }, 389 ) 390 return state 391 } 392 393 // replicate a corrupt resource where only a deposed exists 394 func onlyDeposedState(t *testing.T) *states.State { 395 state := states.NewState() 396 397 rootModule := state.RootModule() 398 if rootModule == nil { 399 t.Errorf("root module is nil; want valid object") 400 } 401 402 rootModule.SetResourceInstanceDeposed( 403 addrs.Resource{ 404 Mode: addrs.ManagedResourceMode, 405 Type: "test_resource", 406 Name: "baz", 407 }.Instance(addrs.IntKey(0)), 408 states.DeposedKey("1234"), 409 &states.ResourceInstanceObjectSrc{ 410 Status: states.ObjectReady, 411 SchemaVersion: 0, 412 AttrsJSON: []byte(`{"woozles":"confuzles","nested": [{"value": "42"}]}`), 413 }, 414 addrs.AbsProviderConfig{ 415 Provider: addrs.NewDefaultProvider("test"), 416 Module: addrs.RootModule, 417 }, 418 ) 419 rootModule.SetResourceInstanceDeposed( 420 addrs.Resource{ 421 Mode: addrs.ManagedResourceMode, 422 Type: "test_resource", 423 Name: "baz", 424 }.Instance(addrs.IntKey(0)), 425 states.DeposedKey("5678"), 426 &states.ResourceInstanceObjectSrc{ 427 Status: states.ObjectReady, 428 SchemaVersion: 0, 429 AttrsJSON: []byte(`{"woozles":"confuzles","nested": [{"value": "42"}]}`), 430 }, 431 addrs.AbsProviderConfig{ 432 Provider: addrs.NewDefaultProvider("test"), 433 Module: addrs.RootModule, 434 }, 435 ) 436 return state 437 }