Skip to content

Commit 482d5ba

Browse files
Add some integration tests for github-auth (microsoft#195729)
1 parent 9abd7cb commit 482d5ba

File tree

8 files changed

+283
-1
lines changed

8 files changed

+283
-1
lines changed

.vscode-test.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ const extensions = [
3131
workspaceFolder: path.join(os.tmpdir(), `nbout-${Math.floor(Math.random() * 100000)}`),
3232
mocha: { timeout: 60_000 }
3333
},
34+
{
35+
label: 'github-authentication',
36+
workspaceFolder: path.join(os.tmpdir(), `msft-auth-${Math.floor(Math.random() * 100000)}`),
37+
mocha: { timeout: 60_000 }
38+
}
3439
];
3540

3641

extensions/github-authentication/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
"vscode-tas-client": "^0.1.47"
6565
},
6666
"devDependencies": {
67+
"@types/mocha": "^9.1.1",
6768
"@types/node": "18.x",
6869
"@types/node-fetch": "^2.5.7"
6970
},

extensions/github-authentication/src/flows.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ export const enum ExtensionHost {
5353
Local
5454
}
5555

56-
interface IFlowQuery {
56+
export interface IFlowQuery {
5757
target: GitHubTarget;
5858
extensionHost: ExtensionHost;
5959
isSupportedClient: boolean;
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
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 * as assert from 'assert';
7+
import { ExtensionHost, GitHubTarget, IFlowQuery, getFlows } from '../flows';
8+
import { Config } from '../config';
9+
10+
const enum Flows {
11+
UrlHandlerFlow = 'url handler',
12+
LocalServerFlow = 'local server',
13+
DeviceCodeFlow = 'device code',
14+
PatFlow = 'personal access token'
15+
}
16+
17+
suite('getFlows', () => {
18+
let lastClientSecret: string | undefined = undefined;
19+
suiteSetup(() => {
20+
lastClientSecret = Config.gitHubClientSecret;
21+
Config.gitHubClientSecret = 'asdf';
22+
});
23+
24+
suiteTeardown(() => {
25+
Config.gitHubClientSecret = lastClientSecret;
26+
});
27+
28+
const testCases: Array<{ label: string; query: IFlowQuery; expectedFlows: Flows[] }> = [
29+
{
30+
label: 'VS Code Desktop. Local filesystem. GitHub.com',
31+
query: {
32+
extensionHost: ExtensionHost.Local,
33+
isSupportedClient: true,
34+
target: GitHubTarget.DotCom
35+
},
36+
expectedFlows: [
37+
Flows.UrlHandlerFlow,
38+
Flows.LocalServerFlow,
39+
Flows.DeviceCodeFlow
40+
]
41+
},
42+
{
43+
label: 'VS Code Desktop. Local filesystem. GitHub Hosted Enterprise',
44+
query: {
45+
extensionHost: ExtensionHost.Local,
46+
isSupportedClient: true,
47+
target: GitHubTarget.HostedEnterprise
48+
},
49+
expectedFlows: [
50+
Flows.UrlHandlerFlow,
51+
Flows.LocalServerFlow,
52+
Flows.DeviceCodeFlow,
53+
Flows.PatFlow
54+
]
55+
},
56+
{
57+
label: 'VS Code Desktop. Local filesystem. GitHub Enterprise Server',
58+
query: {
59+
extensionHost: ExtensionHost.Local,
60+
isSupportedClient: true,
61+
target: GitHubTarget.Enterprise
62+
},
63+
expectedFlows: [
64+
Flows.DeviceCodeFlow,
65+
Flows.PatFlow
66+
]
67+
},
68+
{
69+
label: 'vscode.dev. serverful. GitHub.com',
70+
query: {
71+
extensionHost: ExtensionHost.Remote,
72+
isSupportedClient: true,
73+
target: GitHubTarget.DotCom
74+
},
75+
expectedFlows: [
76+
Flows.UrlHandlerFlow,
77+
Flows.DeviceCodeFlow
78+
]
79+
},
80+
{
81+
label: 'vscode.dev. serverful. GitHub Hosted Enterprise',
82+
query: {
83+
extensionHost: ExtensionHost.Remote,
84+
isSupportedClient: true,
85+
target: GitHubTarget.HostedEnterprise
86+
},
87+
expectedFlows: [
88+
Flows.UrlHandlerFlow,
89+
Flows.DeviceCodeFlow,
90+
Flows.PatFlow
91+
]
92+
},
93+
{
94+
label: 'vscode.dev. serverful. GitHub Enterprise',
95+
query: {
96+
extensionHost: ExtensionHost.Remote,
97+
isSupportedClient: true,
98+
target: GitHubTarget.Enterprise
99+
},
100+
expectedFlows: [
101+
Flows.DeviceCodeFlow,
102+
Flows.PatFlow
103+
]
104+
},
105+
{
106+
label: 'vscode.dev. serverless. GitHub.com',
107+
query: {
108+
extensionHost: ExtensionHost.WebWorker,
109+
isSupportedClient: true,
110+
target: GitHubTarget.DotCom
111+
},
112+
expectedFlows: [
113+
Flows.UrlHandlerFlow
114+
]
115+
},
116+
{
117+
label: 'vscode.dev. serverless. GitHub Hosted Enterprise',
118+
query: {
119+
extensionHost: ExtensionHost.WebWorker,
120+
isSupportedClient: true,
121+
target: GitHubTarget.HostedEnterprise
122+
},
123+
expectedFlows: [
124+
Flows.UrlHandlerFlow,
125+
Flows.PatFlow
126+
]
127+
},
128+
{
129+
label: 'vscode.dev. serverless. GitHub Enterprise Server',
130+
query: {
131+
extensionHost: ExtensionHost.WebWorker,
132+
isSupportedClient: true,
133+
target: GitHubTarget.Enterprise
134+
},
135+
expectedFlows: [
136+
Flows.PatFlow
137+
]
138+
},
139+
{
140+
label: 'Code - OSS. Local filesystem. GitHub.com',
141+
query: {
142+
extensionHost: ExtensionHost.Local,
143+
isSupportedClient: false,
144+
target: GitHubTarget.DotCom
145+
},
146+
expectedFlows: [
147+
Flows.LocalServerFlow,
148+
Flows.DeviceCodeFlow,
149+
Flows.PatFlow
150+
]
151+
},
152+
{
153+
label: 'Code - OSS. Local filesystem. GitHub Hosted Enterprise',
154+
query: {
155+
extensionHost: ExtensionHost.Local,
156+
isSupportedClient: false,
157+
target: GitHubTarget.HostedEnterprise
158+
},
159+
expectedFlows: [
160+
Flows.LocalServerFlow,
161+
Flows.DeviceCodeFlow,
162+
Flows.PatFlow
163+
]
164+
},
165+
{
166+
label: 'Code - OSS. Local filesystem. GitHub Enterprise Server',
167+
query: {
168+
extensionHost: ExtensionHost.Local,
169+
isSupportedClient: false,
170+
target: GitHubTarget.Enterprise
171+
},
172+
expectedFlows: [
173+
Flows.DeviceCodeFlow,
174+
Flows.PatFlow
175+
]
176+
},
177+
];
178+
179+
for (const testCase of testCases) {
180+
test(`gives the correct flows - ${testCase.label}`, () => {
181+
const flows = getFlows(testCase.query);
182+
183+
assert.strictEqual(
184+
flows.length,
185+
testCase.expectedFlows.length,
186+
`Unexpected number of flows: ${flows.map(f => f.label).join(',')}`
187+
);
188+
189+
for (let i = 0; i < flows.length; i++) {
190+
const flow = flows[i];
191+
192+
assert.strictEqual(flow.label, testCase.expectedFlows[i]);
193+
}
194+
});
195+
}
196+
});
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
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 * as assert from 'assert';
7+
import { LoopbackAuthServer } from '../../node/authServer';
8+
9+
suite('LoopbackAuthServer', () => {
10+
let server: LoopbackAuthServer;
11+
let port: number;
12+
13+
setup(async () => {
14+
server = new LoopbackAuthServer(__dirname, 'http://localhost:8080');
15+
port = await server.start();
16+
});
17+
18+
teardown(async () => {
19+
await server.stop();
20+
});
21+
22+
test('should redirect to starting redirect on /signin', async () => {
23+
const response = await fetch(`http://localhost:${port}/signin?nonce=${server.nonce}`, {
24+
redirect: 'manual'
25+
});
26+
// Redirect
27+
assert.strictEqual(response.status, 302);
28+
29+
// Check location
30+
const location = response.headers.get('location');
31+
assert.ok(location);
32+
const locationUrl = new URL(location);
33+
assert.strictEqual(locationUrl.origin, 'http://localhost:8080');
34+
35+
// Check state
36+
const state = locationUrl.searchParams.get('state');
37+
assert.ok(state);
38+
const stateLocation = new URL(state);
39+
assert.strictEqual(stateLocation.origin, `http://127.0.0.1:${port}`);
40+
assert.strictEqual(stateLocation.pathname, '/callback');
41+
assert.strictEqual(stateLocation.searchParams.get('nonce'), server.nonce);
42+
});
43+
44+
test('should return 400 on /callback with missing parameters', async () => {
45+
const response = await fetch(`http://localhost:${port}/callback`);
46+
assert.strictEqual(response.status, 400);
47+
});
48+
49+
test('should resolve with code and state on /callback with valid parameters', async () => {
50+
server.state = 'valid-state';
51+
const response = await fetch(
52+
`http://localhost:${port}/callback?code=valid-code&state=${server.state}&nonce=${server.nonce}`,
53+
{ redirect: 'manual' }
54+
);
55+
assert.strictEqual(response.status, 302);
56+
assert.strictEqual(response.headers.get('location'), '/');
57+
await Promise.race([
58+
server.waitForOAuthResponse().then(result => {
59+
assert.strictEqual(result.code, 'valid-code');
60+
assert.strictEqual(result.state, server.state);
61+
}),
62+
new Promise((_, reject) => setTimeout(() => reject(new Error('Timeout')), 5000))
63+
]);
64+
});
65+
});

extensions/github-authentication/yarn.lock

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,11 @@
259259
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf"
260260
integrity sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==
261261

262+
"@types/mocha@^9.1.1":
263+
version "9.1.1"
264+
resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-9.1.1.tgz#e7c4f1001eefa4b8afbd1eee27a237fee3bf29c4"
265+
integrity sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw==
266+
262267
"@types/node-fetch@^2.5.7":
263268
version "2.5.7"
264269
resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.7.tgz#20a2afffa882ab04d44ca786449a276f9f6bbf3c"

scripts/test-integration.bat

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,11 @@ mkdir %CFWORKSPACE%
9292
call "%INTEGRATION_TEST_ELECTRON_PATH%" %CFWORKSPACE% --extensionDevelopmentPath=%~dp0\..\extensions\configuration-editing --extensionTestsPath=%~dp0\..\extensions\configuration-editing\out\test %API_TESTS_EXTRA_ARGS%
9393
if %errorlevel% neq 0 exit /b %errorlevel%
9494

95+
echo.
96+
echo ### GitHub Authentication tests
97+
call yarn test-extension -l github-authentication
98+
if %errorlevel% neq 0 exit /b %errorlevel%
99+
95100
:: Tests standalone (CommonJS)
96101

97102
echo.

scripts/test-integration.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,11 @@ echo
112112
"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS $(mktemp -d 2>/dev/null) --extensionDevelopmentPath=$ROOT/extensions/configuration-editing --extensionTestsPath=$ROOT/extensions/configuration-editing/out/test $API_TESTS_EXTRA_ARGS
113113
kill_app
114114

115+
echo
116+
echo "### GitHub Authentication tests"
117+
echo
118+
yarn test-extension -l github-authentication
119+
kill_app
115120

116121
# Tests standalone (CommonJS)
117122

0 commit comments

Comments
 (0)