pulumi/sdk/go/auto/local_workspace_test.go
Ian Wahbe 83e24765f3
.NET & python SDKs parity for bad pulumi versions (#8297)
* .NET & python SDKs parity for bad pulumi versions

They handle invalid Pulumi CLI version gracefully.

* Make python version property lazy

* Clarify .NET logic

* Add python test for validate_pulumi_version

* Add tests for invalid versions

* Fix python test

* Fix typo

* Fix tests

* Have _validate_pulumi_version handle parsing

* Modify python and .NET to parseAndValidate

* Modify typescript and go to parseAndValidate

* fix name
2021-10-27 20:54:23 -07:00

2360 lines
70 KiB
Go

// 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 auto
import (
"bytes"
"context"
"fmt"
"math/rand"
"os"
"os/exec"
"path/filepath"
"regexp"
"strings"
"testing"
"time"
"github.com/stretchr/testify/require"
"github.com/blang/semver"
"github.com/stretchr/testify/assert"
"github.com/pulumi/pulumi/sdk/v3/go/auto/events"
"github.com/pulumi/pulumi/sdk/v3/go/auto/optdestroy"
"github.com/pulumi/pulumi/sdk/v3/go/auto/optpreview"
"github.com/pulumi/pulumi/sdk/v3/go/auto/optrefresh"
"github.com/pulumi/pulumi/sdk/v3/go/auto/optremove"
"github.com/pulumi/pulumi/sdk/v3/go/auto/optup"
"github.com/pulumi/pulumi/sdk/v3/go/common/apitype"
"github.com/pulumi/pulumi/sdk/v3/go/common/tokens"
"github.com/pulumi/pulumi/sdk/v3/go/common/workspace"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi/config"
)
var pulumiOrg = getTestOrg()
const pName = "testproj"
const agent = "pulumi/pulumi/test"
func TestWorkspaceSecretsProvider(t *testing.T) {
ctx := context.Background()
sName := fmt.Sprintf("int_test%d", rangeIn(10000000, 99999999))
stackName := FullyQualifiedStackName(pulumiOrg, pName, sName)
opts := []LocalWorkspaceOption{
SecretsProvider("passphrase"),
EnvVars(map[string]string{
"PULUMI_CONFIG_PASSPHRASE": "password",
}),
}
// initialize
s, err := NewStackInlineSource(ctx, stackName, pName, func(ctx *pulumi.Context) error {
c := config.New(ctx, "")
ctx.Export("exp_static", pulumi.String("foo"))
ctx.Export("exp_cfg", pulumi.String(c.Get("bar")))
ctx.Export("exp_secret", c.GetSecret("buzz"))
return nil
}, opts...)
if err != nil {
t.Errorf("failed to initialize stack, err: %v", err)
t.FailNow()
}
defer func() {
err := os.Unsetenv("PULUMI_CONFIG_PASSPHRASE")
assert.Nil(t, err, "failed to unset EnvVar.")
// -- pulumi stack rm --
err = s.Workspace().RemoveStack(ctx, s.Name())
assert.Nil(t, err, "failed to remove stack. Resources have leaked.")
}()
passwordVal := "Password1234!"
err = s.SetConfig(ctx, "MySecretDatabasePassword", ConfigValue{Value: passwordVal, Secret: true})
if err != nil {
t.Errorf("setConfig failed, err: %v", err)
t.FailNow()
}
// -- pulumi up --
res, err := s.Up(ctx)
if err != nil {
t.Errorf("up failed, err: %v", err)
t.FailNow()
}
assert.Equal(t, "update", res.Summary.Kind)
assert.Equal(t, "succeeded", res.Summary.Result)
// -- get config --
conf, err := s.GetConfig(ctx, "MySecretDatabasePassword")
if err != nil {
t.Errorf("GetConfig failed, err: %v", err)
t.FailNow()
}
assert.Equal(t, passwordVal, conf.Value)
assert.Equal(t, true, conf.Secret)
// -- pulumi destroy --
dRes, err := s.Destroy(ctx)
if err != nil {
t.Errorf("destroy failed, err: %v", err)
t.FailNow()
}
assert.Equal(t, "destroy", dRes.Summary.Kind)
assert.Equal(t, "succeeded", dRes.Summary.Result)
}
func TestRemoveWithForce(t *testing.T) {
ctx := context.Background()
sName := fmt.Sprintf("int_test%d", rangeIn(10000000, 99999999))
stackName := FullyQualifiedStackName(pulumiOrg, pName, sName)
cfg := ConfigMap{
"bar": ConfigValue{
Value: "abc",
},
"buzz": ConfigValue{
Value: "secret",
Secret: true,
},
}
// initialize
pDir := filepath.Join(".", "test", "testproj")
s, err := NewStackLocalSource(ctx, stackName, pDir)
if err != nil {
t.Errorf("failed to initialize stack, err: %v", err)
t.FailNow()
}
err = s.SetAllConfig(ctx, cfg)
if err != nil {
t.Errorf("failed to set config, err: %v", err)
t.FailNow()
}
// Set environment variables scoped to the workspace.
envvars := map[string]string{
"foo": "bar",
"barfoo": "foobar",
}
err = s.Workspace().SetEnvVars(envvars)
assert.Nil(t, err, "failed to set environment values")
envvars = s.Workspace().GetEnvVars()
assert.NotNil(t, envvars, "failed to get environment values after setting many")
s.Workspace().SetEnvVar("bar", "buzz")
envvars = s.Workspace().GetEnvVars()
assert.NotNil(t, envvars, "failed to get environment value after setting")
s.Workspace().UnsetEnvVar("bar")
envvars = s.Workspace().GetEnvVars()
assert.NotNil(t, envvars, "failed to get environment values after unsetting.")
// -- pulumi up --
res, err := s.Up(ctx)
if err != nil {
t.Errorf("up failed, err: %v", err)
t.FailNow()
}
assert.Equal(t, 3, len(res.Outputs), "expected two plain outputs")
assert.Equal(t, "foo", res.Outputs["exp_static"].Value)
assert.False(t, res.Outputs["exp_static"].Secret)
assert.Equal(t, "abc", res.Outputs["exp_cfg"].Value)
assert.False(t, res.Outputs["exp_cfg"].Secret)
assert.Equal(t, "secret", res.Outputs["exp_secret"].Value)
assert.True(t, res.Outputs["exp_secret"].Secret)
assert.Equal(t, "update", res.Summary.Kind)
assert.Equal(t, "succeeded", res.Summary.Result)
const permalinkSearchStr = "https://app.pulumi.com"
var startRegex = regexp.MustCompile(permalinkSearchStr)
permalink, err := GetPermalink(res.StdOut)
assert.Nil(t, err, "failed to get permalink.")
assert.True(t, startRegex.MatchString(permalink))
if err = s.Workspace().RemoveStack(ctx, stackName, optremove.Force()); err != nil {
t.Errorf("remove stack with force failed")
t.FailNow()
}
// to make sure stack was removed
err = s.Workspace().SelectStack(ctx, s.Name())
assert.Error(t, err)
assert.True(t, strings.Contains(err.Error(), "no stack named"))
}
func TestNewStackLocalSource(t *testing.T) {
ctx := context.Background()
sName := fmt.Sprintf("int_test%d", rangeIn(10000000, 99999999))
stackName := FullyQualifiedStackName(pulumiOrg, pName, sName)
cfg := ConfigMap{
"bar": ConfigValue{
Value: "abc",
},
"buzz": ConfigValue{
Value: "secret",
Secret: true,
},
}
// initialize
pDir := filepath.Join(".", "test", "testproj")
s, err := NewStackLocalSource(ctx, stackName, pDir)
if err != nil {
t.Errorf("failed to initialize stack, err: %v", err)
t.FailNow()
}
defer func() {
// -- pulumi stack rm --
err = s.Workspace().RemoveStack(ctx, s.Name())
assert.Nil(t, err, "failed to remove stack. Resources have leaked.")
}()
err = s.SetAllConfig(ctx, cfg)
if err != nil {
t.Errorf("failed to set config, err: %v", err)
t.FailNow()
}
// Set environment variables scoped to the workspace.
envvars := map[string]string{
"foo": "bar",
"barfoo": "foobar",
}
err = s.Workspace().SetEnvVars(envvars)
assert.Nil(t, err, "failed to set environment values")
envvars = s.Workspace().GetEnvVars()
assert.NotNil(t, envvars, "failed to get environment values after setting many")
s.Workspace().SetEnvVar("bar", "buzz")
envvars = s.Workspace().GetEnvVars()
assert.NotNil(t, envvars, "failed to get environment value after setting")
s.Workspace().UnsetEnvVar("bar")
envvars = s.Workspace().GetEnvVars()
assert.NotNil(t, envvars, "failed to get environment values after unsetting.")
// -- pulumi up --
res, err := s.Up(ctx, optup.UserAgent(agent))
if err != nil {
t.Errorf("up failed, err: %v", err)
t.FailNow()
}
assert.Equal(t, 3, len(res.Outputs), "expected two plain outputs")
assert.Equal(t, "foo", res.Outputs["exp_static"].Value)
assert.False(t, res.Outputs["exp_static"].Secret)
assert.Equal(t, "abc", res.Outputs["exp_cfg"].Value)
assert.False(t, res.Outputs["exp_cfg"].Secret)
assert.Equal(t, "secret", res.Outputs["exp_secret"].Value)
assert.True(t, res.Outputs["exp_secret"].Secret)
assert.Equal(t, "update", res.Summary.Kind)
assert.Equal(t, "succeeded", res.Summary.Result)
const permalinkSearchStr = "https://app.pulumi.com"
var startRegex = regexp.MustCompile(permalinkSearchStr)
permalink, err := GetPermalink(res.StdOut)
assert.Nil(t, err, "failed to get permalink.")
assert.True(t, startRegex.MatchString(permalink))
// -- pulumi preview --
var previewEvents []events.EngineEvent
prevCh := make(chan events.EngineEvent)
go collectEvents(prevCh, &previewEvents)
prev, err := s.Preview(ctx, optpreview.EventStreams(prevCh), optpreview.UserAgent(agent))
if err != nil {
t.Errorf("preview failed, err: %v", err)
t.FailNow()
}
assert.Equal(t, 1, prev.ChangeSummary[apitype.OpSame])
steps := countSteps(previewEvents)
assert.Equal(t, 1, steps)
// -- pulumi refresh --
ref, err := s.Refresh(ctx, optrefresh.UserAgent(agent))
if err != nil {
t.Errorf("refresh failed, err: %v", err)
t.FailNow()
}
assert.Equal(t, "refresh", ref.Summary.Kind)
assert.Equal(t, "succeeded", ref.Summary.Result)
// -- pulumi destroy --
dRes, err := s.Destroy(ctx, optdestroy.UserAgent(agent))
if err != nil {
t.Errorf("destroy failed, err: %v", err)
t.FailNow()
}
assert.Equal(t, "destroy", dRes.Summary.Kind)
assert.Equal(t, "succeeded", dRes.Summary.Result)
}
func TestUpsertStackLocalSource(t *testing.T) {
ctx := context.Background()
sName := fmt.Sprintf("int_test%d", rangeIn(10000000, 99999999))
stackName := FullyQualifiedStackName(pulumiOrg, pName, sName)
cfg := ConfigMap{
"bar": ConfigValue{
Value: "abc",
},
"buzz": ConfigValue{
Value: "secret",
Secret: true,
},
}
// initialize
pDir := filepath.Join(".", "test", "testproj")
s, err := UpsertStackLocalSource(ctx, stackName, pDir)
if err != nil {
t.Errorf("failed to initialize stack, err: %v", err)
t.FailNow()
}
defer func() {
// -- pulumi stack rm --
err = s.Workspace().RemoveStack(ctx, s.Name())
assert.Nil(t, err, "failed to remove stack. Resources have leaked.")
}()
err = s.SetAllConfig(ctx, cfg)
if err != nil {
t.Errorf("failed to set config, err: %v", err)
t.FailNow()
}
// Set environment variables scoped to the workspace.
envvars := map[string]string{
"foo": "bar",
"barfoo": "foobar",
}
err = s.Workspace().SetEnvVars(envvars)
assert.Nil(t, err, "failed to set environment values")
envvars = s.Workspace().GetEnvVars()
assert.NotNil(t, envvars, "failed to get environment values after setting many")
s.Workspace().SetEnvVar("bar", "buzz")
envvars = s.Workspace().GetEnvVars()
assert.NotNil(t, envvars, "failed to get environment value after setting")
s.Workspace().UnsetEnvVar("bar")
envvars = s.Workspace().GetEnvVars()
assert.NotNil(t, envvars, "failed to get environment values after unsetting.")
// -- pulumi up --
res, err := s.Up(ctx)
if err != nil {
t.Errorf("up failed, err: %v", err)
t.FailNow()
}
assert.Equal(t, 3, len(res.Outputs), "expected two plain outputs")
assert.Equal(t, "foo", res.Outputs["exp_static"].Value)
assert.False(t, res.Outputs["exp_static"].Secret)
assert.Equal(t, "abc", res.Outputs["exp_cfg"].Value)
assert.False(t, res.Outputs["exp_cfg"].Secret)
assert.Equal(t, "secret", res.Outputs["exp_secret"].Value)
assert.True(t, res.Outputs["exp_secret"].Secret)
assert.Equal(t, "update", res.Summary.Kind)
assert.Equal(t, "succeeded", res.Summary.Result)
// -- pulumi preview --
var previewEvents []events.EngineEvent
prevCh := make(chan events.EngineEvent)
go collectEvents(prevCh, &previewEvents)
prev, err := s.Preview(ctx, optpreview.EventStreams(prevCh))
if err != nil {
t.Errorf("preview failed, err: %v", err)
t.FailNow()
}
assert.Equal(t, 1, prev.ChangeSummary[apitype.OpSame])
steps := countSteps(previewEvents)
assert.Equal(t, 1, steps)
// -- pulumi refresh --
ref, err := s.Refresh(ctx)
if err != nil {
t.Errorf("refresh failed, err: %v", err)
t.FailNow()
}
assert.Equal(t, "refresh", ref.Summary.Kind)
assert.Equal(t, "succeeded", ref.Summary.Result)
// -- pulumi destroy --
dRes, err := s.Destroy(ctx)
if err != nil {
t.Errorf("destroy failed, err: %v", err)
t.FailNow()
}
assert.Equal(t, "destroy", dRes.Summary.Kind)
assert.Equal(t, "succeeded", dRes.Summary.Result)
}
func rangeIn(low, hi int) int {
rand.Seed(time.Now().UnixNano())
return low + rand.Intn(hi-low) //nolint:gosec
}
func TestNewStackRemoteSource(t *testing.T) {
ctx := context.Background()
pName := "go_remote_proj"
sName := fmt.Sprintf("int_test%d", rangeIn(10000000, 99999999))
stackName := FullyQualifiedStackName(pulumiOrg, pName, sName)
cfg := ConfigMap{
"bar": ConfigValue{
Value: "abc",
},
"buzz": ConfigValue{
Value: "secret",
Secret: true,
},
}
repo := GitRepo{
URL: "https://github.com/pulumi/test-repo.git",
ProjectPath: "goproj",
}
// initialize
s, err := NewStackRemoteSource(ctx, stackName, repo)
if err != nil {
t.Errorf("failed to initialize stack, err: %v", err)
t.FailNow()
}
defer func() {
// -- pulumi stack rm --
err = s.Workspace().RemoveStack(ctx, s.Name())
assert.Nil(t, err, "failed to remove stack. Resources have leaked.")
}()
err = s.SetAllConfig(ctx, cfg)
if err != nil {
t.Errorf("failed to set config, err: %v", err)
t.FailNow()
}
// -- pulumi up --
res, err := s.Up(ctx)
if err != nil {
t.Errorf("up failed, err: %v", err)
t.FailNow()
}
assert.Equal(t, 3, len(res.Outputs), "expected two plain outputs")
assert.Equal(t, "foo", res.Outputs["exp_static"].Value)
assert.False(t, res.Outputs["exp_static"].Secret)
assert.Equal(t, "abc", res.Outputs["exp_cfg"].Value)
assert.False(t, res.Outputs["exp_cfg"].Secret)
assert.Equal(t, "secret", res.Outputs["exp_secret"].Value)
assert.True(t, res.Outputs["exp_secret"].Secret)
assert.Equal(t, "update", res.Summary.Kind)
assert.Equal(t, "succeeded", res.Summary.Result)
// -- pulumi preview --
var previewEvents []events.EngineEvent
prevCh := make(chan events.EngineEvent)
go collectEvents(prevCh, &previewEvents)
prev, err := s.Preview(ctx, optpreview.EventStreams(prevCh))
if err != nil {
t.Errorf("preview failed, err: %v", err)
t.FailNow()
}
assert.Equal(t, 1, prev.ChangeSummary[apitype.OpSame])
steps := countSteps(previewEvents)
assert.Equal(t, 1, steps)
// -- pulumi refresh --
ref, err := s.Refresh(ctx)
if err != nil {
t.Errorf("refresh failed, err: %v", err)
t.FailNow()
}
assert.Equal(t, "refresh", ref.Summary.Kind)
assert.Equal(t, "succeeded", ref.Summary.Result)
// -- pulumi destroy --
dRes, err := s.Destroy(ctx)
if err != nil {
t.Errorf("destroy failed, err: %v", err)
t.FailNow()
}
assert.Equal(t, "destroy", dRes.Summary.Kind)
assert.Equal(t, "succeeded", dRes.Summary.Result)
}
func TestUpsertStackRemoteSource(t *testing.T) {
ctx := context.Background()
pName := "go_remote_proj"
sName := fmt.Sprintf("int_test%d", rangeIn(10000000, 99999999))
stackName := FullyQualifiedStackName(pulumiOrg, pName, sName)
cfg := ConfigMap{
"bar": ConfigValue{
Value: "abc",
},
"buzz": ConfigValue{
Value: "secret",
Secret: true,
},
}
repo := GitRepo{
URL: "https://github.com/pulumi/test-repo.git",
ProjectPath: "goproj",
}
// initialize
s, err := UpsertStackRemoteSource(ctx, stackName, repo)
if err != nil {
t.Errorf("failed to initialize stack, err: %v", err)
t.FailNow()
}
defer func() {
// -- pulumi stack rm --
err = s.Workspace().RemoveStack(ctx, s.Name())
assert.Nil(t, err, "failed to remove stack. Resources have leaked.")
}()
err = s.SetAllConfig(ctx, cfg)
if err != nil {
t.Errorf("failed to set config, err: %v", err)
t.FailNow()
}
// -- pulumi up --
res, err := s.Up(ctx)
if err != nil {
t.Errorf("up failed, err: %v", err)
t.FailNow()
}
assert.Equal(t, 3, len(res.Outputs), "expected two plain outputs")
assert.Equal(t, "foo", res.Outputs["exp_static"].Value)
assert.False(t, res.Outputs["exp_static"].Secret)
assert.Equal(t, "abc", res.Outputs["exp_cfg"].Value)
assert.False(t, res.Outputs["exp_cfg"].Secret)
assert.Equal(t, "secret", res.Outputs["exp_secret"].Value)
assert.True(t, res.Outputs["exp_secret"].Secret)
assert.Equal(t, "update", res.Summary.Kind)
assert.Equal(t, "succeeded", res.Summary.Result)
// -- pulumi preview --
var previewEvents []events.EngineEvent
prevCh := make(chan events.EngineEvent)
go collectEvents(prevCh, &previewEvents)
prev, err := s.Preview(ctx, optpreview.EventStreams(prevCh))
if err != nil {
t.Errorf("preview failed, err: %v", err)
t.FailNow()
}
assert.Equal(t, 1, prev.ChangeSummary[apitype.OpSame])
steps := countSteps(previewEvents)
assert.Equal(t, 1, steps)
// -- pulumi refresh --
ref, err := s.Refresh(ctx)
if err != nil {
t.Errorf("refresh failed, err: %v", err)
t.FailNow()
}
assert.Equal(t, "refresh", ref.Summary.Kind)
assert.Equal(t, "succeeded", ref.Summary.Result)
// -- pulumi destroy --
dRes, err := s.Destroy(ctx)
if err != nil {
t.Errorf("destroy failed, err: %v", err)
t.FailNow()
}
assert.Equal(t, "destroy", dRes.Summary.Kind)
assert.Equal(t, "succeeded", dRes.Summary.Result)
}
func TestNewStackRemoteSourceWithSetup(t *testing.T) {
ctx := context.Background()
pName := "go_remote_proj"
sName := fmt.Sprintf("int_test%d", rangeIn(10000000, 99999999))
stackName := FullyQualifiedStackName(pulumiOrg, pName, sName)
cfg := ConfigMap{
"bar": ConfigValue{
Value: "abc",
},
"buzz": ConfigValue{
Value: "secret",
Secret: true,
},
}
binName := "examplesBinary"
repo := GitRepo{
URL: "https://github.com/pulumi/test-repo.git",
ProjectPath: "goproj",
Setup: func(ctx context.Context, workspace Workspace) error {
cmd := exec.Command("go", "build", "-o", binName, "main.go")
cmd.Dir = workspace.WorkDir()
return cmd.Run()
},
}
project := workspace.Project{
Name: tokens.PackageName(pName),
Runtime: workspace.NewProjectRuntimeInfo("go", map[string]interface{}{
"binary": binName,
}),
}
// initialize
s, err := NewStackRemoteSource(ctx, stackName, repo, Project(project))
if err != nil {
t.Errorf("failed to initialize stack, err: %v", err)
t.FailNow()
}
defer func() {
// -- pulumi stack rm --
err = s.Workspace().RemoveStack(ctx, s.Name())
assert.Nil(t, err, "failed to remove stack. Resources have leaked.")
}()
err = s.SetAllConfig(ctx, cfg)
if err != nil {
t.Errorf("failed to set config, err: %v", err)
t.FailNow()
}
// -- pulumi up --
res, err := s.Up(ctx)
if err != nil {
t.Errorf("up failed, err: %v", err)
t.FailNow()
}
assert.Equal(t, 3, len(res.Outputs), "expected two plain outputs")
assert.Equal(t, "foo", res.Outputs["exp_static"].Value)
assert.False(t, res.Outputs["exp_static"].Secret)
assert.Equal(t, "abc", res.Outputs["exp_cfg"].Value)
assert.False(t, res.Outputs["exp_cfg"].Secret)
assert.Equal(t, "secret", res.Outputs["exp_secret"].Value)
assert.True(t, res.Outputs["exp_secret"].Secret)
assert.Equal(t, "update", res.Summary.Kind)
assert.Equal(t, "succeeded", res.Summary.Result)
// -- pulumi preview --
var previewEvents []events.EngineEvent
prevCh := make(chan events.EngineEvent)
go collectEvents(prevCh, &previewEvents)
prev, err := s.Preview(ctx, optpreview.EventStreams(prevCh))
if err != nil {
t.Errorf("preview failed, err: %v", err)
t.FailNow()
}
assert.Equal(t, 1, prev.ChangeSummary[apitype.OpSame])
steps := countSteps(previewEvents)
assert.Equal(t, 1, steps)
// -- pulumi refresh --
ref, err := s.Refresh(ctx)
if err != nil {
t.Errorf("refresh failed, err: %v", err)
t.FailNow()
}
assert.Equal(t, "refresh", ref.Summary.Kind)
assert.Equal(t, "succeeded", ref.Summary.Result)
// -- pulumi destroy --
dRes, err := s.Destroy(ctx)
if err != nil {
t.Errorf("destroy failed, err: %v", err)
t.FailNow()
}
assert.Equal(t, "destroy", dRes.Summary.Kind)
assert.Equal(t, "succeeded", dRes.Summary.Result)
}
func TestUpsertStackRemoteSourceWithSetup(t *testing.T) {
ctx := context.Background()
pName := "go_remote_proj"
sName := fmt.Sprintf("int_test%d", rangeIn(10000000, 99999999))
stackName := FullyQualifiedStackName(pulumiOrg, pName, sName)
cfg := ConfigMap{
"bar": ConfigValue{
Value: "abc",
},
"buzz": ConfigValue{
Value: "secret",
Secret: true,
},
}
binName := "examplesBinary"
repo := GitRepo{
URL: "https://github.com/pulumi/test-repo.git",
ProjectPath: "goproj",
Setup: func(ctx context.Context, workspace Workspace) error {
cmd := exec.Command("go", "build", "-o", binName, "main.go")
cmd.Dir = workspace.WorkDir()
return cmd.Run()
},
}
project := workspace.Project{
Name: tokens.PackageName(pName),
Runtime: workspace.NewProjectRuntimeInfo("go", map[string]interface{}{
"binary": binName,
}),
}
// initialize or select
s, err := UpsertStackRemoteSource(ctx, stackName, repo, Project(project))
if err != nil {
t.Errorf("failed to initialize stack, err: %v", err)
t.FailNow()
}
defer func() {
// -- pulumi stack rm --
err = s.Workspace().RemoveStack(ctx, s.Name())
assert.Nil(t, err, "failed to remove stack. Resources have leaked.")
}()
err = s.SetAllConfig(ctx, cfg)
if err != nil {
t.Errorf("failed to set config, err: %v", err)
t.FailNow()
}
// -- pulumi up --
res, err := s.Up(ctx)
if err != nil {
t.Errorf("up failed, err: %v", err)
t.FailNow()
}
assert.Equal(t, 3, len(res.Outputs), "expected two plain outputs")
assert.Equal(t, "foo", res.Outputs["exp_static"].Value)
assert.False(t, res.Outputs["exp_static"].Secret)
assert.Equal(t, "abc", res.Outputs["exp_cfg"].Value)
assert.False(t, res.Outputs["exp_cfg"].Secret)
assert.Equal(t, "secret", res.Outputs["exp_secret"].Value)
assert.True(t, res.Outputs["exp_secret"].Secret)
assert.Equal(t, "update", res.Summary.Kind)
assert.Equal(t, "succeeded", res.Summary.Result)
// -- pulumi preview --
var previewEvents []events.EngineEvent
prevCh := make(chan events.EngineEvent)
go collectEvents(prevCh, &previewEvents)
prev, err := s.Preview(ctx, optpreview.EventStreams(prevCh))
if err != nil {
t.Errorf("preview failed, err: %v", err)
t.FailNow()
}
assert.Equal(t, 1, prev.ChangeSummary[apitype.OpSame])
steps := countSteps(previewEvents)
assert.Equal(t, 1, steps)
// -- pulumi refresh --
ref, err := s.Refresh(ctx)
if err != nil {
t.Errorf("refresh failed, err: %v", err)
t.FailNow()
}
assert.Equal(t, "refresh", ref.Summary.Kind)
assert.Equal(t, "succeeded", ref.Summary.Result)
// -- pulumi destroy --
dRes, err := s.Destroy(ctx)
if err != nil {
t.Errorf("destroy failed, err: %v", err)
t.FailNow()
}
assert.Equal(t, "destroy", dRes.Summary.Kind)
assert.Equal(t, "succeeded", dRes.Summary.Result)
}
func TestNewStackInlineSource(t *testing.T) {
ctx := context.Background()
sName := fmt.Sprintf("int_test%d", rangeIn(10000000, 99999999))
stackName := FullyQualifiedStackName(pulumiOrg, pName, sName)
cfg := ConfigMap{
"bar": ConfigValue{
Value: "abc",
},
"buzz": ConfigValue{
Value: "secret",
Secret: true,
},
}
// initialize
s, err := NewStackInlineSource(ctx, stackName, pName, func(ctx *pulumi.Context) error {
c := config.New(ctx, "")
ctx.Export("exp_static", pulumi.String("foo"))
ctx.Export("exp_cfg", pulumi.String(c.Get("bar")))
ctx.Export("exp_secret", c.GetSecret("buzz"))
return nil
})
if err != nil {
t.Errorf("failed to initialize stack, err: %v", err)
t.FailNow()
}
defer func() {
// -- pulumi stack rm --
err = s.Workspace().RemoveStack(ctx, s.Name())
assert.Nil(t, err, "failed to remove stack. Resources have leaked.")
}()
err = s.SetAllConfig(ctx, cfg)
if err != nil {
t.Errorf("failed to set config, err: %v", err)
t.FailNow()
}
// -- pulumi up --
res, err := s.Up(ctx, optup.UserAgent(agent))
if err != nil {
t.Errorf("up failed, err: %v", err)
t.FailNow()
}
assert.Equal(t, 3, len(res.Outputs), "expected two plain outputs")
assert.Equal(t, "foo", res.Outputs["exp_static"].Value)
assert.False(t, res.Outputs["exp_static"].Secret)
assert.Equal(t, "abc", res.Outputs["exp_cfg"].Value)
assert.False(t, res.Outputs["exp_cfg"].Secret)
assert.Equal(t, "secret", res.Outputs["exp_secret"].Value)
assert.True(t, res.Outputs["exp_secret"].Secret)
assert.Equal(t, "update", res.Summary.Kind)
assert.Equal(t, "succeeded", res.Summary.Result)
assert.Greater(t, res.Summary.Version, 0)
// -- pulumi preview --
var previewEvents []events.EngineEvent
prevCh := make(chan events.EngineEvent)
go collectEvents(prevCh, &previewEvents)
prev, err := s.Preview(ctx, optpreview.EventStreams(prevCh), optpreview.UserAgent(agent))
if err != nil {
t.Errorf("preview failed, err: %v", err)
t.FailNow()
}
assert.Equal(t, 1, prev.ChangeSummary[apitype.OpSame])
steps := countSteps(previewEvents)
assert.Equal(t, 1, steps)
// -- pulumi refresh --
ref, err := s.Refresh(ctx, optrefresh.UserAgent(agent))
if err != nil {
t.Errorf("refresh failed, err: %v", err)
t.FailNow()
}
assert.Equal(t, "refresh", ref.Summary.Kind)
assert.Equal(t, "succeeded", ref.Summary.Result)
// -- pulumi destroy --
dRes, err := s.Destroy(ctx, optdestroy.UserAgent(agent))
if err != nil {
t.Errorf("destroy failed, err: %v", err)
t.FailNow()
}
assert.Equal(t, "destroy", dRes.Summary.Kind)
assert.Equal(t, "succeeded", dRes.Summary.Result)
}
func TestUpsertStackInlineSource(t *testing.T) {
ctx := context.Background()
sName := fmt.Sprintf("int_test%d", rangeIn(10000000, 99999999))
stackName := FullyQualifiedStackName(pulumiOrg, pName, sName)
cfg := ConfigMap{
"bar": ConfigValue{
Value: "abc",
},
"buzz": ConfigValue{
Value: "secret",
Secret: true,
},
}
// initialize or select
s, err := UpsertStackInlineSource(ctx, stackName, pName, func(ctx *pulumi.Context) error {
c := config.New(ctx, "")
ctx.Export("exp_static", pulumi.String("foo"))
ctx.Export("exp_cfg", pulumi.String(c.Get("bar")))
ctx.Export("exp_secret", c.GetSecret("buzz"))
return nil
})
if err != nil {
t.Errorf("failed to initialize stack, err: %v", err)
t.FailNow()
}
defer func() {
// -- pulumi stack rm --
err = s.Workspace().RemoveStack(ctx, s.Name())
assert.Nil(t, err, "failed to remove stack. Resources have leaked.")
}()
err = s.SetAllConfig(ctx, cfg)
if err != nil {
t.Errorf("failed to set config, err: %v", err)
t.FailNow()
}
// -- pulumi up --
res, err := s.Up(ctx)
if err != nil {
t.Errorf("up failed, err: %v", err)
t.FailNow()
}
assert.Equal(t, 3, len(res.Outputs), "expected two plain outputs")
assert.Equal(t, "foo", res.Outputs["exp_static"].Value)
assert.False(t, res.Outputs["exp_static"].Secret)
assert.Equal(t, "abc", res.Outputs["exp_cfg"].Value)
assert.False(t, res.Outputs["exp_cfg"].Secret)
assert.Equal(t, "secret", res.Outputs["exp_secret"].Value)
assert.True(t, res.Outputs["exp_secret"].Secret)
assert.Equal(t, "update", res.Summary.Kind)
assert.Equal(t, "succeeded", res.Summary.Result)
// -- pulumi preview --
var previewEvents []events.EngineEvent
prevCh := make(chan events.EngineEvent)
go collectEvents(prevCh, &previewEvents)
prev, err := s.Preview(ctx, optpreview.EventStreams(prevCh))
if err != nil {
t.Errorf("preview failed, err: %v", err)
t.FailNow()
}
assert.Equal(t, 1, prev.ChangeSummary[apitype.OpSame])
steps := countSteps(previewEvents)
assert.Equal(t, 1, steps)
// -- pulumi refresh --
ref, err := s.Refresh(ctx)
if err != nil {
t.Errorf("refresh failed, err: %v", err)
t.FailNow()
}
assert.Equal(t, "refresh", ref.Summary.Kind)
assert.Equal(t, "succeeded", ref.Summary.Result)
// -- pulumi destroy --
dRes, err := s.Destroy(ctx)
if err != nil {
t.Errorf("destroy failed, err: %v", err)
t.FailNow()
}
assert.Equal(t, "destroy", dRes.Summary.Kind)
assert.Equal(t, "succeeded", dRes.Summary.Result)
}
func TestNestedStackFails(t *testing.T) {
// FIXME: see https://github.com/pulumi/pulumi/issues/5301
t.Skip("skipping test, see pulumi/pulumi#5301")
testCtx := context.Background()
sName := fmt.Sprintf("int_test%d", rangeIn(10000000, 99999999))
parentstackName := FullyQualifiedStackName(pulumiOrg, "parent", sName)
nestedstackName := FullyQualifiedStackName(pulumiOrg, "nested", sName)
nestedStack, err := NewStackInlineSource(testCtx, nestedstackName, "nested", func(ctx *pulumi.Context) error {
ctx.Export("exp_static", pulumi.String("foo"))
return nil
})
if err != nil {
t.Errorf("failed to initialize stack, err: %v", err)
t.FailNow()
}
// initialize
s, err := NewStackInlineSource(testCtx, parentstackName, "parent", func(ctx *pulumi.Context) error {
_, err := nestedStack.Up(testCtx)
return err
})
if err != nil {
t.Errorf("failed to initialize stack, err: %v", err)
t.FailNow()
}
defer func() {
// -- pulumi stack rm --
err = s.Workspace().RemoveStack(testCtx, s.Name())
assert.Nil(t, err, "failed to remove stack. Resources have leaked.")
err = nestedStack.Workspace().RemoveStack(testCtx, nestedStack.Name())
assert.Nil(t, err, "failed to remove stack. Resources have leaked.")
}()
result, err := s.Up(testCtx)
t.Log(result)
assert.Error(t, err)
assert.Contains(t, err.Error(), "nested stack operations are not supported")
// -- pulumi destroy --
dRes, err := s.Destroy(testCtx)
if err != nil {
t.Errorf("destroy failed, err: %v", err)
t.FailNow()
}
assert.Equal(t, "destroy", dRes.Summary.Kind)
assert.Equal(t, "succeeded", dRes.Summary.Result)
dRes, err = nestedStack.Destroy(testCtx)
if err != nil {
t.Errorf("destroy failed, err: %v", err)
t.FailNow()
}
assert.Equal(t, "destroy", dRes.Summary.Kind)
assert.Equal(t, "succeeded", dRes.Summary.Result)
}
func TestProgressStreams(t *testing.T) {
ctx := context.Background()
pName := "inline_progress_streams"
sName := fmt.Sprintf("int_test%d", rangeIn(10000000, 99999999))
stackName := FullyQualifiedStackName(pulumiOrg, pName, sName)
cfg := ConfigMap{
"bar": ConfigValue{
Value: "abc",
},
"buzz": ConfigValue{
Value: "secret",
Secret: true,
},
}
// initialize
s, err := NewStackInlineSource(ctx, stackName, pName, func(ctx *pulumi.Context) error {
c := config.New(ctx, "")
ctx.Export("exp_static", pulumi.String("foo"))
ctx.Export("exp_cfg", pulumi.String(c.Get("bar")))
ctx.Export("exp_secret", c.GetSecret("buzz"))
return nil
})
if err != nil {
t.Errorf("failed to initialize stack, err: %v", err)
t.FailNow()
}
defer func() {
// -- pulumi stack rm --
err = s.Workspace().RemoveStack(ctx, s.Name())
assert.Nil(t, err, "failed to remove stack. Resources have leaked.")
}()
err = s.SetAllConfig(ctx, cfg)
if err != nil {
t.Errorf("failed to set config, err: %v", err)
t.FailNow()
}
// -- pulumi up --
var upOut bytes.Buffer
res, err := s.Up(ctx, optup.ProgressStreams(&upOut))
if err != nil {
t.Errorf("up failed, err: %v", err)
t.FailNow()
}
assert.Equal(t, upOut.String(), res.StdOut, "expected stdout writers to contain same contents")
// -- pulumi refresh --
var refOut bytes.Buffer
ref, err := s.Refresh(ctx, optrefresh.ProgressStreams(&refOut))
if err != nil {
t.Errorf("refresh failed, err: %v", err)
t.FailNow()
}
assert.Equal(t, refOut.String(), ref.StdOut, "expected stdout writers to contain same contents")
// -- pulumi destroy --
var desOut bytes.Buffer
dRes, err := s.Destroy(ctx, optdestroy.ProgressStreams(&desOut))
if err != nil {
t.Errorf("destroy failed, err: %v", err)
t.FailNow()
}
assert.Equal(t, desOut.String(), dRes.StdOut, "expected stdout writers to contain same contents")
}
func TestImportExportStack(t *testing.T) {
ctx := context.Background()
sName := fmt.Sprintf("int_test%d", rangeIn(10000000, 99999999))
stackName := FullyQualifiedStackName(pulumiOrg, pName, sName)
cfg := ConfigMap{
"bar": ConfigValue{
Value: "abc",
},
"buzz": ConfigValue{
Value: "secret",
Secret: true,
},
}
// initialize
s, err := NewStackInlineSource(ctx, stackName, pName, func(ctx *pulumi.Context) error {
c := config.New(ctx, "")
ctx.Export("exp_static", pulumi.String("foo"))
ctx.Export("exp_cfg", pulumi.String(c.Get("bar")))
ctx.Export("exp_secret", c.GetSecret("buzz"))
return nil
})
if err != nil {
t.Errorf("failed to initialize stack, err: %v", err)
t.FailNow()
}
defer func() {
// -- pulumi stack rm --
err = s.Workspace().RemoveStack(ctx, s.Name())
assert.Nil(t, err, "failed to remove stack. Resources have leaked.")
}()
err = s.SetAllConfig(ctx, cfg)
if err != nil {
t.Errorf("failed to set config, err: %v", err)
t.FailNow()
}
// -- pulumi up --
_, err = s.Up(ctx)
if err != nil {
t.Errorf("up failed, err: %v", err)
t.FailNow()
}
// -- pulumi stack export --
state, err := s.Export(ctx)
if err != nil {
t.Errorf("export failed, err: %v", err)
t.FailNow()
}
// -- pulumi stack import --
err = s.Import(ctx, state)
if err != nil {
t.Errorf("import failed, err: %v", err)
t.FailNow()
}
// -- pulumi destroy --
dRes, err := s.Destroy(ctx)
if err != nil {
t.Errorf("destroy failed, err: %v", err)
t.FailNow()
}
assert.Equal(t, "destroy", dRes.Summary.Kind)
assert.Equal(t, "succeeded", dRes.Summary.Result)
}
func TestNestedConfig(t *testing.T) {
if getTestOrg() != "pulumi-test" {
return
}
ctx := context.Background()
stackName := FullyQualifiedStackName(pulumiOrg, "nested_config", "dev")
// initialize
pDir := filepath.Join(".", "test", "nested_config")
s, err := UpsertStackLocalSource(ctx, stackName, pDir)
if err != nil {
t.Errorf("failed to initialize stack, err: %v", err)
t.FailNow()
}
// Also retrieve the stack settings directly from the yaml file and
// make sure the config agrees with the config loaded by Pulumi.
stackSettings, err := s.Workspace().StackSettings(ctx, stackName)
require.NoError(t, err)
confKeys := map[string]bool{}
for k := range stackSettings.Config {
confKeys[k.String()] = true
}
allConfig, err := s.GetAllConfig(ctx)
if err != nil {
t.Errorf("failed to get config, err: %v", err)
t.FailNow()
}
allConfKeys := map[string]bool{}
for k := range allConfig {
allConfKeys[k] = true
}
assert.Equal(t, confKeys, allConfKeys)
assert.NotEmpty(t, confKeys)
outerVal, ok := allConfig["nested_config:outer"]
assert.True(t, ok)
assert.True(t, outerVal.Secret)
assert.JSONEq(t, "{\"inner\":\"my_secret\", \"other\": \"something_else\"}", outerVal.Value)
listVal, ok := allConfig["nested_config:myList"]
assert.True(t, ok)
assert.False(t, listVal.Secret)
assert.JSONEq(t, "[\"one\",\"two\",\"three\"]", listVal.Value)
outer, err := s.GetConfig(ctx, "outer")
if err != nil {
t.Errorf("failed to get config, err: %v", err)
t.FailNow()
}
assert.True(t, outer.Secret)
assert.JSONEq(t, "{\"inner\":\"my_secret\", \"other\": \"something_else\"}", outer.Value)
list, err := s.GetConfig(ctx, "myList")
if err != nil {
t.Errorf("failed to get config, err: %v", err)
t.FailNow()
}
assert.False(t, list.Secret)
assert.JSONEq(t, "[\"one\",\"two\",\"three\"]", list.Value)
}
func TestStructuredOutput(t *testing.T) {
ctx := context.Background()
sName := fmt.Sprintf("int_test%d", rangeIn(10000000, 99999999))
stackName := FullyQualifiedStackName(pulumiOrg, pName, sName)
cfg := ConfigMap{
"bar": ConfigValue{
Value: "abc",
},
"buzz": ConfigValue{
Value: "secret",
Secret: true,
},
}
// initialize
pDir := filepath.Join(".", "test", "testproj")
s, err := UpsertStackLocalSource(ctx, stackName, pDir)
if err != nil {
t.Errorf("failed to initialize stack, err: %v", err)
t.FailNow()
}
defer func() {
// -- pulumi stack rm --
err = s.Workspace().RemoveStack(ctx, s.Name())
assert.Nil(t, err, "failed to remove stack. Resources have leaked.")
}()
err = s.SetAllConfig(ctx, cfg)
if err != nil {
t.Errorf("failed to set config, err: %v", err)
t.FailNow()
}
// Set environment variables scoped to the workspace.
envvars := map[string]string{
"foo": "bar",
"barfoo": "foobar",
}
err = s.Workspace().SetEnvVars(envvars)
assert.Nil(t, err, "failed to set environment values")
envvars = s.Workspace().GetEnvVars()
assert.NotNil(t, envvars, "failed to get environment values after setting many")
s.Workspace().SetEnvVar("bar", "buzz")
envvars = s.Workspace().GetEnvVars()
assert.NotNil(t, envvars, "failed to get environment value after setting")
s.Workspace().UnsetEnvVar("bar")
envvars = s.Workspace().GetEnvVars()
assert.NotNil(t, envvars, "failed to get environment values after unsetting.")
// -- pulumi up --
var upEvents []events.EngineEvent
upCh := make(chan events.EngineEvent)
go collectEvents(upCh, &upEvents)
res, err := s.Up(ctx, optup.EventStreams(upCh))
if err != nil {
t.Errorf("up failed, err: %v", err)
t.FailNow()
}
assert.Equal(t, 3, len(res.Outputs), "expected two plain outputs")
assert.Equal(t, "foo", res.Outputs["exp_static"].Value)
assert.False(t, res.Outputs["exp_static"].Secret)
assert.Equal(t, "abc", res.Outputs["exp_cfg"].Value)
assert.False(t, res.Outputs["exp_cfg"].Secret)
assert.Equal(t, "secret", res.Outputs["exp_secret"].Value)
assert.True(t, res.Outputs["exp_secret"].Secret)
assert.Equal(t, "update", res.Summary.Kind)
assert.Equal(t, "succeeded", res.Summary.Result)
assert.True(t, containsSummary(upEvents))
// -- pulumi preview --
var previewEvents []events.EngineEvent
prevCh := make(chan events.EngineEvent)
go collectEvents(prevCh, &previewEvents)
prev, err := s.Preview(ctx, optpreview.EventStreams(prevCh))
if err != nil {
t.Errorf("preview failed, err: %v", err)
t.FailNow()
}
assert.Equal(t, 1, prev.ChangeSummary[apitype.OpSame])
steps := countSteps(previewEvents)
assert.Equal(t, 1, steps)
assert.True(t, containsSummary(previewEvents))
// -- pulumi refresh --
var refreshEvents []events.EngineEvent
refCh := make(chan events.EngineEvent)
go collectEvents(refCh, &refreshEvents)
ref, err := s.Refresh(ctx, optrefresh.EventStreams(refCh))
if err != nil {
t.Errorf("refresh failed, err: %v", err)
t.FailNow()
}
assert.Equal(t, "refresh", ref.Summary.Kind)
assert.Equal(t, "succeeded", ref.Summary.Result)
assert.True(t, containsSummary(refreshEvents))
// -- pulumi destroy --
var destroyEvents []events.EngineEvent
desCh := make(chan events.EngineEvent)
go collectEvents(desCh, &destroyEvents)
dRes, err := s.Destroy(ctx, optdestroy.EventStreams(desCh))
if err != nil {
t.Errorf("destroy failed, err: %v", err)
t.FailNow()
}
assert.Equal(t, "destroy", dRes.Summary.Kind)
assert.Equal(t, "succeeded", dRes.Summary.Result)
assert.True(t, containsSummary(destroyEvents))
}
func TestSupportsStackOutputs(t *testing.T) {
ctx := context.Background()
sName := fmt.Sprintf("int_test%d", rangeIn(10000000, 99999999))
stackName := FullyQualifiedStackName(pulumiOrg, pName, sName)
cfg := ConfigMap{
"bar": ConfigValue{
Value: "abc",
},
"buzz": ConfigValue{
Value: "secret",
Secret: true,
},
}
// initialize
s, err := NewStackInlineSource(ctx, stackName, pName, func(ctx *pulumi.Context) error {
c := config.New(ctx, "")
nestedObj := pulumi.Map{
"not_a_secret": pulumi.String("foo"),
"is_a_secret": pulumi.ToSecret("iamsecret"),
}
ctx.Export("exp_static", pulumi.String("foo"))
ctx.Export("exp_cfg", pulumi.String(c.Get("bar")))
ctx.Export("exp_secret", c.GetSecret("buzz"))
ctx.Export("nested_obj", nestedObj)
return nil
})
if err != nil {
t.Errorf("failed to initialize stack, err: %v", err)
t.FailNow()
}
defer func() {
// -- pulumi stack rm --
err = s.Workspace().RemoveStack(ctx, s.Name())
assert.Nil(t, err, "failed to remove stack. Resources have leaked.")
}()
err = s.SetAllConfig(ctx, cfg)
if err != nil {
t.Errorf("failed to set config, err: %v", err)
t.FailNow()
}
assertOutputs := func(t *testing.T, outputs OutputMap) {
assert.Equal(t, 4, len(outputs), "expected four outputs")
assert.Equal(t, "foo", outputs["exp_static"].Value)
assert.False(t, outputs["exp_static"].Secret)
assert.Equal(t, "abc", outputs["exp_cfg"].Value)
assert.False(t, outputs["exp_cfg"].Secret)
assert.Equal(t, "secret", outputs["exp_secret"].Value)
assert.True(t, outputs["exp_secret"].Secret)
assert.Equal(t, map[string]interface{}{
"is_a_secret": "iamsecret",
"not_a_secret": "foo",
}, outputs["nested_obj"].Value)
assert.True(t, outputs["nested_obj"].Secret)
}
initialOutputs, err := s.Outputs(ctx)
if err != nil {
t.Errorf("failed to get initial outputs, err: %v", err)
t.FailNow()
}
assert.Equal(t, 0, len(initialOutputs))
// -- pulumi up --
res, err := s.Up(ctx)
if err != nil {
t.Errorf("up failed, err: %v", err)
t.FailNow()
}
assert.Equal(t, "update", res.Summary.Kind)
assert.Equal(t, "succeeded", res.Summary.Result)
assert.Greater(t, res.Summary.Version, 0)
assertOutputs(t, res.Outputs)
outputsAfterUp, err := s.Outputs(ctx)
if err != nil {
t.Errorf("failed to get outputs after up, err: %v", err)
t.FailNow()
}
assertOutputs(t, outputsAfterUp)
// -- pulumi destroy --
dRes, err := s.Destroy(ctx)
if err != nil {
t.Errorf("destroy failed, err: %v", err)
t.FailNow()
}
assert.Equal(t, "destroy", dRes.Summary.Kind)
assert.Equal(t, "succeeded", dRes.Summary.Result)
outputsAfterDestroy, err := s.Outputs(ctx)
if err != nil {
t.Errorf("failed to get outputs after destroy, err: %v", err)
t.FailNow()
}
assert.Equal(t, 0, len(outputsAfterDestroy))
}
func TestPulumiVersion(t *testing.T) {
ctx := context.Background()
ws, err := NewLocalWorkspace(ctx)
if err != nil {
t.Errorf("failed to create workspace, err: %v", err)
t.FailNow()
}
version := ws.PulumiVersion()
assert.NotEqual(t, "v0.0.0", version)
assert.Regexp(t, `(\d+\.)(\d+\.)(\d+)(-.*)?`, version)
}
const PARSE = `Unable to parse`
const MAJOR = `Major version mismatch.`
const MINIMUM = `Minimum version requirement failed.`
var minVersionTests = []struct {
name string
currentVersion string
expectedError string
optOut bool
}{
{
"higher_major",
"100.0.0",
MAJOR,
false,
},
{
"lower_major",
"1.0.0",
MINIMUM,
false,
},
{
"higher_minor",
"2.2.0",
MINIMUM,
false,
},
{
"lower_minor",
"2.1.0",
MINIMUM,
false,
},
{
"equal_minor_higher_patch",
"2.2.2",
MINIMUM,
false,
},
{
"equal_minor_equal_patch",
"2.2.1",
MINIMUM,
false,
},
{
"equal_minor_lower_patch",
"2.2.0",
MINIMUM,
false,
},
{
"equal_minor_equal_patch_prerelease",
// Note that prerelease < release so this case will error
"2.21.1-alpha.1234",
MINIMUM,
false,
},
{
"opt_out_of_check_would_fail_otherwise",
"2.2.0",
"",
true,
},
{
"opt_out_of_check_would_succeed_otherwise",
"2.2.0",
"",
true,
},
{
"unparsable_version",
"invalid",
PARSE,
false,
},
{
"opt_out_unparsable_version",
"invalid",
"",
true,
},
}
func TestMinimumVersion(t *testing.T) {
for _, tt := range minVersionTests {
t.Run(tt.name, func(t *testing.T) {
minVersion := semver.Version{Major: 2, Minor: 21, Patch: 1}
_, err := parseAndValidatePulumiVersion(minVersion, tt.currentVersion, tt.optOut)
if tt.expectedError != "" {
assert.Error(t, err)
assert.Regexp(t, tt.expectedError, err.Error())
} else {
assert.Nil(t, err)
}
})
}
}
func TestProjectSettingsRespected(t *testing.T) {
ctx := context.Background()
sName := fmt.Sprintf("int_test%d", rangeIn(10000000, 99999999))
pName := "correct_project"
stackName := FullyQualifiedStackName(pulumiOrg, pName, sName)
badProjectName := "project_was_overwritten"
stack, err := NewStackInlineSource(ctx, stackName, badProjectName, func(ctx *pulumi.Context) error {
return nil
}, WorkDir(filepath.Join(".", "test", pName)))
defer func() {
// -- pulumi stack rm --
err = stack.Workspace().RemoveStack(ctx, stack.Name())
assert.Nil(t, err, "failed to remove stack. Resources have leaked.")
}()
assert.Nil(t, err)
projectSettings, err := stack.workspace.ProjectSettings(ctx)
assert.Nil(t, err)
assert.Equal(t, projectSettings.Name, tokens.PackageName("correct_project"))
assert.Equal(t, *projectSettings.Description, "This is a description")
}
func TestSaveStackSettings(t *testing.T) {
ctx := context.Background()
sName := fmt.Sprintf("int_test%d", rangeIn(10000000, 99999999))
stackName := FullyQualifiedStackName(pulumiOrg, pName, sName)
opts := []LocalWorkspaceOption{
SecretsProvider("passphrase"),
EnvVars(map[string]string{
"PULUMI_CONFIG_PASSPHRASE": "password",
}),
}
// initialize
s, err := NewStackInlineSource(ctx, stackName, pName, func(ctx *pulumi.Context) error {
c := config.New(ctx, "")
ctx.Export("exp_static", pulumi.String("foo"))
ctx.Export("exp_cfg", pulumi.String(c.Get("bar")))
ctx.Export("exp_secret", c.GetSecret("buzz"))
return nil
}, opts...)
require.NoError(t, err, "failed to initialize stack, err: %v", err)
defer func() {
// -- pulumi stack rm --
err = s.Workspace().RemoveStack(ctx, s.Name())
assert.Nil(t, err, "failed to remove stack. Resources have leaked.")
}()
// first load settings for created stack
stackConfig, err := s.Workspace().StackSettings(ctx, stackName)
require.NoError(t, err)
stackConfig.SecretsProvider = "passphrase"
assert.NoError(t, s.Workspace().SaveStackSettings(ctx, stackName, stackConfig))
// -- pulumi up --
res, err := s.Up(ctx)
if err != nil {
t.Errorf("up failed, err: %v", err)
t.FailNow()
}
assert.Equal(t, "update", res.Summary.Kind)
assert.Equal(t, "succeeded", res.Summary.Result)
reloaded, err := s.workspace.StackSettings(ctx, stackName)
assert.NoError(t, err)
assert.Equal(t, stackConfig, reloaded)
// -- pulumi destroy --
dRes, err := s.Destroy(ctx)
if err != nil {
t.Errorf("destroy failed, err: %v", err)
t.FailNow()
}
assert.Equal(t, "destroy", dRes.Summary.Kind)
assert.Equal(t, "succeeded", dRes.Summary.Result)
}
func TestConfigSecretWarnings(t *testing.T) {
// TODO[pulumi/pulumi#7127]: Re-enabled the warning.
t.Skip("Temporarily skipping test until we've re-enabled the warning - pulumi/pulumi#7127")
ctx := context.Background()
sName := fmt.Sprintf("int_test%d", rangeIn(10000000, 99999999))
stackName := FullyQualifiedStackName(pulumiOrg, pName, sName)
cfg := ConfigMap{
"plainstr1": ConfigValue{Value: "1"},
"plainstr2": ConfigValue{Value: "2"},
"plainstr3": ConfigValue{Value: "3"},
"plainstr4": ConfigValue{Value: "4"},
"plainstr5": ConfigValue{Value: "5"},
"plainstr6": ConfigValue{Value: "6"},
"plainstr7": ConfigValue{Value: "7"},
"plainstr8": ConfigValue{Value: "8"},
"plainstr9": ConfigValue{Value: "9"},
"plainstr10": ConfigValue{Value: "10"},
"plainstr11": ConfigValue{Value: "11"},
"plainstr12": ConfigValue{Value: "12"},
"plainbool1": ConfigValue{Value: "true"},
"plainbool2": ConfigValue{Value: "true"},
"plainbool3": ConfigValue{Value: "true"},
"plainbool4": ConfigValue{Value: "true"},
"plainbool5": ConfigValue{Value: "true"},
"plainbool6": ConfigValue{Value: "true"},
"plainbool7": ConfigValue{Value: "true"},
"plainbool8": ConfigValue{Value: "true"},
"plainbool9": ConfigValue{Value: "true"},
"plainbool10": ConfigValue{Value: "true"},
"plainbool11": ConfigValue{Value: "true"},
"plainbool12": ConfigValue{Value: "true"},
"plainint1": ConfigValue{Value: "1"},
"plainint2": ConfigValue{Value: "2"},
"plainint3": ConfigValue{Value: "3"},
"plainint4": ConfigValue{Value: "4"},
"plainint5": ConfigValue{Value: "5"},
"plainint6": ConfigValue{Value: "6"},
"plainint7": ConfigValue{Value: "7"},
"plainint8": ConfigValue{Value: "8"},
"plainint9": ConfigValue{Value: "9"},
"plainint10": ConfigValue{Value: "10"},
"plainint11": ConfigValue{Value: "11"},
"plainint12": ConfigValue{Value: "12"},
"plainfloat1": ConfigValue{Value: "1.1"},
"plainfloat2": ConfigValue{Value: "2.2"},
"plainfloat3": ConfigValue{Value: "3.3"},
"plainfloat4": ConfigValue{Value: "4.4"},
"plainfloat5": ConfigValue{Value: "5.5"},
"plainfloat6": ConfigValue{Value: "6.6"},
"plainfloat7": ConfigValue{Value: "7.7"},
"plainfloat8": ConfigValue{Value: "8.8"},
"plainfloat9": ConfigValue{Value: "9.9"},
"plainfloat10": ConfigValue{Value: "10.1"},
"plainfloat11": ConfigValue{Value: "11.11"},
"plainfloat12": ConfigValue{Value: "12.12"},
"plainobj1": ConfigValue{Value: "{}"},
"plainobj2": ConfigValue{Value: "{}"},
"plainobj3": ConfigValue{Value: "{}"},
"plainobj4": ConfigValue{Value: "{}"},
"plainobj5": ConfigValue{Value: "{}"},
"plainobj6": ConfigValue{Value: "{}"},
"plainobj7": ConfigValue{Value: "{}"},
"plainobj8": ConfigValue{Value: "{}"},
"plainobj9": ConfigValue{Value: "{}"},
"plainobj10": ConfigValue{Value: "{}"},
"plainobj11": ConfigValue{Value: "{}"},
"plainobj12": ConfigValue{Value: "{}"},
"str1": ConfigValue{Value: "1", Secret: true},
"str2": ConfigValue{Value: "2", Secret: true},
"str3": ConfigValue{Value: "3", Secret: true},
"str4": ConfigValue{Value: "4", Secret: true},
"str5": ConfigValue{Value: "5", Secret: true},
"str6": ConfigValue{Value: "6", Secret: true},
"str7": ConfigValue{Value: "7", Secret: true},
"str8": ConfigValue{Value: "8", Secret: true},
"str9": ConfigValue{Value: "9", Secret: true},
"str10": ConfigValue{Value: "10", Secret: true},
"str11": ConfigValue{Value: "11", Secret: true},
"str12": ConfigValue{Value: "12", Secret: true},
"bool1": ConfigValue{Value: "true", Secret: true},
"bool2": ConfigValue{Value: "true", Secret: true},
"bool3": ConfigValue{Value: "true", Secret: true},
"bool4": ConfigValue{Value: "true", Secret: true},
"bool5": ConfigValue{Value: "true", Secret: true},
"bool6": ConfigValue{Value: "true", Secret: true},
"bool7": ConfigValue{Value: "true", Secret: true},
"bool8": ConfigValue{Value: "true", Secret: true},
"bool9": ConfigValue{Value: "true", Secret: true},
"bool10": ConfigValue{Value: "true", Secret: true},
"bool11": ConfigValue{Value: "true", Secret: true},
"bool12": ConfigValue{Value: "true", Secret: true},
"int1": ConfigValue{Value: "1", Secret: true},
"int2": ConfigValue{Value: "2", Secret: true},
"int3": ConfigValue{Value: "3", Secret: true},
"int4": ConfigValue{Value: "4", Secret: true},
"int5": ConfigValue{Value: "5", Secret: true},
"int6": ConfigValue{Value: "6", Secret: true},
"int7": ConfigValue{Value: "7", Secret: true},
"int8": ConfigValue{Value: "8", Secret: true},
"int9": ConfigValue{Value: "9", Secret: true},
"int10": ConfigValue{Value: "10", Secret: true},
"int11": ConfigValue{Value: "11", Secret: true},
"int12": ConfigValue{Value: "12", Secret: true},
"float1": ConfigValue{Value: "1.1", Secret: true},
"float2": ConfigValue{Value: "2.2", Secret: true},
"float3": ConfigValue{Value: "3.3", Secret: true},
"float4": ConfigValue{Value: "4.4", Secret: true},
"float5": ConfigValue{Value: "5.5", Secret: true},
"float6": ConfigValue{Value: "6.6", Secret: true},
"float7": ConfigValue{Value: "7.7", Secret: true},
"float8": ConfigValue{Value: "8.8", Secret: true},
"float9": ConfigValue{Value: "9.9", Secret: true},
"float10": ConfigValue{Value: "10.1", Secret: true},
"float11": ConfigValue{Value: "11.11", Secret: true},
"float12": ConfigValue{Value: "12.12", Secret: true},
"obj1": ConfigValue{Value: "{}", Secret: true},
"obj2": ConfigValue{Value: "{}", Secret: true},
"obj3": ConfigValue{Value: "{}", Secret: true},
"obj4": ConfigValue{Value: "{}", Secret: true},
"obj5": ConfigValue{Value: "{}", Secret: true},
"obj6": ConfigValue{Value: "{}", Secret: true},
"obj7": ConfigValue{Value: "{}", Secret: true},
"obj8": ConfigValue{Value: "{}", Secret: true},
"obj9": ConfigValue{Value: "{}", Secret: true},
"obj10": ConfigValue{Value: "{}", Secret: true},
"obj11": ConfigValue{Value: "{}", Secret: true},
"obj12": ConfigValue{Value: "{}", Secret: true},
}
// initialize
//nolint:errcheck
s, err := NewStackInlineSource(ctx, stackName, pName, func(ctx *pulumi.Context) error {
c := config.New(ctx, "")
config.Get(ctx, "plainstr1")
config.Require(ctx, "plainstr2")
config.Try(ctx, "plainstr3")
config.GetSecret(ctx, "plainstr4")
config.RequireSecret(ctx, "plainstr5")
config.TrySecret(ctx, "plainstr6")
c.Get("plainstr7")
c.Require("plainstr8")
c.Try("plainstr9")
c.GetSecret("plainstr10")
c.RequireSecret("plainstr11")
c.TrySecret("plainstr12")
config.GetBool(ctx, "plainbool1")
config.RequireBool(ctx, "plainbool2")
config.TryBool(ctx, "plainbool3")
config.GetSecretBool(ctx, "plainbool4")
config.RequireSecretBool(ctx, "plainbool5")
config.TrySecretBool(ctx, "plainbool6")
c.GetBool("plainbool7")
c.RequireBool("plainbool8")
c.TryBool("plainbool9")
c.GetSecretBool("plainbool10")
c.RequireSecretBool("plainbool11")
c.TrySecretBool("plainbool12")
config.GetInt(ctx, "plainint1")
config.RequireInt(ctx, "plainint2")
config.TryInt(ctx, "plainint3")
config.GetSecretInt(ctx, "plainint4")
config.RequireSecretInt(ctx, "plainint5")
config.TrySecretInt(ctx, "plainint6")
c.GetInt("plainint7")
c.RequireInt("plainint8")
c.TryInt("plainint9")
c.GetSecretInt("plainint10")
c.RequireSecretInt("plainint11")
c.TrySecretInt("plainint12")
config.GetFloat64(ctx, "plainfloat1")
config.RequireFloat64(ctx, "plainfloat2")
config.TryFloat64(ctx, "plainfloat3")
config.GetSecretFloat64(ctx, "plainfloat4")
config.RequireSecretFloat64(ctx, "plainfloat5")
config.TrySecretFloat64(ctx, "plainfloat6")
c.GetFloat64("plainfloat7")
c.RequireFloat64("plainfloat8")
c.TryFloat64("plainfloat9")
c.GetSecretFloat64("plainfloat10")
c.RequireSecretFloat64("plainfloat11")
c.TrySecretFloat64("plainfloat12")
var obj interface{}
config.GetObject(ctx, "plainobjj1", &obj)
config.RequireObject(ctx, "plainobj2", &obj)
config.TryObject(ctx, "plainobj3", &obj)
config.GetSecretObject(ctx, "plainobj4", &obj)
config.RequireSecretObject(ctx, "plainobj5", &obj)
config.TrySecretObject(ctx, "plainobj6", &obj)
c.GetObject("plainobjj7", &obj)
c.RequireObject("plainobj8", &obj)
c.TryObject("plainobj9", &obj)
c.GetSecretObject("plainobj10", &obj)
c.RequireSecretObject("plainobj11", &obj)
c.TrySecretObject("plainobj12", &obj)
config.Get(ctx, "str1")
config.Require(ctx, "str2")
config.Try(ctx, "str3")
config.GetSecret(ctx, "str4")
config.RequireSecret(ctx, "str5")
config.TrySecret(ctx, "str6")
c.Get("str7")
c.Require("str8")
c.Try("str9")
c.GetSecret("str10")
c.RequireSecret("str11")
c.TrySecret("str12")
config.GetBool(ctx, "bool1")
config.RequireBool(ctx, "bool2")
config.TryBool(ctx, "bool3")
config.GetSecretBool(ctx, "bool4")
config.RequireSecretBool(ctx, "bool5")
config.TrySecretBool(ctx, "bool6")
c.GetBool("bool7")
c.RequireBool("bool8")
c.TryBool("bool9")
c.GetSecretBool("bool10")
c.RequireSecretBool("bool11")
c.TrySecretBool("bool12")
config.GetInt(ctx, "int1")
config.RequireInt(ctx, "int2")
config.TryInt(ctx, "int3")
config.GetSecretInt(ctx, "int4")
config.RequireSecretInt(ctx, "int5")
config.TrySecretInt(ctx, "int6")
c.GetInt("int7")
c.RequireInt("int8")
c.TryInt("int9")
c.GetSecretInt("int10")
c.RequireSecretInt("int11")
c.TrySecretInt("int12")
config.GetFloat64(ctx, "float1")
config.RequireFloat64(ctx, "float2")
config.TryFloat64(ctx, "float3")
config.GetSecretFloat64(ctx, "float4")
config.RequireSecretFloat64(ctx, "float5")
config.TrySecretFloat64(ctx, "float6")
c.GetFloat64("float7")
c.RequireFloat64("float8")
c.TryFloat64("float9")
c.GetSecretFloat64("float10")
c.RequireSecretFloat64("float11")
c.TrySecretFloat64("float12")
config.GetObject(ctx, "obj1", &obj)
config.RequireObject(ctx, "obj2", &obj)
config.TryObject(ctx, "obj3", &obj)
config.GetSecretObject(ctx, "obj4", &obj)
config.RequireSecretObject(ctx, "obj5", &obj)
config.TrySecretObject(ctx, "obj6", &obj)
c.GetObject("obj7", &obj)
c.RequireObject("obj8", &obj)
c.TryObject("obj9", &obj)
c.GetSecretObject("obj10", &obj)
c.RequireSecretObject("obj11", &obj)
c.TrySecretObject("obj12", &obj)
return nil
})
if err != nil {
t.Errorf("failed to initialize stack, err: %v", err)
t.FailNow()
}
defer func() {
// -- pulumi stack rm --
err = s.Workspace().RemoveStack(ctx, s.Name())
assert.Nil(t, err, "failed to remove stack. Resources have leaked.")
}()
err = s.SetAllConfig(ctx, cfg)
if err != nil {
t.Errorf("failed to set config, err: %v", err)
t.FailNow()
}
validate := func(engineEvents []events.EngineEvent) {
expectedWarnings := []string{
"Configuration 'testproj:str1' value is a secret; use `GetSecret` instead of `Get`",
"Configuration 'testproj:str2' value is a secret; use `RequireSecret` instead of `Require`",
"Configuration 'testproj:str3' value is a secret; use `TrySecret` instead of `Try`",
"Configuration 'testproj:str7' value is a secret; use `GetSecret` instead of `Get`",
"Configuration 'testproj:str8' value is a secret; use `RequireSecret` instead of `Require`",
"Configuration 'testproj:str9' value is a secret; use `TrySecret` instead of `Try`",
"Configuration 'testproj:bool1' value is a secret; use `GetSecretBool` instead of `GetBool`",
"Configuration 'testproj:bool2' value is a secret; use `RequireSecretBool` instead of `RequireBool`",
"Configuration 'testproj:bool3' value is a secret; use `TrySecretBool` instead of `TryBool`",
"Configuration 'testproj:bool7' value is a secret; use `GetSecretBool` instead of `GetBool`",
"Configuration 'testproj:bool8' value is a secret; use `RequireSecretBool` instead of `RequireBool`",
"Configuration 'testproj:bool9' value is a secret; use `TrySecretBool` instead of `TryBool`",
"Configuration 'testproj:int1' value is a secret; use `GetSecretInt` instead of `GetInt`",
"Configuration 'testproj:int2' value is a secret; use `RequireSecretInt` instead of `RequireInt`",
"Configuration 'testproj:int3' value is a secret; use `TrySecretInt` instead of `TryInt`",
"Configuration 'testproj:int7' value is a secret; use `GetSecretInt` instead of `GetInt`",
"Configuration 'testproj:int8' value is a secret; use `RequireSecretInt` instead of `RequireInt`",
"Configuration 'testproj:int9' value is a secret; use `TrySecretInt` instead of `TryInt`",
"Configuration 'testproj:float1' value is a secret; use `GetSecretFloat64` instead of `GetFloat64`",
"Configuration 'testproj:float2' value is a secret; use `RequireSecretFloat64` instead of `RequireFloat64`",
"Configuration 'testproj:float3' value is a secret; use `TrySecretFloat64` instead of `TryFloat64`",
"Configuration 'testproj:float7' value is a secret; use `GetSecretFloat64` instead of `GetFloat64`",
"Configuration 'testproj:float8' value is a secret; use `RequireSecretFloat64` instead of `RequireFloat64`",
"Configuration 'testproj:float9' value is a secret; use `TrySecretFloat64` instead of `TryFloat64`",
"Configuration 'testproj:obj1' value is a secret; use `GetSecretObject` instead of `GetObject`",
"Configuration 'testproj:obj2' value is a secret; use `RequireSecretObject` instead of `RequireObject`",
"Configuration 'testproj:obj3' value is a secret; use `TrySecretObject` instead of `TryObject`",
"Configuration 'testproj:obj7' value is a secret; use `GetSecretObject` instead of `GetObject`",
"Configuration 'testproj:obj8' value is a secret; use `RequireSecretObject` instead of `RequireObject`",
"Configuration 'testproj:obj9' value is a secret; use `TrySecretObject` instead of `TryObject`",
}
for _, warning := range expectedWarnings {
var found bool
for _, event := range engineEvents {
if event.DiagnosticEvent != nil && event.DiagnosticEvent.Severity == "warning" &&
strings.Contains(event.DiagnosticEvent.Message, warning) {
found = true
break
}
}
assert.True(t, found, "expected warning %q", warning)
}
// These keys should not be in any warning messages.
unexpectedWarnings := []string{
"plainstr1",
"plainstr2",
"plainstr3",
"plainstr4",
"plainstr5",
"plainstr6",
"plainstr7",
"plainstr8",
"plainstr9",
"plainstr10",
"plainstr11",
"plainstr12",
"plainbool1",
"plainbool2",
"plainbool3",
"plainbool4",
"plainbool5",
"plainbool6",
"plainbool7",
"plainbool8",
"plainbool9",
"plainbool10",
"plainbool11",
"plainbool12",
"plainint1",
"plainint2",
"plainint3",
"plainint4",
"plainint5",
"plainint6",
"plainint7",
"plainint8",
"plainint9",
"plainint10",
"plainint11",
"plainint12",
"plainfloat1",
"plainfloat2",
"plainfloat3",
"plainfloat4",
"plainfloat5",
"plainfloat6",
"plainfloat7",
"plainfloat8",
"plainfloat9",
"plainfloat10",
"plainfloat11",
"plainfloat12",
"plainobj1",
"plainobj2",
"plainobj3",
"plainobj4",
"plainobj5",
"plainobj6",
"plainobj7",
"plainobj8",
"plainobj9",
"plainobj10",
"plainobj11",
"plainobj12",
}
for _, warning := range unexpectedWarnings {
for _, event := range engineEvents {
if event.DiagnosticEvent != nil {
assert.NotContains(t, event.DiagnosticEvent.Message, warning)
}
}
}
}
// -- pulumi up --
var upEvents []events.EngineEvent
upCh := make(chan events.EngineEvent)
go collectEvents(upCh, &upEvents)
_, err = s.Up(ctx, optup.EventStreams(upCh))
if err != nil {
t.Errorf("up failed, err: %v", err)
t.FailNow()
}
validate(upEvents)
// -- pulumi preview --
var previewEvents []events.EngineEvent
prevCh := make(chan events.EngineEvent)
go collectEvents(prevCh, &previewEvents)
_, err = s.Preview(ctx, optpreview.EventStreams(prevCh))
if err != nil {
t.Errorf("preview failed, err: %v", err)
t.FailNow()
}
validate(previewEvents)
}
func BenchmarkBulkSetConfigMixed(b *testing.B) {
ctx := context.Background()
stackName := FullyQualifiedStackName(pulumiOrg, "set_config_mixed", "dev")
// initialize
s, err := NewStackInlineSource(ctx, stackName, "set_config_mixed", func(ctx *pulumi.Context) error { return nil })
if err != nil {
b.Errorf("failed to initialize stack, err: %v", err)
b.FailNow()
}
cfg := ConfigMap{
"one": ConfigValue{Value: "one", Secret: true},
"two": ConfigValue{Value: "two"},
"three": ConfigValue{Value: "three", Secret: true},
"four": ConfigValue{Value: "four"},
"five": ConfigValue{Value: "five", Secret: true},
"six": ConfigValue{Value: "six"},
"seven": ConfigValue{Value: "seven", Secret: true},
"eight": ConfigValue{Value: "eight"},
"nine": ConfigValue{Value: "nine", Secret: true},
"ten": ConfigValue{Value: "ten"},
"eleven": ConfigValue{Value: "one", Secret: true},
"twelve": ConfigValue{Value: "two"},
"thirteen": ConfigValue{Value: "three", Secret: true},
"fourteen": ConfigValue{Value: "four"},
"fifteen": ConfigValue{Value: "five", Secret: true},
"sixteen": ConfigValue{Value: "six"},
"seventeen": ConfigValue{Value: "seven", Secret: true},
"eighteen": ConfigValue{Value: "eight"},
"nineteen": ConfigValue{Value: "nine", Secret: true},
"twenty": ConfigValue{Value: "ten"},
"one1": ConfigValue{Value: "one", Secret: true},
"two1": ConfigValue{Value: "two"},
"three1": ConfigValue{Value: "three", Secret: true},
"four1": ConfigValue{Value: "four"},
"five1": ConfigValue{Value: "five", Secret: true},
"six1": ConfigValue{Value: "six"},
"seven1": ConfigValue{Value: "seven", Secret: true},
"eight1": ConfigValue{Value: "eight"},
"nine1": ConfigValue{Value: "nine", Secret: true},
"ten1": ConfigValue{Value: "ten"},
"eleven1": ConfigValue{Value: "one", Secret: true},
"twelve1": ConfigValue{Value: "two"},
"thirteen1": ConfigValue{Value: "three", Secret: true},
"fourteen1": ConfigValue{Value: "four"},
"fifteen1": ConfigValue{Value: "five", Secret: true},
"sixteen1": ConfigValue{Value: "six"},
"seventeen1": ConfigValue{Value: "seven", Secret: true},
"eighteen1": ConfigValue{Value: "eight"},
"nineteen1": ConfigValue{Value: "nine", Secret: true},
"twenty1": ConfigValue{Value: "ten"},
}
err = s.SetAllConfig(ctx, cfg)
if err != nil {
b.Errorf("failed to set config, err: %v", err)
b.FailNow()
}
defer func() {
// -- pulumi stack rm --
err = s.Workspace().RemoveStack(ctx, s.Name())
assert.Nil(b, err, "failed to remove stack. Resources have leaked.")
}()
}
func BenchmarkBulkSetConfigPlain(b *testing.B) {
ctx := context.Background()
stackName := FullyQualifiedStackName(pulumiOrg, "set_config_plain", "dev")
// initialize
s, err := NewStackInlineSource(ctx, stackName, "set_config_plain", func(ctx *pulumi.Context) error { return nil })
if err != nil {
b.Errorf("failed to initialize stack, err: %v", err)
b.FailNow()
}
cfg := ConfigMap{
"one": ConfigValue{Value: "one"},
"two": ConfigValue{Value: "two"},
"three": ConfigValue{Value: "three"},
"four": ConfigValue{Value: "four"},
"five": ConfigValue{Value: "five"},
"six": ConfigValue{Value: "six"},
"seven": ConfigValue{Value: "seven"},
"eight": ConfigValue{Value: "eight"},
"nine": ConfigValue{Value: "nine"},
"ten": ConfigValue{Value: "ten"},
"eleven": ConfigValue{Value: "one"},
"twelve": ConfigValue{Value: "two"},
"thirteen": ConfigValue{Value: "three"},
"fourteen": ConfigValue{Value: "four"},
"fifteen": ConfigValue{Value: "five"},
"sixteen": ConfigValue{Value: "six"},
"seventeen": ConfigValue{Value: "seven"},
"eighteen": ConfigValue{Value: "eight"},
"nineteen": ConfigValue{Value: "nine"},
"twenty": ConfigValue{Value: "ten"},
"one1": ConfigValue{Value: "one"},
"two1": ConfigValue{Value: "two"},
"three1": ConfigValue{Value: "three"},
"four1": ConfigValue{Value: "four"},
"five1": ConfigValue{Value: "five"},
"six1": ConfigValue{Value: "six"},
"seven1": ConfigValue{Value: "seven"},
"eight1": ConfigValue{Value: "eight"},
"nine1": ConfigValue{Value: "nine"},
"ten1": ConfigValue{Value: "ten"},
"eleven1": ConfigValue{Value: "one"},
"twelve1": ConfigValue{Value: "two"},
"thirteen1": ConfigValue{Value: "three"},
"fourteen1": ConfigValue{Value: "four"},
"fifteen1": ConfigValue{Value: "five"},
"sixteen1": ConfigValue{Value: "six"},
"seventeen1": ConfigValue{Value: "seven"},
"eighteen1": ConfigValue{Value: "eight"},
"nineteen1": ConfigValue{Value: "nine"},
"twenty1": ConfigValue{Value: "ten"},
}
err = s.SetAllConfig(ctx, cfg)
if err != nil {
b.Errorf("failed to set config, err: %v", err)
b.FailNow()
}
defer func() {
// -- pulumi stack rm --
err = s.Workspace().RemoveStack(ctx, s.Name())
assert.Nil(b, err, "failed to remove stack. Resources have leaked.")
}()
}
func BenchmarkBulkSetConfigSecret(b *testing.B) {
ctx := context.Background()
stackName := FullyQualifiedStackName(pulumiOrg, "set_config_plain", "dev")
// initialize
s, err := NewStackInlineSource(ctx, stackName, "set_config_plain", func(ctx *pulumi.Context) error { return nil })
if err != nil {
b.Errorf("failed to initialize stack, err: %v", err)
b.FailNow()
}
cfg := ConfigMap{
"one": ConfigValue{Value: "one", Secret: true},
"two": ConfigValue{Value: "two", Secret: true},
"three": ConfigValue{Value: "three", Secret: true},
"four": ConfigValue{Value: "four", Secret: true},
"five": ConfigValue{Value: "five", Secret: true},
"six": ConfigValue{Value: "six", Secret: true},
"seven": ConfigValue{Value: "seven", Secret: true},
"eight": ConfigValue{Value: "eight", Secret: true},
"nine": ConfigValue{Value: "nine", Secret: true},
"ten": ConfigValue{Value: "ten", Secret: true},
"eleven": ConfigValue{Value: "one", Secret: true},
"twelve": ConfigValue{Value: "two", Secret: true},
"thirteen": ConfigValue{Value: "three", Secret: true},
"fourteen": ConfigValue{Value: "four", Secret: true},
"fifteen": ConfigValue{Value: "five", Secret: true},
"sixteen": ConfigValue{Value: "six", Secret: true},
"seventeen": ConfigValue{Value: "seven", Secret: true},
"eighteen": ConfigValue{Value: "eight", Secret: true},
"nineteen": ConfigValue{Value: "nine", Secret: true},
"1twenty": ConfigValue{Value: "ten", Secret: true},
"one1": ConfigValue{Value: "one", Secret: true},
"two1": ConfigValue{Value: "two", Secret: true},
"three1": ConfigValue{Value: "three", Secret: true},
"four1": ConfigValue{Value: "four", Secret: true},
"five1": ConfigValue{Value: "five", Secret: true},
"six1": ConfigValue{Value: "six", Secret: true},
"seven1": ConfigValue{Value: "seven", Secret: true},
"eight1": ConfigValue{Value: "eight", Secret: true},
"nine1": ConfigValue{Value: "nine", Secret: true},
"ten1": ConfigValue{Value: "ten", Secret: true},
"eleven1": ConfigValue{Value: "one", Secret: true},
"twelve1": ConfigValue{Value: "two", Secret: true},
"thirteen1": ConfigValue{Value: "three", Secret: true},
"fourteen1": ConfigValue{Value: "four", Secret: true},
"fifteen1": ConfigValue{Value: "five", Secret: true},
"sixteen1": ConfigValue{Value: "six", Secret: true},
"seventeen1": ConfigValue{Value: "seven", Secret: true},
"eighteen1": ConfigValue{Value: "eight", Secret: true},
"nineteen1": ConfigValue{Value: "nine", Secret: true},
"twenty1": ConfigValue{Value: "ten", Secret: true},
}
err = s.SetAllConfig(ctx, cfg)
if err != nil {
b.Errorf("failed to set config, err: %v", err)
b.FailNow()
}
defer func() {
// -- pulumi stack rm --
err = s.Workspace().RemoveStack(ctx, s.Name())
assert.Nil(b, err, "failed to remove stack. Resources have leaked.")
}()
}
func getTestOrg() string {
testOrg := "pulumi-test"
if _, set := os.LookupEnv("PULUMI_TEST_ORG"); set {
testOrg = os.Getenv("PULUMI_TEST_ORG")
}
return testOrg
}
func countSteps(log []events.EngineEvent) int {
steps := 0
for _, e := range log {
if e.ResourcePreEvent != nil {
steps++
}
}
return steps
}
func containsSummary(log []events.EngineEvent) bool {
hasSummary := false
for _, e := range log {
if e.SummaryEvent != nil {
hasSummary = true
}
}
return hasSummary
}
func collectEvents(eventChannel <-chan events.EngineEvent, events *[]events.EngineEvent) {
for {
event, ok := <-eventChannel
if !ok {
return
}
*events = append(*events, event)
}
}