Skip to content

Commit

Permalink
Merge pull request #461 from hashicorp/jbardin/hcldec-unknown-body
Browse files Browse the repository at this point in the history
dynblock,hcldec: Decode unknown dynamic block bodies as entirely unknown values
  • Loading branch information
jbardin authored Apr 16, 2021
2 parents 805c25b + adfdd23 commit ec9b866
Show file tree
Hide file tree
Showing 3 changed files with 374 additions and 140 deletions.
294 changes: 244 additions & 50 deletions ext/dynblock/expand_body_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,47 +190,6 @@ func TestExpand(t *testing.T) {
},
}),
},
{
Type: "dynamic",
Labels: []string{"b"},
LabelRanges: []hcl.Range{hcl.Range{}},
Body: hcltest.MockBody(&hcl.BodyContent{
Attributes: hcltest.MockAttrs(map[string]hcl.Expression{
"for_each": hcltest.MockExprLiteral(cty.UnknownVal(cty.Map(cty.String))),
"iterator": hcltest.MockExprVariable("dyn_b"),
}),
Blocks: hcl.Blocks{
{
Type: "content",
Body: hcltest.MockBody(&hcl.BodyContent{
Blocks: hcl.Blocks{
{
Type: "dynamic",
Labels: []string{"c"},
LabelRanges: []hcl.Range{hcl.Range{}},
Body: hcltest.MockBody(&hcl.BodyContent{
Attributes: hcltest.MockAttrs(map[string]hcl.Expression{
"for_each": hcltest.MockExprTraversalSrc("dyn_b.value"),
}),
Blocks: hcl.Blocks{
{
Type: "content",
Body: hcltest.MockBody(&hcl.BodyContent{
Attributes: hcltest.MockAttrs(map[string]hcl.Expression{
"val0": hcltest.MockExprTraversalSrc("c.value"),
"val1": hcltest.MockExprTraversalSrc("dyn_b.key"),
}),
}),
},
},
}),
},
},
}),
},
},
}),
},
{
Type: "a",
Labels: []string{"static1"},
Expand Down Expand Up @@ -364,15 +323,6 @@ func TestExpand(t *testing.T) {
"val1": cty.StringVal("foo"),
}),
}),
cty.ListVal([]cty.Value{
// This one comes from a dynamic block with an unknown for_each
// value, so we produce a single block object with all of the
// leaf attribute values set to unknown values.
cty.ObjectVal(map[string]cty.Value{
"val0": cty.UnknownVal(cty.String),
"val1": cty.UnknownVal(cty.String),
}),
}),
})

if !got.RawEquals(want) {
Expand All @@ -381,3 +331,247 @@ func TestExpand(t *testing.T) {
})

}

func TestExpandUnknownBodies(t *testing.T) {
srcContent := &hcl.BodyContent{
Blocks: hcl.Blocks{
{
Type: "dynamic",
Labels: []string{"list"},
LabelRanges: []hcl.Range{hcl.Range{}},
Body: hcltest.MockBody(&hcl.BodyContent{
Attributes: hcltest.MockAttrs(map[string]hcl.Expression{
"for_each": hcltest.MockExprLiteral(cty.UnknownVal(cty.Map(cty.String))),
}),
Blocks: hcl.Blocks{
{
Type: "content",
Body: hcltest.MockBody(&hcl.BodyContent{
Attributes: hcltest.MockAttrs(map[string]hcl.Expression{
"val": hcltest.MockExprTraversalSrc("each.value"),
}),
}),
},
},
}),
},
{
Type: "dynamic",
Labels: []string{"tuple"},
LabelRanges: []hcl.Range{hcl.Range{}},
Body: hcltest.MockBody(&hcl.BodyContent{
Attributes: hcltest.MockAttrs(map[string]hcl.Expression{
"for_each": hcltest.MockExprLiteral(cty.UnknownVal(cty.Map(cty.String))),
}),
Blocks: hcl.Blocks{
{
Type: "content",
Body: hcltest.MockBody(&hcl.BodyContent{
Attributes: hcltest.MockAttrs(map[string]hcl.Expression{
"val": hcltest.MockExprTraversalSrc("each.value"),
}),
}),
},
},
}),
},
{
Type: "dynamic",
Labels: []string{"set"},
LabelRanges: []hcl.Range{hcl.Range{}},
Body: hcltest.MockBody(&hcl.BodyContent{
Attributes: hcltest.MockAttrs(map[string]hcl.Expression{
"for_each": hcltest.MockExprLiteral(cty.UnknownVal(cty.Map(cty.String))),
}),
Blocks: hcl.Blocks{
{
Type: "content",
Body: hcltest.MockBody(&hcl.BodyContent{
Attributes: hcltest.MockAttrs(map[string]hcl.Expression{
"val": hcltest.MockExprTraversalSrc("each.value"),
}),
}),
},
},
}),
},
{
Type: "dynamic",
Labels: []string{"map"},
LabelRanges: []hcl.Range{hcl.Range{}},
Body: hcltest.MockBody(&hcl.BodyContent{
Attributes: hcltest.MockAttrs(map[string]hcl.Expression{
"for_each": hcltest.MockExprLiteral(cty.UnknownVal(cty.Map(cty.String))),
"labels": hcltest.MockExprList([]hcl.Expression{
hcltest.MockExprLiteral(cty.StringVal("static")),
}),
}),
Blocks: hcl.Blocks{
{
Type: "content",
Body: hcltest.MockBody(&hcl.BodyContent{
Attributes: hcltest.MockAttrs(map[string]hcl.Expression{
"val": hcltest.MockExprTraversalSrc("each.value"),
}),
}),
},
},
}),
},
{
Type: "dynamic",
Labels: []string{"object"},
LabelRanges: []hcl.Range{hcl.Range{}},
Body: hcltest.MockBody(&hcl.BodyContent{
Attributes: hcltest.MockAttrs(map[string]hcl.Expression{
"for_each": hcltest.MockExprLiteral(cty.UnknownVal(cty.Map(cty.String))),
"labels": hcltest.MockExprList([]hcl.Expression{
hcltest.MockExprLiteral(cty.StringVal("static")),
}),
}),
Blocks: hcl.Blocks{
{
Type: "content",
Body: hcltest.MockBody(&hcl.BodyContent{
Attributes: hcltest.MockAttrs(map[string]hcl.Expression{
"val": hcltest.MockExprTraversalSrc("each.value"),
}),
}),
},
},
}),
},
},
}

srcBody := hcltest.MockBody(srcContent)
dynBody := Expand(srcBody, nil)

t.Run("DecodeList", func(t *testing.T) {
decSpec := &hcldec.BlockListSpec{
TypeName: "list",
Nested: &hcldec.ObjectSpec{
"val": &hcldec.AttrSpec{
Name: "val",
Type: cty.String,
},
},
}

var got cty.Value
var diags hcl.Diagnostics

got, _, diags = hcldec.PartialDecode(dynBody, decSpec, nil)
if len(diags) != 0 {
t.Errorf("unexpected diagnostics")
for _, diag := range diags {
t.Logf("- %s", diag)
}
return
}

want := cty.UnknownVal(cty.List(cty.Object(map[string]cty.Type{
"val": cty.String,
})))

if !got.RawEquals(want) {
t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, want)
}
})

t.Run("DecodeTuple", func(t *testing.T) {
decSpec := &hcldec.BlockTupleSpec{
TypeName: "tuple",
Nested: &hcldec.ObjectSpec{
"val": &hcldec.AttrSpec{
Name: "val",
Type: cty.String,
},
},
}

var got cty.Value
var diags hcl.Diagnostics

got, _, diags = hcldec.PartialDecode(dynBody, decSpec, nil)
if len(diags) != 0 {
t.Errorf("unexpected diagnostics")
for _, diag := range diags {
t.Logf("- %s", diag)
}
return
}

want := cty.DynamicVal

if !got.RawEquals(want) {
t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, want)
}
})

t.Run("DecodeSet", func(t *testing.T) {
decSpec := &hcldec.BlockSetSpec{
TypeName: "tuple",
Nested: &hcldec.ObjectSpec{
"val": &hcldec.AttrSpec{
Name: "val",
Type: cty.String,
},
},
}

var got cty.Value
var diags hcl.Diagnostics

got, _, diags = hcldec.PartialDecode(dynBody, decSpec, nil)
if len(diags) != 0 {
t.Errorf("unexpected diagnostics")
for _, diag := range diags {
t.Logf("- %s", diag)
}
return
}

want := cty.UnknownVal(cty.Set(cty.Object(map[string]cty.Type{
"val": cty.String,
})))

if !got.RawEquals(want) {
t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, want)
}
})

t.Run("DecodeMap", func(t *testing.T) {
decSpec := &hcldec.BlockMapSpec{
TypeName: "map",
LabelNames: []string{"key"},
Nested: &hcldec.ObjectSpec{
"val": &hcldec.AttrSpec{
Name: "val",
Type: cty.String,
},
},
}

var got cty.Value
var diags hcl.Diagnostics

got, _, diags = hcldec.PartialDecode(dynBody, decSpec, nil)
if len(diags) != 0 {
t.Errorf("unexpected diagnostics")
for _, diag := range diags {
t.Logf("- %s", diag)
}
return
}

want := cty.UnknownVal(cty.Map(cty.Object(map[string]cty.Type{
"val": cty.String,
})))

if !got.RawEquals(want) {
t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, want)
}
})

}
5 changes: 5 additions & 0 deletions ext/dynblock/unknown_body.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ type unknownBody struct {

var _ hcl.Body = unknownBody{}

// hcldec.UnkownBody impl
func (b unknownBody) Unknown() bool {
return true
}

func (b unknownBody) Content(schema *hcl.BodySchema) (*hcl.BodyContent, hcl.Diagnostics) {
content, diags := b.template.Content(schema)
content = b.fixupContent(content)
Expand Down
Loading

0 comments on commit ec9b866

Please sign in to comment.