mirror of
https://github.com/opentffoundation/opentf.git
synced 2025-12-21 02:37:43 -05:00
2281 lines
51 KiB
Go
2281 lines
51 KiB
Go
// Copyright (c) The OpenTofu Authors
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
// Copyright (c) 2023 HashiCorp, Inc.
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
package renderers
|
|
|
|
import (
|
|
"encoding/json"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/opentofu/opentofu/internal/command/jsonformat/computed"
|
|
|
|
"github.com/google/go-cmp/cmp"
|
|
"github.com/mitchellh/colorstring"
|
|
"github.com/zclconf/go-cty/cty"
|
|
|
|
"github.com/opentofu/opentofu/internal/plans"
|
|
)
|
|
|
|
func TestRenderers_Human(t *testing.T) {
|
|
colorize := colorstring.Colorize{
|
|
Colors: colorstring.DefaultColors,
|
|
Disable: true,
|
|
}
|
|
|
|
tcs := map[string]struct {
|
|
diff computed.Diff
|
|
expected string
|
|
opts computed.RenderHumanOpts
|
|
}{
|
|
// We're using the string "null" in these tests to demonstrate the
|
|
// difference between rendering an actual string and rendering a null
|
|
// value.
|
|
"primitive_create_string": {
|
|
diff: computed.Diff{
|
|
Renderer: Primitive(nil, "null", cty.String),
|
|
Action: plans.Create,
|
|
},
|
|
expected: "\"null\"",
|
|
},
|
|
"primitive_delete_string": {
|
|
diff: computed.Diff{
|
|
Renderer: Primitive("null", nil, cty.String),
|
|
Action: plans.Delete,
|
|
},
|
|
expected: "\"null\" -> null",
|
|
},
|
|
"primitive_update_string_to_null": {
|
|
diff: computed.Diff{
|
|
Renderer: Primitive("null", nil, cty.String),
|
|
Action: plans.Update,
|
|
},
|
|
expected: "\"null\" -> null",
|
|
},
|
|
"primitive_update_string_from_null": {
|
|
diff: computed.Diff{
|
|
Renderer: Primitive(nil, "null", cty.String),
|
|
Action: plans.Update,
|
|
},
|
|
expected: "null -> \"null\"",
|
|
},
|
|
"primitive_update_multiline_string_to_null": {
|
|
diff: computed.Diff{
|
|
Renderer: Primitive("nu\nll", nil, cty.String),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
<<-EOT
|
|
- nu
|
|
- ll
|
|
+ null
|
|
EOT
|
|
`,
|
|
},
|
|
"primitive_update_multiline_string_from_null": {
|
|
diff: computed.Diff{
|
|
Renderer: Primitive(nil, "nu\nll", cty.String),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
<<-EOT
|
|
- null
|
|
+ nu
|
|
+ ll
|
|
EOT
|
|
`,
|
|
},
|
|
"primitive_update_json_string_to_null": {
|
|
diff: computed.Diff{
|
|
Renderer: Primitive("[null]", nil, cty.String),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
jsonencode(
|
|
[
|
|
- null,
|
|
]
|
|
) -> null
|
|
`,
|
|
},
|
|
"primitive_update_json_string_from_null": {
|
|
diff: computed.Diff{
|
|
Renderer: Primitive(nil, "[null]", cty.String),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
null -> jsonencode(
|
|
[
|
|
+ null,
|
|
]
|
|
)
|
|
`,
|
|
},
|
|
"primitive_create_null_string": {
|
|
diff: computed.Diff{
|
|
Renderer: Primitive(nil, nil, cty.String),
|
|
Action: plans.Create,
|
|
},
|
|
expected: "null",
|
|
},
|
|
"primitive_delete_null_string": {
|
|
diff: computed.Diff{
|
|
Renderer: Primitive(nil, nil, cty.String),
|
|
Action: plans.Delete,
|
|
},
|
|
expected: "null",
|
|
},
|
|
"primitive_create": {
|
|
diff: computed.Diff{
|
|
Renderer: Primitive(nil, json.Number("1"), cty.Number),
|
|
Action: plans.Create,
|
|
},
|
|
expected: "1",
|
|
},
|
|
"primitive_delete": {
|
|
diff: computed.Diff{
|
|
Renderer: Primitive(json.Number("1"), nil, cty.Number),
|
|
Action: plans.Delete,
|
|
},
|
|
expected: "1 -> null",
|
|
},
|
|
"primitive_delete_override": {
|
|
diff: computed.Diff{
|
|
Renderer: Primitive(json.Number("1"), nil, cty.Number),
|
|
Action: plans.Delete,
|
|
},
|
|
opts: computed.RenderHumanOpts{OverrideNullSuffix: true},
|
|
expected: "1",
|
|
},
|
|
"primitive_update_to_null": {
|
|
diff: computed.Diff{
|
|
Renderer: Primitive(json.Number("1"), nil, cty.Number),
|
|
Action: plans.Update,
|
|
},
|
|
expected: "1 -> null",
|
|
},
|
|
"primitive_update_from_null": {
|
|
diff: computed.Diff{
|
|
Renderer: Primitive(nil, json.Number("1"), cty.Number),
|
|
Action: plans.Update,
|
|
},
|
|
expected: "null -> 1",
|
|
},
|
|
"primitive_update": {
|
|
diff: computed.Diff{
|
|
Renderer: Primitive(json.Number("0"), json.Number("1"), cty.Number),
|
|
Action: plans.Update,
|
|
},
|
|
expected: "0 -> 1",
|
|
},
|
|
"primitive_update_max_int64_to_min_int64": {
|
|
diff: computed.Diff{
|
|
// 9223372036854775807 == math.MinInt64
|
|
// -9223372036854775808 == math.MaxInt64
|
|
Renderer: Primitive(json.Number("9223372036854775807"), json.Number("-9223372036854775808"), cty.Number),
|
|
Action: plans.Update,
|
|
},
|
|
expected: "9223372036854775807 -> -9223372036854775808",
|
|
},
|
|
"primitive_update_21_digits_number": {
|
|
diff: computed.Diff{
|
|
// 18446744073709551615 == math.MaxUint64 (which has 20-digits number)
|
|
Renderer: Primitive(json.Number("918446744073709551615"), json.Number("0"), cty.Number),
|
|
Action: plans.Update,
|
|
},
|
|
expected: "918446744073709551615 -> 0",
|
|
},
|
|
"primitive_update_replace": {
|
|
diff: computed.Diff{
|
|
Renderer: Primitive(json.Number("0"), json.Number("1"), cty.Number),
|
|
Action: plans.Update,
|
|
Replace: true,
|
|
},
|
|
expected: "0 -> 1 # forces replacement",
|
|
},
|
|
"primitive_multiline_string_create": {
|
|
diff: computed.Diff{
|
|
Renderer: Primitive(nil, "hello\nworld", cty.String),
|
|
Action: plans.Create,
|
|
},
|
|
expected: `
|
|
<<-EOT
|
|
hello
|
|
world
|
|
EOT
|
|
`,
|
|
},
|
|
"primitive_multiline_string_delete": {
|
|
diff: computed.Diff{
|
|
Renderer: Primitive("hello\nworld", nil, cty.String),
|
|
Action: plans.Delete,
|
|
},
|
|
expected: `
|
|
<<-EOT
|
|
hello
|
|
world
|
|
EOT -> null
|
|
`,
|
|
},
|
|
"primitive_multiline_string_update": {
|
|
diff: computed.Diff{
|
|
Renderer: Primitive("hello\nold\nworld", "hello\nnew\nworld", cty.String),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
<<-EOT
|
|
hello
|
|
- old
|
|
+ new
|
|
world
|
|
EOT
|
|
`,
|
|
},
|
|
"primitive_json_string_create": {
|
|
diff: computed.Diff{
|
|
Renderer: Primitive(nil, "{\"key_one\": \"value_one\",\"key_two\":\"value_two\"}", cty.String),
|
|
Action: plans.Create,
|
|
},
|
|
expected: `
|
|
jsonencode(
|
|
{
|
|
+ key_one = "value_one"
|
|
+ key_two = "value_two"
|
|
}
|
|
)
|
|
`,
|
|
},
|
|
"primitive_json_string_delete": {
|
|
diff: computed.Diff{
|
|
Renderer: Primitive("{\"key_one\": \"value_one\",\"key_two\":\"value_two\"}", nil, cty.String),
|
|
Action: plans.Delete,
|
|
},
|
|
expected: `
|
|
jsonencode(
|
|
{
|
|
- key_one = "value_one"
|
|
- key_two = "value_two"
|
|
}
|
|
) -> null
|
|
`,
|
|
},
|
|
"primitive_json_string_update": {
|
|
diff: computed.Diff{
|
|
Renderer: Primitive("{\"key_one\": \"value_one\",\"key_two\":\"value_two\"}", "{\"key_one\": \"value_one\",\"key_two\":\"value_two\",\"key_three\":\"value_three\"}", cty.String),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
jsonencode(
|
|
~ {
|
|
+ key_three = "value_three"
|
|
# (2 unchanged attributes hidden)
|
|
}
|
|
)
|
|
`,
|
|
},
|
|
"primitive_json_explicit_nulls": {
|
|
diff: computed.Diff{
|
|
Renderer: Primitive("{\"key_one\":\"value_one\",\"key_two\":\"value_two\"}", "{\"key_one\":null}", cty.String),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
jsonencode(
|
|
~ {
|
|
~ key_one = "value_one" -> null
|
|
- key_two = "value_two"
|
|
}
|
|
)
|
|
`,
|
|
},
|
|
"primitive_fake_json_string_update": {
|
|
diff: computed.Diff{
|
|
// This isn't valid JSON, our renderer should be okay with it.
|
|
Renderer: Primitive("{\"key_one\": \"value_one\",\"key_two\":\"value_two\"", "{\"key_one\": \"value_one\",\"key_two\":\"value_two\",\"key_three\":\"value_three\"", cty.String),
|
|
Action: plans.Update,
|
|
},
|
|
expected: "\"{\\\"key_one\\\": \\\"value_one\\\",\\\"key_two\\\":\\\"value_two\\\"\" -> \"{\\\"key_one\\\": \\\"value_one\\\",\\\"key_two\\\":\\\"value_two\\\",\\\"key_three\\\":\\\"value_three\\\"\"",
|
|
},
|
|
"primitive_multiline_to_json_update": {
|
|
diff: computed.Diff{
|
|
Renderer: Primitive("hello\nworld", "{\"key_one\": \"value_one\",\"key_two\":\"value_two\"}", cty.String),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
<<-EOT
|
|
hello
|
|
world
|
|
EOT -> jsonencode(
|
|
{
|
|
+ key_one = "value_one"
|
|
+ key_two = "value_two"
|
|
}
|
|
)
|
|
`,
|
|
},
|
|
"primitive_json_to_multiline_update": {
|
|
diff: computed.Diff{
|
|
Renderer: Primitive("{\"key_one\": \"value_one\",\"key_two\":\"value_two\"}", "hello\nworld", cty.String),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
jsonencode(
|
|
{
|
|
- key_one = "value_one"
|
|
- key_two = "value_two"
|
|
}
|
|
) -> <<-EOT
|
|
hello
|
|
world
|
|
EOT
|
|
`,
|
|
},
|
|
"primitive_json_to_string_update": {
|
|
diff: computed.Diff{
|
|
Renderer: Primitive("{\"key_one\": \"value_one\",\"key_two\":\"value_two\"}", "hello world", cty.String),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
jsonencode(
|
|
{
|
|
- key_one = "value_one"
|
|
- key_two = "value_two"
|
|
}
|
|
) -> "hello world"
|
|
`,
|
|
},
|
|
"primitive_string_to_json_update": {
|
|
diff: computed.Diff{
|
|
Renderer: Primitive("hello world", "{\"key_one\": \"value_one\",\"key_two\":\"value_two\"}", cty.String),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
"hello world" -> jsonencode(
|
|
{
|
|
+ key_one = "value_one"
|
|
+ key_two = "value_two"
|
|
}
|
|
)
|
|
`,
|
|
},
|
|
"primitive_multi_to_single_update": {
|
|
diff: computed.Diff{
|
|
Renderer: Primitive("hello\nworld", "hello world", cty.String),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
<<-EOT
|
|
- hello
|
|
- world
|
|
+ hello world
|
|
EOT
|
|
`,
|
|
},
|
|
"primitive_single_to_multi_update": {
|
|
diff: computed.Diff{
|
|
Renderer: Primitive("hello world", "hello\nworld", cty.String),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
<<-EOT
|
|
- hello world
|
|
+ hello
|
|
+ world
|
|
EOT
|
|
`,
|
|
},
|
|
"sensitive_update": {
|
|
diff: computed.Diff{
|
|
Renderer: Sensitive(computed.Diff{
|
|
Renderer: Primitive(json.Number("0"), json.Number("1"), cty.Number),
|
|
Action: plans.Update,
|
|
}, true, true),
|
|
Action: plans.Update,
|
|
},
|
|
expected: "(sensitive value)",
|
|
},
|
|
"sensitive_update_replace": {
|
|
diff: computed.Diff{
|
|
Renderer: Sensitive(computed.Diff{
|
|
Renderer: Primitive(json.Number("0"), json.Number("1"), cty.Number),
|
|
Action: plans.Update,
|
|
Replace: true,
|
|
}, true, true),
|
|
Action: plans.Update,
|
|
Replace: true,
|
|
},
|
|
expected: "(sensitive value) # forces replacement",
|
|
},
|
|
"computed_create": {
|
|
diff: computed.Diff{
|
|
Renderer: Unknown(computed.Diff{}),
|
|
Action: plans.Create,
|
|
},
|
|
expected: "(known after apply)",
|
|
},
|
|
"computed_update": {
|
|
diff: computed.Diff{
|
|
Renderer: Unknown(computed.Diff{
|
|
Renderer: Primitive(json.Number("0"), nil, cty.Number),
|
|
Action: plans.Delete,
|
|
}),
|
|
Action: plans.Update,
|
|
},
|
|
expected: "0 -> (known after apply)",
|
|
},
|
|
"computed_create_forces_replacement": {
|
|
diff: computed.Diff{
|
|
Renderer: Unknown(computed.Diff{}),
|
|
Action: plans.Create,
|
|
Replace: true,
|
|
},
|
|
expected: "(known after apply) # forces replacement",
|
|
},
|
|
"computed_update_forces_replacement": {
|
|
diff: computed.Diff{
|
|
Renderer: Unknown(computed.Diff{
|
|
Renderer: Primitive(json.Number("0"), nil, cty.Number),
|
|
Action: plans.Delete,
|
|
}),
|
|
Action: plans.Update,
|
|
Replace: true,
|
|
},
|
|
expected: "0 -> (known after apply) # forces replacement",
|
|
},
|
|
"object_created": {
|
|
diff: computed.Diff{
|
|
Renderer: Object(map[string]computed.Diff{}),
|
|
Action: plans.Create,
|
|
},
|
|
expected: "{}",
|
|
},
|
|
"object_created_with_attributes": {
|
|
diff: computed.Diff{
|
|
Renderer: Object(map[string]computed.Diff{
|
|
"attribute_one": {
|
|
Renderer: Primitive(nil, json.Number("0"), cty.Number),
|
|
Action: plans.Create,
|
|
},
|
|
}),
|
|
Action: plans.Create,
|
|
},
|
|
expected: `
|
|
{
|
|
+ attribute_one = 0
|
|
}
|
|
`,
|
|
},
|
|
"object_deleted": {
|
|
diff: computed.Diff{
|
|
Renderer: Object(map[string]computed.Diff{}),
|
|
Action: plans.Delete,
|
|
},
|
|
expected: "{} -> null",
|
|
},
|
|
"object_deleted_with_attributes": {
|
|
diff: computed.Diff{
|
|
Renderer: Object(map[string]computed.Diff{
|
|
"attribute_one": {
|
|
Renderer: Primitive(json.Number("0"), nil, cty.Number),
|
|
Action: plans.Delete,
|
|
},
|
|
}),
|
|
Action: plans.Delete,
|
|
},
|
|
expected: `
|
|
{
|
|
- attribute_one = 0
|
|
} -> null
|
|
`,
|
|
},
|
|
"nested_object_deleted": {
|
|
diff: computed.Diff{
|
|
Renderer: NestedObject(map[string]computed.Diff{}),
|
|
Action: plans.Delete,
|
|
},
|
|
expected: "{} -> null",
|
|
},
|
|
"nested_object_deleted_with_attributes": {
|
|
diff: computed.Diff{
|
|
Renderer: NestedObject(map[string]computed.Diff{
|
|
"attribute_one": {
|
|
Renderer: Primitive(json.Number("0"), nil, cty.Number),
|
|
Action: plans.Delete,
|
|
},
|
|
}),
|
|
Action: plans.Delete,
|
|
},
|
|
expected: `
|
|
{
|
|
- attribute_one = 0 -> null
|
|
} -> null
|
|
`,
|
|
},
|
|
"object_create_attribute": {
|
|
diff: computed.Diff{
|
|
Renderer: Object(map[string]computed.Diff{
|
|
"attribute_one": {
|
|
Renderer: Primitive(nil, json.Number("0"), cty.Number),
|
|
Action: plans.Create,
|
|
},
|
|
}),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
{
|
|
+ attribute_one = 0
|
|
}
|
|
`,
|
|
},
|
|
"object_update_attribute": {
|
|
diff: computed.Diff{
|
|
Renderer: Object(map[string]computed.Diff{
|
|
"attribute_one": {
|
|
Renderer: Primitive(json.Number("0"), json.Number("1"), cty.Number),
|
|
Action: plans.Update,
|
|
},
|
|
}),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
{
|
|
~ attribute_one = 0 -> 1
|
|
}
|
|
`,
|
|
},
|
|
"object_update_attribute_forces_replacement": {
|
|
diff: computed.Diff{
|
|
Renderer: Object(map[string]computed.Diff{
|
|
"attribute_one": {
|
|
Renderer: Primitive(json.Number("0"), json.Number("1"), cty.Number),
|
|
Action: plans.Update,
|
|
},
|
|
}),
|
|
Action: plans.Update,
|
|
Replace: true,
|
|
},
|
|
expected: `
|
|
{ # forces replacement
|
|
~ attribute_one = 0 -> 1
|
|
}
|
|
`,
|
|
},
|
|
"object_delete_attribute": {
|
|
diff: computed.Diff{
|
|
Renderer: Object(map[string]computed.Diff{
|
|
"attribute_one": {
|
|
Renderer: Primitive(json.Number("0"), nil, cty.Number),
|
|
Action: plans.Delete,
|
|
},
|
|
}),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
{
|
|
- attribute_one = 0
|
|
}
|
|
`,
|
|
},
|
|
"object_ignore_unchanged_attributes": {
|
|
diff: computed.Diff{
|
|
Renderer: Object(map[string]computed.Diff{
|
|
"attribute_one": {
|
|
Renderer: Primitive(json.Number("0"), json.Number("1"), cty.Number),
|
|
Action: plans.Update,
|
|
},
|
|
"attribute_two": {
|
|
Renderer: Primitive(json.Number("0"), json.Number("0"), cty.Number),
|
|
Action: plans.NoOp,
|
|
},
|
|
"attribute_three": {
|
|
Renderer: Primitive(nil, json.Number("1"), cty.Number),
|
|
Action: plans.Create,
|
|
},
|
|
}),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
{
|
|
~ attribute_one = 0 -> 1
|
|
+ attribute_three = 1
|
|
# (1 unchanged attribute hidden)
|
|
}
|
|
`,
|
|
},
|
|
"object_create_sensitive_attribute": {
|
|
diff: computed.Diff{
|
|
Renderer: Object(map[string]computed.Diff{
|
|
"attribute_one": {
|
|
Renderer: Sensitive(computed.Diff{
|
|
Renderer: Primitive(nil, json.Number("1"), cty.Number),
|
|
Action: plans.Create,
|
|
}, false, true),
|
|
Action: plans.Create,
|
|
},
|
|
}),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
{
|
|
+ attribute_one = (sensitive value)
|
|
}
|
|
`,
|
|
},
|
|
"object_update_sensitive_attribute": {
|
|
diff: computed.Diff{
|
|
Renderer: Object(map[string]computed.Diff{
|
|
"attribute_one": {
|
|
Renderer: Sensitive(computed.Diff{
|
|
Renderer: Primitive(json.Number("0"), json.Number("1"), cty.Number),
|
|
Action: plans.Update,
|
|
}, true, true),
|
|
Action: plans.Update,
|
|
},
|
|
}),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
{
|
|
~ attribute_one = (sensitive value)
|
|
}
|
|
`,
|
|
},
|
|
"object_delete_sensitive_attribute": {
|
|
diff: computed.Diff{
|
|
Renderer: Object(map[string]computed.Diff{
|
|
"attribute_one": {
|
|
Renderer: Sensitive(computed.Diff{
|
|
Renderer: Primitive(json.Number("0"), nil, cty.Number),
|
|
Action: plans.Delete,
|
|
}, true, false),
|
|
Action: plans.Delete,
|
|
},
|
|
}),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
{
|
|
- attribute_one = (sensitive value)
|
|
}
|
|
`,
|
|
},
|
|
"object_create_computed_attribute": {
|
|
diff: computed.Diff{
|
|
Renderer: Object(map[string]computed.Diff{
|
|
"attribute_one": {
|
|
Renderer: Unknown(computed.Diff{Renderer: nil}),
|
|
Action: plans.Create,
|
|
},
|
|
}),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
{
|
|
+ attribute_one = (known after apply)
|
|
}
|
|
`,
|
|
},
|
|
"object_update_computed_attribute": {
|
|
diff: computed.Diff{
|
|
Renderer: Object(map[string]computed.Diff{
|
|
"attribute_one": {
|
|
Renderer: Unknown(computed.Diff{
|
|
Renderer: Primitive(json.Number("1"), nil, cty.Number),
|
|
Action: plans.Delete,
|
|
}),
|
|
Action: plans.Update,
|
|
},
|
|
}),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
{
|
|
~ attribute_one = 1 -> (known after apply)
|
|
}
|
|
`,
|
|
},
|
|
"object_escapes_attribute_keys": {
|
|
diff: computed.Diff{
|
|
Renderer: Object(map[string]computed.Diff{
|
|
"attribute_one": {
|
|
Renderer: Primitive(json.Number("1"), json.Number("2"), cty.Number),
|
|
Action: plans.Update,
|
|
},
|
|
"attribute:two": {
|
|
Renderer: Primitive(json.Number("2"), json.Number("3"), cty.Number),
|
|
Action: plans.Update,
|
|
},
|
|
"attribute_six": {
|
|
Renderer: Primitive(json.Number("3"), json.Number("4"), cty.Number),
|
|
Action: plans.Update,
|
|
},
|
|
}),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
{
|
|
~ "attribute:two" = 2 -> 3
|
|
~ attribute_one = 1 -> 2
|
|
~ attribute_six = 3 -> 4
|
|
}
|
|
`,
|
|
},
|
|
"map_create_empty": {
|
|
diff: computed.Diff{
|
|
Renderer: Map(map[string]computed.Diff{}),
|
|
Action: plans.Create,
|
|
},
|
|
expected: "{}",
|
|
},
|
|
"map_create": {
|
|
diff: computed.Diff{
|
|
Renderer: Map(map[string]computed.Diff{
|
|
"element_one": {
|
|
Renderer: Primitive(nil, "new", cty.String),
|
|
Action: plans.Create,
|
|
},
|
|
}),
|
|
Action: plans.Create,
|
|
},
|
|
expected: `
|
|
{
|
|
+ "element_one" = "new"
|
|
}
|
|
`,
|
|
},
|
|
"map_delete_empty": {
|
|
diff: computed.Diff{
|
|
Renderer: Map(map[string]computed.Diff{}),
|
|
Action: plans.Delete,
|
|
},
|
|
expected: "{} -> null",
|
|
},
|
|
"map_delete": {
|
|
diff: computed.Diff{
|
|
Renderer: Map(map[string]computed.Diff{
|
|
"element_one": {
|
|
Renderer: Primitive("old", nil, cty.String),
|
|
Action: plans.Delete,
|
|
},
|
|
}),
|
|
Action: plans.Delete,
|
|
},
|
|
expected: `
|
|
{
|
|
- "element_one" = "old"
|
|
} -> null
|
|
`,
|
|
},
|
|
"map_create_element": {
|
|
diff: computed.Diff{
|
|
Renderer: Map(map[string]computed.Diff{
|
|
"element_one": {
|
|
Renderer: Primitive(nil, "new", cty.String),
|
|
Action: plans.Create,
|
|
},
|
|
}),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
{
|
|
+ "element_one" = "new"
|
|
}
|
|
`,
|
|
},
|
|
"map_update_element": {
|
|
diff: computed.Diff{
|
|
Renderer: Map(map[string]computed.Diff{
|
|
"element_one": {
|
|
Renderer: Primitive("old", "new", cty.String),
|
|
Action: plans.Update,
|
|
},
|
|
}),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
{
|
|
~ "element_one" = "old" -> "new"
|
|
}
|
|
`,
|
|
},
|
|
"map_delete_element": {
|
|
diff: computed.Diff{
|
|
Renderer: Map(map[string]computed.Diff{
|
|
"element_one": {
|
|
Renderer: Primitive("old", nil, cty.String),
|
|
Action: plans.Delete,
|
|
},
|
|
}),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
{
|
|
- "element_one" = "old" -> null
|
|
}
|
|
`,
|
|
},
|
|
"map_update_forces_replacement": {
|
|
diff: computed.Diff{
|
|
Renderer: Map(map[string]computed.Diff{
|
|
"element_one": {
|
|
Renderer: Primitive("old", "new", cty.String),
|
|
Action: plans.Update,
|
|
},
|
|
}),
|
|
Action: plans.Update,
|
|
Replace: true,
|
|
},
|
|
expected: `
|
|
{ # forces replacement
|
|
~ "element_one" = "old" -> "new"
|
|
}
|
|
`,
|
|
},
|
|
"map_ignore_unchanged_elements": {
|
|
diff: computed.Diff{
|
|
Renderer: Map(map[string]computed.Diff{
|
|
"element_one": {
|
|
Renderer: Primitive(nil, "new", cty.String),
|
|
Action: plans.Create,
|
|
},
|
|
"element_two": {
|
|
Renderer: Primitive("old", "old", cty.String),
|
|
Action: plans.NoOp,
|
|
},
|
|
"element_three": {
|
|
Renderer: Primitive("old", "new", cty.String),
|
|
Action: plans.Update,
|
|
},
|
|
}),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
{
|
|
+ "element_one" = "new"
|
|
~ "element_three" = "old" -> "new"
|
|
# (1 unchanged element hidden)
|
|
}
|
|
`,
|
|
},
|
|
"map_create_sensitive_element": {
|
|
diff: computed.Diff{
|
|
Renderer: Map(map[string]computed.Diff{
|
|
"element_one": {
|
|
Renderer: Sensitive(computed.Diff{
|
|
Renderer: Primitive(nil, json.Number("1"), cty.Number),
|
|
Action: plans.Create,
|
|
}, false, true),
|
|
Action: plans.Create,
|
|
},
|
|
}),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
{
|
|
+ "element_one" = (sensitive value)
|
|
}
|
|
`,
|
|
},
|
|
"map_update_sensitive_element": {
|
|
diff: computed.Diff{
|
|
Renderer: Map(map[string]computed.Diff{
|
|
"element_one": {
|
|
Renderer: Sensitive(computed.Diff{
|
|
Renderer: Primitive(json.Number("0"), json.Number("1"), cty.Number),
|
|
Action: plans.Update,
|
|
}, true, true),
|
|
Action: plans.Update,
|
|
},
|
|
}),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
{
|
|
~ "element_one" = (sensitive value)
|
|
}
|
|
`,
|
|
},
|
|
"map_update_sensitive_element_status": {
|
|
diff: computed.Diff{
|
|
Renderer: Map(map[string]computed.Diff{
|
|
"element_one": {
|
|
Renderer: Sensitive(computed.Diff{
|
|
Renderer: Primitive(json.Number("0"), json.Number("0"), cty.Number),
|
|
Action: plans.NoOp,
|
|
}, true, false),
|
|
Action: plans.Update,
|
|
},
|
|
}),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
{
|
|
# Warning: this attribute value will no longer be marked as sensitive
|
|
# after applying this change. The value is unchanged.
|
|
~ "element_one" = (sensitive value)
|
|
}
|
|
`,
|
|
},
|
|
"map_delete_sensitive_element": {
|
|
diff: computed.Diff{
|
|
Renderer: Map(map[string]computed.Diff{
|
|
"element_one": {
|
|
Renderer: Sensitive(computed.Diff{
|
|
Renderer: Primitive(json.Number("0"), nil, cty.Number),
|
|
Action: plans.Delete,
|
|
}, true, false),
|
|
Action: plans.Delete,
|
|
},
|
|
}),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
{
|
|
- "element_one" = (sensitive value) -> null
|
|
}
|
|
`,
|
|
},
|
|
"map_create_computed_element": {
|
|
diff: computed.Diff{
|
|
Renderer: Map(map[string]computed.Diff{
|
|
"element_one": {
|
|
Renderer: Unknown(computed.Diff{}),
|
|
Action: plans.Create,
|
|
},
|
|
}),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
{
|
|
+ "element_one" = (known after apply)
|
|
}
|
|
`,
|
|
},
|
|
"map_update_computed_element": {
|
|
diff: computed.Diff{
|
|
Renderer: Map(map[string]computed.Diff{
|
|
"element_one": {
|
|
Renderer: Unknown(computed.Diff{
|
|
Renderer: Primitive(json.Number("1"), nil, cty.Number),
|
|
Action: plans.Delete,
|
|
}),
|
|
Action: plans.Update,
|
|
},
|
|
}),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
{
|
|
~ "element_one" = 1 -> (known after apply)
|
|
}
|
|
`,
|
|
},
|
|
"map_aligns_key": {
|
|
diff: computed.Diff{
|
|
Renderer: Map(map[string]computed.Diff{
|
|
"element_one": {
|
|
Renderer: Primitive(json.Number("1"), json.Number("2"), cty.Number),
|
|
Action: plans.Update,
|
|
},
|
|
"element_two": {
|
|
Renderer: Primitive(json.Number("1"), json.Number("3"), cty.Number),
|
|
Action: plans.Update,
|
|
},
|
|
"element_three": {
|
|
Renderer: Primitive(json.Number("1"), json.Number("4"), cty.Number),
|
|
Action: plans.Update,
|
|
},
|
|
}),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
{
|
|
~ "element_one" = 1 -> 2
|
|
~ "element_three" = 1 -> 4
|
|
~ "element_two" = 1 -> 3
|
|
}
|
|
`,
|
|
},
|
|
"nested_map_does_not_align_keys": {
|
|
diff: computed.Diff{
|
|
Renderer: NestedMap(map[string]computed.Diff{
|
|
"element_one": {
|
|
Renderer: Primitive(json.Number("1"), json.Number("2"), cty.Number),
|
|
Action: plans.Update,
|
|
},
|
|
"element_two": {
|
|
Renderer: Primitive(json.Number("1"), json.Number("3"), cty.Number),
|
|
Action: plans.Update,
|
|
},
|
|
"element_three": {
|
|
Renderer: Primitive(json.Number("1"), json.Number("4"), cty.Number),
|
|
Action: plans.Update,
|
|
},
|
|
}),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
{
|
|
~ "element_one" = 1 -> 2
|
|
~ "element_three" = 1 -> 4
|
|
~ "element_two" = 1 -> 3
|
|
}
|
|
`,
|
|
},
|
|
"list_create_empty": {
|
|
diff: computed.Diff{
|
|
Renderer: List([]computed.Diff{}),
|
|
Action: plans.Create,
|
|
},
|
|
expected: "[]",
|
|
},
|
|
"list_create": {
|
|
diff: computed.Diff{
|
|
Renderer: List([]computed.Diff{
|
|
{
|
|
Renderer: Primitive(nil, json.Number("1"), cty.Number),
|
|
Action: plans.Create,
|
|
},
|
|
}),
|
|
Action: plans.Create,
|
|
},
|
|
expected: `
|
|
[
|
|
+ 1,
|
|
]
|
|
`,
|
|
},
|
|
"list_delete_empty": {
|
|
diff: computed.Diff{
|
|
Renderer: List([]computed.Diff{}),
|
|
Action: plans.Delete,
|
|
},
|
|
expected: "[] -> null",
|
|
},
|
|
"list_delete": {
|
|
diff: computed.Diff{
|
|
Renderer: List([]computed.Diff{
|
|
{
|
|
Renderer: Primitive(json.Number("1"), nil, cty.Number),
|
|
Action: plans.Delete,
|
|
},
|
|
}),
|
|
Action: plans.Delete,
|
|
},
|
|
expected: `
|
|
[
|
|
- 1,
|
|
] -> null
|
|
`,
|
|
},
|
|
"list_create_element": {
|
|
diff: computed.Diff{
|
|
Renderer: List([]computed.Diff{
|
|
{
|
|
Renderer: Primitive(nil, json.Number("1"), cty.Number),
|
|
Action: plans.Create,
|
|
},
|
|
}),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
[
|
|
+ 1,
|
|
]
|
|
`,
|
|
},
|
|
"list_update_element": {
|
|
diff: computed.Diff{
|
|
Renderer: List([]computed.Diff{
|
|
{
|
|
Renderer: Primitive(json.Number("0"), json.Number("1"), cty.Number),
|
|
Action: plans.Update,
|
|
},
|
|
}),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
[
|
|
~ 0 -> 1,
|
|
]
|
|
`,
|
|
},
|
|
"list_replace_element": {
|
|
diff: computed.Diff{
|
|
Renderer: List([]computed.Diff{
|
|
{
|
|
Renderer: Primitive(json.Number("0"), nil, cty.Number),
|
|
Action: plans.Delete,
|
|
},
|
|
{
|
|
Renderer: Primitive(nil, json.Number("1"), cty.Number),
|
|
Action: plans.Create,
|
|
},
|
|
}),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
[
|
|
- 0,
|
|
+ 1,
|
|
]
|
|
`,
|
|
},
|
|
"list_delete_element": {
|
|
diff: computed.Diff{
|
|
Renderer: List([]computed.Diff{
|
|
{
|
|
Renderer: Primitive(json.Number("0"), nil, cty.Number),
|
|
Action: plans.Delete,
|
|
},
|
|
}),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
[
|
|
- 0,
|
|
]
|
|
`,
|
|
},
|
|
"list_update_forces_replacement": {
|
|
diff: computed.Diff{
|
|
Renderer: List([]computed.Diff{
|
|
{
|
|
Renderer: Primitive(json.Number("0"), json.Number("1"), cty.Number),
|
|
Action: plans.Update,
|
|
},
|
|
}),
|
|
Action: plans.Update,
|
|
Replace: true,
|
|
},
|
|
expected: `
|
|
[ # forces replacement
|
|
~ 0 -> 1,
|
|
]
|
|
`,
|
|
},
|
|
"list_update_ignores_unchanged": {
|
|
diff: computed.Diff{
|
|
Renderer: NestedList([]computed.Diff{
|
|
{
|
|
Renderer: Primitive(json.Number("0"), json.Number("0"), cty.Number),
|
|
Action: plans.NoOp,
|
|
},
|
|
{
|
|
Renderer: Primitive(json.Number("1"), json.Number("1"), cty.Number),
|
|
Action: plans.NoOp,
|
|
},
|
|
{
|
|
Renderer: Primitive(json.Number("2"), json.Number("5"), cty.Number),
|
|
Action: plans.Update,
|
|
},
|
|
{
|
|
Renderer: Primitive(json.Number("3"), json.Number("3"), cty.Number),
|
|
Action: plans.NoOp,
|
|
},
|
|
{
|
|
Renderer: Primitive(json.Number("4"), json.Number("4"), cty.Number),
|
|
Action: plans.NoOp,
|
|
},
|
|
}),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
[
|
|
~ 2 -> 5,
|
|
# (4 unchanged elements hidden)
|
|
]
|
|
`,
|
|
},
|
|
"list_update_ignored_unchanged_with_context": {
|
|
diff: computed.Diff{
|
|
Renderer: List([]computed.Diff{
|
|
{
|
|
Renderer: Primitive(json.Number("0"), json.Number("0"), cty.Number),
|
|
Action: plans.NoOp,
|
|
},
|
|
{
|
|
Renderer: Primitive(json.Number("1"), json.Number("1"), cty.Number),
|
|
Action: plans.NoOp,
|
|
},
|
|
{
|
|
Renderer: Primitive(json.Number("2"), json.Number("5"), cty.Number),
|
|
Action: plans.Update,
|
|
},
|
|
{
|
|
Renderer: Primitive(json.Number("3"), json.Number("3"), cty.Number),
|
|
Action: plans.NoOp,
|
|
},
|
|
{
|
|
Renderer: Primitive(json.Number("4"), json.Number("4"), cty.Number),
|
|
Action: plans.NoOp,
|
|
},
|
|
}),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
[
|
|
# (1 unchanged element hidden)
|
|
1,
|
|
~ 2 -> 5,
|
|
3,
|
|
# (1 unchanged element hidden)
|
|
]
|
|
`,
|
|
},
|
|
"list_create_sensitive_element": {
|
|
diff: computed.Diff{
|
|
Renderer: List([]computed.Diff{
|
|
{
|
|
Renderer: Sensitive(computed.Diff{
|
|
Renderer: Primitive(nil, json.Number("1"), cty.Number),
|
|
Action: plans.Create,
|
|
}, false, true),
|
|
Action: plans.Create,
|
|
},
|
|
}),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
[
|
|
+ (sensitive value),
|
|
]
|
|
`,
|
|
},
|
|
"list_delete_sensitive_element": {
|
|
diff: computed.Diff{
|
|
Renderer: List([]computed.Diff{
|
|
{
|
|
Renderer: Sensitive(computed.Diff{
|
|
Renderer: Primitive(json.Number("1"), nil, cty.Number),
|
|
Action: plans.Delete,
|
|
}, true, false),
|
|
Action: plans.Delete,
|
|
},
|
|
}),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
[
|
|
- (sensitive value),
|
|
]
|
|
`,
|
|
},
|
|
"list_update_sensitive_element": {
|
|
diff: computed.Diff{
|
|
Renderer: List([]computed.Diff{
|
|
{
|
|
Renderer: Sensitive(computed.Diff{
|
|
Renderer: Primitive(json.Number("0"), json.Number("1"), cty.Number),
|
|
Action: plans.Update,
|
|
}, true, true),
|
|
Action: plans.Update,
|
|
},
|
|
}),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
[
|
|
~ (sensitive value),
|
|
]
|
|
`,
|
|
},
|
|
"list_update_sensitive_element_status": {
|
|
diff: computed.Diff{
|
|
Renderer: List([]computed.Diff{
|
|
{
|
|
Renderer: Sensitive(computed.Diff{
|
|
Renderer: Primitive(json.Number("1"), json.Number("1"), cty.Number),
|
|
Action: plans.NoOp,
|
|
}, false, true),
|
|
Action: plans.Update,
|
|
},
|
|
}),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
[
|
|
# Warning: this attribute value will be marked as sensitive and will not
|
|
# display in UI output after applying this change. The value is unchanged.
|
|
~ (sensitive value),
|
|
]
|
|
`,
|
|
},
|
|
"list_create_computed_element": {
|
|
diff: computed.Diff{
|
|
Renderer: List([]computed.Diff{
|
|
{
|
|
Renderer: Unknown(computed.Diff{}),
|
|
Action: plans.Create,
|
|
},
|
|
}),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
[
|
|
+ (known after apply),
|
|
]
|
|
`,
|
|
},
|
|
"list_update_computed_element": {
|
|
diff: computed.Diff{
|
|
Renderer: List([]computed.Diff{
|
|
{
|
|
Renderer: Unknown(computed.Diff{
|
|
Renderer: Primitive(json.Number("0"), nil, cty.Number),
|
|
Action: plans.Delete,
|
|
}),
|
|
Action: plans.Update,
|
|
},
|
|
}),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
[
|
|
~ 0 -> (known after apply),
|
|
]
|
|
`,
|
|
},
|
|
"set_create_empty": {
|
|
diff: computed.Diff{
|
|
Renderer: Set([]computed.Diff{}),
|
|
Action: plans.Create,
|
|
},
|
|
expected: "[]",
|
|
},
|
|
"set_create": {
|
|
diff: computed.Diff{
|
|
Renderer: Set([]computed.Diff{
|
|
{
|
|
Renderer: Primitive(nil, json.Number("1"), cty.Number),
|
|
Action: plans.Create,
|
|
},
|
|
}),
|
|
Action: plans.Create,
|
|
},
|
|
expected: `
|
|
[
|
|
+ 1,
|
|
]
|
|
`,
|
|
},
|
|
"set_delete_empty": {
|
|
diff: computed.Diff{
|
|
Renderer: Set([]computed.Diff{}),
|
|
Action: plans.Delete,
|
|
},
|
|
expected: "[] -> null",
|
|
},
|
|
"set_delete": {
|
|
diff: computed.Diff{
|
|
Renderer: Set([]computed.Diff{
|
|
{
|
|
Renderer: Primitive(json.Number("1"), nil, cty.Number),
|
|
Action: plans.Delete,
|
|
},
|
|
}),
|
|
Action: plans.Delete,
|
|
},
|
|
expected: `
|
|
[
|
|
- 1,
|
|
] -> null
|
|
`,
|
|
},
|
|
"set_create_element": {
|
|
diff: computed.Diff{
|
|
Renderer: Set([]computed.Diff{
|
|
{
|
|
Renderer: Primitive(nil, json.Number("1"), cty.Number),
|
|
Action: plans.Create,
|
|
},
|
|
}),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
[
|
|
+ 1,
|
|
]
|
|
`,
|
|
},
|
|
"set_update_element": {
|
|
diff: computed.Diff{
|
|
Renderer: Set([]computed.Diff{
|
|
{
|
|
Renderer: Primitive(json.Number("0"), json.Number("1"), cty.Number),
|
|
Action: plans.Update,
|
|
},
|
|
}),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
[
|
|
~ 0 -> 1,
|
|
]
|
|
`,
|
|
},
|
|
"set_replace_element": {
|
|
diff: computed.Diff{
|
|
Renderer: Set([]computed.Diff{
|
|
{
|
|
Renderer: Primitive(json.Number("0"), nil, cty.Number),
|
|
Action: plans.Delete,
|
|
},
|
|
{
|
|
Renderer: Primitive(nil, json.Number("1"), cty.Number),
|
|
Action: plans.Create,
|
|
},
|
|
}),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
[
|
|
- 0,
|
|
+ 1,
|
|
]
|
|
`,
|
|
},
|
|
"set_delete_element": {
|
|
diff: computed.Diff{
|
|
Renderer: Set([]computed.Diff{
|
|
{
|
|
Renderer: Primitive(json.Number("0"), nil, cty.Number),
|
|
Action: plans.Delete,
|
|
},
|
|
}),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
[
|
|
- 0,
|
|
]
|
|
`,
|
|
},
|
|
"set_update_forces_replacement": {
|
|
diff: computed.Diff{
|
|
Renderer: Set([]computed.Diff{
|
|
{
|
|
Renderer: Primitive(json.Number("0"), json.Number("1"), cty.Number),
|
|
Action: plans.Update,
|
|
},
|
|
}),
|
|
Action: plans.Update,
|
|
Replace: true,
|
|
},
|
|
expected: `
|
|
[ # forces replacement
|
|
~ 0 -> 1,
|
|
]
|
|
`,
|
|
},
|
|
"nested_set_update_forces_replacement": {
|
|
diff: computed.Diff{
|
|
Renderer: NestedSet([]computed.Diff{
|
|
{
|
|
Renderer: Object(map[string]computed.Diff{
|
|
"attribute_one": {
|
|
Renderer: Primitive(json.Number("0"), json.Number("1"), cty.Number),
|
|
Action: plans.Update,
|
|
},
|
|
}),
|
|
Action: plans.Update,
|
|
},
|
|
}),
|
|
Action: plans.Update,
|
|
Replace: true,
|
|
},
|
|
expected: `
|
|
[
|
|
~ { # forces replacement
|
|
~ attribute_one = 0 -> 1
|
|
},
|
|
]
|
|
`,
|
|
},
|
|
"set_update_ignores_unchanged": {
|
|
diff: computed.Diff{
|
|
Renderer: Set([]computed.Diff{
|
|
{
|
|
Renderer: Primitive(json.Number("0"), json.Number("0"), cty.Number),
|
|
Action: plans.NoOp,
|
|
},
|
|
{
|
|
Renderer: Primitive(json.Number("1"), json.Number("1"), cty.Number),
|
|
Action: plans.NoOp,
|
|
},
|
|
{
|
|
Renderer: Primitive(json.Number("2"), json.Number("5"), cty.Number),
|
|
Action: plans.Update,
|
|
},
|
|
{
|
|
Renderer: Primitive(json.Number("3"), json.Number("3"), cty.Number),
|
|
Action: plans.NoOp,
|
|
},
|
|
{
|
|
Renderer: Primitive(json.Number("4"), json.Number("4"), cty.Number),
|
|
Action: plans.NoOp,
|
|
},
|
|
}),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
[
|
|
~ 2 -> 5,
|
|
# (4 unchanged elements hidden)
|
|
]
|
|
`,
|
|
},
|
|
"set_create_sensitive_element": {
|
|
diff: computed.Diff{
|
|
Renderer: Set([]computed.Diff{
|
|
{
|
|
Renderer: Sensitive(computed.Diff{
|
|
Renderer: Primitive(nil, json.Number("1"), cty.Number),
|
|
Action: plans.Create,
|
|
}, false, true),
|
|
Action: plans.Create,
|
|
},
|
|
}),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
[
|
|
+ (sensitive value),
|
|
]
|
|
`,
|
|
},
|
|
"set_delete_sensitive_element": {
|
|
diff: computed.Diff{
|
|
Renderer: Set([]computed.Diff{
|
|
{
|
|
Renderer: Sensitive(computed.Diff{
|
|
Renderer: Primitive(json.Number("1"), nil, cty.Number),
|
|
Action: plans.Delete,
|
|
}, false, true),
|
|
Action: plans.Delete,
|
|
},
|
|
}),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
[
|
|
- (sensitive value),
|
|
]
|
|
`,
|
|
},
|
|
"set_update_sensitive_element": {
|
|
diff: computed.Diff{
|
|
Renderer: Set([]computed.Diff{
|
|
{
|
|
Renderer: Sensitive(computed.Diff{
|
|
Renderer: Primitive(json.Number("0"), json.Number("1"), cty.Number),
|
|
Action: plans.Update,
|
|
}, true, true),
|
|
Action: plans.Update,
|
|
},
|
|
}),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
[
|
|
~ (sensitive value),
|
|
]
|
|
`,
|
|
},
|
|
"set_update_sensitive_element_status": {
|
|
diff: computed.Diff{
|
|
Renderer: Set([]computed.Diff{
|
|
{
|
|
Renderer: Sensitive(computed.Diff{
|
|
Renderer: Primitive(json.Number("1"), json.Number("2"), cty.Number),
|
|
Action: plans.Update,
|
|
}, false, true),
|
|
Action: plans.Update,
|
|
},
|
|
}),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
[
|
|
# Warning: this attribute value will be marked as sensitive and will not
|
|
# display in UI output after applying this change.
|
|
~ (sensitive value),
|
|
]
|
|
`,
|
|
},
|
|
"set_create_computed_element": {
|
|
diff: computed.Diff{
|
|
Renderer: Set([]computed.Diff{
|
|
{
|
|
Renderer: Unknown(computed.Diff{}),
|
|
Action: plans.Create,
|
|
},
|
|
}),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
[
|
|
+ (known after apply),
|
|
]
|
|
`,
|
|
},
|
|
"set_update_computed_element": {
|
|
diff: computed.Diff{
|
|
Renderer: Set([]computed.Diff{
|
|
{
|
|
Renderer: Unknown(computed.Diff{
|
|
Renderer: Primitive(json.Number("0"), nil, cty.Number),
|
|
Action: plans.Delete,
|
|
}),
|
|
Action: plans.Update,
|
|
},
|
|
}),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
[
|
|
~ 0 -> (known after apply),
|
|
]
|
|
`,
|
|
},
|
|
"create_empty_block": {
|
|
diff: computed.Diff{
|
|
Renderer: Block(nil, Blocks{}),
|
|
Action: plans.Create,
|
|
},
|
|
expected: "{}",
|
|
},
|
|
"create_populated_block": {
|
|
diff: computed.Diff{
|
|
Renderer: Block(map[string]computed.Diff{
|
|
"string": {
|
|
Renderer: Primitive(nil, "root", cty.String),
|
|
Action: plans.Create,
|
|
},
|
|
"boolean": {
|
|
Renderer: Primitive(nil, true, cty.Bool),
|
|
Action: plans.Create,
|
|
},
|
|
}, Blocks{
|
|
SingleBlocks: map[string]computed.Diff{
|
|
"nested_block": {
|
|
Renderer: Block(map[string]computed.Diff{
|
|
"string": {
|
|
Renderer: Primitive(nil, "one", cty.String),
|
|
Action: plans.Create,
|
|
},
|
|
}, Blocks{}),
|
|
Action: plans.Create,
|
|
},
|
|
"nested_block_two": {
|
|
Renderer: Block(map[string]computed.Diff{
|
|
"string": {
|
|
Renderer: Primitive(nil, "two", cty.String),
|
|
Action: plans.Create,
|
|
},
|
|
}, Blocks{}),
|
|
Action: plans.Create,
|
|
},
|
|
},
|
|
}),
|
|
Action: plans.Create,
|
|
},
|
|
expected: `
|
|
{
|
|
+ boolean = true
|
|
+ string = "root"
|
|
|
|
+ nested_block {
|
|
+ string = "one"
|
|
}
|
|
|
|
+ nested_block_two {
|
|
+ string = "two"
|
|
}
|
|
}`,
|
|
},
|
|
"update_empty_block": {
|
|
diff: computed.Diff{
|
|
Renderer: Block(map[string]computed.Diff{
|
|
"string": {
|
|
Renderer: Primitive(nil, "root", cty.String),
|
|
Action: plans.Create,
|
|
},
|
|
"boolean": {
|
|
Renderer: Primitive(nil, true, cty.Bool),
|
|
Action: plans.Create,
|
|
},
|
|
}, Blocks{
|
|
SingleBlocks: map[string]computed.Diff{
|
|
"nested_block": {
|
|
|
|
Renderer: Block(map[string]computed.Diff{
|
|
"string": {
|
|
Renderer: Primitive(nil, "one", cty.String),
|
|
Action: plans.Create,
|
|
},
|
|
}, Blocks{}),
|
|
Action: plans.Create,
|
|
},
|
|
"nested_block_two": {
|
|
|
|
Renderer: Block(map[string]computed.Diff{
|
|
"string": {
|
|
Renderer: Primitive(nil, "two", cty.String),
|
|
Action: plans.Create,
|
|
},
|
|
}, Blocks{}),
|
|
Action: plans.Create,
|
|
},
|
|
},
|
|
}),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
{
|
|
+ boolean = true
|
|
+ string = "root"
|
|
|
|
+ nested_block {
|
|
+ string = "one"
|
|
}
|
|
|
|
+ nested_block_two {
|
|
+ string = "two"
|
|
}
|
|
}`,
|
|
},
|
|
"update_populated_block": {
|
|
diff: computed.Diff{
|
|
Renderer: Block(map[string]computed.Diff{
|
|
"string": {
|
|
Renderer: Primitive(nil, "root", cty.String),
|
|
Action: plans.Create,
|
|
},
|
|
"boolean": {
|
|
Renderer: Primitive(false, true, cty.Bool),
|
|
Action: plans.Update,
|
|
},
|
|
}, Blocks{
|
|
SingleBlocks: map[string]computed.Diff{
|
|
"nested_block": {
|
|
Renderer: Block(map[string]computed.Diff{
|
|
"string": {
|
|
Renderer: Primitive(nil, "one", cty.String),
|
|
Action: plans.NoOp,
|
|
},
|
|
}, Blocks{}),
|
|
Action: plans.NoOp,
|
|
},
|
|
"nested_block_two": {
|
|
Renderer: Block(map[string]computed.Diff{
|
|
"string": {
|
|
Renderer: Primitive(nil, "two", cty.String),
|
|
Action: plans.Create,
|
|
},
|
|
}, Blocks{}),
|
|
Action: plans.Create,
|
|
},
|
|
},
|
|
}),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
{
|
|
~ boolean = false -> true
|
|
+ string = "root"
|
|
|
|
+ nested_block_two {
|
|
+ string = "two"
|
|
}
|
|
|
|
# (1 unchanged block hidden)
|
|
}`,
|
|
},
|
|
"clear_populated_block": {
|
|
diff: computed.Diff{
|
|
Renderer: Block(map[string]computed.Diff{
|
|
"string": {
|
|
Renderer: Primitive("root", nil, cty.String),
|
|
Action: plans.Delete,
|
|
},
|
|
"boolean": {
|
|
Renderer: Primitive(true, nil, cty.Bool),
|
|
Action: plans.Delete,
|
|
},
|
|
}, Blocks{
|
|
SingleBlocks: map[string]computed.Diff{
|
|
"nested_block": {
|
|
Renderer: Block(map[string]computed.Diff{
|
|
"string": {
|
|
Renderer: Primitive("one", nil, cty.String),
|
|
Action: plans.Delete,
|
|
},
|
|
}, Blocks{}),
|
|
Action: plans.Delete,
|
|
},
|
|
"nested_block_two": {
|
|
Renderer: Block(map[string]computed.Diff{
|
|
"string": {
|
|
Renderer: Primitive("two", nil, cty.String),
|
|
Action: plans.Delete,
|
|
},
|
|
}, Blocks{}),
|
|
Action: plans.Delete,
|
|
},
|
|
},
|
|
}),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
{
|
|
- boolean = true -> null
|
|
- string = "root" -> null
|
|
|
|
- nested_block {
|
|
- string = "one" -> null
|
|
}
|
|
|
|
- nested_block_two {
|
|
- string = "two" -> null
|
|
}
|
|
}`,
|
|
},
|
|
"delete_populated_block": {
|
|
diff: computed.Diff{
|
|
Renderer: Block(map[string]computed.Diff{
|
|
"string": {
|
|
Renderer: Primitive("root", nil, cty.String),
|
|
Action: plans.Delete,
|
|
},
|
|
"boolean": {
|
|
Renderer: Primitive(true, nil, cty.Bool),
|
|
Action: plans.Delete,
|
|
},
|
|
}, Blocks{
|
|
SingleBlocks: map[string]computed.Diff{
|
|
"nested_block": {
|
|
Renderer: Block(map[string]computed.Diff{
|
|
"string": {
|
|
Renderer: Primitive("one", nil, cty.String),
|
|
Action: plans.Delete,
|
|
},
|
|
}, Blocks{}),
|
|
Action: plans.Delete,
|
|
},
|
|
"nested_block_two": {
|
|
Renderer: Block(map[string]computed.Diff{
|
|
"string": {
|
|
Renderer: Primitive("two", nil, cty.String),
|
|
Action: plans.Delete,
|
|
},
|
|
}, Blocks{}),
|
|
Action: plans.Delete,
|
|
},
|
|
},
|
|
}),
|
|
Action: plans.Delete,
|
|
},
|
|
expected: `
|
|
{
|
|
- boolean = true -> null
|
|
- string = "root" -> null
|
|
|
|
- nested_block {
|
|
- string = "one" -> null
|
|
}
|
|
|
|
- nested_block_two {
|
|
- string = "two" -> null
|
|
}
|
|
}`,
|
|
},
|
|
"list_block_update": {
|
|
diff: computed.Diff{
|
|
Renderer: Block(
|
|
nil,
|
|
Blocks{
|
|
ListBlocks: map[string][]computed.Diff{
|
|
"list_blocks": {
|
|
{
|
|
Renderer: Block(map[string]computed.Diff{
|
|
"number": {
|
|
Renderer: Primitive(json.Number("1"), json.Number("2"), cty.Number),
|
|
Action: plans.Update,
|
|
},
|
|
"string": {
|
|
Renderer: Primitive(nil, "new", cty.String),
|
|
Action: plans.Create,
|
|
},
|
|
}, Blocks{}),
|
|
Action: plans.Update,
|
|
},
|
|
{
|
|
Renderer: Block(map[string]computed.Diff{
|
|
"number": {
|
|
Renderer: Primitive(json.Number("1"), nil, cty.Number),
|
|
Action: plans.Delete,
|
|
},
|
|
"string": {
|
|
Renderer: Primitive("old", "new", cty.String),
|
|
Action: plans.Update,
|
|
},
|
|
}, Blocks{}),
|
|
Action: plans.Update,
|
|
},
|
|
},
|
|
},
|
|
}),
|
|
},
|
|
expected: `
|
|
{
|
|
~ list_blocks {
|
|
~ number = 1 -> 2
|
|
+ string = "new"
|
|
}
|
|
~ list_blocks {
|
|
- number = 1 -> null
|
|
~ string = "old" -> "new"
|
|
}
|
|
}`,
|
|
},
|
|
"set_block_update": {
|
|
diff: computed.Diff{
|
|
Renderer: Block(
|
|
nil,
|
|
Blocks{
|
|
SetBlocks: map[string][]computed.Diff{
|
|
"set_blocks": {
|
|
{
|
|
Renderer: Block(map[string]computed.Diff{
|
|
"number": {
|
|
Renderer: Primitive(json.Number("1"), json.Number("2"), cty.Number),
|
|
Action: plans.Update,
|
|
},
|
|
"string": {
|
|
Renderer: Primitive(nil, "new", cty.String),
|
|
Action: plans.Create,
|
|
},
|
|
}, Blocks{}),
|
|
Action: plans.Update,
|
|
},
|
|
{
|
|
Renderer: Block(map[string]computed.Diff{
|
|
"number": {
|
|
Renderer: Primitive(json.Number("1"), nil, cty.Number),
|
|
Action: plans.Delete,
|
|
},
|
|
"string": {
|
|
Renderer: Primitive("old", "new", cty.String),
|
|
Action: plans.Update,
|
|
},
|
|
}, Blocks{}),
|
|
Action: plans.Update,
|
|
},
|
|
},
|
|
},
|
|
}),
|
|
},
|
|
expected: `
|
|
{
|
|
~ set_blocks {
|
|
~ number = 1 -> 2
|
|
+ string = "new"
|
|
}
|
|
~ set_blocks {
|
|
- number = 1 -> null
|
|
~ string = "old" -> "new"
|
|
}
|
|
}`,
|
|
},
|
|
"set_block_override_replacement": {
|
|
diff: computed.Diff{
|
|
Renderer: Block(
|
|
nil,
|
|
Blocks{
|
|
SetBlocks: map[string][]computed.Diff{
|
|
"set_blocks": {
|
|
{
|
|
Renderer: Block(map[string]computed.Diff{
|
|
"number": {
|
|
Renderer: Primitive(json.Number("1"), json.Number("2"), cty.Number),
|
|
Action: plans.Update,
|
|
},
|
|
"string": {
|
|
Renderer: Primitive(nil, "new", cty.String),
|
|
Action: plans.Create,
|
|
},
|
|
}, Blocks{}),
|
|
Action: plans.Update,
|
|
},
|
|
{
|
|
Renderer: Block(map[string]computed.Diff{
|
|
"number": {
|
|
Renderer: Primitive(json.Number("1"), nil, cty.Number),
|
|
Action: plans.Delete,
|
|
},
|
|
"string": {
|
|
Renderer: Primitive("old", "new", cty.String),
|
|
Action: plans.Update,
|
|
},
|
|
}, Blocks{}),
|
|
Action: plans.Update,
|
|
},
|
|
},
|
|
},
|
|
}),
|
|
Replace: true,
|
|
},
|
|
expected: `
|
|
{ # forces replacement
|
|
~ set_blocks {
|
|
~ number = 1 -> 2
|
|
+ string = "new"
|
|
}
|
|
~ set_blocks {
|
|
- number = 1 -> null
|
|
~ string = "old" -> "new"
|
|
}
|
|
}`,
|
|
},
|
|
"map_block_update": {
|
|
diff: computed.Diff{
|
|
Renderer: Block(
|
|
nil,
|
|
Blocks{
|
|
MapBlocks: map[string]map[string]computed.Diff{
|
|
"list_blocks": {
|
|
"key_one": {
|
|
Renderer: Block(map[string]computed.Diff{
|
|
"number": {
|
|
Renderer: Primitive(json.Number("1"), json.Number("2"), cty.Number),
|
|
Action: plans.Update,
|
|
},
|
|
"string": {
|
|
Renderer: Primitive(nil, "new", cty.String),
|
|
Action: plans.Create,
|
|
},
|
|
}, Blocks{}),
|
|
Action: plans.Update,
|
|
},
|
|
"key:two": {
|
|
Renderer: Block(map[string]computed.Diff{
|
|
"number": {
|
|
Renderer: Primitive(json.Number("1"), nil, cty.Number),
|
|
Action: plans.Delete,
|
|
},
|
|
"string": {
|
|
Renderer: Primitive("old", "new", cty.String),
|
|
Action: plans.Update,
|
|
},
|
|
}, Blocks{}),
|
|
Action: plans.Update,
|
|
},
|
|
},
|
|
},
|
|
}),
|
|
},
|
|
expected: `
|
|
{
|
|
~ list_blocks "key:two" {
|
|
- number = 1 -> null
|
|
~ string = "old" -> "new"
|
|
}
|
|
~ list_blocks "key_one" {
|
|
~ number = 1 -> 2
|
|
+ string = "new"
|
|
}
|
|
}
|
|
`,
|
|
},
|
|
"sensitive_block": {
|
|
diff: computed.Diff{
|
|
Renderer: SensitiveBlock(computed.Diff{
|
|
Renderer: Block(nil, Blocks{}),
|
|
Action: plans.NoOp,
|
|
}, true, true),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
{
|
|
# At least one attribute in this block is (or was) sensitive,
|
|
# so its contents will not be displayed.
|
|
}
|
|
`,
|
|
},
|
|
"delete_empty_block": {
|
|
diff: computed.Diff{
|
|
Renderer: Block(nil, Blocks{}),
|
|
Action: plans.Delete,
|
|
},
|
|
expected: "{}",
|
|
},
|
|
"block_escapes_keys": {
|
|
diff: computed.Diff{
|
|
Renderer: Block(map[string]computed.Diff{
|
|
"attribute_one": {
|
|
Renderer: Primitive(json.Number("1"), json.Number("2"), cty.Number),
|
|
Action: plans.Update,
|
|
},
|
|
"attribute:two": {
|
|
Renderer: Primitive(json.Number("2"), json.Number("3"), cty.Number),
|
|
Action: plans.Update,
|
|
},
|
|
"attribute_six": {
|
|
Renderer: Primitive(json.Number("3"), json.Number("4"), cty.Number),
|
|
Action: plans.Update,
|
|
},
|
|
}, Blocks{
|
|
SingleBlocks: map[string]computed.Diff{
|
|
"nested_block:one": {
|
|
Renderer: Block(map[string]computed.Diff{
|
|
"string": {
|
|
Renderer: Primitive("one", "four", cty.String),
|
|
Action: plans.Update,
|
|
},
|
|
}, Blocks{}),
|
|
Action: plans.Update,
|
|
},
|
|
"nested_block_two": {
|
|
Renderer: Block(map[string]computed.Diff{
|
|
"string": {
|
|
Renderer: Primitive("two", "three", cty.String),
|
|
Action: plans.Update,
|
|
},
|
|
}, Blocks{}),
|
|
Action: plans.Update,
|
|
},
|
|
},
|
|
}),
|
|
Action: plans.Update,
|
|
},
|
|
expected: `
|
|
{
|
|
~ "attribute:two" = 2 -> 3
|
|
~ attribute_one = 1 -> 2
|
|
~ attribute_six = 3 -> 4
|
|
|
|
~ "nested_block:one" {
|
|
~ string = "one" -> "four"
|
|
}
|
|
|
|
~ nested_block_two {
|
|
~ string = "two" -> "three"
|
|
}
|
|
}`,
|
|
},
|
|
"block_always_includes_important_attributes": {
|
|
diff: computed.Diff{
|
|
Renderer: Block(map[string]computed.Diff{
|
|
"id": {
|
|
Renderer: Primitive("root", "root", cty.String),
|
|
Action: plans.NoOp,
|
|
},
|
|
"boolean": {
|
|
Renderer: Primitive(false, false, cty.Bool),
|
|
Action: plans.NoOp,
|
|
},
|
|
}, Blocks{
|
|
SingleBlocks: map[string]computed.Diff{
|
|
"nested_block": {
|
|
Renderer: Block(map[string]computed.Diff{
|
|
"string": {
|
|
Renderer: Primitive("one", "one", cty.String),
|
|
Action: plans.NoOp,
|
|
},
|
|
}, Blocks{}),
|
|
Action: plans.NoOp,
|
|
},
|
|
"nested_block_two": {
|
|
Renderer: Block(map[string]computed.Diff{
|
|
"string": {
|
|
Renderer: Primitive("two", "two", cty.String),
|
|
Action: plans.NoOp,
|
|
},
|
|
}, Blocks{}),
|
|
Action: plans.NoOp,
|
|
},
|
|
},
|
|
}),
|
|
Action: plans.NoOp,
|
|
},
|
|
expected: `
|
|
{
|
|
id = "root"
|
|
# (1 unchanged attribute hidden)
|
|
|
|
# (2 unchanged blocks hidden)
|
|
}`,
|
|
},
|
|
"output_map_to_list": {
|
|
diff: computed.Diff{
|
|
Renderer: TypeChange(computed.Diff{
|
|
Renderer: Map(map[string]computed.Diff{
|
|
"element_one": {
|
|
Renderer: Primitive(json.Number("0"), nil, cty.Number),
|
|
Action: plans.Delete,
|
|
},
|
|
"element_two": {
|
|
Renderer: Primitive(json.Number("1"), nil, cty.Number),
|
|
Action: plans.Delete,
|
|
},
|
|
}),
|
|
Action: plans.Delete,
|
|
}, computed.Diff{
|
|
Renderer: List([]computed.Diff{
|
|
{
|
|
Renderer: Primitive(nil, json.Number("0"), cty.Number),
|
|
Action: plans.Create,
|
|
},
|
|
{
|
|
Renderer: Primitive(nil, json.Number("1"), cty.Number),
|
|
Action: plans.Create,
|
|
},
|
|
}),
|
|
Action: plans.Create,
|
|
}),
|
|
},
|
|
expected: `
|
|
{
|
|
- "element_one" = 0
|
|
- "element_two" = 1
|
|
} -> [
|
|
+ 0,
|
|
+ 1,
|
|
]
|
|
`,
|
|
},
|
|
"json_string_no_symbols": {
|
|
diff: computed.Diff{
|
|
Renderer: Primitive("{\"key\":\"value\"}", "{\"key\":\"value\"}", cty.String),
|
|
Action: plans.NoOp,
|
|
},
|
|
opts: computed.RenderHumanOpts{
|
|
HideDiffActionSymbols: true,
|
|
ShowUnchangedChildren: true,
|
|
},
|
|
expected: `
|
|
jsonencode(
|
|
{
|
|
key = "value"
|
|
}
|
|
)
|
|
`,
|
|
},
|
|
}
|
|
for name, tc := range tcs {
|
|
t.Run(name, func(t *testing.T) {
|
|
|
|
opts := tc.opts.Clone()
|
|
opts.Colorize = &colorize
|
|
|
|
expected := strings.TrimSpace(tc.expected)
|
|
actual := tc.diff.RenderHuman(0, opts)
|
|
if diff := cmp.Diff(expected, actual); len(diff) > 0 {
|
|
t.Fatalf("\nexpected:\n%s\nactual:\n%s\ndiff:\n%s\n", expected, actual, diff)
|
|
}
|
|
})
|
|
}
|
|
}
|