Skip to content

Commit

Permalink
Add tests and fix for StackReference output type checking (#600)
Browse files Browse the repository at this point in the history
* Add tests and fix for StackReference output type checking

Ensures that Pulumi YAML programs are able to use StackReference outputs as
"any" typed values. Allows "any" values to be assigned to any value, expanding
the set of valid programs.

Blocked on:
- pulumi/pulumi#16625

Using a Go workspace with that PR applied to Pulumi, the test suite passes.

* Update to refer to pulumi/pkg/v3@master

* chore: Changelog
  • Loading branch information
AaronFriel authored Jul 11, 2024
1 parent 2e5984c commit 021ac5e
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 16 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG_PENDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@

### Bug Fixes

- Fix Stack Reference output properties to be usable as any type, not only strings inputs.
[#600](https://github.com/pulumi/pulumi-yaml/pull/600)
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ require (
github.com/hexops/autogold v1.3.0
github.com/iancoleman/strcase v0.2.0
github.com/pkg/errors v0.9.1
github.com/pulumi/pulumi/pkg/v3 v3.121.0
github.com/pulumi/pulumi/sdk/v3 v3.121.0
github.com/pulumi/pulumi/pkg/v3 v3.123.1-0.20240711160144-b8226b705890
github.com/pulumi/pulumi/sdk/v3 v3.123.1-0.20240711160144-b8226b705890
github.com/spf13/afero v1.9.5
github.com/stretchr/testify v1.9.0
github.com/zclconf/go-cty v1.13.2
Expand Down
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -430,10 +430,10 @@ github.com/pulumi/esc v0.9.1 h1:HH5eEv8sgyxSpY5a8yePyqFXzA8cvBvapfH8457+mIs=
github.com/pulumi/esc v0.9.1/go.mod h1:oEJ6bOsjYlQUpjf70GiX+CXn3VBmpwFDxUTlmtUN84c=
github.com/pulumi/inflector v0.1.1 h1:dvlxlWtXwOJTUUtcYDvwnl6Mpg33prhK+7mzeF+SobA=
github.com/pulumi/inflector v0.1.1/go.mod h1:HUFCjcPTz96YtTuUlwG3i3EZG4WlniBvR9bd+iJxCUY=
github.com/pulumi/pulumi/pkg/v3 v3.121.0 h1:cLUQJYGJKfgCY0ubJo8dVwmsIm2WcgTprb9Orc/yiFg=
github.com/pulumi/pulumi/pkg/v3 v3.121.0/go.mod h1:aaRixfKOh4DhGtuDJcI56dTPkb7oJBgRgH1aMF1FzbU=
github.com/pulumi/pulumi/sdk/v3 v3.121.0 h1:UsnFKIVOtJN/hQKPkWHL9cZktewPVQRbNUXbXQY/qrk=
github.com/pulumi/pulumi/sdk/v3 v3.121.0/go.mod h1:p1U24en3zt51agx+WlNboSOV8eLlPWYAkxMzVEXKbnY=
github.com/pulumi/pulumi/pkg/v3 v3.123.1-0.20240711160144-b8226b705890 h1:fx6UbtFWpsm3Hls6bJ5gzO1EfAbAurmVnLBe94e89ho=
github.com/pulumi/pulumi/pkg/v3 v3.123.1-0.20240711160144-b8226b705890/go.mod h1:Tjrtb9HuGLvPHagkh/oIx7R+KFcnTzsfYIOEiYP54I4=
github.com/pulumi/pulumi/sdk/v3 v3.123.1-0.20240711160144-b8226b705890 h1:CBiyYJ+vERIeud6v8649a/VbU0sPGTmUAtJRovGW6Wc=
github.com/pulumi/pulumi/sdk/v3 v3.123.1-0.20240711160144-b8226b705890/go.mod h1:p1U24en3zt51agx+WlNboSOV8eLlPWYAkxMzVEXKbnY=
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
Expand Down
8 changes: 7 additions & 1 deletion pkg/pulumiyaml/analyser.go
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,10 @@ func (tc *typeCache) isAssignable(fromExpr ast.Expr, to schema.Type) *notAssigna
return nil
}

if from == schema.AnyType || to == schema.AnyType {
return nil
}

dispType := func(t schema.Type) string {
var maybeType string
if schema.IsPrimitiveType(from) {
Expand Down Expand Up @@ -270,9 +274,11 @@ func (tc *typeCache) isAssignable(fromExpr ast.Expr, to schema.Type) *notAssigna
return okIf(len(reasons) == 0).Because(reasons...)

case *schema.TokenType:
underlying := schema.AnyType
var underlying schema.Type
if from.UnderlyingType != nil {
underlying = from.UnderlyingType
} else {
return fail
}
check := isAssignable(underlying, to)
return okIfAssignable(check).WithReason(". '%s' is a Token Type. Token types act like their underlying type", displayType(from))
Expand Down
16 changes: 8 additions & 8 deletions pkg/pulumiyaml/analyser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,7 @@ func TestTypeError(t *testing.T) {
},
message: `Cannot assign '{prop1: asset, prop3: any}' to '{prop1: archive, prop2: boolean, prop3: string}':
prop1: Cannot assign type 'asset' to type 'archive'
prop2: Missing required property 'prop2'
prop3: Cannot assign type 'any' to type 'string'`,
prop2: Missing required property 'prop2'`,
},

// Token Types:
Expand All @@ -126,10 +125,9 @@ func TestTypeError(t *testing.T) {
},
{
// Token types are assignable to the 'any' type, and no other type
from: &schema.TokenType{Token: "foo"},
to: schema.StringType,
message: `Cannot assign 'foo<type = any>' to 'string'. 'foo<type = any>' is a Token Type. Token types act like their underlying type:
Cannot assign type 'any' to type 'string'`,
from: &schema.TokenType{Token: "foo"},
to: schema.StringType,
message: `Cannot assign 'foo<type = any>' to 'string'`,
},
{
// Token types are assignable to their underlying types
Expand Down Expand Up @@ -213,8 +211,10 @@ func TestTypeError(t *testing.T) {
t.Logf("err: %s", result.Error())
}
} else {
require.Error(t, result)
assert.Equal(t, c.message, result.String())
require.Error(t, result, fmt.Sprintf("Expected error %q, no error", c.message))
if result != nil {
assert.Equal(t, c.message, result.String())
}
}
})
}
Expand Down
68 changes: 67 additions & 1 deletion pkg/pulumiyaml/run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ type MockPackageLoader struct {
}

func (m MockPackageLoader) LoadPackage(name string, version *semver.Version) (Package, error) {
if name == "pulumi" {
return resourcePackage{schema.DefaultPulumiPackage.Reference()}, nil
}

if version != nil {
// See if there is a version specific package
if pkg, found := m.packages[name+"@"+version.String()]; found {
Expand Down Expand Up @@ -196,7 +200,13 @@ func newMockPackageMap() PackageLoader {
},
},
}

case "test:resource:with-list-input":
return inputProperties("test:resource:not-run", schema.Property{
Name: "listInput",
Type: &schema.ArrayType{
ElementType: schema.StringType,
},
})
default:
return inputProperties(typeName)
}
Expand Down Expand Up @@ -2270,6 +2280,62 @@ func TestHandleUnknownPropertiesDuringPreview(t *testing.T) {
assert.NoError(t, err)
}

func TestStackReferenceOutputs(t *testing.T) {
t.Parallel()

text := `
name: test-alias
runtime: yaml
resources:
ref:
type: pulumi:pulumi:StackReference
properties:
name: any
sec:
type: test:resource:with-list-input
properties:
listInput: ${ref.outputs["listOutput"]}
`
tmpl := yamlTemplate(t, strings.TrimSpace(text))
mocks := &testMonitor{
NewResourceF: func(args pulumi.MockResourceArgs) (string, resource.PropertyMap, error) {
t.Logf("args: %+v", args)

if args.TypeToken == "pulumi:pulumi:StackReference" {
assert.Equal(t, "ref", args.Name)
return "ref", resource.PropertyMap{
"outputs": resource.NewObjectProperty(resource.NewPropertyMapFromMap(map[string]any{
"listOutput": []string{"foo", "bar"},
})),
}, nil
} else if args.TypeToken == "test:resource:with-list-input" {
assert.Equal(t, "sec", args.Name)
assert.Equal(t,
resource.NewArrayProperty([]resource.PropertyValue{resource.NewStringProperty("foo"), resource.NewStringProperty("bar")}),
args.Inputs["listInput"])
return "sec", args.Inputs, nil
}

t.Fatalf("unexpected type token: %s", args.TypeToken)

return args.Name, args.Inputs, nil
},
}
err := pulumi.RunErr(func(ctx *pulumi.Context) error {
runner := newRunner(tmpl, newMockPackageMap())
_, diags := TypeCheck(runner)
if diags.HasErrors() {
return diags
}
err := runner.Evaluate(ctx)
assert.Len(t, err, 0)
assert.Equal(t, err.Error(), "no diagnostics")

return nil
}, pulumi.WithMocks("project", "stack", mocks))
assert.NoError(t, err)
}

type mockLateboundResource struct {
resourceSchema *schema.Resource
}
Expand Down

0 comments on commit 021ac5e

Please sign in to comment.