Skip to content

Commit

Permalink
PF cross-tests for computed set attributes
Browse files Browse the repository at this point in the history
  • Loading branch information
VenelinMartinov committed Nov 19, 2024
1 parent 02da7bc commit a01b833
Show file tree
Hide file tree
Showing 49 changed files with 1,758 additions and 14 deletions.
106 changes: 92 additions & 14 deletions pkg/pf/tests/diff_set_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"testing"

"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/resource"
rschema "github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
Expand Down Expand Up @@ -151,7 +152,80 @@ func TestDetailedDiffSet(t *testing.T) {
},
})

computedCreateFunc := func(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
computedAttributeCreateFunc := func(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
type ObjectModel struct {
ID types.String `tfsdk:"id"`
Keys types.Set `tfsdk:"key"`
}
reqVal := ObjectModel{}
diags := req.Plan.Get(ctx, &reqVal)
contract.Assertf(diags.ErrorsCount() == 0, "failed to get attribute: %v", diags)

respVal := ObjectModel{
ID: types.StringValue("test-id"),
}
if reqVal.Keys.IsUnknown() {
respVal.Keys = types.SetValueMust(types.StringType, []attr.Value{
types.StringValue("value"),
})
} else {
respVal.Keys = reqVal.Keys
}

diags = resp.State.Set(ctx, &respVal)
contract.Assertf(diags.ErrorsCount() == 0, "failed to set attribute: %v", diags)
}

computedAttributeUpdateFunc := func(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
createResp := resource.CreateResponse{
State: resp.State,
Diagnostics: resp.Diagnostics,
}
computedAttributeCreateFunc(ctx, resource.CreateRequest{
Plan: req.Plan,
Config: req.Config,
ProviderMeta: req.ProviderMeta,
}, &createResp)
resp.State = createResp.State
resp.Diagnostics = createResp.Diagnostics
}

computedSetAttributeSchema := pb.NewResource(pb.NewResourceArgs{
ResourceSchema: rschema.Schema{
Attributes: map[string]rschema.Attribute{
"key": rschema.SetAttribute{
Optional: true,
ElementType: types.StringType,
Computed: true,
PlanModifiers: []planmodifier.Set{
setplanmodifier.UseStateForUnknown(),
},
},
},
},
CreateFunc: computedAttributeCreateFunc,
UpdateFunc: computedAttributeUpdateFunc,
})

computedSetAttributeReplaceSchema := pb.NewResource(pb.NewResourceArgs{
ResourceSchema: rschema.Schema{
Attributes: map[string]rschema.Attribute{
"key": rschema.SetAttribute{
Optional: true,
ElementType: types.StringType,
Computed: true,
PlanModifiers: []planmodifier.Set{
setplanmodifier.RequiresReplace(),
setplanmodifier.UseStateForUnknown(),
},
},
},
},
CreateFunc: computedAttributeCreateFunc,
UpdateFunc: computedAttributeUpdateFunc,
})

computedBlockCreateFunc := func(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
type Nested struct {
Nested types.String `tfsdk:"nested"`
Computed types.String `tfsdk:"computed"`
Expand Down Expand Up @@ -192,12 +266,12 @@ func TestDetailedDiffSet(t *testing.T) {
contract.Assertf(diags.ErrorsCount() == 0, "failed to set attribute: %v", diags)
}

computedUpdateFunc := func(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
computedBlockUpdateFunc := func(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
createResp := resource.CreateResponse{
State: resp.State,
Diagnostics: resp.Diagnostics,
}
computedCreateFunc(ctx, resource.CreateRequest{
computedBlockCreateFunc(ctx, resource.CreateRequest{
Plan: req.Plan,
Config: req.Config,
ProviderMeta: req.ProviderMeta,
Expand Down Expand Up @@ -226,8 +300,8 @@ func TestDetailedDiffSet(t *testing.T) {
},
},
},
CreateFunc: computedCreateFunc,
UpdateFunc: computedUpdateFunc,
CreateFunc: computedBlockCreateFunc,
UpdateFunc: computedBlockUpdateFunc,
})

blockSchemaWithComputedNoStateForUnknown := pb.NewResource(pb.NewResourceArgs{
Expand All @@ -246,8 +320,8 @@ func TestDetailedDiffSet(t *testing.T) {
},
},
},
CreateFunc: computedCreateFunc,
UpdateFunc: computedUpdateFunc,
CreateFunc: computedBlockCreateFunc,
UpdateFunc: computedBlockUpdateFunc,
})

blockSchemaWithComputedReplace := pb.NewResource(pb.NewResourceArgs{
Expand All @@ -272,8 +346,8 @@ func TestDetailedDiffSet(t *testing.T) {
},
},
},
CreateFunc: computedCreateFunc,
UpdateFunc: computedUpdateFunc,
CreateFunc: computedBlockCreateFunc,
UpdateFunc: computedBlockUpdateFunc,
})

blockSchemaWithComputedNestedReplace := pb.NewResource(pb.NewResourceArgs{
Expand All @@ -300,8 +374,8 @@ func TestDetailedDiffSet(t *testing.T) {
},
},
},
CreateFunc: computedCreateFunc,
UpdateFunc: computedUpdateFunc,
CreateFunc: computedBlockCreateFunc,
UpdateFunc: computedBlockUpdateFunc,
})

blockSchemaWithComputedComputedRequiresReplace := pb.NewResource(pb.NewResourceArgs{
Expand All @@ -324,8 +398,8 @@ func TestDetailedDiffSet(t *testing.T) {
},
},
},
CreateFunc: computedCreateFunc,
UpdateFunc: computedUpdateFunc,
CreateFunc: computedBlockCreateFunc,
UpdateFunc: computedBlockUpdateFunc,
})

attrList := func(arr *[]string) cty.Value {
Expand Down Expand Up @@ -393,7 +467,11 @@ func TestDetailedDiffSet(t *testing.T) {
{"block requires replace", blockReplaceSchema, nestedAttrList},
{"block nested requires replace", blockNestedReplaceSchema, nestedAttrList},

// Computed, each state we test both the behaviour when the computed value is specified in the program and when it is not.
// Computed attributes
{"attribute with computed no replace", computedSetAttributeSchema, attrList},
{"attribute with computed requires replace", computedSetAttributeReplaceSchema, attrList},

// Computed blocks, each state we test both the behaviour when the computed value is specified in the program and when it is not.
{"block with computed no replace computed", blockSchemaWithComputed, nestedAttrList},
{"block with computed no replace computed specified in program", blockSchemaWithComputed, nestedAttrListWithComputedSpecified},
{"block with computed requires replace", blockSchemaWithComputedReplace, nestedAttrList},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
tfbridgetests.testOutput{
initialValue: &[]string{},
changeValue: &[]string{"value"},
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:

# testprovider_test.res will be updated in-place
~ resource "testprovider_test" "res" {
id = "test-id"
~ key = [
+ "value",
]
}

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]
~ testprovider:index/test:Test: (update)
[id=test-id]
[urn=urn:pulumi:test::project::testprovider:index/test:Test::p]
~ keys: [
+ [0]: "value"
]
Resources:
~ 1 to update
1 unchanged
`,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
tfbridgetests.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:

# testprovider_test.res will be updated in-place
~ resource "testprovider_test" "res" {
id = "test-id"
~ key = [
+ "val3",
# (2 unchanged elements 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]
~ testprovider:index/test:Test: (update)
[id=test-id]
[urn=urn:pulumi:test::project::testprovider:index/test:Test::p]
~ keys: [
[0]: "val1"
[1]: "val2"
+ [2]: "val3"
]
Resources:
~ 1 to update
1 unchanged
`,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
tfbridgetests.testOutput{
initialValue: &[]string{
"val2",
"val3",
},
changeValue: &[]string{
"val2",
"val3",
"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:

# testprovider_test.res will be updated in-place
~ resource "testprovider_test" "res" {
id = "test-id"
~ key = [
+ "val1",
# (2 unchanged elements 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]
~ testprovider:index/test:Test: (update)
[id=test-id]
[urn=urn:pulumi:test::project::testprovider:index/test:Test::p]
~ keys: [
[0]: "val2"
[1]: "val3"
+ [2]: "val1"
]
Resources:
~ 1 to update
1 unchanged
`,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
tfbridgetests.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:

# testprovider_test.res will be updated in-place
~ resource "testprovider_test" "res" {
id = "test-id"
~ key = [
+ "val1",
# (2 unchanged elements 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]
~ testprovider:index/test:Test: (update)
[id=test-id]
[urn=urn:pulumi:test::project::testprovider:index/test:Test::p]
~ keys: [
~ [0]: "val2" => "val1"
~ [1]: "val3" => "val2"
+ [2]: "val3"
]
Resources:
~ 1 to update
1 unchanged
`,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
tfbridgetests.testOutput{
initialValue: &[]string{
"val3",
"val1",
},
changeValue: &[]string{
"val2",
"val3",
"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:

# testprovider_test.res will be updated in-place
~ resource "testprovider_test" "res" {
id = "test-id"
~ key = [
+ "val2",
# (2 unchanged elements 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]
~ testprovider:index/test:Test: (update)
[id=test-id]
[urn=urn:pulumi:test::project::testprovider:index/test:Test::p]
~ keys: [
~ [0]: "val3" => "val2"
~ [1]: "val1" => "val3"
+ [2]: "val1"
]
Resources:
~ 1 to update
1 unchanged
`,
}
Loading

0 comments on commit a01b833

Please sign in to comment.