Path: blob/main/src/vs/workbench/contrib/notebook/test/browser/notebookKernelService.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 { URI } from '../../../../../base/common/uri.js';7import { ExtensionIdentifier } from '../../../../../platform/extensions/common/extensions.js';8import { setupInstantiationService } from './testNotebookEditor.js';9import { Emitter, Event } from '../../../../../base/common/event.js';10import { INotebookKernel, INotebookKernelService, VariablesResult } from '../../common/notebookKernelService.js';11import { NotebookKernelService } from '../../browser/services/notebookKernelServiceImpl.js';12import { INotebookService } from '../../common/notebookService.js';13import { mock } from '../../../../../base/test/common/mock.js';14import { TestInstantiationService } from '../../../../../platform/instantiation/test/common/instantiationServiceMock.js';15import { DisposableStore } from '../../../../../base/common/lifecycle.js';16import { NotebookTextModel } from '../../common/model/notebookTextModel.js';17import { PLAINTEXT_LANGUAGE_ID } from '../../../../../editor/common/languages/modesRegistry.js';18import { IMenu, IMenuService } from '../../../../../platform/actions/common/actions.js';19import { TransientOptions } from '../../common/notebookCommon.js';20import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js';21import { CancellationToken } from '../../../../../base/common/cancellation.js';22import { AsyncIterableObject } from '../../../../../base/common/async.js';2324suite('NotebookKernelService', () => {2526let instantiationService: TestInstantiationService;27let kernelService: INotebookKernelService;28let disposables: DisposableStore;2930let onDidAddNotebookDocument: Emitter<NotebookTextModel>;31teardown(() => {32disposables.dispose();33});3435ensureNoDisposablesAreLeakedInTestSuite();3637setup(function () {38disposables = new DisposableStore();3940onDidAddNotebookDocument = new Emitter();41disposables.add(onDidAddNotebookDocument);4243instantiationService = setupInstantiationService(disposables);44instantiationService.stub(INotebookService, new class extends mock<INotebookService>() {45override onDidAddNotebookDocument = onDidAddNotebookDocument.event;46override onWillRemoveNotebookDocument = Event.None;47override getNotebookTextModels() { return []; }48});49instantiationService.stub(IMenuService, new class extends mock<IMenuService>() {50override createMenu() {51return new class extends mock<IMenu>() {52override onDidChange = Event.None;53override getActions() { return []; }54override dispose() { }55};56}57});58kernelService = disposables.add(instantiationService.createInstance(NotebookKernelService));59instantiationService.set(INotebookKernelService, kernelService);60});6162test('notebook priorities', function () {6364const u1 = URI.parse('foo:///one');65const u2 = URI.parse('foo:///two');6667const k1 = new TestNotebookKernel({ label: 'z' });68const k2 = new TestNotebookKernel({ label: 'a' });6970disposables.add(kernelService.registerKernel(k1));71disposables.add(kernelService.registerKernel(k2));7273// equal priorities -> sort by name74let info = kernelService.getMatchingKernel({ uri: u1, notebookType: 'foo' });75assert.ok(info.all[0] === k2);76assert.ok(info.all[1] === k1);7778// update priorities for u1 notebook79kernelService.updateKernelNotebookAffinity(k2, u1, 2);80kernelService.updateKernelNotebookAffinity(k2, u2, 1);8182// updated83info = kernelService.getMatchingKernel({ uri: u1, notebookType: 'foo' });84assert.ok(info.all[0] === k2);85assert.ok(info.all[1] === k1);8687// NOT updated88info = kernelService.getMatchingKernel({ uri: u2, notebookType: 'foo' });89assert.ok(info.all[0] === k2);90assert.ok(info.all[1] === k1);9192// reset93kernelService.updateKernelNotebookAffinity(k2, u1, undefined);94info = kernelService.getMatchingKernel({ uri: u1, notebookType: 'foo' });95assert.ok(info.all[0] === k2);96assert.ok(info.all[1] === k1);97});9899test('new kernel with higher affinity wins, https://github.com/microsoft/vscode/issues/122028', function () {100const notebook = URI.parse('foo:///one');101102const kernel = new TestNotebookKernel();103disposables.add(kernelService.registerKernel(kernel));104105let info = kernelService.getMatchingKernel({ uri: notebook, notebookType: 'foo' });106assert.strictEqual(info.all.length, 1);107assert.ok(info.all[0] === kernel);108109const betterKernel = new TestNotebookKernel();110disposables.add(kernelService.registerKernel(betterKernel));111112info = kernelService.getMatchingKernel({ uri: notebook, notebookType: 'foo' });113assert.strictEqual(info.all.length, 2);114115kernelService.updateKernelNotebookAffinity(betterKernel, notebook, 2);116info = kernelService.getMatchingKernel({ uri: notebook, notebookType: 'foo' });117assert.strictEqual(info.all.length, 2);118assert.ok(info.all[0] === betterKernel);119assert.ok(info.all[1] === kernel);120});121122test('onDidChangeSelectedNotebooks not fired on initial notebook open #121904', function () {123124const uri = URI.parse('foo:///one');125const jupyter = { uri, viewType: 'jupyter', notebookType: 'jupyter' };126const dotnet = { uri, viewType: 'dotnet', notebookType: 'dotnet' };127128const jupyterKernel = new TestNotebookKernel({ viewType: jupyter.viewType });129const dotnetKernel = new TestNotebookKernel({ viewType: dotnet.viewType });130disposables.add(kernelService.registerKernel(jupyterKernel));131disposables.add(kernelService.registerKernel(dotnetKernel));132133kernelService.selectKernelForNotebook(jupyterKernel, jupyter);134kernelService.selectKernelForNotebook(dotnetKernel, dotnet);135136let info = kernelService.getMatchingKernel(dotnet);137assert.strictEqual(info.selected === dotnetKernel, true);138139info = kernelService.getMatchingKernel(jupyter);140assert.strictEqual(info.selected === jupyterKernel, true);141});142143test('onDidChangeSelectedNotebooks not fired on initial notebook open #121904, p2', async function () {144145const uri = URI.parse('foo:///one');146const jupyter = { uri, viewType: 'jupyter', notebookType: 'jupyter' };147const dotnet = { uri, viewType: 'dotnet', notebookType: 'dotnet' };148149const jupyterKernel = new TestNotebookKernel({ viewType: jupyter.viewType });150const dotnetKernel = new TestNotebookKernel({ viewType: dotnet.viewType });151disposables.add(kernelService.registerKernel(jupyterKernel));152disposables.add(kernelService.registerKernel(dotnetKernel));153154kernelService.selectKernelForNotebook(jupyterKernel, jupyter);155kernelService.selectKernelForNotebook(dotnetKernel, dotnet);156157const transientOptions: TransientOptions = {158transientOutputs: false,159transientCellMetadata: {},160transientDocumentMetadata: {},161cellContentMetadata: {},162};163164{165// open as jupyter -> bind event166const p1 = Event.toPromise(kernelService.onDidChangeSelectedNotebooks);167const d1 = disposables.add(instantiationService.createInstance(NotebookTextModel, jupyter.viewType, jupyter.uri, [], {}, transientOptions));168onDidAddNotebookDocument.fire(d1);169const event = await p1;170assert.strictEqual(event.newKernel, jupyterKernel.id);171}172{173// RE-open as dotnet -> bind event174const p2 = Event.toPromise(kernelService.onDidChangeSelectedNotebooks);175const d2 = disposables.add(instantiationService.createInstance(NotebookTextModel, dotnet.viewType, dotnet.uri, [], {}, transientOptions));176onDidAddNotebookDocument.fire(d2);177const event2 = await p2;178assert.strictEqual(event2.newKernel, dotnetKernel.id);179}180});181});182183class TestNotebookKernel implements INotebookKernel {184id: string = Math.random() + 'kernel';185label: string = 'test-label';186viewType = '*';187onDidChange = Event.None;188extension: ExtensionIdentifier = new ExtensionIdentifier('test');189localResourceRoot: URI = URI.file('/test');190description?: string | undefined;191detail?: string | undefined;192preloadUris: URI[] = [];193preloadProvides: string[] = [];194supportedLanguages: string[] = [];195executeNotebookCellsRequest(): Promise<void> {196throw new Error('Method not implemented.');197}198cancelNotebookCellExecution(): Promise<void> {199throw new Error('Method not implemented.');200}201provideVariables(notebookUri: URI, parentId: number | undefined, kind: 'named' | 'indexed', start: number, token: CancellationToken): AsyncIterableObject<VariablesResult> {202return AsyncIterableObject.EMPTY;203}204205constructor(opts?: { languages?: string[]; label?: string; viewType?: string }) {206this.supportedLanguages = opts?.languages ?? [PLAINTEXT_LANGUAGE_ID];207this.label = opts?.label ?? this.label;208this.viewType = opts?.viewType ?? this.viewType;209}210}211212213