mirror of
https://github.com/microsoft/vscode.git
synced 2025-12-20 10:19:02 +00:00
Add some integration tests for github-auth (#195729)
This commit is contained in:
committed by
GitHub
parent
9abd7cbbc7
commit
482d5ba393
@@ -31,6 +31,11 @@ const extensions = [
|
|||||||
workspaceFolder: path.join(os.tmpdir(), `nbout-${Math.floor(Math.random() * 100000)}`),
|
workspaceFolder: path.join(os.tmpdir(), `nbout-${Math.floor(Math.random() * 100000)}`),
|
||||||
mocha: { timeout: 60_000 }
|
mocha: { timeout: 60_000 }
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: 'github-authentication',
|
||||||
|
workspaceFolder: path.join(os.tmpdir(), `msft-auth-${Math.floor(Math.random() * 100000)}`),
|
||||||
|
mocha: { timeout: 60_000 }
|
||||||
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -64,6 +64,7 @@
|
|||||||
"vscode-tas-client": "^0.1.47"
|
"vscode-tas-client": "^0.1.47"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/mocha": "^9.1.1",
|
||||||
"@types/node": "18.x",
|
"@types/node": "18.x",
|
||||||
"@types/node-fetch": "^2.5.7"
|
"@types/node-fetch": "^2.5.7"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ export const enum ExtensionHost {
|
|||||||
Local
|
Local
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IFlowQuery {
|
export interface IFlowQuery {
|
||||||
target: GitHubTarget;
|
target: GitHubTarget;
|
||||||
extensionHost: ExtensionHost;
|
extensionHost: ExtensionHost;
|
||||||
isSupportedClient: boolean;
|
isSupportedClient: boolean;
|
||||||
|
|||||||
196
extensions/github-authentication/src/test/flows.test.ts
Normal file
196
extensions/github-authentication/src/test/flows.test.ts
Normal file
@@ -0,0 +1,196 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import * as assert from 'assert';
|
||||||
|
import { ExtensionHost, GitHubTarget, IFlowQuery, getFlows } from '../flows';
|
||||||
|
import { Config } from '../config';
|
||||||
|
|
||||||
|
const enum Flows {
|
||||||
|
UrlHandlerFlow = 'url handler',
|
||||||
|
LocalServerFlow = 'local server',
|
||||||
|
DeviceCodeFlow = 'device code',
|
||||||
|
PatFlow = 'personal access token'
|
||||||
|
}
|
||||||
|
|
||||||
|
suite('getFlows', () => {
|
||||||
|
let lastClientSecret: string | undefined = undefined;
|
||||||
|
suiteSetup(() => {
|
||||||
|
lastClientSecret = Config.gitHubClientSecret;
|
||||||
|
Config.gitHubClientSecret = 'asdf';
|
||||||
|
});
|
||||||
|
|
||||||
|
suiteTeardown(() => {
|
||||||
|
Config.gitHubClientSecret = lastClientSecret;
|
||||||
|
});
|
||||||
|
|
||||||
|
const testCases: Array<{ label: string; query: IFlowQuery; expectedFlows: Flows[] }> = [
|
||||||
|
{
|
||||||
|
label: 'VS Code Desktop. Local filesystem. GitHub.com',
|
||||||
|
query: {
|
||||||
|
extensionHost: ExtensionHost.Local,
|
||||||
|
isSupportedClient: true,
|
||||||
|
target: GitHubTarget.DotCom
|
||||||
|
},
|
||||||
|
expectedFlows: [
|
||||||
|
Flows.UrlHandlerFlow,
|
||||||
|
Flows.LocalServerFlow,
|
||||||
|
Flows.DeviceCodeFlow
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'VS Code Desktop. Local filesystem. GitHub Hosted Enterprise',
|
||||||
|
query: {
|
||||||
|
extensionHost: ExtensionHost.Local,
|
||||||
|
isSupportedClient: true,
|
||||||
|
target: GitHubTarget.HostedEnterprise
|
||||||
|
},
|
||||||
|
expectedFlows: [
|
||||||
|
Flows.UrlHandlerFlow,
|
||||||
|
Flows.LocalServerFlow,
|
||||||
|
Flows.DeviceCodeFlow,
|
||||||
|
Flows.PatFlow
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'VS Code Desktop. Local filesystem. GitHub Enterprise Server',
|
||||||
|
query: {
|
||||||
|
extensionHost: ExtensionHost.Local,
|
||||||
|
isSupportedClient: true,
|
||||||
|
target: GitHubTarget.Enterprise
|
||||||
|
},
|
||||||
|
expectedFlows: [
|
||||||
|
Flows.DeviceCodeFlow,
|
||||||
|
Flows.PatFlow
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'vscode.dev. serverful. GitHub.com',
|
||||||
|
query: {
|
||||||
|
extensionHost: ExtensionHost.Remote,
|
||||||
|
isSupportedClient: true,
|
||||||
|
target: GitHubTarget.DotCom
|
||||||
|
},
|
||||||
|
expectedFlows: [
|
||||||
|
Flows.UrlHandlerFlow,
|
||||||
|
Flows.DeviceCodeFlow
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'vscode.dev. serverful. GitHub Hosted Enterprise',
|
||||||
|
query: {
|
||||||
|
extensionHost: ExtensionHost.Remote,
|
||||||
|
isSupportedClient: true,
|
||||||
|
target: GitHubTarget.HostedEnterprise
|
||||||
|
},
|
||||||
|
expectedFlows: [
|
||||||
|
Flows.UrlHandlerFlow,
|
||||||
|
Flows.DeviceCodeFlow,
|
||||||
|
Flows.PatFlow
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'vscode.dev. serverful. GitHub Enterprise',
|
||||||
|
query: {
|
||||||
|
extensionHost: ExtensionHost.Remote,
|
||||||
|
isSupportedClient: true,
|
||||||
|
target: GitHubTarget.Enterprise
|
||||||
|
},
|
||||||
|
expectedFlows: [
|
||||||
|
Flows.DeviceCodeFlow,
|
||||||
|
Flows.PatFlow
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'vscode.dev. serverless. GitHub.com',
|
||||||
|
query: {
|
||||||
|
extensionHost: ExtensionHost.WebWorker,
|
||||||
|
isSupportedClient: true,
|
||||||
|
target: GitHubTarget.DotCom
|
||||||
|
},
|
||||||
|
expectedFlows: [
|
||||||
|
Flows.UrlHandlerFlow
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'vscode.dev. serverless. GitHub Hosted Enterprise',
|
||||||
|
query: {
|
||||||
|
extensionHost: ExtensionHost.WebWorker,
|
||||||
|
isSupportedClient: true,
|
||||||
|
target: GitHubTarget.HostedEnterprise
|
||||||
|
},
|
||||||
|
expectedFlows: [
|
||||||
|
Flows.UrlHandlerFlow,
|
||||||
|
Flows.PatFlow
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'vscode.dev. serverless. GitHub Enterprise Server',
|
||||||
|
query: {
|
||||||
|
extensionHost: ExtensionHost.WebWorker,
|
||||||
|
isSupportedClient: true,
|
||||||
|
target: GitHubTarget.Enterprise
|
||||||
|
},
|
||||||
|
expectedFlows: [
|
||||||
|
Flows.PatFlow
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Code - OSS. Local filesystem. GitHub.com',
|
||||||
|
query: {
|
||||||
|
extensionHost: ExtensionHost.Local,
|
||||||
|
isSupportedClient: false,
|
||||||
|
target: GitHubTarget.DotCom
|
||||||
|
},
|
||||||
|
expectedFlows: [
|
||||||
|
Flows.LocalServerFlow,
|
||||||
|
Flows.DeviceCodeFlow,
|
||||||
|
Flows.PatFlow
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Code - OSS. Local filesystem. GitHub Hosted Enterprise',
|
||||||
|
query: {
|
||||||
|
extensionHost: ExtensionHost.Local,
|
||||||
|
isSupportedClient: false,
|
||||||
|
target: GitHubTarget.HostedEnterprise
|
||||||
|
},
|
||||||
|
expectedFlows: [
|
||||||
|
Flows.LocalServerFlow,
|
||||||
|
Flows.DeviceCodeFlow,
|
||||||
|
Flows.PatFlow
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Code - OSS. Local filesystem. GitHub Enterprise Server',
|
||||||
|
query: {
|
||||||
|
extensionHost: ExtensionHost.Local,
|
||||||
|
isSupportedClient: false,
|
||||||
|
target: GitHubTarget.Enterprise
|
||||||
|
},
|
||||||
|
expectedFlows: [
|
||||||
|
Flows.DeviceCodeFlow,
|
||||||
|
Flows.PatFlow
|
||||||
|
]
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const testCase of testCases) {
|
||||||
|
test(`gives the correct flows - ${testCase.label}`, () => {
|
||||||
|
const flows = getFlows(testCase.query);
|
||||||
|
|
||||||
|
assert.strictEqual(
|
||||||
|
flows.length,
|
||||||
|
testCase.expectedFlows.length,
|
||||||
|
`Unexpected number of flows: ${flows.map(f => f.label).join(',')}`
|
||||||
|
);
|
||||||
|
|
||||||
|
for (let i = 0; i < flows.length; i++) {
|
||||||
|
const flow = flows[i];
|
||||||
|
|
||||||
|
assert.strictEqual(flow.label, testCase.expectedFlows[i]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import * as assert from 'assert';
|
||||||
|
import { LoopbackAuthServer } from '../../node/authServer';
|
||||||
|
|
||||||
|
suite('LoopbackAuthServer', () => {
|
||||||
|
let server: LoopbackAuthServer;
|
||||||
|
let port: number;
|
||||||
|
|
||||||
|
setup(async () => {
|
||||||
|
server = new LoopbackAuthServer(__dirname, 'http://localhost:8080');
|
||||||
|
port = await server.start();
|
||||||
|
});
|
||||||
|
|
||||||
|
teardown(async () => {
|
||||||
|
await server.stop();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should redirect to starting redirect on /signin', async () => {
|
||||||
|
const response = await fetch(`http://localhost:${port}/signin?nonce=${server.nonce}`, {
|
||||||
|
redirect: 'manual'
|
||||||
|
});
|
||||||
|
// Redirect
|
||||||
|
assert.strictEqual(response.status, 302);
|
||||||
|
|
||||||
|
// Check location
|
||||||
|
const location = response.headers.get('location');
|
||||||
|
assert.ok(location);
|
||||||
|
const locationUrl = new URL(location);
|
||||||
|
assert.strictEqual(locationUrl.origin, 'http://localhost:8080');
|
||||||
|
|
||||||
|
// Check state
|
||||||
|
const state = locationUrl.searchParams.get('state');
|
||||||
|
assert.ok(state);
|
||||||
|
const stateLocation = new URL(state);
|
||||||
|
assert.strictEqual(stateLocation.origin, `http://127.0.0.1:${port}`);
|
||||||
|
assert.strictEqual(stateLocation.pathname, '/callback');
|
||||||
|
assert.strictEqual(stateLocation.searchParams.get('nonce'), server.nonce);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return 400 on /callback with missing parameters', async () => {
|
||||||
|
const response = await fetch(`http://localhost:${port}/callback`);
|
||||||
|
assert.strictEqual(response.status, 400);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should resolve with code and state on /callback with valid parameters', async () => {
|
||||||
|
server.state = 'valid-state';
|
||||||
|
const response = await fetch(
|
||||||
|
`http://localhost:${port}/callback?code=valid-code&state=${server.state}&nonce=${server.nonce}`,
|
||||||
|
{ redirect: 'manual' }
|
||||||
|
);
|
||||||
|
assert.strictEqual(response.status, 302);
|
||||||
|
assert.strictEqual(response.headers.get('location'), '/');
|
||||||
|
await Promise.race([
|
||||||
|
server.waitForOAuthResponse().then(result => {
|
||||||
|
assert.strictEqual(result.code, 'valid-code');
|
||||||
|
assert.strictEqual(result.state, server.state);
|
||||||
|
}),
|
||||||
|
new Promise((_, reject) => setTimeout(() => reject(new Error('Timeout')), 5000))
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -259,6 +259,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf"
|
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf"
|
||||||
integrity sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==
|
integrity sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==
|
||||||
|
|
||||||
|
"@types/mocha@^9.1.1":
|
||||||
|
version "9.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-9.1.1.tgz#e7c4f1001eefa4b8afbd1eee27a237fee3bf29c4"
|
||||||
|
integrity sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw==
|
||||||
|
|
||||||
"@types/node-fetch@^2.5.7":
|
"@types/node-fetch@^2.5.7":
|
||||||
version "2.5.7"
|
version "2.5.7"
|
||||||
resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.7.tgz#20a2afffa882ab04d44ca786449a276f9f6bbf3c"
|
resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.7.tgz#20a2afffa882ab04d44ca786449a276f9f6bbf3c"
|
||||||
|
|||||||
@@ -92,6 +92,11 @@ mkdir %CFWORKSPACE%
|
|||||||
call "%INTEGRATION_TEST_ELECTRON_PATH%" %CFWORKSPACE% --extensionDevelopmentPath=%~dp0\..\extensions\configuration-editing --extensionTestsPath=%~dp0\..\extensions\configuration-editing\out\test %API_TESTS_EXTRA_ARGS%
|
call "%INTEGRATION_TEST_ELECTRON_PATH%" %CFWORKSPACE% --extensionDevelopmentPath=%~dp0\..\extensions\configuration-editing --extensionTestsPath=%~dp0\..\extensions\configuration-editing\out\test %API_TESTS_EXTRA_ARGS%
|
||||||
if %errorlevel% neq 0 exit /b %errorlevel%
|
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo ### GitHub Authentication tests
|
||||||
|
call yarn test-extension -l github-authentication
|
||||||
|
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||||
|
|
||||||
:: Tests standalone (CommonJS)
|
:: Tests standalone (CommonJS)
|
||||||
|
|
||||||
echo.
|
echo.
|
||||||
|
|||||||
@@ -112,6 +112,11 @@ echo
|
|||||||
"$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
|
"$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
|
||||||
kill_app
|
kill_app
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "### GitHub Authentication tests"
|
||||||
|
echo
|
||||||
|
yarn test-extension -l github-authentication
|
||||||
|
kill_app
|
||||||
|
|
||||||
# Tests standalone (CommonJS)
|
# Tests standalone (CommonJS)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user