// Copyright (c) The OpenTofu Authors // SPDX-License-Identifier: MPL-2.0 // Copyright (c) 2023 HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package json import ( "encoding/json" "testing" "github.com/google/go-cmp/cmp" "github.com/opentofu/opentofu/internal/addrs" "github.com/opentofu/opentofu/internal/command/jsonentities" "github.com/opentofu/opentofu/internal/lang/marks" "github.com/opentofu/opentofu/internal/plans" "github.com/opentofu/opentofu/internal/states" "github.com/zclconf/go-cty/cty" ) func TestOutputsFromMap(t *testing.T) { got, diags := OutputsFromMap(map[string]*states.OutputValue{ // Normal non-sensitive output "boop": { Value: cty.NumberIntVal(1234), }, // Sensitive string output "beep": { Value: cty.StringVal("horse-battery").Mark(marks.Sensitive), Sensitive: true, }, // Sensitive object output which is marked at the leaf "blorp": { Value: cty.ObjectVal(map[string]cty.Value{ "a": cty.ObjectVal(map[string]cty.Value{ "b": cty.ObjectVal(map[string]cty.Value{ "c": cty.StringVal("oh, hi").Mark(marks.Sensitive), }), }), }), Sensitive: true, }, // Null value "honk": { Value: cty.NullVal(cty.Map(cty.Bool)), }, // Deprecated string output "bloompypoo": { // DeprecationCause is irrelevant for this test Value: marks.Deprecated(cty.NumberIntVal(1234), marks.DeprecationCause{}), Deprecated: "deprecated", }, }) if len(diags) > 0 { t.Fatal(diags.Err()) } want := jsonentities.Outputs{ "boop": { Sensitive: false, Type: json.RawMessage(`"number"`), Value: json.RawMessage(`1234`), }, "beep": { Sensitive: true, Type: json.RawMessage(`"string"`), }, "blorp": { Sensitive: true, Type: json.RawMessage(`["object",{"a":["object",{"b":["object",{"c":"string"}]}]}]`), }, "honk": { Sensitive: false, Type: json.RawMessage(`["map","bool"]`), Value: json.RawMessage(`null`), }, "bloompypoo": { Sensitive: false, Type: json.RawMessage(`"number"`), Value: json.RawMessage(`1234`), Deprecated: "deprecated", }, } if !cmp.Equal(want, got) { t.Fatalf("unexpected result\n%s", cmp.Diff(want, got)) } } func TestOutputsFromChanges(t *testing.T) { root := addrs.RootModuleInstance num, err := plans.NewDynamicValue(cty.NumberIntVal(1234), cty.Number) if err != nil { t.Fatalf("unexpected error creating dynamic value: %v", err) } str, err := plans.NewDynamicValue(cty.StringVal("1234"), cty.String) if err != nil { t.Fatalf("unexpected error creating dynamic value: %v", err) } got := OutputsFromChanges([]*plans.OutputChangeSrc{ // Unchanged output "boop", value 1234 { Addr: root.OutputValue("boop"), ChangeSrc: plans.ChangeSrc{ Action: plans.NoOp, Before: num, After: num, }, Sensitive: false, }, // New output "beep", value 1234 { Addr: root.OutputValue("beep"), ChangeSrc: plans.ChangeSrc{ Action: plans.Create, Before: nil, After: num, }, Sensitive: false, }, // Deleted output "blorp", prior value 1234 { Addr: root.OutputValue("blorp"), ChangeSrc: plans.ChangeSrc{ Action: plans.Delete, Before: num, After: nil, }, Sensitive: false, }, // Updated output "honk", prior value 1234, new value "1234" { Addr: root.OutputValue("honk"), ChangeSrc: plans.ChangeSrc{ Action: plans.Update, Before: num, After: str, }, Sensitive: false, }, // New sensitive output "secret", value "1234" { Addr: root.OutputValue("secret"), ChangeSrc: plans.ChangeSrc{ Action: plans.Create, Before: nil, After: str, }, Sensitive: true, }, }) want := jsonentities.Outputs{ "boop": { Action: "noop", Sensitive: false, }, "beep": { Action: "create", Sensitive: false, }, "blorp": { Action: "delete", Sensitive: false, }, "honk": { Action: "update", Sensitive: false, }, "secret": { Action: "create", Sensitive: true, }, } if !cmp.Equal(want, got) { t.Fatalf("unexpected result\n%s", cmp.Diff(want, got)) } } func TestOutputs_String(t *testing.T) { outputs := jsonentities.Outputs{ "boop": { Sensitive: false, Type: json.RawMessage(`"number"`), Value: json.RawMessage(`1234`), }, "beep": { Sensitive: true, Type: json.RawMessage(`"string"`), Value: json.RawMessage(`"horse-battery"`), }, } if got, want := outputs.String(), "Outputs: 2"; got != want { t.Fatalf("unexpected value\n got: %q\nwant: %q", got, want) } }