From 6782771f11ae1c0b7dc557cfa8173dd018e05cac Mon Sep 17 00:00:00 2001 From: Steve Hetzel Date: Mon, 2 Oct 2023 12:34:08 -0600 Subject: [PATCH 1/8] fix: handle multiple sandbox processes in a resumable state --- messages/sandboxbase.md | 4 + src/commands/org/resume/sandbox.ts | 6 +- src/shared/sandboxCommandBase.ts | 21 +++++ test/unit/org/resumeSandbox.test.ts | 118 ++++++++++++++++++++++++++++ 4 files changed, 146 insertions(+), 3 deletions(-) create mode 100644 test/unit/org/resumeSandbox.test.ts diff --git a/messages/sandboxbase.md b/messages/sandboxbase.md index 0bb74a12..e4464914 100644 --- a/messages/sandboxbase.md +++ b/messages/sandboxbase.md @@ -15,3 +15,7 @@ If the org is ready, checking the status also authorizes the org for use with Sa # warning.ClientTimeoutWaitingForSandboxCreate The wait time for the sandbox creation has been exhausted. Please see the results below for more information. + +# warning.MultipleMatchingSandboxProcesses + +There were multiple sandbox processes found for "%s" in a resumable state. Ignoring sandbox process ID(s) "%s" in status(es) "%s" and using the most recent process ID "%s". To resume a different sandbox process please use that unique sandbox process ID with the command. E.g, "sf org resume sandbox --job-id %s -o %s" diff --git a/src/commands/org/resume/sandbox.ts b/src/commands/org/resume/sandbox.ts index 07f68194..3775560a 100644 --- a/src/commands/org/resume/sandbox.ts +++ b/src/commands/org/resume/sandbox.ts @@ -93,7 +93,7 @@ export default class ResumeSandbox extends SandboxCommandBase => { - const where = sandboxName ? `SandboxName='${sandboxName}'` : `Id='${jobId}'`; + const where = jobId ? `Id='${jobId}'` : `SandboxName='${sandboxName}'`; const queryStr = `SELECT Id, Status, SandboxName, SandboxInfoId, LicenseType, CreatedDate, CopyProgress, SandboxOrganization, SourceId, Description, EndDate FROM SandboxProcess WHERE ${where} AND Status != 'D'`; try { return await prodOrg.getConnection().singleRecordQuery(queryStr, { diff --git a/src/shared/sandboxCommandBase.ts b/src/shared/sandboxCommandBase.ts index 4034dff8..a2f8e2fb 100644 --- a/src/shared/sandboxCommandBase.ts +++ b/src/shared/sandboxCommandBase.ts @@ -150,6 +150,27 @@ export abstract class SandboxCommandBase extends SfCommand { this.updateProgress(results, options.isAsync); this.reportResults(results); }); + + lifecycle.on(SandboxEvents.EVENT_MULTIPLE_SBX_PROCESSES, async (results: SandboxProcessObject[]) => { + const resumingProcess = results.shift() as SandboxProcessObject; + const sbxProcessIds: string[] = []; + const sbxProcessStatuses: string[] = []; + results.map((sbxProc) => { + sbxProcessIds.push(sbxProc.Id); + sbxProcessStatuses.push(sbxProc.Status); + }); + this.warn( + messages.getMessage('warning.MultipleMatchingSandboxProcesses', [ + results[0].SandboxName, + sbxProcessIds.toString(), + sbxProcessStatuses.toString(), + resumingProcess.Id, + sbxProcessIds[0], + this.prodOrg?.getUsername(), + ]) + ); + return Promise.resolve(); + }); } protected reportResults(results: ResultEvent): void { diff --git a/test/unit/org/resumeSandbox.test.ts b/test/unit/org/resumeSandbox.test.ts new file mode 100644 index 00000000..1679848d --- /dev/null +++ b/test/unit/org/resumeSandbox.test.ts @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2020, salesforce.com, inc. + * All rights reserved. + * Licensed under the BSD 3-Clause license. + * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause + */ +import { + Lifecycle, + Messages, + Org, + SandboxEvents, + SandboxProcessObject, + AuthFields, + SandboxRequestCacheEntry, + SfError, +} from '@salesforce/core'; +import { stubMethod } from '@salesforce/ts-sinon'; +import * as sinon from 'sinon'; +import { expect, config } from 'chai'; +import { OrgAccessor } from '@salesforce/core/lib/stateAggregator'; +import { stubSfCommandUx, stubSpinner, stubUx } from '@salesforce/sf-plugins-core'; +import ResumeSandbox from '../../../src/commands/org/resume/sandbox'; + +config.truncateThreshold = 0; + +const prodOrgUsername = 'resumeSandbox@test.org'; +const sandboxName = 'TestSbx'; +const fakeOrg: AuthFields = { + orgId: '00Dsomefakeorg1', + instanceUrl: 'https://some.fake.org', + username: prodOrgUsername, +}; + +const sandboxProcessObj: SandboxProcessObject = { + Id: '0GR4p000000U8EMXXX', + Status: 'Completed', + SandboxName: sandboxName, + SandboxInfoId: '0GQ4p000000U6sKXXX', + LicenseType: 'DEVELOPER', + CreatedDate: '2021-12-07T16:20:21.000+0000', + CopyProgress: 100, + SandboxOrganization: '00D2f0000008XXX', + SourceId: '123', + Description: 'sandbox description', + ApexClassId: '123', + EndDate: '2021-12-07T16:38:47.000+0000', +}; + +const sandboxRequestData: SandboxRequestCacheEntry = { + prodOrgUsername, + sandboxRequest: {}, + sandboxProcessObject: { + SandboxName: sandboxName, + }, + setDefault: false, +}; + +describe('[org resume sandbox]', () => { + Messages.importMessagesDirectory(__dirname); + const messages = Messages.loadMessages('@salesforce/plugin-org', 'sandboxbase'); + + const sandbox = sinon.createSandbox(); + + beforeEach(() => { + stubMethod(sandbox, OrgAccessor.prototype, 'read').resolves(fakeOrg); + stubMethod(sandbox, OrgAccessor.prototype, 'write').resolves(fakeOrg); + sfCommandUxStubs = stubSfCommandUx(sandbox); + stubUx(sandbox); + stubSpinner(sandbox); + }); + + let sfCommandUxStubs: ReturnType; + + it('will warn when multiple sandboxes are in a resumable state', async () => { + stubMethod(sandbox, ResumeSandbox.prototype, 'getSandboxRequestConfig').resolves(); + stubMethod(sandbox, ResumeSandbox.prototype, 'buildSandboxRequestCacheEntry').returns(sandboxRequestData); + stubMethod(sandbox, ResumeSandbox.prototype, 'createResumeSandboxRequest').returns({ + SandboxName: sandboxName, + }); + stubMethod(sandbox, Org, 'create').resolves(Org.prototype); + stubMethod(sandbox, Org.prototype, 'getUsername').returns(prodOrgUsername); + const sbxCreateNotComplete = new SfError('sbx create not complete', 'sandboxCreateNotComplete'); + const inProgSandboxProcessObj = Object.assign({}, sandboxProcessObj, { + Status: 'In Progress', + Id: '0GR4p000000U8EMZZZ', + CopyProgress: 25, + CreatedDate: '2022-12-07T16:20:21.000+0000', + }); + stubMethod(sandbox, Org.prototype, 'resumeSandbox').callsFake(async () => { + await Lifecycle.getInstance().emit(SandboxEvents.EVENT_MULTIPLE_SBX_PROCESSES, [ + inProgSandboxProcessObj, + sandboxProcessObj, + ]); + throw sbxCreateNotComplete; + }); + + try { + await ResumeSandbox.run(['-o', prodOrgUsername, '--name', sandboxName]); + expect(false, 'ResumeSandbox should have thrown sandboxCreateNotComplete'); + } catch (err: unknown) { + const warningMsg = messages.getMessage('warning.MultipleMatchingSandboxProcesses', [ + sandboxName, + sandboxProcessObj.Id, + sandboxProcessObj.Status, + inProgSandboxProcessObj.Id, + sandboxProcessObj.Id, + prodOrgUsername, + ]); + expect(sfCommandUxStubs.warn.calledWith(warningMsg)).to.be.true; + const error = err as SfError; + expect(error.name).to.equal('sandboxCreateNotComplete'); + } + }); + + afterEach(() => { + sandbox.restore(); + }); +}); From cd74ab533d88b4f06e3559c23d6a0bab30694144 Mon Sep 17 00:00:00 2001 From: Steve Hetzel Date: Mon, 2 Oct 2023 12:47:10 -0600 Subject: [PATCH 2/8] fix: handle multiple sandbox processes in a resumable state --- test/unit/org/resumeSandbox.test.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/unit/org/resumeSandbox.test.ts b/test/unit/org/resumeSandbox.test.ts index 1679848d..eaa77fa9 100644 --- a/test/unit/org/resumeSandbox.test.ts +++ b/test/unit/org/resumeSandbox.test.ts @@ -79,7 +79,6 @@ describe('[org resume sandbox]', () => { }); stubMethod(sandbox, Org, 'create').resolves(Org.prototype); stubMethod(sandbox, Org.prototype, 'getUsername').returns(prodOrgUsername); - const sbxCreateNotComplete = new SfError('sbx create not complete', 'sandboxCreateNotComplete'); const inProgSandboxProcessObj = Object.assign({}, sandboxProcessObj, { Status: 'In Progress', Id: '0GR4p000000U8EMZZZ', @@ -91,7 +90,7 @@ describe('[org resume sandbox]', () => { inProgSandboxProcessObj, sandboxProcessObj, ]); - throw sbxCreateNotComplete; + throw new SfError('sbx create not complete', 'sandboxCreateNotComplete'); }); try { From 11913a329da2ae312c76e736be9945d28c66d8ef Mon Sep 17 00:00:00 2001 From: Steve Hetzel Date: Mon, 2 Oct 2023 12:55:04 -0600 Subject: [PATCH 3/8] fix: handle multiple sandbox processes in a resumable state --- test/tsconfig.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/tsconfig.json b/test/tsconfig.json index c1d1f397..e629218b 100644 --- a/test/tsconfig.json +++ b/test/tsconfig.json @@ -7,7 +7,8 @@ "baseUrl": "../", "sourceMap": true, "paths": { - "@salesforce/kit": ["node_modules/@salesforce/kit"] + "@salesforce/kit": ["node_modules/@salesforce/kit"], + "@salesforce/core": ["node_modules/@salesforce/core"] } } } From 486df94b3dbe1d40a5ebf64a3572b883d220bc89 Mon Sep 17 00:00:00 2001 From: Steve Hetzel Date: Wed, 4 Oct 2023 13:33:31 -0600 Subject: [PATCH 4/8] Apply suggestions from code review Co-authored-by: Juliet Shackell <63259011+jshackell-sfdc@users.noreply.github.com> --- messages/sandboxbase.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/messages/sandboxbase.md b/messages/sandboxbase.md index e4464914..c97cab28 100644 --- a/messages/sandboxbase.md +++ b/messages/sandboxbase.md @@ -14,8 +14,8 @@ If the org is ready, checking the status also authorizes the org for use with Sa # warning.ClientTimeoutWaitingForSandboxCreate -The wait time for the sandbox creation has been exhausted. Please see the results below for more information. +The wait time for the sandbox creation has been exhausted. See the results below for more information. # warning.MultipleMatchingSandboxProcesses -There were multiple sandbox processes found for "%s" in a resumable state. Ignoring sandbox process ID(s) "%s" in status(es) "%s" and using the most recent process ID "%s". To resume a different sandbox process please use that unique sandbox process ID with the command. E.g, "sf org resume sandbox --job-id %s -o %s" +We found multiple sandbox processes for "%s" in a resumable state. We're ignoring the sandbox process ID(s) "%s" in status(es) "%s" and using the most recent process ID "%s". To resume a different sandbox process, use that unique sandbox process ID with the command. For example, "sf org resume sandbox --job-id %s -o %s". From 38bc892bf780007b06be1bbd43c2ab98d84b6676 Mon Sep 17 00:00:00 2001 From: Cristian Dominguez Date: Wed, 4 Oct 2023 18:25:46 -0300 Subject: [PATCH 5/8] chore: bump salesforce/core and dedup lockfile --- package.json | 2 +- yarn.lock | 47 +++++++++++++++++------------------------------ 2 files changed, 18 insertions(+), 31 deletions(-) diff --git a/package.json b/package.json index 7ca3c156..58788235 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "bugs": "https://github.com/forcedotcom/cli/issues", "dependencies": { "@oclif/core": "^2.15.0", - "@salesforce/core": "^5.2.0", + "@salesforce/core": "^5.3.4", "@salesforce/kit": "^3.0.9", "@salesforce/sf-plugins-core": "^3.1.22", "@salesforce/source-deploy-retrieve": "^9.7.13", diff --git a/yarn.lock b/yarn.lock index bae0dc8d..bb2ff8a2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -885,14 +885,14 @@ strip-ansi "6.0.1" ts-retry-promise "^0.7.1" -"@salesforce/core@^5.2.0", "@salesforce/core@^5.2.10", "@salesforce/core@^5.2.7", "@salesforce/core@^5.2.9": - version "5.2.10" - resolved "https://registry.yarnpkg.com/@salesforce/core/-/core-5.2.10.tgz#7f4824ddcef108b6ccec24434260c620de39012e" - integrity sha512-Xj1QRajmHWgl0ahivjKFGKJlGXwe9yFOZ3PwF91qEupGbO74XrCJ8OUM7EVlk53LKy9LlPZQFuy2ATX9MyEDKA== +"@salesforce/core@^5.2.0", "@salesforce/core@^5.2.10", "@salesforce/core@^5.2.7", "@salesforce/core@^5.2.9", "@salesforce/core@^5.3.4": + version "5.3.4" + resolved "https://registry.yarnpkg.com/@salesforce/core/-/core-5.3.4.tgz#bbf87238a4a6f31c07c8d01d4913c552fe0d0443" + integrity sha512-FV5QG0+W/15IaWtaZCxzAZ1K6bonlzkv5v9vuicH2VeEltruGUYYf8Bq7hkoul1xHk3Kl4+9cXx7aGp8Z0kGzQ== dependencies: - "@salesforce/kit" "^3.0.11" + "@salesforce/kit" "^3.0.12" "@salesforce/schemas" "^1.6.0" - "@salesforce/ts-types" "^2.0.7" + "@salesforce/ts-types" "^2.0.8" "@types/semver" "^7.5.2" ajv "^8.12.0" change-case "^4.1.2" @@ -953,12 +953,12 @@ typescript "^4.9.5" wireit "^0.9.5" -"@salesforce/kit@^3.0.11", "@salesforce/kit@^3.0.9": - version "3.0.11" - resolved "https://registry.yarnpkg.com/@salesforce/kit/-/kit-3.0.11.tgz#d03160b658da9817c05e62479ca18283087a0fc0" - integrity sha512-ar44uFJfc/RCDWjz7LlrOtFCFHgNNUpddxe0eJCLqQuR/Xs3IlLZKuovWTx322Rzu+V9IIKrIdpz2IqA95/ClA== +"@salesforce/kit@^3.0.11", "@salesforce/kit@^3.0.12", "@salesforce/kit@^3.0.9": + version "3.0.13" + resolved "https://registry.yarnpkg.com/@salesforce/kit/-/kit-3.0.13.tgz#10b47ad6e0e27c3a9f97eb6a5cdcfffa9ba1f163" + integrity sha512-HLQ5L5bBi0tsMeH5ZHJAhHUpvNUNPQoNJt2O82Jf6C60GGsrlzwzQ5ONAHGNBgKSZ7HLr0UGL5xaA+hE9uOcgw== dependencies: - "@salesforce/ts-types" "^2.0.7" + "@salesforce/ts-types" "^2.0.8" tslib "^2.6.2" "@salesforce/plugin-command-reference@^3.0.34": @@ -1056,10 +1056,10 @@ sinon "^5.1.1" tslib "^2.6.1" -"@salesforce/ts-types@^2.0.6", "@salesforce/ts-types@^2.0.7": - version "2.0.7" - resolved "https://registry.yarnpkg.com/@salesforce/ts-types/-/ts-types-2.0.7.tgz#02a6999d0b0e7bcd6c6d8ce621c79fa61af24701" - integrity sha512-8csXgstPuy6QXL3JavkIi/f8DOWHBNCvWeszrFu5sbVlcKO3YqOOCE+rDFGPkrZsYv5OywV6H8kEi877bWOz6Q== +"@salesforce/ts-types@^2.0.6", "@salesforce/ts-types@^2.0.7", "@salesforce/ts-types@^2.0.8": + version "2.0.8" + resolved "https://registry.yarnpkg.com/@salesforce/ts-types/-/ts-types-2.0.8.tgz#e732b5a42cbec6bda79c089a0633fc643daf8bca" + integrity sha512-vuzLcxtThBhpuhmnoh8GFrVU8XjdoNyQm9gPtmcjUyUD/9nQIBTAX8oGoUvCiiq93c4LFEmSua+xm3yu0bbNfg== dependencies: tslib "^2.6.2" @@ -1356,12 +1356,7 @@ dependencies: "@types/node" "*" -"@types/semver@^7.3.12": - version "7.5.0" - resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.0.tgz#591c1ce3a702c45ee15f47a42ade72c2fd78978a" - integrity sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw== - -"@types/semver@^7.5.2": +"@types/semver@^7.3.12", "@types/semver@^7.5.2": version "7.5.2" resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.2.tgz#31f6eec1ed7ec23f4f05608d3a2d381df041f564" integrity sha512-7aqorHYgdNO4DM36stTiGO3DvKoex9TQRwsJU6vMaFGyqpBA1MNZkz+PG3gaNUPpTAOYhT1WR7M1JyA3fbS9Cw== @@ -6042,15 +6037,7 @@ pify@^4.0.1: resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== -pino-abstract-transport@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/pino-abstract-transport/-/pino-abstract-transport-1.0.0.tgz#cc0d6955fffcadb91b7b49ef220a6cc111d48bb3" - integrity sha512-c7vo5OpW4wIS42hUVcT5REsL8ZljsUfBjqV/e2sFxmFEFZiq1XLUp5EYLtuDH6PEHq9W1egWqRbnLUP5FuZmOA== - dependencies: - readable-stream "^4.0.0" - split2 "^4.0.0" - -pino-abstract-transport@v1.1.0: +pino-abstract-transport@^1.0.0, pino-abstract-transport@v1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/pino-abstract-transport/-/pino-abstract-transport-1.1.0.tgz#083d98f966262164504afb989bccd05f665937a8" integrity sha512-lsleG3/2a/JIWUtf9Q5gUNErBqwIu1tUKTT3dUzaf5DySw9ra1wcqKjJjLX1VTY64Wk1eEOYsVGSaGfCK85ekA== From 24c60c53bcd8415a7ca98d834501c9a4c079f140 Mon Sep 17 00:00:00 2001 From: Cristian Dominguez Date: Wed, 4 Oct 2023 18:32:32 -0300 Subject: [PATCH 6/8] chore: dedupe lockfile --- yarn.lock | 26 +------------------------- 1 file changed, 1 insertion(+), 25 deletions(-) diff --git a/yarn.lock b/yarn.lock index 0d0b9c66..6a0522a7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -885,31 +885,7 @@ strip-ansi "6.0.1" ts-retry-promise "^0.7.1" -"@salesforce/core@^5.2.0", "@salesforce/core@^5.2.10", "@salesforce/core@^5.2.7", "@salesforce/core@^5.2.9", "@salesforce/core@^5.3.1": - version "5.3.2" - resolved "https://registry.yarnpkg.com/@salesforce/core/-/core-5.3.2.tgz#7c930bd1f2d69980b458bff1323379daf26f0a8f" - integrity sha512-PhaboMJkitqJsKrp+VfAHEp9/q57/n9zqKDdO7ML2qHb6oiRgxhyBWC9N02sOxPiFKreiKKSbR1tnsk40T+oAw== - dependencies: - "@salesforce/kit" "^3.0.12" - "@salesforce/schemas" "^1.6.0" - "@salesforce/ts-types" "^2.0.7" - "@types/semver" "^7.5.2" - ajv "^8.12.0" - change-case "^4.1.2" - faye "^1.4.0" - form-data "^4.0.0" - js2xmlparser "^4.0.1" - jsforce "^2.0.0-beta.27" - jsonwebtoken "9.0.2" - jszip "3.10.1" - pino "^8.15.1" - pino-abstract-transport "^1.0.0" - pino-pretty "^10.2.0" - proper-lockfile "^4.1.2" - semver "^7.5.4" - ts-retry-promise "^0.7.1" - -"@salesforce/core@^5.3.4": +"@salesforce/core@^5.2.0", "@salesforce/core@^5.2.10", "@salesforce/core@^5.2.7", "@salesforce/core@^5.2.9", "@salesforce/core@^5.3.1", "@salesforce/core@^5.3.4": version "5.3.4" resolved "https://registry.yarnpkg.com/@salesforce/core/-/core-5.3.4.tgz#bbf87238a4a6f31c07c8d01d4913c552fe0d0443" integrity sha512-FV5QG0+W/15IaWtaZCxzAZ1K6bonlzkv5v9vuicH2VeEltruGUYYf8Bq7hkoul1xHk3Kl4+9cXx7aGp8Z0kGzQ== From 1e34f35c3ad2de93c0dad71c73cdd9a21846b1ca Mon Sep 17 00:00:00 2001 From: Steve Hetzel Date: Thu, 5 Oct 2023 10:18:34 -0600 Subject: [PATCH 7/8] fix: remove event listeners in finally --- src/shared/sandboxCommandBase.ts | 14 ++++++++++++++ test/unit/org/createSandbox.test.ts | 23 ++++++++--------------- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/src/shared/sandboxCommandBase.ts b/src/shared/sandboxCommandBase.ts index a2f8e2fb..241641eb 100644 --- a/src/shared/sandboxCommandBase.ts +++ b/src/shared/sandboxCommandBase.ts @@ -225,6 +225,20 @@ export abstract class SandboxCommandBase extends SfCommand { } } + // eslint-disable-next-line @typescript-eslint/no-explicit-any + protected async finally(_: Error | undefined): Promise { + const lifecycle = Lifecycle.getInstance(); + lifecycle.removeAllListeners('POLLING_TIME_OUT'); + lifecycle.removeAllListeners(SandboxEvents.EVENT_RESUME); + lifecycle.removeAllListeners(SandboxEvents.EVENT_ASYNC_RESULT); + lifecycle.removeAllListeners(SandboxEvents.EVENT_STATUS); + lifecycle.removeAllListeners(SandboxEvents.EVENT_AUTH); + lifecycle.removeAllListeners(SandboxEvents.EVENT_RESULT); + lifecycle.removeAllListeners(SandboxEvents.EVENT_MULTIPLE_SBX_PROCESSES); + + return super.finally(_); + } + private removeSandboxProgressConfig(): void { if (this.latestSandboxProgressObj?.SandboxName) { this.sandboxRequestConfig.unset(this.latestSandboxProgressObj.SandboxName); diff --git a/test/unit/org/createSandbox.test.ts b/test/unit/org/createSandbox.test.ts index 43452541..d901c661 100644 --- a/test/unit/org/createSandbox.test.ts +++ b/test/unit/org/createSandbox.test.ts @@ -37,8 +37,6 @@ const fakeOrg: AuthFields = { describe('org:create:sandbox', () => { beforeEach(() => { - // stubMethod(sandbox, OrgAccessor.prototype, 'read').callsFake(async (): Promise => fakeOrg); - // stubMethod(sandbox, OrgAccessor.prototype, 'write').callsFake(async (): Promise => fakeOrg); stubMethod(sandbox, OrgAccessor.prototype, 'read').resolves(fakeOrg); stubMethod(sandbox, OrgAccessor.prototype, 'write').resolves(fakeOrg); sfCommandUxStubs = stubSfCommandUx(sandbox); @@ -53,23 +51,18 @@ describe('org:create:sandbox', () => { it('will print the correct message for asyncResult lifecycle event', async () => { stubMethod(sandbox, Org, 'create').resolves(Org.prototype); stubMethod(sandbox, Org.prototype, 'getUsername').returns('testProdOrg'); - const createStub = stubMethod(sandbox, Org.prototype, 'createSandbox').callsFake(async () => - (async () => {})().catch() - ); + const createStub = stubMethod(sandbox, Org.prototype, 'createSandbox').callsFake(async () => { + await Lifecycle.getInstance().emit(SandboxEvents.EVENT_ASYNC_RESULT, sandboxProcessObj); + }); await CreateSandbox.run(['-o', 'testProdOrg', '--name', 'mysandboxx', '--no-prompt']); - expect(createStub.firstCall.args[0].SandboxName).includes('mysandboxx'); - expect(createStub.firstCall.args[0].SandboxName.length).equals(10); - - Lifecycle.getInstance().on(SandboxEvents.EVENT_ASYNC_RESULT, async (result) => { - expect(result).to.deep.equal(sandboxProcessObj); - expect(sfCommandUxStubs.info.firstCall.firstArg).to.include(sandboxProcessObj.Id); - return Promise.resolve(); + expect(createStub.firstCall.firstArg).to.deep.equal({ + SandboxName: 'mysandboxx', + LicenseType: 'Developer', }); - - await Lifecycle.getInstance().emit(SandboxEvents.EVENT_ASYNC_RESULT, sandboxProcessObj); - Lifecycle.getInstance().removeAllListeners(SandboxEvents.EVENT_ASYNC_RESULT); + const expectedInfoMsg = `org resume sandbox --job-id ${sandboxProcessObj.Id} -o testProdOrg`; + expect(sfCommandUxStubs.info.firstCall.firstArg).to.include(expectedInfoMsg); }); }); From 1d5e3884a1af9df036c6dbc0702d318dbacb06d9 Mon Sep 17 00:00:00 2001 From: Steve Hetzel Date: Thu, 5 Oct 2023 11:11:43 -0600 Subject: [PATCH 8/8] fix: listener updates to not mutate sandbox process objects --- src/shared/sandboxCommandBase.ts | 13 +++++-------- test/tsconfig.json | 6 +----- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/src/shared/sandboxCommandBase.ts b/src/shared/sandboxCommandBase.ts index 241641eb..b3f7b548 100644 --- a/src/shared/sandboxCommandBase.ts +++ b/src/shared/sandboxCommandBase.ts @@ -152,16 +152,13 @@ export abstract class SandboxCommandBase extends SfCommand { }); lifecycle.on(SandboxEvents.EVENT_MULTIPLE_SBX_PROCESSES, async (results: SandboxProcessObject[]) => { - const resumingProcess = results.shift() as SandboxProcessObject; - const sbxProcessIds: string[] = []; - const sbxProcessStatuses: string[] = []; - results.map((sbxProc) => { - sbxProcessIds.push(sbxProc.Id); - sbxProcessStatuses.push(sbxProc.Status); - }); + const [resumingProcess, ...otherSbxProcesses] = results; + const sbxProcessIds = otherSbxProcesses.map((sbxProcess) => sbxProcess.Id); + const sbxProcessStatuses = otherSbxProcesses.map((sbxProcess) => sbxProcess.Status); + this.warn( messages.getMessage('warning.MultipleMatchingSandboxProcesses', [ - results[0].SandboxName, + otherSbxProcesses[0].SandboxName, sbxProcessIds.toString(), sbxProcessStatuses.toString(), resumingProcess.Id, diff --git a/test/tsconfig.json b/test/tsconfig.json index e629218b..526e989d 100644 --- a/test/tsconfig.json +++ b/test/tsconfig.json @@ -5,10 +5,6 @@ "skipLibCheck": true, "strictNullChecks": true, "baseUrl": "../", - "sourceMap": true, - "paths": { - "@salesforce/kit": ["node_modules/@salesforce/kit"], - "@salesforce/core": ["node_modules/@salesforce/core"] - } + "sourceMap": true } }