2018-05-22 19:43:36 +00:00
|
|
|
// Copyright 2016-2018, Pulumi Corporation.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
2017-08-05 18:37:14 +00:00
|
|
|
|
|
|
|
package integration
|
2017-07-13 19:19:17 +00:00
|
|
|
|
|
|
|
import (
|
2018-02-04 00:17:51 +00:00
|
|
|
"context"
|
2018-06-04 23:34:38 +00:00
|
|
|
cryptorand "crypto/rand"
|
2018-04-12 20:50:07 +00:00
|
|
|
"encoding/hex"
|
2018-04-03 04:34:54 +00:00
|
|
|
"encoding/json"
|
2017-07-13 19:19:17 +00:00
|
|
|
"fmt"
|
|
|
|
"io"
|
2017-08-06 00:49:48 +00:00
|
|
|
"io/ioutil"
|
2017-07-13 19:19:17 +00:00
|
|
|
"os"
|
2018-02-04 00:17:51 +00:00
|
|
|
"os/exec"
|
2018-06-11 20:08:46 +00:00
|
|
|
"os/user"
|
2017-11-15 05:02:47 +00:00
|
|
|
"path"
|
2017-08-06 00:49:48 +00:00
|
|
|
"path/filepath"
|
2017-12-01 01:23:58 +00:00
|
|
|
"strconv"
|
2017-07-13 19:19:17 +00:00
|
|
|
"strings"
|
|
|
|
"testing"
|
2018-02-04 00:17:51 +00:00
|
|
|
"time"
|
2017-07-13 19:19:17 +00:00
|
|
|
|
2018-05-15 16:48:56 +00:00
|
|
|
"github.com/hashicorp/go-multierror"
|
2017-10-28 03:03:38 +00:00
|
|
|
"github.com/pkg/errors"
|
2017-07-13 19:19:17 +00:00
|
|
|
"github.com/stretchr/testify/assert"
|
2017-08-06 00:49:48 +00:00
|
|
|
|
2018-02-28 18:02:02 +00:00
|
|
|
"github.com/pulumi/pulumi/pkg/apitype"
|
2018-02-21 05:05:57 +00:00
|
|
|
"github.com/pulumi/pulumi/pkg/backend/local"
|
2017-11-16 15:49:07 +00:00
|
|
|
"github.com/pulumi/pulumi/pkg/engine"
|
2017-12-14 00:09:14 +00:00
|
|
|
"github.com/pulumi/pulumi/pkg/resource"
|
2017-10-28 03:03:38 +00:00
|
|
|
"github.com/pulumi/pulumi/pkg/tokens"
|
2017-09-22 02:18:21 +00:00
|
|
|
"github.com/pulumi/pulumi/pkg/util/contract"
|
2017-11-30 16:14:47 +00:00
|
|
|
"github.com/pulumi/pulumi/pkg/util/fsutil"
|
2018-02-04 00:17:51 +00:00
|
|
|
"github.com/pulumi/pulumi/pkg/util/retry"
|
2018-06-11 23:01:04 +00:00
|
|
|
"github.com/pulumi/pulumi/pkg/util/testutil"
|
2017-10-23 12:27:26 +00:00
|
|
|
"github.com/pulumi/pulumi/pkg/workspace"
|
2017-07-13 19:19:17 +00:00
|
|
|
)
|
|
|
|
|
2017-12-14 00:09:14 +00:00
|
|
|
// RuntimeValidationStackInfo contains details related to the stack that runtime validation logic may want to use.
|
|
|
|
type RuntimeValidationStackInfo struct {
|
2018-04-12 20:50:07 +00:00
|
|
|
StackName tokens.QName
|
2018-07-20 20:31:41 +00:00
|
|
|
Deployment *apitype.DeploymentV2
|
|
|
|
RootResource apitype.ResourceV2
|
2017-12-14 00:09:14 +00:00
|
|
|
Outputs map[string]interface{}
|
|
|
|
}
|
|
|
|
|
2017-10-26 23:01:28 +00:00
|
|
|
// EditDir is an optional edit to apply to the example, as subsequent deployments.
|
|
|
|
type EditDir struct {
|
|
|
|
Dir string
|
2017-12-14 00:09:14 +00:00
|
|
|
ExtraRuntimeValidation func(t *testing.T, stack RuntimeValidationStackInfo)
|
2017-12-15 01:10:05 +00:00
|
|
|
|
2018-01-10 00:47:17 +00:00
|
|
|
// Additive is true if Dir should be copied *on top* of the test directory.
|
2018-03-06 23:57:57 +00:00
|
|
|
// Otherwise Dir *replaces* the test directory, except we keep .pulumi/ and Pulumi.yaml and Pulumi.<stack>.yaml.
|
2018-01-10 00:47:17 +00:00
|
|
|
Additive bool
|
|
|
|
|
2017-12-20 20:10:46 +00:00
|
|
|
// ExpectFailure is true if we expect this test to fail. This is very coarse grained, and will essentially
|
|
|
|
// tolerate *any* failure in the program (IDEA: in the future, offer a way to narrow this down more).
|
|
|
|
ExpectFailure bool
|
|
|
|
|
2017-12-15 01:10:05 +00:00
|
|
|
// Stdout is the writer to use for all stdout messages.
|
|
|
|
Stdout io.Writer
|
|
|
|
// Stderr is the writer to use for all stderr messages.
|
|
|
|
Stderr io.Writer
|
|
|
|
// Verbose may be set to true to print messages as they occur, rather than buffering and showing upon failure.
|
|
|
|
Verbose bool
|
2017-10-26 23:01:28 +00:00
|
|
|
}
|
|
|
|
|
2017-11-14 17:33:22 +00:00
|
|
|
// TestCommandStats is a collection of data related to running a single command during a test.
|
|
|
|
type TestCommandStats struct {
|
|
|
|
// StartTime is the time at which the command was started
|
|
|
|
StartTime string `json:"startTime"`
|
|
|
|
// EndTime is the time at which the command exited
|
|
|
|
EndTime string `json:"endTime"`
|
|
|
|
// ElapsedSeconds is the time at which the command exited
|
|
|
|
ElapsedSeconds float64 `json:"elapsedSeconds"`
|
|
|
|
// StackName is the name of the stack
|
|
|
|
StackName string `json:"stackName"`
|
|
|
|
// TestId is the unique ID of the test run
|
|
|
|
TestID string `json:"testId"`
|
|
|
|
// StepName is the command line which was invoked1
|
|
|
|
StepName string `json:"stepName"`
|
|
|
|
// CommandLine is the command line which was invoked1
|
|
|
|
CommandLine string `json:"commandLine"`
|
|
|
|
// TestName is the name of the directory in which the test was executed
|
|
|
|
TestName string `json:"testName"`
|
|
|
|
// IsError is true if the command failed
|
|
|
|
IsError bool `json:"isError"`
|
2018-01-30 21:10:32 +00:00
|
|
|
// The Cloud that the test was run against, or empty for local deployments
|
|
|
|
CloudURL string `json:"cloudURL"`
|
|
|
|
// The PPC that the test was run against, or empty for local deployments or for the default PPC
|
|
|
|
CloudPPC string `json:"cloudPPC"`
|
2017-11-14 17:33:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// TestStatsReporter reports results and metadata from a test run.
|
|
|
|
type TestStatsReporter interface {
|
|
|
|
ReportCommand(stats TestCommandStats)
|
|
|
|
}
|
|
|
|
|
2017-12-08 20:59:39 +00:00
|
|
|
// ProgramTestOptions provides options for ProgramTest
|
2017-10-23 01:54:29 +00:00
|
|
|
type ProgramTestOptions struct {
|
2017-08-06 00:49:48 +00:00
|
|
|
// Dir is the program directory to test.
|
|
|
|
Dir string
|
2017-09-22 02:18:21 +00:00
|
|
|
// Array of NPM packages which must be `yarn linked` (e.g. {"pulumi", "@pulumi/aws"})
|
2017-07-13 19:19:17 +00:00
|
|
|
Dependencies []string
|
2017-10-23 01:54:29 +00:00
|
|
|
// Map of config keys and values to set (e.g. {"aws:config:region": "us-east-2"})
|
2017-07-13 19:19:17 +00:00
|
|
|
Config map[string]string
|
2018-03-04 21:34:20 +00:00
|
|
|
// Map of secure config keys and values to set on the stack (e.g. {"aws:config:region": "us-east-2"})
|
2017-10-18 22:37:18 +00:00
|
|
|
Secrets map[string]string
|
2017-08-06 00:49:48 +00:00
|
|
|
// EditDirs is an optional list of edits to apply to the example, as subsequent deployments.
|
2017-10-26 23:01:28 +00:00
|
|
|
EditDirs []EditDir
|
2017-08-18 05:12:58 +00:00
|
|
|
// ExtraRuntimeValidation is an optional callback for additional validation, called before applying edits.
|
2017-12-14 00:09:14 +00:00
|
|
|
ExtraRuntimeValidation func(t *testing.T, stack RuntimeValidationStackInfo)
|
2017-11-15 05:02:47 +00:00
|
|
|
// RelativeWorkDir is an optional path relative to `Dir` which should be used as working directory during tests.
|
|
|
|
RelativeWorkDir string
|
2018-05-23 16:17:10 +00:00
|
|
|
// AllowEmptyPreviewChanges is true if we expect that this test's no-op preview may propose changes (e.g.
|
|
|
|
// because the test is sensitive to the exact contents of its working directory and those contents change
|
|
|
|
// incidentally between the initial update and the empty update).
|
|
|
|
AllowEmptyPreviewChanges bool
|
|
|
|
// AllowEmptyUpdateChanges is true if we expect that this test's no-op update may perform changes (e.g.
|
|
|
|
// because the test is sensitive to the exact contents of its working directory and those contents change
|
|
|
|
// incidentally between the initial update and the empty update).
|
|
|
|
AllowEmptyUpdateChanges bool
|
2017-12-20 20:10:46 +00:00
|
|
|
// ExpectFailure is true if we expect this test to fail. This is very coarse grained, and will essentially
|
|
|
|
// tolerate *any* failure in the program (IDEA: in the future, offer a way to narrow this down more).
|
|
|
|
ExpectFailure bool
|
2018-08-23 00:52:46 +00:00
|
|
|
// ExpectRefreshChanges may be set to true if a test is expected to have changes yielded by an immediate refresh.
|
|
|
|
// This could occur, for example, is a resource's state is constantly changing outside of Pulumi (e.g., timestamps).
|
|
|
|
ExpectRefreshChanges bool
|
2017-11-16 16:15:56 +00:00
|
|
|
// Quick can be set to true to run a "quick" test that skips any non-essential steps (e.g., empty updates).
|
|
|
|
Quick bool
|
2017-12-20 19:17:25 +00:00
|
|
|
// UpdateCommandlineFlags specifies flags to add to the `pulumi update` command line (e.g. "--color=raw")
|
|
|
|
UpdateCommandlineFlags []string
|
2018-06-25 05:47:54 +00:00
|
|
|
// RunBuild indicates that the build step should be run (e.g. run `yarn build` for `nodejs` programs)
|
|
|
|
RunBuild bool
|
2017-08-06 00:49:48 +00:00
|
|
|
|
2018-04-03 04:34:54 +00:00
|
|
|
// CloudURL is an optional URL to override the default Pulumi Service API (https://api.pulumi-staging.io). The
|
|
|
|
// PULUMI_ACCESS_TOKEN environment variable must also be set to a valid access token for the target cloud.
|
2018-01-04 05:26:50 +00:00
|
|
|
CloudURL string
|
|
|
|
// PPCName is the name of the PPC to use when running a test against the hosted service. If
|
|
|
|
// not set, the --ppc flag will not be set on `pulumi stack init`.
|
|
|
|
PPCName string
|
|
|
|
|
2017-12-15 01:10:05 +00:00
|
|
|
// StackName allows the stack name to be explicitly provided instead of computed from the
|
|
|
|
// environment during tests.
|
|
|
|
StackName string
|
|
|
|
|
2018-05-03 20:44:21 +00:00
|
|
|
// Tracing specifies the Zipkin endpoint if any to use for tracing Pulumi invocatoions.
|
|
|
|
Tracing string
|
|
|
|
|
2018-05-15 16:48:56 +00:00
|
|
|
// PrePulumiCommand specifies a callback that will be executed before each `pulumi` invocation. This callback may
|
|
|
|
// optionally return another callback to be invoked after the `pulumi` invocation completes.
|
|
|
|
PrePulumiCommand func(verb string) (func(err error) error, error)
|
|
|
|
|
2017-11-14 17:33:22 +00:00
|
|
|
// ReportStats optionally specifies how to report results from the test for external collection.
|
|
|
|
ReportStats TestStatsReporter
|
|
|
|
|
2017-08-06 00:49:48 +00:00
|
|
|
// Stdout is the writer to use for all stdout messages.
|
|
|
|
Stdout io.Writer
|
|
|
|
// Stderr is the writer to use for all stderr messages.
|
|
|
|
Stderr io.Writer
|
2017-11-06 01:28:12 +00:00
|
|
|
// Verbose may be set to true to print messages as they occur, rather than buffering and showing upon failure.
|
|
|
|
Verbose bool
|
2017-08-06 00:49:48 +00:00
|
|
|
|
2017-12-01 01:23:58 +00:00
|
|
|
// DebugLogging may be set to anything >0 to enable excessively verbose debug logging from `pulumi`. This is
|
|
|
|
// equivalent to `--logtostderr -v=N`, where N is the value of DebugLogLevel. This may also be enabled by setting
|
|
|
|
// the environment variable PULUMI_TEST_DEBUG_LOG_LEVEL.
|
|
|
|
DebugLogLevel int
|
2017-11-28 19:03:34 +00:00
|
|
|
// DebugUpdates may be set to true to enable debug logging from `pulumi preview`, `pulumi update`, and
|
2017-12-01 01:23:58 +00:00
|
|
|
// `pulumi destroy`. This may also be enabled by setting the environment variable PULUMI_TEST_DEBUG_UPDATES.
|
2017-11-24 23:21:43 +00:00
|
|
|
DebugUpdates bool
|
|
|
|
|
2017-10-23 01:54:29 +00:00
|
|
|
// Bin is a location of a `pulumi` executable to be run. Taken from the $PATH if missing.
|
|
|
|
Bin string
|
2017-08-06 00:49:48 +00:00
|
|
|
// YarnBin is a location of a `yarn` executable to be run. Taken from the $PATH if missing.
|
|
|
|
YarnBin string
|
2018-06-10 16:17:19 +00:00
|
|
|
// GoBin is a location of a `go` executable to be run. Taken from the $PATH if missing.
|
|
|
|
GoBin string
|
2018-04-04 22:31:01 +00:00
|
|
|
|
|
|
|
// Additional environment variaibles to pass for each command we run.
|
|
|
|
Env []string
|
2017-08-06 00:49:48 +00:00
|
|
|
}
|
|
|
|
|
2017-12-09 00:59:28 +00:00
|
|
|
func (opts *ProgramTestOptions) GetDebugLogLevel() int {
|
2017-12-01 01:23:58 +00:00
|
|
|
if opts.DebugLogLevel > 0 {
|
|
|
|
return opts.DebugLogLevel
|
|
|
|
}
|
|
|
|
if du := os.Getenv("PULUMI_TEST_DEBUG_LOG_LEVEL"); du != "" {
|
2018-03-29 22:15:52 +00:00
|
|
|
if n, e := strconv.Atoi(du); e != nil {
|
|
|
|
panic(e)
|
|
|
|
} else if n > 0 {
|
2017-12-01 01:23:58 +00:00
|
|
|
return n
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
2017-12-09 00:59:28 +00:00
|
|
|
func (opts *ProgramTestOptions) GetDebugUpdates() bool {
|
2017-12-01 01:23:58 +00:00
|
|
|
return opts.DebugUpdates || os.Getenv("PULUMI_TEST_DEBUG_UPDATES") != ""
|
|
|
|
}
|
|
|
|
|
2017-12-15 01:10:05 +00:00
|
|
|
// GetStackName returns a stack name to use for this test.
|
|
|
|
func (opts *ProgramTestOptions) GetStackName() tokens.QName {
|
|
|
|
if opts.StackName == "" {
|
|
|
|
// Fetch the host and test dir names, cleaned so to contain just [a-zA-Z0-9-_] chars.
|
|
|
|
hostname, err := os.Hostname()
|
|
|
|
contract.AssertNoErrorf(err, "failure to fetch hostname for stack prefix")
|
|
|
|
var host string
|
|
|
|
for _, c := range hostname {
|
|
|
|
if len(host) >= 10 {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
if (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
|
|
|
|
(c >= '0' && c <= '9') || c == '-' || c == '_' {
|
|
|
|
host += string(c)
|
|
|
|
}
|
2017-11-06 15:23:07 +00:00
|
|
|
}
|
2017-11-16 15:49:07 +00:00
|
|
|
|
2017-12-15 01:10:05 +00:00
|
|
|
var test string
|
|
|
|
for _, c := range filepath.Base(opts.Dir) {
|
|
|
|
if len(test) >= 10 {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
if (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
|
|
|
|
(c >= '0' && c <= '9') || c == '-' || c == '_' {
|
|
|
|
test += string(c)
|
|
|
|
}
|
2017-11-06 15:23:07 +00:00
|
|
|
}
|
2017-12-15 01:10:05 +00:00
|
|
|
|
2018-04-12 20:50:07 +00:00
|
|
|
b := make([]byte, 4)
|
2018-06-04 23:34:38 +00:00
|
|
|
_, err = cryptorand.Read(b)
|
2018-04-12 20:50:07 +00:00
|
|
|
contract.AssertNoError(err)
|
|
|
|
|
|
|
|
opts.StackName = strings.ToLower("p-it-" + host + "-" + test + "-" + hex.EncodeToString(b))
|
2017-11-06 15:23:07 +00:00
|
|
|
}
|
2017-11-16 15:49:07 +00:00
|
|
|
|
2017-12-15 01:10:05 +00:00
|
|
|
return tokens.QName(opts.StackName)
|
2017-11-06 15:23:07 +00:00
|
|
|
}
|
|
|
|
|
2018-08-16 01:14:17 +00:00
|
|
|
// GetStackNameWithOwner gets the name of the stack prepended with an owner, if PULUMI_TEST_OWNER is set.
|
|
|
|
// We use this in CI to create test stacks in an organization that all developers have access to, for debugging.
|
|
|
|
func (opts *ProgramTestOptions) GetStackNameWithOwner() tokens.QName {
|
|
|
|
if owner := os.Getenv("PULUMI_TEST_OWNER"); owner != "" {
|
|
|
|
return tokens.QName(fmt.Sprintf("%s/%s", owner, opts.GetStackName()))
|
|
|
|
}
|
|
|
|
|
|
|
|
return opts.GetStackName()
|
|
|
|
}
|
|
|
|
|
2017-08-06 00:49:48 +00:00
|
|
|
// With combines a source set of options with a set of overrides.
|
2017-10-23 01:54:29 +00:00
|
|
|
func (opts ProgramTestOptions) With(overrides ProgramTestOptions) ProgramTestOptions {
|
2017-08-06 00:49:48 +00:00
|
|
|
if overrides.Dir != "" {
|
|
|
|
opts.Dir = overrides.Dir
|
|
|
|
}
|
|
|
|
if overrides.Dependencies != nil {
|
|
|
|
opts.Dependencies = overrides.Dependencies
|
|
|
|
}
|
|
|
|
for k, v := range overrides.Config {
|
|
|
|
if opts.Config == nil {
|
|
|
|
opts.Config = make(map[string]string)
|
|
|
|
}
|
|
|
|
opts.Config[k] = v
|
|
|
|
}
|
2017-11-14 17:33:22 +00:00
|
|
|
for k, v := range overrides.Secrets {
|
|
|
|
if opts.Secrets == nil {
|
|
|
|
opts.Secrets = make(map[string]string)
|
|
|
|
}
|
|
|
|
opts.Secrets[k] = v
|
|
|
|
}
|
2018-01-04 05:26:50 +00:00
|
|
|
if overrides.CloudURL != "" {
|
|
|
|
opts.CloudURL = overrides.CloudURL
|
|
|
|
}
|
|
|
|
if overrides.PPCName != "" {
|
|
|
|
opts.PPCName = overrides.PPCName
|
|
|
|
}
|
2018-05-03 20:44:21 +00:00
|
|
|
if overrides.Tracing != "" {
|
|
|
|
opts.Tracing = overrides.Tracing
|
|
|
|
}
|
2017-08-06 00:49:48 +00:00
|
|
|
if overrides.EditDirs != nil {
|
|
|
|
opts.EditDirs = overrides.EditDirs
|
|
|
|
}
|
2017-11-14 17:33:22 +00:00
|
|
|
if overrides.ExtraRuntimeValidation != nil {
|
|
|
|
opts.ExtraRuntimeValidation = overrides.ExtraRuntimeValidation
|
|
|
|
}
|
2017-11-15 05:02:47 +00:00
|
|
|
if overrides.RelativeWorkDir != "" {
|
|
|
|
opts.RelativeWorkDir = overrides.RelativeWorkDir
|
|
|
|
}
|
2017-11-14 17:33:22 +00:00
|
|
|
if overrides.ReportStats != nil {
|
|
|
|
opts.ReportStats = overrides.ReportStats
|
|
|
|
}
|
2018-06-25 05:47:54 +00:00
|
|
|
if overrides.RunBuild {
|
|
|
|
opts.RunBuild = overrides.RunBuild
|
2018-07-07 05:06:28 +00:00
|
|
|
}
|
2017-08-06 00:49:48 +00:00
|
|
|
return opts
|
2017-07-13 19:19:17 +00:00
|
|
|
}
|
|
|
|
|
2017-12-08 20:59:39 +00:00
|
|
|
// ProgramTest runs a lifecycle of Pulumi commands in a program working directory, using the `pulumi` and `yarn`
|
|
|
|
// binaries available on PATH. It essentially executes the following workflow:
|
2017-10-23 12:27:26 +00:00
|
|
|
//
|
2017-12-08 20:59:39 +00:00
|
|
|
// yarn install
|
|
|
|
// yarn link <each opts.Depencies>
|
2018-08-02 01:09:23 +00:00
|
|
|
// (+) yarn run build
|
2017-12-08 20:59:39 +00:00
|
|
|
// pulumi init
|
2018-01-04 05:26:50 +00:00
|
|
|
// (*) pulumi login
|
2017-12-08 20:59:39 +00:00
|
|
|
// pulumi stack init integrationtesting
|
|
|
|
// pulumi config set <each opts.Config>
|
|
|
|
// pulumi config set --secret <each opts.Secrets>
|
|
|
|
// pulumi preview
|
|
|
|
// pulumi update
|
2018-06-14 23:01:28 +00:00
|
|
|
// pulumi stack export --file stack.json
|
|
|
|
// pulumi stack import --file stack.json
|
2017-12-08 20:59:39 +00:00
|
|
|
// pulumi preview (expected to be empty)
|
|
|
|
// pulumi update (expected to be empty)
|
|
|
|
// pulumi destroy --yes
|
|
|
|
// pulumi stack rm --yes integrationtesting
|
2018-01-04 05:26:50 +00:00
|
|
|
//
|
2018-04-03 04:34:54 +00:00
|
|
|
// (*) Only if PULUMI_ACCESS_TOKEN is set.
|
2018-08-02 01:09:23 +00:00
|
|
|
// (+) Only if `opts.RunBuild` is true.
|
2017-10-23 12:27:26 +00:00
|
|
|
//
|
2017-12-20 20:10:46 +00:00
|
|
|
// All commands must return success return codes for the test to succeed, unless ExpectFailure is true.
|
2017-12-09 00:59:28 +00:00
|
|
|
func ProgramTest(t *testing.T, opts *ProgramTestOptions) {
|
2018-02-21 05:05:57 +00:00
|
|
|
// Disable stack backups for tests to avoid filling up ~/.pulumi/backups with unnecessary
|
|
|
|
// backups of test stacks.
|
|
|
|
if err := os.Setenv(local.DisableCheckpointBackupsEnvVar, "1"); err != nil {
|
|
|
|
t.Errorf("error setting env var '%s': %v", local.DisableCheckpointBackupsEnvVar, err)
|
|
|
|
}
|
|
|
|
|
Restructure test framework to ease multiple languages (#799)
This change restructures the test framework code a bit, to make it
easier to introduce additional languages. Our knowledge of Yarn and
Node.js project structure, for instance, was previously baked in to
the test logic, in a way that was hard to make, for instance, Yarn
optional. (In Python, of course, it will not be used.) To better
support this, I've moved some state onto a new programTester struct
that we can use to lazily find binaries required during the testing
(such as Yarn, Pip, and so on). I'm committing this separately so
that I can minimize merge conflicts in the Python work.
2018-01-13 01:10:53 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2018-06-11 23:01:04 +00:00
|
|
|
if testutil.IsCI() && os.Getenv("PULUMI_ACCESS_TOKEN") == "" {
|
|
|
|
t.Skip("Skipping: PULUMI_ACCESS_TOKEN is not set")
|
|
|
|
}
|
|
|
|
|
2018-01-20 07:07:38 +00:00
|
|
|
// If the test panics, recover and log instead of letting the panic escape the test. Even though *this* test will
|
|
|
|
// have run deferred functions and cleaned up, if the panic reaches toplevel it will kill the process and prevent
|
|
|
|
// other tests running in parallel from cleaning up.
|
|
|
|
defer func() {
|
|
|
|
if failure := recover(); failure != nil {
|
|
|
|
t.Errorf("panic testing %v: %v", opts.Dir, failure)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
2018-05-29 18:24:51 +00:00
|
|
|
// Set up some default values for sending test reports and tracing data. We use environment varaiables to
|
|
|
|
// control these globally and set reasonable values for our own use in CI.
|
|
|
|
if opts.ReportStats == nil {
|
|
|
|
if v := os.Getenv("PULUMI_TEST_REPORT_CONFIG"); v != "" {
|
|
|
|
splits := strings.Split(v, ":")
|
|
|
|
if len(splits) != 3 {
|
|
|
|
t.Errorf("report config should be set to a value of the form: <aws-region>:<bucket-name>:<keyPrefix>")
|
|
|
|
}
|
|
|
|
|
|
|
|
opts.ReportStats = NewS3Reporter(splits[0], splits[1], splits[2])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if opts.Tracing == "" {
|
|
|
|
opts.Tracing = os.Getenv("PULUMI_TEST_TRACE_ENDPOINT")
|
|
|
|
}
|
|
|
|
|
Restructure test framework to ease multiple languages (#799)
This change restructures the test framework code a bit, to make it
easier to introduce additional languages. Our knowledge of Yarn and
Node.js project structure, for instance, was previously baked in to
the test logic, in a way that was hard to make, for instance, Yarn
optional. (In Python, of course, it will not be used.) To better
support this, I've moved some state onto a new programTester struct
that we can use to lazily find binaries required during the testing
(such as Yarn, Pip, and so on). I'm committing this separately so
that I can minimize merge conflicts in the Python work.
2018-01-13 01:10:53 +00:00
|
|
|
pt := newProgramTester(t, opts)
|
|
|
|
err := pt.testLifeCycleInitAndDestroy()
|
2017-12-20 20:10:46 +00:00
|
|
|
assert.NoError(t, err)
|
2017-12-11 22:42:42 +00:00
|
|
|
}
|
|
|
|
|
2018-01-17 01:32:49 +00:00
|
|
|
// fprintf works like fmt.FPrintf, except it explicitly drops the return values. This keeps the linters happy, since
|
|
|
|
// they don't like to see errors dropped on the floor. It is possible that our call to fmt.Fprintf will fail, even
|
|
|
|
// for "standard" streams like `stdout` and `stderr`, if they have been set to non-blocking by an external process.
|
|
|
|
// In that case, we just drop the error on the floor and continue. We see this behavior in Travis when we try to write
|
|
|
|
// a lot of messages quickly (as we do when logging test failures)
|
|
|
|
func fprintf(w io.Writer, format string, a ...interface{}) {
|
|
|
|
_, err := fmt.Fprintf(w, format, a...)
|
|
|
|
contract.IgnoreError(err)
|
|
|
|
}
|
|
|
|
|
Restructure test framework to ease multiple languages (#799)
This change restructures the test framework code a bit, to make it
easier to introduce additional languages. Our knowledge of Yarn and
Node.js project structure, for instance, was previously baked in to
the test logic, in a way that was hard to make, for instance, Yarn
optional. (In Python, of course, it will not be used.) To better
support this, I've moved some state onto a new programTester struct
that we can use to lazily find binaries required during the testing
(such as Yarn, Pip, and so on). I'm committing this separately so
that I can minimize merge conflicts in the Python work.
2018-01-13 01:10:53 +00:00
|
|
|
// programTester contains state associated with running a single test pass.
|
|
|
|
type programTester struct {
|
|
|
|
t *testing.T // the Go tester for this run.
|
|
|
|
opts *ProgramTestOptions // options that control this test run.
|
|
|
|
bin string // the `pulumi` binary we are using.
|
|
|
|
yarnBin string // the `yarn` binary we are using.
|
2018-06-10 16:17:19 +00:00
|
|
|
goBin string // the `go` binary we are using.
|
2018-01-06 01:40:41 +00:00
|
|
|
}
|
|
|
|
|
Restructure test framework to ease multiple languages (#799)
This change restructures the test framework code a bit, to make it
easier to introduce additional languages. Our knowledge of Yarn and
Node.js project structure, for instance, was previously baked in to
the test logic, in a way that was hard to make, for instance, Yarn
optional. (In Python, of course, it will not be used.) To better
support this, I've moved some state onto a new programTester struct
that we can use to lazily find binaries required during the testing
(such as Yarn, Pip, and so on). I'm committing this separately so
that I can minimize merge conflicts in the Python work.
2018-01-13 01:10:53 +00:00
|
|
|
func newProgramTester(t *testing.T, opts *ProgramTestOptions) *programTester {
|
|
|
|
return &programTester{t: t, opts: opts}
|
|
|
|
}
|
2017-12-11 22:42:42 +00:00
|
|
|
|
Restructure test framework to ease multiple languages (#799)
This change restructures the test framework code a bit, to make it
easier to introduce additional languages. Our knowledge of Yarn and
Node.js project structure, for instance, was previously baked in to
the test logic, in a way that was hard to make, for instance, Yarn
optional. (In Python, of course, it will not be used.) To better
support this, I've moved some state onto a new programTester struct
that we can use to lazily find binaries required during the testing
(such as Yarn, Pip, and so on). I'm committing this separately so
that I can minimize merge conflicts in the Python work.
2018-01-13 01:10:53 +00:00
|
|
|
func (pt *programTester) getBin() (string, error) {
|
|
|
|
return getCmdBin(&pt.bin, "pulumi", pt.opts.Bin)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (pt *programTester) getYarnBin() (string, error) {
|
|
|
|
return getCmdBin(&pt.yarnBin, "yarn", pt.opts.YarnBin)
|
|
|
|
}
|
|
|
|
|
2018-06-10 16:17:19 +00:00
|
|
|
func (pt *programTester) getGoBin() (string, error) {
|
|
|
|
return getCmdBin(&pt.goBin, "go", pt.opts.GoBin)
|
|
|
|
}
|
|
|
|
|
Restructure test framework to ease multiple languages (#799)
This change restructures the test framework code a bit, to make it
easier to introduce additional languages. Our knowledge of Yarn and
Node.js project structure, for instance, was previously baked in to
the test logic, in a way that was hard to make, for instance, Yarn
optional. (In Python, of course, it will not be used.) To better
support this, I've moved some state onto a new programTester struct
that we can use to lazily find binaries required during the testing
(such as Yarn, Pip, and so on). I'm committing this separately so
that I can minimize merge conflicts in the Python work.
2018-01-13 01:10:53 +00:00
|
|
|
func (pt *programTester) pulumiCmd(args []string) ([]string, error) {
|
|
|
|
bin, err := pt.getBin()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
cmd := []string{bin}
|
|
|
|
if du := pt.opts.GetDebugLogLevel(); du > 0 {
|
2018-05-03 20:44:21 +00:00
|
|
|
cmd = append(cmd, "--logtostderr", "-v="+strconv.Itoa(du))
|
|
|
|
}
|
|
|
|
cmd = append(cmd, args...)
|
|
|
|
if tracing := pt.opts.Tracing; tracing != "" {
|
|
|
|
cmd = append(cmd, "--tracing", tracing)
|
Restructure test framework to ease multiple languages (#799)
This change restructures the test framework code a bit, to make it
easier to introduce additional languages. Our knowledge of Yarn and
Node.js project structure, for instance, was previously baked in to
the test logic, in a way that was hard to make, for instance, Yarn
optional. (In Python, of course, it will not be used.) To better
support this, I've moved some state onto a new programTester struct
that we can use to lazily find binaries required during the testing
(such as Yarn, Pip, and so on). I'm committing this separately so
that I can minimize merge conflicts in the Python work.
2018-01-13 01:10:53 +00:00
|
|
|
}
|
2018-05-03 20:44:21 +00:00
|
|
|
return cmd, nil
|
Restructure test framework to ease multiple languages (#799)
This change restructures the test framework code a bit, to make it
easier to introduce additional languages. Our knowledge of Yarn and
Node.js project structure, for instance, was previously baked in to
the test logic, in a way that was hard to make, for instance, Yarn
optional. (In Python, of course, it will not be used.) To better
support this, I've moved some state onto a new programTester struct
that we can use to lazily find binaries required during the testing
(such as Yarn, Pip, and so on). I'm committing this separately so
that I can minimize merge conflicts in the Python work.
2018-01-13 01:10:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (pt *programTester) yarnCmd(args []string) ([]string, error) {
|
|
|
|
bin, err := pt.getYarnBin()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
result := []string{bin}
|
|
|
|
result = append(result, args...)
|
|
|
|
return withOptionalYarnFlags(result), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (pt *programTester) runCommand(name string, args []string, wd string) error {
|
|
|
|
return RunCommand(pt.t, name, args, wd, pt.opts)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (pt *programTester) runPulumiCommand(name string, args []string, wd string) error {
|
|
|
|
cmd, err := pt.pulumiCmd(args)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2018-05-15 16:48:56 +00:00
|
|
|
|
|
|
|
var postFn func(error) error
|
|
|
|
if pt.opts.PrePulumiCommand != nil {
|
|
|
|
postFn, err = pt.opts.PrePulumiCommand(args[0])
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
runErr := pt.runCommand(name, cmd, wd)
|
|
|
|
if postFn != nil {
|
|
|
|
if postErr := postFn(runErr); postErr != nil {
|
|
|
|
return multierror.Append(runErr, postErr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return runErr
|
Restructure test framework to ease multiple languages (#799)
This change restructures the test framework code a bit, to make it
easier to introduce additional languages. Our knowledge of Yarn and
Node.js project structure, for instance, was previously baked in to
the test logic, in a way that was hard to make, for instance, Yarn
optional. (In Python, of course, it will not be used.) To better
support this, I've moved some state onto a new programTester struct
that we can use to lazily find binaries required during the testing
(such as Yarn, Pip, and so on). I'm committing this separately so
that I can minimize merge conflicts in the Python work.
2018-01-13 01:10:53 +00:00
|
|
|
}
|
2017-08-06 00:49:48 +00:00
|
|
|
|
Restructure test framework to ease multiple languages (#799)
This change restructures the test framework code a bit, to make it
easier to introduce additional languages. Our knowledge of Yarn and
Node.js project structure, for instance, was previously baked in to
the test logic, in a way that was hard to make, for instance, Yarn
optional. (In Python, of course, it will not be used.) To better
support this, I've moved some state onto a new programTester struct
that we can use to lazily find binaries required during the testing
(such as Yarn, Pip, and so on). I'm committing this separately so
that I can minimize merge conflicts in the Python work.
2018-01-13 01:10:53 +00:00
|
|
|
func (pt *programTester) runYarnCommand(name string, args []string, wd string) error {
|
|
|
|
cmd, err := pt.yarnCmd(args)
|
2018-01-06 00:39:13 +00:00
|
|
|
if err != nil {
|
Restructure test framework to ease multiple languages (#799)
This change restructures the test framework code a bit, to make it
easier to introduce additional languages. Our knowledge of Yarn and
Node.js project structure, for instance, was previously baked in to
the test logic, in a way that was hard to make, for instance, Yarn
optional. (In Python, of course, it will not be used.) To better
support this, I've moved some state onto a new programTester struct
that we can use to lazily find binaries required during the testing
(such as Yarn, Pip, and so on). I'm committing this separately so
that I can minimize merge conflicts in the Python work.
2018-01-13 01:10:53 +00:00
|
|
|
return err
|
|
|
|
}
|
2018-02-04 00:17:51 +00:00
|
|
|
|
|
|
|
_, _, err = retry.Until(context.Background(), retry.Acceptor{
|
|
|
|
Accept: func(try int, nextRetryTime time.Duration) (bool, interface{}, error) {
|
|
|
|
runerr := pt.runCommand(name, cmd, wd)
|
|
|
|
if runerr == nil {
|
|
|
|
return true, nil, nil
|
|
|
|
} else if _, ok := runerr.(*exec.ExitError); ok {
|
|
|
|
// yarn failed, let's try again, assuming we haven't failed a few times.
|
|
|
|
if try > 3 {
|
|
|
|
return false, nil, errors.Errorf("%v did not complete after %v tries", cmd, try)
|
|
|
|
}
|
|
|
|
|
|
|
|
return false, nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// someother error, fail
|
|
|
|
return false, nil, runerr
|
|
|
|
},
|
|
|
|
})
|
|
|
|
return err
|
Restructure test framework to ease multiple languages (#799)
This change restructures the test framework code a bit, to make it
easier to introduce additional languages. Our knowledge of Yarn and
Node.js project structure, for instance, was previously baked in to
the test logic, in a way that was hard to make, for instance, Yarn
optional. (In Python, of course, it will not be used.) To better
support this, I've moved some state onto a new programTester struct
that we can use to lazily find binaries required during the testing
(such as Yarn, Pip, and so on). I'm committing this separately so
that I can minimize merge conflicts in the Python work.
2018-01-13 01:10:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (pt *programTester) testLifeCycleInitAndDestroy() error {
|
2018-06-11 20:22:24 +00:00
|
|
|
tmpdir, projdir, err := pt.copyTestToTemporaryDirectory()
|
Restructure test framework to ease multiple languages (#799)
This change restructures the test framework code a bit, to make it
easier to introduce additional languages. Our knowledge of Yarn and
Node.js project structure, for instance, was previously baked in to
the test logic, in a way that was hard to make, for instance, Yarn
optional. (In Python, of course, it will not be used.) To better
support this, I've moved some state onto a new programTester struct
that we can use to lazily find binaries required during the testing
(such as Yarn, Pip, and so on). I'm committing this separately so
that I can minimize merge conflicts in the Python work.
2018-01-13 01:10:53 +00:00
|
|
|
if err != nil {
|
|
|
|
return errors.Wrap(err, "copying test to temp dir")
|
2018-01-06 00:39:13 +00:00
|
|
|
}
|
|
|
|
|
2018-03-07 19:23:59 +00:00
|
|
|
testFinished := false
|
2018-06-14 22:58:37 +00:00
|
|
|
defer func() {
|
|
|
|
if tmpdir != "" {
|
2018-06-11 20:22:24 +00:00
|
|
|
if !testFinished || pt.t.Failed() {
|
|
|
|
// Test aborted or failed. Maybe copy to "failed tests" directory.
|
|
|
|
failedTestsDir := os.Getenv("PULUMI_FAILED_TESTS_DIR")
|
|
|
|
if failedTestsDir != "" {
|
|
|
|
dest := filepath.Join(failedTestsDir, pt.t.Name()+uniqueSuffix())
|
|
|
|
contract.IgnoreError(fsutil.CopyFile(dest, tmpdir, nil))
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
contract.IgnoreError(os.RemoveAll(tmpdir))
|
2018-01-07 05:05:42 +00:00
|
|
|
}
|
2018-06-14 22:58:37 +00:00
|
|
|
} else {
|
|
|
|
// When tmpdir is empty, we ran "in tree", which means we wrote output
|
|
|
|
// to the "command-output" folder in the projdir, and we should clean
|
|
|
|
// it up if the test passed
|
|
|
|
if testFinished && !pt.t.Failed() {
|
|
|
|
contract.IgnoreError(os.RemoveAll(filepath.Join(projdir, commandOutputFolderName)))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}()
|
2018-01-06 00:39:13 +00:00
|
|
|
|
2018-06-11 20:22:24 +00:00
|
|
|
err = pt.testLifeCycleInitialize(projdir)
|
2017-12-09 00:59:28 +00:00
|
|
|
if err != nil {
|
Restructure test framework to ease multiple languages (#799)
This change restructures the test framework code a bit, to make it
easier to introduce additional languages. Our knowledge of Yarn and
Node.js project structure, for instance, was previously baked in to
the test logic, in a way that was hard to make, for instance, Yarn
optional. (In Python, of course, it will not be used.) To better
support this, I've moved some state onto a new programTester struct
that we can use to lazily find binaries required during the testing
(such as Yarn, Pip, and so on). I'm committing this separately so
that I can minimize merge conflicts in the Python work.
2018-01-13 01:10:53 +00:00
|
|
|
return errors.Wrap(err, "initializing test project")
|
2017-12-09 00:59:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure that before we exit, we attempt to destroy and remove the stack.
|
|
|
|
defer func() {
|
2018-06-11 20:22:24 +00:00
|
|
|
if projdir != "" {
|
|
|
|
destroyErr := pt.testLifeCycleDestroy(projdir)
|
Restructure test framework to ease multiple languages (#799)
This change restructures the test framework code a bit, to make it
easier to introduce additional languages. Our knowledge of Yarn and
Node.js project structure, for instance, was previously baked in to
the test logic, in a way that was hard to make, for instance, Yarn
optional. (In Python, of course, it will not be used.) To better
support this, I've moved some state onto a new programTester struct
that we can use to lazily find binaries required during the testing
(such as Yarn, Pip, and so on). I'm committing this separately so
that I can minimize merge conflicts in the Python work.
2018-01-13 01:10:53 +00:00
|
|
|
assert.NoError(pt.t, destroyErr)
|
2017-12-22 14:57:37 +00:00
|
|
|
}
|
2017-12-09 00:59:28 +00:00
|
|
|
}()
|
|
|
|
|
2018-06-11 20:22:24 +00:00
|
|
|
if err = pt.testPreviewUpdateAndEdits(projdir); err != nil {
|
Restructure test framework to ease multiple languages (#799)
This change restructures the test framework code a bit, to make it
easier to introduce additional languages. Our knowledge of Yarn and
Node.js project structure, for instance, was previously baked in to
the test logic, in a way that was hard to make, for instance, Yarn
optional. (In Python, of course, it will not be used.) To better
support this, I've moved some state onto a new programTester struct
that we can use to lazily find binaries required during the testing
(such as Yarn, Pip, and so on). I'm committing this separately so
that I can minimize merge conflicts in the Python work.
2018-01-13 01:10:53 +00:00
|
|
|
return errors.Wrap(err, "running test preview, update, and edits")
|
2018-01-10 07:25:49 +00:00
|
|
|
}
|
|
|
|
|
2018-03-07 19:23:59 +00:00
|
|
|
testFinished = true
|
2018-01-10 07:25:49 +00:00
|
|
|
return nil
|
2017-12-09 00:59:28 +00:00
|
|
|
}
|
|
|
|
|
Restructure test framework to ease multiple languages (#799)
This change restructures the test framework code a bit, to make it
easier to introduce additional languages. Our knowledge of Yarn and
Node.js project structure, for instance, was previously baked in to
the test logic, in a way that was hard to make, for instance, Yarn
optional. (In Python, of course, it will not be used.) To better
support this, I've moved some state onto a new programTester struct
that we can use to lazily find binaries required during the testing
(such as Yarn, Pip, and so on). I'm committing this separately so
that I can minimize merge conflicts in the Python work.
2018-01-13 01:10:53 +00:00
|
|
|
func (pt *programTester) testLifeCycleInitialize(dir string) error {
|
|
|
|
stackName := pt.opts.GetStackName()
|
2017-12-09 00:59:28 +00:00
|
|
|
|
2017-11-15 05:02:47 +00:00
|
|
|
// If RelativeWorkDir is specified, apply that relative to the temp folder for use as working directory during tests.
|
Restructure test framework to ease multiple languages (#799)
This change restructures the test framework code a bit, to make it
easier to introduce additional languages. Our knowledge of Yarn and
Node.js project structure, for instance, was previously baked in to
the test logic, in a way that was hard to make, for instance, Yarn
optional. (In Python, of course, it will not be used.) To better
support this, I've moved some state onto a new programTester struct
that we can use to lazily find binaries required during the testing
(such as Yarn, Pip, and so on). I'm committing this separately so
that I can minimize merge conflicts in the Python work.
2018-01-13 01:10:53 +00:00
|
|
|
if pt.opts.RelativeWorkDir != "" {
|
|
|
|
dir = path.Join(dir, pt.opts.RelativeWorkDir)
|
2017-11-15 05:02:47 +00:00
|
|
|
}
|
|
|
|
|
2018-04-03 04:34:54 +00:00
|
|
|
// Set the default target Pulumi API if not overridden in options.
|
|
|
|
if pt.opts.CloudURL == "" {
|
|
|
|
pulumiAPI := os.Getenv("PULUMI_API")
|
|
|
|
if pulumiAPI != "" {
|
|
|
|
pt.opts.CloudURL = pulumiAPI
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set the target PPC from an environment variable if not overridden in options.
|
|
|
|
if pt.opts.PPCName == "" {
|
|
|
|
ppcName := os.Getenv("PULUMI_API_PPC_NAME")
|
|
|
|
if ppcName != "" {
|
|
|
|
pt.opts.PPCName = ppcName
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-16 19:04:35 +00:00
|
|
|
// Ensure all links are present, the stack is created, and all configs are applied.
|
2018-01-17 01:32:49 +00:00
|
|
|
fprintf(pt.opts.Stdout, "Initializing project (dir %s; stack %s)\n", dir, stackName)
|
2018-01-04 05:26:50 +00:00
|
|
|
|
|
|
|
// Login as needed.
|
2018-04-04 22:31:01 +00:00
|
|
|
if os.Getenv("PULUMI_ACCESS_TOKEN") == "" && pt.opts.CloudURL == "" {
|
|
|
|
fmt.Printf("Using existing logged in user for tests. Set PULUMI_ACCESS_TOKEN and/or PULUMI_API to override.\n")
|
|
|
|
} else {
|
|
|
|
// Set PulumiCredentialsPathEnvVar to our CWD, so we use credentials specific to just this
|
|
|
|
// test.
|
|
|
|
pt.opts.Env = append(pt.opts.Env, fmt.Sprintf("%s=%s", workspace.PulumiCredentialsPathEnvVar, dir))
|
2018-01-04 05:26:50 +00:00
|
|
|
|
2018-04-04 22:31:01 +00:00
|
|
|
loginArgs := []string{"login"}
|
|
|
|
loginArgs = addFlagIfNonNil(loginArgs, "--cloud-url", pt.opts.CloudURL)
|
|
|
|
|
|
|
|
if err := pt.runPulumiCommand("pulumi-login", loginArgs, dir); err != nil {
|
|
|
|
return err
|
2018-01-04 05:26:50 +00:00
|
|
|
}
|
|
|
|
}
|
2018-04-04 22:31:01 +00:00
|
|
|
|
2018-01-04 05:26:50 +00:00
|
|
|
// Stack init
|
2018-08-16 01:14:17 +00:00
|
|
|
stackInitArgs := []string{"stack", "init", string(pt.opts.GetStackNameWithOwner())}
|
2018-04-04 22:31:01 +00:00
|
|
|
stackInitArgs = addFlagIfNonNil(stackInitArgs, "--ppc", pt.opts.PPCName)
|
|
|
|
|
Restructure test framework to ease multiple languages (#799)
This change restructures the test framework code a bit, to make it
easier to introduce additional languages. Our knowledge of Yarn and
Node.js project structure, for instance, was previously baked in to
the test logic, in a way that was hard to make, for instance, Yarn
optional. (In Python, of course, it will not be used.) To better
support this, I've moved some state onto a new programTester struct
that we can use to lazily find binaries required during the testing
(such as Yarn, Pip, and so on). I'm committing this separately so
that I can minimize merge conflicts in the Python work.
2018-01-13 01:10:53 +00:00
|
|
|
if err := pt.runPulumiCommand("pulumi-stack-init", stackInitArgs, dir); err != nil {
|
2018-01-06 00:39:13 +00:00
|
|
|
return err
|
2017-11-06 17:04:38 +00:00
|
|
|
}
|
2017-12-09 00:59:28 +00:00
|
|
|
|
Restructure test framework to ease multiple languages (#799)
This change restructures the test framework code a bit, to make it
easier to introduce additional languages. Our knowledge of Yarn and
Node.js project structure, for instance, was previously baked in to
the test logic, in a way that was hard to make, for instance, Yarn
optional. (In Python, of course, it will not be used.) To better
support this, I've moved some state onto a new programTester struct
that we can use to lazily find binaries required during the testing
(such as Yarn, Pip, and so on). I'm committing this separately so
that I can minimize merge conflicts in the Python work.
2018-01-13 01:10:53 +00:00
|
|
|
for key, value := range pt.opts.Config {
|
|
|
|
if err := pt.runPulumiCommand("pulumi-config",
|
|
|
|
[]string{"config", "set", key, value}, dir); err != nil {
|
2018-01-06 00:39:13 +00:00
|
|
|
return err
|
2017-11-06 17:04:38 +00:00
|
|
|
}
|
2017-10-18 22:37:18 +00:00
|
|
|
}
|
|
|
|
|
Restructure test framework to ease multiple languages (#799)
This change restructures the test framework code a bit, to make it
easier to introduce additional languages. Our knowledge of Yarn and
Node.js project structure, for instance, was previously baked in to
the test logic, in a way that was hard to make, for instance, Yarn
optional. (In Python, of course, it will not be used.) To better
support this, I've moved some state onto a new programTester struct
that we can use to lazily find binaries required during the testing
(such as Yarn, Pip, and so on). I'm committing this separately so
that I can minimize merge conflicts in the Python work.
2018-01-13 01:10:53 +00:00
|
|
|
for key, value := range pt.opts.Secrets {
|
|
|
|
if err := pt.runPulumiCommand("pulumi-config",
|
|
|
|
[]string{"config", "set", "--secret", key, value}, dir); err != nil {
|
2018-01-06 00:39:13 +00:00
|
|
|
return err
|
2017-11-06 17:04:38 +00:00
|
|
|
}
|
2017-08-06 00:49:48 +00:00
|
|
|
}
|
|
|
|
|
2018-01-06 00:39:13 +00:00
|
|
|
return nil
|
2017-12-09 00:59:28 +00:00
|
|
|
}
|
|
|
|
|
Restructure test framework to ease multiple languages (#799)
This change restructures the test framework code a bit, to make it
easier to introduce additional languages. Our knowledge of Yarn and
Node.js project structure, for instance, was previously baked in to
the test logic, in a way that was hard to make, for instance, Yarn
optional. (In Python, of course, it will not be used.) To better
support this, I've moved some state onto a new programTester struct
that we can use to lazily find binaries required during the testing
(such as Yarn, Pip, and so on). I'm committing this separately so
that I can minimize merge conflicts in the Python work.
2018-01-13 01:10:53 +00:00
|
|
|
func (pt *programTester) testLifeCycleDestroy(dir string) error {
|
|
|
|
// Destroy and remove the stack.
|
2018-01-17 01:32:49 +00:00
|
|
|
fprintf(pt.opts.Stdout, "Destroying stack\n")
|
2018-05-05 18:57:09 +00:00
|
|
|
destroy := []string{"destroy", "--non-interactive", "--skip-preview"}
|
Restructure test framework to ease multiple languages (#799)
This change restructures the test framework code a bit, to make it
easier to introduce additional languages. Our knowledge of Yarn and
Node.js project structure, for instance, was previously baked in to
the test logic, in a way that was hard to make, for instance, Yarn
optional. (In Python, of course, it will not be used.) To better
support this, I've moved some state onto a new programTester struct
that we can use to lazily find binaries required during the testing
(such as Yarn, Pip, and so on). I'm committing this separately so
that I can minimize merge conflicts in the Python work.
2018-01-13 01:10:53 +00:00
|
|
|
if pt.opts.GetDebugUpdates() {
|
2017-11-24 23:21:43 +00:00
|
|
|
destroy = append(destroy, "-d")
|
|
|
|
}
|
Restructure test framework to ease multiple languages (#799)
This change restructures the test framework code a bit, to make it
easier to introduce additional languages. Our knowledge of Yarn and
Node.js project structure, for instance, was previously baked in to
the test logic, in a way that was hard to make, for instance, Yarn
optional. (In Python, of course, it will not be used.) To better
support this, I've moved some state onto a new programTester struct
that we can use to lazily find binaries required during the testing
(such as Yarn, Pip, and so on). I'm committing this separately so
that I can minimize merge conflicts in the Python work.
2018-01-13 01:10:53 +00:00
|
|
|
if err := pt.runPulumiCommand("pulumi-destroy", destroy, dir); err != nil {
|
2017-12-20 20:10:46 +00:00
|
|
|
return err
|
|
|
|
}
|
2018-01-04 05:26:50 +00:00
|
|
|
|
2018-08-16 01:14:17 +00:00
|
|
|
if pt.t.Failed() {
|
|
|
|
fprintf(pt.opts.Stdout, "Test failed, retaining stack '%s'\n", pt.opts.GetStackNameWithOwner())
|
|
|
|
return nil
|
|
|
|
}
|
2018-01-04 05:26:50 +00:00
|
|
|
|
2018-08-16 01:14:17 +00:00
|
|
|
return pt.runPulumiCommand("pulumi-stack-rm", []string{"stack", "rm", "--yes"}, dir)
|
2017-12-09 00:59:28 +00:00
|
|
|
}
|
2017-12-08 20:59:39 +00:00
|
|
|
|
Restructure test framework to ease multiple languages (#799)
This change restructures the test framework code a bit, to make it
easier to introduce additional languages. Our knowledge of Yarn and
Node.js project structure, for instance, was previously baked in to
the test logic, in a way that was hard to make, for instance, Yarn
optional. (In Python, of course, it will not be used.) To better
support this, I've moved some state onto a new programTester struct
that we can use to lazily find binaries required during the testing
(such as Yarn, Pip, and so on). I'm committing this separately so
that I can minimize merge conflicts in the Python work.
2018-01-13 01:10:53 +00:00
|
|
|
func (pt *programTester) testPreviewUpdateAndEdits(dir string) error {
|
2017-12-11 22:42:42 +00:00
|
|
|
// Now preview and update the real changes.
|
2018-01-17 01:32:49 +00:00
|
|
|
fprintf(pt.opts.Stdout, "Performing primary preview and update\n")
|
2018-05-23 16:17:10 +00:00
|
|
|
initErr := pt.previewAndUpdate(dir, "initial", pt.opts.ExpectFailure, false, false)
|
2017-12-11 22:42:42 +00:00
|
|
|
|
|
|
|
// If the initial preview/update failed, just exit without trying the rest (but make sure to destroy).
|
|
|
|
if initErr != nil {
|
2018-01-06 00:39:13 +00:00
|
|
|
return initErr
|
2017-12-11 22:42:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Perform an empty preview and update; nothing is expected to happen here.
|
Restructure test framework to ease multiple languages (#799)
This change restructures the test framework code a bit, to make it
easier to introduce additional languages. Our knowledge of Yarn and
Node.js project structure, for instance, was previously baked in to
the test logic, in a way that was hard to make, for instance, Yarn
optional. (In Python, of course, it will not be used.) To better
support this, I've moved some state onto a new programTester struct
that we can use to lazily find binaries required during the testing
(such as Yarn, Pip, and so on). I'm committing this separately so
that I can minimize merge conflicts in the Python work.
2018-01-13 01:10:53 +00:00
|
|
|
if !pt.opts.Quick {
|
2018-06-14 23:01:28 +00:00
|
|
|
|
|
|
|
fprintf(pt.opts.Stdout, "Roundtripping checkpoint via stack export and stack import\n")
|
|
|
|
|
|
|
|
if err := pt.exportImport(dir); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2018-05-23 16:17:10 +00:00
|
|
|
msg := ""
|
|
|
|
if !pt.opts.AllowEmptyUpdateChanges {
|
|
|
|
msg = "(no changes expected)"
|
|
|
|
}
|
|
|
|
fprintf(pt.opts.Stdout, "Performing empty preview and update%s\n", msg)
|
|
|
|
if err := pt.previewAndUpdate(
|
|
|
|
dir, "empty", false, !pt.opts.AllowEmptyPreviewChanges, !pt.opts.AllowEmptyUpdateChanges); err != nil {
|
|
|
|
|
2018-01-06 00:39:13 +00:00
|
|
|
return err
|
2017-12-11 22:42:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Run additional validation provided by the test options, passing in the checkpoint info.
|
Restructure test framework to ease multiple languages (#799)
This change restructures the test framework code a bit, to make it
easier to introduce additional languages. Our knowledge of Yarn and
Node.js project structure, for instance, was previously baked in to
the test logic, in a way that was hard to make, for instance, Yarn
optional. (In Python, of course, it will not be used.) To better
support this, I've moved some state onto a new programTester struct
that we can use to lazily find binaries required during the testing
(such as Yarn, Pip, and so on). I'm committing this separately so
that I can minimize merge conflicts in the Python work.
2018-01-13 01:10:53 +00:00
|
|
|
if err := pt.performExtraRuntimeValidation(pt.opts.ExtraRuntimeValidation, dir); err != nil {
|
2018-01-06 00:39:13 +00:00
|
|
|
return err
|
2017-12-11 22:42:42 +00:00
|
|
|
}
|
|
|
|
|
2018-08-23 00:52:46 +00:00
|
|
|
// Perform a refresh and ensure it doesn't yield changes.
|
|
|
|
refresh := []string{"refresh", "--non-interactive", "--skip-preview"}
|
|
|
|
if pt.opts.GetDebugUpdates() {
|
|
|
|
refresh = append(refresh, "-d")
|
|
|
|
}
|
|
|
|
if !pt.opts.ExpectRefreshChanges {
|
|
|
|
refresh = append(refresh, "--expect-no-changes")
|
|
|
|
}
|
|
|
|
if err := pt.runPulumiCommand("pulumi-refresh", refresh, dir); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2017-12-11 22:42:42 +00:00
|
|
|
// If there are any edits, apply them and run a preview and update for each one.
|
Restructure test framework to ease multiple languages (#799)
This change restructures the test framework code a bit, to make it
easier to introduce additional languages. Our knowledge of Yarn and
Node.js project structure, for instance, was previously baked in to
the test logic, in a way that was hard to make, for instance, Yarn
optional. (In Python, of course, it will not be used.) To better
support this, I've moved some state onto a new programTester struct
that we can use to lazily find binaries required during the testing
(such as Yarn, Pip, and so on). I'm committing this separately so
that I can minimize merge conflicts in the Python work.
2018-01-13 01:10:53 +00:00
|
|
|
return pt.testEdits(dir)
|
2017-12-11 22:42:42 +00:00
|
|
|
}
|
|
|
|
|
2018-06-14 23:01:28 +00:00
|
|
|
func (pt *programTester) exportImport(dir string) error {
|
|
|
|
exportCmd := []string{"stack", "export", "--file", "stack.json"}
|
|
|
|
importCmd := []string{"stack", "import", "--file", "stack.json"}
|
|
|
|
|
|
|
|
defer func() {
|
|
|
|
contract.IgnoreError(os.Remove(filepath.Join(dir, "stack.json")))
|
|
|
|
}()
|
|
|
|
|
|
|
|
if err := pt.runPulumiCommand("pulumi-stack-export", exportCmd, dir); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return pt.runPulumiCommand("pulumi-stack-import", importCmd, dir)
|
|
|
|
}
|
|
|
|
|
2018-05-23 16:17:10 +00:00
|
|
|
func (pt *programTester) previewAndUpdate(dir string, name string, shouldFail, expectNopPreview,
|
|
|
|
expectNopUpdate bool) error {
|
|
|
|
|
2018-05-05 18:57:09 +00:00
|
|
|
preview := []string{"preview", "--non-interactive"}
|
2018-07-31 17:22:16 +00:00
|
|
|
update := []string{"up", "--non-interactive", "--skip-preview"}
|
Restructure test framework to ease multiple languages (#799)
This change restructures the test framework code a bit, to make it
easier to introduce additional languages. Our knowledge of Yarn and
Node.js project structure, for instance, was previously baked in to
the test logic, in a way that was hard to make, for instance, Yarn
optional. (In Python, of course, it will not be used.) To better
support this, I've moved some state onto a new programTester struct
that we can use to lazily find binaries required during the testing
(such as Yarn, Pip, and so on). I'm committing this separately so
that I can minimize merge conflicts in the Python work.
2018-01-13 01:10:53 +00:00
|
|
|
if pt.opts.GetDebugUpdates() {
|
2017-12-09 00:59:28 +00:00
|
|
|
preview = append(preview, "-d")
|
|
|
|
update = append(update, "-d")
|
2017-08-06 00:49:48 +00:00
|
|
|
}
|
2018-05-23 16:17:10 +00:00
|
|
|
if expectNopPreview {
|
2018-05-16 01:03:30 +00:00
|
|
|
preview = append(preview, "--expect-no-changes")
|
2018-05-23 16:17:10 +00:00
|
|
|
}
|
|
|
|
if expectNopUpdate {
|
2018-05-16 01:03:30 +00:00
|
|
|
update = append(update, "--expect-no-changes")
|
|
|
|
}
|
Restructure test framework to ease multiple languages (#799)
This change restructures the test framework code a bit, to make it
easier to introduce additional languages. Our knowledge of Yarn and
Node.js project structure, for instance, was previously baked in to
the test logic, in a way that was hard to make, for instance, Yarn
optional. (In Python, of course, it will not be used.) To better
support this, I've moved some state onto a new programTester struct
that we can use to lazily find binaries required during the testing
(such as Yarn, Pip, and so on). I'm committing this separately so
that I can minimize merge conflicts in the Python work.
2018-01-13 01:10:53 +00:00
|
|
|
if pt.opts.UpdateCommandlineFlags != nil {
|
|
|
|
update = append(update, pt.opts.UpdateCommandlineFlags...)
|
2017-12-20 19:17:25 +00:00
|
|
|
}
|
2017-08-06 00:49:48 +00:00
|
|
|
|
2018-08-23 00:52:46 +00:00
|
|
|
// If not in quick mode, run an explicit preview.
|
Restructure test framework to ease multiple languages (#799)
This change restructures the test framework code a bit, to make it
easier to introduce additional languages. Our knowledge of Yarn and
Node.js project structure, for instance, was previously baked in to
the test logic, in a way that was hard to make, for instance, Yarn
optional. (In Python, of course, it will not be used.) To better
support this, I've moved some state onto a new programTester struct
that we can use to lazily find binaries required during the testing
(such as Yarn, Pip, and so on). I'm committing this separately so
that I can minimize merge conflicts in the Python work.
2018-01-13 01:10:53 +00:00
|
|
|
if !pt.opts.Quick {
|
|
|
|
if err := pt.runPulumiCommand("pulumi-preview-"+name, preview, dir); err != nil {
|
2017-12-20 20:10:46 +00:00
|
|
|
if shouldFail {
|
2018-01-17 01:32:49 +00:00
|
|
|
fprintf(pt.opts.Stdout, "Permitting failure (ExpectFailure=true for this preview)\n")
|
2017-12-20 20:10:46 +00:00
|
|
|
return nil
|
|
|
|
}
|
2017-12-09 00:59:28 +00:00
|
|
|
return err
|
2017-11-16 16:15:56 +00:00
|
|
|
}
|
2017-11-06 17:04:38 +00:00
|
|
|
}
|
2017-08-06 00:49:48 +00:00
|
|
|
|
2018-08-23 00:52:46 +00:00
|
|
|
// Now run an update.
|
Restructure test framework to ease multiple languages (#799)
This change restructures the test framework code a bit, to make it
easier to introduce additional languages. Our knowledge of Yarn and
Node.js project structure, for instance, was previously baked in to
the test logic, in a way that was hard to make, for instance, Yarn
optional. (In Python, of course, it will not be used.) To better
support this, I've moved some state onto a new programTester struct
that we can use to lazily find binaries required during the testing
(such as Yarn, Pip, and so on). I'm committing this separately so
that I can minimize merge conflicts in the Python work.
2018-01-13 01:10:53 +00:00
|
|
|
if err := pt.runPulumiCommand("pulumi-update-"+name, update, dir); err != nil {
|
2017-12-20 20:10:46 +00:00
|
|
|
if shouldFail {
|
2018-01-17 01:32:49 +00:00
|
|
|
fprintf(pt.opts.Stdout, "Permitting failure (ExpectFailure=true for this update)\n")
|
2017-12-20 20:10:46 +00:00
|
|
|
return nil
|
|
|
|
}
|
2017-12-09 00:59:28 +00:00
|
|
|
return err
|
2017-12-08 00:29:48 +00:00
|
|
|
}
|
|
|
|
|
2017-12-20 20:10:46 +00:00
|
|
|
// If we expected a failure, but none occurred, return an error.
|
|
|
|
if shouldFail {
|
|
|
|
return errors.New("expected this step to fail, but it succeeded")
|
|
|
|
}
|
|
|
|
|
2017-12-09 00:59:28 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
Restructure test framework to ease multiple languages (#799)
This change restructures the test framework code a bit, to make it
easier to introduce additional languages. Our knowledge of Yarn and
Node.js project structure, for instance, was previously baked in to
the test logic, in a way that was hard to make, for instance, Yarn
optional. (In Python, of course, it will not be used.) To better
support this, I've moved some state onto a new programTester struct
that we can use to lazily find binaries required during the testing
(such as Yarn, Pip, and so on). I'm committing this separately so
that I can minimize merge conflicts in the Python work.
2018-01-13 01:10:53 +00:00
|
|
|
func (pt *programTester) testEdits(dir string) error {
|
|
|
|
for i, edit := range pt.opts.EditDirs {
|
2017-12-21 19:01:30 +00:00
|
|
|
var err error
|
Restructure test framework to ease multiple languages (#799)
This change restructures the test framework code a bit, to make it
easier to introduce additional languages. Our knowledge of Yarn and
Node.js project structure, for instance, was previously baked in to
the test logic, in a way that was hard to make, for instance, Yarn
optional. (In Python, of course, it will not be used.) To better
support this, I've moved some state onto a new programTester struct
that we can use to lazily find binaries required during the testing
(such as Yarn, Pip, and so on). I'm committing this separately so
that I can minimize merge conflicts in the Python work.
2018-01-13 01:10:53 +00:00
|
|
|
if err = pt.testEdit(dir, i, edit); err != nil {
|
2018-01-06 00:39:13 +00:00
|
|
|
return err
|
2017-12-20 20:10:46 +00:00
|
|
|
}
|
2017-12-11 23:48:45 +00:00
|
|
|
}
|
2018-01-06 00:39:13 +00:00
|
|
|
return nil
|
2017-12-11 23:48:45 +00:00
|
|
|
}
|
|
|
|
|
Restructure test framework to ease multiple languages (#799)
This change restructures the test framework code a bit, to make it
easier to introduce additional languages. Our knowledge of Yarn and
Node.js project structure, for instance, was previously baked in to
the test logic, in a way that was hard to make, for instance, Yarn
optional. (In Python, of course, it will not be used.) To better
support this, I've moved some state onto a new programTester struct
that we can use to lazily find binaries required during the testing
(such as Yarn, Pip, and so on). I'm committing this separately so
that I can minimize merge conflicts in the Python work.
2018-01-13 01:10:53 +00:00
|
|
|
func (pt *programTester) testEdit(dir string, i int, edit EditDir) error {
|
2018-01-17 01:32:49 +00:00
|
|
|
fprintf(pt.opts.Stdout, "Applying edit '%v' and rerunning preview and update\n", edit.Dir)
|
2017-12-11 23:48:45 +00:00
|
|
|
|
2018-01-10 00:47:17 +00:00
|
|
|
if edit.Additive {
|
|
|
|
// Just copy new files into dir
|
|
|
|
if err := fsutil.CopyFile(dir, edit.Dir, nil); err != nil {
|
|
|
|
return errors.Wrapf(err, "Couldn't copy %v into %v", edit.Dir, dir)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Create a new temporary directory
|
Restructure test framework to ease multiple languages (#799)
This change restructures the test framework code a bit, to make it
easier to introduce additional languages. Our knowledge of Yarn and
Node.js project structure, for instance, was previously baked in to
the test logic, in a way that was hard to make, for instance, Yarn
optional. (In Python, of course, it will not be used.) To better
support this, I've moved some state onto a new programTester struct
that we can use to lazily find binaries required during the testing
(such as Yarn, Pip, and so on). I'm committing this separately so
that I can minimize merge conflicts in the Python work.
2018-01-13 01:10:53 +00:00
|
|
|
newDir, err := ioutil.TempDir("", pt.opts.StackName+"-")
|
2018-01-10 00:47:17 +00:00
|
|
|
if err != nil {
|
|
|
|
return errors.Wrapf(err, "Couldn't create new temporary directory")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Delete whichever copy of the test is unused when we return
|
|
|
|
dirToDelete := newDir
|
|
|
|
defer func() {
|
|
|
|
contract.IgnoreError(os.RemoveAll(dirToDelete))
|
|
|
|
}()
|
|
|
|
|
2018-03-06 23:57:57 +00:00
|
|
|
// Copy everything except Pulumi.yaml, Pulumi.<stack-name>.yaml, and .pulumi from source into new directory
|
2018-01-10 00:47:17 +00:00
|
|
|
exclusions := make(map[string]bool)
|
|
|
|
projectYaml := workspace.ProjectFile + ".yaml"
|
2018-03-06 23:57:57 +00:00
|
|
|
configYaml := workspace.ProjectFile + "." + pt.opts.StackName + ".yaml"
|
2018-01-10 00:47:17 +00:00
|
|
|
exclusions[workspace.BookkeepingDir] = true
|
|
|
|
exclusions[projectYaml] = true
|
2018-03-06 23:57:57 +00:00
|
|
|
exclusions[configYaml] = true
|
2018-01-10 00:47:17 +00:00
|
|
|
|
|
|
|
if err := fsutil.CopyFile(newDir, edit.Dir, exclusions); err != nil {
|
|
|
|
return errors.Wrapf(err, "Couldn't copy %v into %v", edit.Dir, newDir)
|
|
|
|
}
|
|
|
|
|
2018-03-06 23:57:57 +00:00
|
|
|
// Copy Pulumi.yaml, Pulumi.<stack-name>.yaml, and .pulumi from old directory to new directory
|
2018-01-10 00:47:17 +00:00
|
|
|
oldProjectYaml := filepath.Join(dir, projectYaml)
|
|
|
|
newProjectYaml := filepath.Join(newDir, projectYaml)
|
|
|
|
|
2018-03-06 23:57:57 +00:00
|
|
|
oldConfigYaml := filepath.Join(dir, configYaml)
|
|
|
|
newConfigYaml := filepath.Join(newDir, configYaml)
|
|
|
|
|
2018-01-10 00:47:17 +00:00
|
|
|
oldProjectDir := filepath.Join(dir, workspace.BookkeepingDir)
|
|
|
|
newProjectDir := filepath.Join(newDir, workspace.BookkeepingDir)
|
|
|
|
|
|
|
|
if err := fsutil.CopyFile(newProjectYaml, oldProjectYaml, nil); err != nil {
|
2018-03-06 23:57:57 +00:00
|
|
|
return errors.Wrap(err, "Couldn't copy Pulumi.yaml")
|
|
|
|
}
|
|
|
|
if err := fsutil.CopyFile(newConfigYaml, oldConfigYaml, nil); err != nil {
|
|
|
|
return errors.Wrapf(err, "Couldn't copy Pulumi.%s.yaml", pt.opts.StackName)
|
2018-01-10 00:47:17 +00:00
|
|
|
}
|
|
|
|
if err := fsutil.CopyFile(newProjectDir, oldProjectDir, nil); err != nil {
|
2018-03-06 23:57:57 +00:00
|
|
|
return errors.Wrap(err, "Couldn't copy .pulumi")
|
2018-01-10 00:47:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Finally, replace our current temp directory with the new one.
|
|
|
|
dirOld := dir + ".old"
|
|
|
|
if err := os.Rename(dir, dirOld); err != nil {
|
|
|
|
return errors.Wrapf(err, "Couldn't rename %v to %v", dir, dirOld)
|
|
|
|
}
|
|
|
|
|
|
|
|
// There's a brief window here where the old temp dir name could be taken from us.
|
|
|
|
|
|
|
|
if err := os.Rename(newDir, dir); err != nil {
|
|
|
|
return errors.Wrapf(err, "Couldn't rename %v to %v", newDir, dir)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Keep dir, delete oldDir
|
|
|
|
dirToDelete = dirOld
|
|
|
|
}
|
|
|
|
|
2018-06-11 20:22:24 +00:00
|
|
|
err := pt.prepareProjectDir(dir)
|
2017-12-20 20:10:46 +00:00
|
|
|
if err != nil {
|
2018-01-10 00:47:17 +00:00
|
|
|
return errors.Wrapf(err, "Couldn't prepare project in %v", dir)
|
2017-12-11 23:48:45 +00:00
|
|
|
}
|
2017-12-15 01:10:05 +00:00
|
|
|
|
Restructure test framework to ease multiple languages (#799)
This change restructures the test framework code a bit, to make it
easier to introduce additional languages. Our knowledge of Yarn and
Node.js project structure, for instance, was previously baked in to
the test logic, in a way that was hard to make, for instance, Yarn
optional. (In Python, of course, it will not be used.) To better
support this, I've moved some state onto a new programTester struct
that we can use to lazily find binaries required during the testing
(such as Yarn, Pip, and so on). I'm committing this separately so
that I can minimize merge conflicts in the Python work.
2018-01-13 01:10:53 +00:00
|
|
|
oldStdOut := pt.opts.Stdout
|
|
|
|
oldStderr := pt.opts.Stderr
|
|
|
|
oldVerbose := pt.opts.Verbose
|
2017-12-15 01:10:05 +00:00
|
|
|
if edit.Stdout != nil {
|
Restructure test framework to ease multiple languages (#799)
This change restructures the test framework code a bit, to make it
easier to introduce additional languages. Our knowledge of Yarn and
Node.js project structure, for instance, was previously baked in to
the test logic, in a way that was hard to make, for instance, Yarn
optional. (In Python, of course, it will not be used.) To better
support this, I've moved some state onto a new programTester struct
that we can use to lazily find binaries required during the testing
(such as Yarn, Pip, and so on). I'm committing this separately so
that I can minimize merge conflicts in the Python work.
2018-01-13 01:10:53 +00:00
|
|
|
pt.opts.Stdout = edit.Stdout
|
2017-12-15 01:10:05 +00:00
|
|
|
}
|
|
|
|
if edit.Stderr != nil {
|
Restructure test framework to ease multiple languages (#799)
This change restructures the test framework code a bit, to make it
easier to introduce additional languages. Our knowledge of Yarn and
Node.js project structure, for instance, was previously baked in to
the test logic, in a way that was hard to make, for instance, Yarn
optional. (In Python, of course, it will not be used.) To better
support this, I've moved some state onto a new programTester struct
that we can use to lazily find binaries required during the testing
(such as Yarn, Pip, and so on). I'm committing this separately so
that I can minimize merge conflicts in the Python work.
2018-01-13 01:10:53 +00:00
|
|
|
pt.opts.Stderr = edit.Stderr
|
2017-12-15 01:10:05 +00:00
|
|
|
}
|
|
|
|
if edit.Verbose {
|
Restructure test framework to ease multiple languages (#799)
This change restructures the test framework code a bit, to make it
easier to introduce additional languages. Our knowledge of Yarn and
Node.js project structure, for instance, was previously baked in to
the test logic, in a way that was hard to make, for instance, Yarn
optional. (In Python, of course, it will not be used.) To better
support this, I've moved some state onto a new programTester struct
that we can use to lazily find binaries required during the testing
(such as Yarn, Pip, and so on). I'm committing this separately so
that I can minimize merge conflicts in the Python work.
2018-01-13 01:10:53 +00:00
|
|
|
pt.opts.Verbose = true
|
2017-12-15 01:10:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
defer func() {
|
Restructure test framework to ease multiple languages (#799)
This change restructures the test framework code a bit, to make it
easier to introduce additional languages. Our knowledge of Yarn and
Node.js project structure, for instance, was previously baked in to
the test logic, in a way that was hard to make, for instance, Yarn
optional. (In Python, of course, it will not be used.) To better
support this, I've moved some state onto a new programTester struct
that we can use to lazily find binaries required during the testing
(such as Yarn, Pip, and so on). I'm committing this separately so
that I can minimize merge conflicts in the Python work.
2018-01-13 01:10:53 +00:00
|
|
|
pt.opts.Stdout = oldStdOut
|
|
|
|
pt.opts.Stderr = oldStderr
|
|
|
|
pt.opts.Verbose = oldVerbose
|
2017-12-15 01:10:05 +00:00
|
|
|
}()
|
|
|
|
|
2018-05-23 16:17:10 +00:00
|
|
|
if err = pt.previewAndUpdate(dir, fmt.Sprintf("edit-%d", i), edit.ExpectFailure, false, false); err != nil {
|
2018-01-06 00:39:13 +00:00
|
|
|
return err
|
2017-12-11 23:48:45 +00:00
|
|
|
}
|
2018-01-25 02:22:41 +00:00
|
|
|
return pt.performExtraRuntimeValidation(edit.ExtraRuntimeValidation, dir)
|
2017-09-25 21:03:16 +00:00
|
|
|
}
|
|
|
|
|
Restructure test framework to ease multiple languages (#799)
This change restructures the test framework code a bit, to make it
easier to introduce additional languages. Our knowledge of Yarn and
Node.js project structure, for instance, was previously baked in to
the test logic, in a way that was hard to make, for instance, Yarn
optional. (In Python, of course, it will not be used.) To better
support this, I've moved some state onto a new programTester struct
that we can use to lazily find binaries required during the testing
(such as Yarn, Pip, and so on). I'm committing this separately so
that I can minimize merge conflicts in the Python work.
2018-01-13 01:10:53 +00:00
|
|
|
func (pt *programTester) performExtraRuntimeValidation(
|
2017-12-14 00:09:14 +00:00
|
|
|
extraRuntimeValidation func(t *testing.T, stack RuntimeValidationStackInfo), dir string) error {
|
2017-12-09 00:59:28 +00:00
|
|
|
|
|
|
|
if extraRuntimeValidation == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
Restructure test framework to ease multiple languages (#799)
This change restructures the test framework code a bit, to make it
easier to introduce additional languages. Our knowledge of Yarn and
Node.js project structure, for instance, was previously baked in to
the test logic, in a way that was hard to make, for instance, Yarn
optional. (In Python, of course, it will not be used.) To better
support this, I've moved some state onto a new programTester struct
that we can use to lazily find binaries required during the testing
(such as Yarn, Pip, and so on). I'm committing this separately so
that I can minimize merge conflicts in the Python work.
2018-01-13 01:10:53 +00:00
|
|
|
stackName := pt.opts.GetStackName()
|
2017-12-09 00:59:28 +00:00
|
|
|
|
2018-04-03 04:34:54 +00:00
|
|
|
// Create a temporary file name for the stack export
|
|
|
|
tempDir, err := ioutil.TempDir("", string(stackName))
|
2017-12-20 20:10:46 +00:00
|
|
|
if err != nil {
|
2018-04-03 04:34:54 +00:00
|
|
|
return err
|
2017-10-26 23:01:28 +00:00
|
|
|
}
|
2018-04-03 04:34:54 +00:00
|
|
|
fileName := path.Join(tempDir, "stack.json")
|
|
|
|
|
|
|
|
// Invoke `pulumi stack export`
|
|
|
|
if err = pt.runPulumiCommand("pulumi-export", []string{"stack", "export", "--file", fileName}, dir); err != nil {
|
|
|
|
return errors.Wrapf(err, "expected to export stack to file: %s", fileName)
|
2017-10-26 23:01:28 +00:00
|
|
|
}
|
2017-12-14 00:09:14 +00:00
|
|
|
|
2018-04-03 04:34:54 +00:00
|
|
|
// Open the exported JSON file
|
|
|
|
f, err := os.Open(fileName)
|
2017-12-20 20:10:46 +00:00
|
|
|
if err != nil {
|
2018-04-03 04:34:54 +00:00
|
|
|
return errors.Wrapf(err, "expected to be able to open file with stack exports: %s", fileName)
|
2017-12-14 00:09:14 +00:00
|
|
|
}
|
2018-04-03 04:34:54 +00:00
|
|
|
defer func() {
|
|
|
|
contract.IgnoreClose(f)
|
|
|
|
contract.IgnoreError(os.RemoveAll(tempDir))
|
|
|
|
}()
|
2017-12-14 00:09:14 +00:00
|
|
|
|
2018-04-03 04:34:54 +00:00
|
|
|
// Unmarshal the Deployment
|
|
|
|
var untypedDeployment apitype.UntypedDeployment
|
|
|
|
if err = json.NewDecoder(f).Decode(&untypedDeployment); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2018-07-20 20:31:41 +00:00
|
|
|
var deployment apitype.DeploymentV2
|
2018-04-03 04:34:54 +00:00
|
|
|
if err = json.Unmarshal(untypedDeployment.Deployment, &deployment); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the root resource and outputs from the deployment
|
2018-07-20 20:31:41 +00:00
|
|
|
var rootResource apitype.ResourceV2
|
2018-04-03 04:34:54 +00:00
|
|
|
var outputs map[string]interface{}
|
|
|
|
for _, res := range deployment.Resources {
|
|
|
|
if res.Type == resource.RootStackType {
|
|
|
|
rootResource = res
|
|
|
|
outputs = res.Outputs
|
|
|
|
}
|
2017-12-14 00:09:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Populate stack info object with all of this data to pass to the validation function
|
|
|
|
stackInfo := RuntimeValidationStackInfo{
|
2018-04-12 20:50:07 +00:00
|
|
|
StackName: pt.opts.GetStackName(),
|
2018-04-03 04:34:54 +00:00
|
|
|
Deployment: &deployment,
|
|
|
|
RootResource: rootResource,
|
2017-12-14 00:09:14 +00:00
|
|
|
Outputs: outputs,
|
|
|
|
}
|
Restructure test framework to ease multiple languages (#799)
This change restructures the test framework code a bit, to make it
easier to introduce additional languages. Our knowledge of Yarn and
Node.js project structure, for instance, was previously baked in to
the test logic, in a way that was hard to make, for instance, Yarn
optional. (In Python, of course, it will not be used.) To better
support this, I've moved some state onto a new programTester struct
that we can use to lazily find binaries required during the testing
(such as Yarn, Pip, and so on). I'm committing this separately so
that I can minimize merge conflicts in the Python work.
2018-01-13 01:10:53 +00:00
|
|
|
extraRuntimeValidation(pt.t, stackInfo)
|
2017-10-26 23:01:28 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
Restructure test framework to ease multiple languages (#799)
This change restructures the test framework code a bit, to make it
easier to introduce additional languages. Our knowledge of Yarn and
Node.js project structure, for instance, was previously baked in to
the test logic, in a way that was hard to make, for instance, Yarn
optional. (In Python, of course, it will not be used.) To better
support this, I've moved some state onto a new programTester struct
that we can use to lazily find binaries required during the testing
(such as Yarn, Pip, and so on). I'm committing this separately so
that I can minimize merge conflicts in the Python work.
2018-01-13 01:10:53 +00:00
|
|
|
// copyTestToTemporaryDirectory creates a temporary directory to run the test in and copies the test to it.
|
2018-06-11 20:22:24 +00:00
|
|
|
func (pt *programTester) copyTestToTemporaryDirectory() (string, string, error) {
|
|
|
|
// Get the source dir and project info.
|
|
|
|
sourceDir := pt.opts.Dir
|
|
|
|
projinfo, err := pt.getProjinfo(sourceDir)
|
|
|
|
if err != nil {
|
|
|
|
return "", "", err
|
|
|
|
}
|
|
|
|
|
2017-09-25 21:03:16 +00:00
|
|
|
// Set up a prefix so that all output has the test directory name in it. This is important for debugging
|
|
|
|
// because we run tests in parallel, and so all output will be interleaved and difficult to follow otherwise.
|
2017-11-16 15:49:07 +00:00
|
|
|
var prefix string
|
2018-01-10 00:45:40 +00:00
|
|
|
if len(sourceDir) <= 30 {
|
2018-01-06 00:39:13 +00:00
|
|
|
prefix = fmt.Sprintf("[ %30.30s ] ", sourceDir)
|
2017-11-16 15:49:07 +00:00
|
|
|
} else {
|
2018-01-06 00:39:13 +00:00
|
|
|
prefix = fmt.Sprintf("[ %30.30s ] ", sourceDir[len(sourceDir)-30:])
|
2017-11-16 15:49:07 +00:00
|
|
|
}
|
Restructure test framework to ease multiple languages (#799)
This change restructures the test framework code a bit, to make it
easier to introduce additional languages. Our knowledge of Yarn and
Node.js project structure, for instance, was previously baked in to
the test logic, in a way that was hard to make, for instance, Yarn
optional. (In Python, of course, it will not be used.) To better
support this, I've moved some state onto a new programTester struct
that we can use to lazily find binaries required during the testing
(such as Yarn, Pip, and so on). I'm committing this separately so
that I can minimize merge conflicts in the Python work.
2018-01-13 01:10:53 +00:00
|
|
|
stdout := pt.opts.Stdout
|
2017-09-25 21:03:16 +00:00
|
|
|
if stdout == nil {
|
|
|
|
stdout = newPrefixer(os.Stdout, prefix)
|
Restructure test framework to ease multiple languages (#799)
This change restructures the test framework code a bit, to make it
easier to introduce additional languages. Our knowledge of Yarn and
Node.js project structure, for instance, was previously baked in to
the test logic, in a way that was hard to make, for instance, Yarn
optional. (In Python, of course, it will not be used.) To better
support this, I've moved some state onto a new programTester struct
that we can use to lazily find binaries required during the testing
(such as Yarn, Pip, and so on). I'm committing this separately so
that I can minimize merge conflicts in the Python work.
2018-01-13 01:10:53 +00:00
|
|
|
pt.opts.Stdout = stdout
|
2017-09-25 21:03:16 +00:00
|
|
|
}
|
Restructure test framework to ease multiple languages (#799)
This change restructures the test framework code a bit, to make it
easier to introduce additional languages. Our knowledge of Yarn and
Node.js project structure, for instance, was previously baked in to
the test logic, in a way that was hard to make, for instance, Yarn
optional. (In Python, of course, it will not be used.) To better
support this, I've moved some state onto a new programTester struct
that we can use to lazily find binaries required during the testing
(such as Yarn, Pip, and so on). I'm committing this separately so
that I can minimize merge conflicts in the Python work.
2018-01-13 01:10:53 +00:00
|
|
|
stderr := pt.opts.Stderr
|
2017-09-25 21:03:16 +00:00
|
|
|
if stderr == nil {
|
|
|
|
stderr = newPrefixer(os.Stderr, prefix)
|
Restructure test framework to ease multiple languages (#799)
This change restructures the test framework code a bit, to make it
easier to introduce additional languages. Our knowledge of Yarn and
Node.js project structure, for instance, was previously baked in to
the test logic, in a way that was hard to make, for instance, Yarn
optional. (In Python, of course, it will not be used.) To better
support this, I've moved some state onto a new programTester struct
that we can use to lazily find binaries required during the testing
(such as Yarn, Pip, and so on). I'm committing this separately so
that I can minimize merge conflicts in the Python work.
2018-01-13 01:10:53 +00:00
|
|
|
pt.opts.Stderr = stderr
|
2017-09-25 21:03:16 +00:00
|
|
|
}
|
|
|
|
|
2018-01-17 01:32:49 +00:00
|
|
|
fprintf(pt.opts.Stdout, "sample: %v\n", sourceDir)
|
Restructure test framework to ease multiple languages (#799)
This change restructures the test framework code a bit, to make it
easier to introduce additional languages. Our knowledge of Yarn and
Node.js project structure, for instance, was previously baked in to
the test logic, in a way that was hard to make, for instance, Yarn
optional. (In Python, of course, it will not be used.) To better
support this, I've moved some state onto a new programTester struct
that we can use to lazily find binaries required during the testing
(such as Yarn, Pip, and so on). I'm committing this separately so
that I can minimize merge conflicts in the Python work.
2018-01-13 01:10:53 +00:00
|
|
|
bin, err := pt.getBin()
|
|
|
|
if err != nil {
|
2018-06-11 20:22:24 +00:00
|
|
|
return "", "", err
|
Restructure test framework to ease multiple languages (#799)
This change restructures the test framework code a bit, to make it
easier to introduce additional languages. Our knowledge of Yarn and
Node.js project structure, for instance, was previously baked in to
the test logic, in a way that was hard to make, for instance, Yarn
optional. (In Python, of course, it will not be used.) To better
support this, I've moved some state onto a new programTester struct
that we can use to lazily find binaries required during the testing
(such as Yarn, Pip, and so on). I'm committing this separately so
that I can minimize merge conflicts in the Python work.
2018-01-13 01:10:53 +00:00
|
|
|
}
|
2018-01-17 01:32:49 +00:00
|
|
|
fprintf(pt.opts.Stdout, "pulumi: %v\n", bin)
|
2017-09-25 21:03:16 +00:00
|
|
|
|
2018-06-11 20:22:24 +00:00
|
|
|
// For most projects, we will copy to a temporary directory. For Go projects, however, we must not perturb
|
|
|
|
// the source layout, due to GOPATH and vendoring. So, skip it for Go.
|
|
|
|
var tmpdir, projdir string
|
2018-06-25 05:47:54 +00:00
|
|
|
if projinfo.Proj.RuntimeInfo.Name() == "go" {
|
2018-06-11 20:22:24 +00:00
|
|
|
projdir = projinfo.Root
|
|
|
|
} else {
|
|
|
|
stackName := string(pt.opts.GetStackName())
|
|
|
|
targetDir, tempErr := ioutil.TempDir("", stackName+"-")
|
|
|
|
if tempErr != nil {
|
|
|
|
return "", "", errors.Wrap(tempErr, "Couldn't create temporary directory")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Copy the source project.
|
|
|
|
if copyErr := fsutil.CopyFile(targetDir, sourceDir, nil); copyErr != nil {
|
|
|
|
return "", "", copyErr
|
|
|
|
}
|
2018-01-06 00:39:13 +00:00
|
|
|
|
2018-06-11 20:22:24 +00:00
|
|
|
// Set tmpdir so that the caller will clean up afterwards.
|
|
|
|
tmpdir = targetDir
|
|
|
|
projdir = targetDir
|
2018-01-10 00:47:17 +00:00
|
|
|
}
|
2018-06-11 20:22:24 +00:00
|
|
|
projinfo.Root = projdir
|
2018-01-10 00:47:17 +00:00
|
|
|
|
2018-06-11 20:22:24 +00:00
|
|
|
err = pt.prepareProject(projinfo)
|
2017-12-20 20:10:46 +00:00
|
|
|
if err != nil {
|
2018-06-11 20:22:24 +00:00
|
|
|
return "", "", errors.Wrapf(err, "Failed to prepare %v", projdir)
|
2017-09-25 21:03:16 +00:00
|
|
|
}
|
2017-12-11 22:42:42 +00:00
|
|
|
|
2018-06-11 20:22:24 +00:00
|
|
|
fprintf(stdout, "projdir: %v\n", projdir)
|
|
|
|
return tmpdir, projdir, nil
|
2017-07-13 19:19:17 +00:00
|
|
|
}
|
|
|
|
|
2018-06-11 20:22:24 +00:00
|
|
|
func (pt *programTester) getProjinfo(projectDir string) (*engine.Projinfo, error) {
|
Get the empty Python program working
This change gets enough of the Python SDK up and running that the
empty Python program will work. Mostly just scaffolding, but the
basic structure is now in place. The primary remaining work is to
wire up resource creation to the gRPC interfaces.
In summary:
* The basic structure is as follows:
- Everything goes into sdk/python/.
- sdk/python/cmd/pulumi-langhost-python is a Go language host
that simply knows how to spawn Python processes to run out
entrypoint in response to requests by the engine.
- sdk/python/cmd/pulumi-langhost-python-exec is a little Python
shim that is invoked by the language host to run Python programs,
and is responsible for setting up the minimal goo before we can
do so (RPC connections and the like).
- sdk/python/lib/ contains a Python Pip package suitable for PyPi.
- In there, we have two packages: the root pulumi package that
contains all of the basic Pulumi programming model abstractions,
and pulumi.runtime, which contains the implementation of
resource registration, RPC interfacing with the engine, and so on.
* Add logic in our test framework to conditionalize on the language
type and react accordingly. This will allow us to skip Yarn for
Python projects and eventually run Pip if there's a requirements.txt.
* Created the basic project structure, including all of the usual
Make targets for installing into the proper places.
* Building also runs Pylint and we are clean.
There are a few other minor things in here:
* Add an "empty" test for both Node.js and Python. These pass.
* Fix an existing bug in plugin shutdown logic. At some point, we
started waiting for stderr/stdout to flush before shutting down
the plugin; but if certain failures happen "early" during the
plugin launch process, these channels will never get initialized
and so waiting for them deadlocks.
* Recently we seem to have added logic to delete test temp
directories if a failure happened during initialization of said
temp directories. This is unfortunate, because you often need to
look at the temp directory to see what failed. We already clean
them up elsewhere after the full test completes successfully, so
I don't think we need to be doing this, and I've removed it.
Still many loose ends (config, resources, etc), but it's a start!
2018-01-13 18:29:34 +00:00
|
|
|
// Load up the package so we know things like what language the project is.
|
|
|
|
projfile := filepath.Join(projectDir, workspace.ProjectFile+".yaml")
|
|
|
|
proj, err := workspace.LoadProject(projfile)
|
|
|
|
if err != nil {
|
2018-06-11 20:22:24 +00:00
|
|
|
return nil, err
|
Get the empty Python program working
This change gets enough of the Python SDK up and running that the
empty Python program will work. Mostly just scaffolding, but the
basic structure is now in place. The primary remaining work is to
wire up resource creation to the gRPC interfaces.
In summary:
* The basic structure is as follows:
- Everything goes into sdk/python/.
- sdk/python/cmd/pulumi-langhost-python is a Go language host
that simply knows how to spawn Python processes to run out
entrypoint in response to requests by the engine.
- sdk/python/cmd/pulumi-langhost-python-exec is a little Python
shim that is invoked by the language host to run Python programs,
and is responsible for setting up the minimal goo before we can
do so (RPC connections and the like).
- sdk/python/lib/ contains a Python Pip package suitable for PyPi.
- In there, we have two packages: the root pulumi package that
contains all of the basic Pulumi programming model abstractions,
and pulumi.runtime, which contains the implementation of
resource registration, RPC interfacing with the engine, and so on.
* Add logic in our test framework to conditionalize on the language
type and react accordingly. This will allow us to skip Yarn for
Python projects and eventually run Pip if there's a requirements.txt.
* Created the basic project structure, including all of the usual
Make targets for installing into the proper places.
* Building also runs Pylint and we are clean.
There are a few other minor things in here:
* Add an "empty" test for both Node.js and Python. These pass.
* Fix an existing bug in plugin shutdown logic. At some point, we
started waiting for stderr/stdout to flush before shutting down
the plugin; but if certain failures happen "early" during the
plugin launch process, these channels will never get initialized
and so waiting for them deadlocks.
* Recently we seem to have added logic to delete test temp
directories if a failure happened during initialization of said
temp directories. This is unfortunate, because you often need to
look at the temp directory to see what failed. We already clean
them up elsewhere after the full test completes successfully, so
I don't think we need to be doing this, and I've removed it.
Still many loose ends (config, resources, etc), but it's a start!
2018-01-13 18:29:34 +00:00
|
|
|
}
|
2018-06-11 20:22:24 +00:00
|
|
|
return &engine.Projinfo{Proj: proj, Root: projectDir}, nil
|
|
|
|
}
|
Get the empty Python program working
This change gets enough of the Python SDK up and running that the
empty Python program will work. Mostly just scaffolding, but the
basic structure is now in place. The primary remaining work is to
wire up resource creation to the gRPC interfaces.
In summary:
* The basic structure is as follows:
- Everything goes into sdk/python/.
- sdk/python/cmd/pulumi-langhost-python is a Go language host
that simply knows how to spawn Python processes to run out
entrypoint in response to requests by the engine.
- sdk/python/cmd/pulumi-langhost-python-exec is a little Python
shim that is invoked by the language host to run Python programs,
and is responsible for setting up the minimal goo before we can
do so (RPC connections and the like).
- sdk/python/lib/ contains a Python Pip package suitable for PyPi.
- In there, we have two packages: the root pulumi package that
contains all of the basic Pulumi programming model abstractions,
and pulumi.runtime, which contains the implementation of
resource registration, RPC interfacing with the engine, and so on.
* Add logic in our test framework to conditionalize on the language
type and react accordingly. This will allow us to skip Yarn for
Python projects and eventually run Pip if there's a requirements.txt.
* Created the basic project structure, including all of the usual
Make targets for installing into the proper places.
* Building also runs Pylint and we are clean.
There are a few other minor things in here:
* Add an "empty" test for both Node.js and Python. These pass.
* Fix an existing bug in plugin shutdown logic. At some point, we
started waiting for stderr/stdout to flush before shutting down
the plugin; but if certain failures happen "early" during the
plugin launch process, these channels will never get initialized
and so waiting for them deadlocks.
* Recently we seem to have added logic to delete test temp
directories if a failure happened during initialization of said
temp directories. This is unfortunate, because you often need to
look at the temp directory to see what failed. We already clean
them up elsewhere after the full test completes successfully, so
I don't think we need to be doing this, and I've removed it.
Still many loose ends (config, resources, etc), but it's a start!
2018-01-13 18:29:34 +00:00
|
|
|
|
2018-06-11 20:22:24 +00:00
|
|
|
// prepareProject runs setup necessary to get the project ready for `pulumi` commands.
|
|
|
|
func (pt *programTester) prepareProject(projinfo *engine.Projinfo) error {
|
Get the empty Python program working
This change gets enough of the Python SDK up and running that the
empty Python program will work. Mostly just scaffolding, but the
basic structure is now in place. The primary remaining work is to
wire up resource creation to the gRPC interfaces.
In summary:
* The basic structure is as follows:
- Everything goes into sdk/python/.
- sdk/python/cmd/pulumi-langhost-python is a Go language host
that simply knows how to spawn Python processes to run out
entrypoint in response to requests by the engine.
- sdk/python/cmd/pulumi-langhost-python-exec is a little Python
shim that is invoked by the language host to run Python programs,
and is responsible for setting up the minimal goo before we can
do so (RPC connections and the like).
- sdk/python/lib/ contains a Python Pip package suitable for PyPi.
- In there, we have two packages: the root pulumi package that
contains all of the basic Pulumi programming model abstractions,
and pulumi.runtime, which contains the implementation of
resource registration, RPC interfacing with the engine, and so on.
* Add logic in our test framework to conditionalize on the language
type and react accordingly. This will allow us to skip Yarn for
Python projects and eventually run Pip if there's a requirements.txt.
* Created the basic project structure, including all of the usual
Make targets for installing into the proper places.
* Building also runs Pylint and we are clean.
There are a few other minor things in here:
* Add an "empty" test for both Node.js and Python. These pass.
* Fix an existing bug in plugin shutdown logic. At some point, we
started waiting for stderr/stdout to flush before shutting down
the plugin; but if certain failures happen "early" during the
plugin launch process, these channels will never get initialized
and so waiting for them deadlocks.
* Recently we seem to have added logic to delete test temp
directories if a failure happened during initialization of said
temp directories. This is unfortunate, because you often need to
look at the temp directory to see what failed. We already clean
them up elsewhere after the full test completes successfully, so
I don't think we need to be doing this, and I've removed it.
Still many loose ends (config, resources, etc), but it's a start!
2018-01-13 18:29:34 +00:00
|
|
|
// Based on the language, invoke the right routine to prepare the target directory.
|
2018-06-25 05:47:54 +00:00
|
|
|
switch rt := projinfo.Proj.RuntimeInfo.Name(); rt {
|
Get the empty Python program working
This change gets enough of the Python SDK up and running that the
empty Python program will work. Mostly just scaffolding, but the
basic structure is now in place. The primary remaining work is to
wire up resource creation to the gRPC interfaces.
In summary:
* The basic structure is as follows:
- Everything goes into sdk/python/.
- sdk/python/cmd/pulumi-langhost-python is a Go language host
that simply knows how to spawn Python processes to run out
entrypoint in response to requests by the engine.
- sdk/python/cmd/pulumi-langhost-python-exec is a little Python
shim that is invoked by the language host to run Python programs,
and is responsible for setting up the minimal goo before we can
do so (RPC connections and the like).
- sdk/python/lib/ contains a Python Pip package suitable for PyPi.
- In there, we have two packages: the root pulumi package that
contains all of the basic Pulumi programming model abstractions,
and pulumi.runtime, which contains the implementation of
resource registration, RPC interfacing with the engine, and so on.
* Add logic in our test framework to conditionalize on the language
type and react accordingly. This will allow us to skip Yarn for
Python projects and eventually run Pip if there's a requirements.txt.
* Created the basic project structure, including all of the usual
Make targets for installing into the proper places.
* Building also runs Pylint and we are clean.
There are a few other minor things in here:
* Add an "empty" test for both Node.js and Python. These pass.
* Fix an existing bug in plugin shutdown logic. At some point, we
started waiting for stderr/stdout to flush before shutting down
the plugin; but if certain failures happen "early" during the
plugin launch process, these channels will never get initialized
and so waiting for them deadlocks.
* Recently we seem to have added logic to delete test temp
directories if a failure happened during initialization of said
temp directories. This is unfortunate, because you often need to
look at the temp directory to see what failed. We already clean
them up elsewhere after the full test completes successfully, so
I don't think we need to be doing this, and I've removed it.
Still many loose ends (config, resources, etc), but it's a start!
2018-01-13 18:29:34 +00:00
|
|
|
case "nodejs":
|
|
|
|
return pt.prepareNodeJSProject(projinfo)
|
|
|
|
case "python":
|
|
|
|
return pt.preparePythonProject(projinfo)
|
2018-06-10 16:17:19 +00:00
|
|
|
case "go":
|
|
|
|
return pt.prepareGoProject(projinfo)
|
Get the empty Python program working
This change gets enough of the Python SDK up and running that the
empty Python program will work. Mostly just scaffolding, but the
basic structure is now in place. The primary remaining work is to
wire up resource creation to the gRPC interfaces.
In summary:
* The basic structure is as follows:
- Everything goes into sdk/python/.
- sdk/python/cmd/pulumi-langhost-python is a Go language host
that simply knows how to spawn Python processes to run out
entrypoint in response to requests by the engine.
- sdk/python/cmd/pulumi-langhost-python-exec is a little Python
shim that is invoked by the language host to run Python programs,
and is responsible for setting up the minimal goo before we can
do so (RPC connections and the like).
- sdk/python/lib/ contains a Python Pip package suitable for PyPi.
- In there, we have two packages: the root pulumi package that
contains all of the basic Pulumi programming model abstractions,
and pulumi.runtime, which contains the implementation of
resource registration, RPC interfacing with the engine, and so on.
* Add logic in our test framework to conditionalize on the language
type and react accordingly. This will allow us to skip Yarn for
Python projects and eventually run Pip if there's a requirements.txt.
* Created the basic project structure, including all of the usual
Make targets for installing into the proper places.
* Building also runs Pylint and we are clean.
There are a few other minor things in here:
* Add an "empty" test for both Node.js and Python. These pass.
* Fix an existing bug in plugin shutdown logic. At some point, we
started waiting for stderr/stdout to flush before shutting down
the plugin; but if certain failures happen "early" during the
plugin launch process, these channels will never get initialized
and so waiting for them deadlocks.
* Recently we seem to have added logic to delete test temp
directories if a failure happened during initialization of said
temp directories. This is unfortunate, because you often need to
look at the temp directory to see what failed. We already clean
them up elsewhere after the full test completes successfully, so
I don't think we need to be doing this, and I've removed it.
Still many loose ends (config, resources, etc), but it's a start!
2018-01-13 18:29:34 +00:00
|
|
|
default:
|
2018-06-11 20:22:24 +00:00
|
|
|
return errors.Errorf("unrecognized project runtime: %s", rt)
|
Get the empty Python program working
This change gets enough of the Python SDK up and running that the
empty Python program will work. Mostly just scaffolding, but the
basic structure is now in place. The primary remaining work is to
wire up resource creation to the gRPC interfaces.
In summary:
* The basic structure is as follows:
- Everything goes into sdk/python/.
- sdk/python/cmd/pulumi-langhost-python is a Go language host
that simply knows how to spawn Python processes to run out
entrypoint in response to requests by the engine.
- sdk/python/cmd/pulumi-langhost-python-exec is a little Python
shim that is invoked by the language host to run Python programs,
and is responsible for setting up the minimal goo before we can
do so (RPC connections and the like).
- sdk/python/lib/ contains a Python Pip package suitable for PyPi.
- In there, we have two packages: the root pulumi package that
contains all of the basic Pulumi programming model abstractions,
and pulumi.runtime, which contains the implementation of
resource registration, RPC interfacing with the engine, and so on.
* Add logic in our test framework to conditionalize on the language
type and react accordingly. This will allow us to skip Yarn for
Python projects and eventually run Pip if there's a requirements.txt.
* Created the basic project structure, including all of the usual
Make targets for installing into the proper places.
* Building also runs Pylint and we are clean.
There are a few other minor things in here:
* Add an "empty" test for both Node.js and Python. These pass.
* Fix an existing bug in plugin shutdown logic. At some point, we
started waiting for stderr/stdout to flush before shutting down
the plugin; but if certain failures happen "early" during the
plugin launch process, these channels will never get initialized
and so waiting for them deadlocks.
* Recently we seem to have added logic to delete test temp
directories if a failure happened during initialization of said
temp directories. This is unfortunate, because you often need to
look at the temp directory to see what failed. We already clean
them up elsewhere after the full test completes successfully, so
I don't think we need to be doing this, and I've removed it.
Still many loose ends (config, resources, etc), but it's a start!
2018-01-13 18:29:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-11 20:22:24 +00:00
|
|
|
// prepareProjectDir runs setup necessary to get the project ready for `pulumi` commands.
|
|
|
|
func (pt *programTester) prepareProjectDir(projectDir string) error {
|
|
|
|
projinfo, err := pt.getProjinfo(projectDir)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return pt.prepareProject(projinfo)
|
|
|
|
}
|
|
|
|
|
Get the empty Python program working
This change gets enough of the Python SDK up and running that the
empty Python program will work. Mostly just scaffolding, but the
basic structure is now in place. The primary remaining work is to
wire up resource creation to the gRPC interfaces.
In summary:
* The basic structure is as follows:
- Everything goes into sdk/python/.
- sdk/python/cmd/pulumi-langhost-python is a Go language host
that simply knows how to spawn Python processes to run out
entrypoint in response to requests by the engine.
- sdk/python/cmd/pulumi-langhost-python-exec is a little Python
shim that is invoked by the language host to run Python programs,
and is responsible for setting up the minimal goo before we can
do so (RPC connections and the like).
- sdk/python/lib/ contains a Python Pip package suitable for PyPi.
- In there, we have two packages: the root pulumi package that
contains all of the basic Pulumi programming model abstractions,
and pulumi.runtime, which contains the implementation of
resource registration, RPC interfacing with the engine, and so on.
* Add logic in our test framework to conditionalize on the language
type and react accordingly. This will allow us to skip Yarn for
Python projects and eventually run Pip if there's a requirements.txt.
* Created the basic project structure, including all of the usual
Make targets for installing into the proper places.
* Building also runs Pylint and we are clean.
There are a few other minor things in here:
* Add an "empty" test for both Node.js and Python. These pass.
* Fix an existing bug in plugin shutdown logic. At some point, we
started waiting for stderr/stdout to flush before shutting down
the plugin; but if certain failures happen "early" during the
plugin launch process, these channels will never get initialized
and so waiting for them deadlocks.
* Recently we seem to have added logic to delete test temp
directories if a failure happened during initialization of said
temp directories. This is unfortunate, because you often need to
look at the temp directory to see what failed. We already clean
them up elsewhere after the full test completes successfully, so
I don't think we need to be doing this, and I've removed it.
Still many loose ends (config, resources, etc), but it's a start!
2018-01-13 18:29:34 +00:00
|
|
|
// prepareNodeJSProject runs setup necessary to get a Node.js project ready for `pulumi` commands.
|
|
|
|
func (pt *programTester) prepareNodeJSProject(projinfo *engine.Projinfo) error {
|
2017-10-16 21:20:16 +00:00
|
|
|
// Write a .yarnrc file to pass --mutex network to all yarn invocations, since tests
|
|
|
|
// may run concurrently and yarn may fail if invoked concurrently
|
|
|
|
// https://github.com/yarnpkg/yarn/issues/683
|
2018-01-29 17:29:02 +00:00
|
|
|
// Also add --network-concurrency 1 since we've been seeing
|
|
|
|
// https://github.com/yarnpkg/yarn/issues/4563 as well
|
Get the empty Python program working
This change gets enough of the Python SDK up and running that the
empty Python program will work. Mostly just scaffolding, but the
basic structure is now in place. The primary remaining work is to
wire up resource creation to the gRPC interfaces.
In summary:
* The basic structure is as follows:
- Everything goes into sdk/python/.
- sdk/python/cmd/pulumi-langhost-python is a Go language host
that simply knows how to spawn Python processes to run out
entrypoint in response to requests by the engine.
- sdk/python/cmd/pulumi-langhost-python-exec is a little Python
shim that is invoked by the language host to run Python programs,
and is responsible for setting up the minimal goo before we can
do so (RPC connections and the like).
- sdk/python/lib/ contains a Python Pip package suitable for PyPi.
- In there, we have two packages: the root pulumi package that
contains all of the basic Pulumi programming model abstractions,
and pulumi.runtime, which contains the implementation of
resource registration, RPC interfacing with the engine, and so on.
* Add logic in our test framework to conditionalize on the language
type and react accordingly. This will allow us to skip Yarn for
Python projects and eventually run Pip if there's a requirements.txt.
* Created the basic project structure, including all of the usual
Make targets for installing into the proper places.
* Building also runs Pylint and we are clean.
There are a few other minor things in here:
* Add an "empty" test for both Node.js and Python. These pass.
* Fix an existing bug in plugin shutdown logic. At some point, we
started waiting for stderr/stdout to flush before shutting down
the plugin; but if certain failures happen "early" during the
plugin launch process, these channels will never get initialized
and so waiting for them deadlocks.
* Recently we seem to have added logic to delete test temp
directories if a failure happened during initialization of said
temp directories. This is unfortunate, because you often need to
look at the temp directory to see what failed. We already clean
them up elsewhere after the full test completes successfully, so
I don't think we need to be doing this, and I've removed it.
Still many loose ends (config, resources, etc), but it's a start!
2018-01-13 18:29:34 +00:00
|
|
|
if err := ioutil.WriteFile(
|
|
|
|
filepath.Join(projinfo.Root, ".yarnrc"),
|
|
|
|
[]byte("--mutex network\n--network-concurrency 1\n"), 0644); err != nil {
|
2018-01-06 00:39:13 +00:00
|
|
|
return err
|
2017-11-16 15:49:07 +00:00
|
|
|
}
|
Get the empty Python program working
This change gets enough of the Python SDK up and running that the
empty Python program will work. Mostly just scaffolding, but the
basic structure is now in place. The primary remaining work is to
wire up resource creation to the gRPC interfaces.
In summary:
* The basic structure is as follows:
- Everything goes into sdk/python/.
- sdk/python/cmd/pulumi-langhost-python is a Go language host
that simply knows how to spawn Python processes to run out
entrypoint in response to requests by the engine.
- sdk/python/cmd/pulumi-langhost-python-exec is a little Python
shim that is invoked by the language host to run Python programs,
and is responsible for setting up the minimal goo before we can
do so (RPC connections and the like).
- sdk/python/lib/ contains a Python Pip package suitable for PyPi.
- In there, we have two packages: the root pulumi package that
contains all of the basic Pulumi programming model abstractions,
and pulumi.runtime, which contains the implementation of
resource registration, RPC interfacing with the engine, and so on.
* Add logic in our test framework to conditionalize on the language
type and react accordingly. This will allow us to skip Yarn for
Python projects and eventually run Pip if there's a requirements.txt.
* Created the basic project structure, including all of the usual
Make targets for installing into the proper places.
* Building also runs Pylint and we are clean.
There are a few other minor things in here:
* Add an "empty" test for both Node.js and Python. These pass.
* Fix an existing bug in plugin shutdown logic. At some point, we
started waiting for stderr/stdout to flush before shutting down
the plugin; but if certain failures happen "early" during the
plugin launch process, these channels will never get initialized
and so waiting for them deadlocks.
* Recently we seem to have added logic to delete test temp
directories if a failure happened during initialization of said
temp directories. This is unfortunate, because you often need to
look at the temp directory to see what failed. We already clean
them up elsewhere after the full test completes successfully, so
I don't think we need to be doing this, and I've removed it.
Still many loose ends (config, resources, etc), but it's a start!
2018-01-13 18:29:34 +00:00
|
|
|
|
|
|
|
// Get the correct pwd to run Yarn in.
|
2018-02-14 21:56:16 +00:00
|
|
|
cwd, _, err := projinfo.GetPwdMain()
|
2017-11-16 15:49:07 +00:00
|
|
|
if err != nil {
|
2018-01-06 00:39:13 +00:00
|
|
|
return err
|
2017-11-16 15:49:07 +00:00
|
|
|
}
|
|
|
|
|
2017-08-06 00:49:48 +00:00
|
|
|
// Now ensure dependencies are present.
|
Get the empty Python program working
This change gets enough of the Python SDK up and running that the
empty Python program will work. Mostly just scaffolding, but the
basic structure is now in place. The primary remaining work is to
wire up resource creation to the gRPC interfaces.
In summary:
* The basic structure is as follows:
- Everything goes into sdk/python/.
- sdk/python/cmd/pulumi-langhost-python is a Go language host
that simply knows how to spawn Python processes to run out
entrypoint in response to requests by the engine.
- sdk/python/cmd/pulumi-langhost-python-exec is a little Python
shim that is invoked by the language host to run Python programs,
and is responsible for setting up the minimal goo before we can
do so (RPC connections and the like).
- sdk/python/lib/ contains a Python Pip package suitable for PyPi.
- In there, we have two packages: the root pulumi package that
contains all of the basic Pulumi programming model abstractions,
and pulumi.runtime, which contains the implementation of
resource registration, RPC interfacing with the engine, and so on.
* Add logic in our test framework to conditionalize on the language
type and react accordingly. This will allow us to skip Yarn for
Python projects and eventually run Pip if there's a requirements.txt.
* Created the basic project structure, including all of the usual
Make targets for installing into the proper places.
* Building also runs Pylint and we are clean.
There are a few other minor things in here:
* Add an "empty" test for both Node.js and Python. These pass.
* Fix an existing bug in plugin shutdown logic. At some point, we
started waiting for stderr/stdout to flush before shutting down
the plugin; but if certain failures happen "early" during the
plugin launch process, these channels will never get initialized
and so waiting for them deadlocks.
* Recently we seem to have added logic to delete test temp
directories if a failure happened during initialization of said
temp directories. This is unfortunate, because you often need to
look at the temp directory to see what failed. We already clean
them up elsewhere after the full test completes successfully, so
I don't think we need to be doing this, and I've removed it.
Still many loose ends (config, resources, etc), but it's a start!
2018-01-13 18:29:34 +00:00
|
|
|
if err = pt.runYarnCommand("yarn-install", []string{"install", "--verbose"}, cwd); err != nil {
|
|
|
|
return err
|
2017-11-06 17:04:38 +00:00
|
|
|
}
|
Restructure test framework to ease multiple languages (#799)
This change restructures the test framework code a bit, to make it
easier to introduce additional languages. Our knowledge of Yarn and
Node.js project structure, for instance, was previously baked in to
the test logic, in a way that was hard to make, for instance, Yarn
optional. (In Python, of course, it will not be used.) To better
support this, I've moved some state onto a new programTester struct
that we can use to lazily find binaries required during the testing
(such as Yarn, Pip, and so on). I'm committing this separately so
that I can minimize merge conflicts in the Python work.
2018-01-13 01:10:53 +00:00
|
|
|
for _, dependency := range pt.opts.Dependencies {
|
Get the empty Python program working
This change gets enough of the Python SDK up and running that the
empty Python program will work. Mostly just scaffolding, but the
basic structure is now in place. The primary remaining work is to
wire up resource creation to the gRPC interfaces.
In summary:
* The basic structure is as follows:
- Everything goes into sdk/python/.
- sdk/python/cmd/pulumi-langhost-python is a Go language host
that simply knows how to spawn Python processes to run out
entrypoint in response to requests by the engine.
- sdk/python/cmd/pulumi-langhost-python-exec is a little Python
shim that is invoked by the language host to run Python programs,
and is responsible for setting up the minimal goo before we can
do so (RPC connections and the like).
- sdk/python/lib/ contains a Python Pip package suitable for PyPi.
- In there, we have two packages: the root pulumi package that
contains all of the basic Pulumi programming model abstractions,
and pulumi.runtime, which contains the implementation of
resource registration, RPC interfacing with the engine, and so on.
* Add logic in our test framework to conditionalize on the language
type and react accordingly. This will allow us to skip Yarn for
Python projects and eventually run Pip if there's a requirements.txt.
* Created the basic project structure, including all of the usual
Make targets for installing into the proper places.
* Building also runs Pylint and we are clean.
There are a few other minor things in here:
* Add an "empty" test for both Node.js and Python. These pass.
* Fix an existing bug in plugin shutdown logic. At some point, we
started waiting for stderr/stdout to flush before shutting down
the plugin; but if certain failures happen "early" during the
plugin launch process, these channels will never get initialized
and so waiting for them deadlocks.
* Recently we seem to have added logic to delete test temp
directories if a failure happened during initialization of said
temp directories. This is unfortunate, because you often need to
look at the temp directory to see what failed. We already clean
them up elsewhere after the full test completes successfully, so
I don't think we need to be doing this, and I've removed it.
Still many loose ends (config, resources, etc), but it's a start!
2018-01-13 18:29:34 +00:00
|
|
|
if err = pt.runYarnCommand("yarn-link", []string{"link", dependency}, cwd); err != nil {
|
|
|
|
return err
|
2017-11-06 17:04:38 +00:00
|
|
|
}
|
2017-08-06 00:49:48 +00:00
|
|
|
}
|
|
|
|
|
2018-06-25 05:47:54 +00:00
|
|
|
if pt.opts.RunBuild {
|
2018-07-07 05:06:28 +00:00
|
|
|
// And finally compile it using whatever build steps are in the package.json file.
|
|
|
|
if err = pt.runYarnCommand("yarn-build", []string{"run", "build"}, cwd); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
2017-07-13 19:19:17 +00:00
|
|
|
}
|
Get the empty Python program working
This change gets enough of the Python SDK up and running that the
empty Python program will work. Mostly just scaffolding, but the
basic structure is now in place. The primary remaining work is to
wire up resource creation to the gRPC interfaces.
In summary:
* The basic structure is as follows:
- Everything goes into sdk/python/.
- sdk/python/cmd/pulumi-langhost-python is a Go language host
that simply knows how to spawn Python processes to run out
entrypoint in response to requests by the engine.
- sdk/python/cmd/pulumi-langhost-python-exec is a little Python
shim that is invoked by the language host to run Python programs,
and is responsible for setting up the minimal goo before we can
do so (RPC connections and the like).
- sdk/python/lib/ contains a Python Pip package suitable for PyPi.
- In there, we have two packages: the root pulumi package that
contains all of the basic Pulumi programming model abstractions,
and pulumi.runtime, which contains the implementation of
resource registration, RPC interfacing with the engine, and so on.
* Add logic in our test framework to conditionalize on the language
type and react accordingly. This will allow us to skip Yarn for
Python projects and eventually run Pip if there's a requirements.txt.
* Created the basic project structure, including all of the usual
Make targets for installing into the proper places.
* Building also runs Pylint and we are clean.
There are a few other minor things in here:
* Add an "empty" test for both Node.js and Python. These pass.
* Fix an existing bug in plugin shutdown logic. At some point, we
started waiting for stderr/stdout to flush before shutting down
the plugin; but if certain failures happen "early" during the
plugin launch process, these channels will never get initialized
and so waiting for them deadlocks.
* Recently we seem to have added logic to delete test temp
directories if a failure happened during initialization of said
temp directories. This is unfortunate, because you often need to
look at the temp directory to see what failed. We already clean
them up elsewhere after the full test completes successfully, so
I don't think we need to be doing this, and I've removed it.
Still many loose ends (config, resources, etc), but it's a start!
2018-01-13 18:29:34 +00:00
|
|
|
|
|
|
|
// preparePythonProject runs setup necessary to get a Python project ready for `pulumi` commands.
|
|
|
|
func (pt *programTester) preparePythonProject(projinfo *engine.Projinfo) error {
|
|
|
|
return nil
|
|
|
|
}
|
2018-06-10 16:17:19 +00:00
|
|
|
|
|
|
|
// prepareGoProject runs setup necessary to get a Go project ready for `pulumi` commands.
|
|
|
|
func (pt *programTester) prepareGoProject(projinfo *engine.Projinfo) error {
|
|
|
|
// Go programs are compiled, so we will compile the project first.
|
|
|
|
goBin, err := pt.getGoBin()
|
|
|
|
if err != nil {
|
|
|
|
return errors.Wrap(err, "locating `go` binary")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure GOPATH is known.
|
|
|
|
gopath := os.Getenv("GOPATH")
|
|
|
|
if gopath == "" {
|
2018-06-11 20:22:24 +00:00
|
|
|
usr, userErr := user.Current()
|
|
|
|
if userErr != nil {
|
|
|
|
return userErr
|
2018-06-11 20:08:46 +00:00
|
|
|
}
|
|
|
|
gopath = filepath.Join(usr.HomeDir, "go")
|
2018-06-10 16:17:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// To compile, simply run `go build -o $GOPATH/bin/<projname> .` from the project's working directory.
|
|
|
|
cwd, _, err := projinfo.GetPwdMain()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
outBin := filepath.Join(gopath, "bin", string(projinfo.Proj.Name))
|
|
|
|
return pt.runCommand("go-build", []string{goBin, "build", "-o", outBin, "."}, cwd)
|
|
|
|
}
|