diff --git a/test/nightly/deployWorkspaceProject/buildParallelScenarios.ts b/test/nightly/deployWorkspaceProject/buildParallelScenarios.ts new file mode 100644 index 000000000..680b16b94 --- /dev/null +++ b/test/nightly/deployWorkspaceProject/buildParallelScenarios.ts @@ -0,0 +1,97 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See LICENSE.md in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { runWithTestActionContext } from "@microsoft/vscode-azext-dev"; +import * as assert from "assert"; +import * as path from "path"; +import { workspace, type Uri, type WorkspaceFolder } from "vscode"; +import { AzExtFsExtra, deployWorkspaceProject, dwpSettingUtilsV2, ext, parseError, settingUtils, type DeploymentConfigurationSettings, type DeployWorkspaceProjectResults, type IParsedError } from "../../../extension.bundle"; +import { assertStringPropsMatch, getWorkspaceFolderUri } from "../../testUtils"; +import { resourceGroupsToDelete } from "../global.nightly.test"; +import { dwpTestScenarios, type DeployWorkspaceProjectTestScenario } from "./dwpTestScenarios"; + +export interface DwpParallelTestScenario { + title: string; + callback(setupTask: Promise): Promise; + scenario?: Promise; +} + +export function buildParallelTestScenarios(): DwpParallelTestScenario[] { + return dwpTestScenarios.map(scenario => { + return { + title: scenario.label, + callback: buildParallelScenarioCallback(scenario), + }; + }); +} + +function buildParallelScenarioCallback(scenario: DeployWorkspaceProjectTestScenario): DwpParallelTestScenario['callback'] { + return async (setupTask: Promise) => { + await setupTask; + + const workspaceFolderUri: Uri = getWorkspaceFolderUri(scenario.folderName); + const rootFolder: WorkspaceFolder | undefined = workspace.getWorkspaceFolder(workspaceFolderUri); + assert.ok(rootFolder, 'Could not retrieve root workspace folder.'); + + await cleanWorkspaceFolderSettings(rootFolder); + + for (const testCase of scenario.testCases) { + ext.outputChannel.appendLog(`[[[ *** ${scenario.label} - ${testCase.label} *** ]]]`); + await runWithTestActionContext('deployWorkspaceProject', async context => { + await context.ui.runWithInputs(testCase.inputs, async () => { + let results: DeployWorkspaceProjectResults; + let perr: IParsedError | undefined; + try { + results = await deployWorkspaceProject(context); + } catch (e) { + results = {}; + + perr = parseError(e); + console.log(perr); + } + + if (testCase.resourceGroupToDelete) { + resourceGroupsToDelete.add(testCase.resourceGroupToDelete); + } + + // Verify 'expectedErrMsg' + if (perr || testCase.expectedErrMsg) { + if (testCase.expectedErrMsg instanceof RegExp) { + assert.match(perr?.message ?? "", testCase.expectedErrMsg, 'DeployWorkspaceProject thrown and expected error message did not match.'); + } else { + assert.strictEqual(perr?.message ?? "", testCase.expectedErrMsg, 'DeployWorkspaceProject thrown and expected error message did not match.'); + } + } + + // Verify 'expectedResults' + assertStringPropsMatch(results as Partial>, (testCase.expectedResults ?? {}) as Record, 'DeployWorkspaceProject results mismatch.'); + + // Verify 'expectedVSCodeSettings' + const deploymentConfigurationsV2: DeploymentConfigurationSettings[] = await dwpSettingUtilsV2.getWorkspaceDeploymentConfigurations(rootFolder) ?? []; + const expectedDeploymentConfigurations = testCase.expectedVSCodeSettings?.deploymentConfigurations ?? []; + assert.strictEqual(deploymentConfigurationsV2.length, expectedDeploymentConfigurations.length, 'DeployWorkspaceProject ".vscode" saved settings mismatch.'); + + for (const [i, expectedDeploymentConfiguration] of expectedDeploymentConfigurations.entries()) { + const deploymentConfiguration: DeploymentConfigurationSettings = deploymentConfigurationsV2[i] ?? {}; + assertStringPropsMatch(deploymentConfiguration as Partial>, expectedDeploymentConfiguration, 'DeployWorkspaceProject ".vscode" saved settings mismatch.'); + } + + // Verify 'postTestAssertion' + await testCase.postTestAssertion?.(context, results, 'DeployWorkspaceProject resource settings mismatch.'); + }); + }); + } + + await cleanWorkspaceFolderSettings(rootFolder); + } +} + +async function cleanWorkspaceFolderSettings(rootFolder: WorkspaceFolder) { + const settingsPath: string = settingUtils.getDefaultRootWorkspaceSettingsPath(rootFolder); + const vscodeFolderPath: string = path.dirname(settingsPath); + if (await AzExtFsExtra.pathExists(vscodeFolderPath)) { + await AzExtFsExtra.deleteResource(vscodeFolderPath, { recursive: true }); + } +} diff --git a/test/nightly/deployWorkspaceProject/deployWorkspaceProject.test.ts b/test/nightly/deployWorkspaceProject/deployWorkspaceProject.test.ts index e840da5ac..86a5d5246 100644 --- a/test/nightly/deployWorkspaceProject/deployWorkspaceProject.test.ts +++ b/test/nightly/deployWorkspaceProject/deployWorkspaceProject.test.ts @@ -3,19 +3,19 @@ * Licensed under the MIT License. See LICENSE.md in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { type ManagedEnvironment } from '@azure/arm-appcontainers'; -import { runWithTestActionContext } from '@microsoft/vscode-azext-dev'; -import { nonNullProp, parseError, randomUtils, type IParsedError } from "@microsoft/vscode-azext-utils"; -import * as assert from 'assert'; -import * as path from 'path'; -import { workspace, type Uri, type WorkspaceFolder } from 'vscode'; -import { AzExtFsExtra, createManagedEnvironment, deployWorkspaceProject, dwpSettingUtilsV2, settingUtils, type DeploymentConfigurationSettings, type DeployWorkspaceProjectResults } from '../../../extension.bundle'; +import { type ManagedEnvironment } from "@azure/arm-appcontainers"; +import { runWithTestActionContext } from "@microsoft/vscode-azext-dev"; +import { nonNullProp, randomUtils } from "@microsoft/vscode-azext-utils"; +import * as assert from "assert"; +import { createManagedEnvironment } from "../../../extension.bundle"; import { longRunningTestsEnabled } from '../../global.test'; -import { assertStringPropsMatch, getWorkspaceFolderUri } from '../../testUtils'; -import { resourceGroupsToDelete } from '../global.nightly.test'; -import { dwpTestScenarios } from './dwpTestScenarios'; +import { resourceGroupsToDelete } from "../global.nightly.test"; +import { buildParallelTestScenarios, type DwpParallelTestScenario } from './buildParallelScenarios'; -suite('deployWorkspaceProject', function (this: Mocha.Suite) { +let setupTask: Promise; +const testScenarios: DwpParallelTestScenario[] = buildParallelTestScenarios(); + +suite('deployWorkspaceProject', async function (this: Mocha.Suite) { this.timeout(15 * 60 * 1000); suiteSetup(async function (this: Mocha.Context) { @@ -26,89 +26,33 @@ suite('deployWorkspaceProject', function (this: Mocha.Suite) { // Create a managed environment first so that we can guarantee one is always built before workspace deployment tests start. // This is crucial for test consistency because the managed environment prompt will skip if no managed environment // resources are available yet. Creating at least one environment first ensures consistent reproduceability. - const managedEnvironment: ManagedEnvironment | undefined = await setupManagedEnvironment(); - assert.ok(managedEnvironment, 'Failed to create managed environment - skipping "deployWorkspaceProject" tests.'); - resourceGroupsToDelete.add(nonNullProp(managedEnvironment, 'name')); - }); - - for (const scenario of dwpTestScenarios) { - suite(scenario.label, function () { - const workspaceFolderUri: Uri = getWorkspaceFolderUri(scenario.folderName); - const rootFolder: WorkspaceFolder | undefined = workspace.getWorkspaceFolder(workspaceFolderUri); - assert.ok(rootFolder, 'Could not retrieve root workspace folder.'); - - suiteSetup(getMethodCleanWorkspaceFolderSettings(rootFolder)); - suiteTeardown(getMethodCleanWorkspaceFolderSettings(rootFolder)); - - for (const testCase of scenario.testCases) { - test(testCase.label, async function () { - await runWithTestActionContext('deployWorkspaceProject', async context => { - await context.ui.runWithInputs(testCase.inputs, async () => { - let results: DeployWorkspaceProjectResults; - let perr: IParsedError | undefined; - try { - results = await deployWorkspaceProject(context); - } catch (e) { - results = {}; - - perr = parseError(e); - console.log(perr); - } - - if (testCase.resourceGroupToDelete) { - resourceGroupsToDelete.add(testCase.resourceGroupToDelete); - } - - // Verify 'expectedErrMsg' - if (perr || testCase.expectedErrMsg) { - if (testCase.expectedErrMsg instanceof RegExp) { - assert.match(perr?.message ?? "", testCase.expectedErrMsg, 'DeployWorkspaceProject thrown and expected error message did not match.'); - } else { - assert.strictEqual(perr?.message ?? "", testCase.expectedErrMsg, 'DeployWorkspaceProject thrown and expected error message did not match.'); - } - } - - // Verify 'expectedResults' - assertStringPropsMatch(results as Partial>, (testCase.expectedResults ?? {}) as Record, 'DeployWorkspaceProject results mismatch.'); + setupTask = setupManagedEnvironment(); - // Verify 'expectedVSCodeSettings' - const deploymentConfigurationsV2: DeploymentConfigurationSettings[] = await dwpSettingUtilsV2.getWorkspaceDeploymentConfigurations(rootFolder) ?? []; - const expectedDeploymentConfigurations = testCase.expectedVSCodeSettings?.deploymentConfigurations ?? []; - assert.strictEqual(deploymentConfigurationsV2.length, expectedDeploymentConfigurations.length, 'DeployWorkspaceProject ".vscode" saved settings mismatch.'); - - for (const [i, expectedDeploymentConfiguration] of expectedDeploymentConfigurations.entries()) { - const deploymentConfiguration: DeploymentConfigurationSettings = deploymentConfigurationsV2[i] ?? {}; - assertStringPropsMatch(deploymentConfiguration as Partial>, expectedDeploymentConfiguration, 'DeployWorkspaceProject ".vscode" saved settings mismatch.'); - } + for (const s of testScenarios) { + s.scenario = s.callback(setupTask); + } + }); - // Verify 'postTestAssertion' - await testCase.postTestAssertion?.(context, results, 'DeployWorkspaceProject resource settings mismatch.'); - }); - }); - }); - } + for (const s of testScenarios) { + test(s.title, async function () { + await nonNullProp(s, 'scenario'); }); } }); -async function setupManagedEnvironment(): Promise { +async function setupManagedEnvironment(): Promise { let managedEnvironment: ManagedEnvironment | undefined; - await runWithTestActionContext('createManagedEnvironment', async context => { - const resourceName: string = 'dwp' + randomUtils.getRandomHexString(6); - await context.ui.runWithInputs([resourceName, 'East US'], async () => { - managedEnvironment = await createManagedEnvironment(context); + try { + await runWithTestActionContext('createManagedEnvironment', async context => { + const resourceName: string = 'dwp' + randomUtils.getRandomHexString(6); + await context.ui.runWithInputs([resourceName, 'East US'], async () => { + managedEnvironment = await createManagedEnvironment(context); + }); }); - }); - return managedEnvironment; -} - -function getMethodCleanWorkspaceFolderSettings(rootFolder: WorkspaceFolder) { - return async function cleanWorkspaceFolderSettings(): Promise { - const settingsPath: string = settingUtils.getDefaultRootWorkspaceSettingsPath(rootFolder); - const vscodeFolderPath: string = path.dirname(settingsPath); - if (await AzExtFsExtra.pathExists(vscodeFolderPath)) { - await AzExtFsExtra.deleteResource(vscodeFolderPath, { recursive: true }); - } + } catch (e) { + console.error(e); } -} + assert.ok(managedEnvironment, 'Failed to create managed environment - skipping "deployWorkspaceProject" tests.'); + resourceGroupsToDelete.add(nonNullProp(managedEnvironment, 'name')); +} diff --git a/test/nightly/deployWorkspaceProject/dwpTestScenarios.ts b/test/nightly/deployWorkspaceProject/dwpTestScenarios.ts index 09abd8980..38e0643fe 100644 --- a/test/nightly/deployWorkspaceProject/dwpTestScenarios.ts +++ b/test/nightly/deployWorkspaceProject/dwpTestScenarios.ts @@ -7,7 +7,7 @@ import { generateAlbumApiJavaScriptTestCases } from "./testCases/albumApiJavaScr import { type DeployWorkspaceProjectTestCase } from "./testCases/DeployWorkspaceProjectTestCase"; import { generateMonoRepoBasicTestCases } from "./testCases/monoRepoBasicTestCases"; -interface DeployWorkspaceProjectTestScenario { +export interface DeployWorkspaceProjectTestScenario { label: string; folderName: string; testCases: DeployWorkspaceProjectTestCase[];