Skip to content

Commit 333a169

Browse files
authored
test: Add DeepnoteKernelAutoSelector tests (#168)
Signed-off-by: Tomas Kislan <tomas@kislan.sk>
1 parent ed71529 commit 333a169

File tree

2 files changed

+167
-2
lines changed

2 files changed

+167
-2
lines changed

src/notebooks/deepnote/deepnoteKernelAutoSelector.node.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,7 @@ export class DeepnoteKernelAutoSelector implements IDeepnoteKernelAutoSelector,
320320
// }
321321
}
322322

323-
private async onKernelStarted(kernel: IKernel) {
323+
public async onKernelStarted(kernel: IKernel) {
324324
// Only handle deepnote notebooks
325325
if (kernel.notebook?.notebookType !== DEEPNOTE_NOTEBOOK_TYPE) {
326326
return;

src/notebooks/deepnote/deepnoteKernelAutoSelector.node.unit.test.ts

Lines changed: 166 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { assert } from 'chai';
22
import * as sinon from 'sinon';
3-
import { anything, instance, mock, when } from 'ts-mockito';
3+
import { anything, instance, mock, verify, when } from 'ts-mockito';
44
import { DeepnoteKernelAutoSelector } from './deepnoteKernelAutoSelector.node';
55
import {
66
IDeepnoteEnvironmentManager,
@@ -21,6 +21,7 @@ import { NotebookDocument, Uri, NotebookController, CancellationToken } from 'vs
2121
import { DeepnoteEnvironment } from '../../kernels/deepnote/environments/deepnoteEnvironment';
2222
import { PythonEnvironment } from '../../platform/pythonEnvironments/info';
2323
import { computeRequirementsHash } from './deepnoteProjectUtils';
24+
import { mockedVSCodeNamespaces, resetVSCodeMocks } from '../../test/vscode-mock';
2425

2526
suite('DeepnoteKernelAutoSelector - rebuildController', () => {
2627
let selector: DeepnoteKernelAutoSelector;
@@ -48,6 +49,7 @@ suite('DeepnoteKernelAutoSelector - rebuildController', () => {
4849
let sandbox: sinon.SinonSandbox;
4950

5051
setup(() => {
52+
resetVSCodeMocks();
5153
sandbox = sinon.createSandbox();
5254

5355
// Create mocks for all dependencies
@@ -275,6 +277,169 @@ suite('DeepnoteKernelAutoSelector - rebuildController', () => {
275277
});
276278
});
277279

280+
suite('pickEnvironment', () => {
281+
test('should return selected environment when user picks one', async () => {
282+
// Arrange
283+
const notebookUri = Uri.parse('file:///test/notebook.deepnote');
284+
const mockEnv1 = createMockEnvironment('env-1', 'Environment 1');
285+
const mockEnv2 = createMockEnvironment('env-2', 'Environment 2');
286+
const environments = [mockEnv1, mockEnv2];
287+
288+
// Mock environment manager
289+
when(mockEnvironmentManager.waitForInitialization()).thenResolve();
290+
when(mockEnvironmentManager.listEnvironments()).thenReturn(environments);
291+
292+
// Mock window.showQuickPick to simulate user selecting the first environment
293+
when(mockedVSCodeNamespaces.window.showQuickPick(anything(), anything())).thenResolve({
294+
label: mockEnv1.name,
295+
description: mockEnv1.pythonInterpreter.uri.fsPath,
296+
environment: mockEnv1
297+
} as any);
298+
299+
// Act
300+
const result = await selector.pickEnvironment(notebookUri);
301+
302+
// Assert
303+
assert.strictEqual(result, mockEnv1, 'Should return the selected environment');
304+
});
305+
});
306+
307+
suite('onKernelStarted', () => {
308+
test('should return early and not call initNotebookRunner for non-deepnote notebooks', async () => {
309+
// Arrange
310+
const mockKernel = mock<IKernel>();
311+
const mockJupyterNotebook = mock<NotebookDocument>();
312+
313+
when(mockJupyterNotebook.notebookType).thenReturn('jupyter-notebook');
314+
when(mockKernel.notebook).thenReturn(instance(mockJupyterNotebook));
315+
316+
// Mock initNotebookRunner to track if it gets called
317+
when(mockInitNotebookRunner.runInitNotebookIfNeeded(anything(), anything(), anything())).thenResolve();
318+
319+
// Act
320+
await selector.onKernelStarted(instance(mockKernel));
321+
322+
// Assert - verify initNotebookRunner was never called
323+
verify(mockInitNotebookRunner.runInitNotebookIfNeeded(anything(), anything(), anything())).never();
324+
});
325+
});
326+
327+
suite('ensureKernelSelected', () => {
328+
test('should return false when no environment ID is assigned to the notebook', async () => {
329+
// Mock environment mapper to return null (no environment assigned)
330+
when(mockNotebookEnvironmentMapper.getEnvironmentForNotebook(anything())).thenReturn(undefined);
331+
332+
// Stub ensureKernelSelectedWithConfiguration to track if it gets called
333+
const ensureKernelSelectedStub = sandbox.stub(selector, 'ensureKernelSelectedWithConfiguration').resolves();
334+
335+
// Mock commands.executeCommand
336+
when(mockedVSCodeNamespaces.commands.executeCommand(anything(), anything())).thenResolve();
337+
338+
// Act
339+
const result = await selector.ensureKernelSelected(
340+
mockNotebook,
341+
mockProgress,
342+
instance(mockCancellationToken)
343+
);
344+
345+
// Assert
346+
assert.strictEqual(result, false, 'Should return false when no environment is assigned');
347+
assert.strictEqual(
348+
ensureKernelSelectedStub.called,
349+
false,
350+
'ensureKernelSelectedWithConfiguration should not be called'
351+
);
352+
verify(mockNotebookEnvironmentMapper.getEnvironmentForNotebook(anything())).once();
353+
});
354+
355+
test('should return false and remove mapping when environment is not found', async () => {
356+
// Arrange
357+
const environmentId = 'missing-env-id';
358+
359+
// Mock environment mapper to return an ID
360+
when(mockNotebookEnvironmentMapper.getEnvironmentForNotebook(anything())).thenReturn(environmentId);
361+
362+
// Mock environment manager to return null (environment not found)
363+
when(mockEnvironmentManager.getEnvironment(environmentId)).thenReturn(undefined);
364+
365+
// Mock remove environment mapping
366+
when(mockNotebookEnvironmentMapper.removeEnvironmentForNotebook(anything())).thenResolve();
367+
368+
// Stub ensureKernelSelectedWithConfiguration to track if it gets called
369+
const ensureKernelSelectedStub = sandbox.stub(selector, 'ensureKernelSelectedWithConfiguration').resolves();
370+
371+
// Mock commands.executeCommand
372+
when(mockedVSCodeNamespaces.commands.executeCommand(anything(), anything())).thenResolve();
373+
374+
// Act
375+
const result = await selector.ensureKernelSelected(
376+
mockNotebook,
377+
mockProgress,
378+
instance(mockCancellationToken)
379+
);
380+
381+
// Assert
382+
assert.strictEqual(result, false, 'Should return false when environment is not found');
383+
assert.strictEqual(
384+
ensureKernelSelectedStub.called,
385+
false,
386+
'ensureKernelSelectedWithConfiguration should not be called'
387+
);
388+
verify(mockNotebookEnvironmentMapper.getEnvironmentForNotebook(anything())).once();
389+
verify(mockEnvironmentManager.getEnvironment(environmentId)).once();
390+
verify(mockNotebookEnvironmentMapper.removeEnvironmentForNotebook(anything())).once();
391+
});
392+
393+
test('should return true and call ensureKernelSelectedWithConfiguration when environment is found', async () => {
394+
// Arrange
395+
const baseFileUri = mockNotebook.uri.with({ query: '', fragment: '' });
396+
const notebookKey = mockNotebook.uri.toString();
397+
const projectKey = baseFileUri.fsPath;
398+
const environmentId = 'test-env-id';
399+
const mockEnvironment = createMockEnvironment(environmentId, 'Test Environment');
400+
401+
// Mock environment mapper to return an ID
402+
when(mockNotebookEnvironmentMapper.getEnvironmentForNotebook(anything())).thenReturn(environmentId);
403+
404+
// Mock environment manager to return the environment
405+
when(mockEnvironmentManager.getEnvironment(environmentId)).thenReturn(mockEnvironment);
406+
407+
// Stub ensureKernelSelectedWithConfiguration to track calls
408+
const ensureKernelSelectedStub = sandbox.stub(selector, 'ensureKernelSelectedWithConfiguration').resolves();
409+
410+
// Mock commands.executeCommand
411+
when(mockedVSCodeNamespaces.commands.executeCommand(anything(), anything())).thenResolve();
412+
413+
// Act
414+
const result = await selector.ensureKernelSelected(
415+
mockNotebook,
416+
mockProgress,
417+
instance(mockCancellationToken)
418+
);
419+
420+
// Assert
421+
assert.strictEqual(result, true, 'Should return true when environment is found');
422+
assert.strictEqual(
423+
ensureKernelSelectedStub.calledOnce,
424+
true,
425+
'ensureKernelSelectedWithConfiguration should be called once'
426+
);
427+
428+
// Verify it was called with correct arguments
429+
const callArgs = ensureKernelSelectedStub.firstCall.args;
430+
assert.strictEqual(callArgs[0], mockNotebook, 'First arg should be notebook');
431+
assert.strictEqual(callArgs[1], mockEnvironment, 'Second arg should be environment');
432+
assert.strictEqual(callArgs[2].toString(), baseFileUri.toString(), 'Third arg should be baseFileUri');
433+
assert.strictEqual(callArgs[3], notebookKey, 'Fourth arg should be notebookKey');
434+
assert.strictEqual(callArgs[4], projectKey, 'Fifth arg should be projectKey');
435+
assert.strictEqual(callArgs[5], mockProgress, 'Sixth arg should be progress');
436+
assert.strictEqual(callArgs[6], instance(mockCancellationToken), 'Seventh arg should be token');
437+
438+
verify(mockNotebookEnvironmentMapper.getEnvironmentForNotebook(anything())).once();
439+
verify(mockEnvironmentManager.getEnvironment(environmentId)).once();
440+
});
441+
});
442+
278443
// Priority 1 Tests - Critical for environment switching
279444
// UT-4: Configuration Refresh After startServer
280445
suite('Priority 1: Configuration Refresh (UT-4)', () => {

0 commit comments

Comments
 (0)