Add code coverage tests for cell.ts (#8564)

This commit is contained in:
Cory Rivera
2019-12-04 14:45:48 -08:00
committed by GitHub
parent a7f5741608
commit 9691fab917
4 changed files with 429 additions and 21 deletions

View File

@@ -80,7 +80,7 @@ export class CellModel implements ICellModel {
}
public equals(other: ICellModel) {
return other && other.id === this.id;
return other !== undefined && other.id === this.id;
}
public get onCollapseStateChanged(): Event<boolean> {
@@ -91,10 +91,6 @@ export class CellModel implements ICellModel {
return this._onOutputsChanged.event;
}
public get onCellModeChanged(): Event<boolean> {
return this._onCellModeChanged.event;
}
public get isEditMode(): boolean {
return this._isEditMode;
}
@@ -191,17 +187,13 @@ export class CellModel implements ICellModel {
}
public get notebookModel(): NotebookModel {
return <NotebookModel>this.options.notebook;
return this._options && <NotebookModel>this._options.notebook;
}
public set cellUri(value: URI) {
this._cellUri = value;
}
public get options(): ICellModelOptions {
return this._options;
}
public get cellType(): CellType {
return this._cellType;
}
@@ -234,7 +226,7 @@ export class CellModel implements ICellModel {
if (this._language) {
return this._language;
}
return this.options.notebook.language;
return this._options.notebook.language;
}
public get cellGuid(): string {
@@ -370,7 +362,7 @@ export class CellModel implements ICellModel {
}
private async getOrStartKernel(notificationService: INotificationService): Promise<nb.IKernel> {
let model = this.options.notebook;
let model = this._options.notebook;
let clientSession = model && model.clientSession;
if (!clientSession) {
this.sendNotification(notificationService, Severity.Error, localize('notebookNotReady', "The session for this notebook is not yet ready"));
@@ -516,7 +508,7 @@ export class CellModel implements ICellModel {
try {
let result = output as nb.IDisplayResult;
if (result && result.data && result.data['text/html']) {
let model = (this as CellModel).options.notebook as NotebookModel;
let model = this._options.notebook as NotebookModel;
if (model.activeConnection) {
let gatewayEndpointInfo = this.getGatewayEndpoint(model.activeConnection);
if (gatewayEndpointInfo) {

View File

@@ -418,6 +418,8 @@ export interface INotebookModel {
* @param cell New active cell
*/
updateActiveCell(cell: ICellModel);
requestConnection(): Promise<boolean>;
}
export interface NotebookContentChange {
@@ -491,6 +493,7 @@ export interface ICellModel {
isCollapsed: boolean;
readonly onCollapseStateChanged: Event<boolean>;
modelContentChangedEvent: IModelContentChangedEvent;
isEditMode: boolean;
}
export interface FutureInternal extends nb.IFuture {

View File

@@ -11,15 +11,21 @@ import * as objects from 'vs/base/common/objects';
import { CellTypes } from 'sql/workbench/contrib/notebook/common/models/contracts';
import { ModelFactory } from 'sql/workbench/contrib/notebook/browser/models/modelFactory';
import { NotebookModelStub } from './common';
import { NotebookModelStub, ClientSessionStub, KernelStub, FutureStub } from './common';
import { EmptyFuture } from 'sql/workbench/services/notebook/browser/sessionManager';
import { ICellModel } from 'sql/workbench/contrib/notebook/browser/models/modelInterfaces';
import { ICellModel, ICellModelOptions, IClientSession, INotebookModel } from 'sql/workbench/contrib/notebook/browser/models/modelInterfaces';
import { Deferred } from 'sql/base/common/promise';
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
import { isUndefinedOrNull } from 'vs/base/common/types';
import { startsWith } from 'vs/base/common/strings';
import { Schemas } from 'vs/base/common/network';
import { URI } from 'vs/base/common/uri';
import { IModelContentChangedEvent } from 'vs/editor/common/model/textModelEvents';
import { Promise } from 'es6-promise';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { TestNotificationService } from 'vs/platform/notification/test/common/testNotificationService';
let instantiationService: IInstantiationService;
@@ -590,4 +596,242 @@ suite('Cell Model', function (): void {
});
});
test('Getters and setters test', async function (): Promise<void> {
// Code Cell
let cellData: nb.ICellContents = {
cell_type: CellTypes.Code,
source: '1+1',
outputs: [],
metadata: { language: 'python' },
execution_count: 1
};
let cell = factory.createCell(cellData, undefined);
assert.strictEqual(cell.trustedMode, false, 'Cell should not be trusted by default');
cell.trustedMode = true;
assert.strictEqual(cell.trustedMode, true, 'Cell should be trusted after manually setting trustedMode');
assert.strictEqual(cell.isEditMode, true, 'Code cells should be editable by default');
cell.isEditMode = false;
assert.strictEqual(cell.isEditMode, false, 'Cell should not be editable after manually setting isEditMode');
cell.hover = true;
assert.strictEqual(cell.hover, true, 'Cell should be hovered after manually setting hover=true');
cell.hover = false;
assert.strictEqual(cell.hover, false, 'Cell should be hovered after manually setting hover=false');
let cellUri = URI.from({ scheme: Schemas.untitled, path: `notebook-editor-${cell.id}` });
assert.deepStrictEqual(cell.cellUri, cellUri);
cellUri = URI.from({ scheme: Schemas.untitled, path: `test-uri-12345` });
cell.cellUri = cellUri;
assert.deepStrictEqual(cell.cellUri, cellUri);
assert.strictEqual(cell.language, 'python');
assert.strictEqual(cell.notebookModel, undefined);
assert.strictEqual(cell.modelContentChangedEvent, undefined);
let contentChangedEvent = <IModelContentChangedEvent>{};
cell.modelContentChangedEvent = contentChangedEvent;
assert.strictEqual(cell.modelContentChangedEvent, contentChangedEvent);
assert.strictEqual(cell.stdInVisible, false, 'Cell stdin should not be visible by default');
cell.stdInVisible = true;
assert.strictEqual(cell.stdInVisible, true, 'Cell stdin should not be visible by default');
cell.loaded = true;
assert.strictEqual(cell.loaded, true, 'Cell should be loaded after manually setting loaded=true');
cell.loaded = false;
assert.strictEqual(cell.loaded, false, 'Cell should be loaded after manually setting loaded=false');
assert.ok(cell.onExecutionStateChange !== undefined, 'onExecutionStateChange event should not be undefined');
assert.ok(cell.onLoaded !== undefined, 'onLoaded event should not be undefined');
// Markdown cell
cellData = {
cell_type: CellTypes.Markdown,
source: 'some *markdown*',
outputs: [],
metadata: { language: 'python' }
};
let notebookModel = new NotebookModelStub({
name: 'python',
version: '',
mimetype: ''
});
let cellOptions: ICellModelOptions = { notebook: notebookModel, isTrusted: true };
cell = factory.createCell(cellData, cellOptions);
assert.strictEqual(cell.isEditMode, false, 'Markdown cells should not be editable by default');
assert.strictEqual(cell.trustedMode, true, 'Cell should be trusted when providing isTrusted=true in the cell options');
assert.strictEqual(cell.language, 'markdown');
assert.strictEqual(cell.notebookModel, notebookModel);
});
test('Equals test', async function (): Promise<void> {
let cell = factory.createCell(undefined, undefined);
let result = cell.equals(undefined);
assert.strictEqual(result, false, 'Cell should not be equal to undefined');
result = cell.equals(cell);
assert.strictEqual(result, true, 'Cell should be equal to itself');
let otherCell = factory.createCell(undefined, undefined);
result = cell.equals(otherCell);
assert.strictEqual(result, false, 'Cell should not be equal to a different cell');
});
suite('Run Cell tests', function (): void {
let cellOptions: ICellModelOptions;
let mockClientSession: TypeMoq.Mock<IClientSession>;
let mockNotebookModel: TypeMoq.Mock<INotebookModel>;
let mockKernel: TypeMoq.Mock<nb.IKernel>;
const codeCellContents: nb.ICellContents = {
cell_type: CellTypes.Code,
source: '1+1',
outputs: [],
metadata: { language: 'python' },
execution_count: 1
};
const markdownCellContents: nb.ICellContents = {
cell_type: CellTypes.Markdown,
source: 'some *markdown*',
outputs: [],
metadata: { language: 'python' }
};
setup(() => {
mockKernel = TypeMoq.Mock.ofType<nb.IKernel>(KernelStub);
mockClientSession = TypeMoq.Mock.ofType<IClientSession>(ClientSessionStub);
mockClientSession.setup(s => s.kernel).returns(() => mockKernel.object);
mockClientSession.setup(s => s.isReady).returns(() => true);
mockNotebookModel = TypeMoq.Mock.ofType<INotebookModel>(NotebookModelStub);
mockNotebookModel.setup(m => m.clientSession).returns(() => mockClientSession.object);
mockNotebookModel.setup(m => m.updateActiveCell(TypeMoq.It.isAny()));
cellOptions = { notebook: mockNotebookModel.object, isTrusted: true };
});
test('Run markdown cell', async function (): Promise<void> {
let cell = factory.createCell(markdownCellContents, cellOptions);
let result = await cell.runCell();
assert.strictEqual(result, false, 'Markdown cells should not be runnable');
});
test('No client session provided', async function (): Promise<void> {
mockNotebookModel.reset();
mockNotebookModel.setup(m => m.clientSession).returns(() => undefined);
mockNotebookModel.setup(m => m.updateActiveCell(TypeMoq.It.isAny()));
cellOptions.notebook = mockNotebookModel.object;
let cell = factory.createCell(codeCellContents, cellOptions);
let result = await cell.runCell();
assert.strictEqual(result, false, 'Running code cell without a client session should fail');
});
test('No Kernel provided', async function (): Promise<void> {
mockClientSession.reset();
mockClientSession.setup(s => s.kernel).returns(() => null);
mockClientSession.setup(s => s.isReady).returns(() => true);
mockNotebookModel.reset();
mockNotebookModel.setup(m => m.defaultKernel).returns(() => null);
mockNotebookModel.setup(m => m.clientSession).returns(() => mockClientSession.object);
mockNotebookModel.setup(m => m.updateActiveCell(TypeMoq.It.isAny()));
cellOptions.notebook = mockNotebookModel.object;
let cell = factory.createCell(codeCellContents, cellOptions);
let result = await cell.runCell();
assert.strictEqual(result, false, 'Running code cell without a kernel should fail');
});
test('Kernel fails to connect', async function (): Promise<void> {
mockKernel.setup(k => k.requiresConnection).returns(() => true);
mockNotebookModel.setup(m => m.requestConnection()).returns(() => Promise.resolve(false));
let cell = factory.createCell(codeCellContents, cellOptions);
let result = await cell.runCell();
assert.strictEqual(result, false, 'Running code cell should fail after connection fails');
});
test('Normal execute', async function (): Promise<void> {
mockKernel.setup(k => k.requiresConnection).returns(() => false);
mockKernel.setup(k => k.requestExecute(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => {
let replyMsg: nb.IExecuteReplyMsg = <nb.IExecuteReplyMsg>{
content: <nb.IExecuteReply>{
execution_count: 1,
status: 'ok'
}
};
return new FutureStub(undefined, Promise.resolve(replyMsg));
});
let cell = factory.createCell(codeCellContents, cellOptions);
let result = await cell.runCell();
assert.strictEqual(result, true, 'Running normal code cell should succeed');
});
test('Execute returns error status', async function (): Promise<void> {
mockKernel.setup(k => k.requiresConnection).returns(() => false);
mockKernel.setup(k => k.requestExecute(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => {
let replyMsg: nb.IExecuteReplyMsg = <nb.IExecuteReplyMsg>{
content: <nb.IExecuteReply>{
execution_count: 1,
status: 'error'
}
};
return new FutureStub(undefined, Promise.resolve(replyMsg));
});
let cell = factory.createCell(codeCellContents, cellOptions);
let result = await cell.runCell();
assert.strictEqual(result, false, 'Run cell should fail if execute returns error status');
});
test('Execute returns abort status', async function (): Promise<void> {
mockKernel.setup(k => k.requiresConnection).returns(() => false);
mockKernel.setup(k => k.requestExecute(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => {
let replyMsg: nb.IExecuteReplyMsg = <nb.IExecuteReplyMsg>{
content: <nb.IExecuteReply>{
execution_count: 1,
status: 'abort'
}
};
return new FutureStub(undefined, Promise.resolve(replyMsg));
});
let cell = factory.createCell(codeCellContents, cellOptions);
let result = await cell.runCell();
assert.strictEqual(result, false, 'Run cell should fail if execute returns abort status');
});
test('Execute throws exception', async function (): Promise<void> {
let testMsg = 'Test message';
mockKernel.setup(k => k.requiresConnection).returns(() => false);
mockKernel.setup(k => k.requestExecute(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => {
throw new Error(testMsg);
});
let actualMsg: string;
let mockNotification = TypeMoq.Mock.ofType<INotificationService>(TestNotificationService);
mockNotification.setup(n => n.notify(TypeMoq.It.isAny())).returns(notification => {
actualMsg = notification.message;
return undefined;
});
let cell = factory.createCell(codeCellContents, cellOptions);
let result = await cell.runCell(mockNotification.object);
assert.strictEqual(result, true, 'Run cell should report errors via notification service');
assert.ok(actualMsg !== undefined, 'Should have received an error notification');
assert.strictEqual(actualMsg, testMsg);
});
});
});

View File

@@ -6,7 +6,7 @@
import { nb, IConnectionProfile } from 'azdata';
import { Event, Emitter } from 'vs/base/common/event';
import { INotebookModel, ICellModel, IClientSession, IDefaultConnection, NotebookContentChange } from 'sql/workbench/contrib/notebook/browser/models/modelInterfaces';
import { INotebookModel, ICellModel, IClientSession, IDefaultConnection, NotebookContentChange, IKernelPreference } from 'sql/workbench/contrib/notebook/browser/models/modelInterfaces';
import { NotebookChangeType, CellType } from 'sql/workbench/contrib/notebook/common/models/contracts';
import { INotebookManager, INotebookService, INotebookEditor, ILanguageMagic, INotebookProvider, INavigationProvider } from 'sql/workbench/services/notebook/browser/notebookService';
import { ISingleNotebookEditOperation } from 'sql/workbench/api/common/sqlExtHostTypes';
@@ -17,11 +17,11 @@ import { RenderMimeRegistry } from 'sql/workbench/contrib/notebook/browser/outpu
export class NotebookModelStub implements INotebookModel {
constructor(private _languageInfo?: nb.ILanguageInfo) {
}
public trustedMode: boolean;
trustedMode: boolean;
language: string;
standardKernels: IStandardKernelWithProvider[];
public get languageInfo(): nb.ILanguageInfo {
get languageInfo(): nb.ILanguageInfo {
return this._languageInfo;
}
onCellChange(cell: ICellModel, change: NotebookChangeType): void {
@@ -114,7 +114,9 @@ export class NotebookModelStub implements INotebookModel {
updateActiveCell(cell: ICellModel) {
throw new Error('Method not implemented.');
}
requestConnection(): Promise<boolean> {
throw new Error('Method not implemented.');
}
}
export class NotebookManagerStub implements INotebookManager {
@@ -125,12 +127,12 @@ export class NotebookManagerStub implements INotebookManager {
}
export class ServerManagerStub implements nb.ServerManager {
public onServerStartedEmitter = new Emitter<void>();
onServerStartedEmitter = new Emitter<void>();
onServerStarted: Event<void> = this.onServerStartedEmitter.event;
isStarted: boolean = false;
calledStart: boolean = false;
calledEnd: boolean = false;
public result: Promise<void> = undefined;
result: Promise<void> = undefined;
startServer(): Promise<void> {
this.calledStart = true;
@@ -202,3 +204,170 @@ export class NotebookServiceStub implements INotebookService {
throw new Error('Method not implemented.');
}
}
export class ClientSessionStub implements IClientSession {
initialize(): Promise<void> {
throw new Error('Method not implemented.');
}
changeKernel(options: nb.IKernelSpec, oldKernel?: nb.IKernel): Promise<nb.IKernel> {
throw new Error('Method not implemented.');
}
configureKernel(options: nb.IKernelSpec): Promise<void> {
throw new Error('Method not implemented.');
}
shutdown(): Promise<void> {
throw new Error('Method not implemented.');
}
selectKernel(): Promise<void> {
throw new Error('Method not implemented.');
}
restart(): Promise<boolean> {
throw new Error('Method not implemented.');
}
setPath(path: string): Promise<void> {
throw new Error('Method not implemented.');
}
setName(name: string): Promise<void> {
throw new Error('Method not implemented.');
}
setType(type: string): Promise<void> {
throw new Error('Method not implemented.');
}
updateConnection(connection: IConnectionProfile): Promise<void> {
throw new Error('Method not implemented.');
}
onKernelChanging(changeHandler: (kernel: nb.IKernelChangedArgs) => Promise<void>): void {
throw new Error('Method not implemented.');
}
dispose(): void {
throw new Error('Method not implemented.');
}
get terminated(): Event<void> {
throw new Error('Method not implemented.');
}
get kernelChanged(): Event<nb.IKernelChangedArgs> {
throw new Error('Method not implemented.');
}
get statusChanged(): Event<nb.ISession> {
throw new Error('Method not implemented.');
}
get iopubMessage(): Event<nb.IMessage> {
throw new Error('Method not implemented.');
}
get unhandledMessage(): Event<nb.IMessage> {
throw new Error('Method not implemented.');
}
get propertyChanged(): Event<'path' | 'name' | 'type'> {
throw new Error('Method not implemented.');
}
get kernel(): nb.IKernel | null {
throw new Error('Method not implemented.');
}
get notebookUri(): URI {
throw new Error('Method not implemented.');
}
get name(): string {
throw new Error('Method not implemented.');
}
get type(): string {
throw new Error('Method not implemented.');
}
get status(): nb.KernelStatus {
throw new Error('Method not implemented.');
}
get isReady(): boolean {
throw new Error('Method not implemented.');
}
get ready(): Promise<void> {
throw new Error('Method not implemented.');
}
get kernelChangeCompleted(): Promise<void> {
throw new Error('Method not implemented.');
}
get kernelPreference(): IKernelPreference {
throw new Error('Method not implemented.');
}
set kernelPreference(value: IKernelPreference) {
throw new Error('Method not implemented.');
}
get kernelDisplayName(): string {
throw new Error('Method not implemented.');
}
get errorMessage(): string {
throw new Error('Method not implemented.');
}
get isInErrorState(): boolean {
throw new Error('Method not implemented.');
}
get cachedKernelSpec(): nb.IKernelSpec {
throw new Error('Method not implemented.');
}
}
export class KernelStub implements nb.IKernel {
get id(): string {
throw new Error('Method not implemented.');
}
get name(): string {
throw new Error('Method not implemented.');
}
get supportsIntellisense(): boolean {
throw new Error('Method not implemented.');
}
get requiresConnection(): boolean {
throw new Error('Method not implemented.');
}
get isReady(): boolean {
throw new Error('Method not implemented.');
}
get ready(): Thenable<void> {
throw new Error('Method not implemented.');
}
get info(): nb.IInfoReply {
throw new Error('Method not implemented.');
}
getSpec(): Thenable<nb.IKernelSpec> {
throw new Error('Method not implemented.');
}
requestExecute(content: nb.IExecuteRequest, disposeOnDone?: boolean): nb.IFuture {
throw new Error('Method not implemented.');
}
requestComplete(content: nb.ICompleteRequest): Thenable<nb.ICompleteReplyMsg> {
throw new Error('Method not implemented.');
}
interrupt(): Thenable<void> {
throw new Error('Method not implemented.');
}
}
export class FutureStub implements nb.IFuture {
constructor(private _msg: nb.IMessage, private _done: Thenable<nb.IShellMessage>) {
}
get msg(): nb.IMessage {
return this._msg;
}
get done(): Thenable<nb.IShellMessage> {
return this._done;
}
setReplyHandler(handler: nb.MessageHandler<nb.IShellMessage>): void {
return;
}
setStdInHandler(handler: nb.MessageHandler<nb.IStdinMessage>): void {
return;
}
setIOPubHandler(handler: nb.MessageHandler<nb.IIOPubMessage>): void {
return;
}
registerMessageHook(hook: (msg: nb.IIOPubMessage) => boolean | Thenable<boolean>): void {
return;
}
removeMessageHook(hook: (msg: nb.IIOPubMessage) => boolean | Thenable<boolean>): void {
return;
}
sendInputReply(content: nb.IInputReply): void {
return;
}
dispose() {
return;
}
}