Skip to content

Commit 3816291

Browse files
authored
Add tests for domain name label scopes, fix order of any existing tests (#4926)
1 parent 087b06d commit 3816291

File tree

4 files changed

+173
-20
lines changed

4 files changed

+173
-20
lines changed

src/commands/createFunctionApp/containerImage/detectDockerfile.ts

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,27 +5,14 @@
55

66
import { AzExtFsExtra, nonNullProp, type IActionContext, type IAzureQuickPickItem } from '@microsoft/vscode-azext-utils';
77
import * as path from 'path';
8-
import { RelativePattern, workspace, type MessageItem, type Uri, type WorkspaceFolder } from 'vscode';
8+
import { RelativePattern, workspace, type MessageItem, type Uri } from 'vscode';
99
import { browseItem, dockerfileGlobPattern } from '../../../constants';
1010
import { getAzureContainerAppsApi } from '../../../getExtensionApi';
1111
import { localize } from '../../../localize';
1212
import { type ICreateFunctionAppContext } from '../../../tree/SubscriptionTreeItem';
13-
import { getRootWorkspaceFolder } from '../../../utils/workspace';
1413
import { tryGetFunctionProjectRoot } from '../../createNewProject/verifyIsProject';
1514

1615
export async function detectDockerfile(context: ICreateFunctionAppContext): Promise<string | undefined> {
17-
if (!workspace.workspaceFolders?.length) {
18-
return undefined;
19-
}
20-
21-
try {
22-
context.workspaceFolder ??= await getRootWorkspaceFolder() as WorkspaceFolder;
23-
} catch {
24-
// If the user cancels workspace folder selection (e.g., in a multi-root workspace),
25-
// skip dockerfile detection rather than failing the entire creation flow
26-
return undefined;
27-
}
28-
2916
if (!context.workspaceFolder) {
3017
return undefined;
3118
}

test/nightly/createProjectAndDeploy.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ import { getRandomAlphanumericString, getRandomHexString } from '../../src/utils
1616
import { addParallelSuite, runInSeries, type ParallelTest } from '../addParallelSuite';
1717
import { getTestWorkspaceFolder } from '../global.test';
1818
import { NodeModelVersion, PythonModelVersion, defaultTestFuncVersion, getJavaScriptValidateOptions, getPythonValidateOptions, getTypeScriptValidateOptions, validateProject, type IValidateProjectOptions } from '../project/validateProject';
19+
import { getCachedTestApi } from '../utils/testApiAccess';
1920
import { getRotatingAuthLevel, getRotatingLocation, getRotatingNodeVersion, getRotatingPythonVersion } from './getRotatingValue';
2021
import { resourceGroupsToDelete } from './global.nightly.test';
21-
import { getCachedTestApi } from '../utils/testApiAccess';
2222

2323
interface CreateProjectAndDeployTestCase extends ICreateProjectAndDeployOptions {
2424
title: string;
@@ -97,7 +97,7 @@ async function testCreateProjectAndDeploy(options: ICreateProjectAndDeployOption
9797
resourceGroupsToDelete.push(appName);
9898
await runWithTestActionContext('deploy', async context => {
9999
options.deployInputs = options.deployInputs || [];
100-
await context.ui.runWithInputs([testWorkspacePath, /create new function app/i, appName, getRotatingLocation(), ...options.deployInputs], async () => {
100+
await context.ui.runWithInputs([testWorkspacePath, /create new function app/i, getRotatingLocation(), appName, ...options.deployInputs], async () => {
101101
await testApi.commands.deployProductionSlot(context)
102102
});
103103
});
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
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 Site } from '@azure/arm-appservice';
7+
import { DomainNameLabelScope, tryGetWebApp } from '@microsoft/vscode-azext-azureappservice';
8+
import { runWithTestActionContext } from '@microsoft/vscode-azext-dev';
9+
import * as assert from 'assert';
10+
import { getRandomHexString } from '../../src/utils/fs';
11+
import { longRunningTestsEnabled } from '../global.test';
12+
import { getCachedTestApi } from '../utils/testApiAccess';
13+
import { resourceGroupsToDelete, testClient } from './global.nightly.test';
14+
15+
/**
16+
* Tests for Domain Name Label Scope functionality in function app creation.
17+
*
18+
* DomainNameLabelScope quick pick options:
19+
* - Tenant (TenantReuse): Secure unique default hostname
20+
* - Legacy: Global default hostname
21+
*
22+
* In basic create, the domain scope is automatically set to Tenant (no prompt)
23+
* In advanced create, the user is prompted to select between Tenant or Legacy
24+
*/
25+
suite('Domain Name Label Scope', function (this: Mocha.Suite): void {
26+
this.timeout(10 * 60 * 1000);
27+
28+
let location: string;
29+
let rgName: string;
30+
31+
suiteSetup(async function (this: Mocha.Context): Promise<void> {
32+
if (!longRunningTestsEnabled) {
33+
this.skip();
34+
}
35+
36+
rgName = getRandomHexString();
37+
resourceGroupsToDelete.push(rgName);
38+
location = 'West US 2';
39+
});
40+
41+
test('Basic creation uses Tenant scope by default', async () => {
42+
const appName = getRandomHexString();
43+
const testApi = getCachedTestApi();
44+
45+
const testInputs: (string | RegExp)[] = [
46+
location, // Location
47+
appName, // App name
48+
/\.net/i, // Stack
49+
/secrets/i, // Auth type
50+
];
51+
52+
await runWithTestActionContext('createFunctionApp', async context => {
53+
await context.ui.runWithInputs(testInputs, async () => {
54+
await testApi.commands.createFunctionApp(context);
55+
});
56+
});
57+
58+
const createdApp: Site | undefined = await tryGetWebApp(testClient, appName, appName);
59+
assert.ok(createdApp, 'Function app should be created');
60+
assert.equal(createdApp.autoGeneratedDomainNameLabelScope, DomainNameLabelScope.Tenant);
61+
});
62+
63+
test('Advanced creation with Tenant scope', async () => {
64+
const appName = getRandomHexString();
65+
const saName = getRandomHexString().toLowerCase();
66+
const miName = getRandomHexString();
67+
const aiName = getRandomHexString();
68+
const testApi = getCachedTestApi();
69+
70+
const testInputs: (string | RegExp)[] = [
71+
location, // Location
72+
'$(plus) Create new resource group', // Resource Group
73+
rgName, // RG name
74+
/secure.*unique|tenant/i, // Domain scope (Tenant)
75+
appName, // App name
76+
'Flex Consumption', // Hosting plan
77+
/\.net/i, // Stack
78+
'4096', // Instance memory
79+
'100', // Max instances
80+
'Managed identity', // Auth type
81+
'$(plus) Create new user-assigned identity', // Create new identity
82+
miName, // Identity name
83+
'$(plus) Create new storage account', // Storage account
84+
saName, // SA name
85+
'$(plus) Create new Application Insights resource', // App Insights
86+
aiName, // AI name
87+
];
88+
89+
await runWithTestActionContext('createFunctionAppAdvanced', async context => {
90+
await context.ui.runWithInputs(testInputs, async () => {
91+
await testApi.commands.createFunctionAppAdvanced(context);
92+
});
93+
});
94+
95+
const createdApp: Site | undefined = await tryGetWebApp(testClient, rgName, appName);
96+
assert.ok(createdApp, 'Function app should be created with Tenant domain scope');
97+
assert.equal(createdApp.autoGeneratedDomainNameLabelScope, DomainNameLabelScope.Tenant);
98+
});
99+
100+
test('Advanced creation with Legacy scope', async () => {
101+
const appName = getRandomHexString();
102+
const saName = getRandomHexString().toLowerCase();
103+
const miName = getRandomHexString();
104+
const aiName = getRandomHexString();
105+
const testApi = getCachedTestApi();
106+
107+
const testInputs: (string | RegExp)[] = [
108+
location, // Location
109+
rgName, // Use existing RG
110+
/global.*default|legacy/i, // Domain scope (Legacy)
111+
appName, // App name
112+
'Flex Consumption', // Hosting plan
113+
/\.net/i, // Stack
114+
'4096', // Instance memory
115+
'100', // Max instances
116+
'Managed identity', // Auth type
117+
'$(plus) Create new user-assigned identity', // Create new identity
118+
miName, // Identity name
119+
'$(plus) Create new storage account', // Storage account
120+
saName, // SA name
121+
'$(plus) Create new Application Insights resource', // App Insights
122+
aiName, // AI name
123+
];
124+
125+
await runWithTestActionContext('createFunctionAppAdvanced', async context => {
126+
await context.ui.runWithInputs(testInputs, async () => {
127+
await testApi.commands.createFunctionAppAdvanced(context);
128+
});
129+
});
130+
131+
const createdApp: Site | undefined = await tryGetWebApp(testClient, rgName, appName);
132+
assert.ok(createdApp, 'Function app should be created with Global domain scope');
133+
assert.equal(createdApp.autoGeneratedDomainNameLabelScope, undefined);
134+
});
135+
});

test/nightly/functionAppOperations.test.ts

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import * as assert from 'assert';
1111
import { getRandomHexString } from '../../src/utils/fs';
1212
import { cleanTestWorkspace, longRunningTestsEnabled } from '../global.test';
1313
import { getCachedTestApi } from '../utils/testApiAccess';
14-
import { getRotatingLocation } from './getRotatingValue';
1514
import { resourceGroupsToDelete, testClient } from './global.nightly.test';
1615

1716
suite('Function App Operations', function (this: Mocha.Suite): void {
@@ -40,11 +39,28 @@ suite('Function App Operations', function (this: Mocha.Suite): void {
4039
saName = getRandomHexString().toLowerCase(); // storage account must have lower case name
4140
aiName = getRandomHexString();
4241
miName = getRandomHexString();
43-
location = getRotatingLocation();
42+
location = 'West US 2';
4443
});
4544

4645
test('Create - Advanced', async () => {
47-
const testInputs: (string | RegExp)[] = [appName, 'Flex Consumption', location, /\.net/i, '4096', '100', '$(plus) Create new resource group', rgName, 'Managed identity', '$(plus) Create new user-assigned identity', miName, '$(plus) Create new storage account', saName, '$(plus) Create new Application Insights resource', aiName];
46+
const testInputs: (string | RegExp)[] = [
47+
location, // Location
48+
'$(plus) Create new resource group', // Resource Group
49+
rgName, // RG name
50+
/secure.*unique|tenant/i, // Domain scope (Tenant)
51+
appName, // App name
52+
'Flex Consumption', // Hosting plan
53+
/\.net/i, // Stack
54+
'4096', // Instance memory
55+
'100', // Max instances
56+
'Managed identity', // Auth type
57+
'$(plus) Create new user-assigned identity', // Create new identity
58+
miName, // Identity name
59+
'$(plus) Create new storage account', // Storage account
60+
saName, // SA name
61+
'$(plus) Create new Application Insights resource', // App Insights
62+
aiName, // AI name
63+
];
4864
const testApi = getCachedTestApi();
4965
await runWithTestActionContext('createFunctionAppAdvanced', async context => {
5066
await context.ui.runWithInputs(testInputs, async () => {
@@ -56,7 +72,22 @@ suite('Function App Operations', function (this: Mocha.Suite): void {
5672
});
5773

5874
test('Create - Advanced - Existing RG/SA/AI', async () => {
59-
const testInputs: (string | RegExp)[] = [app2Name, 'Flex Consumption', location, /\.net/i, '4096', '100', rgName, 'Managed identity', '$(plus) Create new user-assigned identity', app2Name, app2Name, app2Name];
75+
// Same prompt order as above, but using existing resources
76+
const testInputs: (string | RegExp)[] = [
77+
location, // Location
78+
rgName, // Use existing RG
79+
/secure.*unique|tenant/i, // Domain scope (Tenant)
80+
app2Name, // App name
81+
'Flex Consumption', // Hosting plan
82+
/\.net/i, // Stack
83+
'4096', // Instance memory
84+
'100', // Max instances
85+
'Managed identity', // Auth type
86+
'$(plus) Create new user-assigned identity', // Create new identity
87+
app2Name, // Identity name (reuse app2Name)
88+
app2Name, // SA name (reuse existing)
89+
app2Name, // AI name (reuse existing)
90+
];
6091
const testApi = getCachedTestApi();
6192
await runWithTestActionContext('createFunctionAppAdvanced', async context => {
6293
await context.ui.runWithInputs(testInputs, async () => {

0 commit comments

Comments
 (0)