Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/contrib/notebook/test/browser/notebookExecutionService.test.ts
3296 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import assert from 'assert';
7
import * as sinon from 'sinon';
8
import { AsyncIterableObject } from '../../../../../base/common/async.js';
9
import { CancellationToken } from '../../../../../base/common/cancellation.js';
10
import { Event } from '../../../../../base/common/event.js';
11
import { DisposableStore } from '../../../../../base/common/lifecycle.js';
12
import { URI } from '../../../../../base/common/uri.js';
13
import { mock } from '../../../../../base/test/common/mock.js';
14
import { assertThrowsAsync, ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js';
15
import { PLAINTEXT_LANGUAGE_ID } from '../../../../../editor/common/languages/modesRegistry.js';
16
import { IMenu, IMenuService } from '../../../../../platform/actions/common/actions.js';
17
import { ICommandService } from '../../../../../platform/commands/common/commands.js';
18
import { IContextKeyService } from '../../../../../platform/contextkey/common/contextkey.js';
19
import { ExtensionIdentifier } from '../../../../../platform/extensions/common/extensions.js';
20
import { TestInstantiationService } from '../../../../../platform/instantiation/test/common/instantiationServiceMock.js';
21
import { insertCellAtIndex } from '../../browser/controller/cellOperations.js';
22
import { NotebookExecutionService } from '../../browser/services/notebookExecutionServiceImpl.js';
23
import { NotebookKernelService } from '../../browser/services/notebookKernelServiceImpl.js';
24
import { NotebookViewModel } from '../../browser/viewModel/notebookViewModelImpl.js';
25
import { NotebookTextModel } from '../../common/model/notebookTextModel.js';
26
import { CellKind, IOutputDto, NotebookCellMetadata } from '../../common/notebookCommon.js';
27
import { INotebookExecutionStateService } from '../../common/notebookExecutionStateService.js';
28
import { INotebookKernel, INotebookKernelHistoryService, INotebookKernelService, INotebookTextModelLike, VariablesResult } from '../../common/notebookKernelService.js';
29
import { INotebookLoggingService } from '../../common/notebookLoggingService.js';
30
import { INotebookService } from '../../common/notebookService.js';
31
import { setupInstantiationService, withTestNotebook as _withTestNotebook } from './testNotebookEditor.js';
32
33
suite('NotebookExecutionService', () => {
34
35
let instantiationService: TestInstantiationService;
36
let contextKeyService: IContextKeyService;
37
let kernelService: INotebookKernelService;
38
let disposables: DisposableStore;
39
40
teardown(() => {
41
disposables.dispose();
42
});
43
44
ensureNoDisposablesAreLeakedInTestSuite();
45
46
setup(function () {
47
48
disposables = new DisposableStore();
49
50
instantiationService = setupInstantiationService(disposables);
51
52
instantiationService.stub(INotebookService, new class extends mock<INotebookService>() {
53
override onDidAddNotebookDocument = Event.None;
54
override onWillRemoveNotebookDocument = Event.None;
55
override getNotebookTextModels() { return []; }
56
});
57
58
instantiationService.stub(INotebookLoggingService, new class extends mock<INotebookLoggingService>() {
59
override debug(category: string, output: string): void {
60
//
61
}
62
});
63
64
instantiationService.stub(IMenuService, new class extends mock<IMenuService>() {
65
override createMenu() {
66
return new class extends mock<IMenu>() {
67
override onDidChange = Event.None;
68
override getActions() { return []; }
69
override dispose() { }
70
};
71
}
72
});
73
74
instantiationService.stub(INotebookKernelHistoryService, new class extends mock<INotebookKernelHistoryService>() {
75
override getKernels(notebook: INotebookTextModelLike) {
76
return kernelService.getMatchingKernel(notebook);
77
}
78
override addMostRecentKernel(kernel: INotebookKernel): void { }
79
});
80
81
instantiationService.stub(ICommandService, new class extends mock<ICommandService>() {
82
override executeCommand(_commandId: string, ..._args: any[]) {
83
return Promise.resolve(undefined);
84
}
85
});
86
87
kernelService = disposables.add(instantiationService.createInstance(NotebookKernelService));
88
instantiationService.set(INotebookKernelService, kernelService);
89
contextKeyService = instantiationService.get(IContextKeyService);
90
});
91
92
async function withTestNotebook(cells: [string, string, CellKind, IOutputDto[], NotebookCellMetadata][], callback: (viewModel: NotebookViewModel, textModel: NotebookTextModel, disposables: DisposableStore) => void | Promise<void>) {
93
return _withTestNotebook(cells, (editor, viewModel, disposables) => callback(viewModel, viewModel.notebookDocument, disposables));
94
}
95
96
// test('ctor', () => {
97
// instantiationService.createInstance(NotebookEditorKernelManager, { activeKernel: undefined, viewModel: undefined });
98
// const contextKeyService = instantiationService.get(IContextKeyService);
99
100
// assert.strictEqual(contextKeyService.getContextKeyValue(NOTEBOOK_KERNEL_COUNT.key), 0);
101
// });
102
103
test('cell is not runnable when no kernel is selected', async () => {
104
await withTestNotebook(
105
[],
106
async (viewModel, textModel, disposables) => {
107
const executionService = instantiationService.createInstance(NotebookExecutionService);
108
109
const cell = insertCellAtIndex(viewModel, 1, 'var c = 3', 'javascript', CellKind.Code, {}, [], true, true);
110
await assertThrowsAsync(async () => await executionService.executeNotebookCells(textModel, [cell.model], contextKeyService));
111
});
112
});
113
114
test('cell is not runnable when kernel does not support the language', async () => {
115
await withTestNotebook(
116
[],
117
async (viewModel, textModel) => {
118
119
disposables.add(kernelService.registerKernel(new TestNotebookKernel({ languages: ['testlang'] })));
120
const executionService = disposables.add(instantiationService.createInstance(NotebookExecutionService));
121
const cell = disposables.add(insertCellAtIndex(viewModel, 1, 'var c = 3', 'javascript', CellKind.Code, {}, [], true, true));
122
await assertThrowsAsync(async () => await executionService.executeNotebookCells(textModel, [cell.model], contextKeyService));
123
124
});
125
});
126
127
test('cell is runnable when kernel does support the language', async () => {
128
await withTestNotebook(
129
[],
130
async (viewModel, textModel) => {
131
const kernel = new TestNotebookKernel({ languages: ['javascript'] });
132
disposables.add(kernelService.registerKernel(kernel));
133
kernelService.selectKernelForNotebook(kernel, textModel);
134
const executionService = disposables.add(instantiationService.createInstance(NotebookExecutionService));
135
const executeSpy = sinon.spy();
136
kernel.executeNotebookCellsRequest = executeSpy;
137
138
const cell = disposables.add(insertCellAtIndex(viewModel, 0, 'var c = 3', 'javascript', CellKind.Code, {}, [], true, true));
139
await executionService.executeNotebookCells(viewModel.notebookDocument, [cell.model], contextKeyService);
140
assert.strictEqual(executeSpy.calledOnce, true);
141
});
142
});
143
144
test('Completes unconfirmed executions', async function () {
145
146
return withTestNotebook([], async (viewModel, textModel) => {
147
let didExecute = false;
148
const kernel = new class extends TestNotebookKernel {
149
constructor() {
150
super({ languages: ['javascript'] });
151
this.id = 'mySpecialId';
152
}
153
154
override async executeNotebookCellsRequest() {
155
didExecute = true;
156
return;
157
}
158
};
159
160
disposables.add(kernelService.registerKernel(kernel));
161
kernelService.selectKernelForNotebook(kernel, textModel);
162
const executionService = disposables.add(instantiationService.createInstance(NotebookExecutionService));
163
const exeStateService = instantiationService.get(INotebookExecutionStateService);
164
165
const cell = disposables.add(insertCellAtIndex(viewModel, 0, 'var c = 3', 'javascript', CellKind.Code, {}, [], true, true));
166
await executionService.executeNotebookCells(textModel, [cell.model], contextKeyService);
167
168
assert.strictEqual(didExecute, true);
169
assert.strictEqual(exeStateService.getCellExecution(cell.uri), undefined);
170
});
171
});
172
});
173
174
class TestNotebookKernel implements INotebookKernel {
175
id: string = 'test';
176
label: string = '';
177
viewType = '*';
178
onDidChange = Event.None;
179
extension: ExtensionIdentifier = new ExtensionIdentifier('test');
180
localResourceRoot: URI = URI.file('/test');
181
description?: string | undefined;
182
detail?: string | undefined;
183
preloadUris: URI[] = [];
184
preloadProvides: string[] = [];
185
supportedLanguages: string[] = [];
186
provideVariables(notebookUri: URI, parentId: number | undefined, kind: 'named' | 'indexed', start: number, token: CancellationToken): AsyncIterableObject<VariablesResult> {
187
return AsyncIterableObject.EMPTY;
188
}
189
executeNotebookCellsRequest(): Promise<void> {
190
throw new Error('Method not implemented.');
191
}
192
cancelNotebookCellExecution(): Promise<void> {
193
throw new Error('Method not implemented.');
194
}
195
constructor(opts?: { languages: string[] }) {
196
this.supportedLanguages = opts?.languages ?? [PLAINTEXT_LANGUAGE_ID];
197
}
198
implementsInterrupt?: boolean | undefined;
199
implementsExecutionOrder?: boolean | undefined;
200
}
201
202