diff --git a/pkg/internal/tests/cross-tests/diff_check.go b/pkg/internal/tests/cross-tests/diff_check.go index 7a7972c01..553352acc 100644 --- a/pkg/internal/tests/cross-tests/diff_check.go +++ b/pkg/internal/tests/cross-tests/diff_check.go @@ -59,7 +59,11 @@ func runDiffCheck(t T, tc diffTestCase) crosstestsimpl.DiffResult { resMap := map[string]*schema.Resource{defRtype: tc.Resource} tfp := &schema.Provider{ResourcesMap: resMap} - bridgedProvider := pulcheck.BridgedProvider(t, defProviderShortName, tfp, pulcheck.EnableAccurateBridgePreviews()) + opts := []pulcheck.BridgedProviderOpt{} + if os.Getenv("PULUMI_TF_BRIDGE_ACCURATE_BRIDGE_PREVIEW") != "false" { + opts = append(opts, pulcheck.EnableAccurateBridgePreviews()) + } + bridgedProvider := pulcheck.BridgedProvider(t, defProviderShortName, tfp, opts...) if tc.DeleteBeforeReplace { bridgedProvider.Resources[defRtype].DeleteBeforeReplace = true } diff --git a/pkg/internal/tests/cross-tests/diff_cross_test.go b/pkg/internal/tests/cross-tests/diff_cross_test.go index 1391df0f5..2427b737b 100644 --- a/pkg/internal/tests/cross-tests/diff_cross_test.go +++ b/pkg/internal/tests/cross-tests/diff_cross_test.go @@ -20,6 +20,7 @@ import ( "fmt" "hash/crc32" "slices" + "strconv" "strings" "testing" @@ -1625,6 +1626,14 @@ func TestBlockCollectionElementForceNew(t *testing.T) { }) } +type diffTestOutput struct { + initialValue cty.Value + changeValue cty.Value + tfOut string + pulumiOut string + detailedDiff map[string]any +} + func TestDetailedDiffReplacementComputedProperty(t *testing.T) { t.Parallel() // TODO[pulumi/pulumi-terraform-bridge#2660] @@ -1650,14 +1659,6 @@ func TestDetailedDiffReplacementComputedProperty(t *testing.T) { }, } - type testOutput struct { - initialValue cty.Value - changeValue cty.Value - tfOut string - pulumiOut string - detailedDiff map[string]any - } - t.Run("no change", func(t *testing.T) { t.Parallel() initialValue := cty.ObjectVal(map[string]cty.Value{}) @@ -1668,7 +1669,7 @@ func TestDetailedDiffReplacementComputedProperty(t *testing.T) { Config2: changeValue, }) - autogold.ExpectFile(t, testOutput{ + autogold.ExpectFile(t, diffTestOutput{ initialValue: initialValue, changeValue: changeValue, tfOut: diff.TFOut, @@ -1687,7 +1688,7 @@ func TestDetailedDiffReplacementComputedProperty(t *testing.T) { Config2: changeValue, }) - autogold.ExpectFile(t, testOutput{ + autogold.ExpectFile(t, diffTestOutput{ initialValue: initialValue, changeValue: changeValue, tfOut: diff.TFOut, @@ -1706,7 +1707,7 @@ func TestDetailedDiffReplacementComputedProperty(t *testing.T) { Config2: changeValue, }) - autogold.ExpectFile(t, testOutput{ + autogold.ExpectFile(t, diffTestOutput{ initialValue: initialValue, changeValue: changeValue, tfOut: diff.TFOut, @@ -1725,7 +1726,7 @@ func TestDetailedDiffReplacementComputedProperty(t *testing.T) { Config2: changeValue, }) - autogold.ExpectFile(t, testOutput{ + autogold.ExpectFile(t, diffTestOutput{ initialValue: initialValue, changeValue: changeValue, tfOut: diff.TFOut, @@ -1734,3 +1735,112 @@ func TestDetailedDiffReplacementComputedProperty(t *testing.T) { }) }) } + +func TestPropertyWithDot(t *testing.T) { + res := &schema.Resource{ + Schema: map[string]*schema.Schema{ + "prop": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "foo": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + }, + } + + for _, accuratePreivewsEnabled := range []bool{true, false} { + t.Run(fmt.Sprintf("accuratePreivewsEnabled=%v", accuratePreivewsEnabled), func(t *testing.T) { + t.Setenv("PULUMI_TF_BRIDGE_ACCURATE_BRIDGE_PREVIEW", strconv.FormatBool(accuratePreivewsEnabled)) + t.Run("unchanged", func(t *testing.T) { + initialValue := cty.ObjectVal(map[string]cty.Value{ + "prop": cty.ListVal([]cty.Value{ + cty.ObjectVal(map[string]cty.Value{"foo.bar": cty.StringVal("baz")}), + }), + }) + changeValue := cty.ObjectVal(map[string]cty.Value{ + "prop": cty.ListVal([]cty.Value{ + cty.ObjectVal(map[string]cty.Value{"foo.bar": cty.StringVal("baz")}), + }), + }) + diff := runDiffCheck(t, diffTestCase{ + Resource: res, + Config1: initialValue, + Config2: changeValue, + }) + + autogold.ExpectFile(t, diffTestOutput{ + initialValue: initialValue, + changeValue: changeValue, + tfOut: diff.TFOut, + pulumiOut: diff.PulumiOut, + detailedDiff: diff.PulumiDiff.DetailedDiff, + }) + }) + + t.Run("added", func(t *testing.T) { + initialValue := cty.ObjectVal(map[string]cty.Value{ + "prop": cty.ListVal([]cty.Value{ + cty.ObjectVal(map[string]cty.Value{"foo": cty.StringVal("bar")}), + }), + }) + changeValue := cty.ObjectVal(map[string]cty.Value{ + "prop": cty.ListVal([]cty.Value{ + cty.ObjectVal(map[string]cty.Value{ + "foo": cty.StringVal("bar"), + "foo.bar": cty.StringVal("baz"), + }), + }), + }) + diff := runDiffCheck(t, diffTestCase{ + Resource: res, + Config1: initialValue, + Config2: changeValue, + }) + + autogold.ExpectFile(t, diffTestOutput{ + initialValue: initialValue, + changeValue: changeValue, + tfOut: diff.TFOut, + pulumiOut: diff.PulumiOut, + detailedDiff: diff.PulumiDiff.DetailedDiff, + }) + }) + + t.Run("deleted", func(t *testing.T) { + initialValue := cty.ObjectVal(map[string]cty.Value{ + "prop": cty.ListVal([]cty.Value{ + cty.ObjectVal(map[string]cty.Value{ + "foo": cty.StringVal("bar"), + "foo.bar": cty.StringVal("baz"), + }), + }), + }) + changeValue := cty.ObjectVal(map[string]cty.Value{ + "prop": cty.ListVal([]cty.Value{ + cty.ObjectVal(map[string]cty.Value{"foo": cty.StringVal("bar")}), + }), + }) + diff := runDiffCheck(t, diffTestCase{ + Resource: res, + Config1: initialValue, + Config2: changeValue, + }) + + autogold.ExpectFile(t, diffTestOutput{ + initialValue: initialValue, + changeValue: changeValue, + tfOut: diff.TFOut, + pulumiOut: diff.PulumiOut, + detailedDiff: diff.PulumiDiff.DetailedDiff, + }) + }) + }) + } +} diff --git a/pkg/internal/tests/cross-tests/testdata/TestPropertyWithDot/accuratePreivewsEnabled=false/added.golden b/pkg/internal/tests/cross-tests/testdata/TestPropertyWithDot/accuratePreivewsEnabled=false/added.golden new file mode 100644 index 000000000..aab5c5c11 --- /dev/null +++ b/pkg/internal/tests/cross-tests/testdata/TestPropertyWithDot/accuratePreivewsEnabled=false/added.golden @@ -0,0 +1,44 @@ +crosstests.diffTestOutput{ + initialValue: cty.Value{ + ty: cty.Type{typeImpl: cty.typeObject{ + AttrTypes: map[string]cty.Type{"prop": { + typeImpl: cty.typeList{ElementTypeT: cty.Type{ + typeImpl: cty.typeObject{AttrTypes: map[string]cty.Type{ + "foo": {typeImpl: cty.primitiveType{ + Kind: cty.primitiveTypeKind(83), + }}, + }}, + }}, + }}, + }}, + v: map[string]interface{}{"prop": []interface{}{map[string]interface{}{"foo": "bar"}}}, + }, + changeValue: cty.Value{ + ty: cty.Type{typeImpl: cty.typeObject{AttrTypes: map[string]cty.Type{"prop": {typeImpl: cty.typeList{ + ElementTypeT: cty.Type{typeImpl: cty.typeObject{ + AttrTypes: map[string]cty.Type{ + "foo": { + typeImpl: cty.primitiveType{Kind: cty.primitiveTypeKind(83)}, + }, + "foo.bar": {typeImpl: cty.primitiveType{Kind: cty.primitiveTypeKind(83)}}, + }, + }}, + }}}}}, + v: map[string]interface{}{"prop": []interface{}{map[string]interface{}{ + "foo": "bar", + "foo.bar": "baz", + }}}, + }, + tfOut: ` +No changes. Your infrastructure matches the configuration. + +Terraform has compared your real infrastructure against your configuration +and found no differences, so no changes are needed. +`, + pulumiOut: `Previewing update (test): + pulumi:pulumi:Stack: (same) + [urn=urn:pulumi:test::project::pulumi:pulumi:Stack::project-test] +Resources: + 2 unchanged +`, +} diff --git a/pkg/internal/tests/cross-tests/testdata/TestPropertyWithDot/accuratePreivewsEnabled=false/deleted.golden b/pkg/internal/tests/cross-tests/testdata/TestPropertyWithDot/accuratePreivewsEnabled=false/deleted.golden new file mode 100644 index 000000000..bd3964402 --- /dev/null +++ b/pkg/internal/tests/cross-tests/testdata/TestPropertyWithDot/accuratePreivewsEnabled=false/deleted.golden @@ -0,0 +1,42 @@ +crosstests.diffTestOutput{ + initialValue: cty.Value{ + ty: cty.Type{typeImpl: cty.typeObject{ + AttrTypes: map[string]cty.Type{"prop": { + typeImpl: cty.typeList{ElementTypeT: cty.Type{ + typeImpl: cty.typeObject{AttrTypes: map[string]cty.Type{ + "foo": {typeImpl: cty.primitiveType{ + Kind: cty.primitiveTypeKind(83), + }}, + "foo.bar": {typeImpl: cty.primitiveType{Kind: cty.primitiveTypeKind(83)}}, + }}, + }}, + }}, + }}, + v: map[string]interface{}{"prop": []interface{}{map[string]interface{}{ + "foo": "bar", + "foo.bar": "baz", + }}}, + }, + changeValue: cty.Value{ + ty: cty.Type{typeImpl: cty.typeObject{AttrTypes: map[string]cty.Type{"prop": {typeImpl: cty.typeList{ + ElementTypeT: cty.Type{typeImpl: cty.typeObject{ + AttrTypes: map[string]cty.Type{"foo": { + typeImpl: cty.primitiveType{Kind: cty.primitiveTypeKind(83)}, + }}, + }}, + }}}}}, + v: map[string]interface{}{"prop": []interface{}{map[string]interface{}{"foo": "bar"}}}, + }, + tfOut: ` +No changes. Your infrastructure matches the configuration. + +Terraform has compared your real infrastructure against your configuration +and found no differences, so no changes are needed. +`, + pulumiOut: `Previewing update (test): + pulumi:pulumi:Stack: (same) + [urn=urn:pulumi:test::project::pulumi:pulumi:Stack::project-test] +Resources: + 2 unchanged +`, +} diff --git a/pkg/internal/tests/cross-tests/testdata/TestPropertyWithDot/accuratePreivewsEnabled=false/unchanged.golden b/pkg/internal/tests/cross-tests/testdata/TestPropertyWithDot/accuratePreivewsEnabled=false/unchanged.golden new file mode 100644 index 000000000..be541fbc7 --- /dev/null +++ b/pkg/internal/tests/cross-tests/testdata/TestPropertyWithDot/accuratePreivewsEnabled=false/unchanged.golden @@ -0,0 +1,38 @@ +crosstests.diffTestOutput{ + initialValue: cty.Value{ + ty: cty.Type{typeImpl: cty.typeObject{ + AttrTypes: map[string]cty.Type{"prop": { + typeImpl: cty.typeList{ElementTypeT: cty.Type{ + typeImpl: cty.typeObject{AttrTypes: map[string]cty.Type{ + "foo.bar": {typeImpl: cty.primitiveType{ + Kind: cty.primitiveTypeKind(83), + }}, + }}, + }}, + }}, + }}, + v: map[string]interface{}{"prop": []interface{}{map[string]interface{}{"foo.bar": "baz"}}}, + }, + changeValue: cty.Value{ + ty: cty.Type{typeImpl: cty.typeObject{AttrTypes: map[string]cty.Type{"prop": {typeImpl: cty.typeList{ + ElementTypeT: cty.Type{typeImpl: cty.typeObject{ + AttrTypes: map[string]cty.Type{"foo.bar": { + typeImpl: cty.primitiveType{Kind: cty.primitiveTypeKind(83)}, + }}, + }}, + }}}}}, + v: map[string]interface{}{"prop": []interface{}{map[string]interface{}{"foo.bar": "baz"}}}, + }, + tfOut: ` +No changes. Your infrastructure matches the configuration. + +Terraform has compared your real infrastructure against your configuration +and found no differences, so no changes are needed. +`, + pulumiOut: `Previewing update (test): + pulumi:pulumi:Stack: (same) + [urn=urn:pulumi:test::project::pulumi:pulumi:Stack::project-test] +Resources: + 2 unchanged +`, +} diff --git a/pkg/internal/tests/cross-tests/testdata/TestPropertyWithDot/accuratePreivewsEnabled=true/added.golden b/pkg/internal/tests/cross-tests/testdata/TestPropertyWithDot/accuratePreivewsEnabled=true/added.golden new file mode 100644 index 000000000..aab5c5c11 --- /dev/null +++ b/pkg/internal/tests/cross-tests/testdata/TestPropertyWithDot/accuratePreivewsEnabled=true/added.golden @@ -0,0 +1,44 @@ +crosstests.diffTestOutput{ + initialValue: cty.Value{ + ty: cty.Type{typeImpl: cty.typeObject{ + AttrTypes: map[string]cty.Type{"prop": { + typeImpl: cty.typeList{ElementTypeT: cty.Type{ + typeImpl: cty.typeObject{AttrTypes: map[string]cty.Type{ + "foo": {typeImpl: cty.primitiveType{ + Kind: cty.primitiveTypeKind(83), + }}, + }}, + }}, + }}, + }}, + v: map[string]interface{}{"prop": []interface{}{map[string]interface{}{"foo": "bar"}}}, + }, + changeValue: cty.Value{ + ty: cty.Type{typeImpl: cty.typeObject{AttrTypes: map[string]cty.Type{"prop": {typeImpl: cty.typeList{ + ElementTypeT: cty.Type{typeImpl: cty.typeObject{ + AttrTypes: map[string]cty.Type{ + "foo": { + typeImpl: cty.primitiveType{Kind: cty.primitiveTypeKind(83)}, + }, + "foo.bar": {typeImpl: cty.primitiveType{Kind: cty.primitiveTypeKind(83)}}, + }, + }}, + }}}}}, + v: map[string]interface{}{"prop": []interface{}{map[string]interface{}{ + "foo": "bar", + "foo.bar": "baz", + }}}, + }, + tfOut: ` +No changes. Your infrastructure matches the configuration. + +Terraform has compared your real infrastructure against your configuration +and found no differences, so no changes are needed. +`, + pulumiOut: `Previewing update (test): + pulumi:pulumi:Stack: (same) + [urn=urn:pulumi:test::project::pulumi:pulumi:Stack::project-test] +Resources: + 2 unchanged +`, +} diff --git a/pkg/internal/tests/cross-tests/testdata/TestPropertyWithDot/accuratePreivewsEnabled=true/deleted.golden b/pkg/internal/tests/cross-tests/testdata/TestPropertyWithDot/accuratePreivewsEnabled=true/deleted.golden new file mode 100644 index 000000000..bd3964402 --- /dev/null +++ b/pkg/internal/tests/cross-tests/testdata/TestPropertyWithDot/accuratePreivewsEnabled=true/deleted.golden @@ -0,0 +1,42 @@ +crosstests.diffTestOutput{ + initialValue: cty.Value{ + ty: cty.Type{typeImpl: cty.typeObject{ + AttrTypes: map[string]cty.Type{"prop": { + typeImpl: cty.typeList{ElementTypeT: cty.Type{ + typeImpl: cty.typeObject{AttrTypes: map[string]cty.Type{ + "foo": {typeImpl: cty.primitiveType{ + Kind: cty.primitiveTypeKind(83), + }}, + "foo.bar": {typeImpl: cty.primitiveType{Kind: cty.primitiveTypeKind(83)}}, + }}, + }}, + }}, + }}, + v: map[string]interface{}{"prop": []interface{}{map[string]interface{}{ + "foo": "bar", + "foo.bar": "baz", + }}}, + }, + changeValue: cty.Value{ + ty: cty.Type{typeImpl: cty.typeObject{AttrTypes: map[string]cty.Type{"prop": {typeImpl: cty.typeList{ + ElementTypeT: cty.Type{typeImpl: cty.typeObject{ + AttrTypes: map[string]cty.Type{"foo": { + typeImpl: cty.primitiveType{Kind: cty.primitiveTypeKind(83)}, + }}, + }}, + }}}}}, + v: map[string]interface{}{"prop": []interface{}{map[string]interface{}{"foo": "bar"}}}, + }, + tfOut: ` +No changes. Your infrastructure matches the configuration. + +Terraform has compared your real infrastructure against your configuration +and found no differences, so no changes are needed. +`, + pulumiOut: `Previewing update (test): + pulumi:pulumi:Stack: (same) + [urn=urn:pulumi:test::project::pulumi:pulumi:Stack::project-test] +Resources: + 2 unchanged +`, +} diff --git a/pkg/internal/tests/cross-tests/testdata/TestPropertyWithDot/accuratePreivewsEnabled=true/unchanged.golden b/pkg/internal/tests/cross-tests/testdata/TestPropertyWithDot/accuratePreivewsEnabled=true/unchanged.golden new file mode 100644 index 000000000..be541fbc7 --- /dev/null +++ b/pkg/internal/tests/cross-tests/testdata/TestPropertyWithDot/accuratePreivewsEnabled=true/unchanged.golden @@ -0,0 +1,38 @@ +crosstests.diffTestOutput{ + initialValue: cty.Value{ + ty: cty.Type{typeImpl: cty.typeObject{ + AttrTypes: map[string]cty.Type{"prop": { + typeImpl: cty.typeList{ElementTypeT: cty.Type{ + typeImpl: cty.typeObject{AttrTypes: map[string]cty.Type{ + "foo.bar": {typeImpl: cty.primitiveType{ + Kind: cty.primitiveTypeKind(83), + }}, + }}, + }}, + }}, + }}, + v: map[string]interface{}{"prop": []interface{}{map[string]interface{}{"foo.bar": "baz"}}}, + }, + changeValue: cty.Value{ + ty: cty.Type{typeImpl: cty.typeObject{AttrTypes: map[string]cty.Type{"prop": {typeImpl: cty.typeList{ + ElementTypeT: cty.Type{typeImpl: cty.typeObject{ + AttrTypes: map[string]cty.Type{"foo.bar": { + typeImpl: cty.primitiveType{Kind: cty.primitiveTypeKind(83)}, + }}, + }}, + }}}}}, + v: map[string]interface{}{"prop": []interface{}{map[string]interface{}{"foo.bar": "baz"}}}, + }, + tfOut: ` +No changes. Your infrastructure matches the configuration. + +Terraform has compared your real infrastructure against your configuration +and found no differences, so no changes are needed. +`, + pulumiOut: `Previewing update (test): + pulumi:pulumi:Stack: (same) + [urn=urn:pulumi:test::project::pulumi:pulumi:Stack::project-test] +Resources: + 2 unchanged +`, +} diff --git a/pkg/tfbridge/diff_test.go b/pkg/tfbridge/diff_test.go index 5cba5ec1b..782dd7881 100644 --- a/pkg/tfbridge/diff_test.go +++ b/pkg/tfbridge/diff_test.go @@ -2173,6 +2173,7 @@ type diffTestCase struct { } func diffTest2(t *testing.T, tc diffTestCase) { + t.Helper() ctx := context.Background() res := &v2Schema.Resource{ Schema: tc.resourceSchema, @@ -2275,3 +2276,42 @@ func TestChangingMaxItems1FilterProperty(t *testing.T) { }, }) } + +func TestPropertyWithDot(t *testing.T) { + t.Parallel() + // TODO[pulumi/pulumi-terraform-bridge#2669] + t.Skip("We currently fail to return the correct detailed diff for this case") + + schema := map[string]*v2Schema.Schema{ + "prop": { + Type: v2Schema.TypeMap, + Optional: true, + Elem: &v2Schema.Schema{ + Type: v2Schema.TypeString, + }, + }, + } + + diffTest2(t, diffTestCase{ + resourceSchema: schema, + state: resource.PropertyMap{ + "prop": resource.NewObjectProperty(resource.PropertyMap{ + "foo": resource.NewStringProperty("bar"), + }), + }, + inputs: resource.PropertyMap{ + "prop": resource.NewObjectProperty(resource.PropertyMap{ + "foo.bar": resource.NewStringProperty("baz"), + }), + }, + expectedDiffChanges: pulumirpc.DiffResponse_DIFF_SOME, + expected: map[string]*pulumirpc.PropertyDiff{ + "prop.foo": { + Kind: pulumirpc.PropertyDiff_DELETE, + }, + "prop[\"foo.bar\"]": { + Kind: pulumirpc.PropertyDiff_ADD, + }, + }, + }) +}