2022-11-03 20:30:35 +00:00
|
|
|
// Copyright 2016-2022, 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.
|
|
|
|
|
2023-01-30 19:30:30 +00:00
|
|
|
//go:build (go || all) && !xplatform_acceptance
|
2020-09-02 16:11:15 +00:00
|
|
|
|
|
|
|
package ints
|
|
|
|
|
|
|
|
import (
|
2022-08-26 14:16:48 +00:00
|
|
|
"bytes"
|
2023-07-11 15:39:45 +00:00
|
|
|
"context"
|
2020-09-02 16:11:15 +00:00
|
|
|
"os"
|
|
|
|
"path/filepath"
|
|
|
|
"runtime"
|
2021-05-18 22:02:43 +00:00
|
|
|
"strings"
|
2020-09-02 16:11:15 +00:00
|
|
|
"testing"
|
|
|
|
|
2023-07-11 15:39:45 +00:00
|
|
|
"github.com/grapl-security/pulumi-hcp/sdk/go/hcp"
|
2023-11-30 14:21:35 +00:00
|
|
|
"github.com/pulumi/appdash"
|
2021-06-11 02:57:18 +00:00
|
|
|
"github.com/stretchr/testify/assert"
|
2023-07-11 15:39:45 +00:00
|
|
|
"github.com/stretchr/testify/require"
|
2021-06-11 02:57:18 +00:00
|
|
|
|
2021-03-17 13:20:05 +00:00
|
|
|
"github.com/pulumi/pulumi/pkg/v3/testing/integration"
|
2023-07-11 15:39:45 +00:00
|
|
|
"github.com/pulumi/pulumi/sdk/v3/go/auto"
|
2021-03-17 13:20:05 +00:00
|
|
|
"github.com/pulumi/pulumi/sdk/v3/go/common/resource"
|
2021-08-27 18:25:10 +00:00
|
|
|
ptesting "github.com/pulumi/pulumi/sdk/v3/go/common/testing"
|
2023-07-11 15:39:45 +00:00
|
|
|
"github.com/pulumi/pulumi/sdk/v3/go/common/workspace"
|
|
|
|
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
|
2020-09-02 16:11:15 +00:00
|
|
|
)
|
|
|
|
|
2022-09-14 21:48:09 +00:00
|
|
|
// This checks that the buildTarget option for Pulumi Go programs does build a binary.
|
|
|
|
func TestBuildTarget(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
e := ptesting.NewEnvironment(t)
|
2024-07-23 10:37:01 +00:00
|
|
|
defer e.DeleteIfNotFailed()
|
2022-09-14 21:48:09 +00:00
|
|
|
e.ImportDirectory(filepath.Join("go", "go-build-target"))
|
|
|
|
|
|
|
|
e.RunCommand("pulumi", "login", "--cloud-url", e.LocalURL())
|
|
|
|
e.RunCommand("pulumi", "stack", "init", "go-build-target-test-stack")
|
|
|
|
e.RunCommand("pulumi", "stack", "select", "go-build-target-test-stack")
|
|
|
|
e.RunCommand("pulumi", "preview")
|
|
|
|
_, err := os.Stat(filepath.Join(e.RootPath, "a.out"))
|
|
|
|
assert.NoError(t, err)
|
|
|
|
}
|
|
|
|
|
2022-08-26 14:16:48 +00:00
|
|
|
// This checks that the Exit Status artifact from Go Run is not being produced
|
2023-12-02 17:16:09 +00:00
|
|
|
//
|
|
|
|
//nolint:paralleltest // ProgramTest calls t.Parallel()
|
2022-08-26 14:16:48 +00:00
|
|
|
func TestNoEmitExitStatus(t *testing.T) {
|
|
|
|
stderr := &bytes.Buffer{}
|
|
|
|
integration.ProgramTest(t, &integration.ProgramTestOptions{
|
|
|
|
Dir: filepath.Join("go", "go-exit-5"),
|
|
|
|
Dependencies: []string{
|
|
|
|
"github.com/pulumi/pulumi/sdk/v3",
|
|
|
|
},
|
|
|
|
Stderr: stderr,
|
|
|
|
ExpectFailure: true,
|
|
|
|
Quick: true,
|
2022-09-14 03:07:59 +00:00
|
|
|
SkipRefresh: true,
|
2022-08-26 14:16:48 +00:00
|
|
|
ExtraRuntimeValidation: func(t *testing.T, stackInfo integration.RuntimeValidationStackInfo) {
|
|
|
|
// ensure exit status is not emitted by the program
|
|
|
|
assert.NotContains(t, stderr.String(), "exit status")
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2023-12-02 17:16:09 +00:00
|
|
|
//nolint:paralleltest // ProgramTest calls t.Parallel()
|
2023-05-19 18:04:48 +00:00
|
|
|
func TestPanickingProgram(t *testing.T) {
|
|
|
|
var stderr bytes.Buffer
|
|
|
|
integration.ProgramTest(t, &integration.ProgramTestOptions{
|
|
|
|
Dir: filepath.Join("go", "program-panic"),
|
|
|
|
Dependencies: []string{
|
|
|
|
"github.com/pulumi/pulumi/sdk/v3",
|
|
|
|
},
|
|
|
|
Stderr: &stderr,
|
|
|
|
ExpectFailure: true,
|
|
|
|
Quick: true,
|
|
|
|
SkipRefresh: true,
|
|
|
|
ExtraRuntimeValidation: func(t *testing.T, stackInfo integration.RuntimeValidationStackInfo) {
|
|
|
|
assert.Contains(t, stderr.String(), "panic: great sadness\n")
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestPanickingComponentConfigure(t *testing.T) {
|
2023-12-02 17:16:09 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2023-05-19 18:04:48 +00:00
|
|
|
var (
|
|
|
|
testDir = filepath.Join("go", "component-configure-panic")
|
|
|
|
componentDir = "testcomponent-go"
|
|
|
|
)
|
|
|
|
runComponentSetup(t, testDir)
|
|
|
|
|
|
|
|
var stderr bytes.Buffer
|
|
|
|
integration.ProgramTest(t, &integration.ProgramTestOptions{
|
|
|
|
Dir: filepath.Join("go", "component-configure-panic", "go"),
|
|
|
|
Dependencies: []string{
|
|
|
|
"github.com/pulumi/pulumi/sdk/v3",
|
|
|
|
},
|
|
|
|
LocalProviders: []integration.LocalDependency{
|
|
|
|
{
|
|
|
|
Package: "testcomponent",
|
|
|
|
Path: filepath.Join(testDir, componentDir),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Stderr: &stderr,
|
|
|
|
ExpectFailure: true,
|
|
|
|
Quick: true,
|
|
|
|
SkipRefresh: true,
|
2023-12-02 17:16:09 +00:00
|
|
|
NoParallel: true,
|
2023-05-19 18:04:48 +00:00
|
|
|
ExtraRuntimeValidation: func(t *testing.T, stackInfo integration.RuntimeValidationStackInfo) {
|
|
|
|
assert.Contains(t, stderr.String(), "panic: great sadness\n")
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2022-09-06 23:44:29 +00:00
|
|
|
// This checks that error logs are not being emitted twice
|
2023-12-02 17:16:09 +00:00
|
|
|
//
|
|
|
|
//nolint:paralleltest // ProgramTest calls t.Parallel()
|
2022-09-06 23:44:29 +00:00
|
|
|
func TestNoLogError(t *testing.T) {
|
|
|
|
stdout := &bytes.Buffer{}
|
|
|
|
stderr := &bytes.Buffer{}
|
|
|
|
integration.ProgramTest(t, &integration.ProgramTestOptions{
|
|
|
|
Dir: filepath.Join("go", "go-exit-error"),
|
|
|
|
Dependencies: []string{
|
|
|
|
"github.com/pulumi/pulumi/sdk/v3",
|
|
|
|
},
|
|
|
|
Stdout: stdout,
|
|
|
|
Stderr: stderr,
|
|
|
|
Quick: true,
|
|
|
|
ExpectFailure: true,
|
|
|
|
ExtraRuntimeValidation: func(t *testing.T, stackInfo integration.RuntimeValidationStackInfo) {
|
|
|
|
errorCount := strings.Count(stderr.String()+stdout.String(), " error: ")
|
|
|
|
|
|
|
|
// ensure ` error: ` is only being shown once by the program
|
|
|
|
assert.Equal(t, 1, errorCount)
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2022-08-26 14:16:48 +00:00
|
|
|
// This checks that the PULUMI_GO_USE_RUN=true flag is triggering go run by checking the `exit status`
|
|
|
|
// string is being emitted. This is a temporary fallback measure in case it breaks users and should
|
|
|
|
// not be assumed to be stable.
|
2023-12-02 17:16:09 +00:00
|
|
|
//
|
|
|
|
//nolint:paralleltest // ProgramTest calls t.Parallel()
|
2022-08-26 14:16:48 +00:00
|
|
|
func TestGoRunEnvFlag(t *testing.T) {
|
|
|
|
stderr := &bytes.Buffer{}
|
|
|
|
integration.ProgramTest(t, &integration.ProgramTestOptions{
|
|
|
|
Env: []string{"PULUMI_GO_USE_RUN=true"},
|
|
|
|
Dir: filepath.Join("go", "go-exit-5"),
|
|
|
|
Dependencies: []string{
|
|
|
|
"github.com/pulumi/pulumi/sdk/v3",
|
|
|
|
},
|
|
|
|
Stderr: stderr,
|
|
|
|
ExpectFailure: true,
|
|
|
|
Quick: true,
|
2022-09-14 03:07:59 +00:00
|
|
|
SkipRefresh: true,
|
2022-08-26 14:16:48 +00:00
|
|
|
ExtraRuntimeValidation: func(t *testing.T, stackInfo integration.RuntimeValidationStackInfo) {
|
|
|
|
// ensure exit status IS emitted by the program as it indicates `go run` was used
|
|
|
|
assert.Contains(t, stderr.String(), "exit status")
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-09-02 16:11:15 +00:00
|
|
|
// TestEmptyGoRun exercises the 'go run' invocation path that doesn't require an explicit build step.
|
2023-12-02 17:16:09 +00:00
|
|
|
//
|
|
|
|
//nolint:paralleltest // ProgramTest calls t.Parallel()
|
2020-09-02 16:11:15 +00:00
|
|
|
func TestEmptyGoRun(t *testing.T) {
|
|
|
|
integration.ProgramTest(t, &integration.ProgramTestOptions{
|
|
|
|
Dir: filepath.Join("empty", "gorun"),
|
|
|
|
Dependencies: []string{
|
2021-03-17 13:20:05 +00:00
|
|
|
"github.com/pulumi/pulumi/sdk/v3",
|
2020-09-02 16:11:15 +00:00
|
|
|
},
|
|
|
|
Quick: true,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// TestEmptyGoRunMain exercises the 'go run' invocation path with a 'main' entrypoint specified in Pulumi.yml
|
2023-12-02 17:16:09 +00:00
|
|
|
//
|
|
|
|
//nolint:paralleltest // ProgramTest calls t.Parallel()
|
2020-09-02 16:11:15 +00:00
|
|
|
func TestEmptyGoRunMain(t *testing.T) {
|
|
|
|
integration.ProgramTest(t, &integration.ProgramTestOptions{
|
|
|
|
Dir: filepath.Join("empty", "gorun_main"),
|
|
|
|
Dependencies: []string{
|
2021-03-17 13:20:05 +00:00
|
|
|
"github.com/pulumi/pulumi/sdk/v3",
|
2020-09-02 16:11:15 +00:00
|
|
|
},
|
|
|
|
Quick: true,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
Fix #3982, missing output which lacks newlines (#8671)
* Fix #3982, missing output which lacks newlines
If the last line printed to stdout or stderr was missing a
terminating newline, it would go entirely missing (in all languages).
The reason for this is a bug in the engine's handling of plugin
outputs: Go's Reader.ReadString('\n') returns a string containing what
was read and/or an error; if the string terminated in a '\n', the
error is nil, and the entire line is returned; if the stream ends,
however, a non-nil error is returned *and* what was read is returned,
even though it wasn't terminated in a newline. The fix is simple:
instead of ignoring that text, we use it, and *then* exit the read-loop.
Also added some test cases since this is subtle and easy to regress.
* Add a changelog entry
2022-01-03 22:39:10 +00:00
|
|
|
// TestPrintfGo tests that we capture stdout and stderr streams properly, even when the last line lacks an \n.
|
2023-12-02 17:16:09 +00:00
|
|
|
//
|
|
|
|
//nolint:paralleltest // ProgramTest calls t.Parallel()
|
Fix #3982, missing output which lacks newlines (#8671)
* Fix #3982, missing output which lacks newlines
If the last line printed to stdout or stderr was missing a
terminating newline, it would go entirely missing (in all languages).
The reason for this is a bug in the engine's handling of plugin
outputs: Go's Reader.ReadString('\n') returns a string containing what
was read and/or an error; if the string terminated in a '\n', the
error is nil, and the entire line is returned; if the stream ends,
however, a non-nil error is returned *and* what was read is returned,
even though it wasn't terminated in a newline. The fix is simple:
instead of ignoring that text, we use it, and *then* exit the read-loop.
Also added some test cases since this is subtle and easy to regress.
* Add a changelog entry
2022-01-03 22:39:10 +00:00
|
|
|
func TestPrintfGo(t *testing.T) {
|
|
|
|
integration.ProgramTest(t, &integration.ProgramTestOptions{
|
|
|
|
Dir: filepath.Join("printf", "go"),
|
|
|
|
Dependencies: []string{
|
|
|
|
"github.com/pulumi/pulumi/sdk/v3",
|
|
|
|
},
|
|
|
|
Quick: true,
|
|
|
|
ExtraRuntimeValidation: printfTestValidation,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-09-02 16:11:15 +00:00
|
|
|
// Tests basic configuration from the perspective of a Pulumi Go program.
|
2023-12-02 17:16:09 +00:00
|
|
|
//
|
|
|
|
//nolint:paralleltest // ProgramTest calls t.Parallel()
|
2020-09-02 16:11:15 +00:00
|
|
|
func TestConfigBasicGo(t *testing.T) {
|
|
|
|
integration.ProgramTest(t, &integration.ProgramTestOptions{
|
2023-06-22 08:45:24 +00:00
|
|
|
Dir: filepath.Join("config_basic", "go"),
|
|
|
|
Dependencies: []string{"github.com/pulumi/pulumi/sdk/v3"},
|
|
|
|
Quick: true,
|
2020-09-02 16:11:15 +00:00
|
|
|
Config: map[string]string{
|
|
|
|
"aConfigValue": "this value is a value",
|
|
|
|
},
|
|
|
|
Secrets: map[string]string{
|
|
|
|
"bEncryptedSecret": "this super secret is encrypted",
|
|
|
|
},
|
|
|
|
OrderedConfig: []integration.ConfigValue{
|
|
|
|
{Key: "outer.inner", Value: "value", Path: true},
|
|
|
|
{Key: "names[0]", Value: "a", Path: true},
|
|
|
|
{Key: "names[1]", Value: "b", Path: true},
|
|
|
|
{Key: "names[2]", Value: "c", Path: true},
|
|
|
|
{Key: "names[3]", Value: "super secret name", Path: true, Secret: true},
|
|
|
|
{Key: "servers[0].port", Value: "80", Path: true},
|
|
|
|
{Key: "servers[0].host", Value: "example", Path: true},
|
|
|
|
{Key: "a.b[0].c", Value: "true", Path: true},
|
|
|
|
{Key: "a.b[1].c", Value: "false", Path: true},
|
|
|
|
{Key: "tokens[0]", Value: "shh", Path: true, Secret: true},
|
|
|
|
{Key: "foo.bar", Value: "don't tell", Path: true, Secret: true},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2023-06-22 08:45:24 +00:00
|
|
|
// Tests configuration error from the perspective of a Pulumi Go program.
|
2023-12-02 17:16:09 +00:00
|
|
|
//
|
|
|
|
//nolint:paralleltest // ProgramTest calls t.Parallel()
|
2023-06-22 08:45:24 +00:00
|
|
|
func TestConfigMissingGo(t *testing.T) {
|
|
|
|
integration.ProgramTest(t, &integration.ProgramTestOptions{
|
|
|
|
Dir: filepath.Join("config_missing", "go"),
|
|
|
|
Dependencies: []string{
|
|
|
|
"github.com/pulumi/pulumi/sdk/v3",
|
|
|
|
},
|
|
|
|
Quick: true,
|
|
|
|
ExpectFailure: true,
|
|
|
|
ExtraRuntimeValidation: func(t *testing.T, stackInfo integration.RuntimeValidationStackInfo) {
|
|
|
|
assert.NotEmpty(t, stackInfo.Events)
|
|
|
|
text1 := "Missing required configuration variable 'config_missing_go:notFound'"
|
|
|
|
text2 := "\tplease set a value using the command `pulumi config set --secret config_missing_go:notFound <value>`"
|
|
|
|
var found1, found2 bool
|
|
|
|
for _, event := range stackInfo.Events {
|
|
|
|
if event.DiagnosticEvent != nil && strings.Contains(event.DiagnosticEvent.Message, text1) {
|
|
|
|
found1 = true
|
|
|
|
}
|
|
|
|
if event.DiagnosticEvent != nil && strings.Contains(event.DiagnosticEvent.Message, text2) {
|
|
|
|
found2 = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
assert.True(t, found1, "expected error %q", text1)
|
|
|
|
assert.True(t, found2, "expected error %q", text2)
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-05-18 22:02:43 +00:00
|
|
|
// Tests that accessing config secrets using non-secret APIs results in warnings being logged.
|
2023-12-02 17:16:09 +00:00
|
|
|
//
|
|
|
|
//nolint:paralleltest // ProgramTest calls t.Parallel()
|
2021-05-18 22:02:43 +00:00
|
|
|
func TestConfigSecretsWarnGo(t *testing.T) {
|
2021-05-24 23:06:27 +00:00
|
|
|
// TODO[pulumi/pulumi#7127]: Re-enabled the warning.
|
|
|
|
t.Skip("Temporarily skipping test until we've re-enabled the warning - pulumi/pulumi#7127")
|
2021-05-18 22:02:43 +00:00
|
|
|
integration.ProgramTest(t, &integration.ProgramTestOptions{
|
|
|
|
Dir: filepath.Join("config_secrets_warn", "go"),
|
|
|
|
Dependencies: []string{
|
|
|
|
"github.com/pulumi/pulumi/sdk/v3",
|
|
|
|
},
|
|
|
|
Quick: true,
|
|
|
|
Config: map[string]string{
|
|
|
|
"plainstr1": "1",
|
|
|
|
"plainstr2": "2",
|
|
|
|
"plainstr3": "3",
|
|
|
|
"plainstr4": "4",
|
|
|
|
"plainstr5": "5",
|
|
|
|
"plainstr6": "6",
|
|
|
|
"plainstr7": "7",
|
|
|
|
"plainstr8": "8",
|
|
|
|
"plainstr9": "9",
|
|
|
|
"plainstr10": "10",
|
|
|
|
"plainstr11": "11",
|
|
|
|
"plainstr12": "12",
|
|
|
|
"plainbool1": "true",
|
|
|
|
"plainbool2": "true",
|
|
|
|
"plainbool3": "true",
|
|
|
|
"plainbool4": "true",
|
|
|
|
"plainbool5": "true",
|
|
|
|
"plainbool6": "true",
|
|
|
|
"plainbool7": "true",
|
|
|
|
"plainbool8": "true",
|
|
|
|
"plainbool9": "true",
|
|
|
|
"plainbool10": "true",
|
|
|
|
"plainbool11": "true",
|
|
|
|
"plainbool12": "true",
|
|
|
|
"plainint1": "1",
|
|
|
|
"plainint2": "2",
|
|
|
|
"plainint3": "3",
|
|
|
|
"plainint4": "4",
|
|
|
|
"plainint5": "5",
|
|
|
|
"plainint6": "6",
|
|
|
|
"plainint7": "7",
|
|
|
|
"plainint8": "8",
|
|
|
|
"plainint9": "9",
|
|
|
|
"plainint10": "10",
|
|
|
|
"plainint11": "11",
|
|
|
|
"plainint12": "12",
|
|
|
|
"plainfloat1": "1.1",
|
|
|
|
"plainfloat2": "2.2",
|
|
|
|
"plainfloat3": "3.3",
|
|
|
|
"plainfloat4": "4.4",
|
|
|
|
"plainfloat5": "5.5",
|
|
|
|
"plainfloat6": "6.6",
|
|
|
|
"plainfloat7": "7.7",
|
|
|
|
"plainfloat8": "8.8",
|
|
|
|
"plainfloat9": "9.9",
|
|
|
|
"plainfloat10": "10.1",
|
|
|
|
"plainfloat11": "11.11",
|
|
|
|
"plainfloat12": "12.12",
|
|
|
|
"plainobj1": "{}",
|
|
|
|
"plainobj2": "{}",
|
|
|
|
"plainobj3": "{}",
|
|
|
|
"plainobj4": "{}",
|
|
|
|
"plainobj5": "{}",
|
|
|
|
"plainobj6": "{}",
|
|
|
|
"plainobj7": "{}",
|
|
|
|
"plainobj8": "{}",
|
|
|
|
"plainobj9": "{}",
|
|
|
|
"plainobj10": "{}",
|
|
|
|
"plainobj11": "{}",
|
|
|
|
"plainobj12": "{}",
|
|
|
|
},
|
|
|
|
Secrets: map[string]string{
|
|
|
|
"str1": "1",
|
|
|
|
"str2": "2",
|
|
|
|
"str3": "3",
|
|
|
|
"str4": "4",
|
|
|
|
"str5": "5",
|
|
|
|
"str6": "6",
|
|
|
|
"str7": "7",
|
|
|
|
"str8": "8",
|
|
|
|
"str9": "9",
|
|
|
|
"str10": "10",
|
|
|
|
"str11": "11",
|
|
|
|
"str12": "12",
|
|
|
|
"bool1": "true",
|
|
|
|
"bool2": "true",
|
|
|
|
"bool3": "true",
|
|
|
|
"bool4": "true",
|
|
|
|
"bool5": "true",
|
|
|
|
"bool6": "true",
|
|
|
|
"bool7": "true",
|
|
|
|
"bool8": "true",
|
|
|
|
"bool9": "true",
|
|
|
|
"bool10": "true",
|
|
|
|
"bool11": "true",
|
|
|
|
"bool12": "true",
|
|
|
|
"int1": "1",
|
|
|
|
"int2": "2",
|
|
|
|
"int3": "3",
|
|
|
|
"int4": "4",
|
|
|
|
"int5": "5",
|
|
|
|
"int6": "6",
|
|
|
|
"int7": "7",
|
|
|
|
"int8": "8",
|
|
|
|
"int9": "9",
|
|
|
|
"int10": "10",
|
|
|
|
"int11": "11",
|
|
|
|
"int12": "12",
|
|
|
|
"float1": "1.1",
|
|
|
|
"float2": "2.2",
|
|
|
|
"float3": "3.3",
|
|
|
|
"float4": "4.4",
|
|
|
|
"float5": "5.5",
|
|
|
|
"float6": "6.6",
|
|
|
|
"float7": "7.7",
|
|
|
|
"float8": "8.8",
|
|
|
|
"float9": "9.9",
|
|
|
|
"float10": "10.1",
|
|
|
|
"float11": "11.11",
|
|
|
|
"float12": "12.12",
|
|
|
|
"obj1": "{}",
|
|
|
|
"obj2": "{}",
|
|
|
|
"obj3": "{}",
|
|
|
|
"obj4": "{}",
|
|
|
|
"obj5": "{}",
|
|
|
|
"obj6": "{}",
|
|
|
|
"obj7": "{}",
|
|
|
|
"obj8": "{}",
|
|
|
|
"obj9": "{}",
|
|
|
|
"obj10": "{}",
|
|
|
|
"obj11": "{}",
|
|
|
|
"obj12": "{}",
|
|
|
|
},
|
|
|
|
OrderedConfig: []integration.ConfigValue{
|
|
|
|
{Key: "parent1.foo", Value: "plain1", Path: true},
|
|
|
|
{Key: "parent1.bar", Value: "secret1", Path: true, Secret: true},
|
|
|
|
{Key: "parent2.foo", Value: "plain2", Path: true},
|
|
|
|
{Key: "parent2.bar", Value: "secret2", Path: true, Secret: true},
|
|
|
|
{Key: "parent3.foo", Value: "plain2", Path: true},
|
|
|
|
{Key: "parent3.bar", Value: "secret2", Path: true, Secret: true},
|
|
|
|
{Key: "names1[0]", Value: "plain1", Path: true},
|
|
|
|
{Key: "names1[1]", Value: "secret1", Path: true, Secret: true},
|
|
|
|
{Key: "names2[0]", Value: "plain2", Path: true},
|
|
|
|
{Key: "names2[1]", Value: "secret2", Path: true, Secret: true},
|
|
|
|
{Key: "names3[0]", Value: "plain2", Path: true},
|
|
|
|
{Key: "names3[1]", Value: "secret2", Path: true, Secret: true},
|
|
|
|
},
|
|
|
|
ExtraRuntimeValidation: func(t *testing.T, stackInfo integration.RuntimeValidationStackInfo) {
|
|
|
|
assert.NotEmpty(t, stackInfo.Events)
|
|
|
|
//nolint:lll
|
|
|
|
expectedWarnings := []string{
|
|
|
|
"Configuration 'config_secrets_go:str1' value is a secret; use `GetSecret` instead of `Get`",
|
|
|
|
"Configuration 'config_secrets_go:str2' value is a secret; use `RequireSecret` instead of `Require`",
|
|
|
|
"Configuration 'config_secrets_go:str3' value is a secret; use `TrySecret` instead of `Try`",
|
|
|
|
"Configuration 'config_secrets_go:str7' value is a secret; use `GetSecret` instead of `Get`",
|
|
|
|
"Configuration 'config_secrets_go:str8' value is a secret; use `RequireSecret` instead of `Require`",
|
|
|
|
"Configuration 'config_secrets_go:str9' value is a secret; use `TrySecret` instead of `Try`",
|
|
|
|
|
|
|
|
"Configuration 'config_secrets_go:bool1' value is a secret; use `GetSecretBool` instead of `GetBool`",
|
|
|
|
"Configuration 'config_secrets_go:bool2' value is a secret; use `RequireSecretBool` instead of `RequireBool`",
|
|
|
|
"Configuration 'config_secrets_go:bool3' value is a secret; use `TrySecretBool` instead of `TryBool`",
|
|
|
|
"Configuration 'config_secrets_go:bool7' value is a secret; use `GetSecretBool` instead of `GetBool`",
|
|
|
|
"Configuration 'config_secrets_go:bool8' value is a secret; use `RequireSecretBool` instead of `RequireBool`",
|
|
|
|
"Configuration 'config_secrets_go:bool9' value is a secret; use `TrySecretBool` instead of `TryBool`",
|
|
|
|
|
|
|
|
"Configuration 'config_secrets_go:int1' value is a secret; use `GetSecretInt` instead of `GetInt`",
|
|
|
|
"Configuration 'config_secrets_go:int2' value is a secret; use `RequireSecretInt` instead of `RequireInt`",
|
|
|
|
"Configuration 'config_secrets_go:int3' value is a secret; use `TrySecretInt` instead of `TryInt`",
|
|
|
|
"Configuration 'config_secrets_go:int7' value is a secret; use `GetSecretInt` instead of `GetInt`",
|
|
|
|
"Configuration 'config_secrets_go:int8' value is a secret; use `RequireSecretInt` instead of `RequireInt`",
|
|
|
|
"Configuration 'config_secrets_go:int9' value is a secret; use `TrySecretInt` instead of `TryInt`",
|
|
|
|
|
|
|
|
"Configuration 'config_secrets_go:float1' value is a secret; use `GetSecretFloat64` instead of `GetFloat64`",
|
|
|
|
"Configuration 'config_secrets_go:float2' value is a secret; use `RequireSecretFloat64` instead of `RequireFloat64`",
|
|
|
|
"Configuration 'config_secrets_go:float3' value is a secret; use `TrySecretFloat64` instead of `TryFloat64`",
|
|
|
|
"Configuration 'config_secrets_go:float7' value is a secret; use `GetSecretFloat64` instead of `GetFloat64`",
|
|
|
|
"Configuration 'config_secrets_go:float8' value is a secret; use `RequireSecretFloat64` instead of `RequireFloat64`",
|
|
|
|
"Configuration 'config_secrets_go:float9' value is a secret; use `TrySecretFloat64` instead of `TryFloat64`",
|
|
|
|
|
|
|
|
"Configuration 'config_secrets_go:obj1' value is a secret; use `GetSecretObject` instead of `GetObject`",
|
|
|
|
"Configuration 'config_secrets_go:obj2' value is a secret; use `RequireSecretObject` instead of `RequireObject`",
|
|
|
|
"Configuration 'config_secrets_go:obj3' value is a secret; use `TrySecretObject` instead of `TryObject`",
|
|
|
|
"Configuration 'config_secrets_go:obj7' value is a secret; use `GetSecretObject` instead of `GetObject`",
|
|
|
|
"Configuration 'config_secrets_go:obj8' value is a secret; use `RequireSecretObject` instead of `RequireObject`",
|
|
|
|
"Configuration 'config_secrets_go:obj9' value is a secret; use `TrySecretObject` instead of `TryObject`",
|
|
|
|
|
|
|
|
"Configuration 'config_secrets_go:parent1' value is a secret; use `GetSecretObject` instead of `GetObject`",
|
|
|
|
"Configuration 'config_secrets_go:parent2' value is a secret; use `RequireSecretObject` instead of `RequireObject`",
|
|
|
|
"Configuration 'config_secrets_go:parent3' value is a secret; use `TrySecretObject` instead of `TryObject`",
|
|
|
|
|
|
|
|
"Configuration 'config_secrets_go:names1' value is a secret; use `GetSecretObject` instead of `GetObject`",
|
|
|
|
"Configuration 'config_secrets_go:names2' value is a secret; use `RequireSecretObject` instead of `RequireObject`",
|
|
|
|
"Configuration 'config_secrets_go:names3' value is a secret; use `TrySecretObject` instead of `TryObject`",
|
|
|
|
}
|
|
|
|
for _, warning := range expectedWarnings {
|
|
|
|
var found bool
|
|
|
|
for _, event := range stackInfo.Events {
|
|
|
|
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 stackInfo.Events {
|
|
|
|
if event.DiagnosticEvent != nil {
|
|
|
|
assert.NotContains(t, event.DiagnosticEvent.Message, warning)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-09-02 16:11:15 +00:00
|
|
|
// Tests a resource with a large (>4mb) string prop in Go
|
2023-12-02 17:16:09 +00:00
|
|
|
//
|
|
|
|
//nolint:paralleltest // ProgramTest calls t.Parallel()
|
2020-09-02 16:11:15 +00:00
|
|
|
func TestLargeResourceGo(t *testing.T) {
|
|
|
|
integration.ProgramTest(t, &integration.ProgramTestOptions{
|
|
|
|
Dependencies: []string{
|
2021-03-17 13:20:05 +00:00
|
|
|
"github.com/pulumi/pulumi/sdk/v3",
|
2020-09-02 16:11:15 +00:00
|
|
|
},
|
|
|
|
Dir: filepath.Join("large_resource", "go"),
|
|
|
|
})
|
|
|
|
}
|
2020-10-29 22:13:17 +00:00
|
|
|
|
2021-04-05 18:11:27 +00:00
|
|
|
// Test remote component construction with a child resource that takes a long time to be created, ensuring it's created.
|
|
|
|
func TestConstructSlowGo(t *testing.T) {
|
2023-12-02 17:16:09 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2022-09-20 15:16:25 +00:00
|
|
|
localProvider := testComponentSlowLocalProvider(t)
|
2022-07-25 15:51:40 +00:00
|
|
|
|
2021-04-05 18:11:27 +00:00
|
|
|
// TODO[pulumi/pulumi#5455]: Dynamic providers fail to load when used from multi-lang components.
|
|
|
|
// Until we've addressed this, set PULUMI_TEST_YARN_LINK_PULUMI, which tells the integration test
|
|
|
|
// module to run `yarn install && yarn link @pulumi/pulumi` in the Go program's directory, allowing
|
|
|
|
// the Node.js dynamic provider plugin to load.
|
|
|
|
// When the underlying issue has been fixed, the use of this environment variable inside the integration
|
|
|
|
// test module should be removed.
|
|
|
|
const testYarnLinkPulumiEnv = "PULUMI_TEST_YARN_LINK_PULUMI=true"
|
|
|
|
|
2022-09-14 02:24:22 +00:00
|
|
|
testDir := "construct_component_slow"
|
|
|
|
runComponentSetup(t, testDir)
|
|
|
|
|
2021-04-15 18:49:51 +00:00
|
|
|
opts := &integration.ProgramTestOptions{
|
2022-09-20 15:16:25 +00:00
|
|
|
Env: []string{testYarnLinkPulumiEnv},
|
2022-09-14 02:24:22 +00:00
|
|
|
Dir: filepath.Join(testDir, "go"),
|
2021-04-05 18:11:27 +00:00
|
|
|
Dependencies: []string{
|
2021-04-01 11:18:12 +00:00
|
|
|
"github.com/pulumi/pulumi/sdk/v3",
|
2021-04-05 18:11:27 +00:00
|
|
|
},
|
2022-09-20 15:16:25 +00:00
|
|
|
LocalProviders: []integration.LocalDependency{localProvider},
|
|
|
|
Quick: true,
|
2023-12-02 17:16:09 +00:00
|
|
|
NoParallel: true,
|
2021-04-05 18:11:27 +00:00
|
|
|
ExtraRuntimeValidation: func(t *testing.T, stackInfo integration.RuntimeValidationStackInfo) {
|
|
|
|
assert.NotNil(t, stackInfo.Deployment)
|
|
|
|
if assert.Equal(t, 5, len(stackInfo.Deployment.Resources)) {
|
|
|
|
stackRes := stackInfo.Deployment.Resources[0]
|
|
|
|
assert.NotNil(t, stackRes)
|
|
|
|
assert.Equal(t, resource.RootStackType, stackRes.Type)
|
|
|
|
assert.Equal(t, "", string(stackRes.Parent))
|
|
|
|
}
|
|
|
|
},
|
|
|
|
}
|
|
|
|
integration.ProgramTest(t, opts)
|
|
|
|
}
|
|
|
|
|
2021-04-09 21:36:22 +00:00
|
|
|
// Test remote component construction with prompt inputs.
|
|
|
|
func TestConstructPlainGo(t *testing.T) {
|
2022-03-04 08:17:41 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2022-09-14 02:24:22 +00:00
|
|
|
testDir := "construct_component_plain"
|
|
|
|
runComponentSetup(t, testDir)
|
|
|
|
|
2021-04-18 16:18:25 +00:00
|
|
|
tests := []struct {
|
|
|
|
componentDir string
|
|
|
|
expectedResourceCount int
|
|
|
|
env []string
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
componentDir: "testcomponent",
|
|
|
|
expectedResourceCount: 9,
|
|
|
|
// TODO[pulumi/pulumi#5455]: Dynamic providers fail to load when used from multi-lang components.
|
|
|
|
// Until we've addressed this, set PULUMI_TEST_YARN_LINK_PULUMI, which tells the integration test
|
|
|
|
// module to run `yarn install && yarn link @pulumi/pulumi` in the Go program's directory, allowing
|
|
|
|
// the Node.js dynamic provider plugin to load.
|
|
|
|
// When the underlying issue has been fixed, the use of this environment variable inside the integration
|
|
|
|
// test module should be removed.
|
|
|
|
env: []string{"PULUMI_TEST_YARN_LINK_PULUMI=true"},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
componentDir: "testcomponent-python",
|
|
|
|
expectedResourceCount: 9,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
componentDir: "testcomponent-go",
|
|
|
|
expectedResourceCount: 8, // One less because no dynamic provider.
|
|
|
|
},
|
|
|
|
}
|
2021-04-09 21:36:22 +00:00
|
|
|
|
2023-12-02 17:16:09 +00:00
|
|
|
//nolint:paralleltest // ProgramTest calls t.Parallel()
|
2021-04-18 16:18:25 +00:00
|
|
|
for _, test := range tests {
|
2022-03-04 08:17:41 +00:00
|
|
|
test := test
|
2021-04-18 16:18:25 +00:00
|
|
|
t.Run(test.componentDir, func(t *testing.T) {
|
2023-03-03 16:36:39 +00:00
|
|
|
localProviders := []integration.LocalDependency{
|
|
|
|
{Package: "testcomponent", Path: filepath.Join(testDir, test.componentDir)},
|
|
|
|
}
|
2021-04-18 16:18:25 +00:00
|
|
|
integration.ProgramTest(t,
|
2022-09-20 15:16:25 +00:00
|
|
|
optsForConstructPlainGo(t, test.expectedResourceCount, localProviders, test.env...))
|
2021-04-18 16:18:25 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2021-04-09 21:36:22 +00:00
|
|
|
|
2023-11-28 16:43:48 +00:00
|
|
|
func optsForConstructPlainGo(
|
|
|
|
t *testing.T, expectedResourceCount int, localProviders []integration.LocalDependency, env ...string,
|
|
|
|
) *integration.ProgramTestOptions {
|
2021-04-18 16:18:25 +00:00
|
|
|
return &integration.ProgramTestOptions{
|
2022-07-25 15:51:40 +00:00
|
|
|
Env: env,
|
|
|
|
Dir: filepath.Join("construct_component_plain", "go"),
|
2021-04-09 21:36:22 +00:00
|
|
|
Dependencies: []string{
|
2022-09-14 03:02:19 +00:00
|
|
|
"github.com/pulumi/pulumi/sdk/v3",
|
2021-04-09 21:36:22 +00:00
|
|
|
},
|
2022-09-20 15:16:25 +00:00
|
|
|
LocalProviders: localProviders,
|
|
|
|
Quick: true,
|
2021-04-09 21:36:22 +00:00
|
|
|
ExtraRuntimeValidation: func(t *testing.T, stackInfo integration.RuntimeValidationStackInfo) {
|
|
|
|
assert.NotNil(t, stackInfo.Deployment)
|
2021-04-18 16:18:25 +00:00
|
|
|
assert.Equal(t, expectedResourceCount, len(stackInfo.Deployment.Resources))
|
2021-04-09 21:36:22 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-21 16:51:41 +00:00
|
|
|
// Test remote component inputs properly handle unknowns.
|
|
|
|
func TestConstructUnknownGo(t *testing.T) {
|
2023-12-02 17:16:09 +00:00
|
|
|
t.Parallel()
|
2021-06-21 16:51:41 +00:00
|
|
|
testConstructUnknown(t, "go", "github.com/pulumi/pulumi/sdk/v3")
|
|
|
|
}
|
|
|
|
|
2021-07-08 00:28:21 +00:00
|
|
|
func TestConstructMethodsGo(t *testing.T) {
|
2022-03-04 08:17:41 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2022-09-14 02:24:22 +00:00
|
|
|
testDir := "construct_component_methods"
|
|
|
|
runComponentSetup(t, testDir)
|
|
|
|
|
2021-07-08 00:28:21 +00:00
|
|
|
tests := []struct {
|
|
|
|
componentDir string
|
2021-07-19 21:58:55 +00:00
|
|
|
env []string
|
2021-07-08 00:28:21 +00:00
|
|
|
}{
|
|
|
|
{
|
|
|
|
componentDir: "testcomponent",
|
|
|
|
},
|
2021-07-19 21:58:55 +00:00
|
|
|
{
|
|
|
|
componentDir: "testcomponent-python",
|
|
|
|
},
|
2021-07-08 00:28:21 +00:00
|
|
|
{
|
|
|
|
componentDir: "testcomponent-go",
|
|
|
|
},
|
|
|
|
}
|
2023-12-02 17:16:09 +00:00
|
|
|
|
|
|
|
//nolint:paralleltest // ProgramTest calls t.Parallel()
|
2021-07-08 00:28:21 +00:00
|
|
|
for _, test := range tests {
|
2022-03-04 08:17:41 +00:00
|
|
|
test := test
|
2021-07-08 00:28:21 +00:00
|
|
|
t.Run(test.componentDir, func(t *testing.T) {
|
2022-09-20 15:16:25 +00:00
|
|
|
localProvider := integration.LocalDependency{
|
2022-09-22 14:10:40 +00:00
|
|
|
Package: "testcomponent", Path: filepath.Join(testDir, test.componentDir),
|
2022-09-20 15:16:25 +00:00
|
|
|
}
|
2021-07-08 00:28:21 +00:00
|
|
|
integration.ProgramTest(t, &integration.ProgramTestOptions{
|
2022-09-20 15:16:25 +00:00
|
|
|
Env: test.env,
|
2022-09-14 02:24:22 +00:00
|
|
|
Dir: filepath.Join(testDir, "go"),
|
2021-07-08 00:28:21 +00:00
|
|
|
Dependencies: []string{
|
|
|
|
"github.com/pulumi/pulumi/sdk/v3",
|
|
|
|
},
|
2022-09-20 15:16:25 +00:00
|
|
|
LocalProviders: []integration.LocalDependency{localProvider},
|
|
|
|
Quick: true,
|
2021-07-08 00:28:21 +00:00
|
|
|
ExtraRuntimeValidation: func(t *testing.T, stackInfo integration.RuntimeValidationStackInfo) {
|
|
|
|
assert.Equal(t, "Hello World, Alice!", stackInfo.Outputs["message"])
|
[sdk/go] Track rehydrated components as dependencies
When expanding dependencies, local component resources act as aggregations of their descendants; rather than adding the component resource itself, each child resource is added as a dependency. Remote component resources, on the other hand, are added directly to the set, as they naturally act as aggregations of their children with respect to dependencies: the construction of a remote component always waits on the construction of its children.
https://github.com/pulumi/pulumi/blob/46ccb5a22caaece6895d828cd019f3886eb7902a/sdk/go/pulumi/rpc.go#L65-L91
However, rehydrated components (i.e. instances of a component resource that have been recreated from a URN, typically via deserialization of a resource reference) won't have any children from the SDK's perspective. And because of that, they aren't currently kept as a dependency.
This change fixes rehydrated components to be marked as remote components, in the same way as "dependency resources" are marked as remote components, so that they are kept as a dependency.
2023-03-24 18:29:42 +00:00
|
|
|
|
|
|
|
// TODO[pulumi/pulumi#12471]: Only the Go SDK has been fixed such that rehydrated
|
|
|
|
// components are kept as dependencies. So only check this for the provider written
|
|
|
|
// in Go. Once the other SDKs are fixed, we can test the other providers as well.
|
|
|
|
if test.componentDir == "testcomponent-go" {
|
|
|
|
var componentURN string
|
|
|
|
for _, res := range stackInfo.Deployment.Resources {
|
|
|
|
if res.URN.Name() == "component" {
|
|
|
|
componentURN = string(res.URN)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
assert.Contains(t, stackInfo.Outputs["messagedeps"], componentURN)
|
|
|
|
}
|
2021-07-08 00:28:21 +00:00
|
|
|
},
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-29 18:11:52 +00:00
|
|
|
func TestConstructMethodsUnknownGo(t *testing.T) {
|
2023-12-02 17:16:09 +00:00
|
|
|
t.Parallel()
|
2021-07-29 18:11:52 +00:00
|
|
|
testConstructMethodsUnknown(t, "go", "github.com/pulumi/pulumi/sdk/v3")
|
|
|
|
}
|
|
|
|
|
2021-11-15 19:17:53 +00:00
|
|
|
func TestConstructMethodsResourcesGo(t *testing.T) {
|
2023-12-02 17:16:09 +00:00
|
|
|
t.Parallel()
|
2021-11-15 19:17:53 +00:00
|
|
|
testConstructMethodsResources(t, "go", "github.com/pulumi/pulumi/sdk/v3")
|
|
|
|
}
|
2021-11-16 16:58:46 +00:00
|
|
|
|
|
|
|
func TestConstructMethodsErrorsGo(t *testing.T) {
|
2023-12-02 17:16:09 +00:00
|
|
|
t.Parallel()
|
2021-11-16 16:58:46 +00:00
|
|
|
testConstructMethodsErrors(t, "go", "github.com/pulumi/pulumi/sdk/v3")
|
|
|
|
}
|
2021-11-15 19:17:53 +00:00
|
|
|
|
[sdk/nodejs] Fix provider for resource methods (#13796)
The `Resource` class in the Node.js SDK has the following internal
property:
```typescript
/** @internal */
readonly __prov?: ProviderResource;
```
When a resource is created, the provider specified for the resource is
stored in this property. If it is set, it is passed along in the `Call`
request when a method is called on the resource.
Prior to #13282, the property was only set for custom resources in
`Resource`'s constructor:
```typescript
this.__prov = custom ? opts.provider : undefined;
```
With #13282, it was changed to also store the value for remote
components:
```diff
- this.__prov = custom ? opts.provider : undefined;
+ this.__prov = custom || remote ? opts.provider : undefined;
```
This regressed the behavior when calling a method on a remote component
that had an explicit provider that wasn't the component provider, but
some other provider (e.g. AWS provider) specified as:
```typescript
const component = new MyRemoteComponent("comp", {
}, { provider: awsProvider });
```
The `awsProvider` was being stored in `Resource.__prov`, and when making
the method call on the resource, it would try to invoke `Call` on the
AWS provider, rather than calling the remote component provider's
`Call`, which resulted in an error.
Note that specifying the AWS provider using the more verbose `providers:
[awsProvider]` works around the issue.
The fix is to only set `__prov` if the provider's package is the same as
the resource's package. Otherwise, don't set it, because the user is
specifying a provider with the `provider: awsProvider` syntax as
shorthand for `providers: [awsProvider]`.
Fixes #13777
2023-08-30 14:49:53 +00:00
|
|
|
func TestConstructMethodsProviderGo(t *testing.T) {
|
2023-12-02 17:16:09 +00:00
|
|
|
t.Parallel()
|
[sdk/nodejs] Fix provider for resource methods (#13796)
The `Resource` class in the Node.js SDK has the following internal
property:
```typescript
/** @internal */
readonly __prov?: ProviderResource;
```
When a resource is created, the provider specified for the resource is
stored in this property. If it is set, it is passed along in the `Call`
request when a method is called on the resource.
Prior to #13282, the property was only set for custom resources in
`Resource`'s constructor:
```typescript
this.__prov = custom ? opts.provider : undefined;
```
With #13282, it was changed to also store the value for remote
components:
```diff
- this.__prov = custom ? opts.provider : undefined;
+ this.__prov = custom || remote ? opts.provider : undefined;
```
This regressed the behavior when calling a method on a remote component
that had an explicit provider that wasn't the component provider, but
some other provider (e.g. AWS provider) specified as:
```typescript
const component = new MyRemoteComponent("comp", {
}, { provider: awsProvider });
```
The `awsProvider` was being stored in `Resource.__prov`, and when making
the method call on the resource, it would try to invoke `Call` on the
AWS provider, rather than calling the remote component provider's
`Call`, which resulted in an error.
Note that specifying the AWS provider using the more verbose `providers:
[awsProvider]` works around the issue.
The fix is to only set `__prov` if the provider's package is the same as
the resource's package. Otherwise, don't set it, because the user is
specifying a provider with the `provider: awsProvider` syntax as
shorthand for `providers: [awsProvider]`.
Fixes #13777
2023-08-30 14:49:53 +00:00
|
|
|
testConstructMethodsProvider(t, "go", "github.com/pulumi/pulumi/sdk/v3")
|
|
|
|
}
|
|
|
|
|
2021-07-23 21:10:06 +00:00
|
|
|
func TestConstructProviderGo(t *testing.T) {
|
2022-03-04 08:17:41 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2021-07-23 21:10:06 +00:00
|
|
|
const testDir = "construct_component_provider"
|
2022-09-14 02:24:22 +00:00
|
|
|
runComponentSetup(t, testDir)
|
|
|
|
|
2021-07-23 21:10:06 +00:00
|
|
|
tests := []struct {
|
|
|
|
componentDir string
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
componentDir: "testcomponent",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
componentDir: "testcomponent-python",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
componentDir: "testcomponent-go",
|
|
|
|
},
|
|
|
|
}
|
2023-12-02 17:16:09 +00:00
|
|
|
|
|
|
|
//nolint:paralleltest // ProgramTest calls t.Parallel()
|
2021-07-23 21:10:06 +00:00
|
|
|
for _, test := range tests {
|
2022-03-04 08:17:41 +00:00
|
|
|
test := test
|
2021-07-23 21:10:06 +00:00
|
|
|
t.Run(test.componentDir, func(t *testing.T) {
|
2022-09-20 15:16:25 +00:00
|
|
|
localProvider := integration.LocalDependency{
|
2022-09-22 14:10:40 +00:00
|
|
|
Package: "testcomponent", Path: filepath.Join(testDir, test.componentDir),
|
2022-09-20 15:16:25 +00:00
|
|
|
}
|
2021-07-23 21:10:06 +00:00
|
|
|
integration.ProgramTest(t, &integration.ProgramTestOptions{
|
|
|
|
Dir: filepath.Join(testDir, "go"),
|
|
|
|
Dependencies: []string{
|
|
|
|
"github.com/pulumi/pulumi/sdk/v3",
|
|
|
|
},
|
2022-09-20 15:16:25 +00:00
|
|
|
LocalProviders: []integration.LocalDependency{localProvider},
|
|
|
|
Quick: true,
|
2021-07-23 21:10:06 +00:00
|
|
|
ExtraRuntimeValidation: func(t *testing.T, stackInfo integration.RuntimeValidationStackInfo) {
|
|
|
|
assert.Equal(t, "hello world", stackInfo.Outputs["message"])
|
|
|
|
},
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-02 17:16:09 +00:00
|
|
|
//nolint:paralleltest // Sets env vars
|
2020-12-01 18:03:47 +00:00
|
|
|
func TestGetResourceGo(t *testing.T) {
|
2023-10-14 08:32:43 +00:00
|
|
|
// This uses the random plugin so needs to be able to download it
|
|
|
|
t.Setenv("PULUMI_DISABLE_AUTOMATIC_PLUGIN_ACQUISITION", "false")
|
|
|
|
|
2020-12-01 18:03:47 +00:00
|
|
|
integration.ProgramTest(t, &integration.ProgramTestOptions{
|
2023-10-14 08:32:43 +00:00
|
|
|
NoParallel: true,
|
2020-12-01 18:03:47 +00:00
|
|
|
Dependencies: []string{
|
2021-03-17 13:20:05 +00:00
|
|
|
"github.com/pulumi/pulumi/sdk/v3",
|
2020-12-01 18:03:47 +00:00
|
|
|
},
|
|
|
|
Dir: filepath.Join("get_resource", "go"),
|
|
|
|
AllowEmptyPreviewChanges: true,
|
2022-07-26 18:04:13 +00:00
|
|
|
Secrets: map[string]string{
|
|
|
|
"bar": "this super secret is encrypted",
|
|
|
|
},
|
2020-12-01 18:03:47 +00:00
|
|
|
ExtraRuntimeValidation: func(t *testing.T, stack integration.RuntimeValidationStackInfo) {
|
|
|
|
assert.NotNil(t, stack.Outputs)
|
|
|
|
assert.Equal(t, float64(2), stack.Outputs["getPetLength"])
|
2022-07-26 18:04:13 +00:00
|
|
|
|
|
|
|
out, ok := stack.Outputs["secret"].(map[string]interface{})
|
|
|
|
assert.True(t, ok)
|
|
|
|
|
|
|
|
_, ok = out["ciphertext"]
|
|
|
|
assert.True(t, ok)
|
2020-12-01 18:03:47 +00:00
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
2021-05-19 14:11:18 +00:00
|
|
|
|
|
|
|
func TestComponentProviderSchemaGo(t *testing.T) {
|
2023-12-02 17:16:09 +00:00
|
|
|
t.Parallel()
|
2023-03-06 14:14:49 +00:00
|
|
|
// TODO[https://github.com/pulumi/pulumi/issues/12365] We no longer build the go-component in
|
|
|
|
// component_setup.sh so there's no native binary for the testComponentProviderSchema to just exec. It
|
|
|
|
// _ought_ to be rewritten to use the plugin host framework so that it starts the component up the same as
|
|
|
|
// all the other tests are doing (via shimless).
|
2022-10-04 08:58:01 +00:00
|
|
|
t.Skip("testComponentProviderSchema needs to be updated to use a plugin host to deal with non-native-binary providers")
|
|
|
|
|
2021-05-19 14:11:18 +00:00
|
|
|
path := filepath.Join("component_provider_schema", "testcomponent-go", "pulumi-resource-testcomponent")
|
|
|
|
if runtime.GOOS == WindowsOS {
|
|
|
|
path += ".exe"
|
|
|
|
}
|
|
|
|
testComponentProviderSchema(t, path)
|
|
|
|
}
|
2021-06-11 02:57:18 +00:00
|
|
|
|
|
|
|
// TestTracePropagationGo checks that --tracing flag lets golang sub-process to emit traces.
|
|
|
|
func TestTracePropagationGo(t *testing.T) {
|
2023-12-02 17:16:09 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2022-12-03 07:17:08 +00:00
|
|
|
dir := t.TempDir()
|
2021-06-11 02:57:18 +00:00
|
|
|
|
|
|
|
opts := &integration.ProgramTestOptions{
|
|
|
|
Dir: filepath.Join("empty", "go"),
|
|
|
|
Dependencies: []string{"github.com/pulumi/pulumi/sdk/v3"},
|
|
|
|
SkipRefresh: true,
|
2022-09-16 21:11:08 +00:00
|
|
|
SkipPreview: true,
|
|
|
|
SkipUpdate: false,
|
2021-06-11 02:57:18 +00:00
|
|
|
SkipExportImport: true,
|
|
|
|
SkipEmptyPreviewUpdate: true,
|
|
|
|
Quick: false,
|
2024-04-19 06:20:33 +00:00
|
|
|
Tracing: "file:" + filepath.Join(dir, "{command}.trace"),
|
2022-09-16 21:11:08 +00:00
|
|
|
RequireService: true,
|
2023-12-02 17:16:09 +00:00
|
|
|
NoParallel: true,
|
2021-06-11 02:57:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
integration.ProgramTest(t, opts)
|
|
|
|
|
2022-09-16 21:11:08 +00:00
|
|
|
store, err := ReadMemoryStoreFromFile(filepath.Join(dir, "pulumi-update-initial.trace"))
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.NotNil(t, store)
|
|
|
|
|
feat(go/host): Support vendored dependencies
The Go language host cannot resolve dependencies or plugins if a Pulumi
program vendors its dependencies.
BACKGROUND
The GetRequiredPlugins and GetProgramDependencies methods of the Go
language host rely on the following two commands:
go list -m -mod=mod all
go list -m -mod=mod ...
# '...' means current module and its descendants
GetRequiredPlugins additionally searches the source directories for each
returned module for pulumi-plugin.json files at a pre-determined paths.
$module/pulumi-plugin.json
$module/go/pulumi-plugin.json
$module/go/*/pulumi-plugin.json
This works for most Pulumi programs, except those that vendor private
dependencies with 'go mod vendor'.
For those programs, the above commands fail because -mod=mod forces them
to run in module mode, and their private dependencies are not accessible
in module mode (because they are not exposed publicly).
We use the -mod=mod flag to force 'go list' to run in module mode
because otherwise, it will automatically use vendor mode if a vendor
directory is present. However, in vendor mode, the two 'go list'
commands above are not supported.
The following links add more context on why, but in short:
vendor does not have enough information for the general 'go list'.
- https://stackoverflow.com/a/60660593,
- https://github.com/golang/go/issues/35589#issuecomment-554488544
In short,
- list all with -mod=mod fails because the dependency is private
- list without -mod=mod will use vendor mode
- vendor mode doesn't support the listing all
SOLUTION
Drop the -mod=mod flag so that 'go list' can decide whether to run in
module mode or vendor mode.
However, instead of running it with 'all' or '...',
pass in a list of dependencies extracted from the go.mod.
go list -m import/path1 import/path2 # ...
This operation is completely offline in vendor mode
so it can list information about private dependencies too.
This alone isn't enough though because in vendor mode,
the JSON output does not include the module root directory.
E.g.
% go list -mod=vendor -json -m github.com/pulumi/pulumi/sdk/v3
{
"Path": "github.com/pulumi/pulumi/sdk/v3",
"Version": "v3.55.0",
"GoVersion": "1.18"
}
# Versus
% go list -mod=mod -json -m github.com/pulumi/pulumi/sdk/v3
{
"Path": "github.com/pulumi/pulumi/sdk/v3",
"Version": "v3.55.0",
"Time": "2023-02-14T11:04:22Z",
"Dir": "[...]/go/pkg/mod/github.com/pulumi/pulumi/sdk/v3@v3.55.0",
"GoMod": "[...]/go/pkg/mod/cache/download/github.com/pulumi/pulumi/sdk/v3/@v/v3.55.0.mod",
"GoVersion": "1.18"
}
Therefore, we have to manually calculate the path for each module root.
That's easy enough: vendor/$importPath.
Lastly, since GetProgramDependencies only needs a dependency list,
it now extracts information from the go.mod without calling 'go list'.
TESTING
Adds a variant of the test added in #12715 that verifies the
functionality with vendoring. It removes the sources for the
dependencies to simulate private dependencies. The new test fails
without the accompanying change.
The fix was further manually verified against the reproduction included
in #12526.
% cd go-output
% pulumi plugin rm -a -y
% pulumi preview
Previewing update (abhinav):
Downloading plugin: 15.19 MiB / 15.19 MiB [=========================] 100.00% 0s
[resource plugin random-4.8.2] installing
Type Name Plan
+ pulumi:pulumi:Stack go-output-abhinav create
+ └─ random:index:RandomId rrr create
Resources:
+ 2 to create
% pulumi plugin ls
NAME KIND VERSION SIZE INSTALLED LAST USED
random resource 4.8.2 33 MB 26 seconds ago 26 seconds ago
TOTAL plugin cache size: 33 MB
Note that the version of random (4.8.2) is what's specified in the
go.mod, not the latest release (v4.12.1).
% grep pulumi-random go.mod
github.com/pulumi/pulumi-random/sdk/v4 v4.8.2
With the plugin downloaded, I ran this again without an internet
connection.
% pulumi preview
Previewing update (abhinav):
Type Name Plan
+ pulumi:pulumi:Stack go-output-abhinav create
+ └─ random:index:RandomId rrr create
Resources:
+ 2 to create
This means that if the dependencies are vendored, and the plugin is
already available, we won't make additional network requests, which also
addresses #7089.
Resolves #12526
Resolves #7089
2023-04-20 23:27:39 +00:00
|
|
|
t.Run("traced `go list -m -json`", func(t *testing.T) {
|
2023-12-02 17:16:09 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2022-09-16 21:11:08 +00:00
|
|
|
isGoListTrace := func(t *appdash.Trace) bool {
|
|
|
|
m := t.Span.Annotations.StringMap()
|
|
|
|
|
|
|
|
isGoCmd := strings.HasSuffix(m["command"], "go") ||
|
|
|
|
strings.HasSuffix(m["command"], "go.exe")
|
|
|
|
|
feat(go/host): Support vendored dependencies
The Go language host cannot resolve dependencies or plugins if a Pulumi
program vendors its dependencies.
BACKGROUND
The GetRequiredPlugins and GetProgramDependencies methods of the Go
language host rely on the following two commands:
go list -m -mod=mod all
go list -m -mod=mod ...
# '...' means current module and its descendants
GetRequiredPlugins additionally searches the source directories for each
returned module for pulumi-plugin.json files at a pre-determined paths.
$module/pulumi-plugin.json
$module/go/pulumi-plugin.json
$module/go/*/pulumi-plugin.json
This works for most Pulumi programs, except those that vendor private
dependencies with 'go mod vendor'.
For those programs, the above commands fail because -mod=mod forces them
to run in module mode, and their private dependencies are not accessible
in module mode (because they are not exposed publicly).
We use the -mod=mod flag to force 'go list' to run in module mode
because otherwise, it will automatically use vendor mode if a vendor
directory is present. However, in vendor mode, the two 'go list'
commands above are not supported.
The following links add more context on why, but in short:
vendor does not have enough information for the general 'go list'.
- https://stackoverflow.com/a/60660593,
- https://github.com/golang/go/issues/35589#issuecomment-554488544
In short,
- list all with -mod=mod fails because the dependency is private
- list without -mod=mod will use vendor mode
- vendor mode doesn't support the listing all
SOLUTION
Drop the -mod=mod flag so that 'go list' can decide whether to run in
module mode or vendor mode.
However, instead of running it with 'all' or '...',
pass in a list of dependencies extracted from the go.mod.
go list -m import/path1 import/path2 # ...
This operation is completely offline in vendor mode
so it can list information about private dependencies too.
This alone isn't enough though because in vendor mode,
the JSON output does not include the module root directory.
E.g.
% go list -mod=vendor -json -m github.com/pulumi/pulumi/sdk/v3
{
"Path": "github.com/pulumi/pulumi/sdk/v3",
"Version": "v3.55.0",
"GoVersion": "1.18"
}
# Versus
% go list -mod=mod -json -m github.com/pulumi/pulumi/sdk/v3
{
"Path": "github.com/pulumi/pulumi/sdk/v3",
"Version": "v3.55.0",
"Time": "2023-02-14T11:04:22Z",
"Dir": "[...]/go/pkg/mod/github.com/pulumi/pulumi/sdk/v3@v3.55.0",
"GoMod": "[...]/go/pkg/mod/cache/download/github.com/pulumi/pulumi/sdk/v3/@v/v3.55.0.mod",
"GoVersion": "1.18"
}
Therefore, we have to manually calculate the path for each module root.
That's easy enough: vendor/$importPath.
Lastly, since GetProgramDependencies only needs a dependency list,
it now extracts information from the go.mod without calling 'go list'.
TESTING
Adds a variant of the test added in #12715 that verifies the
functionality with vendoring. It removes the sources for the
dependencies to simulate private dependencies. The new test fails
without the accompanying change.
The fix was further manually verified against the reproduction included
in #12526.
% cd go-output
% pulumi plugin rm -a -y
% pulumi preview
Previewing update (abhinav):
Downloading plugin: 15.19 MiB / 15.19 MiB [=========================] 100.00% 0s
[resource plugin random-4.8.2] installing
Type Name Plan
+ pulumi:pulumi:Stack go-output-abhinav create
+ └─ random:index:RandomId rrr create
Resources:
+ 2 to create
% pulumi plugin ls
NAME KIND VERSION SIZE INSTALLED LAST USED
random resource 4.8.2 33 MB 26 seconds ago 26 seconds ago
TOTAL plugin cache size: 33 MB
Note that the version of random (4.8.2) is what's specified in the
go.mod, not the latest release (v4.12.1).
% grep pulumi-random go.mod
github.com/pulumi/pulumi-random/sdk/v4 v4.8.2
With the plugin downloaded, I ran this again without an internet
connection.
% pulumi preview
Previewing update (abhinav):
Type Name Plan
+ pulumi:pulumi:Stack go-output-abhinav create
+ └─ random:index:RandomId rrr create
Resources:
+ 2 to create
This means that if the dependencies are vendored, and the plugin is
already available, we won't make additional network requests, which also
addresses #7089.
Resolves #12526
Resolves #7089
2023-04-20 23:27:39 +00:00
|
|
|
return isGoCmd &&
|
|
|
|
m["component"] == "exec.Command" &&
|
|
|
|
strings.Contains(m["args"], "list -m -json")
|
2022-09-16 21:11:08 +00:00
|
|
|
}
|
|
|
|
tr, err := FindTrace(store, isGoListTrace)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.NotNil(t, tr)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("traced api/exportStack exactly once", func(t *testing.T) {
|
2023-12-02 17:16:09 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2022-09-16 21:11:08 +00:00
|
|
|
exportStackCounter := 0
|
|
|
|
err := WalkTracesWithDescendants(store, func(tr *appdash.Trace) error {
|
|
|
|
name := tr.Span.Name()
|
|
|
|
if name == "api/exportStack" {
|
|
|
|
exportStackCounter++
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, 1, exportStackCounter)
|
|
|
|
})
|
2021-06-11 02:57:18 +00:00
|
|
|
}
|
2021-08-27 17:39:49 +00:00
|
|
|
|
|
|
|
// Test that the about command works as expected. Because about parses the
|
|
|
|
// results of each runtime independently, we have an integration test in each
|
|
|
|
// language.
|
|
|
|
func TestAboutGo(t *testing.T) {
|
2022-03-04 08:17:41 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2021-08-27 17:39:49 +00:00
|
|
|
dir := filepath.Join("about", "go")
|
|
|
|
|
|
|
|
e := ptesting.NewEnvironment(t)
|
2024-07-23 10:37:01 +00:00
|
|
|
defer e.DeleteIfNotFailed()
|
2021-08-27 17:39:49 +00:00
|
|
|
e.ImportDirectory(dir)
|
|
|
|
|
|
|
|
e.RunCommand("pulumi", "login", "--cloud-url", e.LocalURL())
|
2021-08-28 04:31:46 +00:00
|
|
|
e.RunCommand("pulumi", "stack", "init", "about-stack")
|
2021-08-27 23:04:42 +00:00
|
|
|
e.RunCommand("pulumi", "stack", "select", "about-stack")
|
2021-08-28 15:53:17 +00:00
|
|
|
stdout, _ := e.RunCommand("pulumi", "about", "-t")
|
2021-08-28 04:31:46 +00:00
|
|
|
|
2021-08-27 17:39:49 +00:00
|
|
|
// Assert we parsed the dependencies
|
2022-09-14 03:02:19 +00:00
|
|
|
assert.Contains(t, stdout, "github.com/pulumi/pulumi/sdk/v3")
|
2021-08-27 17:39:49 +00:00
|
|
|
}
|
2021-11-15 23:42:04 +00:00
|
|
|
|
|
|
|
func TestConstructOutputValuesGo(t *testing.T) {
|
2023-12-02 17:16:09 +00:00
|
|
|
t.Parallel()
|
2021-11-15 23:42:04 +00:00
|
|
|
testConstructOutputValues(t, "go", "github.com/pulumi/pulumi/sdk/v3")
|
|
|
|
}
|
2022-09-22 13:46:48 +00:00
|
|
|
|
|
|
|
// TestProjectMainGo tests out the ability to override the main entrypoint.
|
2023-12-02 17:16:09 +00:00
|
|
|
//
|
|
|
|
//nolint:paralleltest // ProgramTest calls t.Parallel()
|
2022-09-22 13:46:48 +00:00
|
|
|
func TestProjectMainGo(t *testing.T) {
|
|
|
|
test := integration.ProgramTestOptions{
|
|
|
|
Dir: "project_main/go",
|
|
|
|
Dependencies: []string{"github.com/pulumi/pulumi/sdk/v3"},
|
|
|
|
ExtraRuntimeValidation: func(t *testing.T, stackInfo integration.RuntimeValidationStackInfo) {
|
|
|
|
// Simple runtime validation that just ensures the checkpoint was written and read.
|
|
|
|
assert.NotNil(t, stackInfo.Deployment)
|
|
|
|
},
|
|
|
|
}
|
|
|
|
integration.ProgramTest(t, &test)
|
|
|
|
}
|
2022-11-03 20:30:35 +00:00
|
|
|
|
|
|
|
// TestRefreshGo simply tests that we can build and run an empty Go project with the `refresh` option set.
|
2023-12-02 17:16:09 +00:00
|
|
|
//
|
|
|
|
//nolint:paralleltest // ProgramTest calls t.Parallel()
|
2022-11-03 20:30:35 +00:00
|
|
|
func TestRefreshGo(t *testing.T) {
|
|
|
|
integration.ProgramTest(t, &integration.ProgramTestOptions{
|
|
|
|
Dir: filepath.Join("refresh", "go"),
|
|
|
|
Dependencies: []string{
|
|
|
|
"github.com/pulumi/pulumi/sdk/v3",
|
|
|
|
},
|
|
|
|
Quick: true,
|
|
|
|
})
|
|
|
|
}
|
2022-11-30 19:25:07 +00:00
|
|
|
|
|
|
|
// TestResourceRefsGetResourceGo tests that invoking the built-in 'pulumi:pulumi:getResource' function
|
|
|
|
// returns resource references for any resource reference in a resource's state.
|
2023-12-02 17:16:09 +00:00
|
|
|
//
|
|
|
|
//nolint:paralleltest // ProgramTest calls t.Parallel()
|
2022-11-30 19:25:07 +00:00
|
|
|
func TestResourceRefsGetResourceGo(t *testing.T) {
|
|
|
|
integration.ProgramTest(t, &integration.ProgramTestOptions{
|
|
|
|
Dir: filepath.Join("resource_refs_get_resource", "go"),
|
|
|
|
Dependencies: []string{
|
|
|
|
"github.com/pulumi/pulumi/sdk/v3",
|
|
|
|
},
|
|
|
|
Quick: true,
|
|
|
|
})
|
|
|
|
}
|
[sdk/{go,nodejs,python}] Fix DeletedWith resource option
This change fixes the `DeletedWith` resource option in the Go, Node.js,
and Python SDKs and adds tests.
This feature was a community contribution and while there were engine
tests included with the original PR, there weren't any tests confirming
the functionality worked correctly from each SDK.
Here's a summary of the fixes:
* Go: The `DeletedWith` resource option was never usable as it accepted
a URN instead of a Resource. We discussed this internally a while back
and decided to go ahead and fix this. (Note: While changing the
signature is technically a breaking change, the feature is currently
unusable, so the change would not break anyone, so there's no need to
wait for a major version bump.)
* Node.js: The `deletedWith` resource option did not work at all from
the Node.js SDK because it was incorrectly passing the resource object
itself in the RegisterResource request, rather than the resource's
URN.
* Python: The `deleted_with` resource option did not work at all from
the Python SDK because it was incorrectly passing the resource object
itself in the RegisterResource request, rather than the resource's
URN.
A `FailsOnDelete` resource has been added to the testprovider, which
will fail when its `Delete` gRPC is called. The tests use this to ensure
`Delete` is not called for resources of this type with the `DeletedWith`
option specified.
2023-01-16 00:19:26 +00:00
|
|
|
|
|
|
|
// TestDeletedWithGo tests the DeletedWith resource option.
|
2023-12-02 17:16:09 +00:00
|
|
|
//
|
|
|
|
//nolint:paralleltest // ProgramTest calls t.Parallel()
|
[sdk/{go,nodejs,python}] Fix DeletedWith resource option
This change fixes the `DeletedWith` resource option in the Go, Node.js,
and Python SDKs and adds tests.
This feature was a community contribution and while there were engine
tests included with the original PR, there weren't any tests confirming
the functionality worked correctly from each SDK.
Here's a summary of the fixes:
* Go: The `DeletedWith` resource option was never usable as it accepted
a URN instead of a Resource. We discussed this internally a while back
and decided to go ahead and fix this. (Note: While changing the
signature is technically a breaking change, the feature is currently
unusable, so the change would not break anyone, so there's no need to
wait for a major version bump.)
* Node.js: The `deletedWith` resource option did not work at all from
the Node.js SDK because it was incorrectly passing the resource object
itself in the RegisterResource request, rather than the resource's
URN.
* Python: The `deleted_with` resource option did not work at all from
the Python SDK because it was incorrectly passing the resource object
itself in the RegisterResource request, rather than the resource's
URN.
A `FailsOnDelete` resource has been added to the testprovider, which
will fail when its `Delete` gRPC is called. The tests use this to ensure
`Delete` is not called for resources of this type with the `DeletedWith`
option specified.
2023-01-16 00:19:26 +00:00
|
|
|
func TestDeletedWithGo(t *testing.T) {
|
|
|
|
integration.ProgramTest(t, &integration.ProgramTestOptions{
|
|
|
|
Dir: filepath.Join("deleted_with", "go"),
|
|
|
|
Dependencies: []string{
|
|
|
|
"github.com/pulumi/pulumi/sdk/v3",
|
|
|
|
},
|
|
|
|
LocalProviders: []integration.LocalDependency{
|
2022-11-23 09:53:41 +00:00
|
|
|
{Package: "testprovider", Path: filepath.Join("..", "testprovider")},
|
[sdk/{go,nodejs,python}] Fix DeletedWith resource option
This change fixes the `DeletedWith` resource option in the Go, Node.js,
and Python SDKs and adds tests.
This feature was a community contribution and while there were engine
tests included with the original PR, there weren't any tests confirming
the functionality worked correctly from each SDK.
Here's a summary of the fixes:
* Go: The `DeletedWith` resource option was never usable as it accepted
a URN instead of a Resource. We discussed this internally a while back
and decided to go ahead and fix this. (Note: While changing the
signature is technically a breaking change, the feature is currently
unusable, so the change would not break anyone, so there's no need to
wait for a major version bump.)
* Node.js: The `deletedWith` resource option did not work at all from
the Node.js SDK because it was incorrectly passing the resource object
itself in the RegisterResource request, rather than the resource's
URN.
* Python: The `deleted_with` resource option did not work at all from
the Python SDK because it was incorrectly passing the resource object
itself in the RegisterResource request, rather than the resource's
URN.
A `FailsOnDelete` resource has been added to the testprovider, which
will fail when its `Delete` gRPC is called. The tests use this to ensure
`Delete` is not called for resources of this type with the `DeletedWith`
option specified.
2023-01-16 00:19:26 +00:00
|
|
|
},
|
|
|
|
Quick: true,
|
|
|
|
})
|
|
|
|
}
|
2023-04-05 18:43:12 +00:00
|
|
|
|
|
|
|
func TestConstructProviderPropagationGo(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
testConstructProviderPropagation(t, "go", []string{"github.com/pulumi/pulumi/sdk/v3"})
|
|
|
|
}
|
2023-04-18 19:24:22 +00:00
|
|
|
|
|
|
|
func TestConstructResourceOptionsGo(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
testConstructResourceOptions(t, "go", []string{"github.com/pulumi/pulumi/sdk/v3"})
|
|
|
|
}
|
2023-07-11 15:39:45 +00:00
|
|
|
|
|
|
|
// Regression test for https://github.com/pulumi/pulumi/issues/13301.
|
|
|
|
// The reproduction is a bit involved:
|
|
|
|
//
|
|
|
|
// - Set up a fake Pulumi Go project that imports a specific non-Pulumi plugin.
|
|
|
|
// Specifically, the plugin MUST NOT be imported by any Go file in the project.
|
|
|
|
// - Install that plugin with 'pulumi plugin install'.
|
|
|
|
// - Run a Go Automation program that uses that plugin.
|
|
|
|
//
|
|
|
|
// The issue in #13301 was that this plugin would not be downloaded by `pulumi plugin install`,
|
|
|
|
// causing a failure when the Automation program tried to use it.
|
|
|
|
func TestAutomation_externalPluginDownload_issue13301(t *testing.T) {
|
2023-12-02 17:16:09 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2023-07-11 15:39:45 +00:00
|
|
|
// Context scoped to the lifetime of the test.
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
t.Cleanup(cancel)
|
|
|
|
|
|
|
|
e := ptesting.NewEnvironment(t)
|
2024-07-23 10:37:01 +00:00
|
|
|
defer e.DeleteIfNotFailed()
|
2023-07-11 15:39:45 +00:00
|
|
|
e.ImportDirectory(filepath.Join("go", "regress-13301"))
|
2023-07-26 19:02:03 +00:00
|
|
|
|
|
|
|
// Rename go.mod.bad to go.mod so that the Go toolchain uses it.
|
|
|
|
require.NoError(t, os.Rename(
|
|
|
|
filepath.Join(e.CWD, "go.mod.bad"),
|
|
|
|
filepath.Join(e.CWD, "go.mod"),
|
|
|
|
))
|
|
|
|
|
2023-07-11 15:39:45 +00:00
|
|
|
e.RunCommand("pulumi", "login", "--cloud-url", e.LocalURL())
|
|
|
|
|
|
|
|
// Plugins are installed globally in PULUMI_HOME.
|
|
|
|
// We will set that to a temporary directory,
|
|
|
|
// so this is not polluted by other tests.
|
|
|
|
pulumiHome := filepath.Join(e.RootPath, ".pulumi-home")
|
|
|
|
require.NoError(t, os.MkdirAll(pulumiHome, 0o700))
|
|
|
|
|
|
|
|
// The commands that follow will make gRPC requests that
|
|
|
|
// we don't have a lot of visibility into.
|
|
|
|
// If we run the Pulumi CLI with PULUMI_DEBUG_GRPC set to a path,
|
|
|
|
// it will log the gRPC requests and responses to that file.
|
|
|
|
//
|
|
|
|
// Capture these and print them if the test fails.
|
|
|
|
grpcLog := filepath.Join(e.RootPath, "debug-grpc.log")
|
|
|
|
defer func() {
|
|
|
|
if !t.Failed() {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if bs, err := os.ReadFile(grpcLog); err == nil {
|
|
|
|
t.Logf("grpc debug log:\n%s", bs)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
e.Env = append(e.Env,
|
|
|
|
"PULUMI_HOME="+pulumiHome,
|
|
|
|
"PULUMI_DEBUG_GRPC="+grpcLog)
|
|
|
|
e.RunCommand("pulumi", "plugin", "install")
|
|
|
|
|
|
|
|
ws, err := auto.NewLocalWorkspace(ctx,
|
|
|
|
auto.Project(workspace.Project{
|
|
|
|
Name: "issue-13301",
|
|
|
|
Runtime: workspace.NewProjectRuntimeInfo("go", nil),
|
|
|
|
}),
|
|
|
|
auto.WorkDir(e.CWD),
|
|
|
|
auto.PulumiHome(pulumiHome),
|
|
|
|
auto.EnvVars(map[string]string{
|
|
|
|
"PULUMI_CONFIG_PASSPHRASE": "not-a-real-passphrase",
|
|
|
|
"PULUMI_DEBUG_COMMANDS": "true",
|
|
|
|
"PULUMI_CREDENTIALS_PATH": e.RootPath,
|
|
|
|
"PULUMI_DEBUG_GRPC": grpcLog,
|
|
|
|
}),
|
|
|
|
)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
ws.SetProgram(func(ctx *pulumi.Context) error {
|
|
|
|
provider, err := hcp.NewProvider(ctx, "hcp", &hcp.ProviderArgs{})
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
_ = provider // unused
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
|
|
|
|
stack, err := auto.UpsertStack(ctx, "foo", ws)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
_, err = stack.Preview(ctx)
|
|
|
|
require.NoError(t, err)
|
|
|
|
}
|
2023-06-26 06:20:14 +00:00
|
|
|
|
|
|
|
func TestConstructProviderExplicitGo(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
testConstructProviderExplicit(t, "go", []string{"github.com/pulumi/pulumi/sdk/v3"})
|
|
|
|
}
|
2024-03-25 22:37:46 +00:00
|
|
|
|
|
|
|
// TestStackOutputsProgramErrorGo tests that when a program error occurs, we update any
|
|
|
|
// updated stack outputs, but otherwise leave others untouched.
|
|
|
|
//
|
|
|
|
//nolint:paralleltest // ProgramTest calls t.Parallel()
|
|
|
|
func TestStackOutputsProgramErrorGo(t *testing.T) {
|
|
|
|
d := filepath.Join("stack_outputs_program_error", "go")
|
|
|
|
|
|
|
|
validateOutputs := func(
|
|
|
|
expected map[string]interface{},
|
|
|
|
) func(t *testing.T, stackInfo integration.RuntimeValidationStackInfo) {
|
|
|
|
return func(t *testing.T, stackInfo integration.RuntimeValidationStackInfo) {
|
|
|
|
assert.Equal(t, expected, stackInfo.RootResource.Outputs)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
integration.ProgramTest(t, &integration.ProgramTestOptions{
|
|
|
|
Dir: filepath.Join(d, "step1"),
|
|
|
|
Dependencies: []string{
|
|
|
|
"github.com/pulumi/pulumi/sdk/v3",
|
|
|
|
},
|
|
|
|
Quick: true,
|
|
|
|
ExtraRuntimeValidation: validateOutputs(map[string]interface{}{
|
|
|
|
"xyz": "ABC",
|
|
|
|
"foo": float64(42),
|
|
|
|
}),
|
|
|
|
EditDirs: []integration.EditDir{
|
|
|
|
{
|
|
|
|
Dir: filepath.Join(d, "step2"),
|
|
|
|
Additive: true,
|
|
|
|
ExpectFailure: true,
|
|
|
|
ExtraRuntimeValidation: validateOutputs(map[string]interface{}{
|
|
|
|
"xyz": "DEF", // Expected to be updated
|
|
|
|
"foo": float64(42), // Expected to remain the same
|
|
|
|
}),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// TestStackOutputsResourceErrorGo tests that when a resource error occurs, we update any
|
|
|
|
// updated stack outputs, but otherwise leave others untouched.
|
|
|
|
//
|
|
|
|
//nolint:paralleltest // ProgramTest calls t.Parallel()
|
|
|
|
func TestStackOutputsResourceErrorGo(t *testing.T) {
|
|
|
|
d := filepath.Join("stack_outputs_resource_error", "go")
|
|
|
|
|
|
|
|
validateOutputs := func(
|
|
|
|
expected map[string]interface{},
|
|
|
|
) func(t *testing.T, stackInfo integration.RuntimeValidationStackInfo) {
|
|
|
|
return func(t *testing.T, stackInfo integration.RuntimeValidationStackInfo) {
|
|
|
|
assert.Equal(t, expected, stackInfo.RootResource.Outputs)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
integration.ProgramTest(t, &integration.ProgramTestOptions{
|
|
|
|
Dir: filepath.Join(d, "step1"),
|
|
|
|
Dependencies: []string{
|
|
|
|
"github.com/pulumi/pulumi/sdk/v3",
|
|
|
|
},
|
|
|
|
LocalProviders: []integration.LocalDependency{
|
|
|
|
{Package: "testprovider", Path: filepath.Join("..", "testprovider")},
|
|
|
|
},
|
|
|
|
Quick: true,
|
|
|
|
ExtraRuntimeValidation: validateOutputs(map[string]interface{}{
|
|
|
|
"xyz": "ABC",
|
|
|
|
"foo": float64(42),
|
|
|
|
}),
|
|
|
|
EditDirs: []integration.EditDir{
|
|
|
|
{
|
|
|
|
Dir: filepath.Join(d, "step2"),
|
|
|
|
Additive: true,
|
|
|
|
ExpectFailure: true,
|
|
|
|
// Expect the values to remain the same because the deployment ends before RegisterResourceOutputs is
|
|
|
|
// called for the stack.
|
|
|
|
ExtraRuntimeValidation: validateOutputs(map[string]interface{}{
|
|
|
|
"xyz": "ABC",
|
|
|
|
"foo": float64(42),
|
|
|
|
}),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Dir: filepath.Join(d, "step3"),
|
|
|
|
Additive: true,
|
|
|
|
ExpectFailure: true,
|
|
|
|
// Expect the values to be updated.
|
|
|
|
ExtraRuntimeValidation: validateOutputs(map[string]interface{}{
|
|
|
|
"xyz": "DEF",
|
|
|
|
"foo": float64(1),
|
|
|
|
}),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|