Skip to content

Commit 7ccdd03

Browse files
Add extract schema inputs tests for sdkv2 (#2224)
This adds test cases for how TF types are handled by `ExtractInputsFromOutputs` in combination with `Default` and `Computed` and `MaxItems: 1` `ExtractInputsFromOutputs` is the function in `schema.go` responsible for generating the inputs from resource outputs when a resource is imported. Its output is what the engine then uses for generating the code for the import. Notably, nested computed values are wrong for both max items one and non-max items one. In #2180 we found a regression there, so this fills in some missing coverage. Extracting the tests to make the changes more apparent and to make sure we don't regress in #2181
1 parent 6796105 commit 7ccdd03

File tree

1 file changed

+306
-0
lines changed

1 file changed

+306
-0
lines changed

pkg/tfbridge/schema_test.go

Lines changed: 306 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3436,3 +3436,309 @@ func Test_makeTerraformInputsNoDefaults(t *testing.T) {
34363436
})
34373437
}
34383438
}
3439+
3440+
func TestExtractInputsFromOutputsSdkv2(t *testing.T) {
3441+
t.Parallel()
3442+
3443+
type testCase struct {
3444+
name string
3445+
props resource.PropertyMap
3446+
schemaMap map[string]*schemav2.Schema
3447+
expected autogold.Value
3448+
}
3449+
3450+
testCases := []testCase{
3451+
{
3452+
name: "string attribute extracted",
3453+
props: resource.NewPropertyMapFromMap(map[string]interface{}{"foo": "bar"}),
3454+
schemaMap: map[string]*schemav2.Schema{
3455+
"foo": {Type: schemav2.TypeString, Optional: true},
3456+
},
3457+
expected: autogold.Expect(resource.PropertyMap{
3458+
resource.PropertyKey("__defaults"): resource.PropertyValue{
3459+
V: []resource.PropertyValue{},
3460+
},
3461+
resource.PropertyKey("foo"): resource.PropertyValue{V: "bar"},
3462+
}),
3463+
},
3464+
{
3465+
name: "string attribute with defaults not extracted",
3466+
props: resource.NewPropertyMapFromMap(map[string]interface{}{"foo": "baz"}),
3467+
schemaMap: map[string]*schemav2.Schema{
3468+
"foo": {Type: schemav2.TypeString, Optional: true, Default: "baz"},
3469+
},
3470+
expected: autogold.Expect(resource.PropertyMap{resource.PropertyKey("__defaults"): resource.PropertyValue{
3471+
V: []resource.PropertyValue{},
3472+
}}),
3473+
},
3474+
{
3475+
name: "string attribute with empty value not extracted",
3476+
props: resource.NewPropertyMapFromMap(map[string]interface{}{"foo": ""}),
3477+
schemaMap: map[string]*schemav2.Schema{
3478+
"foo": {Type: schemav2.TypeString, Optional: true},
3479+
},
3480+
expected: autogold.Expect(resource.PropertyMap{resource.PropertyKey("__defaults"): resource.PropertyValue{
3481+
V: []resource.PropertyValue{},
3482+
}}),
3483+
},
3484+
{
3485+
name: "string attribute with computed not extracted",
3486+
props: resource.NewPropertyMapFromMap(map[string]interface{}{
3487+
"foo": resource.Computed{Element: resource.NewStringProperty("bar")},
3488+
}),
3489+
schemaMap: map[string]*schemav2.Schema{
3490+
"foo": {Type: schemav2.TypeString, Computed: true},
3491+
},
3492+
expected: autogold.Expect(resource.PropertyMap{resource.PropertyKey("__defaults"): resource.PropertyValue{
3493+
V: []resource.PropertyValue{},
3494+
}}),
3495+
},
3496+
{
3497+
name: "map attribute extracted",
3498+
props: resource.NewPropertyMapFromMap(map[string]interface{}{
3499+
"foo": map[string]interface{}{
3500+
"bar": "baz",
3501+
},
3502+
}),
3503+
schemaMap: map[string]*schemav2.Schema{
3504+
"foo": {
3505+
Type: schemav2.TypeMap,
3506+
Optional: true,
3507+
Elem: &schemav2.Schema{
3508+
Type: schemav2.TypeString,
3509+
},
3510+
},
3511+
},
3512+
expected: autogold.Expect(resource.PropertyMap{
3513+
resource.PropertyKey("__defaults"): resource.PropertyValue{
3514+
V: []resource.PropertyValue{},
3515+
},
3516+
resource.PropertyKey("foo"): resource.PropertyValue{V: resource.PropertyMap{
3517+
resource.PropertyKey("__defaults"): resource.PropertyValue{
3518+
V: []resource.PropertyValue{},
3519+
},
3520+
resource.PropertyKey("bar"): resource.PropertyValue{V: "baz"},
3521+
}},
3522+
}),
3523+
},
3524+
{
3525+
name: "map attribute with computed not extracted",
3526+
props: resource.NewPropertyMapFromMap(map[string]interface{}{
3527+
"foo": resource.Computed{Element: resource.NewStringProperty("bar")},
3528+
}),
3529+
schemaMap: map[string]*schemav2.Schema{
3530+
"foo": {
3531+
Type: schemav2.TypeMap,
3532+
Computed: true,
3533+
Elem: &schemav2.Schema{
3534+
Type: schemav2.TypeString,
3535+
},
3536+
},
3537+
},
3538+
expected: autogold.Expect(resource.PropertyMap{resource.PropertyKey("__defaults"): resource.PropertyValue{
3539+
V: []resource.PropertyValue{},
3540+
}}),
3541+
},
3542+
{
3543+
name: "list attribute extracted",
3544+
props: resource.NewPropertyMapFromMap(map[string]interface{}{
3545+
"foo": []interface{}{"bar"},
3546+
}),
3547+
schemaMap: map[string]*schemav2.Schema{
3548+
"foo": {
3549+
Type: schemav2.TypeList,
3550+
Optional: true,
3551+
Elem: &schemav2.Schema{
3552+
Type: schemav2.TypeString,
3553+
},
3554+
},
3555+
},
3556+
expected: autogold.Expect(resource.PropertyMap{
3557+
resource.PropertyKey("__defaults"): resource.PropertyValue{
3558+
V: []resource.PropertyValue{},
3559+
},
3560+
resource.PropertyKey("foo"): resource.PropertyValue{V: []resource.PropertyValue{{
3561+
V: "bar",
3562+
}}},
3563+
}),
3564+
},
3565+
{
3566+
name: "list block extracted",
3567+
props: resource.NewPropertyMapFromMap(map[string]interface{}{
3568+
"foo": []interface{}{map[string]string{"bar": "baz"}},
3569+
}),
3570+
schemaMap: map[string]*schemav2.Schema{
3571+
"foo": {
3572+
Type: schemav2.TypeList,
3573+
Optional: true,
3574+
Elem: &schemav2.Resource{
3575+
Schema: map[string]*schemav2.Schema{
3576+
"bar": {Type: schemav2.TypeString, Optional: true},
3577+
},
3578+
},
3579+
},
3580+
},
3581+
expected: autogold.Expect(resource.PropertyMap{
3582+
resource.PropertyKey("__defaults"): resource.PropertyValue{
3583+
V: []resource.PropertyValue{},
3584+
},
3585+
resource.PropertyKey("foo"): resource.PropertyValue{V: []resource.PropertyValue{{
3586+
V: resource.PropertyMap{
3587+
resource.PropertyKey("__defaults"): resource.PropertyValue{
3588+
V: []resource.PropertyValue{},
3589+
},
3590+
resource.PropertyKey("bar"): resource.PropertyValue{V: "baz"},
3591+
},
3592+
}}},
3593+
}),
3594+
},
3595+
{
3596+
name: "list block with computed not extracted",
3597+
props: resource.NewPropertyMapFromMap(map[string]interface{}{
3598+
"foo": []interface{}{map[string]string{"bar": "baz"}},
3599+
}),
3600+
schemaMap: map[string]*schemav2.Schema{
3601+
"foo": {
3602+
Type: schemav2.TypeList,
3603+
Computed: true,
3604+
Elem: &schemav2.Resource{
3605+
Schema: map[string]*schemav2.Schema{
3606+
"bar": {Type: schemav2.TypeString, Optional: true},
3607+
},
3608+
},
3609+
},
3610+
},
3611+
expected: autogold.Expect(resource.PropertyMap{resource.PropertyKey("__defaults"): resource.PropertyValue{
3612+
V: []resource.PropertyValue{},
3613+
}}),
3614+
},
3615+
{
3616+
name: "list block max items one extracted",
3617+
props: resource.NewPropertyMapFromMap(map[string]interface{}{
3618+
"foo": map[string]interface{}{
3619+
"bar": "baz",
3620+
},
3621+
}),
3622+
schemaMap: map[string]*schemav2.Schema{
3623+
"foo": {
3624+
Type: schemav2.TypeList,
3625+
Optional: true,
3626+
MaxItems: 1,
3627+
Elem: &schemav2.Resource{
3628+
Schema: map[string]*schemav2.Schema{
3629+
"bar": {Type: schemav2.TypeString, Optional: true},
3630+
},
3631+
},
3632+
},
3633+
},
3634+
expected: autogold.Expect(resource.PropertyMap{
3635+
resource.PropertyKey("__defaults"): resource.PropertyValue{
3636+
V: []resource.PropertyValue{},
3637+
},
3638+
resource.PropertyKey("foo"): resource.PropertyValue{V: resource.PropertyMap{
3639+
resource.PropertyKey("__defaults"): resource.PropertyValue{
3640+
V: []resource.PropertyValue{},
3641+
},
3642+
resource.PropertyKey("bar"): resource.PropertyValue{V: "baz"},
3643+
}},
3644+
}),
3645+
},
3646+
// This case is invalid since MaxItemsOne only works on settable fields.
3647+
// {
3648+
// name: "list block max items one computed",
3649+
// props: resource.NewPropertyMapFromMap(map[string]interface{}{
3650+
// "foo": map[string]interface{}{
3651+
// "bar": "baz",
3652+
// },
3653+
// }),
3654+
// schemaMap: map[string]*schemav2.Schema{
3655+
// "foo": {
3656+
// Type: schemav2.TypeList,
3657+
// Computed: true,
3658+
// MaxItems: 1,
3659+
// Elem: &schemav2.Resource{
3660+
// Schema: map[string]*schemav2.Schema{
3661+
// "bar": {Type: schemav2.TypeString, Optional: true},
3662+
// },
3663+
// },
3664+
// },
3665+
// },
3666+
// expected: autogold.Expect(),
3667+
// },
3668+
// TODO[pulumi/pulumi-terraform-bridge#2180]: This is wrong as an input should not be produced for computed values.
3669+
{
3670+
name: "list block with computed element not extracted",
3671+
props: resource.NewPropertyMapFromMap(map[string]interface{}{
3672+
"foo": []interface{}{map[string]string{"bar": "baz"}},
3673+
}),
3674+
schemaMap: map[string]*schemav2.Schema{
3675+
"foo": {
3676+
Type: schemav2.TypeList,
3677+
Optional: true,
3678+
Elem: &schemav2.Resource{
3679+
Schema: map[string]*schemav2.Schema{
3680+
"bar": {Type: schemav2.TypeString, Computed: true},
3681+
},
3682+
},
3683+
},
3684+
},
3685+
expected: autogold.Expect(resource.PropertyMap{
3686+
resource.PropertyKey("__defaults"): resource.PropertyValue{
3687+
V: []resource.PropertyValue{},
3688+
},
3689+
resource.PropertyKey("foo"): resource.PropertyValue{V: []resource.PropertyValue{{
3690+
V: resource.PropertyMap{
3691+
resource.PropertyKey("__defaults"): resource.PropertyValue{
3692+
V: []resource.PropertyValue{},
3693+
},
3694+
resource.PropertyKey("bar"): resource.PropertyValue{V: "baz"},
3695+
},
3696+
}}},
3697+
}),
3698+
},
3699+
// TODO[pulumi/pulumi-terraform-bridge#2180]: This is wrong as an input should not be produced for computed values.
3700+
{
3701+
name: "list block max items one with computed element not extracted",
3702+
props: resource.NewPropertyMapFromMap(map[string]interface{}{
3703+
"foo": []interface{}{map[string]string{"bar": "baz"}},
3704+
}),
3705+
schemaMap: map[string]*schemav2.Schema{
3706+
"foo": {
3707+
Type: schemav2.TypeList,
3708+
MaxItems: 1,
3709+
Optional: true,
3710+
Elem: &schemav2.Resource{
3711+
Schema: map[string]*schemav2.Schema{
3712+
"bar": {Type: schemav2.TypeString, Computed: true},
3713+
},
3714+
},
3715+
},
3716+
},
3717+
expected: autogold.Expect(resource.PropertyMap{
3718+
resource.PropertyKey("__defaults"): resource.PropertyValue{
3719+
V: []resource.PropertyValue{},
3720+
},
3721+
resource.PropertyKey("foo"): resource.PropertyValue{V: []resource.PropertyValue{{
3722+
V: resource.PropertyMap{resource.PropertyKey("bar"): resource.PropertyValue{
3723+
V: "baz",
3724+
}},
3725+
}}},
3726+
}),
3727+
},
3728+
}
3729+
3730+
for _, tc := range testCases {
3731+
tc := tc
3732+
3733+
t.Run(tc.name, func(t *testing.T) {
3734+
sm := shimv2.NewSchemaMap(tc.schemaMap)
3735+
err := sm.Validate()
3736+
require.NoErrorf(t, err, "Invalid test case schema, please fix the testCase")
3737+
3738+
result, err := ExtractInputsFromOutputs(nil, tc.props, sm, nil, false)
3739+
require.NoError(t, err)
3740+
tc.expected.Equal(t, result)
3741+
})
3742+
3743+
}
3744+
}

0 commit comments

Comments
 (0)