From 85c68f0ce03bb52eefc2b51cdb75737ad7d86c25 Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Thu, 17 Aug 2023 10:04:19 +1000 Subject: [PATCH] Add more tests --- .../userServerUriProvider.unit.test.ts | 108 ++++++++++++++++-- .../userServerUrlProvider.ts | 1 - .../jupyter/connection.vscode.test.ts | 11 +- 3 files changed, 100 insertions(+), 20 deletions(-) diff --git a/src/standalone/userJupyterServer/userServerUriProvider.unit.test.ts b/src/standalone/userJupyterServer/userServerUriProvider.unit.test.ts index da48482abdc..dc5b6b06453 100644 --- a/src/standalone/userJupyterServer/userServerUriProvider.unit.test.ts +++ b/src/standalone/userJupyterServer/userServerUriProvider.unit.test.ts @@ -39,10 +39,9 @@ import { disposeAllDisposables } from '../../platform/common/helpers'; import { JVSC_EXTENSION_ID, Settings, UserJupyterServerPickerProviderId } from '../../platform/common/constants'; import { assert } from 'chai'; import { generateIdFromRemoteProvider } from '../../kernels/jupyter/jupyterUtils'; -import { Common, DataScience } from '../../platform/common/utils/localize'; import { IJupyterPasswordConnectInfo, JupyterPasswordConnect } from './jupyterPasswordConnect'; import { IFileSystem } from '../../platform/common/platform/types'; -import { JupyterServerCollection } from '../../api'; +import { IJupyterServerUri, JupyterServerCollection } from '../../api'; /* eslint-disable @typescript-eslint/no-explicit-any, , */ suite('User Uri Provider', () => { @@ -507,13 +506,6 @@ suite('User Uri Provider', () => { if (server instanceof InputFlowAction || server === 'back') { throw new Error('Server not returned'); } - verify( - applicationShell.showWarningMessage( - DataScience.insecureSessionMessage, - Common.bannerLabelYes, - Common.bannerLabelNo - ) - ).never(); assert.isFalse(secureConnectionStub.called); const servers = await provider.getJupyterServers(token); assert.isAtLeast(servers.length, 3, '2 migrated urls and one entered'); @@ -529,4 +521,102 @@ suite('User Uri Provider', () => { assert.strictEqual(serversInNewStorage.length, 3); assert.strictEqual(serversInNewStorage2.length, 3); }); + test('When pre-populating with https url and without password auth, the next step should be the displayName & back from displayName should get out of this UI flow (without displaying the Url picker)', async () => { + await testMigration(); + getPasswordConnectionInfoStub.restore(); + getPasswordConnectionInfoStub.reset(); + const urlInputStub = sinon.stub(UserJupyterServerUriInput.prototype, 'getUrlFromUser'); + urlInputStub.resolves(); + sinon.stub(JupyterPasswordConnect.prototype, 'getPasswordConnectionInfo').resolves({ requiresPassword: false }); + const secureConnectionStub = sinon.stub(SecureConnectionValidator.prototype, 'promptToUseInsecureConnections'); + secureConnectionStub.resolves(false); + const displayNameStub = sinon.stub(UserJupyterServerDisplayName.prototype, 'getDisplayName'); + displayNameStub.rejects(InputFlowAction.back); + + const [cmd] = await provider.getCommands('https://localhost:3333', token); + const server = await provider.handleCommand(cmd, token); + + assert.strictEqual(server, 'back'); + assert.strictEqual(displayNameStub.callCount, 1); + assert.strictEqual(urlInputStub.callCount, 0); // Since a url was provided we should never prompt for this, even when clicking back in display name. + }); + test('When pre-populating with https url and without password auth, the next step should be the displayName & cancel from displayName should get out of this UI flow (without displaying the Url picker)', async () => { + await testMigration(); + getPasswordConnectionInfoStub.restore(); + getPasswordConnectionInfoStub.reset(); + const urlInputStub = sinon.stub(UserJupyterServerUriInput.prototype, 'getUrlFromUser'); + urlInputStub.resolves(); + sinon.stub(JupyterPasswordConnect.prototype, 'getPasswordConnectionInfo').resolves({ requiresPassword: false }); + const secureConnectionStub = sinon.stub(SecureConnectionValidator.prototype, 'promptToUseInsecureConnections'); + secureConnectionStub.resolves(false); + const displayNameStub = sinon.stub(UserJupyterServerDisplayName.prototype, 'getDisplayName'); + displayNameStub.rejects(InputFlowAction.cancel); + + const [cmd] = await provider.getCommands('https://localhost:3333', token); + const server = await provider.handleCommand(cmd, token); + + assert.isUndefined(server); + assert.strictEqual(displayNameStub.callCount, 1); + assert.strictEqual(urlInputStub.callCount, 0); // Since a url was provided we should never prompt for this, even when clicking back in display name. + }); + test('When pre-populating with https url and without password auth, and the server is invalid the next step should be the url display', async () => { + await testMigration(); + getPasswordConnectionInfoStub.restore(); + getPasswordConnectionInfoStub.reset(); + const urlInputStub = sinon.stub(UserJupyterServerUriInput.prototype, 'getUrlFromUser'); + let getUrlFromUserCallCount = 0; + urlInputStub.callsFake(async (_initialValue, errorMessage, _) => { + switch (getUrlFromUserCallCount++) { + case 0: { + // Originally we should be called with an error message. + assert.isOk(errorMessage, 'Error Message should not be empty'); + return { + jupyterServerUri: { + baseUrl: 'https://localhost:9999/', + displayName: 'ABCD', + token: '' + }, + url: 'https://localhost:9999/?token=ABCD' + }; + } + case 1: { + // There should be no error message displayed, + // We should have come here from the back button of the display name. + assert.isEmpty(errorMessage, 'Error Message should be empty'); + // Lets get out of here. + throw InputFlowAction.back; + } + default: + throw new Error('Method should not be called again'); + } + }); + sinon.stub(JupyterPasswordConnect.prototype, 'getPasswordConnectionInfo').resolves({ requiresPassword: false }); + const displayNameStub = sinon.stub(UserJupyterServerDisplayName.prototype, 'getDisplayName'); + displayNameStub.rejects(InputFlowAction.back); + when(jupyterConnection.validateRemoteUri(anything(), anything(), true)).thenCall( + (_, uri: IJupyterServerUri) => { + if (!uri) { + return; + } + if (uri.baseUrl.startsWith('https://localhost:9999')) { + return; + } + throw new Error('Remote Connection Failure'); + } + ); + + // Steps + // 1. First provide a url https://localhost:3333 to a server that is non-existent + // 2. Verify the error message is displayed and user is prompted to enter the Url again. + // 3. Next verify the user is prompted for a display name + // 4. When we click back button on display name ui, ensure we go back to Url ui. + // 5. Hitting back button on Url ui should exit out completely + + const [cmd] = await provider.getCommands('https://localhost:3333', token); + const server = await provider.handleCommand(cmd, token); + + assert.strictEqual(server, 'back'); + assert.strictEqual(displayNameStub.callCount, 1); + assert.strictEqual(urlInputStub.callCount, 2); // Displayed twice, first time for error message, second time when hit back button from display UI. + }); }); diff --git a/src/standalone/userJupyterServer/userServerUrlProvider.ts b/src/standalone/userJupyterServer/userServerUrlProvider.ts index f31d9a85718..c5947f85eea 100644 --- a/src/standalone/userJupyterServer/userServerUrlProvider.ts +++ b/src/standalone/userJupyterServer/userServerUrlProvider.ts @@ -542,7 +542,6 @@ export class UserJupyterServerUrlProvider disposeAllDisposables(passwordDisposables); } } - if (token.isCancellationRequested) { return InputFlowAction.cancel; } diff --git a/src/test/datascience/jupyter/connection.vscode.test.ts b/src/test/datascience/jupyter/connection.vscode.test.ts index 0bc03a7a124..64cccb8c80d 100644 --- a/src/test/datascience/jupyter/connection.vscode.test.ts +++ b/src/test/datascience/jupyter/connection.vscode.test.ts @@ -16,7 +16,6 @@ import { } from '../../../platform/common/types'; import { IS_REMOTE_NATIVE_TEST, initialize } from '../../initialize.node'; import { startJupyterServer, closeNotebooksAndCleanUpAfterTests } from '../notebook/helper.node'; -import { hijackPrompt } from '../notebook/helper'; import { SecureConnectionValidator, UserJupyterServerDisplayName, @@ -36,7 +35,7 @@ import { disposeAllDisposables } from '../../../platform/common/helpers'; import { anything, instance, mock, when } from 'ts-mockito'; import { CancellationTokenSource, Disposable, EventEmitter, InputBox, Memento } from 'vscode'; import { noop } from '../../../platform/common/utils/misc'; -import { Common, DataScience } from '../../../platform/common/utils/localize'; +import { DataScience } from '../../../platform/common/utils/localize'; import * as sinon from 'sinon'; import assert from 'assert'; import { createDeferred, createDeferredFromPromise } from '../../../platform/common/utils/async'; @@ -167,14 +166,6 @@ suite('Connect to Remote Jupyter Servers', function () { disposables.push(onDidRemoveUriStorage); when(serverUriStorage.onDidRemove).thenReturn(onDidRemoveUriStorage.event); - const prompt = await hijackPrompt( - 'showWarningMessage', - { contains: DataScience.insecureSessionMessage }, - { clickImmediately: true, result: Common.bannerLabelYes }, - disposables - ); - disposables.push(prompt); - userUriProvider = new UserJupyterServerUrlProvider( instance(clipboard), appShell,