Skip to content

Commit

Permalink
SDKv2 Diff tests for Computed in List (#2858)
Browse files Browse the repository at this point in the history
This PR adds Diff tests for Computed in lists for the SDKv2 bridge.

fixes #2788
  • Loading branch information
VenelinMartinov authored Jan 22, 2025
1 parent 3c7db4e commit deacda0
Show file tree
Hide file tree
Showing 91 changed files with 6,033 additions and 0 deletions.
118 changes: 118 additions & 0 deletions pkg/tests/diff_test/detailed_diff_list_test.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package tests

import (
"context"
"fmt"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/pulumi/pulumi/sdk/v3/go/common/util/contract"
)

func TestSDKv2DetailedDiffList(t *testing.T) {
Expand Down Expand Up @@ -221,6 +224,110 @@ func TestSDKv2DetailedDiffList(t *testing.T) {
},
}

listAttributeSchemaComputed := schema.Resource{
Schema: map[string]*schema.Schema{
"prop": {
Type: schema.TypeList,
Optional: true,
Computed: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
},
CreateContext: func(ctx context.Context, d *schema.ResourceData, i interface{}) diag.Diagnostics {
d.SetId("id")
if _, ok := d.GetOk("prop"); !ok {
err := d.Set("prop", []interface{}{"computed"})
contract.Assertf(err == nil, "failed to set attribute: %v", err)
}
return nil
},
UpdateContext: func(ctx context.Context, d *schema.ResourceData, i interface{}) diag.Diagnostics {
if _, ok := d.GetOk("prop"); !ok {
err := d.Set("prop", []interface{}{"computed"})
contract.Assertf(err == nil, "failed to set attribute: %v", err)
}
return nil
},
}

computedListBlockFunc := func(ctx context.Context, d *schema.ResourceData, i interface{}) diag.Diagnostics {
if _, ok := d.GetOk("prop"); !ok {
err := d.Set("prop", []map[string]interface{}{{"nested_prop": "computed"}})
contract.Assertf(err == nil, "failed to set attribute: %v", err)
}
return nil
}

listBlockSchemaComputed := schema.Resource{
Schema: map[string]*schema.Schema{
"prop": {
Type: schema.TypeList,
Optional: true,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"nested_prop": {
Type: schema.TypeString,
Optional: true,
},
},
},
},
},
CreateContext: func(ctx context.Context, rd *schema.ResourceData, i interface{}) diag.Diagnostics {
rd.SetId("id")
return computedListBlockFunc(ctx, rd, i)
},
UpdateContext: computedListBlockFunc,
}

computedListBlockNestedFunc := func(ctx context.Context, d *schema.ResourceData, i interface{}) diag.Diagnostics {
contract.Assertf(d.Get("prop") != nil, "test attribute is nil")
testVals := d.Get("prop").([]interface{})
newVals := []map[string]interface{}{}
for _, v := range testVals {
val := v.(map[string]interface{})
if val["computed"] == nil || val["computed"] == "" {
compVal := "computed1"
if val["nested_prop"] != nil {
compVal = val["nested_prop"].(string)
}
val["computed"] = compVal
}
newVals = append(newVals, val)
}
err := d.Set("prop", newVals)
contract.Assertf(err == nil, "failed to set attribute: %v", err)
return nil
}

listBlockSchemaNestedComputed := schema.Resource{
Schema: map[string]*schema.Schema{
"prop": {
Type: schema.TypeList,
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"nested_prop": {
Type: schema.TypeString,
Optional: true,
},
"computed": {
Type: schema.TypeString,
Optional: true,
Computed: true,
},
},
},
},
},
CreateContext: func(ctx context.Context, rd *schema.ResourceData, i interface{}) diag.Diagnostics {
rd.SetId("id")
return computedListBlockNestedFunc(ctx, rd, i)
},
UpdateContext: computedListBlockNestedFunc,
}

listPairs := []diffSchemaValueMakerPair[[]string]{
{"list attribute", listAttrSchema, listValueMaker},
{"list attribute force new", listAttrSchemaForceNew, listValueMaker},
Expand All @@ -234,6 +341,17 @@ func TestSDKv2DetailedDiffList(t *testing.T) {
"list block nested default with default specified in program",
listBlockSchemaNestedDefault, nestedListValueMakerWithDefaultSpecified,
},
{"list attribute computed", listAttributeSchemaComputed, listValueMaker},
{"list block computed", listBlockSchemaComputed, nestedListValueMaker},
{
"list block computed with computed specified in program",
listBlockSchemaComputed, nestedListValueMakerWithComputedSpecified,
},
{"list block nested computed", listBlockSchemaNestedComputed, nestedListValueMaker},
{
"list block nested computed with computed specified in program",
listBlockSchemaNestedComputed, nestedListValueMakerWithComputedSpecified,
},
}

maxItemsOnePairs := []diffSchemaValueMakerPair[[]string]{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
tests.testOutput{
initialValue: nil, changeValue: &[]string{},
tfOut: `
Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
~ update in-place

Terraform will perform the following actions:

# crossprovider_test_res.example will be updated in-place
~ resource "crossprovider_test_res" "example" {
id = "id"
~ prop = [
- "computed",
]
}

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

`,
pulumiOut: `Previewing update (test):
pulumi:pulumi:Stack: (same)
[urn=urn:pulumi:test::project::pulumi:pulumi:Stack::project-test]
~ crossprovider:index/testRes:TestRes: (update)
[id=id]
[urn=urn:pulumi:test::project::crossprovider:index/testRes:TestRes::example]
- props: [
- [0]: "computed"
]
Resources:
~ 1 to update
1 unchanged
`,
detailedDiff: map[string]interface{}{"props": map[string]interface{}{"kind": "DELETE"}},
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
tests.testOutput{
initialValue: nil, changeValue: &[]string{
"val1",
},
tfOut: `
Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
~ update in-place

Terraform will perform the following actions:

# crossprovider_test_res.example will be updated in-place
~ resource "crossprovider_test_res" "example" {
id = "id"
~ prop = [
~ "computed" -> "val1",
]
}

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

`,
pulumiOut: `Previewing update (test):
pulumi:pulumi:Stack: (same)
[urn=urn:pulumi:test::project::pulumi:pulumi:Stack::project-test]
~ crossprovider:index/testRes:TestRes: (update)
[id=id]
[urn=urn:pulumi:test::project::crossprovider:index/testRes:TestRes::example]
~ props: [
~ [0]: "computed" => "val1"
]
Resources:
~ 1 to update
1 unchanged
`,
detailedDiff: map[string]interface{}{"props[0]": map[string]interface{}{"kind": "UPDATE"}},
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
tests.testOutput{
initialValue: &[]string{
"val1",
},
changeValue: &[]string{"val2"},
tfOut: `
Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
~ update in-place

Terraform will perform the following actions:

# crossprovider_test_res.example will be updated in-place
~ resource "crossprovider_test_res" "example" {
id = "id"
~ prop = [
~ "val1" -> "val2",
]
}

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

`,
pulumiOut: `Previewing update (test):
pulumi:pulumi:Stack: (same)
[urn=urn:pulumi:test::project::pulumi:pulumi:Stack::project-test]
~ crossprovider:index/testRes:TestRes: (update)
[id=id]
[urn=urn:pulumi:test::project::crossprovider:index/testRes:TestRes::example]
~ props: [
~ [0]: "val1" => "val2"
]
Resources:
~ 1 to update
1 unchanged
`,
detailedDiff: map[string]interface{}{"props[0]": map[string]interface{}{"kind": "UPDATE"}},
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
tests.testOutput{
initialValue: &[]string{
"val1",
"val2",
},
changeValue: &[]string{
"val1",
"val2",
"val3",
},
tfOut: `
Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
~ update in-place

Terraform will perform the following actions:

# crossprovider_test_res.example will be updated in-place
~ resource "crossprovider_test_res" "example" {
id = "id"
~ prop = [
# (1 unchanged element hidden)
"val2",
+ "val3",
]
}

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

`,
pulumiOut: `Previewing update (test):
pulumi:pulumi:Stack: (same)
[urn=urn:pulumi:test::project::pulumi:pulumi:Stack::project-test]
~ crossprovider:index/testRes:TestRes: (update)
[id=id]
[urn=urn:pulumi:test::project::crossprovider:index/testRes:TestRes::example]
~ props: [
+ [2]: "val3"
]
Resources:
~ 1 to update
1 unchanged
`,
detailedDiff: map[string]interface{}{"props[2]": map[string]interface{}{}},
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
tests.testOutput{
initialValue: &[]string{
"val2",
"val3",
},
changeValue: &[]string{
"val1",
"val2",
"val3",
},
tfOut: `
Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
~ update in-place

Terraform will perform the following actions:

# crossprovider_test_res.example will be updated in-place
~ resource "crossprovider_test_res" "example" {
id = "id"
~ prop = [
+ "val1",
"val2",
# (1 unchanged element hidden)
]
}

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

`,
pulumiOut: `Previewing update (test):
pulumi:pulumi:Stack: (same)
[urn=urn:pulumi:test::project::pulumi:pulumi:Stack::project-test]
~ crossprovider:index/testRes:TestRes: (update)
[id=id]
[urn=urn:pulumi:test::project::crossprovider:index/testRes:TestRes::example]
~ props: [
~ [0]: "val2" => "val1"
~ [1]: "val3" => "val2"
+ [2]: "val3"
]
Resources:
~ 1 to update
1 unchanged
`,
detailedDiff: map[string]interface{}{
"props[0]": map[string]interface{}{"kind": "UPDATE"},
"props[1]": map[string]interface{}{"kind": "UPDATE"},
"props[2]": map[string]interface{}{},
},
}
Loading

0 comments on commit deacda0

Please sign in to comment.