github.com/graywolf-at-work-2/terraform-vendor@v1.4.5/internal/states/statefile/version4_test.go (about) 1 package statefile 2 3 import ( 4 "sort" 5 "strings" 6 "testing" 7 8 "github.com/hashicorp/terraform/internal/tfdiags" 9 "github.com/zclconf/go-cty/cty" 10 ) 11 12 // This test verifies that modules are sorted before resources: 13 // https://github.com/hashicorp/terraform/issues/21552 14 func TestVersion4_sort(t *testing.T) { 15 resources := sortResourcesV4{ 16 { 17 Module: "module.child", 18 Type: "test_instance", 19 Name: "foo", 20 }, 21 { 22 Type: "test_instance", 23 Name: "foo", 24 }, 25 { 26 Module: "module.kinder", 27 Type: "test_instance", 28 Name: "foo", 29 }, 30 { 31 Module: "module.child.grandchild", 32 Type: "test_instance", 33 Name: "foo", 34 }, 35 } 36 sort.Stable(resources) 37 38 moduleOrder := []string{"", "module.child", "module.child.grandchild", "module.kinder"} 39 40 for i, resource := range resources { 41 if resource.Module != moduleOrder[i] { 42 t.Errorf("wrong sort order: expected %q, got %q\n", moduleOrder[i], resource.Module) 43 } 44 } 45 } 46 47 func TestVersion4_unmarshalPaths(t *testing.T) { 48 testCases := map[string]struct { 49 json string 50 paths []cty.Path 51 diags []string 52 }{ 53 "no paths": { 54 json: `[]`, 55 paths: []cty.Path{}, 56 }, 57 "attribute path": { 58 json: `[ 59 [ 60 { 61 "type": "get_attr", 62 "value": "password" 63 } 64 ] 65 ]`, 66 paths: []cty.Path{cty.GetAttrPath("password")}, 67 }, 68 "attribute and string index": { 69 json: `[ 70 [ 71 { 72 "type": "get_attr", 73 "value": "triggers" 74 }, 75 { 76 "type": "index", 77 "value": { 78 "value": "secret", 79 "type": "string" 80 } 81 } 82 ] 83 ]`, 84 paths: []cty.Path{cty.GetAttrPath("triggers").IndexString("secret")}, 85 }, 86 "attribute, number index, attribute": { 87 json: `[ 88 [ 89 { 90 "type": "get_attr", 91 "value": "identities" 92 }, 93 { 94 "type": "index", 95 "value": { 96 "value": 2, 97 "type": "number" 98 } 99 }, 100 { 101 "type": "get_attr", 102 "value": "private_key" 103 } 104 ] 105 ]`, 106 paths: []cty.Path{cty.GetAttrPath("identities").IndexInt(2).GetAttr("private_key")}, 107 }, 108 "multiple paths": { 109 json: `[ 110 [ 111 { 112 "type": "get_attr", 113 "value": "alpha" 114 } 115 ], 116 [ 117 { 118 "type": "get_attr", 119 "value": "beta" 120 } 121 ], 122 [ 123 { 124 "type": "get_attr", 125 "value": "gamma" 126 } 127 ] 128 ]`, 129 paths: []cty.Path{cty.GetAttrPath("alpha"), cty.GetAttrPath("beta"), cty.GetAttrPath("gamma")}, 130 }, 131 "errors": { 132 json: `[ 133 [ 134 { 135 "type": "get_attr", 136 "value": 5 137 } 138 ], 139 [ 140 { 141 "type": "index", 142 "value": "test" 143 } 144 ], 145 [ 146 { 147 "type": "invalid_type", 148 "value": ["this is invalid too"] 149 } 150 ] 151 ]`, 152 paths: []cty.Path{}, 153 diags: []string{ 154 "Failed to unmarshal get attr step name", 155 "Failed to unmarshal index step key", 156 "Unsupported path step", 157 }, 158 }, 159 "one invalid path, others valid": { 160 json: `[ 161 [ 162 { 163 "type": "get_attr", 164 "value": "alpha" 165 } 166 ], 167 [ 168 { 169 "type": "invalid_type", 170 "value": ["this is invalid too"] 171 } 172 ], 173 [ 174 { 175 "type": "get_attr", 176 "value": "gamma" 177 } 178 ] 179 ]`, 180 paths: []cty.Path{cty.GetAttrPath("alpha"), cty.GetAttrPath("gamma")}, 181 diags: []string{"Unsupported path step"}, 182 }, 183 "invalid structure": { 184 json: `{}`, 185 paths: []cty.Path{}, 186 diags: []string{"Error unmarshaling path steps"}, 187 }, 188 } 189 190 for name, tc := range testCases { 191 t.Run(name, func(t *testing.T) { 192 paths, diags := unmarshalPaths([]byte(tc.json)) 193 194 if len(tc.diags) == 0 { 195 if len(diags) != 0 { 196 t.Errorf("expected no diags, got: %#v", diags) 197 } 198 } else { 199 if got, want := len(diags), len(tc.diags); got != want { 200 t.Fatalf("got %d diags, want %d\n%s", got, want, diags.Err()) 201 } 202 for i := range tc.diags { 203 got := tfdiags.Diagnostics{diags[i]}.Err().Error() 204 if !strings.Contains(got, tc.diags[i]) { 205 t.Errorf("expected diag %d to contain %q, but was:\n%s", i, tc.diags[i], got) 206 } 207 } 208 } 209 210 if len(paths) != len(tc.paths) { 211 t.Fatalf("got %d paths, want %d", len(paths), len(tc.paths)) 212 } 213 for i, path := range paths { 214 if !path.Equals(tc.paths[i]) { 215 t.Errorf("wrong paths\n got: %#v\nwant: %#v", path, tc.paths[i]) 216 } 217 } 218 }) 219 } 220 } 221 222 func TestVersion4_marshalPaths(t *testing.T) { 223 testCases := map[string]struct { 224 paths []cty.Path 225 json string 226 }{ 227 "no paths": { 228 paths: []cty.Path{}, 229 json: `[]`, 230 }, 231 "attribute path": { 232 paths: []cty.Path{cty.GetAttrPath("password")}, 233 json: `[[{"type":"get_attr","value":"password"}]]`, 234 }, 235 "attribute, number index, attribute": { 236 paths: []cty.Path{cty.GetAttrPath("identities").IndexInt(2).GetAttr("private_key")}, 237 json: `[[{"type":"get_attr","value":"identities"},{"type":"index","value":{"value":2,"type":"number"}},{"type":"get_attr","value":"private_key"}]]`, 238 }, 239 "multiple paths": { 240 paths: []cty.Path{cty.GetAttrPath("a"), cty.GetAttrPath("b"), cty.GetAttrPath("c")}, 241 json: `[[{"type":"get_attr","value":"a"}],[{"type":"get_attr","value":"b"}],[{"type":"get_attr","value":"c"}]]`, 242 }, 243 } 244 245 for name, tc := range testCases { 246 t.Run(name, func(t *testing.T) { 247 json, diags := marshalPaths(tc.paths) 248 249 if len(diags) != 0 { 250 t.Fatalf("expected no diags, got: %#v", diags) 251 } 252 253 if got, want := string(json), tc.json; got != want { 254 t.Fatalf("wrong JSON output\n got: %s\nwant: %s\n", got, want) 255 } 256 }) 257 } 258 }