| // Copyright (c) HashiCorp, Inc. |
| // SPDX-License-Identifier: MPL-2.0 |
| |
| package terraform |
| |
| import ( |
| "bytes" |
| "strings" |
| "testing" |
| ) |
| |
| // TestReadUpgradeStateV2toV3 tests the state upgrade process from the V2 state |
| // to the current version, and needs editing each time. This means it tests the |
| // entire pipeline of upgrades (which migrate version to version). |
| func TestReadUpgradeStateV2toV3(t *testing.T) { |
| // ReadState should transparently detect the old version but will upgrade |
| // it on Write. |
| upgraded, err := ReadState(strings.NewReader(testV2State)) |
| if err != nil { |
| t.Fatalf("err: %s", err) |
| } |
| |
| buf := new(bytes.Buffer) |
| if err := WriteState(upgraded, buf); err != nil { |
| t.Fatalf("err: %s", err) |
| } |
| |
| if upgraded.Version != 3 { |
| t.Fatalf("bad: State version not incremented; is %d", upgraded.Version) |
| } |
| |
| // For this test we cannot assert that we match the round trip because an |
| // empty map has been removed from state. Instead we make assertions against |
| // some of the key fields in the _upgraded_ state. |
| instanceState, ok := upgraded.RootModule().Resources["test_resource.main"] |
| if !ok { |
| t.Fatalf("Instance state for test_resource.main was removed from state during upgrade") |
| } |
| |
| primary := instanceState.Primary |
| if primary == nil { |
| t.Fatalf("Primary instance was removed from state for test_resource.main") |
| } |
| |
| // Non-empty computed map is moved from .# to .% |
| if _, ok := primary.Attributes["computed_map.#"]; ok { |
| t.Fatalf("Count was not upgraded from .# to .%% for computed_map") |
| } |
| if count, ok := primary.Attributes["computed_map.%"]; !ok || count != "1" { |
| t.Fatalf("Count was not in .%% or was not 2 for computed_map") |
| } |
| |
| // list_of_map top level retains .# |
| if count, ok := primary.Attributes["list_of_map.#"]; !ok || count != "2" { |
| t.Fatal("Count for list_of_map was migrated incorrectly") |
| } |
| |
| // list_of_map.0 is moved from .# to .% |
| if _, ok := primary.Attributes["list_of_map.0.#"]; ok { |
| t.Fatalf("Count was not upgraded from .# to .%% for list_of_map.0") |
| } |
| if count, ok := primary.Attributes["list_of_map.0.%"]; !ok || count != "2" { |
| t.Fatalf("Count was not in .%% or was not 2 for list_of_map.0") |
| } |
| |
| // list_of_map.1 is moved from .# to .% |
| if _, ok := primary.Attributes["list_of_map.1.#"]; ok { |
| t.Fatalf("Count was not upgraded from .# to .%% for list_of_map.1") |
| } |
| if count, ok := primary.Attributes["list_of_map.1.%"]; !ok || count != "2" { |
| t.Fatalf("Count was not in .%% or was not 2 for list_of_map.1") |
| } |
| |
| // map is moved from .# to .% |
| if _, ok := primary.Attributes["map.#"]; ok { |
| t.Fatalf("Count was not upgraded from .# to .%% for map") |
| } |
| if count, ok := primary.Attributes["map.%"]; !ok || count != "2" { |
| t.Fatalf("Count was not in .%% or was not 2 for map") |
| } |
| |
| // optional_computed_map should be removed from state |
| if _, ok := primary.Attributes["optional_computed_map"]; ok { |
| t.Fatal("optional_computed_map was not removed from state") |
| } |
| |
| // required_map is moved from .# to .% |
| if _, ok := primary.Attributes["required_map.#"]; ok { |
| t.Fatalf("Count was not upgraded from .# to .%% for required_map") |
| } |
| if count, ok := primary.Attributes["required_map.%"]; !ok || count != "3" { |
| t.Fatalf("Count was not in .%% or was not 3 for map") |
| } |
| |
| // computed_list keeps .# |
| if count, ok := primary.Attributes["computed_list.#"]; !ok || count != "2" { |
| t.Fatal("Count was migrated incorrectly for computed_list") |
| } |
| |
| // computed_set keeps .# |
| if count, ok := primary.Attributes["computed_set.#"]; !ok || count != "2" { |
| t.Fatal("Count was migrated incorrectly for computed_set") |
| } |
| if val, ok := primary.Attributes["computed_set.2337322984"]; !ok || val != "setval1" { |
| t.Fatal("Set item for computed_set.2337322984 changed or moved") |
| } |
| if val, ok := primary.Attributes["computed_set.307881554"]; !ok || val != "setval2" { |
| t.Fatal("Set item for computed_set.307881554 changed or moved") |
| } |
| |
| // string properties are unaffected |
| if val, ok := primary.Attributes["id"]; !ok || val != "testId" { |
| t.Fatal("id was not set correctly after migration") |
| } |
| } |
| |
| const testV2State = `{ |
| "version": 2, |
| "terraform_version": "0.7.0", |
| "serial": 2, |
| "modules": [ |
| { |
| "path": [ |
| "root" |
| ], |
| "outputs": { |
| "computed_map": { |
| "sensitive": false, |
| "type": "map", |
| "value": { |
| "key1": "value1" |
| } |
| }, |
| "computed_set": { |
| "sensitive": false, |
| "type": "list", |
| "value": [ |
| "setval1", |
| "setval2" |
| ] |
| }, |
| "map": { |
| "sensitive": false, |
| "type": "map", |
| "value": { |
| "key": "test", |
| "test": "test" |
| } |
| }, |
| "set": { |
| "sensitive": false, |
| "type": "list", |
| "value": [ |
| "test1", |
| "test2" |
| ] |
| } |
| }, |
| "resources": { |
| "test_resource.main": { |
| "type": "test_resource", |
| "primary": { |
| "id": "testId", |
| "attributes": { |
| "computed_list.#": "2", |
| "computed_list.0": "listval1", |
| "computed_list.1": "listval2", |
| "computed_map.#": "1", |
| "computed_map.key1": "value1", |
| "computed_read_only": "value_from_api", |
| "computed_read_only_force_new": "value_from_api", |
| "computed_set.#": "2", |
| "computed_set.2337322984": "setval1", |
| "computed_set.307881554": "setval2", |
| "id": "testId", |
| "list_of_map.#": "2", |
| "list_of_map.0.#": "2", |
| "list_of_map.0.key1": "value1", |
| "list_of_map.0.key2": "value2", |
| "list_of_map.1.#": "2", |
| "list_of_map.1.key3": "value3", |
| "list_of_map.1.key4": "value4", |
| "map.#": "2", |
| "map.key": "test", |
| "map.test": "test", |
| "map_that_look_like_set.#": "2", |
| "map_that_look_like_set.12352223": "hello", |
| "map_that_look_like_set.36234341": "world", |
| "optional_computed_map.#": "0", |
| "required": "Hello World", |
| "required_map.#": "3", |
| "required_map.key1": "value1", |
| "required_map.key2": "value2", |
| "required_map.key3": "value3", |
| "set.#": "2", |
| "set.2326977762": "test1", |
| "set.331058520": "test2" |
| } |
| } |
| } |
| } |
| } |
| ] |
| } |
| ` |