Path: blob/main/src/vs/workbench/contrib/notebook/test/browser/notebookExecutionService.test.ts
3296 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import assert from 'assert';6import * as sinon from 'sinon';7import { AsyncIterableObject } from '../../../../../base/common/async.js';8import { CancellationToken } from '../../../../../base/common/cancellation.js';9import { Event } from '../../../../../base/common/event.js';10import { DisposableStore } from '../../../../../base/common/lifecycle.js';11import { URI } from '../../../../../base/common/uri.js';12import { mock } from '../../../../../base/test/common/mock.js';13import { assertThrowsAsync, ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js';14import { PLAINTEXT_LANGUAGE_ID } from '../../../../../editor/common/languages/modesRegistry.js';15import { IMenu, IMenuService } from '../../../../../platform/actions/common/actions.js';16import { ICommandService } from '../../../../../platform/commands/common/commands.js';17import { IContextKeyService } from '../../../../../platform/contextkey/common/contextkey.js';18import { ExtensionIdentifier } from '../../../../../platform/extensions/common/extensions.js';19import { TestInstantiationService } from '../../../../../platform/instantiation/test/common/instantiationServiceMock.js';20import { insertCellAtIndex } from '../../browser/controller/cellOperations.js';21import { NotebookExecutionService } from '../../browser/services/notebookExecutionServiceImpl.js';22import { NotebookKernelService } from '../../browser/services/notebookKernelServiceImpl.js';23import { NotebookViewModel } from '../../browser/viewModel/notebookViewModelImpl.js';24import { NotebookTextModel } from '../../common/model/notebookTextModel.js';25import { CellKind, IOutputDto, NotebookCellMetadata } from '../../common/notebookCommon.js';26import { INotebookExecutionStateService } from '../../common/notebookExecutionStateService.js';27import { INotebookKernel, INotebookKernelHistoryService, INotebookKernelService, INotebookTextModelLike, VariablesResult } from '../../common/notebookKernelService.js';28import { INotebookLoggingService } from '../../common/notebookLoggingService.js';29import { INotebookService } from '../../common/notebookService.js';30import { setupInstantiationService, withTestNotebook as _withTestNotebook } from './testNotebookEditor.js';3132suite('NotebookExecutionService', () => {3334let instantiationService: TestInstantiationService;35let contextKeyService: IContextKeyService;36let kernelService: INotebookKernelService;37let disposables: DisposableStore;3839teardown(() => {40disposables.dispose();41});4243ensureNoDisposablesAreLeakedInTestSuite();4445setup(function () {4647disposables = new DisposableStore();4849instantiationService = setupInstantiationService(disposables);5051instantiationService.stub(INotebookService, new class extends mock<INotebookService>() {52override onDidAddNotebookDocument = Event.None;53override onWillRemoveNotebookDocument = Event.None;54override getNotebookTextModels() { return []; }55});5657instantiationService.stub(INotebookLoggingService, new class extends mock<INotebookLoggingService>() {58override debug(category: string, output: string): void {59//60}61});6263instantiationService.stub(IMenuService, new class extends mock<IMenuService>() {64override createMenu() {65return new class extends mock<IMenu>() {66override onDidChange = Event.None;67override getActions() { return []; }68override dispose() { }69};70}71});7273instantiationService.stub(INotebookKernelHistoryService, new class extends mock<INotebookKernelHistoryService>() {74override getKernels(notebook: INotebookTextModelLike) {75return kernelService.getMatchingKernel(notebook);76}77override addMostRecentKernel(kernel: INotebookKernel): void { }78});7980instantiationService.stub(ICommandService, new class extends mock<ICommandService>() {81override executeCommand(_commandId: string, ..._args: any[]) {82return Promise.resolve(undefined);83}84});8586kernelService = disposables.add(instantiationService.createInstance(NotebookKernelService));87instantiationService.set(INotebookKernelService, kernelService);88contextKeyService = instantiationService.get(IContextKeyService);89});9091async function withTestNotebook(cells: [string, string, CellKind, IOutputDto[], NotebookCellMetadata][], callback: (viewModel: NotebookViewModel, textModel: NotebookTextModel, disposables: DisposableStore) => void | Promise<void>) {92return _withTestNotebook(cells, (editor, viewModel, disposables) => callback(viewModel, viewModel.notebookDocument, disposables));93}9495// test('ctor', () => {96// instantiationService.createInstance(NotebookEditorKernelManager, { activeKernel: undefined, viewModel: undefined });97// const contextKeyService = instantiationService.get(IContextKeyService);9899// assert.strictEqual(contextKeyService.getContextKeyValue(NOTEBOOK_KERNEL_COUNT.key), 0);100// });101102test('cell is not runnable when no kernel is selected', async () => {103await withTestNotebook(104[],105async (viewModel, textModel, disposables) => {106const executionService = instantiationService.createInstance(NotebookExecutionService);107108const cell = insertCellAtIndex(viewModel, 1, 'var c = 3', 'javascript', CellKind.Code, {}, [], true, true);109await assertThrowsAsync(async () => await executionService.executeNotebookCells(textModel, [cell.model], contextKeyService));110});111});112113test('cell is not runnable when kernel does not support the language', async () => {114await withTestNotebook(115[],116async (viewModel, textModel) => {117118disposables.add(kernelService.registerKernel(new TestNotebookKernel({ languages: ['testlang'] })));119const executionService = disposables.add(instantiationService.createInstance(NotebookExecutionService));120const cell = disposables.add(insertCellAtIndex(viewModel, 1, 'var c = 3', 'javascript', CellKind.Code, {}, [], true, true));121await assertThrowsAsync(async () => await executionService.executeNotebookCells(textModel, [cell.model], contextKeyService));122123});124});125126test('cell is runnable when kernel does support the language', async () => {127await withTestNotebook(128[],129async (viewModel, textModel) => {130const kernel = new TestNotebookKernel({ languages: ['javascript'] });131disposables.add(kernelService.registerKernel(kernel));132kernelService.selectKernelForNotebook(kernel, textModel);133const executionService = disposables.add(instantiationService.createInstance(NotebookExecutionService));134const executeSpy = sinon.spy();135kernel.executeNotebookCellsRequest = executeSpy;136137const cell = disposables.add(insertCellAtIndex(viewModel, 0, 'var c = 3', 'javascript', CellKind.Code, {}, [], true, true));138await executionService.executeNotebookCells(viewModel.notebookDocument, [cell.model], contextKeyService);139assert.strictEqual(executeSpy.calledOnce, true);140});141});142143test('Completes unconfirmed executions', async function () {144145return withTestNotebook([], async (viewModel, textModel) => {146let didExecute = false;147const kernel = new class extends TestNotebookKernel {148constructor() {149super({ languages: ['javascript'] });150this.id = 'mySpecialId';151}152153override async executeNotebookCellsRequest() {154didExecute = true;155return;156}157};158159disposables.add(kernelService.registerKernel(kernel));160kernelService.selectKernelForNotebook(kernel, textModel);161const executionService = disposables.add(instantiationService.createInstance(NotebookExecutionService));162const exeStateService = instantiationService.get(INotebookExecutionStateService);163164const cell = disposables.add(insertCellAtIndex(viewModel, 0, 'var c = 3', 'javascript', CellKind.Code, {}, [], true, true));165await executionService.executeNotebookCells(textModel, [cell.model], contextKeyService);166167assert.strictEqual(didExecute, true);168assert.strictEqual(exeStateService.getCellExecution(cell.uri), undefined);169});170});171});172173class TestNotebookKernel implements INotebookKernel {174id: string = 'test';175label: string = '';176viewType = '*';177onDidChange = Event.None;178extension: ExtensionIdentifier = new ExtensionIdentifier('test');179localResourceRoot: URI = URI.file('/test');180description?: string | undefined;181detail?: string | undefined;182preloadUris: URI[] = [];183preloadProvides: string[] = [];184supportedLanguages: string[] = [];185provideVariables(notebookUri: URI, parentId: number | undefined, kind: 'named' | 'indexed', start: number, token: CancellationToken): AsyncIterableObject<VariablesResult> {186return AsyncIterableObject.EMPTY;187}188executeNotebookCellsRequest(): Promise<void> {189throw new Error('Method not implemented.');190}191cancelNotebookCellExecution(): Promise<void> {192throw new Error('Method not implemented.');193}194constructor(opts?: { languages: string[] }) {195this.supportedLanguages = opts?.languages ?? [PLAINTEXT_LANGUAGE_ID];196}197implementsInterrupt?: boolean | undefined;198implementsExecutionOrder?: boolean | undefined;199}200201202