Skip to content

Commit 874ff43

Browse files
authored
Setup workspace project tests to run in parallel (#788)
1 parent 05bee27 commit 874ff43

File tree

3 files changed

+129
-88
lines changed

3 files changed

+129
-88
lines changed
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See LICENSE.md in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import { runWithTestActionContext } from "@microsoft/vscode-azext-dev";
7+
import * as assert from "assert";
8+
import * as path from "path";
9+
import { workspace, type Uri, type WorkspaceFolder } from "vscode";
10+
import { AzExtFsExtra, deployWorkspaceProject, dwpSettingUtilsV2, ext, parseError, settingUtils, type DeploymentConfigurationSettings, type DeployWorkspaceProjectResults, type IParsedError } from "../../../extension.bundle";
11+
import { assertStringPropsMatch, getWorkspaceFolderUri } from "../../testUtils";
12+
import { resourceGroupsToDelete } from "../global.nightly.test";
13+
import { dwpTestScenarios, type DeployWorkspaceProjectTestScenario } from "./dwpTestScenarios";
14+
15+
export interface DwpParallelTestScenario {
16+
title: string;
17+
callback(setupTask: Promise<void>): Promise<void>;
18+
scenario?: Promise<void>;
19+
}
20+
21+
export function buildParallelTestScenarios(): DwpParallelTestScenario[] {
22+
return dwpTestScenarios.map(scenario => {
23+
return {
24+
title: scenario.label,
25+
callback: buildParallelScenarioCallback(scenario),
26+
};
27+
});
28+
}
29+
30+
function buildParallelScenarioCallback(scenario: DeployWorkspaceProjectTestScenario): DwpParallelTestScenario['callback'] {
31+
return async (setupTask: Promise<void>) => {
32+
await setupTask;
33+
34+
const workspaceFolderUri: Uri = getWorkspaceFolderUri(scenario.folderName);
35+
const rootFolder: WorkspaceFolder | undefined = workspace.getWorkspaceFolder(workspaceFolderUri);
36+
assert.ok(rootFolder, 'Could not retrieve root workspace folder.');
37+
38+
await cleanWorkspaceFolderSettings(rootFolder);
39+
40+
for (const testCase of scenario.testCases) {
41+
ext.outputChannel.appendLog(`[[[ *** ${scenario.label} - ${testCase.label} *** ]]]`);
42+
await runWithTestActionContext('deployWorkspaceProject', async context => {
43+
await context.ui.runWithInputs(testCase.inputs, async () => {
44+
let results: DeployWorkspaceProjectResults;
45+
let perr: IParsedError | undefined;
46+
try {
47+
results = await deployWorkspaceProject(context);
48+
} catch (e) {
49+
results = {};
50+
51+
perr = parseError(e);
52+
console.log(perr);
53+
}
54+
55+
if (testCase.resourceGroupToDelete) {
56+
resourceGroupsToDelete.add(testCase.resourceGroupToDelete);
57+
}
58+
59+
// Verify 'expectedErrMsg'
60+
if (perr || testCase.expectedErrMsg) {
61+
if (testCase.expectedErrMsg instanceof RegExp) {
62+
assert.match(perr?.message ?? "", testCase.expectedErrMsg, 'DeployWorkspaceProject thrown and expected error message did not match.');
63+
} else {
64+
assert.strictEqual(perr?.message ?? "", testCase.expectedErrMsg, 'DeployWorkspaceProject thrown and expected error message did not match.');
65+
}
66+
}
67+
68+
// Verify 'expectedResults'
69+
assertStringPropsMatch(results as Partial<Record<string, string>>, (testCase.expectedResults ?? {}) as Record<string, string | RegExp>, 'DeployWorkspaceProject results mismatch.');
70+
71+
// Verify 'expectedVSCodeSettings'
72+
const deploymentConfigurationsV2: DeploymentConfigurationSettings[] = await dwpSettingUtilsV2.getWorkspaceDeploymentConfigurations(rootFolder) ?? [];
73+
const expectedDeploymentConfigurations = testCase.expectedVSCodeSettings?.deploymentConfigurations ?? [];
74+
assert.strictEqual(deploymentConfigurationsV2.length, expectedDeploymentConfigurations.length, 'DeployWorkspaceProject ".vscode" saved settings mismatch.');
75+
76+
for (const [i, expectedDeploymentConfiguration] of expectedDeploymentConfigurations.entries()) {
77+
const deploymentConfiguration: DeploymentConfigurationSettings = deploymentConfigurationsV2[i] ?? {};
78+
assertStringPropsMatch(deploymentConfiguration as Partial<Record<string, string>>, expectedDeploymentConfiguration, 'DeployWorkspaceProject ".vscode" saved settings mismatch.');
79+
}
80+
81+
// Verify 'postTestAssertion'
82+
await testCase.postTestAssertion?.(context, results, 'DeployWorkspaceProject resource settings mismatch.');
83+
});
84+
});
85+
}
86+
87+
await cleanWorkspaceFolderSettings(rootFolder);
88+
}
89+
}
90+
91+
async function cleanWorkspaceFolderSettings(rootFolder: WorkspaceFolder) {
92+
const settingsPath: string = settingUtils.getDefaultRootWorkspaceSettingsPath(rootFolder);
93+
const vscodeFolderPath: string = path.dirname(settingsPath);
94+
if (await AzExtFsExtra.pathExists(vscodeFolderPath)) {
95+
await AzExtFsExtra.deleteResource(vscodeFolderPath, { recursive: true });
96+
}
97+
}

test/nightly/deployWorkspaceProject/deployWorkspaceProject.test.ts

Lines changed: 31 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,19 @@
33
* Licensed under the MIT License. See LICENSE.md in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
55

6-
import { type ManagedEnvironment } from '@azure/arm-appcontainers';
7-
import { runWithTestActionContext } from '@microsoft/vscode-azext-dev';
8-
import { nonNullProp, parseError, randomUtils, type IParsedError } from "@microsoft/vscode-azext-utils";
9-
import * as assert from 'assert';
10-
import * as path from 'path';
11-
import { workspace, type Uri, type WorkspaceFolder } from 'vscode';
12-
import { AzExtFsExtra, createManagedEnvironment, deployWorkspaceProject, dwpSettingUtilsV2, settingUtils, type DeploymentConfigurationSettings, type DeployWorkspaceProjectResults } from '../../../extension.bundle';
6+
import { type ManagedEnvironment } from "@azure/arm-appcontainers";
7+
import { runWithTestActionContext } from "@microsoft/vscode-azext-dev";
8+
import { nonNullProp, randomUtils } from "@microsoft/vscode-azext-utils";
9+
import * as assert from "assert";
10+
import { createManagedEnvironment } from "../../../extension.bundle";
1311
import { longRunningTestsEnabled } from '../../global.test';
14-
import { assertStringPropsMatch, getWorkspaceFolderUri } from '../../testUtils';
15-
import { resourceGroupsToDelete } from '../global.nightly.test';
16-
import { dwpTestScenarios } from './dwpTestScenarios';
12+
import { resourceGroupsToDelete } from "../global.nightly.test";
13+
import { buildParallelTestScenarios, type DwpParallelTestScenario } from './buildParallelScenarios';
1714

18-
suite('deployWorkspaceProject', function (this: Mocha.Suite) {
15+
let setupTask: Promise<void>;
16+
const testScenarios: DwpParallelTestScenario[] = buildParallelTestScenarios();
17+
18+
suite('deployWorkspaceProject', async function (this: Mocha.Suite) {
1919
this.timeout(15 * 60 * 1000);
2020

2121
suiteSetup(async function (this: Mocha.Context) {
@@ -26,89 +26,33 @@ suite('deployWorkspaceProject', function (this: Mocha.Suite) {
2626
// Create a managed environment first so that we can guarantee one is always built before workspace deployment tests start.
2727
// This is crucial for test consistency because the managed environment prompt will skip if no managed environment
2828
// resources are available yet. Creating at least one environment first ensures consistent reproduceability.
29-
const managedEnvironment: ManagedEnvironment | undefined = await setupManagedEnvironment();
30-
assert.ok(managedEnvironment, 'Failed to create managed environment - skipping "deployWorkspaceProject" tests.');
31-
resourceGroupsToDelete.add(nonNullProp(managedEnvironment, 'name'));
32-
});
33-
34-
for (const scenario of dwpTestScenarios) {
35-
suite(scenario.label, function () {
36-
const workspaceFolderUri: Uri = getWorkspaceFolderUri(scenario.folderName);
37-
const rootFolder: WorkspaceFolder | undefined = workspace.getWorkspaceFolder(workspaceFolderUri);
38-
assert.ok(rootFolder, 'Could not retrieve root workspace folder.');
39-
40-
suiteSetup(getMethodCleanWorkspaceFolderSettings(rootFolder));
41-
suiteTeardown(getMethodCleanWorkspaceFolderSettings(rootFolder));
42-
43-
for (const testCase of scenario.testCases) {
44-
test(testCase.label, async function () {
45-
await runWithTestActionContext('deployWorkspaceProject', async context => {
46-
await context.ui.runWithInputs(testCase.inputs, async () => {
47-
let results: DeployWorkspaceProjectResults;
48-
let perr: IParsedError | undefined;
49-
try {
50-
results = await deployWorkspaceProject(context);
51-
} catch (e) {
52-
results = {};
53-
54-
perr = parseError(e);
55-
console.log(perr);
56-
}
57-
58-
if (testCase.resourceGroupToDelete) {
59-
resourceGroupsToDelete.add(testCase.resourceGroupToDelete);
60-
}
61-
62-
// Verify 'expectedErrMsg'
63-
if (perr || testCase.expectedErrMsg) {
64-
if (testCase.expectedErrMsg instanceof RegExp) {
65-
assert.match(perr?.message ?? "", testCase.expectedErrMsg, 'DeployWorkspaceProject thrown and expected error message did not match.');
66-
} else {
67-
assert.strictEqual(perr?.message ?? "", testCase.expectedErrMsg, 'DeployWorkspaceProject thrown and expected error message did not match.');
68-
}
69-
}
70-
71-
// Verify 'expectedResults'
72-
assertStringPropsMatch(results as Partial<Record<string, string>>, (testCase.expectedResults ?? {}) as Record<string, string | RegExp>, 'DeployWorkspaceProject results mismatch.');
29+
setupTask = setupManagedEnvironment();
7330

74-
// Verify 'expectedVSCodeSettings'
75-
const deploymentConfigurationsV2: DeploymentConfigurationSettings[] = await dwpSettingUtilsV2.getWorkspaceDeploymentConfigurations(rootFolder) ?? [];
76-
const expectedDeploymentConfigurations = testCase.expectedVSCodeSettings?.deploymentConfigurations ?? [];
77-
assert.strictEqual(deploymentConfigurationsV2.length, expectedDeploymentConfigurations.length, 'DeployWorkspaceProject ".vscode" saved settings mismatch.');
78-
79-
for (const [i, expectedDeploymentConfiguration] of expectedDeploymentConfigurations.entries()) {
80-
const deploymentConfiguration: DeploymentConfigurationSettings = deploymentConfigurationsV2[i] ?? {};
81-
assertStringPropsMatch(deploymentConfiguration as Partial<Record<string, string>>, expectedDeploymentConfiguration, 'DeployWorkspaceProject ".vscode" saved settings mismatch.');
82-
}
31+
for (const s of testScenarios) {
32+
s.scenario = s.callback(setupTask);
33+
}
34+
});
8335

84-
// Verify 'postTestAssertion'
85-
await testCase.postTestAssertion?.(context, results, 'DeployWorkspaceProject resource settings mismatch.');
86-
});
87-
});
88-
});
89-
}
36+
for (const s of testScenarios) {
37+
test(s.title, async function () {
38+
await nonNullProp(s, 'scenario');
9039
});
9140
}
9241
});
9342

94-
async function setupManagedEnvironment(): Promise<ManagedEnvironment | undefined> {
43+
async function setupManagedEnvironment(): Promise<void> {
9544
let managedEnvironment: ManagedEnvironment | undefined;
96-
await runWithTestActionContext('createManagedEnvironment', async context => {
97-
const resourceName: string = 'dwp' + randomUtils.getRandomHexString(6);
98-
await context.ui.runWithInputs([resourceName, 'East US'], async () => {
99-
managedEnvironment = await createManagedEnvironment(context);
45+
try {
46+
await runWithTestActionContext('createManagedEnvironment', async context => {
47+
const resourceName: string = 'dwp' + randomUtils.getRandomHexString(6);
48+
await context.ui.runWithInputs([resourceName, 'East US'], async () => {
49+
managedEnvironment = await createManagedEnvironment(context);
50+
});
10051
});
101-
});
102-
return managedEnvironment;
103-
}
104-
105-
function getMethodCleanWorkspaceFolderSettings(rootFolder: WorkspaceFolder) {
106-
return async function cleanWorkspaceFolderSettings(): Promise<void> {
107-
const settingsPath: string = settingUtils.getDefaultRootWorkspaceSettingsPath(rootFolder);
108-
const vscodeFolderPath: string = path.dirname(settingsPath);
109-
if (await AzExtFsExtra.pathExists(vscodeFolderPath)) {
110-
await AzExtFsExtra.deleteResource(vscodeFolderPath, { recursive: true });
111-
}
52+
} catch (e) {
53+
console.error(e);
11254
}
113-
}
11455

56+
assert.ok(managedEnvironment, 'Failed to create managed environment - skipping "deployWorkspaceProject" tests.');
57+
resourceGroupsToDelete.add(nonNullProp(managedEnvironment, 'name'));
58+
}

test/nightly/deployWorkspaceProject/dwpTestScenarios.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { generateAlbumApiJavaScriptTestCases } from "./testCases/albumApiJavaScr
77
import { type DeployWorkspaceProjectTestCase } from "./testCases/DeployWorkspaceProjectTestCase";
88
import { generateMonoRepoBasicTestCases } from "./testCases/monoRepoBasicTestCases";
99

10-
interface DeployWorkspaceProjectTestScenario {
10+
export interface DeployWorkspaceProjectTestScenario {
1111
label: string;
1212
folderName: string;
1313
testCases: DeployWorkspaceProjectTestCase[];

0 commit comments

Comments
 (0)