// 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 plugin import ( "fmt" "runtime" "testing" structpb "github.com/golang/protobuf/ptypes/struct" "github.com/stretchr/testify/assert" "github.com/pulumi/pulumi/sdk/v2/go/common/resource" "github.com/pulumi/pulumi/sdk/v2/go/common/util/contract" ) func setProperty(s *structpb.Value, k string, v interface{}) { marshaled, err := MarshalPropertyValue(resource.NewPropertyValue(v), MarshalOptions{}) contract.Assert(err == nil) s.GetStructValue().Fields[k] = marshaled } func TestAssetSerialize(t *testing.T) { // Ensure that asset and archive serialization round trips. text := "a test asset" asset, err := resource.NewTextAsset(text) assert.Nil(t, err) assert.Equal(t, text, asset.Text) assert.Equal(t, "e34c74529110661faae4e121e57165ff4cb4dbdde1ef9770098aa3695e6b6704", asset.Hash) assetProps, err := MarshalPropertyValue(resource.NewAssetProperty(asset), MarshalOptions{}) assert.Nil(t, err) fmt.Printf("%v\n", assetProps) assetValue, err := UnmarshalPropertyValue(assetProps, MarshalOptions{}) assert.Nil(t, err) assert.True(t, assetValue.IsAsset()) assetDes := assetValue.AssetValue() assert.True(t, assetDes.IsText()) assert.Equal(t, text, assetDes.Text) assert.Equal(t, "e34c74529110661faae4e121e57165ff4cb4dbdde1ef9770098aa3695e6b6704", assetDes.Hash) // Ensure that an invalid asset produces an error. setProperty(assetProps, resource.AssetHashProperty, 0) _, err = UnmarshalPropertyValue(assetProps, MarshalOptions{}) assert.Error(t, err) setProperty(assetProps, resource.AssetHashProperty, asset.Hash) setProperty(assetProps, resource.AssetTextProperty, 0) _, err = UnmarshalPropertyValue(assetProps, MarshalOptions{}) assert.Error(t, err) setProperty(assetProps, resource.AssetTextProperty, "") setProperty(assetProps, resource.AssetPathProperty, 0) _, err = UnmarshalPropertyValue(assetProps, MarshalOptions{}) assert.Error(t, err) setProperty(assetProps, resource.AssetPathProperty, "") setProperty(assetProps, resource.AssetURIProperty, 0) _, err = UnmarshalPropertyValue(assetProps, MarshalOptions{}) assert.Error(t, err) setProperty(assetProps, resource.AssetURIProperty, "") arch, err := resource.NewAssetArchive(map[string]interface{}{"foo": asset}) assert.Nil(t, err) switch runtime.Version() { case "go1.9": assert.Equal(t, "d8ce0142b3b10300c7c76487fad770f794c1e84e1b0c73a4b2e1503d4fbac093", arch.Hash) default: // Go 1.10 introduced breaking changes to archive/zip and archive/tar headers assert.Equal(t, "27ab4a14a617df10cff3e1cf4e30cf510302afe56bf4cc91f84041c9f7b62fd8", arch.Hash) } archProps, err := MarshalPropertyValue(resource.NewArchiveProperty(arch), MarshalOptions{}) assert.Nil(t, err) archValue, err := UnmarshalPropertyValue(archProps, MarshalOptions{}) assert.Nil(t, err) assert.True(t, archValue.IsArchive()) archDes := archValue.ArchiveValue() assert.True(t, archDes.IsAssets()) assert.Equal(t, 1, len(archDes.Assets)) assert.True(t, archDes.Assets["foo"].(*resource.Asset).IsText()) assert.Equal(t, text, archDes.Assets["foo"].(*resource.Asset).Text) switch runtime.Version() { case "go1.9": assert.Equal(t, "d8ce0142b3b10300c7c76487fad770f794c1e84e1b0c73a4b2e1503d4fbac093", archDes.Hash) default: // Go 1.10 introduced breaking changes to archive/zip and archive/tar headers assert.Equal(t, "27ab4a14a617df10cff3e1cf4e30cf510302afe56bf4cc91f84041c9f7b62fd8", archDes.Hash) } // Ensure that an invalid archive produces an error. setProperty(archProps, resource.ArchiveHashProperty, 0) _, err = UnmarshalPropertyValue(archProps, MarshalOptions{}) assert.Error(t, err) setProperty(archProps, resource.ArchiveHashProperty, arch.Hash) setProperty(archProps, resource.ArchiveAssetsProperty, 0) _, err = UnmarshalPropertyValue(archProps, MarshalOptions{}) assert.Error(t, err) setProperty(archProps, resource.ArchiveAssetsProperty, nil) setProperty(archProps, resource.ArchivePathProperty, 0) _, err = UnmarshalPropertyValue(archProps, MarshalOptions{}) assert.Error(t, err) setProperty(archProps, resource.ArchivePathProperty, "") setProperty(archProps, resource.ArchiveURIProperty, 0) _, err = UnmarshalPropertyValue(archProps, MarshalOptions{}) assert.Error(t, err) setProperty(archProps, resource.ArchiveURIProperty, "") } func TestComputedSerialize(t *testing.T) { // Ensure that computed properties survive round trips. opts := MarshalOptions{KeepUnknowns: true} { cprop, err := MarshalPropertyValue( resource.NewComputedProperty( resource.Computed{Element: resource.NewStringProperty("")}), opts) assert.Nil(t, err) cpropU, err := UnmarshalPropertyValue(cprop, opts) assert.Nil(t, err) assert.True(t, cpropU.IsComputed()) assert.True(t, cpropU.Input().Element.IsString()) } { cprop, err := MarshalPropertyValue( resource.NewComputedProperty( resource.Computed{Element: resource.NewNumberProperty(0)}), opts) assert.Nil(t, err) cpropU, err := UnmarshalPropertyValue(cprop, opts) assert.Nil(t, err) assert.True(t, cpropU.IsComputed()) assert.True(t, cpropU.Input().Element.IsNumber()) } } func TestComputedSkip(t *testing.T) { // Ensure that computed properties are skipped when KeepUnknowns == false. opts := MarshalOptions{KeepUnknowns: false} { cprop, err := MarshalPropertyValue( resource.NewComputedProperty( resource.Computed{Element: resource.NewStringProperty("")}), opts) assert.Nil(t, err) assert.Nil(t, cprop) } { cprop, err := MarshalPropertyValue( resource.NewComputedProperty( resource.Computed{Element: resource.NewNumberProperty(0)}), opts) assert.Nil(t, err) assert.Nil(t, cprop) } } func TestComputedReject(t *testing.T) { // Ensure that computed properties produce errors when RejectUnknowns == true. opts := MarshalOptions{RejectUnknowns: true} { cprop, err := MarshalPropertyValue( resource.NewComputedProperty( resource.Computed{Element: resource.NewStringProperty("")}), opts) assert.NotNil(t, err) assert.Nil(t, cprop) } { cprop, err := MarshalPropertyValue( resource.NewComputedProperty( resource.Computed{Element: resource.NewStringProperty("")}), MarshalOptions{KeepUnknowns: true}) assert.Nil(t, err) cpropU, err := UnmarshalPropertyValue(cprop, opts) assert.NotNil(t, err) assert.Nil(t, cpropU) } } func TestAssetReject(t *testing.T) { // Ensure that asset and archive properties produce errors when RejectAssets == true. opts := MarshalOptions{RejectAssets: true} text := "a test asset" asset, err := resource.NewTextAsset(text) assert.Nil(t, err) { assetProps, err := MarshalPropertyValue(resource.NewAssetProperty(asset), opts) assert.NotNil(t, err) assert.Nil(t, assetProps) } { assetProps, err := MarshalPropertyValue(resource.NewAssetProperty(asset), MarshalOptions{}) assert.Nil(t, err) assetPropU, err := UnmarshalPropertyValue(assetProps, opts) assert.NotNil(t, err) assert.Nil(t, assetPropU) } arch, err := resource.NewAssetArchive(map[string]interface{}{"foo": asset}) assert.Nil(t, err) { archProps, err := MarshalPropertyValue(resource.NewArchiveProperty(arch), opts) assert.NotNil(t, err) assert.Nil(t, archProps) } { archProps, err := MarshalPropertyValue(resource.NewArchiveProperty(arch), MarshalOptions{}) assert.Nil(t, err) archValue, err := UnmarshalPropertyValue(archProps, opts) assert.NotNil(t, err) assert.Nil(t, archValue) } } func TestUnsupportedSecret(t *testing.T) { rawProp := resource.NewObjectProperty(resource.NewPropertyMapFromMap(map[string]interface{}{ resource.SigKey: resource.SecretSig, "value": "foo", })) prop, err := MarshalPropertyValue(rawProp, MarshalOptions{}) assert.Nil(t, err) val, err := UnmarshalPropertyValue(prop, MarshalOptions{}) assert.Nil(t, err) assert.True(t, val.IsString()) assert.False(t, val.IsSecret()) assert.Equal(t, "foo", val.StringValue()) } func TestSupportedSecret(t *testing.T) { rawProp := resource.NewObjectProperty(resource.NewPropertyMapFromMap(map[string]interface{}{ resource.SigKey: resource.SecretSig, "value": "foo", })) prop, err := MarshalPropertyValue(rawProp, MarshalOptions{KeepSecrets: true}) assert.Nil(t, err) val, err := UnmarshalPropertyValue(prop, MarshalOptions{KeepSecrets: true}) assert.Nil(t, err) assert.False(t, val.IsString()) assert.True(t, val.IsSecret()) assert.Equal(t, "foo", val.SecretValue().Element.StringValue()) } func TestUnknownSig(t *testing.T) { rawProp := resource.NewObjectProperty(resource.NewPropertyMapFromMap(map[string]interface{}{ resource.SigKey: "foobar", })) prop, err := MarshalPropertyValue(rawProp, MarshalOptions{}) assert.Nil(t, err) _, err = UnmarshalPropertyValue(prop, MarshalOptions{}) assert.Error(t, err) } func TestSkipInternalKeys(t *testing.T) { opts := MarshalOptions{SkipInternalKeys: true} expected := &structpb.Struct{ Fields: map[string]*structpb.Value{ "keepers": { Kind: &structpb.Value_StructValue{ StructValue: &structpb.Struct{ Fields: map[string]*structpb.Value{}, }, }, }, }, } props := resource.NewPropertyMapFromMap(map[string]interface{}{ "__defaults": []string{}, "keepers": map[string]interface{}{ "__defaults": []string{}, }, }) actual, err := MarshalProperties(props, opts) assert.NoError(t, err) assert.Equal(t, expected, actual) } func TestResourceReference(t *testing.T) { // Test round-trip opts := MarshalOptions{KeepResources: true} rawProp := resource.MakeCustomResourceReference("fakeURN", "fakeID", "fakeVersion") prop, err := MarshalPropertyValue(rawProp, opts) assert.NoError(t, err) actual, err := UnmarshalPropertyValue(prop, opts) assert.NoError(t, err) assert.Equal(t, rawProp, *actual) // Test unmarshaling as an ID opts.KeepResources = false actual, err = UnmarshalPropertyValue(prop, opts) assert.NoError(t, err) assert.Equal(t, resource.NewStringProperty(rawProp.ResourceReferenceValue().ID.StringValue()), *actual) // Test marshaling as an ID prop, err = MarshalPropertyValue(rawProp, opts) assert.NoError(t, err) opts.KeepResources = true actual, err = UnmarshalPropertyValue(prop, opts) assert.NoError(t, err) assert.Equal(t, resource.NewStringProperty(rawProp.ResourceReferenceValue().ID.StringValue()), *actual) // Test unmarshaling as a URN rawProp = resource.MakeComponentResourceReference("fakeURN", "fakeVersion") prop, err = MarshalPropertyValue(rawProp, opts) assert.NoError(t, err) opts.KeepResources = false actual, err = UnmarshalPropertyValue(prop, opts) assert.NoError(t, err) assert.Equal(t, resource.NewStringProperty(string(rawProp.ResourceReferenceValue().URN)), *actual) // Test marshaling as a URN prop, err = MarshalPropertyValue(rawProp, opts) assert.NoError(t, err) opts.KeepResources = true actual, err = UnmarshalPropertyValue(prop, opts) assert.NoError(t, err) assert.Equal(t, resource.NewStringProperty(string(rawProp.ResourceReferenceValue().URN)), *actual) }