259 lines
5.2 KiB
Go
259 lines
5.2 KiB
Go
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)
|
|
}
|
|
})
|
|
}
|
|
}
|