Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cross test fix required empty blocks #1995

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pkg/convert/encoding.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ func deriveDecoder(pctx *schemaPropContext, t tftypes.Type) (Decoder, error) {
}
return &flattenedDecoder{
elementDecoder: decoder,
elementType: elementType,
}, nil
}

Expand Down
12 changes: 12 additions & 0 deletions pkg/convert/flattened.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package convert

import (
"fmt"

"github.com/hashicorp/terraform-plugin-go/tftypes"

"github.com/pulumi/pulumi/sdk/v3/go/common/resource"
Expand All @@ -42,6 +43,7 @@ func (enc *flattenedEncoder) fromPropertyValue(v resource.PropertyValue) (tftype

type flattenedDecoder struct {
elementDecoder Decoder
elementType tftypes.Type
}

func (dec *flattenedDecoder) toPropertyValue(v tftypes.Value) (resource.PropertyValue, error) {
Expand All @@ -51,6 +53,16 @@ func (dec *flattenedDecoder) toPropertyValue(v tftypes.Value) (resource.Property
}
switch len(list) {
case 0:
if dec.elementType.Is(tftypes.Object{}) {
tfVal := tftypes.NewValue(dec.elementType, map[string]tftypes.Value{})
return dec.elementDecoder.toPropertyValue(tfVal)
} else if dec.elementType.Is(tftypes.List{}) {
tfVal := tftypes.NewValue(dec.elementType, []tftypes.Value{})
return dec.elementDecoder.toPropertyValue(tfVal)
} else if dec.elementType.Is(tftypes.Set{}) {
tfVal := tftypes.NewValue(dec.elementType, []tftypes.Value{})
return dec.elementDecoder.toPropertyValue(tfVal)
}
return resource.NewNullProperty(), nil
case 1:
return dec.elementDecoder.toPropertyValue(list[0])
Expand Down
141 changes: 141 additions & 0 deletions pkg/tests/cross-tests/input_cross_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,147 @@ func TestExplicitNilList(t *testing.T) {
},
},
// TODO: How does one express this with tftypes?
// tftypes.NewValue(tftypes.DynamicPseudoType, nil)?
Config: map[string]interface{}{"f0": nil},
})
}

func TestRequiredEmptyListOfObjects(t *testing.T) {
skipUnlessLinux(t)

t1 := tftypes.Object{}
t0 := tftypes.Object{AttributeTypes: map[string]tftypes.Type{
"d3f0": tftypes.List{ElementType: t1},
}}
config := tftypes.NewValue(t0, map[string]tftypes.Value{
"d3f0": tftypes.NewValue(tftypes.List{ElementType: t1}, []tftypes.Value{}),
})

runCreateInputCheck(t, inputTestCase{
Resource: &schema.Resource{
Schema: map[string]*schema.Schema{
"d3f0": {
Type: schema.TypeList,
Required: true,
Elem: &schema.Resource{Schema: map[string]*schema.Schema{}},
MaxItems: 1,
},
},
},
Config: config,
})
}

func TestRequiredEmptyListOfLists(t *testing.T) {
skipUnlessLinux(t)
t.Skipf("Fix - returns []interface {}{interface {}(nil)} instead of []interface {}{}")

t1 := tftypes.List{ElementType: tftypes.String}
t0 := tftypes.Object{AttributeTypes: map[string]tftypes.Type{
"d3f0": tftypes.List{ElementType: t1},
}}
config := tftypes.NewValue(t0, map[string]tftypes.Value{
"d3f0": tftypes.NewValue(tftypes.List{ElementType: t1}, []tftypes.Value{}),
})

runCreateInputCheck(t, inputTestCase{
Resource: &schema.Resource{
Schema: map[string]*schema.Schema{
"d3f0": {
Type: schema.TypeList,
Required: true,
Elem: &schema.Schema{
Type: schema.TypeList, Elem: &schema.Schema{Type: schema.TypeString},
},
MaxItems: 1,
},
},
},
Config: config,
})
}

func TestRequiredEmptyListOfSets(t *testing.T) {
skipUnlessLinux(t)
t.Skipf("Fix - returns []interface {}{interface {}(nil)} instead of []interface {}{}")

t1 := tftypes.Set{ElementType: tftypes.String}
t0 := tftypes.Object{AttributeTypes: map[string]tftypes.Type{
"d3f0": tftypes.List{ElementType: t1},
}}
config := tftypes.NewValue(t0, map[string]tftypes.Value{
"d3f0": tftypes.NewValue(tftypes.List{ElementType: t1}, []tftypes.Value{}),
})

runCreateInputCheck(t, inputTestCase{
Resource: &schema.Resource{
Schema: map[string]*schema.Schema{
"d3f0": {
Type: schema.TypeList,
Required: true,
Elem: &schema.Schema{
Type: schema.TypeSet, Elem: &schema.Schema{Type: schema.TypeString},
},
MaxItems: 1,
},
},
},
Config: config,
})
}

func TestNonEmptyNestedMaxItemsOnes(t *testing.T) {
skipUnlessLinux(t)

t1 := tftypes.List{ElementType: tftypes.String}
t0 := tftypes.Object{AttributeTypes: map[string]tftypes.Type{
"d3f0": tftypes.List{ElementType: t1},
}}
// Non-empty
config1 := tftypes.NewValue(t0, map[string]tftypes.Value{
"d3f0": tftypes.NewValue(tftypes.List{ElementType: t1}, []tftypes.Value{
tftypes.NewValue(t1, []tftypes.Value{
tftypes.NewValue(tftypes.String, "foo"),
}),
}),
})
// first level empty
config2 := tftypes.NewValue(t0, map[string]tftypes.Value{
"d3f0": tftypes.NewValue(tftypes.List{ElementType: t1}, []tftypes.Value{}),
})
// second level empty - this is impossible to handle because of flattening
_ = tftypes.NewValue(t0, map[string]tftypes.Value{
"d3f0": tftypes.NewValue(tftypes.List{ElementType: t1}, []tftypes.Value{
tftypes.NewValue(t1, []tftypes.Value{}),
}),
})

for _, tc := range []struct {
name string
config tftypes.Value
}{
{"non-empty", config1},
{"first-level-empty", config2},
// {"second-level-empty", config3},
} {
t.Run(tc.name, func(t *testing.T) {
runCreateInputCheck(t, inputTestCase{
Resource: &schema.Resource{
Schema: map[string]*schema.Schema{
"d3f0": {
Type: schema.TypeList,
Required: true,
Elem: &schema.Schema{
Type: schema.TypeList,
MaxItems: 1,
Elem: &schema.Schema{Type: schema.TypeString},
},
MaxItems: 1,
},
},
},
Config: tc.config,
})
})
}
}
8 changes: 8 additions & 0 deletions pkg/tests/cross-tests/tfwrite.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ func writeBlock(body *hclwrite.Body, schemas map[string]*schema.Schema, values m
continue
}

if value.LengthInt() == 0 {
body.AppendNewBlock(key, nil)
}

for _, v := range value.AsValueSet().Values() {
newBlock := body.AppendNewBlock(key, nil)
writeBlock(newBlock.Body(), elem.Schema, v.AsValueMap())
Expand All @@ -69,6 +73,10 @@ func writeBlock(body *hclwrite.Body, schemas map[string]*schema.Schema, values m
continue
}

if value.LengthInt() == 0 {
body.AppendNewBlock(key, nil)
}

for _, v := range value.AsValueSlice() {
newBlock := body.AppendNewBlock(key, nil)
writeBlock(newBlock.Body(), elem.Schema, v.AsValueMap())
Expand Down
1 change: 1 addition & 0 deletions pkg/tests/cross-tests/tfwrite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ resource "res" "ex" {
}
`),
},
// TODO: empty list/set test case
}

for _, tc := range testCases {
Expand Down
Loading