"use strict";
// Copyright 2016-2021, Pulumi Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
    result["default"] = mod;
    return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
const assert_1 = __importDefault(require("assert"));
const semver = __importStar(require("semver"));
const tmp = __importStar(require("tmp"));
const upath = __importStar(require("upath"));
const automation_1 = require("../../automation");
const index_1 = require("../../index");
const util_1 = require("./util");
const versionRegex = /(\d+\.)(\d+\.)(\d+)(-.*)?/;
const userAgent = "pulumi/pulumi/test";
describe("LocalWorkspace", () => {
    it(`projectSettings from yaml/yml/json`, () => __awaiter(void 0, void 0, void 0, function* () {
        for (const ext of ["yaml", "yml", "json"]) {
            const ws = yield automation_1.LocalWorkspace.create({ workDir: upath.joinSafe(__dirname, "data", ext) });
            const settings = yield ws.projectSettings();
            assert_1.default(settings.name, "testproj");
            assert_1.default(settings.runtime, "go");
            assert_1.default(settings.description, "A minimal Go Pulumi program");
        }
    }));
    it(`stackSettings from yaml/yml/json`, () => __awaiter(void 0, void 0, void 0, function* () {
        for (const ext of ["yaml", "yml", "json"]) {
            const ws = yield automation_1.LocalWorkspace.create({ workDir: upath.joinSafe(__dirname, "data", ext) });
            const settings = yield ws.stackSettings("dev");
            assert_1.default.strictEqual(settings.secretsProvider, "abc");
            assert_1.default.strictEqual(settings.config["plain"], "plain");
            assert_1.default.strictEqual(settings.config["secure"].secure, "secret");
            yield ws.saveStackSettings("dev", settings);
            assert_1.default.strictEqual(settings.secretsProvider, "abc");
        }
    }));
    it(`fails gracefully for missing local workspace workDir`, () => __awaiter(void 0, void 0, void 0, function* () {
        try {
            const ws = yield automation_1.LocalWorkspace.create({ workDir: "invalid-missing-workdir" });
            assert_1.default.fail("expected create with invalid workDir to throw");
        }
        catch (err) {
            assert_1.default.strictEqual(err.toString(), "Error: Invalid workDir passed to local workspace: 'invalid-missing-workdir' does not exist");
        }
    }));
    it(`adds/removes/lists plugins successfully`, () => __awaiter(void 0, void 0, void 0, function* () {
        const ws = yield automation_1.LocalWorkspace.create({});
        yield ws.installPlugin("aws", "v3.0.0");
        // See https://github.com/pulumi/pulumi/issues/11013 for why this is disabled
        //await ws.installPluginFromServer("scaleway", "v1.2.0", "github://api.github.com/lbrlabs");
        yield ws.removePlugin("aws", "3.0.0");
        yield ws.listPlugins();
    }));
    it(`create/select/remove LocalWorkspace stack`, () => __awaiter(void 0, void 0, void 0, function* () {
        const projectName = "node_test";
        const projectSettings = {
            name: projectName,
            runtime: "nodejs",
        };
        const ws = yield automation_1.LocalWorkspace.create({ projectSettings });
        const stackName = automation_1.fullyQualifiedStackName(util_1.getTestOrg(), projectName, `int_test${util_1.getTestSuffix()}`);
        yield ws.createStack(stackName);
        yield ws.selectStack(stackName);
        yield ws.removeStack(stackName);
    }));
    it(`create/select/createOrSelect Stack`, () => __awaiter(void 0, void 0, void 0, function* () {
        const projectName = "node_test";
        const projectSettings = {
            name: projectName,
            runtime: "nodejs",
        };
        const ws = yield automation_1.LocalWorkspace.create({ projectSettings });
        const stackName = automation_1.fullyQualifiedStackName(util_1.getTestOrg(), projectName, `int_test${util_1.getTestSuffix()}`);
        yield automation_1.Stack.create(stackName, ws);
        yield automation_1.Stack.select(stackName, ws);
        yield automation_1.Stack.createOrSelect(stackName, ws);
        yield ws.removeStack(stackName);
    }));
    describe("Tag methods: get/set/remove/list", () => {
        const projectName = "testProjectName";
        const runtime = "nodejs";
        const stackName = automation_1.fullyQualifiedStackName(util_1.getTestOrg(), projectName, `int_test${util_1.getTestSuffix()}`);
        const projectSettings = {
            name: projectName,
            runtime,
        };
        let workspace;
        beforeEach(() => __awaiter(void 0, void 0, void 0, function* () {
            workspace = yield automation_1.LocalWorkspace.create({
                projectSettings: projectSettings,
            });
            yield workspace.createStack(stackName);
        }));
        it("lists tag values", () => __awaiter(void 0, void 0, void 0, function* () {
            const result = yield workspace.listTags(stackName);
            assert_1.default.strictEqual(result["pulumi:project"], projectName);
            assert_1.default.strictEqual(result["pulumi:runtime"], runtime);
        }));
        it("sets and removes tag values", () => __awaiter(void 0, void 0, void 0, function* () {
            // sets
            yield workspace.setTag(stackName, "foo", "bar");
            const actualValue = yield workspace.getTag(stackName, "foo");
            assert_1.default.strictEqual(actualValue, "bar");
            // removes
            yield workspace.removeTag(stackName, "foo");
            const actualTags = yield workspace.listTags(stackName);
            assert_1.default.strictEqual(actualTags["foo"], undefined);
        }));
        it("gets a single tag value", () => __awaiter(void 0, void 0, void 0, function* () {
            const actualValue = yield workspace.getTag(stackName, "pulumi:project");
            assert_1.default.strictEqual(actualValue, actualValue.trim());
            assert_1.default.strictEqual(actualValue, projectName);
        }));
        afterEach(() => __awaiter(void 0, void 0, void 0, function* () {
            yield workspace.removeStack(stackName);
        }));
    });
    describe("ListStack Methods", () => __awaiter(void 0, void 0, void 0, function* () {
        describe("ListStacks", () => __awaiter(void 0, void 0, void 0, function* () {
            const stackJson = `[
                    {
                        "name": "testorg1/testproj1/teststack1",
                        "current": false,
                        "url": "https://app.pulumi.com/testorg1/testproj1/teststack1"
                    },
                    {
                        "name": "testorg1/testproj1/teststack2",
                        "current": false,
                        "url": "https://app.pulumi.com/testorg1/testproj1/teststack2"
                    }
                ]`;
            it(`should handle stacks correctly for listStacks`, () => __awaiter(void 0, void 0, void 0, function* () {
                const mockWithReturnedStacks = {
                    command: "pulumi",
                    version: null,
                    run: (args, cwd, additionalEnv) => __awaiter(void 0, void 0, void 0, function* () {
                        return new automation_1.CommandResult(stackJson, "", 0);
                    }),
                };
                const workspace = yield automation_1.LocalWorkspace.create({ pulumiCommand: mockWithReturnedStacks });
                const stacks = yield workspace.listStacks();
                assert_1.default.strictEqual(stacks.length, 2);
                assert_1.default.strictEqual(stacks[0].name, "testorg1/testproj1/teststack1");
                assert_1.default.strictEqual(stacks[0].current, false);
                assert_1.default.strictEqual(stacks[0].url, "https://app.pulumi.com/testorg1/testproj1/teststack1");
                assert_1.default.strictEqual(stacks[1].name, "testorg1/testproj1/teststack2");
                assert_1.default.strictEqual(stacks[1].current, false);
                assert_1.default.strictEqual(stacks[1].url, "https://app.pulumi.com/testorg1/testproj1/teststack2");
            }));
            it(`should use correct args for listStacks`, () => __awaiter(void 0, void 0, void 0, function* () {
                let capturedArgs = [];
                const mockPulumiCommand = {
                    command: "pulumi",
                    version: null,
                    run: (args, cwd, additionalEnv) => __awaiter(void 0, void 0, void 0, function* () {
                        capturedArgs = args;
                        return new automation_1.CommandResult(stackJson, "", 0);
                    }),
                };
                const workspace = yield automation_1.LocalWorkspace.create({
                    pulumiCommand: mockPulumiCommand,
                });
                yield workspace.listStacks();
                assert_1.default.deepStrictEqual(capturedArgs, ["stack", "ls", "--json"]);
            }));
        }));
        describe("ListStacks with all", () => __awaiter(void 0, void 0, void 0, function* () {
            const stackJson = `[
                    {
                        "name": "testorg1/testproj1/teststack1",
                        "current": false,
                        "url": "https://app.pulumi.com/testorg1/testproj1/teststack1"
                    },
                    {
                        "name": "testorg1/testproj2/teststack2",
                        "current": false,
                        "url": "https://app.pulumi.com/testorg1/testproj2/teststack2"
                    }
                ]`;
            it(`should handle stacks correctly for listStacks when all is set`, () => __awaiter(void 0, void 0, void 0, function* () {
                const mockWithReturnedStacks = {
                    command: "pulumi",
                    version: null,
                    run: () => __awaiter(void 0, void 0, void 0, function* () { return new automation_1.CommandResult(stackJson, "", 0); }),
                };
                const workspace = yield automation_1.LocalWorkspace.create({
                    pulumiCommand: mockWithReturnedStacks,
                });
                const stacks = yield workspace.listStacks({ all: true });
                assert_1.default.strictEqual(stacks.length, 2);
                assert_1.default.strictEqual(stacks[0].name, "testorg1/testproj1/teststack1");
                assert_1.default.strictEqual(stacks[0].current, false);
                assert_1.default.strictEqual(stacks[0].url, "https://app.pulumi.com/testorg1/testproj1/teststack1");
                assert_1.default.strictEqual(stacks[1].name, "testorg1/testproj2/teststack2");
                assert_1.default.strictEqual(stacks[1].current, false);
                assert_1.default.strictEqual(stacks[1].url, "https://app.pulumi.com/testorg1/testproj2/teststack2");
            }));
            it(`should use correct args for listStacks when all is set`, () => __awaiter(void 0, void 0, void 0, function* () {
                let capturedArgs = [];
                const mockPuluiCommand = {
                    command: "pulumi",
                    version: null,
                    run: (args, cwd, additionalEnv) => __awaiter(void 0, void 0, void 0, function* () {
                        capturedArgs = args;
                        return new automation_1.CommandResult(stackJson, "", 0);
                    }),
                };
                const workspace = yield automation_1.LocalWorkspace.create({
                    pulumiCommand: mockPuluiCommand,
                });
                yield workspace.listStacks({ all: true });
                assert_1.default.deepStrictEqual(capturedArgs, ["stack", "ls", "--json", "--all"]);
            }));
        }));
    }));
    it(`Environment functions`, function () {
        return __awaiter(this, void 0, void 0, function* () {
            // Skipping test because the required environments are in the moolumi org.
            if (util_1.getTestOrg() !== "moolumi") {
                this.skip();
                return;
            }
            const projectName = "node_env_test";
            const projectSettings = {
                name: projectName,
                runtime: "nodejs",
            };
            const ws = yield automation_1.LocalWorkspace.create({ projectSettings });
            const stackName = automation_1.fullyQualifiedStackName(util_1.getTestOrg(), projectName, `int_test${util_1.getTestSuffix()}`);
            const stack = yield automation_1.Stack.create(stackName, ws);
            // Adding non-existent env should fail.
            yield assert_1.default.rejects(stack.addEnvironments("non-existent-env"), "stack.addEnvironments('non-existent-env') did not reject");
            // Adding existing envs should succeed.
            yield stack.addEnvironments("automation-api-test-env", "automation-api-test-env-2");
            let envs = yield stack.listEnvironments();
            assert_1.default.deepStrictEqual(envs, ["automation-api-test-env", "automation-api-test-env-2"]);
            const config = yield stack.getAllConfig();
            assert_1.default.strictEqual(config["node_env_test:new_key"].value, "test_value");
            assert_1.default.strictEqual(config["node_env_test:also"].value, "business");
            // Removing existing env should succeed.
            yield stack.removeEnvironment("automation-api-test-env");
            envs = yield stack.listEnvironments();
            assert_1.default.deepStrictEqual(envs, ["automation-api-test-env-2"]);
            const alsoConfig = yield stack.getConfig("also");
            assert_1.default.strictEqual(alsoConfig.value, "business");
            yield assert_1.default.rejects(stack.getConfig("new_key"), "stack.getConfig('new_key') did not reject");
            yield stack.removeEnvironment("automation-api-test-env-2");
            envs = yield stack.listEnvironments();
            assert_1.default.strictEqual(envs.length, 0);
            yield assert_1.default.rejects(stack.getConfig("also"), "stack.getConfig('also') did not reject");
            yield ws.removeStack(stackName);
        });
    });
    it(`Config`, () => __awaiter(void 0, void 0, void 0, function* () {
        const projectName = "node_test";
        const projectSettings = {
            name: projectName,
            runtime: "nodejs",
        };
        const ws = yield automation_1.LocalWorkspace.create({ projectSettings });
        const stackName = automation_1.fullyQualifiedStackName(util_1.getTestOrg(), projectName, `int_test${util_1.getTestSuffix()}`);
        const stack = yield automation_1.Stack.create(stackName, ws);
        const config = {
            plain: { value: "abc" },
            secret: { value: "def", secret: true },
        };
        let caught = 0;
        const plainKey = normalizeConfigKey("plain", projectName);
        const secretKey = normalizeConfigKey("secret", projectName);
        try {
            yield stack.getConfig(plainKey);
        }
        catch (error) {
            caught++;
        }
        assert_1.default.strictEqual(caught, 1, "expected config get on empty value to throw");
        let values = yield stack.getAllConfig();
        assert_1.default.strictEqual(Object.keys(values).length, 0, "expected stack config to be empty");
        yield stack.setAllConfig(config);
        values = yield stack.getAllConfig();
        assert_1.default.strictEqual(values[plainKey].value, "abc");
        assert_1.default.strictEqual(values[plainKey].secret, false);
        assert_1.default.strictEqual(values[secretKey].value, "def");
        assert_1.default.strictEqual(values[secretKey].secret, true);
        yield stack.removeConfig("plain");
        values = yield stack.getAllConfig();
        assert_1.default.strictEqual(Object.keys(values).length, 1, "expected stack config to have 1 value");
        yield stack.setConfig("foo", { value: "bar" });
        values = yield stack.getAllConfig();
        assert_1.default.strictEqual(Object.keys(values).length, 2, "expected stack config to have 2 values");
        yield ws.removeStack(stackName);
    }));
    it(`config_flag_like`, () => __awaiter(void 0, void 0, void 0, function* () {
        const projectName = "config_flag_like";
        const projectSettings = {
            name: projectName,
            runtime: "nodejs",
        };
        const ws = yield automation_1.LocalWorkspace.create({ projectSettings });
        const stackName = automation_1.fullyQualifiedStackName(util_1.getTestOrg(), projectName, `int_test${util_1.getTestSuffix()}`);
        const stack = yield automation_1.Stack.create(stackName, ws);
        yield stack.setConfig("key", { value: "-value" });
        yield stack.setConfig("secret-key", { value: "-value", secret: true });
        const values = yield stack.getAllConfig();
        assert_1.default.strictEqual(values["config_flag_like:key"].value, "-value");
        assert_1.default.strictEqual(values["config_flag_like:key"].secret, false);
        assert_1.default.strictEqual(values["config_flag_like:secret-key"].value, "-value");
        assert_1.default.strictEqual(values["config_flag_like:secret-key"].secret, true);
        yield stack.setAllConfig({
            key: { value: "-value2" },
            "secret-key": { value: "-value2", secret: true },
        });
        const values2 = yield stack.getAllConfig();
        assert_1.default.strictEqual(values2["config_flag_like:key"].value, "-value2");
        assert_1.default.strictEqual(values2["config_flag_like:key"].secret, false);
        assert_1.default.strictEqual(values2["config_flag_like:secret-key"].value, "-value2");
        assert_1.default.strictEqual(values2["config_flag_like:secret-key"].secret, true);
    }));
    it(`Config path`, () => __awaiter(void 0, void 0, void 0, function* () {
        const projectName = "node_test";
        const projectSettings = {
            name: projectName,
            runtime: "nodejs",
        };
        const ws = yield automation_1.LocalWorkspace.create({ projectSettings });
        const stackName = automation_1.fullyQualifiedStackName(util_1.getTestOrg(), projectName, `int_test${util_1.getTestSuffix()}`);
        const stack = yield automation_1.Stack.create(stackName, ws);
        // test backward compatibility
        yield stack.setConfig("key1", { value: "value1" });
        // test new flag without subPath
        yield stack.setConfig("key2", { value: "value2" }, false);
        // test new flag with subPath
        yield stack.setConfig("key3.subKey1", { value: "value3" }, true);
        // test secret
        yield stack.setConfig("key4", { value: "value4", secret: true });
        // test subPath and key as secret
        yield stack.setConfig("key5.subKey1", { value: "value5", secret: true }, true);
        // test string with dots
        yield stack.setConfig("key6.subKey1", { value: "value6", secret: true });
        // test string with dots
        yield stack.setConfig("key7.subKey1", { value: "value7", secret: true }, false);
        // test subPath
        yield stack.setConfig("key7.subKey2", { value: "value8" }, true);
        // test subPath
        yield stack.setConfig("key7.subKey3", { value: "value9" }, true);
        // test backward compatibility
        const cv1 = yield stack.getConfig("key1");
        assert_1.default.strictEqual(cv1.value, "value1");
        assert_1.default.strictEqual(cv1.secret, false);
        // test new flag without subPath
        const cv2 = yield stack.getConfig("key2", false);
        assert_1.default.strictEqual(cv2.value, "value2");
        assert_1.default.strictEqual(cv2.secret, false);
        // test new flag with subPath
        const cv3 = yield stack.getConfig("key3.subKey1", true);
        assert_1.default.strictEqual(cv3.value, "value3");
        assert_1.default.strictEqual(cv3.secret, false);
        // test secret
        const cv4 = yield stack.getConfig("key4");
        assert_1.default.strictEqual(cv4.value, "value4");
        assert_1.default.strictEqual(cv4.secret, true);
        // test subPath and key as secret
        const cv5 = yield stack.getConfig("key5.subKey1", true);
        assert_1.default.strictEqual(cv5.value, "value5");
        assert_1.default.strictEqual(cv5.secret, true);
        // test string with dots
        const cv6 = yield stack.getConfig("key6.subKey1");
        assert_1.default.strictEqual(cv6.value, "value6");
        assert_1.default.strictEqual(cv6.secret, true);
        // test string with dots
        const cv7 = yield stack.getConfig("key7.subKey1", false);
        assert_1.default.strictEqual(cv7.value, "value7");
        assert_1.default.strictEqual(cv7.secret, true);
        // test string with dots
        const cv8 = yield stack.getConfig("key7.subKey2", true);
        assert_1.default.strictEqual(cv8.value, "value8");
        assert_1.default.strictEqual(cv8.secret, false);
        // test string with dots
        const cv9 = yield stack.getConfig("key7.subKey3", true);
        assert_1.default.strictEqual(cv9.value, "value9");
        assert_1.default.strictEqual(cv9.secret, false);
        yield stack.removeConfig("key1");
        yield stack.removeConfig("key2", false);
        yield stack.removeConfig("key3", false);
        yield stack.removeConfig("key4", false);
        yield stack.removeConfig("key5", false);
        yield stack.removeConfig("key6.subKey1", false);
        yield stack.removeConfig("key7.subKey1", false);
        const cfg = yield stack.getAllConfig();
        assert_1.default.strictEqual(cfg["node_test:key7"].value, '{"subKey2":"value8","subKey3":"value9"}');
        yield ws.removeStack(stackName);
    }));
    // This test requires the existence of a Pulumi.dev.yaml file because we are reading the nested
    // config from the file. This means we can't remove the stack at the end of the test.
    // We should also not include secrets in this config, because the secret encryption is only valid within
    // the context of a stack and org, and running this test in different orgs will fail if there are secrets.
    it(`nested_config`, () => __awaiter(void 0, void 0, void 0, function* () {
        const stackName = automation_1.fullyQualifiedStackName(util_1.getTestOrg(), "nested_config", "dev");
        const workDir = upath.joinSafe(__dirname, "data", "nested_config");
        const stack = yield automation_1.LocalWorkspace.createOrSelectStack({ stackName, workDir });
        const allConfig = yield stack.getAllConfig();
        const outerVal = allConfig["nested_config:outer"];
        assert_1.default.strictEqual(outerVal.secret, false);
        assert_1.default.strictEqual(outerVal.value, '{"inner":"my_value","other":"something_else"}');
        const listVal = allConfig["nested_config:myList"];
        assert_1.default.strictEqual(listVal.secret, false);
        assert_1.default.strictEqual(listVal.value, '["one","two","three"]');
        const outer = yield stack.getConfig("outer");
        assert_1.default.strictEqual(outer.secret, false);
        assert_1.default.strictEqual(outer.value, '{"inner":"my_value","other":"something_else"}');
        const list = yield stack.getConfig("myList");
        assert_1.default.strictEqual(list.secret, false);
        assert_1.default.strictEqual(list.value, '["one","two","three"]');
    }));
    it(`can list stacks and currently selected stack`, () => __awaiter(void 0, void 0, void 0, function* () {
        const projectName = `node_list_test${util_1.getTestSuffix()}`;
        const projectSettings = {
            name: projectName,
            runtime: "nodejs",
        };
        const ws = yield automation_1.LocalWorkspace.create({ projectSettings });
        const stackNamer = () => `int_test${util_1.getTestSuffix()}`;
        const stackNames = [];
        for (let i = 0; i < 2; i++) {
            const stackName = automation_1.fullyQualifiedStackName(util_1.getTestOrg(), projectName, stackNamer());
            stackNames[i] = stackName;
            yield automation_1.Stack.create(stackName, ws);
            const stackSummary = yield ws.stack();
            assert_1.default.strictEqual(stackSummary === null || stackSummary === void 0 ? void 0 : stackSummary.current, true);
            const stacks = yield ws.listStacks();
            assert_1.default.strictEqual(stacks.length, i + 1);
        }
        for (const name of stackNames) {
            yield ws.removeStack(name);
        }
    }));
    it(`returns valid whoami result`, () => __awaiter(void 0, void 0, void 0, function* () {
        const projectName = "node_test";
        const projectSettings = {
            name: projectName,
            runtime: "nodejs",
        };
        const ws = yield automation_1.LocalWorkspace.create({ projectSettings });
        const whoAmIResult = yield ws.whoAmI();
        assert_1.default(whoAmIResult.user !== null);
        assert_1.default(whoAmIResult.url !== null);
    }));
    it(`stack status methods`, () => __awaiter(void 0, void 0, void 0, function* () {
        const projectName = "node_test";
        const projectSettings = {
            name: projectName,
            runtime: "nodejs",
        };
        const ws = yield automation_1.LocalWorkspace.create({ projectSettings });
        const stackName = automation_1.fullyQualifiedStackName(util_1.getTestOrg(), projectName, `int_test${util_1.getTestSuffix()}`);
        const stack = yield automation_1.Stack.create(stackName, ws);
        const history = yield stack.history();
        assert_1.default.strictEqual(history.length, 0);
        const info = yield stack.info();
        assert_1.default.strictEqual(typeof info, "undefined");
        yield ws.removeStack(stackName);
    }));
    // TODO[pulumi/pulumi#8220] understand why this test was flaky
    xit(`runs through the stack lifecycle with a local program`, () => __awaiter(void 0, void 0, void 0, function* () {
        const stackName = automation_1.fullyQualifiedStackName(util_1.getTestOrg(), "testproj", `int_test${util_1.getTestSuffix()}`);
        const workDir = upath.joinSafe(__dirname, "data", "testproj");
        const stack = yield automation_1.LocalWorkspace.createStack({ stackName, workDir });
        const config = {
            bar: { value: "abc" },
            buzz: { value: "secret", secret: true },
        };
        yield stack.setAllConfig(config);
        // pulumi up
        const upRes = yield stack.up({ userAgent });
        assert_1.default.strictEqual(Object.keys(upRes.outputs).length, 3);
        assert_1.default.strictEqual(upRes.outputs["exp_static"].value, "foo");
        assert_1.default.strictEqual(upRes.outputs["exp_static"].secret, false);
        assert_1.default.strictEqual(upRes.outputs["exp_cfg"].value, "abc");
        assert_1.default.strictEqual(upRes.outputs["exp_cfg"].secret, false);
        assert_1.default.strictEqual(upRes.outputs["exp_secret"].value, "secret");
        assert_1.default.strictEqual(upRes.outputs["exp_secret"].secret, true);
        assert_1.default.strictEqual(upRes.summary.kind, "update");
        assert_1.default.strictEqual(upRes.summary.result, "succeeded");
        // pulumi preview
        const preRes = yield stack.preview({ userAgent });
        assert_1.default.strictEqual(preRes.changeSummary.same, 1);
        // pulumi refresh
        const refRes = yield stack.refresh({ userAgent });
        assert_1.default.strictEqual(refRes.summary.kind, "refresh");
        assert_1.default.strictEqual(refRes.summary.result, "succeeded");
        // pulumi destroy
        const destroyRes = yield stack.destroy({ userAgent });
        assert_1.default.strictEqual(destroyRes.summary.kind, "destroy");
        assert_1.default.strictEqual(destroyRes.summary.result, "succeeded");
        yield stack.workspace.removeStack(stackName);
    }));
    it(`runs through the stack lifecycle with a local dotnet program`, () => __awaiter(void 0, void 0, void 0, function* () {
        const stackName = automation_1.fullyQualifiedStackName(util_1.getTestOrg(), "testproj_dotnet", `int_test${util_1.getTestSuffix()}`);
        const workDir = upath.joinSafe(__dirname, "data", "testproj_dotnet");
        const stack = yield automation_1.LocalWorkspace.createStack({ stackName, workDir });
        // pulumi up
        const upRes = yield stack.up({ userAgent });
        assert_1.default.strictEqual(Object.keys(upRes.outputs).length, 1);
        assert_1.default.strictEqual(upRes.outputs["exp_static"].value, "foo");
        assert_1.default.strictEqual(upRes.outputs["exp_static"].secret, false);
        assert_1.default.strictEqual(upRes.summary.kind, "update");
        assert_1.default.strictEqual(upRes.summary.result, "succeeded");
        // pulumi preview
        const preRes = yield stack.preview({ userAgent });
        assert_1.default.strictEqual(preRes.changeSummary.same, 1);
        // pulumi refresh
        const refRes = yield stack.refresh({ userAgent });
        assert_1.default.strictEqual(refRes.summary.kind, "refresh");
        assert_1.default.strictEqual(refRes.summary.result, "succeeded");
        // pulumi destroy
        const destroyRes = yield stack.destroy({ userAgent });
        assert_1.default.strictEqual(destroyRes.summary.kind, "destroy");
        assert_1.default.strictEqual(destroyRes.summary.result, "succeeded");
        yield stack.workspace.removeStack(stackName);
    }));
    it(`runs through the stack lifecycle with an inline program`, () => __awaiter(void 0, void 0, void 0, function* () {
        const program = () => __awaiter(void 0, void 0, void 0, function* () {
            const config = new index_1.Config();
            return {
                exp_static: "foo",
                exp_cfg: config.get("bar"),
                exp_secret: config.getSecret("buzz"),
            };
        });
        const projectName = "inline_node";
        const stackName = automation_1.fullyQualifiedStackName(util_1.getTestOrg(), projectName, `int_test${util_1.getTestSuffix()}`);
        const stack = yield automation_1.LocalWorkspace.createStack({ stackName, projectName, program });
        const stackConfig = {
            bar: { value: "abc" },
            buzz: { value: "secret", secret: true },
        };
        yield stack.setAllConfig(stackConfig);
        // pulumi up
        const upRes = yield stack.up({ userAgent });
        assert_1.default.strictEqual(Object.keys(upRes.outputs).length, 3);
        assert_1.default.strictEqual(upRes.outputs["exp_static"].value, "foo");
        assert_1.default.strictEqual(upRes.outputs["exp_static"].secret, false);
        assert_1.default.strictEqual(upRes.outputs["exp_cfg"].value, "abc");
        assert_1.default.strictEqual(upRes.outputs["exp_cfg"].secret, false);
        assert_1.default.strictEqual(upRes.outputs["exp_secret"].value, "secret");
        assert_1.default.strictEqual(upRes.outputs["exp_secret"].secret, true);
        assert_1.default.strictEqual(upRes.summary.kind, "update");
        assert_1.default.strictEqual(upRes.summary.result, "succeeded");
        // pulumi preview
        const preRes = yield stack.preview({ userAgent });
        assert_1.default.strictEqual(preRes.changeSummary.same, 1);
        // pulumi refresh
        const refRes = yield stack.refresh({ userAgent });
        assert_1.default.strictEqual(refRes.summary.kind, "refresh");
        assert_1.default.strictEqual(refRes.summary.result, "succeeded");
        // pulumi destroy
        const destroyRes = yield stack.destroy({ userAgent });
        assert_1.default.strictEqual(destroyRes.summary.kind, "destroy");
        assert_1.default.strictEqual(destroyRes.summary.result, "succeeded");
        yield stack.workspace.removeStack(stackName);
    }));
    it(`refreshes before preview`, () => __awaiter(void 0, void 0, void 0, function* () {
        // We create a simple program, and scan the output for an indication
        // that adding refresh: true will perfrom a refresh operation.
        const program = () => __awaiter(void 0, void 0, void 0, function* () {
            return {
                toggle: true,
            };
        });
        const projectName = "inline_node";
        const stackName = automation_1.fullyQualifiedStackName(util_1.getTestOrg(), projectName, `int_test${util_1.getTestSuffix()}`);
        const stack = yield automation_1.LocalWorkspace.createStack({ stackName, projectName, program });
        // • First, run Up so we can set the initial state.
        yield stack.up({ userAgent });
        // • Next, run preview with refresh and check that the refresh was performed.
        const refresh = true;
        const previewRes = yield stack.preview({ userAgent, refresh });
        assert_1.default.match(previewRes.stdout, /refreshing/);
        assert_1.default.strictEqual(previewRes.changeSummary.same, 1, "preview expected 1 same (the stack)");
    }));
    it(`destroys an inline program with excludeProtected`, () => __awaiter(void 0, void 0, void 0, function* () {
        const program = () => __awaiter(void 0, void 0, void 0, function* () {
            var _a;
            class MyResource extends index_1.ComponentResource {
                constructor(name, opts) {
                    super("my:module:MyResource", name, {}, opts);
                }
            }
            const config = new index_1.Config();
            const protect = (_a = config.getBoolean("protect")) !== null && _a !== void 0 ? _a : false;
            new MyResource("first", { protect });
            new MyResource("second");
            return {};
        });
        const projectName = "inline_node";
        const stackName = automation_1.fullyQualifiedStackName(util_1.getTestOrg(), projectName, `int_test${util_1.getTestSuffix()}`);
        const stack = yield automation_1.LocalWorkspace.createStack({ stackName, projectName, program });
        // initial up
        yield stack.setConfig("protect", { value: "true" });
        yield stack.up({ userAgent });
        // pulumi destroy
        const destroyRes = yield stack.destroy({ userAgent, excludeProtected: true });
        assert_1.default.strictEqual(destroyRes.summary.kind, "destroy");
        assert_1.default.strictEqual(destroyRes.summary.result, "succeeded");
        assert_1.default.match(destroyRes.stdout, /All unprotected resources were destroyed/);
        // unprotected resources
        yield stack.removeConfig("protect");
        yield stack.up({ userAgent });
        // pulumi destroy to cleanup all resources
        yield stack.destroy({ userAgent });
        yield stack.workspace.removeStack(stackName);
    }));
    it(`successfully initializes multiple stacks`, () => __awaiter(void 0, void 0, void 0, function* () {
        const program = () => __awaiter(void 0, void 0, void 0, function* () {
            const config = new index_1.Config();
            return {
                exp_static: "foo",
                exp_cfg: config.get("bar"),
                exp_secret: config.getSecret("buzz"),
            };
        });
        const projectName = "inline_node";
        const stackNames = Array.from(Array(10).keys()).map((_) => automation_1.fullyQualifiedStackName(util_1.getTestOrg(), projectName, `int_test${util_1.getTestSuffix()}`));
        const stacks = yield Promise.all(stackNames.map((stackName) => __awaiter(void 0, void 0, void 0, function* () { return automation_1.LocalWorkspace.createStack({ stackName, projectName, program }); })));
        yield stacks.map((stack) => stack.workspace.removeStack(stack.name));
    }));
    it(`runs through the stack lifecycle with multiple inline programs in parallel`, () => __awaiter(void 0, void 0, void 0, function* () {
        const program = () => __awaiter(void 0, void 0, void 0, function* () {
            const config = new index_1.Config();
            return {
                exp_static: "foo",
                exp_cfg: config.get("bar"),
                exp_secret: config.getSecret("buzz"),
            };
        });
        const projectName = "inline_node";
        const stackNames = Array.from(Array(30).keys()).map((_) => automation_1.fullyQualifiedStackName(util_1.getTestOrg(), projectName, `int_test${util_1.getTestSuffix()}`));
        const testStackLifetime = (stackName) => __awaiter(void 0, void 0, void 0, function* () {
            const stack = yield automation_1.LocalWorkspace.createStack({ stackName, projectName, program });
            const stackConfig = {
                bar: { value: "abc" },
                buzz: { value: "secret", secret: true },
            };
            yield stack.setAllConfig(stackConfig);
            // pulumi up
            const upRes = yield stack.up({ userAgent }); // pulumi up
            assert_1.default.strictEqual(Object.keys(upRes.outputs).length, 3);
            assert_1.default.strictEqual(upRes.outputs["exp_static"].value, "foo");
            assert_1.default.strictEqual(upRes.outputs["exp_static"].secret, false);
            assert_1.default.strictEqual(upRes.outputs["exp_cfg"].value, "abc");
            assert_1.default.strictEqual(upRes.outputs["exp_cfg"].secret, false);
            assert_1.default.strictEqual(upRes.outputs["exp_secret"].value, "secret");
            assert_1.default.strictEqual(upRes.outputs["exp_secret"].secret, true);
            assert_1.default.strictEqual(upRes.summary.kind, "update");
            assert_1.default.strictEqual(upRes.summary.result, "succeeded");
            // pulumi preview
            const preRes = yield stack.preview({ userAgent }); // pulumi preview
            assert_1.default.strictEqual(preRes.changeSummary.same, 1);
            // pulumi refresh
            const refRes = yield stack.refresh({ userAgent });
            assert_1.default.strictEqual(refRes.summary.kind, "refresh");
            assert_1.default.strictEqual(refRes.summary.result, "succeeded");
            // pulumi destroy
            const destroyRes = yield stack.destroy({ userAgent });
            assert_1.default.strictEqual(destroyRes.summary.kind, "destroy");
            assert_1.default.strictEqual(destroyRes.summary.result, "succeeded");
            yield stack.workspace.removeStack(stack.name);
        });
        for (let i = 0; i < stackNames.length; i += 10) {
            const chunk = stackNames.slice(i, i + 10);
            yield Promise.all(chunk.map((stackName) => __awaiter(void 0, void 0, void 0, function* () { return yield testStackLifetime(stackName); })));
        }
    }));
    it(`handles events`, () => __awaiter(void 0, void 0, void 0, function* () {
        const program = () => __awaiter(void 0, void 0, void 0, function* () {
            const config = new index_1.Config();
            return {
                exp_static: "foo",
                exp_cfg: config.get("bar"),
                exp_secret: config.getSecret("buzz"),
            };
        });
        const projectName = "inline_node";
        const stackName = automation_1.fullyQualifiedStackName(util_1.getTestOrg(), projectName, `int_test${util_1.getTestSuffix()}`);
        const stack = yield automation_1.LocalWorkspace.createStack({ stackName, projectName, program });
        const stackConfig = {
            bar: { value: "abc" },
            buzz: { value: "secret", secret: true },
        };
        yield stack.setAllConfig(stackConfig);
        let seenSummaryEvent = false;
        const findSummaryEvent = (event) => {
            if (event.summaryEvent) {
                seenSummaryEvent = true;
            }
        };
        // pulumi preview
        const preRes = yield stack.preview({ onEvent: findSummaryEvent });
        assert_1.default.strictEqual(seenSummaryEvent, true, "No SummaryEvent for `preview`");
        assert_1.default.strictEqual(preRes.changeSummary.create, 1);
        // pulumi up
        seenSummaryEvent = false;
        const upRes = yield stack.up({ onEvent: findSummaryEvent });
        assert_1.default.strictEqual(seenSummaryEvent, true, "No SummaryEvent for `up`");
        assert_1.default.strictEqual(upRes.summary.kind, "update");
        assert_1.default.strictEqual(upRes.summary.result, "succeeded");
        // pulumi preview
        seenSummaryEvent = false;
        const preResAgain = yield stack.preview({ onEvent: findSummaryEvent });
        assert_1.default.strictEqual(seenSummaryEvent, true, "No SummaryEvent for `preview`");
        assert_1.default.strictEqual(preResAgain.changeSummary.same, 1);
        // pulumi refresh
        seenSummaryEvent = false;
        const refRes = yield stack.refresh({ onEvent: findSummaryEvent });
        assert_1.default.strictEqual(seenSummaryEvent, true, "No SummaryEvent for `refresh`");
        assert_1.default.strictEqual(refRes.summary.kind, "refresh");
        assert_1.default.strictEqual(refRes.summary.result, "succeeded");
        // pulumi destroy
        seenSummaryEvent = false;
        const destroyRes = yield stack.destroy({ onEvent: findSummaryEvent });
        assert_1.default.strictEqual(seenSummaryEvent, true, "No SummaryEvent for `destroy`");
        assert_1.default.strictEqual(destroyRes.summary.kind, "destroy");
        assert_1.default.strictEqual(destroyRes.summary.result, "succeeded");
        yield stack.workspace.removeStack(stackName);
    }));
    // TODO[pulumi/pulumi#7127]: Re-enabled the warning.
    // Temporarily skipping test until we've re-enabled the warning.
    it.skip(`has secret config warnings`, () => __awaiter(void 0, void 0, void 0, function* () {
        const program = () => __awaiter(void 0, void 0, void 0, function* () {
            const config = new index_1.Config();
            config.get("plainstr1");
            config.require("plainstr2");
            config.getSecret("plainstr3");
            config.requireSecret("plainstr4");
            config.getBoolean("plainbool1");
            config.requireBoolean("plainbool2");
            config.getSecretBoolean("plainbool3");
            config.requireSecretBoolean("plainbool4");
            config.getNumber("plainnum1");
            config.requireNumber("plainnum2");
            config.getSecretNumber("plainnum3");
            config.requireSecretNumber("plainnum4");
            config.getObject("plainobj1");
            config.requireObject("plainobj2");
            config.getSecretObject("plainobj3");
            config.requireSecretObject("plainobj4");
            config.get("str1");
            config.require("str2");
            config.getSecret("str3");
            config.requireSecret("str4");
            config.getBoolean("bool1");
            config.requireBoolean("bool2");
            config.getSecretBoolean("bool3");
            config.requireSecretBoolean("bool4");
            config.getNumber("num1");
            config.requireNumber("num2");
            config.getSecretNumber("num3");
            config.requireSecretNumber("num4");
            config.getObject("obj1");
            config.requireObject("obj2");
            config.getSecretObject("obj3");
            config.requireSecretObject("obj4");
        });
        const projectName = "inline_node";
        const stackName = automation_1.fullyQualifiedStackName(util_1.getTestOrg(), projectName, `int_test${util_1.getTestSuffix()}`);
        const stack = yield automation_1.LocalWorkspace.createStack({ stackName, projectName, program });
        const stackConfig = {
            plainstr1: { value: "1" },
            plainstr2: { value: "2" },
            plainstr3: { value: "3" },
            plainstr4: { value: "4" },
            plainbool1: { value: "true" },
            plainbool2: { value: "true" },
            plainbool3: { value: "true" },
            plainbool4: { value: "true" },
            plainnum1: { value: "1" },
            plainnum2: { value: "2" },
            plainnum3: { value: "3" },
            plainnum4: { value: "4" },
            plainobj1: { value: "{}" },
            plainobj2: { value: "{}" },
            plainobj3: { value: "{}" },
            plainobj4: { value: "{}" },
            str1: { value: "1", secret: true },
            str2: { value: "2", secret: true },
            str3: { value: "3", secret: true },
            str4: { value: "4", secret: true },
            bool1: { value: "true", secret: true },
            bool2: { value: "true", secret: true },
            bool3: { value: "true", secret: true },
            bool4: { value: "true", secret: true },
            num1: { value: "1", secret: true },
            num2: { value: "2", secret: true },
            num3: { value: "3", secret: true },
            num4: { value: "4", secret: true },
            obj1: { value: "{}", secret: true },
            obj2: { value: "{}", secret: true },
            obj3: { value: "{}", secret: true },
            obj4: { value: "{}", secret: true },
        };
        yield stack.setAllConfig(stackConfig);
        let events = [];
        const findDiagnosticEvents = (event) => {
            var _a;
            if (((_a = event.diagnosticEvent) === null || _a === void 0 ? void 0 : _a.severity) === "warning") {
                events.push(event.diagnosticEvent.message);
            }
        };
        const expectedWarnings = [
            "Configuration 'inline_node:str1' value is a secret; use `getSecret` instead of `get`",
            "Configuration 'inline_node:str2' value is a secret; use `requireSecret` instead of `require`",
            "Configuration 'inline_node:bool1' value is a secret; use `getSecretBoolean` instead of `getBoolean`",
            "Configuration 'inline_node:bool2' value is a secret; use `requireSecretBoolean` instead of `requireBoolean`",
            "Configuration 'inline_node:num1' value is a secret; use `getSecretNumber` instead of `getNumber`",
            "Configuration 'inline_node:num2' value is a secret; use `requireSecretNumber` instead of `requireNumber`",
            "Configuration 'inline_node:obj1' value is a secret; use `getSecretObject` instead of `getObject`",
            "Configuration 'inline_node:obj2' value is a secret; use `requireSecretObject` instead of `requireObject`",
        ];
        // These keys should not be in any warning messages.
        const unexpectedWarnings = [
            "plainstr1",
            "plainstr2",
            "plainstr3",
            "plainstr4",
            "plainbool1",
            "plainbool2",
            "plainbool3",
            "plainbool4",
            "plainnum1",
            "plainnum2",
            "plainnum3",
            "plainnum4",
            "plainobj1",
            "plainobj2",
            "plainobj3",
            "plainobj4",
            "str3",
            "str4",
            "bool3",
            "bool4",
            "num3",
            "num4",
            "obj3",
            "obj4",
        ];
        const validate = (warnings) => {
            for (const expected of expectedWarnings) {
                let found = false;
                for (const warning of warnings) {
                    if (warning.includes(expected)) {
                        found = true;
                        break;
                    }
                }
                assert_1.default.strictEqual(found, true, `expected warning not found`);
            }
            for (const unexpected of unexpectedWarnings) {
                for (const warning of warnings) {
                    assert_1.default.strictEqual(warning.includes(unexpected), false, `Unexpected '${unexpected}' found in warning`);
                }
            }
        };
        // pulumi preview
        yield stack.preview({ onEvent: findDiagnosticEvents });
        validate(events);
        // pulumi up
        events = [];
        yield stack.up({ onEvent: findDiagnosticEvents });
        validate(events);
        yield stack.workspace.removeStack(stackName);
    }));
    it(`imports and exports stacks`, () => __awaiter(void 0, void 0, void 0, function* () {
        const program = () => __awaiter(void 0, void 0, void 0, function* () {
            const config = new index_1.Config();
            return {
                exp_static: "foo",
                exp_cfg: config.get("bar"),
                exp_secret: config.getSecret("buzz"),
            };
        });
        const projectName = "import_export_node";
        const stackName = automation_1.fullyQualifiedStackName(util_1.getTestOrg(), projectName, `int_test${util_1.getTestSuffix()}`);
        const stack = yield automation_1.LocalWorkspace.createStack({ stackName, projectName, program });
        try {
            yield stack.setAllConfig({
                bar: { value: "abc" },
                buzz: { value: "secret", secret: true },
            });
            yield stack.up();
            // export stack
            const state = yield stack.exportStack();
            // import stack
            yield stack.importStack(state);
            const configVal = yield stack.getConfig("bar");
            assert_1.default.strictEqual(configVal.value, "abc");
        }
        finally {
            const destroyRes = yield stack.destroy();
            assert_1.default.strictEqual(destroyRes.summary.kind, "destroy");
            assert_1.default.strictEqual(destroyRes.summary.result, "succeeded");
            yield stack.workspace.removeStack(stackName);
        }
    }));
    // TODO[pulumi/pulumi#8061] flaky test
    xit(`supports stack outputs`, () => __awaiter(void 0, void 0, void 0, function* () {
        const program = () => __awaiter(void 0, void 0, void 0, function* () {
            const config = new index_1.Config();
            return {
                exp_static: "foo",
                exp_cfg: config.get("bar"),
                exp_secret: config.getSecret("buzz"),
            };
        });
        const projectName = "import_export_node";
        const stackName = automation_1.fullyQualifiedStackName(util_1.getTestOrg(), projectName, `int_test${util_1.getTestSuffix()}`);
        const stack = yield automation_1.LocalWorkspace.createStack({ stackName, projectName, program });
        const assertOutputs = (outputs) => {
            assert_1.default.strictEqual(Object.keys(outputs).length, 3, "expected to have 3 outputs");
            assert_1.default.strictEqual(outputs["exp_static"].value, "foo");
            assert_1.default.strictEqual(outputs["exp_static"].secret, false);
            assert_1.default.strictEqual(outputs["exp_cfg"].value, "abc");
            assert_1.default.strictEqual(outputs["exp_cfg"].secret, false);
            assert_1.default.strictEqual(outputs["exp_secret"].value, "secret");
            assert_1.default.strictEqual(outputs["exp_secret"].secret, true);
        };
        try {
            yield stack.setAllConfig({
                bar: { value: "abc" },
                buzz: { value: "secret", secret: true },
            });
            const initialOutputs = yield stack.outputs();
            assert_1.default.strictEqual(Object.keys(initialOutputs).length, 0, "expected initialOutputs to be empty");
            // pulumi up
            const upRes = yield stack.up();
            assert_1.default.strictEqual(upRes.summary.kind, "update");
            assert_1.default.strictEqual(upRes.summary.result, "succeeded");
            assertOutputs(upRes.outputs);
            const outputsAfterUp = yield stack.outputs();
            assertOutputs(outputsAfterUp);
            const destroyRes = yield stack.destroy();
            assert_1.default.strictEqual(destroyRes.summary.kind, "destroy");
            assert_1.default.strictEqual(destroyRes.summary.result, "succeeded");
            const outputsAfterDestroy = yield stack.outputs();
            assert_1.default.strictEqual(Object.keys(outputsAfterDestroy).length, 0, "expected outputsAfterDestroy to be empty");
        }
        finally {
            yield stack.workspace.removeStack(stackName);
        }
    }));
    it(`runs an inline program that exits gracefully`, () => __awaiter(void 0, void 0, void 0, function* () {
        const program = () => __awaiter(void 0, void 0, void 0, function* () { return ({}); });
        const projectName = "inline_node";
        const stackName = automation_1.fullyQualifiedStackName(util_1.getTestOrg(), projectName, `int_test${util_1.getTestSuffix()}`);
        const stack = yield automation_1.LocalWorkspace.createStack({ stackName, projectName, program });
        // pulumi up
        yield assert_1.default.doesNotReject(stack.up());
        // pulumi destroy
        const destroyRes = yield stack.destroy();
        assert_1.default.strictEqual(destroyRes.summary.kind, "destroy");
        assert_1.default.strictEqual(destroyRes.summary.result, "succeeded");
        yield stack.workspace.removeStack(stackName);
    }));
    it(`runs an inline program that rejects a promise and exits gracefully`, () => __awaiter(void 0, void 0, void 0, function* () {
        const program = () => __awaiter(void 0, void 0, void 0, function* () {
            Promise.reject(new Error());
            return {};
        });
        const projectName = "inline_node";
        const stackName = automation_1.fullyQualifiedStackName(util_1.getTestOrg(), projectName, `int_test${util_1.getTestSuffix()}`);
        const stack = yield automation_1.LocalWorkspace.createStack({ stackName, projectName, program });
        // pulumi up
        yield assert_1.default.rejects(stack.up());
        // pulumi destroy
        const destroyRes = yield stack.destroy();
        assert_1.default.strictEqual(destroyRes.summary.kind, "destroy");
        assert_1.default.strictEqual(destroyRes.summary.result, "succeeded");
        yield stack.workspace.removeStack(stackName);
    }));
    it(`runs successfully after a previous failure`, () => __awaiter(void 0, void 0, void 0, function* () {
        let shouldFail = true;
        const program = () => __awaiter(void 0, void 0, void 0, function* () {
            if (shouldFail) {
                Promise.reject(new Error());
            }
            return {};
        });
        const projectName = "inline_node";
        const stackName = automation_1.fullyQualifiedStackName(util_1.getTestOrg(), projectName, `int_test${util_1.getTestSuffix()}`);
        const stack = yield automation_1.LocalWorkspace.createStack({ stackName, projectName, program });
        // pulumi up rejects the first time
        yield assert_1.default.rejects(stack.up());
        // pulumi up succeeds the 2nd time
        shouldFail = false;
        yield assert_1.default.doesNotReject(stack.up());
        // pulumi destroy
        const destroyRes = yield stack.destroy();
        assert_1.default.strictEqual(destroyRes.summary.kind, "destroy");
        assert_1.default.strictEqual(destroyRes.summary.result, "succeeded");
        yield stack.workspace.removeStack(stackName);
    }));
    it(`sets pulumi version`, () => __awaiter(void 0, void 0, void 0, function* () {
        const ws = yield automation_1.LocalWorkspace.create({});
        assert_1.default(ws.pulumiVersion);
        assert_1.default.strictEqual(versionRegex.test(ws.pulumiVersion), true);
    }));
    it("sets pulumi version when using a custom CLI instance", () => __awaiter(void 0, void 0, void 0, function* () {
        const tmpDir = tmp.dirSync({ prefix: "automation-test-", unsafeCleanup: true });
        try {
            const cmd = yield automation_1.PulumiCommand.get();
            const ws = yield automation_1.LocalWorkspace.create({ pulumiCommand: cmd });
            assert_1.default.strictEqual(versionRegex.test(ws.pulumiVersion), true);
        }
        finally {
            tmpDir.removeCallback();
        }
    }));
    it("throws when attempting to retrieve an invalid pulumi version", () => __awaiter(void 0, void 0, void 0, function* () {
        const mockWithNoVersion = {
            command: "pulumi",
            version: null,
            run: () => __awaiter(void 0, void 0, void 0, function* () { return new automation_1.CommandResult("some output", "", 0); }),
        };
        const ws = yield automation_1.LocalWorkspace.create({
            pulumiCommand: mockWithNoVersion,
            envVars: {
                PULUMI_AUTOMATION_API_SKIP_VERSION_CHECK: "true",
            },
        });
        assert_1.default.throws(() => ws.pulumiVersion);
    }));
    it("fails creation if remote operation is not supported", () => __awaiter(void 0, void 0, void 0, function* () {
        const mockWithNoRemoteSupport = {
            command: "pulumi",
            version: new semver.SemVer("2.0.0"),
            // We inspect the output of `pulumi preview --help` to determine
            // if the CLI supports remote operations, see
            // `LocalWorkspace.checkRemoteSupport`.
            run: () => __awaiter(void 0, void 0, void 0, function* () { return new automation_1.CommandResult("some output", "", 0); }),
        };
        yield assert_1.default.rejects(automation_1.LocalWorkspace.create({ pulumiCommand: mockWithNoRemoteSupport, remote: true }));
    }));
    it("bypasses remote support check", () => __awaiter(void 0, void 0, void 0, function* () {
        const mockWithNoRemoteSupport = {
            command: "pulumi",
            version: new semver.SemVer("2.0.0"),
            // We inspect the output of `pulumi preview --help` to determine
            // if the CLI supports remote operations, see
            // `LocalWorkspace.checkRemoteSupport`.
            run: () => __awaiter(void 0, void 0, void 0, function* () { return new automation_1.CommandResult("some output", "", 0); }),
        };
        yield assert_1.default.doesNotReject(automation_1.LocalWorkspace.create({
            pulumiCommand: mockWithNoRemoteSupport,
            remote: true,
            envVars: {
                PULUMI_AUTOMATION_API_SKIP_VERSION_CHECK: "true",
            },
        }));
    }));
    it(`respects existing project settings`, () => __awaiter(void 0, void 0, void 0, function* () {
        const projectName = "correct_project";
        const stackName = automation_1.fullyQualifiedStackName(util_1.getTestOrg(), projectName, `int_test${util_1.getTestSuffix()}`);
        const stack = yield automation_1.LocalWorkspace.createStack({
            stackName,
            projectName,
            program: () => __awaiter(void 0, void 0, void 0, function* () {
                return;
            }),
        }, { workDir: upath.joinSafe(__dirname, "data", "correct_project") });
        const projectSettings = yield stack.workspace.projectSettings();
        assert_1.default.strictEqual(projectSettings.name, "correct_project");
        // the description check is enough to verify that the stack wasn't overwritten
        assert_1.default.strictEqual(projectSettings.description, "This is a description");
        yield stack.workspace.removeStack(stackName);
    }));
    it(`correctly sets config on multiple stacks concurrently`, () => __awaiter(void 0, void 0, void 0, function* () {
        const dones = [];
        const stacks = ["dev", "dev2", "dev3", "dev4", "dev5"];
        const workDir = upath.joinSafe(__dirname, "data", "tcfg");
        const ws = yield automation_1.LocalWorkspace.create({
            workDir,
            projectSettings: {
                name: "concurrent-config",
                runtime: "nodejs",
                backend: { url: "file://~" },
            },
            envVars: {
                PULUMI_CONFIG_PASSPHRASE: "test",
            },
        });
        for (let i = 0; i < stacks.length; i++) {
            yield automation_1.Stack.create(stacks[i], ws);
        }
        for (let i = 0; i < stacks.length; i++) {
            const x = i;
            const s = stacks[i];
            dones.push((() => __awaiter(void 0, void 0, void 0, function* () {
                for (let j = 0; j < 20; j++) {
                    yield ws.setConfig(s, "var-" + j, { value: (x * 20 + j).toString() });
                }
            }))());
        }
        yield Promise.all(dones);
        for (let i = 0; i < stacks.length; i++) {
            const stack = yield automation_1.LocalWorkspace.selectStack({
                stackName: stacks[i],
                workDir,
            });
            const config = yield stack.getAllConfig();
            assert_1.default.strictEqual(Object.keys(config).length, 20);
            yield stack.workspace.removeStack(stacks[i]);
        }
    }));
});
const normalizeConfigKey = (key, projectName) => {
    const parts = key.split(":");
    if (parts.length < 2) {
        return `${projectName}:${key}`;
    }
    return "";
};
//# sourceMappingURL=localWorkspace.spec.js.map