Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add some integration tests for github-auth #195729

Merged
merged 1 commit into from
Oct 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions .vscode-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ const extensions = [
workspaceFolder: path.join(os.tmpdir(), `nbout-${Math.floor(Math.random() * 100000)}`),
mocha: { timeout: 60_000 }
},
{
label: 'github-authentication',
workspaceFolder: path.join(os.tmpdir(), `msft-auth-${Math.floor(Math.random() * 100000)}`),
mocha: { timeout: 60_000 }
}
];


Expand Down
1 change: 1 addition & 0 deletions extensions/github-authentication/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
"vscode-tas-client": "^0.1.47"
},
"devDependencies": {
"@types/mocha": "^9.1.1",
"@types/node": "18.x",
"@types/node-fetch": "^2.5.7"
},
Expand Down
2 changes: 1 addition & 1 deletion extensions/github-authentication/src/flows.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export const enum ExtensionHost {
Local
}

interface IFlowQuery {
export interface IFlowQuery {
target: GitHubTarget;
extensionHost: ExtensionHost;
isSupportedClient: boolean;
Expand Down
196 changes: 196 additions & 0 deletions extensions/github-authentication/src/test/flows.test.ts
Original file line number Diff line number Diff line change
@@ -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]);
}
});
}
});
65 changes: 65 additions & 0 deletions extensions/github-authentication/src/test/node/authServer.test.ts
Original file line number Diff line number Diff line change
@@ -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))
]);
});
});
5 changes: 5 additions & 0 deletions extensions/github-authentication/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,11 @@
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf"
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":
version "2.5.7"
resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.7.tgz#20a2afffa882ab04d44ca786449a276f9f6bbf3c"
Expand Down
5 changes: 5 additions & 0 deletions scripts/test-integration.bat
Original file line number Diff line number Diff line change
Expand Up @@ -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%
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)

echo.
Expand Down
5 changes: 5 additions & 0 deletions scripts/test-integration.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
kill_app

echo
echo "### GitHub Authentication tests"
echo
yarn test-extension -l github-authentication
kill_app

# Tests standalone (CommonJS)

Expand Down