blob: d71d33734f05ecd6b772775024d8be0e76df22de [file] [log] [blame]
package statefile
import (
"sort"
"strings"
"testing"
"github.com/hashicorp/terraform/internal/tfdiags"
"github.com/zclconf/go-cty/cty"
)
// This test verifies that modules are sorted before resources:
// https://github.com/hashicorp/terraform/issues/21552
func TestVersion4_sort(t *testing.T) {
resources := sortResourcesV4{
{
Module: "module.child",
Type: "test_instance",
Name: "foo",
},
{
Type: "test_instance",
Name: "foo",
},
{
Module: "module.kinder",
Type: "test_instance",
Name: "foo",
},
{
Module: "module.child.grandchild",
Type: "test_instance",
Name: "foo",
},
}
sort.Stable(resources)
moduleOrder := []string{"", "module.child", "module.child.grandchild", "module.kinder"}
for i, resource := range resources {
if resource.Module != moduleOrder[i] {
t.Errorf("wrong sort order: expected %q, got %q\n", moduleOrder[i], resource.Module)
}
}
}
func TestVersion4_unmarshalPaths(t *testing.T) {
testCases := map[string]struct {
json string
paths []cty.Path
diags []string
}{
"no paths": {
json: `[]`,
paths: []cty.Path{},
},
"attribute path": {
json: `[
[
{
"type": "get_attr",
"value": "password"
}
]
]`,
paths: []cty.Path{cty.GetAttrPath("password")},
},
"attribute and string index": {
json: `[
[
{
"type": "get_attr",
"value": "triggers"
},
{
"type": "index",
"value": {
"value": "secret",
"type": "string"
}
}
]
]`,
paths: []cty.Path{cty.GetAttrPath("triggers").IndexString("secret")},
},
"attribute, number index, attribute": {
json: `[
[
{
"type": "get_attr",
"value": "identities"
},
{
"type": "index",
"value": {
"value": 2,
"type": "number"
}
},
{
"type": "get_attr",
"value": "private_key"
}
]
]`,
paths: []cty.Path{cty.GetAttrPath("identities").IndexInt(2).GetAttr("private_key")},
},
"multiple paths": {
json: `[
[
{
"type": "get_attr",
"value": "alpha"
}
],
[
{
"type": "get_attr",
"value": "beta"
}
],
[
{
"type": "get_attr",
"value": "gamma"
}
]
]`,
paths: []cty.Path{cty.GetAttrPath("alpha"), cty.GetAttrPath("beta"), cty.GetAttrPath("gamma")},
},
"errors": {
json: `[
[
{
"type": "get_attr",
"value": 5
}
],
[
{
"type": "index",
"value": "test"
}
],
[
{
"type": "invalid_type",
"value": ["this is invalid too"]
}
]
]`,
paths: []cty.Path{},
diags: []string{
"Failed to unmarshal get attr step name",
"Failed to unmarshal index step key",
"Unsupported path step",
},
},
"one invalid path, others valid": {
json: `[
[
{
"type": "get_attr",
"value": "alpha"
}
],
[
{
"type": "invalid_type",
"value": ["this is invalid too"]
}
],
[
{
"type": "get_attr",
"value": "gamma"
}
]
]`,
paths: []cty.Path{cty.GetAttrPath("alpha"), cty.GetAttrPath("gamma")},
diags: []string{"Unsupported path step"},
},
"invalid structure": {
json: `{}`,
paths: []cty.Path{},
diags: []string{"Error unmarshaling path steps"},
},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
paths, diags := unmarshalPaths([]byte(tc.json))
if len(tc.diags) == 0 {
if len(diags) != 0 {
t.Errorf("expected no diags, got: %#v", diags)
}
} else {
if got, want := len(diags), len(tc.diags); got != want {
t.Fatalf("got %d diags, want %d\n%s", got, want, diags.Err())
}
for i := range tc.diags {
got := tfdiags.Diagnostics{diags[i]}.Err().Error()
if !strings.Contains(got, tc.diags[i]) {
t.Errorf("expected diag %d to contain %q, but was:\n%s", i, tc.diags[i], got)
}
}
}
if len(paths) != len(tc.paths) {
t.Fatalf("got %d paths, want %d", len(paths), len(tc.paths))
}
for i, path := range paths {
if !path.Equals(tc.paths[i]) {
t.Errorf("wrong paths\n got: %#v\nwant: %#v", path, tc.paths[i])
}
}
})
}
}
func TestVersion4_marshalPaths(t *testing.T) {
testCases := map[string]struct {
paths []cty.Path
json string
}{
"no paths": {
paths: []cty.Path{},
json: `[]`,
},
"attribute path": {
paths: []cty.Path{cty.GetAttrPath("password")},
json: `[[{"type":"get_attr","value":"password"}]]`,
},
"attribute, number index, attribute": {
paths: []cty.Path{cty.GetAttrPath("identities").IndexInt(2).GetAttr("private_key")},
json: `[[{"type":"get_attr","value":"identities"},{"type":"index","value":{"value":2,"type":"number"}},{"type":"get_attr","value":"private_key"}]]`,
},
"multiple paths": {
paths: []cty.Path{cty.GetAttrPath("a"), cty.GetAttrPath("b"), cty.GetAttrPath("c")},
json: `[[{"type":"get_attr","value":"a"}],[{"type":"get_attr","value":"b"}],[{"type":"get_attr","value":"c"}]]`,
},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
json, diags := marshalPaths(tc.paths)
if len(diags) != 0 {
t.Fatalf("expected no diags, got: %#v", diags)
}
if got, want := string(json), tc.json; got != want {
t.Fatalf("wrong JSON output\n got: %s\nwant: %s\n", got, want)
}
})
}
}