Tests + nil check

This commit is contained in:
Ian Wahbe 2021-11-23 13:33:22 -08:00
parent a4bdec7ff7
commit 67132f947c
8 changed files with 168 additions and 19 deletions

View file

@ -1494,6 +1494,7 @@ func (pkg *pkgContext) genResource(w io.Writer, r *schema.Resource, generateReso
fmt.Fprintf(w, "\t}\n")
} else if name := pkg.provideDefaultsFuncName(p.Type); name != "" && !pkg.disableObjectDefaults {
var value string
var needsNilCheck bool
if codegen.IsNOptionalInput(p.Type) {
innerFuncType := strings.TrimSuffix(pkg.typeString(codegen.UnwrapType(p.Type)), "Args")
applyName := fmt.Sprintf("%sApplier", camel(p.Name))
@ -1504,11 +1505,29 @@ func (pkg *pkgContext) genResource(w io.Writer, r *schema.Resource, generateReso
if strings.HasSuffix(outputType, "Input") {
outputType = strings.TrimSuffix(outputType, "Input") + "Output"
}
value = fmt.Sprintf("%s.ApplyT(%s).(%s)", outputValue, applyName, outputType)
// Because applies return pointers, we need to convert to PtrOutput and then call .Elem().
var tail string
if !strings.HasSuffix(outputType, "PtrOutput") {
outputType = strings.TrimSuffix(outputType, "Output") + "PtrOutput"
tail = ".Elem()"
}
needsNilCheck = !p.IsRequired()
value = fmt.Sprintf("%s.ApplyT(%s).(%s)%s", outputValue, applyName, outputType, tail)
} else {
value = fmt.Sprintf("args.%[1]s.%[2]s()", Title(p.Name), name)
}
fmt.Fprintf(w, "args.%[1]s = %s\n", Title(p.Name), value)
v := func() {
fmt.Fprintf(w, "args.%[1]s = %s\n", Title(p.Name), value)
}
if needsNilCheck {
fmt.Fprintf(w, "if args.%s != nil {\n", Title(p.Name))
v()
fmt.Fprint(w, "}\n")
} else {
v()
}
}
}

View file

@ -30,7 +30,9 @@ func NewRubberTree(ctx *pulumi.Context,
}
containerApplier := func(v plantprovider.Container) *plantprovider.Container { return v.Defaults() }
args.Container = args.Container.ToContainerPtrOutput().Elem().ApplyT(containerApplier).(plantprovider.ContainerPtrOutput)
if args.Container != nil {
args.Container = args.Container.ToContainerPtrOutput().Elem().ApplyT(containerApplier).(plantprovider.ContainerPtrOutput)
}
if isZero(args.Diameter) {
args.Diameter = Diameter(6.0)
}

View file

@ -35,8 +35,8 @@ func (mocks) NewResource(args pulumi.MockResourceArgs) (string, resource.Propert
}
func (mocks) Call(args pulumi.MockCallArgs) (resource.PropertyMap, error) {
if args.Token == "mypkg::listStorageAccountKeys" {
switch args.Token {
case "mypkg::listStorageAccountKeys":
targs := mypkg.ListStorageAccountKeysArgs{}
for k, v := range args.Args {
switch k {
@ -72,12 +72,11 @@ func (mocks) Call(args pulumi.MockCallArgs) (resource.PropertyMap, error) {
"keys": result.Keys,
}
return resource.NewPropertyMapFromMap(outputs), nil
}
if args.Token == "mypkg::funcWithDefaultValue" ||
args.Token == "mypkg::funcWithAllOptionalInputs" ||
args.Token == "mypkg::funcWithListParam" ||
args.Token == "mypkg::funcWithDictParam" {
case "mypkg::funcWithDefaultValue",
"mypkg::funcWithAllOptionalInputs",
"mypkg::funcWithListParam",
"mypkg::funcWithDictParam":
result := mypkg.FuncWithDefaultValueResult{
R: fmt.Sprintf("%v", args.Args),
}
@ -85,9 +84,8 @@ func (mocks) Call(args pulumi.MockCallArgs) (resource.PropertyMap, error) {
"r": result.R,
}
return resource.NewPropertyMapFromMap(outputs), nil
}
if args.Token == "mypkg::getIntegrationRuntimeObjectMetadatum" {
case "mypkg::getIntegrationRuntimeObjectMetadatum":
targs := mypkg.GetIntegrationRuntimeObjectMetadatumArgs{}
for k, v := range args.Args {
switch k {

View file

@ -0,0 +1,118 @@
// Copyright 2016-2021, 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 codegentest
import (
"fmt"
"os"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/pulumi/pulumi/sdk/v3/go/common/resource"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
"plain-object-defaults/example"
)
type mocks int
// We assert that default values were passed to our constuctor
func (mocks) NewResource(args pulumi.MockResourceArgs) (string, resource.PropertyMap, error) {
checkFloat64 := func(v resource.PropertyValue, k string, expected float64) {
m := v.V.(resource.PropertyMap)
if m[resource.PropertyKey(k)].V.(float64) != expected {
panic(fmt.Sprintf("Expected %s to have value %.2f", k, expected))
}
}
for k, v := range args.Inputs {
switch k {
case "kubeClientSettings":
checkFloat64(v, "burst", 42)
case "backupKubeClientSettings":
checkFloat64(v, "qps", 7)
}
}
return args.Name, args.Inputs.Copy(), nil
}
func (mocks) Call(args pulumi.MockCallArgs) (resource.PropertyMap, error) {
panic("Call not supported")
}
func TestObjectDefaults(t *testing.T) {
path := "thePath"
defaultDriver := "secret"
kcs := example.HelmReleaseSettings{
PluginsPath: &path,
RequiredArg: "This is required",
}
withDefaults := kcs.Defaults()
assert.Equal(t, kcs.RequiredArg, withDefaults.RequiredArg)
assert.Equal(t, kcs.PluginsPath, withDefaults.PluginsPath)
assert.Nil(t, kcs.Driver)
assert.Equal(t, withDefaults.Driver, &defaultDriver)
}
func TestTransitiveObjectDefaults(t *testing.T) {
layered := example.LayeredType{
Other: example.HelmReleaseSettings{},
}
withDefaults := layered.Defaults()
assert.Equal(t, "secret", *withDefaults.Other.Driver)
}
// We already have that defaults for resources. We test that they translate through objects.
func TestDefaultResource(t *testing.T) {
os.Setenv("PULUMI_K8S_CLIENT_BURST", "42")
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := example.NewFoo(ctx, "foo", &example.FooArgs{
KubeClientSettings: example.KubeClientSettingsPtr(&example.KubeClientSettingsArgs{}),
BackupKubeClientSettings: &example.KubeClientSettingsArgs{Qps: pulumi.Float64(7)},
})
assert.NoError(t, err)
return nil
}, pulumi.WithMocks("example", "stack", mocks(0)))
}
func waitOut(t *testing.T, output pulumi.Output) interface{} {
result, err := waitOutput(output, 1*time.Second)
if err != nil {
t.Error(err)
return nil
}
return result
}
func waitOutput(output pulumi.Output, timeout time.Duration) (interface{}, error) {
c := make(chan interface{}, 2)
output.ApplyT(func(v interface{}) interface{} {
c <- v
return v
})
var timeoutMarker *int = new(int)
go func() {
time.Sleep(timeout)
c <- timeoutMarker
}()
result := <-c
if result == timeoutMarker {
return nil, fmt.Errorf("Timed out waiting for pulumi.Output after %v", timeout)
} else {
return result, nil
}
}

View file

@ -30,11 +30,15 @@ func NewFoo(ctx *pulumi.Context,
return nil, errors.New("invalid value for required argument 'BackupKubeClientSettings'")
}
backupKubeClientSettingsApplier := func(v KubeClientSettings) *KubeClientSettings { return v.Defaults() }
args.BackupKubeClientSettings = args.BackupKubeClientSettings.ToKubeClientSettingsOutput().ApplyT(backupKubeClientSettingsApplier).(KubeClientSettingsOutput)
args.BackupKubeClientSettings = args.BackupKubeClientSettings.ToKubeClientSettingsOutput().ApplyT(backupKubeClientSettingsApplier).(KubeClientSettingsPtrOutput).Elem()
kubeClientSettingsApplier := func(v KubeClientSettings) *KubeClientSettings { return v.Defaults() }
args.KubeClientSettings = args.KubeClientSettings.ToKubeClientSettingsPtrOutput().Elem().ApplyT(kubeClientSettingsApplier).(KubeClientSettingsPtrOutput)
if args.KubeClientSettings != nil {
args.KubeClientSettings = args.KubeClientSettings.ToKubeClientSettingsPtrOutput().Elem().ApplyT(kubeClientSettingsApplier).(KubeClientSettingsPtrOutput)
}
settingsApplier := func(v LayeredType) *LayeredType { return v.Defaults() }
args.Settings = args.Settings.ToLayeredTypePtrOutput().Elem().ApplyT(settingsApplier).(LayeredTypePtrOutput)
if args.Settings != nil {
args.Settings = args.Settings.ToLayeredTypePtrOutput().Elem().ApplyT(settingsApplier).(LayeredTypePtrOutput)
}
var resource Foo
err := ctx.RegisterResource("example:index:Foo", name, args, &resource, opts...)
if err != nil {

View file

@ -23,9 +23,13 @@ func NewModuleTest(ctx *pulumi.Context,
}
mod1Applier := func(v mod1.Typ) *mod1.Typ { return v.Defaults() }
args.Mod1 = args.Mod1.ToTypPtrOutput().Elem().ApplyT(mod1Applier).(mod1.TypPtrOutput)
if args.Mod1 != nil {
args.Mod1 = args.Mod1.ToTypPtrOutput().Elem().ApplyT(mod1Applier).(mod1.TypPtrOutput)
}
valApplier := func(v Typ) *Typ { return v.Defaults() }
args.Val = args.Val.ToTypPtrOutput().Elem().ApplyT(valApplier).(TypPtrOutput)
if args.Val != nil {
args.Val = args.Val.ToTypPtrOutput().Elem().ApplyT(valApplier).(TypPtrOutput)
}
var resource ModuleTest
err := ctx.RegisterResource("example:index:moduleTest", name, args, &resource, opts...)
if err != nil {

View file

@ -23,7 +23,9 @@ func NewProvider(ctx *pulumi.Context,
}
helmReleaseSettingsApplier := func(v HelmReleaseSettings) *HelmReleaseSettings { return v.Defaults() }
args.HelmReleaseSettings = args.HelmReleaseSettings.ToHelmReleaseSettingsPtrOutput().Elem().ApplyT(helmReleaseSettingsApplier).(HelmReleaseSettingsPtrOutput)
if args.HelmReleaseSettings != nil {
args.HelmReleaseSettings = args.HelmReleaseSettings.ToHelmReleaseSettingsPtrOutput().Elem().ApplyT(helmReleaseSettingsApplier).(HelmReleaseSettingsPtrOutput)
}
var resource Provider
err := ctx.RegisterResource("pulumi:providers:example", name, args, &resource, opts...)
if err != nil {

View file

@ -30,7 +30,9 @@ func NewRubberTree(ctx *pulumi.Context,
}
containerApplier := func(v plant.Container) *plant.Container { return v.Defaults() }
args.Container = args.Container.ToContainerPtrOutput().Elem().ApplyT(containerApplier).(plant.ContainerPtrOutput)
if args.Container != nil {
args.Container = args.Container.ToContainerPtrOutput().Elem().ApplyT(containerApplier).(plant.ContainerPtrOutput)
}
if isZero(args.Diameter) {
args.Diameter = Diameter(6.0)
}