github.com/opentofu/opentofu@v1.7.1/internal/legacy/tofu/upgrade_state_v2_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 tofu 7 8 import ( 9 "bytes" 10 "strings" 11 "testing" 12 ) 13 14 // TestReadUpgradeStateV2toV3 tests the state upgrade process from the V2 state 15 // to the current version, and needs editing each time. This means it tests the 16 // entire pipeline of upgrades (which migrate version to version). 17 func TestReadUpgradeStateV2toV3(t *testing.T) { 18 // ReadState should transparently detect the old version but will upgrade 19 // it on Write. 20 upgraded, err := ReadState(strings.NewReader(testV2State)) 21 if err != nil { 22 t.Fatalf("err: %s", err) 23 } 24 25 buf := new(bytes.Buffer) 26 if err := WriteState(upgraded, buf); err != nil { 27 t.Fatalf("err: %s", err) 28 } 29 30 if upgraded.Version != 3 { 31 t.Fatalf("bad: State version not incremented; is %d", upgraded.Version) 32 } 33 34 // For this test we cannot assert that we match the round trip because an 35 // empty map has been removed from state. Instead we make assertions against 36 // some of the key fields in the _upgraded_ state. 37 instanceState, ok := upgraded.RootModule().Resources["test_resource.main"] 38 if !ok { 39 t.Fatalf("Instance state for test_resource.main was removed from state during upgrade") 40 } 41 42 primary := instanceState.Primary 43 if primary == nil { 44 t.Fatalf("Primary instance was removed from state for test_resource.main") 45 } 46 47 // Non-empty computed map is moved from .# to .% 48 if _, ok := primary.Attributes["computed_map.#"]; ok { 49 t.Fatalf("Count was not upgraded from .# to .%% for computed_map") 50 } 51 if count, ok := primary.Attributes["computed_map.%"]; !ok || count != "1" { 52 t.Fatalf("Count was not in .%% or was not 2 for computed_map") 53 } 54 55 // list_of_map top level retains .# 56 if count, ok := primary.Attributes["list_of_map.#"]; !ok || count != "2" { 57 t.Fatal("Count for list_of_map was migrated incorrectly") 58 } 59 60 // list_of_map.0 is moved from .# to .% 61 if _, ok := primary.Attributes["list_of_map.0.#"]; ok { 62 t.Fatalf("Count was not upgraded from .# to .%% for list_of_map.0") 63 } 64 if count, ok := primary.Attributes["list_of_map.0.%"]; !ok || count != "2" { 65 t.Fatalf("Count was not in .%% or was not 2 for list_of_map.0") 66 } 67 68 // list_of_map.1 is moved from .# to .% 69 if _, ok := primary.Attributes["list_of_map.1.#"]; ok { 70 t.Fatalf("Count was not upgraded from .# to .%% for list_of_map.1") 71 } 72 if count, ok := primary.Attributes["list_of_map.1.%"]; !ok || count != "2" { 73 t.Fatalf("Count was not in .%% or was not 2 for list_of_map.1") 74 } 75 76 // map is moved from .# to .% 77 if _, ok := primary.Attributes["map.#"]; ok { 78 t.Fatalf("Count was not upgraded from .# to .%% for map") 79 } 80 if count, ok := primary.Attributes["map.%"]; !ok || count != "2" { 81 t.Fatalf("Count was not in .%% or was not 2 for map") 82 } 83 84 // optional_computed_map should be removed from state 85 if _, ok := primary.Attributes["optional_computed_map"]; ok { 86 t.Fatal("optional_computed_map was not removed from state") 87 } 88 89 // required_map is moved from .# to .% 90 if _, ok := primary.Attributes["required_map.#"]; ok { 91 t.Fatalf("Count was not upgraded from .# to .%% for required_map") 92 } 93 if count, ok := primary.Attributes["required_map.%"]; !ok || count != "3" { 94 t.Fatalf("Count was not in .%% or was not 3 for map") 95 } 96 97 // computed_list keeps .# 98 if count, ok := primary.Attributes["computed_list.#"]; !ok || count != "2" { 99 t.Fatal("Count was migrated incorrectly for computed_list") 100 } 101 102 // computed_set keeps .# 103 if count, ok := primary.Attributes["computed_set.#"]; !ok || count != "2" { 104 t.Fatal("Count was migrated incorrectly for computed_set") 105 } 106 if val, ok := primary.Attributes["computed_set.2337322984"]; !ok || val != "setval1" { 107 t.Fatal("Set item for computed_set.2337322984 changed or moved") 108 } 109 if val, ok := primary.Attributes["computed_set.307881554"]; !ok || val != "setval2" { 110 t.Fatal("Set item for computed_set.307881554 changed or moved") 111 } 112 113 // string properties are unaffected 114 if val, ok := primary.Attributes["id"]; !ok || val != "testId" { 115 t.Fatal("id was not set correctly after migration") 116 } 117 } 118 119 const testV2State = `{ 120 "version": 2, 121 "terraform_version": "0.7.0", 122 "serial": 2, 123 "modules": [ 124 { 125 "path": [ 126 "root" 127 ], 128 "outputs": { 129 "computed_map": { 130 "sensitive": false, 131 "type": "map", 132 "value": { 133 "key1": "value1" 134 } 135 }, 136 "computed_set": { 137 "sensitive": false, 138 "type": "list", 139 "value": [ 140 "setval1", 141 "setval2" 142 ] 143 }, 144 "map": { 145 "sensitive": false, 146 "type": "map", 147 "value": { 148 "key": "test", 149 "test": "test" 150 } 151 }, 152 "set": { 153 "sensitive": false, 154 "type": "list", 155 "value": [ 156 "test1", 157 "test2" 158 ] 159 } 160 }, 161 "resources": { 162 "test_resource.main": { 163 "type": "test_resource", 164 "primary": { 165 "id": "testId", 166 "attributes": { 167 "computed_list.#": "2", 168 "computed_list.0": "listval1", 169 "computed_list.1": "listval2", 170 "computed_map.#": "1", 171 "computed_map.key1": "value1", 172 "computed_read_only": "value_from_api", 173 "computed_read_only_force_new": "value_from_api", 174 "computed_set.#": "2", 175 "computed_set.2337322984": "setval1", 176 "computed_set.307881554": "setval2", 177 "id": "testId", 178 "list_of_map.#": "2", 179 "list_of_map.0.#": "2", 180 "list_of_map.0.key1": "value1", 181 "list_of_map.0.key2": "value2", 182 "list_of_map.1.#": "2", 183 "list_of_map.1.key3": "value3", 184 "list_of_map.1.key4": "value4", 185 "map.#": "2", 186 "map.key": "test", 187 "map.test": "test", 188 "map_that_look_like_set.#": "2", 189 "map_that_look_like_set.12352223": "hello", 190 "map_that_look_like_set.36234341": "world", 191 "optional_computed_map.#": "0", 192 "required": "Hello World", 193 "required_map.#": "3", 194 "required_map.key1": "value1", 195 "required_map.key2": "value2", 196 "required_map.key3": "value3", 197 "set.#": "2", 198 "set.2326977762": "test1", 199 "set.331058520": "test2" 200 } 201 } 202 } 203 } 204 } 205 ] 206 } 207 `