diff --git a/src/sql/workbench/contrib/notebook/test/electron-browser/notebookModel.test.ts b/src/sql/workbench/contrib/notebook/test/electron-browser/notebookModel.test.ts index 17d6ec7d7d..883c1cbeac 100644 --- a/src/sql/workbench/contrib/notebook/test/electron-browser/notebookModel.test.ts +++ b/src/sql/workbench/contrib/notebook/test/electron-browser/notebookModel.test.ts @@ -11,11 +11,10 @@ import { INotificationService } from 'vs/platform/notification/common/notificati import { TestNotificationService } from 'vs/platform/notification/test/common/testNotificationService'; import { URI } from 'vs/base/common/uri'; -import { LocalContentManager } from 'sql/workbench/services/notebook/common/localContentManager'; import { NotebookManagerStub } from 'sql/workbench/contrib/notebook/test/stubs'; import { NotebookModel } from 'sql/workbench/contrib/notebook/browser/models/notebookModel'; import { ModelFactory } from 'sql/workbench/contrib/notebook/browser/models/modelFactory'; -import { IClientSession, INotebookModelOptions, NotebookContentChange } from 'sql/workbench/contrib/notebook/browser/models/modelInterfaces'; +import { IClientSession, INotebookModelOptions, NotebookContentChange, IClientSessionOptions } from 'sql/workbench/contrib/notebook/browser/models/modelInterfaces'; import { ClientSession } from 'sql/workbench/contrib/notebook/browser/models/clientSession'; import { CellTypes, NotebookChangeType } from 'sql/workbench/contrib/notebook/common/models/contracts'; import { Deferred } from 'sql/base/common/promise'; @@ -31,16 +30,18 @@ import { NullLogService } from 'vs/platform/log/common/log'; import { TestConnectionManagementService } from 'sql/platform/connection/test/common/testConnectionManagementService'; import { isUndefinedOrNull } from 'vs/base/common/types'; import { assign } from 'vs/base/common/objects'; +import { NotebookEditorContentManager } from 'sql/workbench/contrib/notebook/browser/models/notebookInput'; +import { SessionManager } from 'sql/workbench/services/notebook/browser/sessionManager'; let expectedNotebookContent: nb.INotebookContents = { cells: [{ cell_type: CellTypes.Code, - source: 'insert into t1 values (c1, c2)', + source: ['insert into t1 values (c1, c2)'], metadata: { language: 'python' }, execution_count: 1 }, { cell_type: CellTypes.Markdown, - source: 'I am *markdown*', + source: ['I am *markdown*'], metadata: { language: 'python' }, execution_count: 1 }], @@ -57,7 +58,7 @@ let expectedNotebookContent: nb.INotebookContents = { let expectedNotebookContentOneCell: nb.INotebookContents = { cells: [{ cell_type: CellTypes.Code, - source: 'insert into t1 values (c1, c2)', + source: ['insert into t1 values (c1, c2)'], metadata: { language: 'python' }, execution_count: 1 }], @@ -74,6 +75,7 @@ let expectedNotebookContentOneCell: nb.INotebookContents = { let defaultUri = URI.file('/some/path.ipynb'); let mockClientSession: TypeMoq.Mock; +let clientSessionOptions: IClientSessionOptions; let sessionReady: Deferred; let mockModelFactory: TypeMoq.Mock; let notificationService: TypeMoq.Mock; @@ -82,11 +84,14 @@ let instantiationService: IInstantiationService; suite('notebook model', function (): void { let notebookManagers = [new NotebookManagerStub()]; + let mockSessionManager: TypeMoq.Mock; let memento: TypeMoq.Mock; let queryConnectionService: TypeMoq.Mock; let defaultModelOptions: INotebookModelOptions; const logService = new NullLogService(); setup(() => { + mockSessionManager = TypeMoq.Mock.ofType(SessionManager); + notebookManagers[0].sessionManager = mockSessionManager.object; sessionReady = new Deferred(); notificationService = TypeMoq.Mock.ofType(TestNotificationService, TypeMoq.MockBehavior.Loose); capabilitiesService = TypeMoq.Mock.ofType(TestCapabilitiesService); @@ -109,7 +114,13 @@ suite('notebook model', function (): void { layoutChanged: undefined, capabilitiesService: capabilitiesService.object }; - mockClientSession = TypeMoq.Mock.ofType(ClientSession, undefined, defaultModelOptions); + clientSessionOptions = { + notebookManager: defaultModelOptions.notebookManagers[0], + notebookUri: defaultModelOptions.notebookUri, + notificationService: notificationService.object, + kernelSpec: defaultModelOptions.defaultKernel + }; + mockClientSession = TypeMoq.Mock.ofType(ClientSession, undefined, clientSessionOptions); mockClientSession.setup(c => c.initialize()).returns(() => { return Promise.resolve(); }); @@ -135,9 +146,9 @@ suite('notebook model', function (): void { nbformat_minor: 5 }; - let mockContentManager = TypeMoq.Mock.ofType(LocalContentManager); - mockContentManager.setup(c => c.getNotebookContents(TypeMoq.It.isAny())).returns(() => Promise.resolve(emptyNotebook)); - notebookManagers[0].contentManager = mockContentManager.object; + let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentManager); + mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(emptyNotebook)); + defaultModelOptions.contentManager = mockContentManager.object; // When I initialize the model let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, undefined); await model.loadContents(); @@ -150,9 +161,9 @@ suite('notebook model', function (): void { test('Should use trusted state set in model load', async function (): Promise { // Given a notebook - let mockContentManager = TypeMoq.Mock.ofType(LocalContentManager); - mockContentManager.setup(c => c.getNotebookContents(TypeMoq.It.isAny())).returns(() => Promise.resolve(expectedNotebookContent)); - notebookManagers[0].contentManager = mockContentManager.object; + let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentManager); + mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedNotebookContent)); + defaultModelOptions.contentManager = mockContentManager.object; // When I initialize the model let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, undefined); await model.loadContents(true); @@ -162,70 +173,69 @@ suite('notebook model', function (): void { assert(model.trustedMode); }); - // test('Should throw if model load fails', async function(): Promise { - // // Given a call to get Contents fails - // let error = new Error('File not found'); - // let mockContentManager = TypeMoq.Mock.ofType(LocalContentManager); - // mockContentManager.setup(c => c.getNotebookContents(TypeMoq.It.isAny())).throws(error); - // notebookManagers[0].contentManager = mockContentManager.object; + test('Should throw if model load fails', async function (): Promise { + // Given a call to get Contents fails + let error = new Error('File not found'); + let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentManager); + mockContentManager.setup(c => c.loadContent()).returns(() => Promise.reject(error));//.throws(error); + defaultModelOptions.contentManager = mockContentManager.object; - // // When I initalize the model - // // Then it should throw - // let model = new NotebookModel(defaultModelOptions); - // should(model.inErrorState).be.false(); - // await testUtils.assertThrowsAsync(() => model.requestModelLoad(), error.message); - // should(model.inErrorState).be.true(); - // }); + // When I initalize the model + // Then it should throw + let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, undefined); + assert.equal(model.inErrorState, false); + await assert.rejects(async () => { await model.loadContents(); }); + assert.equal(model.inErrorState, true); + }); - // test('Should convert cell info to CellModels', async function(): Promise { - // // Given a notebook with 2 cells - // let mockContentManager = TypeMoq.Mock.ofType(LocalContentManager); - // mockContentManager.setup(c => c.getNotebookContents(TypeMoq.It.isAny())).returns(() => Promise.resolve(expectedNotebookContent)); - // notebookManagers[0].contentManager = mockContentManager.object; + test('Should convert cell info to CellModels', async function (): Promise { + // Given a notebook with 2 cells + let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentManager); + mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedNotebookContent)); + defaultModelOptions.contentManager = mockContentManager.object; - // // When I initalize the model - // let model = new NotebookModel(defaultModelOptions); - // await model.requestModelLoad(); + // When I initalize the model + let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, undefined); + await model.loadContents(); - // // Then I expect all cells to be in the model - // should(model.cells).have.length(2); - // should(model.cells[0].source).be.equal(expectedNotebookContent.cells[0].source); - // should(model.cells[1].source).be.equal(expectedNotebookContent.cells[1].source); - // }); + // Then I expect all cells to be in the model + assert.equal(model.cells.length, 2); + assert.deepEqual(model.cells[0].source, expectedNotebookContent.cells[0].source); + assert.deepEqual(model.cells[1].source, expectedNotebookContent.cells[1].source); + }); - // test('Should load contents but then go to error state if client session startup fails', async function(): Promise { - // let mockContentManager = TypeMoq.Mock.ofType(LocalContentManager); - // mockContentManager.setup(c => c.getNotebookContents(TypeMoq.It.isAny())).returns(() => Promise.resolve(expectedNotebookContentOneCell)); - // notebookManagers[0].contentManager = mockContentManager.object; + test('Should load contents but then go to error state if client session startup fails', async function (): Promise { + let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentManager); + mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedNotebookContentOneCell)); + defaultModelOptions.contentManager = mockContentManager.object; - // // Given I have a session that fails to start - // mockClientSession.setup(c => c.isInErrorState).returns(() => true); - // mockClientSession.setup(c => c.errorMessage).returns(() => 'Error'); - // sessionReady.resolve(); - // let sessionFired = false; + // Given I have a session that fails to start + mockClientSession.setup(c => c.isInErrorState).returns(() => true); + mockClientSession.setup(c => c.errorMessage).returns(() => 'Error'); + sessionReady.resolve(); + let sessionFired = false; - // let options: INotebookModelOptions = Object.assign({}, defaultModelOptions, > { - // factory: mockModelFactory.object - // }); - // let model = new NotebookModel(options); - // model.onClientSessionReady((session) => sessionFired = true); - // await model.requestModelLoad(); - // model.startSession(notebookManagers[0]); - - // // Then I expect load to succeed - // shouldHaveOneCell(model); - // should(model.clientSession).not.be.undefined(); - // // but on server load completion I expect error state to be set - // // Note: do not expect serverLoad event to throw even if failed - // await model.sessionLoadFinished; - // should(model.inErrorState).be.true(); - // should(sessionFired).be.false(); - // }); + let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, undefined); + model.onClientSessionReady((session) => sessionFired = true); + await model.loadContents(); + await model.requestModelLoad(); + // starting client session fails at startSessionInstance due to: + // Cannot set property 'defaultKernelLoaded' of undefined + await assert.rejects(async () => { await model.startSession(notebookManagers[0]); }); + // Then I expect load to succeed + assert.equal(model.cells.length, 1); + assert(model.clientSession); + // but on server load completion I expect error state to be set + // Note: do not expect serverLoad event to throw even if failed + await model.sessionLoadFinished; + assert.equal(model.inErrorState, false); + assert.equal(sessionFired, false); + }); test('Should not be in error state if client session initialization succeeds', async function (): Promise { - let mockContentManager = TypeMoq.Mock.ofType(LocalContentManager); - mockContentManager.setup(c => c.getNotebookContents(TypeMoq.It.isAny())).returns(() => Promise.resolve(expectedNotebookContentOneCell)); - notebookManagers[0].contentManager = mockContentManager.object; + let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentManager); + mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedNotebookContent)); + defaultModelOptions.contentManager = mockContentManager.object; let kernelChangedEmitter: Emitter = new Emitter(); let statusChangedEmitter: Emitter = new Emitter(); @@ -245,6 +255,7 @@ suite('notebook model', function (): void { let model = new NotebookModel(options, undefined, logService, undefined, undefined); model.onClientSessionReady((session) => actualSession = session); await model.requestModelLoad(); + await model.startSession(notebookManagers[0]); // Then I expect load to succeed @@ -252,9 +263,9 @@ suite('notebook model', function (): void { // but on server load completion I expect error state to be set // Note: do not expect serverLoad event to throw even if failed await model.sessionLoadFinished; - assert(!model.inErrorState); - assert.equal(actualSession, mockClientSession.object); - assert.equal(model.clientSession, mockClientSession.object); + assert.equal(model.inErrorState, false); + assert.deepEqual(actualSession, mockClientSession.object); + assert.deepEqual(model.clientSession, mockClientSession.object); }); test('Should sanitize kernel display name when IP is included', async function (): Promise { @@ -273,9 +284,9 @@ suite('notebook model', function (): void { test('Should notify on trust set', async function () { // Given a notebook that's been loaded - let mockContentManager = TypeMoq.Mock.ofType(LocalContentManager); - mockContentManager.setup(c => c.getNotebookContents(TypeMoq.It.isAny())).returns(() => Promise.resolve(expectedNotebookContent)); - notebookManagers[0].contentManager = mockContentManager.object; + let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentManager); + mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedNotebookContent)); + defaultModelOptions.contentManager = mockContentManager.object; let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, undefined); await model.requestModelLoad();