@@ -6,6 +6,7 @@ import * as typeMoq from 'typemoq';
6
6
import * as path from 'path' ;
7
7
import * as assert from 'assert' ;
8
8
import * as fs from 'fs' ;
9
+ import * as os from 'os' ;
9
10
import { PytestTestDiscoveryAdapter } from '../../../client/testing/testController/pytest/pytestDiscoveryAdapter' ;
10
11
import { ITestController , ITestResultResolver } from '../../../client/testing/testController/common/types' ;
11
12
import { IPythonExecutionFactory } from '../../../client/common/process/types' ;
@@ -62,6 +63,13 @@ suite('End to End Tests: test adapters', () => {
62
63
'testTestingRootWkspc' ,
63
64
'symlinkWorkspace' ,
64
65
) ;
66
+ const nestedTarget = path . join ( EXTENSION_ROOT_DIR_FOR_TESTS , 'src' , 'testTestingRootWkspc' , 'target workspace' ) ;
67
+ const nestedSymlink = path . join (
68
+ EXTENSION_ROOT_DIR_FOR_TESTS ,
69
+ 'src' ,
70
+ 'testTestingRootWkspc' ,
71
+ 'symlink_parent-folder' ,
72
+ ) ;
65
73
suiteSetup ( async ( ) => {
66
74
serviceContainer = ( await initialize ( ) ) . serviceContainer ;
67
75
@@ -73,7 +81,14 @@ suite('End to End Tests: test adapters', () => {
73
81
if ( err ) {
74
82
traceError ( err ) ;
75
83
} else {
76
- traceLog ( 'Symlink created successfully for end to end tests.' ) ;
84
+ traceLog ( 'Symlink created successfully for regular symlink end to end tests.' ) ;
85
+ }
86
+ } ) ;
87
+ fs . symlink ( nestedTarget , nestedSymlink , 'dir' , ( err ) => {
88
+ if ( err ) {
89
+ traceError ( err ) ;
90
+ } else {
91
+ traceLog ( 'Symlink created successfully for nested symlink end to end tests.' ) ;
77
92
}
78
93
} ) ;
79
94
} catch ( err ) {
@@ -116,11 +131,23 @@ suite('End to End Tests: test adapters', () => {
116
131
if ( err ) {
117
132
traceError ( err ) ;
118
133
} else {
119
- traceLog ( 'Symlink removed successfully after tests.' ) ;
134
+ traceLog ( 'Symlink removed successfully after tests, rootPathDiscoverySymlink.' ) ;
135
+ }
136
+ } ) ;
137
+ } else {
138
+ traceLog ( 'Symlink was not found to remove after tests, exiting successfully, rootPathDiscoverySymlink.' ) ;
139
+ }
140
+
141
+ if ( fs . existsSync ( nestedSymlink ) ) {
142
+ fs . unlink ( nestedSymlink , ( err ) => {
143
+ if ( err ) {
144
+ traceError ( err ) ;
145
+ } else {
146
+ traceLog ( 'Symlink removed successfully after tests, nestedSymlink.' ) ;
120
147
}
121
148
} ) ;
122
149
} else {
123
- traceLog ( 'Symlink was not found to remove after tests, exiting successfully' ) ;
150
+ traceLog ( 'Symlink was not found to remove after tests, exiting successfully, nestedSymlink. ' ) ;
124
151
}
125
152
} ) ;
126
153
test ( 'unittest discovery adapter small workspace' , async ( ) => {
@@ -256,7 +283,103 @@ suite('End to End Tests: test adapters', () => {
256
283
assert . strictEqual ( callCount , 1 , 'Expected _resolveDiscovery to be called once' ) ;
257
284
} ) ;
258
285
} ) ;
286
+ test ( 'pytest discovery adapter nested symlink' , async ( ) => {
287
+ if ( os . platform ( ) === 'win32' ) {
288
+ console . log ( 'Skipping test for windows' ) ;
289
+ return ;
290
+ }
291
+
292
+ // result resolver and saved data for assertions
293
+ let actualData : {
294
+ cwd : string ;
295
+ tests ?: unknown ;
296
+ status : 'success' | 'error' ;
297
+ error ?: string [ ] ;
298
+ } ;
299
+ // set workspace to test workspace folder
300
+ const workspacePath = path . join ( nestedSymlink , 'custom_sub_folder' ) ;
301
+ const workspacePathParent = nestedSymlink ;
302
+ workspaceUri = Uri . parse ( workspacePath ) ;
303
+ const filePath = path . join ( workspacePath , 'test_simple.py' ) ;
304
+ const stats = fs . lstatSync ( workspacePathParent ) ;
305
+
306
+ // confirm that the path is a symbolic link
307
+ assert . ok ( stats . isSymbolicLink ( ) , 'The PARENT path is not a symbolic link but must be for this test.' ) ;
308
+
309
+ resultResolver = new PythonResultResolver ( testController , pytestProvider , workspaceUri ) ;
310
+ let callCount = 0 ;
311
+ resultResolver . _resolveDiscovery = async ( payload , _token ?) => {
312
+ traceLog ( `resolveDiscovery ${ payload } ` ) ;
313
+ callCount = callCount + 1 ;
314
+ actualData = payload ;
315
+ return Promise . resolve ( ) ;
316
+ } ;
317
+ // run pytest discovery
318
+ const discoveryAdapter = new PytestTestDiscoveryAdapter (
319
+ configService ,
320
+ testOutputChannel . object ,
321
+ resultResolver ,
322
+ envVarsService ,
323
+ ) ;
324
+ configService . getSettings ( workspaceUri ) . testing . pytestArgs = [ ] ;
325
+
326
+ await discoveryAdapter . discoverTests ( workspaceUri , pythonExecFactory ) . finally ( ( ) => {
327
+ // verification after discovery is complete
328
+
329
+ // 1. Check the status is "success"
330
+ assert . strictEqual (
331
+ actualData . status ,
332
+ 'success' ,
333
+ `Expected status to be 'success' instead status is ${ actualData . status } ` ,
334
+ ) ; // 2. Confirm no errors
335
+ assert . strictEqual ( actualData . error ?. length , 0 , "Expected no errors in 'error' field" ) ;
336
+ // 3. Confirm tests are found
337
+ assert . ok ( actualData . tests , 'Expected tests to be present' ) ;
338
+ // 4. Confirm that the cwd returned is the symlink path and the test's path is also using the symlink as the root
339
+ if ( process . platform === 'win32' ) {
340
+ // covert string to lowercase for windows as the path is case insensitive
341
+ traceLog ( 'windows machine detected, converting path to lowercase for comparison' ) ;
342
+ const a = actualData . cwd . toLowerCase ( ) ;
343
+ const b = filePath . toLowerCase ( ) ;
344
+ const testSimpleActual = ( actualData . tests as {
345
+ children : {
346
+ path : string ;
347
+ } [ ] ;
348
+ } ) . children [ 0 ] . path . toLowerCase ( ) ;
349
+ const testSimpleExpected = filePath . toLowerCase ( ) ;
350
+ assert . strictEqual ( a , b , `Expected cwd to be the symlink path actual: ${ a } expected: ${ b } ` ) ;
351
+ assert . strictEqual (
352
+ testSimpleActual ,
353
+ testSimpleExpected ,
354
+ `Expected test path to be the symlink path actual: ${ testSimpleActual } expected: ${ testSimpleExpected } ` ,
355
+ ) ;
356
+ } else {
357
+ assert . strictEqual (
358
+ path . join ( actualData . cwd ) ,
359
+ path . join ( workspacePath ) ,
360
+ 'Expected cwd to be the symlink path, check for non-windows machines' ,
361
+ ) ;
362
+ assert . strictEqual (
363
+ ( actualData . tests as {
364
+ children : {
365
+ path : string ;
366
+ } [ ] ;
367
+ } ) . children [ 0 ] . path ,
368
+ filePath ,
369
+ 'Expected test path to be the symlink path, check for non windows machines' ,
370
+ ) ;
371
+ }
372
+
373
+ // 5. Confirm that resolveDiscovery was called once
374
+ assert . strictEqual ( callCount , 1 , 'Expected _resolveDiscovery to be called once' ) ;
375
+ } ) ;
376
+ } ) ;
259
377
test ( 'pytest discovery adapter small workspace with symlink' , async ( ) => {
378
+ if ( os . platform ( ) === 'win32' ) {
379
+ console . log ( 'Skipping test for windows' ) ;
380
+ return ;
381
+ }
382
+
260
383
// result resolver and saved data for assertions
261
384
let actualData : {
262
385
cwd : string ;
0 commit comments