Skip to content

Commit 82ee194

Browse files
authored
Fix long running tests in support of migration to esbuild (#1081)
1 parent 7eab894 commit 82ee194

14 files changed

Lines changed: 343 additions & 90 deletions

src/commands/api/createContainerAppsApiProvider.ts

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,11 @@
55

66
import { callWithTelemetryAndErrorHandling, createApiProvider, maskUserInfo, type apiUtils, type IActionContext } from "@microsoft/vscode-azext-utils";
77
import { prepareAzureResourcesApiRequest, type AzureResourcesApiRequestContext, type AzureResourcesApiRequestError } from "@microsoft/vscode-azureresources-api";
8+
import * as api from "../../commands/api/vscode-azurecontainerapps.api";
89
import { ext } from "../../extensionVariables";
910
import { localize } from "../../utils/localize";
10-
import { deployImageApi } from "./deployImageApi";
11-
import { deployWorkspaceProjectApi } from "./deployWorkspaceProjectApi";
12-
import type * as api from "./vscode-azurecontainerapps.api";
1311

14-
export function createContainerAppsApiProvider(registerBranchResources: AzureResourcesApiRequestContext["onDidReceiveAzureResourcesApis"]): apiUtils.AzureExtensionApiProvider {
12+
export function createContainerAppsApiProvider(registerBranchResources: AzureResourcesApiRequestContext["onDidReceiveAzureResourcesApis"], coreExtensionApi: api.AzureContainerAppsExtensionApi): apiUtils.AzureExtensionApiProvider {
1513
const context: AzureResourcesApiRequestContext = {
1614
azureResourcesApiVersions: ['^2.0.0'],
1715
clientExtensionId: ext.context.extension.id,
@@ -27,13 +25,7 @@ export function createContainerAppsApiProvider(registerBranchResources: AzureRes
2725
},
2826
};
2927

30-
const containerAppsApi: api.AzureContainerAppsExtensionApi = {
31-
apiVersion: '1.1.0',
32-
deployImage: deployImageApi,
33-
deployWorkspaceProject: deployWorkspaceProjectApi,
34-
};
35-
36-
const { clientApi, requestResourcesApis } = prepareAzureResourcesApiRequest(context, containerAppsApi);
28+
const { clientApi, requestResourcesApis } = prepareAzureResourcesApiRequest(context, coreExtensionApi);
3729
requestResourcesApis();
3830
return createApiProvider([clientApi]);
3931
}

src/commands/api/deployWorkspaceProjectApi.ts

Lines changed: 46 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -21,55 +21,59 @@ import type * as api from "./vscode-azurecontainerapps.api";
2121
export async function deployWorkspaceProjectApi(deployWorkspaceProjectOptions: api.DeployWorkspaceProjectOptionsContract): Promise<DeployWorkspaceProjectResults> {
2222
return await callWithTelemetryAndErrorHandling('containerApps.api.deployWorkspaceProject', async (context: IActionContext): Promise<DeployWorkspaceProjectResults> => {
2323
context.errorHandling.rethrow = true;
24+
return await deployWorkspaceProjectApiInternal(context, deployWorkspaceProjectOptions);
25+
}) ?? {};
26+
}
2427

25-
const {
26-
resourceGroupId,
27-
location,
28-
rootPath,
29-
dockerfilePath,
30-
srcPath,
31-
suppressConfirmation,
32-
suppressContainerAppCreation,
33-
shouldSaveDeploySettings
34-
} = deployWorkspaceProjectOptions;
28+
// Separated from `deployWorkspaceProjectApi` so tests can inject their own test action context
29+
export async function deployWorkspaceProjectApiInternal(context: IActionContext, deployWorkspaceProjectOptions: api.DeployWorkspaceProjectOptionsContract): Promise<DeployWorkspaceProjectResults> {
30+
const {
31+
resourceGroupId,
32+
location,
33+
rootPath,
34+
dockerfilePath,
35+
srcPath,
36+
suppressConfirmation,
37+
suppressContainerAppCreation,
38+
shouldSaveDeploySettings
39+
} = deployWorkspaceProjectOptions;
3540

36-
const subscription: AzureSubscription = await subscriptionExperience(context, ext.rgApiV2.resources.azureResourceTreeDataProvider, {
37-
selectBySubscriptionId: getSubscriptionIdFromOptions(deployWorkspaceProjectOptions),
38-
showLoadingPrompt: false
39-
});
40-
const subscriptionContext: ISubscriptionContext = createSubscriptionContext(subscription);
41+
const subscription: AzureSubscription = await subscriptionExperience(context, ext.rgApiV2.resources.azureResourceTreeDataProvider, {
42+
selectBySubscriptionId: getSubscriptionIdFromOptions(deployWorkspaceProjectOptions),
43+
showLoadingPrompt: false
44+
});
45+
const subscriptionContext: ISubscriptionContext = createSubscriptionContext(subscription);
4146

42-
const rootFolder: WorkspaceFolder | undefined = rootPath ? getWorkspaceFolderFromPath(rootPath) : undefined;
43-
const resourceGroup: ResourceGroup | undefined = resourceGroupId ? await getResourceGroupFromId({ ...context, ...subscriptionContext }, resourceGroupId) : undefined;
47+
const rootFolder: WorkspaceFolder | undefined = rootPath ? getWorkspaceFolderFromPath(rootPath) : undefined;
48+
const resourceGroup: ResourceGroup | undefined = resourceGroupId ? await getResourceGroupFromId({ ...context, ...subscriptionContext }, resourceGroupId) : undefined;
4449

45-
const deployWorkspaceProjectInternalContext: DeployWorkspaceProjectInternalContext = Object.assign(context, {
46-
...subscriptionContext,
47-
subscription,
48-
resourceGroup,
49-
newManagedEnvironmentName: await tryGetNewManagedEnvironmentName({ ...context, ...subscriptionContext }, resourceGroup?.name, resourceGroup?.name),
50-
rootFolder,
51-
srcPath: srcPath ? Uri.file(srcPath).fsPath : undefined,
52-
dockerfilePath: dockerfilePath ? Uri.file(dockerfilePath).fsPath : undefined,
53-
newRegistryCredentialType: RegistryCredentialType.DockerLogin,
54-
shouldSaveDeploySettings: !!shouldSaveDeploySettings,
55-
});
50+
const deployWorkspaceProjectInternalContext: DeployWorkspaceProjectInternalContext = Object.assign(context, {
51+
...subscriptionContext,
52+
subscription,
53+
resourceGroup,
54+
newManagedEnvironmentName: await tryGetNewManagedEnvironmentName({ ...context, ...subscriptionContext }, resourceGroup?.name, resourceGroup?.name),
55+
rootFolder,
56+
srcPath: srcPath ? Uri.file(srcPath).fsPath : undefined,
57+
dockerfilePath: dockerfilePath ? Uri.file(dockerfilePath).fsPath : undefined,
58+
newRegistryCredentialType: RegistryCredentialType.DockerLogin,
59+
shouldSaveDeploySettings: !!shouldSaveDeploySettings,
60+
});
5661

57-
if (location || deployWorkspaceProjectInternalContext.resourceGroup) {
58-
const autoSelectLocation = location ?? nonNullValueAndProp(deployWorkspaceProjectInternalContext.resourceGroup, 'location');
59-
await LocationListStep.setAutoSelectLocation(deployWorkspaceProjectInternalContext, autoSelectLocation);
60-
}
62+
if (location || deployWorkspaceProjectInternalContext.resourceGroup) {
63+
const autoSelectLocation = location ?? nonNullValueAndProp(deployWorkspaceProjectInternalContext.resourceGroup, 'location');
64+
await LocationListStep.setAutoSelectLocation(deployWorkspaceProjectInternalContext, autoSelectLocation);
65+
}
6166

62-
const deployWorkspaceProjectContext: DeployWorkspaceProjectContext = await deployWorkspaceProjectInternal(deployWorkspaceProjectInternalContext, {
63-
advancedCreate: false,
64-
suppressActivity: true,
65-
suppressConfirmation,
66-
suppressContainerAppCreation,
67-
suppressProgress: true,
68-
suppressWizardTitle: true,
69-
});
67+
const deployWorkspaceProjectContext: DeployWorkspaceProjectContext = await deployWorkspaceProjectInternal(deployWorkspaceProjectInternalContext, {
68+
advancedCreate: false,
69+
suppressActivity: true,
70+
suppressConfirmation,
71+
suppressContainerAppCreation,
72+
suppressProgress: true,
73+
suppressWizardTitle: true,
74+
});
7075

71-
return await getDeployWorkspaceProjectResults(deployWorkspaceProjectContext);
72-
}) ?? {};
76+
return await getDeployWorkspaceProjectResults(deployWorkspaceProjectContext);
7377
}
7478

7579
async function tryGetNewManagedEnvironmentName(context: ISubscriptionActionContext, resourceGroupName?: string, newEnvironmentName?: string): Promise<string | undefined> {

src/commands/createContainerApp/ContainerAppListStep.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import { type ContainerApp, type ContainerAppsAPIClient } from "@azure/arm-appcontainers";
77
import { LocationListStep, parseAzureResourceId, ResourceGroupListStep, uiUtils } from "@microsoft/vscode-azext-azureutils";
8-
import { AzureWizardPromptStep, nonNullProp, nonNullValueAndProp, type AzureWizardExecuteStep, type ConfirmationViewProperty, type IAzureQuickPickItem, type IWizardOptions } from "@microsoft/vscode-azext-utils";
8+
import { AzureWizardPromptStep, nonNullProp, type AzureWizardExecuteStep, type ConfirmationViewProperty, type IAzureQuickPickItem, type IWizardOptions } from "@microsoft/vscode-azext-utils";
99
import { containerAppProvider, containerAppResourceType } from "../../constants";
1010
import { ContainerAppItem } from "../../tree/ContainerAppItem";
1111
import { createContainerAppsAPIClient } from "../../utils/azureClients";
@@ -65,7 +65,7 @@ export class ContainerAppListStep<T extends ContainerAppCreateContext> extends A
6565
public confirmationViewProperty(context: T): ConfirmationViewProperty {
6666
return {
6767
name: localize('containerApp', 'Container App'),
68-
value: nonNullValueAndProp(context.containerApp, 'name'),
68+
value: context.containerApp?.name ?? context.newContainerAppName ?? '',
6969
contextPropertyName: 'containerApp',
7070
};
7171
}

src/commands/createManagedEnvironment/ManagedEnvironmentListStep.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { type ContainerAppsAPIClient, type ManagedEnvironment } from "@azure/arm
77
import { type Workspace } from "@azure/arm-operationalinsights";
88
import { type ResourceGroup } from "@azure/arm-resources";
99
import { getResourceGroupFromId, LocationListStep, ResourceGroupListStep, uiUtils } from "@microsoft/vscode-azext-azureutils";
10-
import { AzureWizardPromptStep, nonNullProp, nonNullValueAndProp, type AzureWizardExecuteStep, type ConfirmationViewProperty, type IAzureQuickPickItem, type ISubscriptionActionContext, type IWizardOptions } from "@microsoft/vscode-azext-utils";
10+
import { AzureWizardPromptStep, nonNullProp, type AzureWizardExecuteStep, type ConfirmationViewProperty, type IAzureQuickPickItem, type ISubscriptionActionContext, type IWizardOptions } from "@microsoft/vscode-azext-utils";
1111
import { logAnalyticsProvider, logAnalyticsResourceType, managedEnvironmentProvider, managedEnvironmentResourceType } from "../../constants";
1212
import { createContainerAppsAPIClient } from "../../utils/azureClients";
1313
import { localize } from "../../utils/localize";
@@ -63,7 +63,7 @@ export class ManagedEnvironmentListStep<T extends ManagedEnvironmentCreateContex
6363
public confirmationViewProperty(context: T): ConfirmationViewProperty {
6464
return {
6565
name: localize('containerAppEnvironment', 'Container Apps Environment'),
66-
value: nonNullValueAndProp(context.managedEnvironment, 'name'),
66+
value: context.managedEnvironment?.name ?? context.newManagedEnvironmentName ?? '',
6767
contextPropertyName: 'managedEnvironment',
6868
};
6969
}

src/extension.ts

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,18 @@ import { TreeElementStateManager, callWithTelemetryAndErrorHandling, createApiPr
1111
import { AzExtResourceType, type AzureResourcesExtensionApi } from '@microsoft/vscode-azureresources-api';
1212
import { v4 as uuid } from 'uuid';
1313
import * as vscode from 'vscode';
14+
import * as api from "../src/commands/api/vscode-azurecontainerapps.api";
1415
import { createContainerAppsApiProvider } from './commands/api/createContainerAppsApiProvider';
16+
import { deployImageApi } from './commands/api/deployImageApi';
17+
import { deployWorkspaceProjectApi, deployWorkspaceProjectApiInternal } from './commands/api/deployWorkspaceProjectApi';
18+
import { createContainerApp } from './commands/createContainerApp/createContainerApp';
19+
import { createManagedEnvironment } from './commands/createManagedEnvironment/createManagedEnvironment';
20+
import { deployContainerApp } from './commands/deployContainerApp/deployContainerApp';
21+
import { deployWorkspaceProject } from './commands/deployWorkspaceProject/deployWorkspaceProject';
1522
import { registerCommands } from './commands/registerCommands';
1623
import { RevisionDraftFileSystem } from './commands/revisionDraft/RevisionDraftFileSystem';
1724
import { ext } from './extensionVariables';
25+
import { AzureContainerAppsTestApi } from './testApi';
1826
import { ContainerAppsResourceBranchDataProvider } from './tree/ContainerAppResourceItem';
1927
import { ContainerAppsBranchDataProvider } from './tree/ContainerAppsBranchDataProvider';
2028
import { localize } from './utils/localize';
@@ -51,6 +59,10 @@ export async function activate(context: vscode.ExtensionContext, perfStats: { lo
5159
const authHandshakeStartMs = Date.now();
5260
activateContext.telemetry.properties.authHandshakeId = authHandshakeId;
5361

62+
// Deferred promise that extracts `resolve` so `registerBranchResources` can signal completion to awaiting callers
63+
let resolveHandshake: () => void;
64+
const handshakePromise = new Promise<void>((resolve) => { resolveHandshake = resolve; });
65+
5466
const registerBranchResources = async (azureResourcesApis: (AzureResourcesExtensionApi | undefined)[]) => {
5567
await callWithTelemetryAndErrorHandling('hostApiRequestSucceeded', (actionContext: IActionContext) => {
5668
actionContext.telemetry.measurements.authHandshakeDuration = (Date.now() - authHandshakeStartMs) / 1000;
@@ -67,9 +79,42 @@ export async function activate(context: vscode.ExtensionContext, perfStats: { lo
6779
ext.rgApiV2.resources.registerAzureResourceBranchDataProvider(AzExtResourceType.ContainerAppsEnvironment, ext.branchDataProvider);
6880
ext.rgApiV2.resources.registerAzureResourceBranchDataProvider(AzExtResourceType.ContainerApps, ext.containerAppsResourceBranchDataProvider);
6981
});
82+
resolveHandshake();
83+
};
84+
85+
const coreApiEndpoints = {
86+
deployImage: deployImageApi,
87+
deployWorkspaceProject: deployWorkspaceProjectApi,
7088
};
7189

72-
return createContainerAppsApiProvider(registerBranchResources);
90+
let coreExtensionApi: api.AzureContainerAppsExtensionApi | AzureContainerAppsTestApi;
91+
if (process.env.VSCODE_RUNNING_TESTS) {
92+
// Provide test API when running tests
93+
// This allows tests to access internal extension state
94+
coreExtensionApi = {
95+
apiVersion: '99.0.0',
96+
...coreApiEndpoints,
97+
extensionVariables: {
98+
getState: () => { return ext.state; },
99+
getOutputChannel: () => { return ext.outputChannel; },
100+
getRgApiV2: async () => { await handshakePromise; return ext.rgApiV2; },
101+
getBranchDataProvider: async () => { await handshakePromise; return ext.branchDataProvider; },
102+
},
103+
// Export internal methods so that we can test them directly
104+
createContainerAppInternal: createContainerApp,
105+
createManagedEnvironmentInternal: createManagedEnvironment,
106+
deployContainerAppInternal: deployContainerApp,
107+
deployWorkspaceProjectInternal: deployWorkspaceProject,
108+
deployWorkspaceProjectApiInternal: deployWorkspaceProjectApiInternal,
109+
} satisfies AzureContainerAppsTestApi;
110+
} else {
111+
coreExtensionApi = {
112+
apiVersion: '1.1.0',
113+
...coreApiEndpoints,
114+
};
115+
}
116+
117+
return createContainerAppsApiProvider(registerBranchResources, coreExtensionApi);
73118

74119
}) ?? createApiProvider([]);
75120
}

src/testApi.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import { type IAzExtOutputChannel, type TreeElementStateManager } from "@microsoft/vscode-azext-utils";
7+
import { type AzureResourcesExtensionApi } from "@microsoft/vscode-azureresources-api";
8+
import * as api from "../src/commands/api/vscode-azurecontainerapps.api";
9+
import { type deployWorkspaceProjectApiInternal } from "./commands/api/deployWorkspaceProjectApi";
10+
import { createContainerApp } from "./commands/createContainerApp/createContainerApp";
11+
import { createManagedEnvironment } from "./commands/createManagedEnvironment/createManagedEnvironment";
12+
import { deployContainerApp } from "./commands/deployContainerApp/deployContainerApp";
13+
import { deployWorkspaceProject } from "./commands/deployWorkspaceProject/deployWorkspaceProject";
14+
import { type ContainerAppsBranchDataProvider } from "./tree/ContainerAppsBranchDataProvider";
15+
16+
/**
17+
* Test-only API for accessing internal extension state.
18+
* This API is only available when VSCODE_RUNNING_TESTS environment variable is set.
19+
* It should NEVER be used in production code.
20+
*/
21+
export interface AzureContainerAppsTestApi extends api.AzureContainerAppsExtensionApi {
22+
apiVersion: '99.0.0';
23+
extensionVariables: {
24+
getState(): TreeElementStateManager;
25+
getOutputChannel(): IAzExtOutputChannel;
26+
getRgApiV2(): Promise<AzureResourcesExtensionApi>;
27+
getBranchDataProvider(): Promise<ContainerAppsBranchDataProvider>;
28+
};
29+
/** A private test export for {@link createContainerApp} */
30+
createContainerAppInternal: typeof createContainerApp;
31+
/** A private test export for {@link createManagedEnvironment} */
32+
createManagedEnvironmentInternal: typeof createManagedEnvironment;
33+
/** A private test export for {@link deployContainerApp} */
34+
deployContainerAppInternal: typeof deployContainerApp;
35+
/** A private test export for {@link deployWorkspaceProject} */
36+
deployWorkspaceProjectInternal: typeof deployWorkspaceProject;
37+
/** A private test export for {@link deployWorkspaceProjectApiInternal} */
38+
deployWorkspaceProjectApiInternal: typeof deployWorkspaceProjectApiInternal;
39+
}

test/global.test.ts

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

6-
import { registerOnActionStartHandler, TestOutputChannel, TestUserInput } from '@microsoft/vscode-azext-utils';
7-
import * as assert from 'assert';
6+
import { registerAzureUtilsExtensionVariables } from '@microsoft/vscode-azext-azureutils';
7+
import { registerOnActionStartHandler, testGlobalSetup, TestUserInput } from '@microsoft/vscode-azext-utils';
88
import * as vscode from 'vscode';
99
import { ext } from '../src/extensionVariables';
10+
import { getTestApi } from './utils/testApiAccess';
1011

1112
export const longRunningLocalTestsEnabled: boolean = !/^(false|0)?$/i.test(process.env.AzCode_EnableLongRunningTestsLocal || '');
1213
export const longRunningRemoteTestsEnabled: boolean = !!process.env.FC_SERVICE_CONNECTION_NAME
@@ -18,15 +19,10 @@ export const longRunningTestsEnabled: boolean = longRunningLocalTestsEnabled ||
1819
suiteSetup(async function (this: Mocha.Context): Promise<void> {
1920
this.timeout(2 * 60 * 1000);
2021

21-
const extension = vscode.extensions.getExtension('ms-azuretools.vscode-azurecontainerapps');
22-
if (!extension) {
23-
assert.fail('Failed to find extension.');
24-
} else {
25-
await extension.activate();
26-
}
27-
28-
ext.outputChannel = new TestOutputChannel();
22+
await getTestApi();
23+
Object.assign(ext, { prefix: 'containerApps', ...testGlobalSetup() });
2924

25+
registerAzureUtilsExtensionVariables(ext);
3026
registerOnActionStartHandler(context => {
3127
// Use `TestUserInput` by default so we get an error if an unexpected call to `context.ui` occurs, rather than timing out
3228
context.ui = new TestUserInput(vscode);

0 commit comments

Comments
 (0)