diff --git a/pkg/backend/snapshot_test.go b/pkg/backend/snapshot_test.go index 8ca3e53e9..f514d6056 100644 --- a/pkg/backend/snapshot_test.go +++ b/pkg/backend/snapshot_test.go @@ -18,11 +18,12 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" + "github.com/pulumi/pulumi/pkg/resource" "github.com/pulumi/pulumi/pkg/resource/deploy" "github.com/pulumi/pulumi/pkg/tokens" "github.com/pulumi/pulumi/pkg/version" - "github.com/stretchr/testify/assert" ) type MockRegisterResourceEvent struct { diff --git a/sdk/go/pulumi/properties.go b/sdk/go/pulumi/properties.go index 8162e5660..070bcbdd7 100644 --- a/sdk/go/pulumi/properties.go +++ b/sdk/go/pulumi/properties.go @@ -109,6 +109,42 @@ func (out *Output) Value() (interface{}, error) { return out.voe.value, out.voe.err } +// Array retrives the underlying value for this output property as an array. +func (out *Output) Array() ([]interface{}, error) { + v, err := out.Value() + if err != nil { + return nil, err + } + return v.([]interface{}), nil +} + +// Bool retrives the underlying value for this output property as a bool. +func (out *Output) Bool() (bool, error) { + v, err := out.Value() + if err != nil { + return false, err + } + return v.(bool), nil +} + +// Map retrives the underlying value for this output property as a map. +func (out *Output) Map() (map[string]interface{}, error) { + v, err := out.Value() + if err != nil { + return nil, err + } + return v.(map[string]interface{}), nil +} + +// Number retrives the underlying value for this output property as a number. +func (out *Output) Number() (float64, error) { + v, err := out.Value() + if err != nil { + return 0, err + } + return v.(float64), nil +} + // String retrives the underlying value for this output property as a string. func (out *Output) String() (string, error) { v, err := out.Value() @@ -138,3 +174,33 @@ func (out *Output) URN() (URN, error) { // Outputs is a map of property name to value, one for each resource output property. type Outputs map[string]*Output + +// ArrayOutput is an Output that is typed to return arrays of values. +type ArrayOutput Output + +// Value returns the underlying array value. +func (out *ArrayOutput) Value() ([]interface{}, error) { return (*Output)(out).Array() } + +// BoolOutput is an Output that is typed to return bool values. +type BoolOutput Output + +// Value returns the underlying bool value. +func (out *BoolOutput) Value() (bool, error) { return (*Output)(out).Bool() } + +// MapOutput is an Output that is typed to return string-keyed maps of values. +type MapOutput Output + +// Value returns the underlying map value. +func (out *MapOutput) Value() (map[string]interface{}, error) { return (*Output)(out).Map() } + +// NumberOutput is an Output that is typed to return number values. +type NumberOutput Output + +// Value returns the underlying number value. +func (out *NumberOutput) Value() (float64, error) { return (*Output)(out).Number() } + +// StringOutput is an Output that is typed to return number values. +type StringOutput Output + +// Value returns the underlying number value. +func (out *StringOutput) Value() (string, error) { return (*Output)(out).String() } diff --git a/sdk/go/pulumi/properties_test.go b/sdk/go/pulumi/properties_test.go new file mode 100644 index 000000000..41ebee2fa --- /dev/null +++ b/sdk/go/pulumi/properties_test.go @@ -0,0 +1,155 @@ +// Copyright 2016-2018, Pulumi Corporation. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package pulumi + +import ( + "testing" + + "github.com/pkg/errors" + "github.com/stretchr/testify/assert" +) + +func TestBasicOutputs(t *testing.T) { + // Just test basic resolve and reject functionality. + { + out, resolve, _ := NewOutput(nil) + go func() { + resolve(42) + }() + v, err := out.Value() + assert.Nil(t, err) + assert.NotNil(t, v) + assert.Equal(t, 42, v.(int)) + } + { + out, _, reject := NewOutput(nil) + go func() { + reject(errors.New("boom")) + }() + v, err := out.Value() + assert.NotNil(t, err) + assert.Nil(t, v) + } +} + +func TestArrayOutputs(t *testing.T) { + out, resolve, _ := NewOutput(nil) + go func() { + resolve([]interface{}{nil, 0, "x"}) + }() + { + v, err := out.Array() + assert.Nil(t, err) + assert.NotNil(t, v) + if assert.Equal(t, 3, len(v)) { + assert.Equal(t, nil, v[0]) + assert.Equal(t, 0, v[1]) + assert.Equal(t, "x", v[2]) + } + } + { + arr := (*ArrayOutput)(out) + v, err := arr.Value() + assert.Nil(t, err) + assert.NotNil(t, v) + if assert.Equal(t, 3, len(v)) { + assert.Equal(t, nil, v[0]) + assert.Equal(t, 0, v[1]) + assert.Equal(t, "x", v[2]) + } + } +} + +func TestBoolOutputs(t *testing.T) { + out, resolve, _ := NewOutput(nil) + go func() { + resolve(true) + }() + { + v, err := out.Bool() + assert.Nil(t, err) + assert.True(t, v) + } + { + b := (*BoolOutput)(out) + v, err := b.Value() + assert.Nil(t, err) + assert.True(t, v) + } +} + +func TestMapOutputs(t *testing.T) { + out, resolve, _ := NewOutput(nil) + go func() { + resolve(map[string]interface{}{ + "x": 1, + "y": false, + "z": "abc", + }) + }() + { + v, err := out.Map() + assert.Nil(t, err) + assert.NotNil(t, v) + assert.Equal(t, 1, v["x"]) + assert.Equal(t, false, v["y"]) + assert.Equal(t, "abc", v["z"]) + } + { + b := (*MapOutput)(out) + v, err := b.Value() + assert.Nil(t, err) + assert.NotNil(t, v) + assert.Equal(t, 1, v["x"]) + assert.Equal(t, false, v["y"]) + assert.Equal(t, "abc", v["z"]) + } +} + +func TestNumberOutputs(t *testing.T) { + out, resolve, _ := NewOutput(nil) + go func() { + resolve(42.345) + }() + { + v, err := out.Number() + assert.Nil(t, err) + assert.Equal(t, 42.345, v) + } + { + b := (*NumberOutput)(out) + v, err := b.Value() + assert.Nil(t, err) + assert.Equal(t, 42.345, v) + } +} + +func TestStringOutputs(t *testing.T) { + out, resolve, _ := NewOutput(nil) + go func() { + resolve("a stringy output") + }() + { + v, err := out.String() + assert.Nil(t, err) + assert.Equal(t, "a stringy output", v) + } + { + b := (*StringOutput)(out) + v, err := b.Value() + assert.Nil(t, err) + assert.Equal(t, "a stringy output", v) + } +}