Skip to content

Commit

Permalink
WIP Specify full blocks
Browse files Browse the repository at this point in the history
  • Loading branch information
iwahbe committed Oct 15, 2024
1 parent a4ae424 commit d963913
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 52 deletions.
6 changes: 2 additions & 4 deletions pf/tests/util/property/pf/value/provider/primitive.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import (
"fmt"

"github.com/hashicorp/terraform-plugin-go/tftypes"
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfbridge"
"github.com/pulumi/pulumi/sdk/v3/go/common/resource"
"github.com/zclconf/go-cty/cty"
"pgregory.net/rapid"
Expand Down Expand Up @@ -78,13 +77,12 @@ func convertMap(m map[string]value, elem cty.Type) value {
}
}

func convertObject(m map[string]value) value {
func convertObject(m map[string]value, names map[string]resource.PropertyKey) value {
tfMap, puMap := make(map[string]cty.Value, len(m)), make(resource.PropertyMap, len(m))
for k, v := range m {
tfMap[k] = v.Tf
if v.hasValue {
// TODO: Correctly handle name conversion
puMap[resource.PropertyKey(tfbridge.TerraformToPulumiNameV2(k, nil, nil))] = v.Pu
puMap[names[k]] = v.Pu
}
}
return value{
Expand Down
169 changes: 121 additions & 48 deletions pf/tests/util/property/pf/value/provider/value.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,51 +53,25 @@ type generator struct {
isInput bool
}

func WithValue(schema schema.Schema) *rapid.Generator[Value] {

// All rapid.Custom generators *must* consume entropy, so we special case empty
// schemas.
if len(schema.Attributes)+len(schema.Blocks) == 0 {
return rapid.Just(Value{
Tf: cty.EmptyObjectVal,
Pu: resource.PropertyMap{},
})
}
return rapid.Custom(func(t *rapid.T) Value {
g := generator{isInput: true}
ctyM, puM := map[string]cty.Value{}, resource.PropertyMap{}

for k, s := range schema.Attributes {
v := g.withAttr(s).Draw(t, k)
ctyM[k] = v.Tf
if v.hasValue {
puK := tfbridge.TerraformToPulumiNameV2(k, shimschema.SchemaMap{
k: (&shimschema.Schema{Type: shimType(s.GetType())}).Shim(),
}, nil)
puM[resource.PropertyKey(puK)] = v.Pu
func WithValue(s schema.Schema) *rapid.Generator[Value] {
g := generator{isInput: true}

return rapid.Map(
g.nestedBlockObject(schema.NestedBlockObject{
Attributes: s.Attributes,
Blocks: s.Blocks,
}),
func(v value) Value {
var pu resource.PropertyMap
if !v.Pu.IsNull() {
pu = v.Pu.ObjectValue()
}
}

for k, b := range schema.Blocks {
v := g.withBlock(b).Draw(t, k)
ctyM[k] = v.Tf
if v.hasValue {
puK := tfbridge.TerraformToPulumiNameV2(k, shimschema.SchemaMap{
k: (&shimschema.Schema{Type: shimType(b.Type())}).Shim(),
}, nil)
puM[resource.PropertyKey(puK)] = v.Pu
}
}

return Value{
Tf: cty.ObjectVal(ctyM),
Pu: puM,
}
})
return Value{Tf: v.Tf, Pu: pu}
},
)
}

func shimType(a attr.Type) shim.ValueType {
t := a.TerraformType(context.Background())
func shimType(t tftypes.Type) shim.ValueType {
switch {
case t.Is(tftypes.Set{}):
return shim.TypeSet
Expand Down Expand Up @@ -213,11 +187,12 @@ func (g generator) withAttr(attr schema.Attribute) *rapid.Generator[value] {
// TODO: Explore sending empty maps here
return rapid.Just(value{Tf: cty.EmptyObjectVal})
}
names := translateAttrNames(attr.AttributeTypes)
return rapid.Custom(func(t *rapid.T) value {
for k, a := range attr.AttributeTypes {
m[k] = baseAttr(a.TerraformType(ctx)).Draw(t, k)
}
return convertObject(m)
return convertObject(m, names)
})

// Nested attributes
Expand All @@ -226,11 +201,12 @@ func (g generator) withAttr(attr schema.Attribute) *rapid.Generator[value] {
if len(attr.Attributes) == 0 {
return rapid.Just(value{Tf: cty.EmptyObjectVal})
}
names := translateNames(attr.Attributes, nil)
return rapid.Custom(func(t *rapid.T) value {
for k, a := range attr.Attributes {
m[k] = g.withAttr(a).Draw(t, k)
}
return convertObject(m)
return convertObject(m, names)
})
case schema.MapNestedAttribute:
return rapid.Map(
Expand Down Expand Up @@ -262,6 +238,9 @@ func baseAttr(typ tftypes.Type) *rapid.Generator[value] {
if len(o.AttributeTypes) == 0 {
return rapid.Just(value{Tf: cty.EmptyObjectVal})
}

names := translareTftypeNames(o.AttributeTypes)

return rapid.Custom(func(t *rapid.T) value {
m := make(map[string]value, len(o.AttributeTypes))
for k, a := range o.AttributeTypes {
Expand All @@ -274,7 +253,7 @@ func baseAttr(typ tftypes.Type) *rapid.Generator[value] {
m[k] = baseAttr(a).Draw(t, k)
}
}
return convertObject(m)
return convertObject(m, names)
})
case typ.Is(tftypes.Bool):
return rapid.Custom(boolVal)
Expand Down Expand Up @@ -308,20 +287,69 @@ func baseAttr(typ tftypes.Type) *rapid.Generator[value] {
func (g generator) nestedObject(obj schema.NestedAttributeObject) *rapid.Generator[value] {
if len(obj.Attributes) == 0 {
m := make(map[string]value, len(obj.Attributes))
return rapid.Just(convertObject(m))
return rapid.Just(convertObject(m, nil))
}

names := translateNames(obj.Attributes, nil)
return rapid.Custom(func(t *rapid.T) value {
m := make(map[string]value, len(obj.Attributes))
for k, a := range obj.Attributes {
m[k] = g.withAttr(a).Draw(t, k)
}
return convertObject(m)
return convertObject(m, names)
})
}

func (g generator) withBlock(block schema.Block) *rapid.Generator[value] {
contract.Assertf(g.isInput, "only input values are implemented")
return baseAttr(block.Type().TerraformType(context.Background()))
ctx := context.Background()

switch block := block.(type) {
case schema.ListNestedBlock:
return rapid.Map(
rapid.SliceOfN(g.nestedBlockObject(block.NestedObject), -1, maxIterableSize),
makeConvertList(ctyType(block.NestedObject.Type().TerraformType(ctx))),
)
case schema.SetNestedBlock:
return rapid.Map(
rapid.SliceOfNDistinct(g.nestedBlockObject(block.NestedObject), -1, maxIterableSize, valueID),
makeConvertSet(ctyType(block.NestedObject.Type().TerraformType(ctx))),
)
case schema.SingleNestedBlock:
return g.nestedBlockObject(schema.NestedBlockObject{
Attributes: block.Attributes,
Blocks: block.Blocks,
})
default:
panic(fmt.Sprintf("Unknown schema.Block type: %T", block))
}
}

func (g generator) nestedBlockObject(obj schema.NestedBlockObject) *rapid.Generator[value] {

// All rapid.Custom generators *must* consume entropy, so we special case empty
// schemas.
if len(obj.Attributes)+len(obj.Blocks) == 0 {
return rapid.Just(value{
Tf: cty.EmptyObjectVal,
Pu: resource.NewNullProperty(),
})
}

names := translateNames(obj.Attributes, obj.Blocks)

return rapid.Custom(func(t *rapid.T) value {
m := map[string]value{}
for k, s := range obj.Attributes {
m[k] = g.withAttr(s).Draw(t, k)
}

for k, b := range obj.Blocks {
m[k] = g.withBlock(b).Draw(t, k)
}

return convertObject(m, names)
})
}

func valueID(v value) uint64 {
Expand All @@ -330,3 +358,48 @@ func valueID(v value) uint64 {
h.WriteString(v.Pu.String())

Check failure on line 358 in pf/tests/util/property/pf/value/provider/value.go

View workflow job for this annotation

GitHub Actions / Test and Lint / lint

Error return value of `h.WriteString` is not checked (errcheck)
return h.Sum64()
}

func translareTftypeNames(attrs map[string]tftypes.Type) map[string]resource.PropertyKey {
sch := make(shimschema.SchemaMap, len(attrs))
for k, v := range attrs {
sch[k] = (&shimschema.Schema{
Type: shimType(v),
}).Shim()
}

names := make(map[string]resource.PropertyKey, len(sch))
for k := range sch {
names[k] = resource.PropertyKey(tfbridge.TerraformToPulumiNameV2(k, sch, nil))
}
return names
}

func translateAttrNames(attrs map[string]attr.Type) map[string]resource.PropertyKey {
ctx := context.Background()
m := make(map[string]tftypes.Type, len(attrs))
for k, v := range attrs {
m[k] = v.TerraformType(ctx)
}
return translareTftypeNames(m)
}

func translateNames(attrs map[string]schema.Attribute, blocks map[string]schema.Block) map[string]resource.PropertyKey {
ctx := context.Background()
sch := make(shimschema.SchemaMap, len(attrs)+len(blocks))
for k, v := range attrs {
sch[k] = (&shimschema.Schema{
Type: shimType(v.GetType().TerraformType(ctx)),
}).Shim()
}
for k, v := range blocks {
sch[k] = (&shimschema.Schema{
Type: shimType(v.Type().TerraformType(ctx)),
}).Shim()
}

names := make(map[string]resource.PropertyKey, len(sch))
for k := range sch {
names[k] = resource.PropertyKey(tfbridge.TerraformToPulumiNameV2(k, sch, nil))
}
return names
}

0 comments on commit d963913

Please sign in to comment.