@@ -2,11 +2,14 @@ import { assert, use } from 'chai';
22import chaiAsPromised from 'chai-as-promised' ;
33import { anything , instance , mock , when , verify } from 'ts-mockito' ;
44import { Uri } from 'vscode' ;
5+ import * as fs from 'fs' ;
6+ import * as os from 'os' ;
57import { DeepnoteEnvironmentManager } from './deepnoteEnvironmentManager.node' ;
68import { DeepnoteEnvironmentStorage } from './deepnoteEnvironmentStorage.node' ;
79import { IExtensionContext , IOutputChannel } from '../../../platform/common/types' ;
810import { IDeepnoteServerStarter } from '../types' ;
911import { PythonEnvironment } from '../../../platform/pythonEnvironments/info' ;
12+ import { IFileSystem } from '../../../platform/common/platform/types' ;
1013
1114use ( chaiAsPromised ) ;
1215
@@ -16,6 +19,8 @@ suite('DeepnoteEnvironmentManager', () => {
1619 let mockStorage : DeepnoteEnvironmentStorage ;
1720 let mockServerStarter : IDeepnoteServerStarter ;
1821 let mockOutputChannel : IOutputChannel ;
22+ let mockFileSystem : IFileSystem ;
23+ let testGlobalStoragePath : string ;
1924
2025 const testInterpreter : PythonEnvironment = {
2126 id : 'test-python-id' ,
@@ -28,18 +33,39 @@ suite('DeepnoteEnvironmentManager', () => {
2833 mockStorage = mock < DeepnoteEnvironmentStorage > ( ) ;
2934 mockServerStarter = mock < IDeepnoteServerStarter > ( ) ;
3035 mockOutputChannel = mock < IOutputChannel > ( ) ;
36+ mockFileSystem = mock < IFileSystem > ( ) ;
3137
32- when ( mockContext . globalStorageUri ) . thenReturn ( Uri . file ( '/global/storage' ) ) ;
38+ // Create a temporary directory for test storage
39+ testGlobalStoragePath = fs . mkdtempSync ( `${ os . tmpdir ( ) } /deepnote-test-` ) ;
40+
41+ when ( mockContext . globalStorageUri ) . thenReturn ( Uri . file ( testGlobalStoragePath ) ) ;
3342 when ( mockStorage . loadEnvironments ( ) ) . thenResolve ( [ ] ) ;
3443
44+ // Configure mockFileSystem to actually delete directories for testing
45+ when ( mockFileSystem . delete ( anything ( ) ) ) . thenCall ( ( uri : Uri ) => {
46+ const dirPath = uri . fsPath ;
47+ if ( fs . existsSync ( dirPath ) ) {
48+ fs . rmSync ( dirPath , { recursive : true , force : true } ) ;
49+ }
50+ return Promise . resolve ( ) ;
51+ } ) ;
52+
3553 manager = new DeepnoteEnvironmentManager (
3654 instance ( mockContext ) ,
3755 instance ( mockStorage ) ,
3856 instance ( mockServerStarter ) ,
39- instance ( mockOutputChannel )
57+ instance ( mockOutputChannel ) ,
58+ instance ( mockFileSystem )
4059 ) ;
4160 } ) ;
4261
62+ teardown ( ( ) => {
63+ // Clean up the temporary directory after each test
64+ if ( testGlobalStoragePath && fs . existsSync ( testGlobalStoragePath ) ) {
65+ fs . rmSync ( testGlobalStoragePath , { recursive : true , force : true } ) ;
66+ }
67+ } ) ;
68+
4369 suite ( 'activate' , ( ) => {
4470 test ( 'should load environments on activation' , async ( ) => {
4571 const existingConfigs = [
@@ -235,6 +261,32 @@ suite('DeepnoteEnvironmentManager', () => {
235261 test ( 'should throw error for non-existent environment' , async ( ) => {
236262 await assert . isRejected ( manager . deleteEnvironment ( 'non-existent' ) , 'Environment not found: non-existent' ) ;
237263 } ) ;
264+
265+ test ( 'should delete virtual environment directory from disk' , async ( ) => {
266+ when ( mockStorage . saveEnvironments ( anything ( ) ) ) . thenResolve ( ) ;
267+
268+ const config = await manager . createEnvironment ( {
269+ name : 'Test' ,
270+ pythonInterpreter : testInterpreter
271+ } ) ;
272+
273+ // Create the virtual environment directory to simulate it existing
274+ const venvDirPath = config . venvPath . fsPath ;
275+ fs . mkdirSync ( venvDirPath , { recursive : true } ) ;
276+
277+ // Create a dummy file inside to make it a "real" directory
278+ fs . writeFileSync ( `${ venvDirPath } /test.txt` , 'test content' ) ;
279+
280+ // Verify directory and file exist before deletion
281+ assert . isTrue ( fs . existsSync ( venvDirPath ) , 'Directory should exist before deletion' ) ;
282+ assert . isTrue ( fs . existsSync ( `${ venvDirPath } /test.txt` ) , 'File should exist before deletion' ) ;
283+
284+ // Delete the environment
285+ await manager . deleteEnvironment ( config . id ) ;
286+
287+ // Verify directory no longer exists
288+ assert . isFalse ( fs . existsSync ( venvDirPath ) , 'Directory should not exist after deletion' ) ;
289+ } ) ;
238290 } ) ;
239291
240292 suite ( 'updateLastUsed' , ( ) => {
0 commit comments