Skip to content

Commit

Permalink
SDKv2 Diff cross tests for replacement of computed properties
Browse files Browse the repository at this point in the history
  • Loading branch information
VenelinMartinov committed Nov 26, 2024
1 parent d7eacfb commit 4eeafda
Show file tree
Hide file tree
Showing 6 changed files with 273 additions and 1 deletion.
3 changes: 2 additions & 1 deletion pkg/internal/tests/cross-tests/diff_check.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (

"github.com/hashicorp/terraform-plugin-go/tftypes"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/pulumi/pulumi/sdk/v3/go/auto/optpreview"
"github.com/stretchr/testify/require"

crosstestsimpl "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/internal/tests/cross-tests/impl"
Expand Down Expand Up @@ -79,7 +80,7 @@ func runDiffCheck(t T, tc diffTestCase) crosstestsimpl.DiffResult {
err := os.WriteFile(filepath.Join(pt.CurrentStack().Workspace().WorkDir(), "Pulumi.yaml"), yamlProgram, 0o600)
require.NoErrorf(t, err, "writing Pulumi.yaml")

previewRes := pt.Preview(t)
previewRes := pt.Preview(t, optpreview.Diff())
diffResponse := crosstestsimpl.GetPulumiDiffResponse(t, pt.GrpcLog(t).Entries)
x := pt.Up(t)

Expand Down
112 changes: 112 additions & 0 deletions pkg/internal/tests/cross-tests/diff_cross_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@ import (
"github.com/hashicorp/terraform-plugin-go/tftypes"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hexops/autogold/v2"
"github.com/pulumi/pulumi/sdk/v3/go/common/util/contract"
"github.com/stretchr/testify/require"
"github.com/zclconf/go-cty/cty"
)

func TestUnchangedBasicObject(t *testing.T) {
Expand Down Expand Up @@ -1621,3 +1624,112 @@ func TestBlockCollectionElementForceNew(t *testing.T) {
})
})
}

func TestDetailedDiffReplacementComputedProperty(t *testing.T) {
t.Parallel()

res := &schema.Resource{
Schema: map[string]*schema.Schema{
"computed": {
Type: schema.TypeString,
Computed: true,
},
"other": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},
},
CreateContext: func(ctx context.Context, rd *schema.ResourceData, meta interface{}) diag.Diagnostics {
rd.SetId("r1")

err := rd.Set("computed", "computed_value")
contract.AssertNoErrorf(err, "setting computed")
return nil
},
}

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{})
changeValue := cty.ObjectVal(map[string]cty.Value{})
diff := runDiffCheck(t, diffTestCase{
Resource: res,
Config1: initialValue,
Config2: changeValue,
})

autogold.ExpectFile(t, testOutput{
initialValue: initialValue,
changeValue: changeValue,
tfOut: diff.TFOut,
pulumiOut: diff.PulumiOut,
detailedDiff: diff.PulumiDiff.DetailedDiff,
})
})

t.Run("non-computed added", func(t *testing.T) {
t.Parallel()
initialValue := cty.ObjectVal(map[string]cty.Value{})
changeValue := cty.ObjectVal(map[string]cty.Value{"other": cty.StringVal("other_value")})
diff := runDiffCheck(t, diffTestCase{
Resource: res,
Config1: initialValue,
Config2: changeValue,
})

autogold.ExpectFile(t, testOutput{
initialValue: initialValue,
changeValue: changeValue,
tfOut: diff.TFOut,
pulumiOut: diff.PulumiOut,
detailedDiff: diff.PulumiDiff.DetailedDiff,
})
})

t.Run("non-computed removed", func(t *testing.T) {
t.Parallel()
initialValue := cty.ObjectVal(map[string]cty.Value{"other": cty.StringVal("other_value")})
changeValue := cty.ObjectVal(map[string]cty.Value{})
diff := runDiffCheck(t, diffTestCase{
Resource: res,
Config1: initialValue,
Config2: changeValue,
})

autogold.ExpectFile(t, testOutput{
initialValue: initialValue,
changeValue: changeValue,
tfOut: diff.TFOut,
pulumiOut: diff.PulumiOut,
detailedDiff: diff.PulumiDiff.DetailedDiff,
})
})

t.Run("non-computed changed", func(t *testing.T) {
t.Parallel()
initialValue := cty.ObjectVal(map[string]cty.Value{"other": cty.StringVal("other_value")})
changeValue := cty.ObjectVal(map[string]cty.Value{"other": cty.StringVal("other_value_2")})
diff := runDiffCheck(t, diffTestCase{
Resource: res,
Config1: initialValue,
Config2: changeValue,
})

autogold.ExpectFile(t, testOutput{
initialValue: initialValue,
changeValue: changeValue,
tfOut: diff.TFOut,
pulumiOut: diff.PulumiOut,
detailedDiff: diff.PulumiDiff.DetailedDiff,
})
})
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
crosstests.testOutput{
initialValue: cty.Value{
ty: cty.Type{typeImpl: cty.typeObject{
AttrTypes: map[string]cty.Type{},
}},
v: map[string]interface{}{},
},
changeValue: cty.Value{
ty: cty.Type{typeImpl: cty.typeObject{AttrTypes: map[string]cty.Type{}}},
v: map[string]interface{}{},
},
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
`,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
crosstests.testOutput{
initialValue: cty.Value{
ty: cty.Type{typeImpl: cty.typeObject{
AttrTypes: map[string]cty.Type{},
}},
v: map[string]interface{}{},
},
changeValue: cty.Value{
ty: cty.Type{typeImpl: cty.typeObject{AttrTypes: map[string]cty.Type{
"other": {typeImpl: cty.primitiveType{
Kind: cty.primitiveTypeKind(83),
}},
}}},
v: map[string]interface{}{"other": "other_value"},
},
tfOut: `
Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
+/- create replacement and then destroy

Terraform will perform the following actions:

# crossprovider_test_res.example must be replaced
+/- resource "crossprovider_test_res" "example" {
~ computed = "computed_value" -> (known after apply)
~ id = "r1" -> (known after apply)
+ other = "other_value" # forces replacement
}

Plan: 1 to add, 0 to change, 1 to destroy.

`,
pulumiOut: `Previewing update (test):
pulumi:pulumi:Stack: (same)
[urn=urn:pulumi:test::project::pulumi:pulumi:Stack::project-test]
+-crossprovider:index/testRes:TestRes: (replace)
[id=r1]
[urn=urn:pulumi:test::project::crossprovider:index/testRes:TestRes::example]
+ other: "other_value"
Resources:
+-1 to replace
1 unchanged
`,
detailedDiff: map[string]interface{}{"other": map[string]interface{}{"kind": "ADD_REPLACE"}},
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
crosstests.testOutput{
initialValue: cty.Value{
ty: cty.Type{typeImpl: cty.typeObject{
AttrTypes: map[string]cty.Type{"other": {
typeImpl: cty.primitiveType{Kind: cty.primitiveTypeKind(83)},
}},
}},
v: map[string]interface{}{"other": "other_value"},
},
changeValue: cty.Value{
ty: cty.Type{typeImpl: cty.typeObject{AttrTypes: map[string]cty.Type{
"other": {typeImpl: cty.primitiveType{
Kind: cty.primitiveTypeKind(83),
}},
}}},
v: map[string]interface{}{"other": "other_value_2"},
},
tfOut: `
Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
+/- create replacement and then destroy

Terraform will perform the following actions:

# crossprovider_test_res.example must be replaced
+/- resource "crossprovider_test_res" "example" {
~ computed = "computed_value" -> (known after apply)
~ id = "r1" -> (known after apply)
~ other = "other_value" -> "other_value_2" # forces replacement
}

Plan: 1 to add, 0 to change, 1 to destroy.

`,
pulumiOut: `Previewing update (test):
pulumi:pulumi:Stack: (same)
[urn=urn:pulumi:test::project::pulumi:pulumi:Stack::project-test]
+-crossprovider:index/testRes:TestRes: (replace)
[id=r1]
[urn=urn:pulumi:test::project::crossprovider:index/testRes:TestRes::example]
~ other: "other_value" => "other_value_2"
Resources:
+-1 to replace
1 unchanged
`,
detailedDiff: map[string]interface{}{"other": map[string]interface{}{"kind": "UPDATE_REPLACE"}},
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
crosstests.testOutput{
initialValue: cty.Value{
ty: cty.Type{typeImpl: cty.typeObject{
AttrTypes: map[string]cty.Type{"other": {
typeImpl: cty.primitiveType{Kind: cty.primitiveTypeKind(83)},
}},
}},
v: map[string]interface{}{"other": "other_value"},
},
changeValue: cty.Value{
ty: cty.Type{typeImpl: cty.typeObject{AttrTypes: map[string]cty.Type{}}},
v: map[string]interface{}{},
},
tfOut: `
Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
+/- create replacement and then destroy

Terraform will perform the following actions:

# crossprovider_test_res.example must be replaced
+/- resource "crossprovider_test_res" "example" {
~ computed = "computed_value" -> (known after apply)
~ id = "r1" -> (known after apply)
- other = "other_value" -> null # forces replacement
}

Plan: 1 to add, 0 to change, 1 to destroy.

`,
pulumiOut: `Previewing update (test):
pulumi:pulumi:Stack: (same)
[urn=urn:pulumi:test::project::pulumi:pulumi:Stack::project-test]
+-crossprovider:index/testRes:TestRes: (replace)
[id=r1]
[urn=urn:pulumi:test::project::crossprovider:index/testRes:TestRes::example]
- other: "other_value"
Resources:
+-1 to replace
1 unchanged
`,
detailedDiff: map[string]interface{}{"other": map[string]interface{}{"kind": "DELETE_REPLACE"}},
}

0 comments on commit 4eeafda

Please sign in to comment.