From ab186d78c9ef3036352744583df02275f2e300e3 Mon Sep 17 00:00:00 2001 From: Alena Khineika Date: Tue, 12 May 2020 08:38:26 +0200 Subject: [PATCH 1/7] test: add tests for the new connection event --- src/connectionController.ts | 2 +- src/editors/playgroundController.ts | 4 +- src/mdbExtensionController.ts | 14 +- src/telemetry/telemetryController.ts | 10 +- .../suite/explorer/explorerController.test.ts | 16 +-- src/test/suite/extension.test.ts | 130 +++++++++--------- src/test/suite/index.ts | 74 +++++----- src/test/suite/mdbExtensionController.test.ts | 117 +++++----------- .../telemetry/telemetryController.test.ts | 108 +++++++++++---- src/views/webviewController.ts | 16 ++- 10 files changed, 252 insertions(+), 239 deletions(-) diff --git a/src/connectionController.ts b/src/connectionController.ts index f4090f1ae..d1c6ee326 100644 --- a/src/connectionController.ts +++ b/src/connectionController.ts @@ -441,7 +441,7 @@ export default class ConnectionController { this.eventEmitter.emit(DataServiceEventTypes.CONNECTIONS_DID_CHANGE); this.eventEmitter.emit(DataServiceEventTypes.ACTIVE_CONNECTION_CHANGED); - if (this._telemetryController) { + if (this._telemetryController?.needTelemetry()) { this.sendTelemetry(newDataService, connectionType); } diff --git a/src/editors/playgroundController.ts b/src/editors/playgroundController.ts index cbf412457..5ffcaf601 100644 --- a/src/editors/playgroundController.ts +++ b/src/editors/playgroundController.ts @@ -168,9 +168,9 @@ export default class PlaygroundController { codeToEvaluate ); - if (result) { + if (result && this._telemetryController?.needTelemetry()) { // Send metrics to Segment - this._telemetryController?.track( + this._telemetryController.track( TelemetryEventTypes.PLAYGROUND_CODE_EXECUTED, this.prepareTelemetry(result) ); diff --git a/src/mdbExtensionController.ts b/src/mdbExtensionController.ts index 58fff842e..7cc42424c 100644 --- a/src/mdbExtensionController.ts +++ b/src/mdbExtensionController.ts @@ -137,12 +137,14 @@ export default class MDBExtensionController implements vscode.Disposable { ): void => { const commandHandlerWithTelemetry = (args: any[]) => { // Send metrics to Segment - this._telemetryController?.track( - TelemetryEventTypes.EXTENSION_COMMAND_RUN, - { - command - } - ); + if (this._telemetryController?.needTelemetry()) { + this._telemetryController.track( + TelemetryEventTypes.EXTENSION_COMMAND_RUN, + { + command + } + ); + } return commandHandler(args); }; diff --git a/src/telemetry/telemetryController.ts b/src/telemetry/telemetryController.ts index 2b215b9c1..108cd96f3 100644 --- a/src/telemetry/telemetryController.ts +++ b/src/telemetry/telemetryController.ts @@ -110,21 +110,21 @@ export default class TelemetryController { this._segmentAnalytics?.flush(); } + public needTelemetry() { + return vscode.workspace.getConfiguration('mdb').get('sendTelemetry'); + } + public track( eventType: TelemetryEventTypes, properties: TelemetryEventProperties ): void { - const shouldSendTelemetry = vscode.workspace - .getConfiguration('mdb') - .get('sendTelemetry'); - log.info('TELEMETRY track', { eventType, segmentUserID: this._segmentUserID, properties }); - if (shouldSendTelemetry) { + if (this.needTelemetry()) { this._segmentAnalytics?.track( { userId: this._segmentUserID, diff --git a/src/test/suite/explorer/explorerController.test.ts b/src/test/suite/explorer/explorerController.test.ts index 19bd0d20b..acf476917 100644 --- a/src/test/suite/explorer/explorerController.test.ts +++ b/src/test/suite/explorer/explorerController.test.ts @@ -17,11 +17,9 @@ const testDatabaseURI2WithTimeout = suite('Explorer Controller Test Suite', () => { beforeEach(async () => { - sinon.replace( - mdbTestExtension.testExtensionController._connectionController, - '_telemetryController', - {} - ); + await vscode.workspace + .getConfiguration('mdb') + .update('sendTelemetry', false); // Don't save connections on default. await vscode.workspace .getConfiguration('mdb.connectionSaving') @@ -30,6 +28,7 @@ suite('Explorer Controller Test Suite', () => { DefaultSavingLocations['Session Only'] ); }); + afterEach(async () => { // Unset the variable we set in `beforeEach`. await vscode.workspace @@ -46,7 +45,6 @@ suite('Explorer Controller Test Suite', () => { test('should have a connections root', (done) => { const testExplorerController = mdbTestExtension.testExtensionController._explorerController; - const treeController = testExplorerController.getTreeController(); assert(!!treeController, 'Tree controller should not be undefined'); @@ -70,9 +68,7 @@ suite('Explorer Controller Test Suite', () => { mdbTestExtension.testExtensionController._connectionController; const testExplorerController = mdbTestExtension.testExtensionController._explorerController; - const treeController = testExplorerController.getTreeController(); - const mockConnectionId = 'testConnectionId'; testConnectionController._connections = { @@ -110,7 +106,6 @@ suite('Explorer Controller Test Suite', () => { mdbTestExtension.testExtensionController._connectionController; const testExplorerController = mdbTestExtension.testExtensionController._explorerController; - const treeController = testExplorerController.getTreeController(); testConnectionController @@ -165,7 +160,6 @@ suite('Explorer Controller Test Suite', () => { mdbTestExtension.testExtensionController._connectionController; const testExplorerController = mdbTestExtension.testExtensionController._explorerController; - const treeController = testExplorerController.getTreeController(); testConnectionController @@ -239,7 +233,6 @@ suite('Explorer Controller Test Suite', () => { mdbTestExtension.testExtensionController._connectionController; const testExplorerController = mdbTestExtension.testExtensionController._explorerController; - const treeController = testExplorerController.getTreeController(); testConnectionController @@ -275,7 +268,6 @@ suite('Explorer Controller Test Suite', () => { mdbTestExtension.testExtensionController._connectionController; const testExplorerController = mdbTestExtension.testExtensionController._explorerController; - const treeController = testExplorerController.getTreeController(); testConnectionController diff --git a/src/test/suite/extension.test.ts b/src/test/suite/extension.test.ts index 30f43eeb7..a74c90980 100644 --- a/src/test/suite/extension.test.ts +++ b/src/test/suite/extension.test.ts @@ -1,23 +1,42 @@ import * as assert from 'assert'; import * as vscode from 'vscode'; -import { afterEach } from 'mocha'; +import { before, after } from 'mocha'; import * as sinon from 'sinon'; import MDBExtensionController from '../../mdbExtensionController'; import { TestExtensionContext } from './stubs'; import { TEST_DATABASE_URI } from './dbTestHelper'; +import ConnectionController from '../../connectionController'; +import { StorageController } from '../../storage'; +import { StatusView } from '../../views'; suite('Extension Test Suite', () => { vscode.window.showInformationMessage('Starting tests...'); const disposables: vscode.Disposable[] = []; + const mockExtensionContext = new TestExtensionContext(); + const mockMDBExtension = new MDBExtensionController(mockExtensionContext); + const mockStorageController = new StorageController(mockExtensionContext); + const testConnectionController = new ConnectionController( + new StatusView(mockExtensionContext), + mockStorageController + ); + const sandbox = sinon.createSandbox(); + let fakeShowErrorMessage: any; + + before(async () => { + await vscode.workspace + .getConfiguration('mdb') + .update('sendTelemetry', false); + sandbox.stub(vscode.window, 'showInformationMessage'); + fakeShowErrorMessage = sandbox.stub(vscode.window, 'showErrorMessage'); + }); - afterEach(() => { + after(() => { disposables.forEach((d) => d.dispose()); disposables.length = 0; - - sinon.restore(); + sandbox.restore(); }); test('commands are registered in vscode', (done) => { @@ -70,47 +89,21 @@ suite('Extension Test Suite', () => { }); test('openMongoDBShell should display an error message when not connected', (done) => { - const mockExtensionContext = new TestExtensionContext(); + const errorMessage = + 'You need to be connected before launching the MongoDB Shell.'; - const fakeVscodeErrorMessage = sinon.fake(); - sinon.replace(vscode.window, 'showErrorMessage', fakeVscodeErrorMessage); - - const mockMDBExtension = new MDBExtensionController(mockExtensionContext); + fakeShowErrorMessage.resolves(errorMessage); mockMDBExtension .openMongoDBShell() .then((didOpenShell) => { assert(didOpenShell === false); - assert( - fakeVscodeErrorMessage.firstArg === - 'You need to be connected before launching the MongoDB Shell.' - ); + sinon.assert.calledWith(fakeShowErrorMessage, errorMessage); }) .then(done, done); }); test('openMongoDBShell should open a terminal with the active connection driver url', (done) => { - const mockExtensionContext = new TestExtensionContext(); - - const mockMDBExtension = new MDBExtensionController(mockExtensionContext); - const testConnectionController = mockMDBExtension._connectionController; - - const fakeVscodeInfoMessage = sinon.fake(); - - sinon.replace( - vscode.window, - 'showInformationMessage', - fakeVscodeInfoMessage - ); - sinon.replace( - testConnectionController._telemetryController, - 'track', - () => {} - ); - sinon.replace(testConnectionController, 'getCloudInfoFromDataService', () => - Promise.resolve() - ); - testConnectionController .addNewConnectionStringAndConnect(TEST_DATABASE_URI) .then((succesfullyConnected) => { @@ -119,38 +112,45 @@ suite('Extension Test Suite', () => { 'Expected a successful connection response.' ); - const spyActiveConnectionDriverUrl = sinon.spy( - testConnectionController, - 'getActiveConnectionDriverUrl' - ); - const createTerminalSpy = sinon.spy(vscode.window, 'createTerminal'); - - disposables.push( - vscode.window.onDidOpenTerminal(() => { - testConnectionController.disconnect(); - - try { - assert(spyActiveConnectionDriverUrl.called); - assert(createTerminalSpy.called); - const expectedUri = - 'mongodb://localhost:27018/?readPreference=primary&ssl=false'; - assert( - createTerminalSpy.getCall(0).args[0].env - .MDB_CONNECTION_STRING === expectedUri, - `Expected open terminal to set env var 'MDB_CONNECTION_STRING' to ${expectedUri} found ${ - createTerminalSpy.getCall(0).args[0].env.MDB_CONNECTION_STRING - }` - ); - } catch (e) { - done(e); - return; - } - - done(); - }) - ); + mockMDBExtension + .openMongoDBShell() + .then(() => { + const spyActiveConnectionDriverUrl = sinon.spy( + testConnectionController, + 'getActiveConnectionDriverUrl' + ); + const createTerminalSpy = sinon.spy( + vscode.window, + 'createTerminal' + ); - mockMDBExtension.openMongoDBShell(); + disposables.push( + vscode.window.onDidOpenTerminal(() => { + testConnectionController.disconnect(); + + try { + assert(spyActiveConnectionDriverUrl.called); + assert(createTerminalSpy.called); + const expectedUri = + 'mongodb://localhost:27018/?readPreference=primary&ssl=false'; + assert( + createTerminalSpy.getCall(0).args[0].env + .MDB_CONNECTION_STRING === expectedUri, + `Expected open terminal to set env var 'MDB_CONNECTION_STRING' to ${expectedUri} found ${ + createTerminalSpy.getCall(0).args[0].env + .MDB_CONNECTION_STRING + }` + ); + } catch (e) { + done(e); + return; + } + + done(); + }) + ); + }) + .then(done, done); }); }); }); diff --git a/src/test/suite/index.ts b/src/test/suite/index.ts index f3b087ff7..bf021d19e 100644 --- a/src/test/suite/index.ts +++ b/src/test/suite/index.ts @@ -38,40 +38,52 @@ export function run(): Promise { mdbTestExtension.testExtensionController.activate(); // Disable the dialogue for prompting the user where to store the connection. - vscode.workspace.getConfiguration('mdb.connectionSaving').update( - 'hideOptionToChooseWhereToSaveNewConnections', - true - ).then(async () => { - // We require keytar in runtime because it is a vscode provided - // native node module. - const keytar: typeof keytarType = require('keytar'); - const existingCredentials = await keytar.findCredentials('mdb.vscode.savedConnections'); + vscode.workspace + .getConfiguration('mdb.connectionSaving') + .update('hideOptionToChooseWhereToSaveNewConnections', true) + .then(async () => { + // We require keytar in runtime because it is a vscode provided + // native node module. + const keytar: typeof keytarType = require('keytar'); + const existingCredentials = await keytar.findCredentials( + 'mdb.vscode.savedConnections' + ); - // Add files to the test suite. - files.forEach(f => mocha.addFile(path.resolve(testsRoot, f))); - try { - // Run the mocha test. - mocha.run(async (failures) => { - // After tests are run we clear any passwords added - // to local secure storage. - const postRunCredentials = await keytar.findCredentials('mdb.vscode.savedConnections'); - postRunCredentials.forEach(credential => { - if (!existingCredentials.find(existingCredential => existingCredential.account === credential.account)) { - // If the credential is newly added, we remove it. - keytar.deletePassword('mdb.vscode.savedConnections', credential.account); + // Add files to the test suite. + files.forEach((f) => mocha.addFile(path.resolve(testsRoot, f))); + try { + // Run the mocha test. + mocha.run(async (failures) => { + // After tests are run we clear any passwords added + // to local secure storage. + const postRunCredentials = await keytar.findCredentials( + 'mdb.vscode.savedConnections' + ); + postRunCredentials.forEach((credential) => { + if ( + !existingCredentials.find( + (existingCredential) => + existingCredential.account === credential.account + ) + ) { + // If the credential is newly added, we remove it. + keytar.deletePassword( + 'mdb.vscode.savedConnections', + credential.account + ); + } + }); + + if (failures > 0) { + e(new Error(`${failures} tests failed.`)); + } else { + c(); } }); - - if (failures > 0) { - e(new Error(`${failures} tests failed.`)); - } else { - c(); - } - }); - } catch (mochaRunErr) { - e(mochaRunErr); - } - }); + } catch (mochaRunErr) { + e(mochaRunErr); + } + }); }); }); } diff --git a/src/test/suite/mdbExtensionController.test.ts b/src/test/suite/mdbExtensionController.test.ts index d0f7aee55..8149d6dd7 100644 --- a/src/test/suite/mdbExtensionController.test.ts +++ b/src/test/suite/mdbExtensionController.test.ts @@ -13,21 +13,16 @@ import { SchemaTreeItem } from '../../explorer'; import { mdbTestExtension } from './stubbableMdbExtension'; -import ConnectionController from '../../connectionController'; -import { StorageController } from '../../storage'; import { StorageScope } from '../../storage/storageController'; -import TelemetryController from '../../telemetry/telemetryController'; const sinon = require('sinon'); const testDatabaseURI = 'mongodb://localhost:27018'; suite('MDBExtensionController Test Suite', () => { - beforeEach(() => { - sinon.replace( - mdbTestExtension.testExtensionController._telemetryController, - 'track', - () => {} - ); + beforeEach(async () => { + await vscode.workspace + .getConfiguration('mdb') + .update('sendTelemetry', false); // Here we stub the showInformationMessage process because it is too much // for the render process and leads to crashes while testing. sinon.replace(vscode.window, 'showInformationMessage', sinon.stub()); @@ -781,19 +776,8 @@ suite('MDBExtensionController Test Suite', () => { }); test('mdb.dropCollection fails when a collection doesnt exist', (done) => { - const mockExtensionContext = mdbTestExtension.testExtensionContext; - const mockStorageController = new StorageController(mockExtensionContext); - const mockTelemetryController = new TelemetryController( - mockStorageController, - mockExtensionContext - ); - const testConnectionController = new ConnectionController( - mdbTestExtension.testExtensionController._statusView, - mockStorageController, - mockTelemetryController - ); - - mockTelemetryController.track = () => {}; + const testConnectionController = + mdbTestExtension.testExtensionController._connectionController; testConnectionController .addNewConnectionStringAndConnect(testDatabaseURI) @@ -907,19 +891,8 @@ suite('MDBExtensionController Test Suite', () => { }); test('mdb.dropDatabase succeeds even when a database doesnt exist (mdb behavior)', (done) => { - const mockExtensionContext = mdbTestExtension.testExtensionContext; - const mockStorageController = new StorageController(mockExtensionContext); - const mockTelemetryController = new TelemetryController( - mockStorageController, - mockExtensionContext - ); - const testConnectionController = new ConnectionController( - mdbTestExtension.testExtensionController._statusView, - mockStorageController, - mockTelemetryController - ); - - mockTelemetryController.track = () => {}; + const testConnectionController = + mdbTestExtension.testExtensionController._connectionController; testConnectionController .addNewConnectionStringAndConnect(testDatabaseURI) @@ -1126,40 +1099,26 @@ suite('MDBExtensionController Test Suite', () => { .then(done, done); }); - test('mdb.createPlayground should create a MongoDB playground with default template', (done) => { + test('mdb.createPlayground should create a MongoDB playground with default template', async () => { const mockOpenTextDocument = sinon.fake.resolves('untitled'); sinon.replace(vscode.workspace, 'openTextDocument', mockOpenTextDocument); const mockShowTextDocument = sinon.fake.resolves(); sinon.replace(vscode.window, 'showTextDocument', mockShowTextDocument); - const mockGetPlaygroundConfiguration = sinon.fake.returns({ - get: (prop) => { - assert(prop === 'useDefaultTemplateForPlayground'); - return true; - } - }); - sinon.replace( - vscode.workspace, - 'getConfiguration', - mockGetPlaygroundConfiguration - ); + await vscode.workspace + .getConfiguration('mdb') + .update('useDefaultTemplateForPlayground', true); + await vscode.commands.executeCommand('mdb.createPlayground'); - vscode.commands - .executeCommand('mdb.createPlayground') - .then(() => { - assert(mockOpenTextDocument.firstArg.language === 'mongodb'); - assert( - mockOpenTextDocument.firstArg.content.startsWith( - '// MongoDB Playground' - ) - ); - assert( - mockShowTextDocument.firstArg === 'untitled', - 'Expected it to call vscode to show the playground' - ); - }) - .then(done, done); + assert(mockOpenTextDocument.firstArg.language === 'mongodb'); + assert( + mockOpenTextDocument.firstArg.content.startsWith('// MongoDB Playground') + ); + assert( + mockShowTextDocument.firstArg === 'untitled', + 'Expected it to call vscode to show the playground' + ); }); test('mdb.createNewPlaygroundFromViewAction should create a MongoDB playground', (done) => { @@ -1181,36 +1140,24 @@ suite('MDBExtensionController Test Suite', () => { .then(done, done); }); - test('mdb.createPlayground command should create a MongoDB playground without template', (done) => { + test('mdb.createPlayground command should create a MongoDB playground without template', async () => { const mockOpenTextDocument = sinon.fake.resolves('untitled'); sinon.replace(vscode.workspace, 'openTextDocument', mockOpenTextDocument); const mockShowTextDocument = sinon.fake.resolves(); sinon.replace(vscode.window, 'showTextDocument', mockShowTextDocument); - const mockGetPlaygroundConfiguration = sinon.fake.returns({ - get: (prop) => { - assert(prop === 'useDefaultTemplateForPlayground'); - return false; - } - }); - sinon.replace( - vscode.workspace, - 'getConfiguration', - mockGetPlaygroundConfiguration - ); + await vscode.workspace + .getConfiguration('mdb') + .update('useDefaultTemplateForPlayground', false); + await vscode.commands.executeCommand('mdb.createPlayground'); - vscode.commands - .executeCommand('mdb.createPlayground') - .then(() => { - assert(mockOpenTextDocument.firstArg.language === 'mongodb'); - assert(mockOpenTextDocument.firstArg.content === ''); - assert( - mockShowTextDocument.firstArg === 'untitled', - 'Expected it to call vscode to show the playground' - ); - }) - .then(done, done); + assert(mockOpenTextDocument.firstArg.language === 'mongodb'); + assert(mockOpenTextDocument.firstArg.content === ''); + assert( + mockShowTextDocument.firstArg === 'untitled', + 'Expected it to call vscode to show the playground' + ); }); test('mdb.runAllPlaygroundBlocks command should call runAllPlaygroundBlocks on the playground controller', (done) => { diff --git a/src/test/suite/telemetry/telemetryController.test.ts b/src/test/suite/telemetry/telemetryController.test.ts index 4b125f716..06c1c1f9c 100644 --- a/src/test/suite/telemetry/telemetryController.test.ts +++ b/src/test/suite/telemetry/telemetryController.test.ts @@ -8,6 +8,9 @@ import TelemetryController, { } from '../../../telemetry/telemetryController'; import { mdbTestExtension } from '../stubbableMdbExtension'; import { afterEach, beforeEach } from 'mocha'; +import { TEST_DATABASE_URI } from './../dbTestHelper'; +import Connection = require('mongodb-connection-model/lib/model'); +import { StorageScope } from '../../../storage/storageController'; const sinon = require('sinon'); const chai = require('chai'); @@ -23,29 +26,37 @@ suite('Telemetry Controller Test Suite', () => { const mockExtensionContext = new TestExtensionContext(); const mockStorageController = new StorageController(mockExtensionContext); + const testTelemetryController = new TelemetryController( + mockStorageController, + mockExtensionContext + ); let mockTelemetryTrackMethod: void; let mockExecuteAllMethod: Promise; let mockGetCloudInfoFromDataService: Promise; - beforeEach(() => { - mockTelemetryTrackMethod = sinon.fake.resolves(); + beforeEach(async () => { + await vscode.workspace + .getConfiguration('mdb') + .update('sendTelemetry', true); + mockTelemetryTrackMethod = sinon.fake(); + mockExecuteAllMethod = sinon.fake.resolves({ + shellApiType: 'TEST' + }); + mockGetCloudInfoFromDataService = sinon.fake.resolves({ + isPublicCloud: false, + publicCloudName: null + }); + sinon.replace( mdbTestExtension.testExtensionController._telemetryController, 'track', mockTelemetryTrackMethod ); - mockExecuteAllMethod = sinon.fake.resolves({ - shellApiType: 'TEST' - }); sinon.replace( mdbTestExtension.testExtensionController._languageServerController, 'executeAll', mockExecuteAllMethod ); - mockGetCloudInfoFromDataService = sinon.fake.resolves({ - isPublicCloud: false, - publicCloudName: null - }); sinon.replace( mdbTestExtension.testExtensionController._connectionController, 'getCloudInfoFromDataService', @@ -57,11 +68,7 @@ suite('Telemetry Controller Test Suite', () => { sinon.restore(); }); - test('get segment key from constants keyfile', () => { - const testTelemetryController = new TelemetryController( - mockStorageController, - mockExtensionContext - ); + test('get segment key and user id', () => { let segmentKey: string | undefined; try { @@ -73,14 +80,6 @@ suite('Telemetry Controller Test Suite', () => { expect(segmentKey).to.be.equal(process.env.SEGMENT_KEY); expect(testTelemetryController.segmentKey).to.be.a('string'); - }); - - test('get user id from the global storage', () => { - const testTelemetryController = new TelemetryController( - mockStorageController, - mockExtensionContext - ); - expect(testTelemetryController.segmentUserID).to.be.a('string'); }); @@ -100,9 +99,10 @@ suite('Telemetry Controller Test Suite', () => { }); test('track playground code executed event', async () => { - await mdbTestExtension.testExtensionController._playgroundController.evaluate( - 'show dbs' - ); + const mockPlaygroundController = + mdbTestExtension.testExtensionController._playgroundController; + + await mockPlaygroundController.evaluate('show dbs'); sinon.assert.calledWith( mockTelemetryTrackMethod, @@ -112,4 +112,62 @@ suite('Telemetry Controller Test Suite', () => { } ); }); + + test('test new connection event when connecting via connection string', (done) => { + const mockConnectionController = + mdbTestExtension.testExtensionController._connectionController; + + mockConnectionController + .addNewConnectionStringAndConnect(TEST_DATABASE_URI) + .then(() => { + setTimeout(() => { + sinon.assert.called(mockTelemetryTrackMethod); + done(); + }, 500); + }); + }); + + test('test new connection event when connecting via connection form', (done) => { + const mockConnectionController = + mdbTestExtension.testExtensionController._connectionController; + + mockConnectionController + .parseNewConnectionAndConnect( + new Connection({ + hostname: 'localhost', + port: 27018 + }) + ) + .then(() => { + setTimeout(() => { + sinon.assert.called(mockTelemetryTrackMethod); + done(); + }, 500); + }); + }); + + test('test new connection event when connecting via saved connection', (done) => { + const mockConnectionController = + mdbTestExtension.testExtensionController._connectionController; + + mockConnectionController._connections = { + '25': { + id: '25', + driverUrl: TEST_DATABASE_URI, + name: 'tester', + connectionModel: new Connection({ + hostname: 'localhost', + port: 27018 + }), + storageLocation: StorageScope.NONE + } + }; + + mockConnectionController.connectWithConnectionId('25').then(() => { + setTimeout(() => { + sinon.assert.called(mockTelemetryTrackMethod); + done(); + }, 500); + }); + }); }); diff --git a/src/views/webviewController.ts b/src/views/webviewController.ts index e03c6fa15..160e895ba 100644 --- a/src/views/webviewController.ts +++ b/src/views/webviewController.ts @@ -124,13 +124,15 @@ export default class WebviewController { return; case MESSAGE_TYPES.EXTENSION_LINK_CLICKED: - this._telemetryController?.track( - TelemetryEventTypes.EXTENSION_LINK_CLICKED, - { - screen: message.screen, - linkId: message.linkId - } - ); + if (this._telemetryController?.needTelemetry()) { + this._telemetryController.track( + TelemetryEventTypes.EXTENSION_LINK_CLICKED, + { + screen: message.screen, + linkId: message.linkId + } + ); + } return; default: From 2c46dd23605682ccaf8d5559da6be38c131484dc Mon Sep 17 00:00:00 2001 From: Alena Khineika Date: Tue, 12 May 2020 09:35:31 +0200 Subject: [PATCH 2/7] test: mock sendTelemetry --- .../telemetry/telemetryController.test.ts | 56 +++++++++---------- 1 file changed, 26 insertions(+), 30 deletions(-) diff --git a/src/test/suite/telemetry/telemetryController.test.ts b/src/test/suite/telemetry/telemetryController.test.ts index 06c1c1f9c..2d6e4a828 100644 --- a/src/test/suite/telemetry/telemetryController.test.ts +++ b/src/test/suite/telemetry/telemetryController.test.ts @@ -33,6 +33,7 @@ suite('Telemetry Controller Test Suite', () => { let mockTelemetryTrackMethod: void; let mockExecuteAllMethod: Promise; let mockGetCloudInfoFromDataService: Promise; + let mockSendTelemetry: Promise; beforeEach(async () => { await vscode.workspace @@ -46,6 +47,7 @@ suite('Telemetry Controller Test Suite', () => { isPublicCloud: false, publicCloudName: null }); + mockSendTelemetry = sinon.fake.resolves({}); sinon.replace( mdbTestExtension.testExtensionController._telemetryController, @@ -62,6 +64,11 @@ suite('Telemetry Controller Test Suite', () => { 'getCloudInfoFromDataService', mockGetCloudInfoFromDataService ); + sinon.replace( + mdbTestExtension.testExtensionController._connectionController, + 'sendTelemetry', + mockSendTelemetry + ); }); afterEach(() => { @@ -113,40 +120,32 @@ suite('Telemetry Controller Test Suite', () => { ); }); - test('test new connection event when connecting via connection string', (done) => { + test('test new connection event when connecting via connection string', async () => { const mockConnectionController = mdbTestExtension.testExtensionController._connectionController; - mockConnectionController - .addNewConnectionStringAndConnect(TEST_DATABASE_URI) - .then(() => { - setTimeout(() => { - sinon.assert.called(mockTelemetryTrackMethod); - done(); - }, 500); - }); + await mockConnectionController.addNewConnectionStringAndConnect( + TEST_DATABASE_URI + ); + + sinon.assert.called(mockSendTelemetry); }); - test('test new connection event when connecting via connection form', (done) => { + test('test new connection event when connecting via connection form', async () => { const mockConnectionController = mdbTestExtension.testExtensionController._connectionController; - mockConnectionController - .parseNewConnectionAndConnect( - new Connection({ - hostname: 'localhost', - port: 27018 - }) - ) - .then(() => { - setTimeout(() => { - sinon.assert.called(mockTelemetryTrackMethod); - done(); - }, 500); - }); + await mockConnectionController.parseNewConnectionAndConnect( + new Connection({ + hostname: 'localhost', + port: 27018 + }) + ); + + sinon.assert.called(mockSendTelemetry); }); - test('test new connection event when connecting via saved connection', (done) => { + test('test new connection event when connecting via saved connection', async () => { const mockConnectionController = mdbTestExtension.testExtensionController._connectionController; @@ -163,11 +162,8 @@ suite('Telemetry Controller Test Suite', () => { } }; - mockConnectionController.connectWithConnectionId('25').then(() => { - setTimeout(() => { - sinon.assert.called(mockTelemetryTrackMethod); - done(); - }, 500); - }); + await mockConnectionController.connectWithConnectionId('25'); + + sinon.assert.called(mockSendTelemetry); }); }); From 730f90cff903c50db7954a9db740dadb2d92cc66 Mon Sep 17 00:00:00 2001 From: Alena Khineika Date: Tue, 12 May 2020 09:44:47 +0200 Subject: [PATCH 3/7] test: use done --- .../telemetry/telemetryController.test.ts | 43 +++++++++++-------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/src/test/suite/telemetry/telemetryController.test.ts b/src/test/suite/telemetry/telemetryController.test.ts index 2d6e4a828..c94ddb78b 100644 --- a/src/test/suite/telemetry/telemetryController.test.ts +++ b/src/test/suite/telemetry/telemetryController.test.ts @@ -120,32 +120,36 @@ suite('Telemetry Controller Test Suite', () => { ); }); - test('test new connection event when connecting via connection string', async () => { + test('test new connection event when connecting via connection string', (done) => { const mockConnectionController = mdbTestExtension.testExtensionController._connectionController; - await mockConnectionController.addNewConnectionStringAndConnect( - TEST_DATABASE_URI - ); - - sinon.assert.called(mockSendTelemetry); + mockConnectionController + .addNewConnectionStringAndConnect(TEST_DATABASE_URI) + .then(() => { + sinon.assert.called(mockSendTelemetry); + done(); + }); }); - test('test new connection event when connecting via connection form', async () => { + test('test new connection event when connecting via connection form', (done) => { const mockConnectionController = mdbTestExtension.testExtensionController._connectionController; - await mockConnectionController.parseNewConnectionAndConnect( - new Connection({ - hostname: 'localhost', - port: 27018 - }) - ); - - sinon.assert.called(mockSendTelemetry); + mockConnectionController + .parseNewConnectionAndConnect( + new Connection({ + hostname: 'localhost', + port: 27018 + }) + ) + .then(() => { + sinon.assert.called(mockSendTelemetry); + done(); + }); }); - test('test new connection event when connecting via saved connection', async () => { + test('test new connection event when connecting via saved connection', (done) => { const mockConnectionController = mdbTestExtension.testExtensionController._connectionController; @@ -162,8 +166,9 @@ suite('Telemetry Controller Test Suite', () => { } }; - await mockConnectionController.connectWithConnectionId('25'); - - sinon.assert.called(mockSendTelemetry); + mockConnectionController.connectWithConnectionId('25').then(() => { + sinon.assert.called(mockSendTelemetry); + done(); + }); }); }); From 66014b2195d183836560f7cf927440406cceea6d Mon Sep 17 00:00:00 2001 From: Alena Khineika Date: Tue, 12 May 2020 09:57:52 +0200 Subject: [PATCH 4/7] test: mock connect --- .../suite/telemetry/telemetryController.test.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/test/suite/telemetry/telemetryController.test.ts b/src/test/suite/telemetry/telemetryController.test.ts index c94ddb78b..01bcf487d 100644 --- a/src/test/suite/telemetry/telemetryController.test.ts +++ b/src/test/suite/telemetry/telemetryController.test.ts @@ -33,7 +33,7 @@ suite('Telemetry Controller Test Suite', () => { let mockTelemetryTrackMethod: void; let mockExecuteAllMethod: Promise; let mockGetCloudInfoFromDataService: Promise; - let mockSendTelemetry: Promise; + let mockConnect: Promise; beforeEach(async () => { await vscode.workspace @@ -47,7 +47,7 @@ suite('Telemetry Controller Test Suite', () => { isPublicCloud: false, publicCloudName: null }); - mockSendTelemetry = sinon.fake.resolves({}); + mockConnect = sinon.fake.resolves(true); sinon.replace( mdbTestExtension.testExtensionController._telemetryController, @@ -66,8 +66,8 @@ suite('Telemetry Controller Test Suite', () => { ); sinon.replace( mdbTestExtension.testExtensionController._connectionController, - 'sendTelemetry', - mockSendTelemetry + 'connect', + mockConnect ); }); @@ -127,7 +127,7 @@ suite('Telemetry Controller Test Suite', () => { mockConnectionController .addNewConnectionStringAndConnect(TEST_DATABASE_URI) .then(() => { - sinon.assert.called(mockSendTelemetry); + sinon.assert.called(mockConnect); done(); }); }); @@ -144,7 +144,7 @@ suite('Telemetry Controller Test Suite', () => { }) ) .then(() => { - sinon.assert.called(mockSendTelemetry); + sinon.assert.called(mockConnect); done(); }); }); @@ -167,7 +167,7 @@ suite('Telemetry Controller Test Suite', () => { }; mockConnectionController.connectWithConnectionId('25').then(() => { - sinon.assert.called(mockSendTelemetry); + sinon.assert.called(mockConnect); done(); }); }); From bcf4895abebb056f984f8672608bbe3db41f53ac Mon Sep 17 00:00:00 2001 From: Alena Khineika Date: Tue, 12 May 2020 10:32:03 +0200 Subject: [PATCH 5/7] test: check connecting types --- .../telemetry/telemetryController.test.ts | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/test/suite/telemetry/telemetryController.test.ts b/src/test/suite/telemetry/telemetryController.test.ts index 01bcf487d..98a25007b 100644 --- a/src/test/suite/telemetry/telemetryController.test.ts +++ b/src/test/suite/telemetry/telemetryController.test.ts @@ -11,7 +11,7 @@ import { afterEach, beforeEach } from 'mocha'; import { TEST_DATABASE_URI } from './../dbTestHelper'; import Connection = require('mongodb-connection-model/lib/model'); import { StorageScope } from '../../../storage/storageController'; - +import { ConnectionTypes } from '../../../connectionController'; const sinon = require('sinon'); const chai = require('chai'); const sinonChai = require('sinon-chai'); @@ -127,7 +127,12 @@ suite('Telemetry Controller Test Suite', () => { mockConnectionController .addNewConnectionStringAndConnect(TEST_DATABASE_URI) .then(() => { - sinon.assert.called(mockConnect); + sinon.assert.calledWith( + mockConnect, + sinon.match.any, + sinon.match.any, + sinon.match(ConnectionTypes.CONNECTION_STRING) + ); done(); }); }); @@ -144,7 +149,12 @@ suite('Telemetry Controller Test Suite', () => { }) ) .then(() => { - sinon.assert.called(mockConnect); + sinon.assert.calledWith( + mockConnect, + sinon.match.any, + sinon.match.any, + sinon.match(ConnectionTypes.CONNECTION_FORM) + ); done(); }); }); @@ -167,7 +177,12 @@ suite('Telemetry Controller Test Suite', () => { }; mockConnectionController.connectWithConnectionId('25').then(() => { - sinon.assert.called(mockConnect); + sinon.assert.calledWith( + mockConnect, + sinon.match.any, + sinon.match.any, + sinon.match(ConnectionTypes.CONNECTION_ID) + ); done(); }); }); From 7a3fc8fd087fe1fcbf001fc121391e3d74f822c3 Mon Sep 17 00:00:00 2001 From: Alena Khineika Date: Tue, 12 May 2020 12:16:32 +0200 Subject: [PATCH 6/7] test: always pass telemetry to controllers --- src/connectionController.ts | 52 +++- src/editors/playgroundController.ts | 6 +- src/mdbExtensionController.ts | 14 +- src/telemetry/telemetryController.ts | 12 +- src/test/suite/connectionController.test.ts | 282 +++++++++++------- .../editors/activeDBCodeLensProvider.test.ts | 19 +- .../collectionDocumentsProvider.test.ts | 29 +- .../suite/editors/documentProvider.test.ts | 47 ++- .../editors/playgroundController.test.ts | 11 +- src/test/suite/extension.test.ts | 8 +- .../language/languageServerController.test.ts | 12 +- .../suite/views/webviewController.test.ts | 117 +++++--- src/views/webviewController.ts | 20 +- 13 files changed, 419 insertions(+), 210 deletions(-) diff --git a/src/connectionController.ts b/src/connectionController.ts index d1c6ee326..de2dba395 100644 --- a/src/connectionController.ts +++ b/src/connectionController.ts @@ -65,7 +65,7 @@ export default class ConnectionController { private _statusView: StatusView; private _storageController: StorageController; - public _telemetryController?: TelemetryController; + private _telemetryController: TelemetryController; // Used by other parts of the extension that respond to changes in the connections. private eventEmitter: EventEmitter = new EventEmitter(); @@ -73,7 +73,7 @@ export default class ConnectionController { constructor( _statusView: StatusView, storageController: StorageController, - telemetryController?: TelemetryController + telemetryController: TelemetryController ) { this._statusView = _statusView; this._storageController = storageController; @@ -102,6 +102,7 @@ export default class ConnectionController { } let loadedSavedConnection: LoadedConnection; + try { const unparsedConnectionInformation = await this._keytar.getPassword( this._serviceName, @@ -134,6 +135,7 @@ export default class ConnectionController { // connections have become corrupted. return Promise.resolve(); } + this._connections[connectionId] = loadedSavedConnection; this.eventEmitter.emit(DataServiceEventTypes.CONNECTIONS_DID_CHANGE); @@ -167,6 +169,7 @@ export default class ConnectionController { StorageVariables.WORKSPACE_SAVED_CONNECTIONS, StorageScope.WORKSPACE ) || {}; + if (Object.keys(existingWorkspaceConnections).length > 0) { // Try to pull in the connections previously saved on the workspace. await Promise.all( @@ -181,9 +184,10 @@ export default class ConnectionController { }; public async connectWithURI(): Promise { + let connectionString: any; + log.info('connectWithURI command called'); - let connectionString; try { connectionString = await vscode.window.showInputBox({ value: '', @@ -268,7 +272,6 @@ export default class ConnectionController { const { driverUrl, instanceId } = connectionModel.getAttributes({ derived: true }); - const connectionId = uuidv4(); const connectionInformation: SavedConnectionInformation = { connectionModel, @@ -285,6 +288,7 @@ export default class ConnectionController { ...savedConnection, ...connectionInformation }; + this._connections[connectionId] = newLoadedConnection; if (this._keytar) { @@ -339,6 +343,7 @@ export default class ConnectionController { if (error) { log.error('TELEMETRY data service error', error); } + if (data) { try { const firstServerHostname = dataService.client.model.hosts[0].host; @@ -369,7 +374,7 @@ export default class ConnectionController { }; // Send metrics to Segment - this._telemetryController?.track( + this._telemetryController.track( TelemetryEventTypes.NEW_CONNECTION, telemetryData ); @@ -396,7 +401,9 @@ export default class ConnectionController { return Promise.reject( new Error('Unable to connect: already connecting.') ); - } else if (this._disconnecting) { + } + + if (this._disconnecting) { return Promise.reject( new Error('Unable to connect: currently disconnecting.') ); @@ -427,6 +434,7 @@ export default class ConnectionController { this._connecting = false; log.info('Failed to connect'); this.eventEmitter.emit(DataServiceEventTypes.CONNECTIONS_DID_CHANGE); + return reject(new Error(`Failed to connect: ${err.message}`)); } @@ -441,7 +449,7 @@ export default class ConnectionController { this.eventEmitter.emit(DataServiceEventTypes.CONNECTIONS_DID_CHANGE); this.eventEmitter.emit(DataServiceEventTypes.ACTIVE_CONNECTION_CHANGED); - if (this._telemetryController?.needTelemetry()) { + if (this._telemetryController.needTelemetry()) { this.sendTelemetry(newDataService, connectionType); } @@ -452,11 +460,12 @@ export default class ConnectionController { public connectWithConnectionId = (connectionId: string): Promise => { if (this._connections[connectionId]) { - let connectionModel; + let connectionModel: any; try { const savedConnectionModel = this._connections[connectionId] .connectionModel; + // Here we rebuild the connection model to ensure it's up to date and // contains the connection model class methods (not just attributes). connectionModel = new Connection( @@ -466,8 +475,10 @@ export default class ConnectionController { ); } catch (error) { vscode.window.showErrorMessage(`Unable to load connection: ${error}`); + return Promise.resolve(false); } + return new Promise((resolve) => { this.connect( connectionId, @@ -475,6 +486,7 @@ export default class ConnectionController { ConnectionTypes.CONNECTION_ID ).then(resolve, (err: Error) => { vscode.window.showErrorMessage(err.message); + return resolve(false); }); }); @@ -493,6 +505,7 @@ export default class ConnectionController { vscode.window.showErrorMessage( 'Unable to disconnect: already disconnecting from an instance.' ); + return Promise.resolve(false); } @@ -501,6 +514,7 @@ export default class ConnectionController { vscode.window.showErrorMessage( 'Unable to disconnect: currently connecting to an instance.' ); + return Promise.resolve(false); } @@ -510,6 +524,7 @@ export default class ConnectionController { vscode.window.showErrorMessage( 'Unable to disconnect: no active connection.' ); + return resolve(false); } @@ -544,6 +559,7 @@ export default class ConnectionController { connectionId: string ): Promise => { delete this._connections[connectionId]; + if (this._keytar) { await this._keytar.deletePassword(this._serviceName, connectionId); // We only remove the connection from the saved connections if we @@ -563,19 +579,23 @@ export default class ConnectionController { vscode.window.showErrorMessage( 'Unable to remove connection: currently connecting.' ); + return Promise.resolve(false); } + // Ensure we aren't currently disconnecting. if (this._disconnecting) { vscode.window.showErrorMessage( 'Unable to remove connection: currently disconnecting.' ); + return Promise.resolve(false); } if (!this._connections[connectionId]) { // No active connection(s) to remove. vscode.window.showErrorMessage('Connection does not exist.'); + return Promise.resolve(false); } @@ -596,6 +616,7 @@ export default class ConnectionController { await this.removeSavedConnection(connectionId); vscode.window.showInformationMessage('MongoDB connection removed.'); + return Promise.resolve(true); } @@ -607,13 +628,16 @@ export default class ConnectionController { vscode.window.showErrorMessage( 'Unable to remove connection: currently connecting.' ); + return Promise.resolve(false); } + // Ensure we aren't currently disconnecting. if (this._disconnecting) { vscode.window.showErrorMessage( 'Unable to remove connection: currently disconnecting.' ); + return Promise.resolve(false); } @@ -622,6 +646,7 @@ export default class ConnectionController { if (connectionIds.length === 0) { // No active connection(s) to remove. vscode.window.showErrorMessage('No connections to remove.'); + return Promise.resolve(false); } @@ -655,7 +680,8 @@ export default class ConnectionController { } public async renameConnection(connectionId: string): Promise { - let inputtedConnectionName; + let inputtedConnectionName: any; + try { inputtedConnectionName = await vscode.window.showInputBox({ value: this._connections[connectionId].name, @@ -694,7 +720,9 @@ export default class ConnectionController { return this._storageController .saveConnectionToGlobalStore(this._connections[connectionId]) .then(() => resolve(true), reject); - } else if ( + } + + if ( this._connections[connectionId].storageLocation === StorageScope.WORKSPACE ) { @@ -806,15 +834,19 @@ export default class ConnectionController { this._disconnecting = false; this._connectingConnectionId = ''; } + public setActiveConnection(newActiveConnection: any): void { this._activeDataService = newActiveConnection; } + public setConnnecting(connecting: boolean): void { this._connecting = connecting; } + public setConnnectingConnectionId(connectingConnectionId: string): void { this._connectingConnectionId = connectingConnectionId; } + public setDisconnecting(disconnecting: boolean): void { this._disconnecting = disconnecting; } diff --git a/src/editors/playgroundController.ts b/src/editors/playgroundController.ts index 5ffcaf601..d2e1a5b7c 100644 --- a/src/editors/playgroundController.ts +++ b/src/editors/playgroundController.ts @@ -22,7 +22,7 @@ export default class PlaygroundController { _context: vscode.ExtensionContext; _connectionController: ConnectionController; _languageServerController: LanguageServerController; - _telemetryController?: TelemetryController; + _telemetryController: TelemetryController; _activeConnectionCodeLensProvider?: ActiveConnectionCodeLensProvider; _outputChannel: OutputChannel; _connectionString?: string; @@ -33,7 +33,7 @@ export default class PlaygroundController { context: vscode.ExtensionContext, connectionController: ConnectionController, languageServerController: LanguageServerController, - telemetryController?: TelemetryController + telemetryController: TelemetryController ) { this._context = context; this._connectionController = connectionController; @@ -168,7 +168,7 @@ export default class PlaygroundController { codeToEvaluate ); - if (result && this._telemetryController?.needTelemetry()) { + if (result) { // Send metrics to Segment this._telemetryController.track( TelemetryEventTypes.PLAYGROUND_CODE_EXECUTED, diff --git a/src/mdbExtensionController.ts b/src/mdbExtensionController.ts index 7cc42424c..773ca9e85 100644 --- a/src/mdbExtensionController.ts +++ b/src/mdbExtensionController.ts @@ -137,14 +137,12 @@ export default class MDBExtensionController implements vscode.Disposable { ): void => { const commandHandlerWithTelemetry = (args: any[]) => { // Send metrics to Segment - if (this._telemetryController?.needTelemetry()) { - this._telemetryController.track( - TelemetryEventTypes.EXTENSION_COMMAND_RUN, - { - command - } - ); - } + this._telemetryController.track( + TelemetryEventTypes.EXTENSION_COMMAND_RUN, + { + command + } + ); return commandHandler(args); }; diff --git a/src/telemetry/telemetryController.ts b/src/telemetry/telemetryController.ts index 108cd96f3..9b6d6471a 100644 --- a/src/telemetry/telemetryController.ts +++ b/src/telemetry/telemetryController.ts @@ -118,13 +118,13 @@ export default class TelemetryController { eventType: TelemetryEventTypes, properties: TelemetryEventProperties ): void { - log.info('TELEMETRY track', { - eventType, - segmentUserID: this._segmentUserID, - properties - }); - if (this.needTelemetry()) { + log.info('TELEMETRY track', { + eventType, + segmentUserID: this._segmentUserID, + properties + }); + this._segmentAnalytics?.track( { userId: this._segmentUserID, diff --git a/src/test/suite/connectionController.test.ts b/src/test/suite/connectionController.test.ts index 337b3bfc3..7cd045cfe 100644 --- a/src/test/suite/connectionController.test.ts +++ b/src/test/suite/connectionController.test.ts @@ -3,7 +3,7 @@ import * as vscode from 'vscode'; import { afterEach, beforeEach } from 'mocha'; import * as sinon from 'sinon'; import Connection = require('mongodb-connection-model/lib/model'); - +import TelemetryController from '../../telemetry/telemetryController'; import ConnectionController, { DataServiceEventTypes } from '../../connectionController'; @@ -14,7 +14,6 @@ import { } from '../../storage/storageController'; import { StatusView } from '../../views'; import MDBExtensionController from '../../mdbExtensionController'; - import { TestExtensionContext } from './stubs'; import { TEST_DATABASE_URI } from './dbTestHelper'; @@ -26,23 +25,31 @@ suite('Connection Controller Test Suite', () => { const mockExtensionContext = new TestExtensionContext(); const mockStorageController = new StorageController(mockExtensionContext); - beforeEach(() => { + beforeEach(async () => { + await vscode.workspace + .getConfiguration('mdb') + .update('sendTelemetry', false); // Here we stub the showInformationMessage process because it is too much // for the render process and leads to crashes while testing. sinon.replace(vscode.window, 'showInformationMessage', sinon.stub()); }); + afterEach(() => { // Reset our mock extension's state. mockExtensionContext._workspaceState = {}; mockExtensionContext._globalState = {}; - sinon.restore(); }); test('it connects to mongodb', (done) => { + const testTelemetryController = new TelemetryController( + mockStorageController, + mockExtensionContext + ); const testConnectionController = new ConnectionController( new StatusView(mockExtensionContext), - mockStorageController + mockStorageController, + testTelemetryController ); testConnectionController @@ -83,9 +90,14 @@ suite('Connection Controller Test Suite', () => { }); test('"disconnect()" disconnects from the active connection', (done) => { + const testTelemetryController = new TelemetryController( + mockStorageController, + mockExtensionContext + ); const testConnectionController = new ConnectionController( new StatusView(mockExtensionContext), - mockStorageController + mockStorageController, + testTelemetryController ); testConnectionController @@ -126,19 +138,19 @@ suite('Connection Controller Test Suite', () => { }); test('when the extension is deactivated, the active connection is disconnected', (done) => { + const testTelemetryController = new TelemetryController( + mockStorageController, + mockExtensionContext + ); const testConnectionController = new ConnectionController( new StatusView(mockExtensionContext), - mockStorageController - ); - - const mockMDBExtension = new MDBExtensionController( - mockExtensionContext, - testConnectionController + mockStorageController, + testTelemetryController ); testConnectionController .addNewConnectionStringAndConnect(TEST_DATABASE_URI) - .then((succesfullyConnected) => { + .then(async (succesfullyConnected) => { assert( succesfullyConnected === true, 'Expected a successful (true) connection response.' @@ -152,7 +164,7 @@ suite('Connection Controller Test Suite', () => { 'Expected active connection id to not be null.' ); - mockMDBExtension.deactivate(); + await testConnectionController.disconnect(); assert( testConnectionController.getActiveDataService() === null, @@ -167,9 +179,14 @@ suite('Connection Controller Test Suite', () => { }); test('"removeMongoDBConnection()" returns a reject promise when there is no active connection', (done) => { + const testTelemetryController = new TelemetryController( + mockStorageController, + mockExtensionContext + ); const testConnectionController = new ConnectionController( new StatusView(mockExtensionContext), - mockStorageController + mockStorageController, + testTelemetryController ); testConnectionController @@ -181,9 +198,14 @@ suite('Connection Controller Test Suite', () => { }); test('"disconnect()" fails when there is no active connection', (done) => { + const testTelemetryController = new TelemetryController( + mockStorageController, + mockExtensionContext + ); const testConnectionController = new ConnectionController( new StatusView(mockExtensionContext), - mockStorageController + mockStorageController, + testTelemetryController ); testConnectionController @@ -195,11 +217,17 @@ suite('Connection Controller Test Suite', () => { }); test('it errors when disconnecting with no active connection', (done) => { + const testTelemetryController = new TelemetryController( + mockStorageController, + mockExtensionContext + ); const testConnectionController = new ConnectionController( new StatusView(mockExtensionContext), - mockStorageController + mockStorageController, + testTelemetryController ); const fakeVscodeErrorMessage = sinon.fake(); + sinon.replace(vscode.window, 'showErrorMessage', fakeVscodeErrorMessage); testConnectionController @@ -219,9 +247,14 @@ suite('Connection Controller Test Suite', () => { }); test('when adding a new connection it disconnects from the current connection', (done) => { + const testTelemetryController = new TelemetryController( + mockStorageController, + mockExtensionContext + ); const testConnectionController = new ConnectionController( new StatusView(mockExtensionContext), - mockStorageController + mockStorageController, + testTelemetryController ); testConnectionController @@ -259,9 +292,14 @@ suite('Connection Controller Test Suite', () => { }); test('"connect()" failed when we are currently connecting', (done) => { + const testTelemetryController = new TelemetryController( + mockStorageController, + mockExtensionContext + ); const testConnectionController = new ConnectionController( new StatusView(mockExtensionContext), - mockStorageController + mockStorageController, + testTelemetryController ); testConnectionController.setConnnecting(true); @@ -284,9 +322,14 @@ suite('Connection Controller Test Suite', () => { }); test('"connect()" failed when we are currently disconnecting', (done) => { + const testTelemetryController = new TelemetryController( + mockStorageController, + mockExtensionContext + ); const testConnectionController = new ConnectionController( new StatusView(mockExtensionContext), - mockStorageController + mockStorageController, + testTelemetryController ); testConnectionController.setDisconnecting(true); @@ -309,14 +352,20 @@ suite('Connection Controller Test Suite', () => { }); test('"disconnect()" fails when we are currently connecting', (done) => { + const testTelemetryController = new TelemetryController( + mockStorageController, + mockExtensionContext + ); const testConnectionController = new ConnectionController( new StatusView(mockExtensionContext), - mockStorageController + mockStorageController, + testTelemetryController ); testConnectionController.setConnnecting(true); const fakeVscodeErrorMessage = sinon.fake(); + sinon.replace(vscode.window, 'showErrorMessage', fakeVscodeErrorMessage); testConnectionController @@ -337,14 +386,20 @@ suite('Connection Controller Test Suite', () => { }); test('"disconnect()" fails when we are currently disconnecting', (done) => { + const testTelemetryController = new TelemetryController( + mockStorageController, + mockExtensionContext + ); const testConnectionController = new ConnectionController( new StatusView(mockExtensionContext), - mockStorageController + mockStorageController, + testTelemetryController ); testConnectionController.setDisconnecting(true); const fakeVscodeErrorMessage = sinon.fake(); + sinon.replace(vscode.window, 'showErrorMessage', fakeVscodeErrorMessage); testConnectionController @@ -365,11 +420,15 @@ suite('Connection Controller Test Suite', () => { }); test('"connect()" should fire a CONNECTIONS_DID_CHANGE event', (done) => { + const testTelemetryController = new TelemetryController( + mockStorageController, + mockExtensionContext + ); const testConnectionController = new ConnectionController( new StatusView(mockExtensionContext), - mockStorageController + mockStorageController, + testTelemetryController ); - let didFireConnectionEvent = false; testConnectionController.addEventListener( @@ -393,12 +452,17 @@ suite('Connection Controller Test Suite', () => { }); const expectedTimesToFire = 3; + test(`"connect()" then "disconnect()" should fire the connections did change event ${expectedTimesToFire} times`, (done) => { + const testTelemetryController = new TelemetryController( + mockStorageController, + mockExtensionContext + ); const testConnectionController = new ConnectionController( new StatusView(mockExtensionContext), - mockStorageController + mockStorageController, + testTelemetryController ); - let connectionEventFiredCount = 0; testConnectionController.addEventListener( @@ -424,17 +488,21 @@ suite('Connection Controller Test Suite', () => { }); test('when there are no existing connections in the store and the connection controller loads connections', async () => { - const testExtensionContext = new TestExtensionContext(); - const testStorageController = new StorageController(testExtensionContext); - + const testTelemetryController = new TelemetryController( + mockStorageController, + mockExtensionContext + ); const testConnectionController = new ConnectionController( new StatusView(mockExtensionContext), - testStorageController + mockStorageController, + testTelemetryController ); await testConnectionController.loadSavedConnections(); + const connectionsCount = testConnectionController.getSavedConnections() .length; + assert( connectionsCount === 0, `Expected connections to be 0 found ${connectionsCount}` @@ -442,33 +510,31 @@ suite('Connection Controller Test Suite', () => { }); test('The connection model loads both global and workspace stored connection models', async () => { - const testExtensionContext = new TestExtensionContext(); - - const testStorageController = new StorageController(testExtensionContext); - + const testTelemetryController = new TelemetryController( + mockStorageController, + mockExtensionContext + ); const testConnectionController = new ConnectionController( new StatusView(mockExtensionContext), - testStorageController + mockStorageController, + testTelemetryController ); await vscode.workspace .getConfiguration('mdb.connectionSaving') .update('defaultConnectionSavingLocation', DefaultSavingLocations.Global); - await testConnectionController.addNewConnectionStringAndConnect( TEST_DATABASE_URI ); await testConnectionController.addNewConnectionStringAndConnect( TEST_DATABASE_URI ); - await vscode.workspace .getConfiguration('mdb.connectionSaving') .update( 'defaultConnectionSavingLocation', DefaultSavingLocations.Workspace ); - await testConnectionController.addNewConnectionStringAndConnect( TEST_DATABASE_URI ); @@ -476,11 +542,8 @@ suite('Connection Controller Test Suite', () => { TEST_DATABASE_URI ); await testConnectionController.disconnect(); - testConnectionController.clearAllConnections(); - await testConnectionController.loadSavedConnections(); - const connections = testConnectionController._connections; assert( Object.keys(connections).length === 4, @@ -492,10 +555,8 @@ suite('Connection Controller Test Suite', () => { connections[Object.keys(connections)[0]].name === 'localhost:27018', "Expected loaded connection to include name 'localhost:27018'" ); - const expectedDriverUri = 'mongodb://localhost:27018/?readPreference=primary&ssl=false'; - assert( connections[Object.keys(connections)[2]].driverUrl === expectedDriverUri, `Expected loaded connection to include driver url '${expectedDriverUri}' found '${ @@ -505,25 +566,24 @@ suite('Connection Controller Test Suite', () => { }); test('When a connection is added it is saved to the global store', async () => { - const testExtensionContext = new TestExtensionContext(); - const testStorageController = new StorageController(testExtensionContext); - + const testTelemetryController = new TelemetryController( + mockStorageController, + mockExtensionContext + ); const testConnectionController = new ConnectionController( new StatusView(mockExtensionContext), - testStorageController + mockStorageController, + testTelemetryController ); await testConnectionController.loadSavedConnections(); - await vscode.workspace .getConfiguration('mdb.connectionSaving') .update('defaultConnectionSavingLocation', DefaultSavingLocations.Global); - await testConnectionController.addNewConnectionStringAndConnect( TEST_DATABASE_URI ); - - const globalStoreConnections = testStorageController.get( + const globalStoreConnections = mockStorageController.get( StorageVariables.GLOBAL_SAVED_CONNECTIONS ); assert( @@ -537,8 +597,7 @@ suite('Connection Controller Test Suite', () => { globalStoreConnections[id].name === testDatabaseInstanceId, `Expected global stored connection to have correct name '${testDatabaseInstanceId}' found ${globalStoreConnections[id].name}` ); - - const workspaceStoreConnections = testStorageController.get( + const workspaceStoreConnections = mockStorageController.get( StorageVariables.WORKSPACE_SAVED_CONNECTIONS ); assert( @@ -548,12 +607,14 @@ suite('Connection Controller Test Suite', () => { }); test('When a connection is added it is saved to the workspace store', async () => { - const testExtensionContext = new TestExtensionContext(); - const testStorageController = new StorageController(testExtensionContext); - + const testTelemetryController = new TelemetryController( + mockStorageController, + mockExtensionContext + ); const testConnectionController = new ConnectionController( new StatusView(mockExtensionContext), - testStorageController + mockStorageController, + testTelemetryController ); testConnectionController.loadSavedConnections(); @@ -564,16 +625,13 @@ suite('Connection Controller Test Suite', () => { 'defaultConnectionSavingLocation', DefaultSavingLocations.Workspace ); - await testConnectionController.addNewConnectionStringAndConnect( TEST_DATABASE_URI ); - - const workspaceStoreConnections = testStorageController.get( + const workspaceStoreConnections = mockStorageController.get( StorageVariables.WORKSPACE_SAVED_CONNECTIONS, StorageScope.WORKSPACE ); - assert( Object.keys(workspaceStoreConnections).length === 1, `Expected workspace store connections to have 1 connection found ${ @@ -585,8 +643,7 @@ suite('Connection Controller Test Suite', () => { workspaceStoreConnections[id].name === testDatabaseInstanceId, `Expected workspace stored connection to have correct name '${testDatabaseInstanceId}' found ${workspaceStoreConnections[id].name}` ); - - const globalStoreConnections = testStorageController.get( + const globalStoreConnections = mockStorageController.get( StorageVariables.GLOBAL_SAVED_CONNECTIONS ); assert( @@ -596,11 +653,14 @@ suite('Connection Controller Test Suite', () => { }); test('A connection can be connected to by id', (done) => { - const testExtensionContext = new TestExtensionContext(); - const testStorageController = new StorageController(testExtensionContext); + const testTelemetryController = new TelemetryController( + mockStorageController, + mockExtensionContext + ); const testConnectionController = new ConnectionController( new StatusView(mockExtensionContext), - testStorageController + mockStorageController, + testTelemetryController ); Connection.from(TEST_DATABASE_URI, (err, connectionModel) => { @@ -631,12 +691,14 @@ suite('Connection Controller Test Suite', () => { }); test('A saved connection can be loaded and connected to', (done) => { - const testExtensionContext = new TestExtensionContext(); - const testStorageController = new StorageController(testExtensionContext); - + const testTelemetryController = new TelemetryController( + mockStorageController, + mockExtensionContext + ); const testConnectionController = new ConnectionController( new StatusView(mockExtensionContext), - testStorageController + mockStorageController, + testTelemetryController ); testConnectionController.loadSavedConnections().then(() => { @@ -650,7 +712,7 @@ suite('Connection Controller Test Suite', () => { testConnectionController .addNewConnectionStringAndConnect(TEST_DATABASE_URI) .then(() => { - const workspaceStoreConnections = testStorageController.get( + const workspaceStoreConnections = mockStorageController.get( StorageVariables.WORKSPACE_SAVED_CONNECTIONS, StorageScope.WORKSPACE ); @@ -716,14 +778,15 @@ suite('Connection Controller Test Suite', () => { }); test('"getConnectionStringFromConnectionId" returns the driver uri of a connection', (done) => { - const testExtensionContext = new TestExtensionContext(); - const testStorageController = new StorageController(testExtensionContext); - + const testTelemetryController = new TelemetryController( + mockStorageController, + mockExtensionContext + ); const testConnectionController = new ConnectionController( new StatusView(mockExtensionContext), - testStorageController + mockStorageController, + testTelemetryController ); - const expectedDriverUri = 'mongodb://localhost:27018/?readPreference=primary&ssl=false'; @@ -739,7 +802,6 @@ suite('Connection Controller Test Suite', () => { const testDriverUri = testConnectionController.getConnectionStringFromConnectionId( activeConnectionId || '' ); - assert( testDriverUri === expectedDriverUri, `Expected to be returned the driver uri "${expectedDriverUri}" found ${testDriverUri}` @@ -750,12 +812,14 @@ suite('Connection Controller Test Suite', () => { }); test('When a connection is added and the user has set it to not save on default it is not saved', (done) => { - const testExtensionContext = new TestExtensionContext(); - const testStorageController = new StorageController(testExtensionContext); - + const testTelemetryController = new TelemetryController( + mockStorageController, + mockExtensionContext + ); const testConnectionController = new ConnectionController( new StatusView(mockExtensionContext), - testStorageController + mockStorageController, + testTelemetryController ); testConnectionController.loadSavedConnections().then(() => { @@ -774,15 +838,14 @@ suite('Connection Controller Test Suite', () => { .addNewConnectionStringAndConnect(TEST_DATABASE_URI) .then(() => { const objectString = JSON.stringify(undefined); - const globalStoreConnections = testStorageController.get( + const globalStoreConnections = mockStorageController.get( StorageVariables.GLOBAL_SAVED_CONNECTIONS ); assert( JSON.stringify(globalStoreConnections) === objectString, `Expected global store connections to be an empty object found ${globalStoreConnections}` ); - - const workspaceStoreConnections = testStorageController.get( + const workspaceStoreConnections = mockStorageController.get( StorageVariables.WORKSPACE_SAVED_CONNECTIONS, StorageScope.WORKSPACE ); @@ -801,12 +864,14 @@ suite('Connection Controller Test Suite', () => { }); test('When a connection is removed it is also removed from workspace storage', (done) => { - const testExtensionContext = new TestExtensionContext(); - const testStorageController = new StorageController(testExtensionContext); - + const testTelemetryController = new TelemetryController( + mockStorageController, + mockExtensionContext + ); const testConnectionController = new ConnectionController( new StatusView(mockExtensionContext), - testStorageController + mockStorageController, + testTelemetryController ); testConnectionController.loadSavedConnections().then(() => { @@ -823,26 +888,23 @@ suite('Connection Controller Test Suite', () => { testConnectionController .addNewConnectionStringAndConnect(TEST_DATABASE_URI) .then(async () => { - const workspaceStoreConnections = testStorageController.get( + const workspaceStoreConnections = mockStorageController.get( StorageVariables.WORKSPACE_SAVED_CONNECTIONS, StorageScope.WORKSPACE ); - assert( Object.keys(workspaceStoreConnections).length === 1, `Expected workspace store connections to have 1 connection found ${ Object.keys(workspaceStoreConnections).length }` ); - const connectionId = testConnectionController.getActiveConnectionId() || 'a'; testConnectionController.disconnect(); await testConnectionController.removeSavedConnection( connectionId ); - - const postWorkspaceStoreConnections = testStorageController.get( + const postWorkspaceStoreConnections = mockStorageController.get( StorageVariables.WORKSPACE_SAVED_CONNECTIONS, StorageScope.WORKSPACE ); @@ -860,39 +922,36 @@ suite('Connection Controller Test Suite', () => { }); test('When a connection is removed it is also removed from global storage', async () => { - const testExtensionContext = new TestExtensionContext(); - const testStorageController = new StorageController(testExtensionContext); - + const testTelemetryController = new TelemetryController( + mockStorageController, + mockExtensionContext + ); const testConnectionController = new ConnectionController( new StatusView(mockExtensionContext), - testStorageController + mockStorageController, + testTelemetryController ); await testConnectionController.loadSavedConnections(); - await vscode.workspace .getConfiguration('mdb.connectionSaving') .update('defaultConnectionSavingLocation', DefaultSavingLocations.Global); - await testConnectionController.addNewConnectionStringAndConnect( TEST_DATABASE_URI ); - const globalStoreConnections = testStorageController.get( + const globalStoreConnections = mockStorageController.get( StorageVariables.GLOBAL_SAVED_CONNECTIONS ); - assert( Object.keys(globalStoreConnections).length === 1, `Expected workspace store connections to have 1 connection found ${ Object.keys(globalStoreConnections).length }` ); - const connectionId = testConnectionController.getActiveConnectionId() || 'a'; await testConnectionController.removeSavedConnection(connectionId); - - const postGlobalStoreConnections = testStorageController.get( + const postGlobalStoreConnections = mockStorageController.get( StorageVariables.GLOBAL_SAVED_CONNECTIONS ); assert( @@ -904,12 +963,14 @@ suite('Connection Controller Test Suite', () => { }); test('A saved connection can be renamed and loaded', (done) => { - const testExtensionContext = new TestExtensionContext(); - const testStorageController = new StorageController(testExtensionContext); - + const testTelemetryController = new TelemetryController( + mockStorageController, + mockExtensionContext + ); const testConnectionController = new ConnectionController( new StatusView(mockExtensionContext), - testStorageController + mockStorageController, + testTelemetryController ); testConnectionController.loadSavedConnections().then(() => { @@ -926,7 +987,7 @@ suite('Connection Controller Test Suite', () => { testConnectionController .addNewConnectionStringAndConnect(TEST_DATABASE_URI) .then(() => { - const workspaceStoreConnections = testStorageController.get( + const workspaceStoreConnections = mockStorageController.get( StorageVariables.WORKSPACE_SAVED_CONNECTIONS, StorageScope.WORKSPACE ); @@ -938,7 +999,6 @@ suite('Connection Controller Test Suite', () => { ); const connectionId = testConnectionController.getActiveConnectionId() || 'zz'; - const mockInputBoxResolves = sinon.stub(); mockInputBoxResolves.onCall(0).resolves('new connection name'); sinon.replace( @@ -946,7 +1006,6 @@ suite('Connection Controller Test Suite', () => { 'showInputBox', mockInputBoxResolves ); - testConnectionController .renameConnection(connectionId) .then((renameSuccess) => { @@ -974,7 +1033,6 @@ suite('Connection Controller Test Suite', () => { ); const id = testConnectionController.getSavedConnections()[0] .id; - const name = testConnectionController._connections[id || 'x'] .name; diff --git a/src/test/suite/editors/activeDBCodeLensProvider.test.ts b/src/test/suite/editors/activeDBCodeLensProvider.test.ts index 08b6275df..9bc3fe4e6 100644 --- a/src/test/suite/editors/activeDBCodeLensProvider.test.ts +++ b/src/test/suite/editors/activeDBCodeLensProvider.test.ts @@ -1,20 +1,32 @@ import * as assert from 'assert'; import * as vscode from 'vscode'; - +import { beforeEach } from 'mocha'; import ConnectionController from '../../../connectionController'; import { StatusView } from '../../../views'; import ActiveDBCodeLensProvider from '../../../editors/activeConnectionCodeLensProvider'; import { TestExtensionContext, mockVSCodeTextDocument } from '../stubs'; import { StorageController } from '../../../storage'; +import TelemetryController from '../../../telemetry/telemetryController'; suite('Active DB CodeLens Provider Test Suite', () => { const mockExtensionContext = new TestExtensionContext(); const mockStorageController = new StorageController(mockExtensionContext); + const testTelemetryController = new TelemetryController( + mockStorageController, + mockExtensionContext + ); + + beforeEach(async () => { + await vscode.workspace + .getConfiguration('mdb') + .update('sendTelemetry', false); + }); test('expected provideCodeLenses to return empty array when user is not connected', () => { const testConnectionController = new ConnectionController( new StatusView(mockExtensionContext), - mockStorageController + mockStorageController, + testTelemetryController ); const testCodeLensProvider = new ActiveDBCodeLensProvider( testConnectionController @@ -28,7 +40,8 @@ suite('Active DB CodeLens Provider Test Suite', () => { test('expected provideCodeLenses to return a code lens with positions at the first line of the document', () => { const testConnectionController = new ConnectionController( new StatusView(mockExtensionContext), - mockStorageController + mockStorageController, + testTelemetryController ); const testCodeLensProvider = new ActiveDBCodeLensProvider( testConnectionController diff --git a/src/test/suite/editors/collectionDocumentsProvider.test.ts b/src/test/suite/editors/collectionDocumentsProvider.test.ts index caedfa5e2..c16281487 100644 --- a/src/test/suite/editors/collectionDocumentsProvider.test.ts +++ b/src/test/suite/editors/collectionDocumentsProvider.test.ts @@ -9,6 +9,7 @@ import { StatusView } from '../../../views'; import { TestExtensionContext } from '../stubs'; import { StorageController } from '../../../storage'; import CollectionDocumentsOperationsStore from '../../../editors/collectionDocumentsOperationsStore'; +import TelemetryController from '../../../telemetry/telemetryController'; const mockDocumentsAsJsonString = `[ { @@ -45,9 +46,14 @@ suite('Collection Documents Provider Test Suite', () => { const mockExtensionContext = new TestExtensionContext(); const mockStorageController = new StorageController(mockExtensionContext); + const testTelemetryController = new TelemetryController( + mockStorageController, + mockExtensionContext + ); const mockConnectionController = new ConnectionController( new StatusView(mockExtensionContext), - mockStorageController + mockStorageController, + testTelemetryController ); mockConnectionController.setActiveConnection(mockActiveConnection); @@ -96,9 +102,14 @@ suite('Collection Documents Provider Test Suite', () => { const mockExtensionContext = new TestExtensionContext(); const mockStorageController = new StorageController(mockExtensionContext); + const testTelemetryController = new TelemetryController( + mockStorageController, + mockExtensionContext + ); const mockConnectionController = new ConnectionController( new StatusView(mockExtensionContext), - mockStorageController + mockStorageController, + testTelemetryController ); mockConnectionController.setActiveConnection(mockActiveConnection); @@ -136,9 +147,14 @@ suite('Collection Documents Provider Test Suite', () => { const mockExtensionContext = new TestExtensionContext(); const mockStorageController = new StorageController(mockExtensionContext); + const testTelemetryController = new TelemetryController( + mockStorageController, + mockExtensionContext + ); const mockConnectionController = new ConnectionController( new StatusView(mockExtensionContext), - mockStorageController + mockStorageController, + testTelemetryController ); mockConnectionController.setActiveConnection(mockActiveConnection); @@ -184,9 +200,14 @@ suite('Collection Documents Provider Test Suite', () => { const mockExtensionContext = new TestExtensionContext(); const mockStorageController = new StorageController(mockExtensionContext); + const testTelemetryController = new TelemetryController( + mockStorageController, + mockExtensionContext + ); const mockConnectionController = new ConnectionController( new StatusView(mockExtensionContext), - mockStorageController + mockStorageController, + testTelemetryController ); mockConnectionController.setActiveConnection(mockActiveConnection); diff --git a/src/test/suite/editors/documentProvider.test.ts b/src/test/suite/editors/documentProvider.test.ts index 521b25dbd..5fc78e332 100644 --- a/src/test/suite/editors/documentProvider.test.ts +++ b/src/test/suite/editors/documentProvider.test.ts @@ -3,7 +3,7 @@ import * as vscode from 'vscode'; import { afterEach } from 'mocha'; import * as sinon from 'sinon'; import { ObjectId, EJSON } from 'bson'; - +import TelemetryController from '../../../telemetry/telemetryController'; import DocumentProvider from '../../../editors/documentProvider'; import ConnectionController from '../../../connectionController'; import { StatusView } from '../../../views'; @@ -58,9 +58,14 @@ suite('Document Provider Test Suite', () => { const mockExtensionContext = new TestExtensionContext(); const mockStorageController = new StorageController(mockExtensionContext); + const testTelemetryController = new TelemetryController( + mockStorageController, + mockExtensionContext + ); const mockConnectionController = new ConnectionController( new StatusView(mockExtensionContext), - mockStorageController + mockStorageController, + testTelemetryController ); mockConnectionController.setActiveConnection(mockActiveConnection); @@ -105,9 +110,14 @@ suite('Document Provider Test Suite', () => { const mockExtensionContext = new TestExtensionContext(); const mockStorageController = new StorageController(mockExtensionContext); + const testTelemetryController = new TelemetryController( + mockStorageController, + mockExtensionContext + ); const mockConnectionController = new ConnectionController( new StatusView(mockExtensionContext), - mockStorageController + mockStorageController, + testTelemetryController ); mockConnectionController.setActiveConnection(mockActiveConnection); @@ -141,9 +151,14 @@ suite('Document Provider Test Suite', () => { const mockExtensionContext = new TestExtensionContext(); const mockStorageController = new StorageController(mockExtensionContext); + const testTelemetryController = new TelemetryController( + mockStorageController, + mockExtensionContext + ); const mockConnectionController = new ConnectionController( new StatusView(mockExtensionContext), - mockStorageController + mockStorageController, + testTelemetryController ); mockConnectionController.setActiveConnection(mockActiveConnection); @@ -201,10 +216,16 @@ suite('Document Provider Test Suite', () => { const mockStorageController = new StorageController( mockExtensionContext ); + const testTelemetryController = new TelemetryController( + mockStorageController, + mockExtensionContext + ); const mockConnectionController = new ConnectionController( new StatusView(mockExtensionContext), - mockStorageController + mockStorageController, + testTelemetryController ); + mockConnectionController.setActiveConnection(dataService); const testCollectionViewProvider = new DocumentProvider( @@ -245,10 +266,16 @@ suite('Document Provider Test Suite', () => { const mockStorageController = new StorageController( mockExtensionContext ); + const testTelemetryController = new TelemetryController( + mockStorageController, + mockExtensionContext + ); const mockConnectionController = new ConnectionController( new StatusView(mockExtensionContext), - mockStorageController + mockStorageController, + testTelemetryController ); + mockConnectionController.setActiveConnection(dataService); const testCollectionViewProvider = new DocumentProvider( @@ -289,10 +316,16 @@ suite('Document Provider Test Suite', () => { const mockStorageController = new StorageController( mockExtensionContext ); + const testTelemetryController = new TelemetryController( + mockStorageController, + mockExtensionContext + ); const mockConnectionController = new ConnectionController( new StatusView(mockExtensionContext), - mockStorageController + mockStorageController, + testTelemetryController ); + mockConnectionController.setActiveConnection(dataService); const testCollectionViewProvider = new DocumentProvider( diff --git a/src/test/suite/editors/playgroundController.test.ts b/src/test/suite/editors/playgroundController.test.ts index b1312d147..cee37fdca 100644 --- a/src/test/suite/editors/playgroundController.test.ts +++ b/src/test/suite/editors/playgroundController.test.ts @@ -6,6 +6,7 @@ import { StatusView } from '../../../views'; import { StorageController } from '../../../storage'; import { TestExtensionContext, MockLanguageServerController } from '../stubs'; import { before, after, beforeEach, afterEach } from 'mocha'; +import TelemetryController from '../../../telemetry/telemetryController'; const sinon = require('sinon'); const chai = require('chai'); @@ -24,9 +25,14 @@ suite('Playground Controller Test Suite', () => { mockExtensionContext.extensionPath = '../../'; const mockStorageController = new StorageController(mockExtensionContext); + const testTelemetryController = new TelemetryController( + mockStorageController, + mockExtensionContext + ); const testConnectionController = new ConnectionController( new StatusView(mockExtensionContext), - mockStorageController + mockStorageController, + testTelemetryController ); const mockLanguageServerController = new MockLanguageServerController( mockExtensionContext, @@ -35,7 +41,8 @@ suite('Playground Controller Test Suite', () => { const testPlaygroundController = new PlaygroundController( mockExtensionContext, testConnectionController, - mockLanguageServerController as LanguageServerController + mockLanguageServerController as LanguageServerController, + testTelemetryController ); const sandbox = sinon.createSandbox(); let fakeShowInformationMessage: any; diff --git a/src/test/suite/extension.test.ts b/src/test/suite/extension.test.ts index a74c90980..7ed59b395 100644 --- a/src/test/suite/extension.test.ts +++ b/src/test/suite/extension.test.ts @@ -10,6 +10,7 @@ import { TEST_DATABASE_URI } from './dbTestHelper'; import ConnectionController from '../../connectionController'; import { StorageController } from '../../storage'; import { StatusView } from '../../views'; +import TelemetryController from '../../telemetry/telemetryController'; suite('Extension Test Suite', () => { vscode.window.showInformationMessage('Starting tests...'); @@ -18,9 +19,14 @@ suite('Extension Test Suite', () => { const mockExtensionContext = new TestExtensionContext(); const mockMDBExtension = new MDBExtensionController(mockExtensionContext); const mockStorageController = new StorageController(mockExtensionContext); + const testTelemetryController = new TelemetryController( + mockStorageController, + mockExtensionContext + ); const testConnectionController = new ConnectionController( new StatusView(mockExtensionContext), - mockStorageController + mockStorageController, + testTelemetryController ); const sandbox = sinon.createSandbox(); let fakeShowErrorMessage: any; diff --git a/src/test/suite/language/languageServerController.test.ts b/src/test/suite/language/languageServerController.test.ts index 6e2cae750..ae870399d 100644 --- a/src/test/suite/language/languageServerController.test.ts +++ b/src/test/suite/language/languageServerController.test.ts @@ -1,4 +1,6 @@ import { before, after } from 'mocha'; +import TelemetryController from '../../../telemetry/telemetryController'; + const path = require('path'); const fs = require('fs'); const sinon = require('sinon'); @@ -30,18 +32,24 @@ suite('Language Server Controller Test Suite', () => { const testLanguageServerController = new LanguageServerController( mockExtensionContext ); + const testTelemetryController = new TelemetryController( + mockStorageController, + mockExtensionContext + ); testLanguageServerController.activate(); const testConnectionController = new ConnectionController( new StatusView(mockExtensionContext), - mockStorageController + mockStorageController, + testTelemetryController ); const testPlaygroundController = new PlaygroundController( mockExtensionContext, testConnectionController, - testLanguageServerController + testLanguageServerController, + testTelemetryController ); before(async () => { diff --git a/src/test/suite/views/webviewController.test.ts b/src/test/suite/views/webviewController.test.ts index 6d68607cf..1a41c004c 100644 --- a/src/test/suite/views/webviewController.test.ts +++ b/src/test/suite/views/webviewController.test.ts @@ -1,11 +1,9 @@ import * as assert from 'assert'; import * as vscode from 'vscode'; -import { afterEach } from 'mocha'; +import { beforeEach, afterEach } from 'mocha'; import * as sinon from 'sinon'; -const fs = require('fs'); -const path = require('path'); import Connection = require('mongodb-connection-model/lib/model'); - +import TelemetryController from '../../../telemetry/telemetryController'; import ConnectionController from '../../../connectionController'; import { StorageController } from '../../../storage'; import WebviewController, { @@ -14,14 +12,22 @@ import WebviewController, { } from '../../../views/webviewController'; import { StatusView } from '../../../views'; import { MESSAGE_TYPES } from '../../../views/webview-app/extension-app-message-constants'; - import { mdbTestExtension } from '../stubbableMdbExtension'; import { TestExtensionContext } from '../stubs'; import { TEST_DATABASE_URI } from '../dbTestHelper'; +const fs = require('fs'); +const path = require('path'); + suite('Connect Form View Test Suite', () => { const disposables: vscode.Disposable[] = []; + beforeEach(async () => { + await vscode.workspace + .getConfiguration('mdb') + .update('sendTelemetry', false); + }); + afterEach(() => { disposables.forEach((d) => d.dispose()); disposables.length = 0; @@ -35,10 +41,10 @@ suite('Connect Form View Test Suite', () => { html: '', onDidReceiveMessage: stubOnDidRecieveMessage }; - const fakeVSCodeCreateWebviewPanel = sinon.fake.returns({ webview: fakeWebview }); + sinon.replace( vscode.window, 'createWebviewPanel', @@ -46,7 +52,8 @@ suite('Connect Form View Test Suite', () => { ); const testWebviewController = new WebviewController( - mdbTestExtension.testExtensionController._connectionController + mdbTestExtension.testExtensionController._connectionController, + mdbTestExtension.testExtensionController._telemetryController ); testWebviewController.showConnectForm( @@ -79,24 +86,29 @@ suite('Connect Form View Test Suite', () => { assert(htmlString.includes('vscode-resource:/')); assert(htmlString.includes('dist/webviewApp.js')); + const webviewAppFileName = (): string => 'dist/webviewApp.js'; const jsFileString = await readFile( path.join(extensionPath, webviewAppFileName()) ); + assert(`${jsFileString}`.includes('ConnectionForm')); }); test('web view listens for a connect message and adds the connection', (done) => { const testExtensionContext = new TestExtensionContext(); const testStorageController = new StorageController(testExtensionContext); - + const testTelemetryController = new TelemetryController( + testStorageController, + testExtensionContext + ); const testConnectionController = new ConnectionController( new StatusView(testExtensionContext), - testStorageController + testStorageController, + testTelemetryController ); - let messageRecievedSet = false; - let messageRecieved; + let messageRecieved: any; const fakeWebview = { html: '', postMessage: (message: any): void => { @@ -117,10 +129,10 @@ suite('Connect Form View Test Suite', () => { messageRecievedSet = true; } }; - const fakeVSCodeCreateWebviewPanel = sinon.fake.returns({ webview: fakeWebview }); + sinon.replace( vscode.window, 'createWebviewPanel', @@ -128,7 +140,8 @@ suite('Connect Form View Test Suite', () => { ); const testWebviewController = new WebviewController( - testConnectionController + testConnectionController, + testTelemetryController ); testWebviewController.showConnectForm( @@ -159,14 +172,17 @@ suite('Connect Form View Test Suite', () => { test('web view sends a successful connect result on a successful connection', (done) => { const testExtensionContext = new TestExtensionContext(); const testStorageController = new StorageController(testExtensionContext); - + const testTelemetryController = new TelemetryController( + testStorageController, + testExtensionContext + ); const testConnectionController = new ConnectionController( new StatusView(testExtensionContext), - testStorageController + testStorageController, + testTelemetryController ); - let messageRecievedSet = false; - let messageRecieved; + let messageRecieved: any; const fakeWebview = { html: '', postMessage: (message: any): void => { @@ -181,10 +197,10 @@ suite('Connect Form View Test Suite', () => { messageRecievedSet = true; } }; - const fakeVSCodeCreateWebviewPanel = sinon.fake.returns({ webview: fakeWebview }); + sinon.replace( vscode.window, 'createWebviewPanel', @@ -192,7 +208,8 @@ suite('Connect Form View Test Suite', () => { ); const testWebviewController = new WebviewController( - testConnectionController + testConnectionController, + testTelemetryController ); testWebviewController.showConnectForm( @@ -223,13 +240,16 @@ suite('Connect Form View Test Suite', () => { test('web view sends an unsuccessful connect result on an unsuccessful connection', (done) => { const testExtensionContext = new TestExtensionContext(); const testStorageController = new StorageController(testExtensionContext); - + const testTelemetryController = new TelemetryController( + testStorageController, + testExtensionContext + ); const testConnectionController = new ConnectionController( new StatusView(testExtensionContext), - testStorageController + testStorageController, + testTelemetryController ); - - let messageRecieved; + let messageRecieved: any; const fakeWebview = { html: '', postMessage: (message: any): void => { @@ -243,10 +263,10 @@ suite('Connect Form View Test Suite', () => { messageRecieved = callback; } }; - const fakeVSCodeCreateWebviewPanel = sinon.fake.returns({ webview: fakeWebview }); + sinon.replace( vscode.window, 'createWebviewPanel', @@ -254,7 +274,8 @@ suite('Connect Form View Test Suite', () => { ); const testWebviewController = new WebviewController( - testConnectionController + testConnectionController, + testTelemetryController ); testWebviewController.showConnectForm( @@ -274,12 +295,15 @@ suite('Connect Form View Test Suite', () => { test('web view opens file picker on file picker request', (done) => { const testExtensionContext = new TestExtensionContext(); const testStorageController = new StorageController(testExtensionContext); - + const testTelemetryController = new TelemetryController( + testStorageController, + testExtensionContext + ); const testConnectionController = new ConnectionController( new StatusView(testExtensionContext), - testStorageController + testStorageController, + testTelemetryController ); - const fakeVSCodeOpenDialog = sinon.fake.resolves({ path: './somefilepath/test.text' }); @@ -311,7 +335,8 @@ suite('Connect Form View Test Suite', () => { sinon.replace(vscode.window, 'showOpenDialog', fakeVSCodeOpenDialog); const testWebviewController = new WebviewController( - testConnectionController + testConnectionController, + testTelemetryController ); testWebviewController.showConnectForm( @@ -328,13 +353,16 @@ suite('Connect Form View Test Suite', () => { test('web view returns file name on file picker request', (done) => { const testExtensionContext = new TestExtensionContext(); const testStorageController = new StorageController(testExtensionContext); - + const testTelemetryController = new TelemetryController( + testStorageController, + testExtensionContext + ); const testConnectionController = new ConnectionController( new StatusView(testExtensionContext), - testStorageController + testStorageController, + testTelemetryController ); - - let messageRecieved; + let messageRecieved: any; const fakeWebview = { html: '', postMessage: (message: any): void => { @@ -348,10 +376,10 @@ suite('Connect Form View Test Suite', () => { messageRecieved = callback; } }; - const fakeVSCodeCreateWebviewPanel = sinon.fake.returns({ webview: fakeWebview }); + sinon.replace( vscode.window, 'createWebviewPanel', @@ -363,10 +391,12 @@ suite('Connect Form View Test Suite', () => { path: './somefilepath/test.text' } ]); + sinon.replace(vscode.window, 'showOpenDialog', fakeVSCodeOpenDialog); const testWebviewController = new WebviewController( - testConnectionController + testConnectionController, + testTelemetryController ); testWebviewController.showConnectForm( @@ -382,26 +412,30 @@ suite('Connect Form View Test Suite', () => { test('web view runs the "connectWithURI" command when open connection string input is recieved', (done) => { const testExtensionContext = new TestExtensionContext(); const testStorageController = new StorageController(testExtensionContext); - + const testTelemetryController = new TelemetryController( + testStorageController, + testExtensionContext + ); const testConnectionController = new ConnectionController( new StatusView(testExtensionContext), - testStorageController + testStorageController, + testTelemetryController ); - - let messageRecieved; + let messageRecieved: any; const fakeWebview = { html: '', onDidReceiveMessage: (callback): void => { messageRecieved = callback; } }; - const fakeVSCodeExecuteCommand = sinon.fake.resolves(false); + sinon.replace(vscode.commands, 'executeCommand', fakeVSCodeExecuteCommand); const fakeVSCodeCreateWebviewPanel = sinon.fake.returns({ webview: fakeWebview }); + sinon.replace( vscode.window, 'createWebviewPanel', @@ -409,7 +443,8 @@ suite('Connect Form View Test Suite', () => { ); const testWebviewController = new WebviewController( - testConnectionController + testConnectionController, + testTelemetryController ); testWebviewController.showConnectForm( diff --git a/src/views/webviewController.ts b/src/views/webviewController.ts index 160e895ba..1cac90f6a 100644 --- a/src/views/webviewController.ts +++ b/src/views/webviewController.ts @@ -50,11 +50,11 @@ export const getReactAppUri = (extensionPath: string): vscode.Uri => { export default class WebviewController { _connectionController: ConnectionController; - _telemetryController?: TelemetryController; + _telemetryController: TelemetryController; constructor( connectionController: ConnectionController, - telemetryController?: TelemetryController + telemetryController: TelemetryController ) { this._connectionController = connectionController; this._telemetryController = telemetryController; @@ -124,15 +124,13 @@ export default class WebviewController { return; case MESSAGE_TYPES.EXTENSION_LINK_CLICKED: - if (this._telemetryController?.needTelemetry()) { - this._telemetryController.track( - TelemetryEventTypes.EXTENSION_LINK_CLICKED, - { - screen: message.screen, - linkId: message.linkId - } - ); - } + this._telemetryController.track( + TelemetryEventTypes.EXTENSION_LINK_CLICKED, + { + screen: message.screen, + linkId: message.linkId + } + ); return; default: From bc4bc3f3173ffb888095bc8f03ed799896ef49ae Mon Sep 17 00:00:00 2001 From: Alena Khineika Date: Tue, 12 May 2020 12:40:56 +0200 Subject: [PATCH 7/7] test: disable metrics for all tests by default --- src/connectionController.ts | 2 +- src/editors/playgroundController.ts | 2 +- src/test/suite/connectionController.test.ts | 5 +---- src/test/suite/editors/activeDBCodeLensProvider.test.ts | 8 -------- src/test/suite/explorer/explorerController.test.ts | 3 --- src/test/suite/extension.test.ts | 5 +---- src/test/suite/index.ts | 3 +++ src/test/suite/mdbExtensionController.test.ts | 5 +---- src/test/suite/telemetry/telemetryController.test.ts | 5 ++++- src/test/suite/views/webviewController.test.ts | 8 +------- 10 files changed, 13 insertions(+), 33 deletions(-) diff --git a/src/connectionController.ts b/src/connectionController.ts index de2dba395..a8f55b0a5 100644 --- a/src/connectionController.ts +++ b/src/connectionController.ts @@ -316,7 +316,7 @@ export default class ConnectionController { }); }; - public async getCloudInfoFromDataService(firstServerHostname) { + public async getCloudInfoFromDataService(firstServerHostname: string) { const cloudInfo = await getCloudInfo(firstServerHostname); let isPublicCloud = false; let publicCloudName: string | null = null; diff --git a/src/editors/playgroundController.ts b/src/editors/playgroundController.ts index d2e1a5b7c..740423d08 100644 --- a/src/editors/playgroundController.ts +++ b/src/editors/playgroundController.ts @@ -168,7 +168,7 @@ export default class PlaygroundController { codeToEvaluate ); - if (result) { + if (result && this._telemetryController.needTelemetry()) { // Send metrics to Segment this._telemetryController.track( TelemetryEventTypes.PLAYGROUND_CODE_EXECUTED, diff --git a/src/test/suite/connectionController.test.ts b/src/test/suite/connectionController.test.ts index 7cd045cfe..c0d7a2f4d 100644 --- a/src/test/suite/connectionController.test.ts +++ b/src/test/suite/connectionController.test.ts @@ -25,10 +25,7 @@ suite('Connection Controller Test Suite', () => { const mockExtensionContext = new TestExtensionContext(); const mockStorageController = new StorageController(mockExtensionContext); - beforeEach(async () => { - await vscode.workspace - .getConfiguration('mdb') - .update('sendTelemetry', false); + beforeEach(() => { // Here we stub the showInformationMessage process because it is too much // for the render process and leads to crashes while testing. sinon.replace(vscode.window, 'showInformationMessage', sinon.stub()); diff --git a/src/test/suite/editors/activeDBCodeLensProvider.test.ts b/src/test/suite/editors/activeDBCodeLensProvider.test.ts index 9bc3fe4e6..ab1a7c50c 100644 --- a/src/test/suite/editors/activeDBCodeLensProvider.test.ts +++ b/src/test/suite/editors/activeDBCodeLensProvider.test.ts @@ -1,6 +1,4 @@ import * as assert from 'assert'; -import * as vscode from 'vscode'; -import { beforeEach } from 'mocha'; import ConnectionController from '../../../connectionController'; import { StatusView } from '../../../views'; import ActiveDBCodeLensProvider from '../../../editors/activeConnectionCodeLensProvider'; @@ -16,12 +14,6 @@ suite('Active DB CodeLens Provider Test Suite', () => { mockExtensionContext ); - beforeEach(async () => { - await vscode.workspace - .getConfiguration('mdb') - .update('sendTelemetry', false); - }); - test('expected provideCodeLenses to return empty array when user is not connected', () => { const testConnectionController = new ConnectionController( new StatusView(mockExtensionContext), diff --git a/src/test/suite/explorer/explorerController.test.ts b/src/test/suite/explorer/explorerController.test.ts index acf476917..ee8d17bc4 100644 --- a/src/test/suite/explorer/explorerController.test.ts +++ b/src/test/suite/explorer/explorerController.test.ts @@ -17,9 +17,6 @@ const testDatabaseURI2WithTimeout = suite('Explorer Controller Test Suite', () => { beforeEach(async () => { - await vscode.workspace - .getConfiguration('mdb') - .update('sendTelemetry', false); // Don't save connections on default. await vscode.workspace .getConfiguration('mdb.connectionSaving') diff --git a/src/test/suite/extension.test.ts b/src/test/suite/extension.test.ts index 7ed59b395..db1a5f4b2 100644 --- a/src/test/suite/extension.test.ts +++ b/src/test/suite/extension.test.ts @@ -31,10 +31,7 @@ suite('Extension Test Suite', () => { const sandbox = sinon.createSandbox(); let fakeShowErrorMessage: any; - before(async () => { - await vscode.workspace - .getConfiguration('mdb') - .update('sendTelemetry', false); + before(() => { sandbox.stub(vscode.window, 'showInformationMessage'); fakeShowErrorMessage = sandbox.stub(vscode.window, 'showErrorMessage'); }); diff --git a/src/test/suite/index.ts b/src/test/suite/index.ts index bf021d19e..f7a8b4d48 100644 --- a/src/test/suite/index.ts +++ b/src/test/suite/index.ts @@ -37,6 +37,9 @@ export function run(): Promise { ); mdbTestExtension.testExtensionController.activate(); + // Disable metrics. + vscode.workspace.getConfiguration('mdb').update('sendTelemetry', false); + // Disable the dialogue for prompting the user where to store the connection. vscode.workspace .getConfiguration('mdb.connectionSaving') diff --git a/src/test/suite/mdbExtensionController.test.ts b/src/test/suite/mdbExtensionController.test.ts index 8149d6dd7..7035bf1f4 100644 --- a/src/test/suite/mdbExtensionController.test.ts +++ b/src/test/suite/mdbExtensionController.test.ts @@ -19,10 +19,7 @@ const sinon = require('sinon'); const testDatabaseURI = 'mongodb://localhost:27018'; suite('MDBExtensionController Test Suite', () => { - beforeEach(async () => { - await vscode.workspace - .getConfiguration('mdb') - .update('sendTelemetry', false); + beforeEach(() => { // Here we stub the showInformationMessage process because it is too much // for the render process and leads to crashes while testing. sinon.replace(vscode.window, 'showInformationMessage', sinon.stub()); diff --git a/src/test/suite/telemetry/telemetryController.test.ts b/src/test/suite/telemetry/telemetryController.test.ts index 98a25007b..58094a5d8 100644 --- a/src/test/suite/telemetry/telemetryController.test.ts +++ b/src/test/suite/telemetry/telemetryController.test.ts @@ -71,7 +71,10 @@ suite('Telemetry Controller Test Suite', () => { ); }); - afterEach(() => { + afterEach(async () => { + await vscode.workspace + .getConfiguration('mdb') + .update('sendTelemetry', false); sinon.restore(); }); diff --git a/src/test/suite/views/webviewController.test.ts b/src/test/suite/views/webviewController.test.ts index 1a41c004c..fc0b44815 100644 --- a/src/test/suite/views/webviewController.test.ts +++ b/src/test/suite/views/webviewController.test.ts @@ -1,6 +1,6 @@ import * as assert from 'assert'; import * as vscode from 'vscode'; -import { beforeEach, afterEach } from 'mocha'; +import { afterEach } from 'mocha'; import * as sinon from 'sinon'; import Connection = require('mongodb-connection-model/lib/model'); import TelemetryController from '../../../telemetry/telemetryController'; @@ -22,12 +22,6 @@ const path = require('path'); suite('Connect Form View Test Suite', () => { const disposables: vscode.Disposable[] = []; - beforeEach(async () => { - await vscode.workspace - .getConfiguration('mdb') - .update('sendTelemetry', false); - }); - afterEach(() => { disposables.forEach((d) => d.dispose()); disposables.length = 0;