88import { ChildProcess , spawn } from 'child_process' ;
99import * as getFreePort from 'get-port' ;
1010import * as path from 'path' ;
11+ import * as TypeMoq from 'typemoq' ;
12+ import { DebugConfiguration , Uri } from 'vscode' ;
1113import { DebugClient } from 'vscode-debugadapter-testsupport' ;
1214import { EXTENSION_ROOT_DIR } from '../../client/common/constants' ;
1315import '../../client/common/extensions' ;
16+ import { IS_WINDOWS } from '../../client/common/platform/constants' ;
17+ import { IPlatformService } from '../../client/common/platform/types' ;
18+ import { PythonV2DebugConfigurationProvider } from '../../client/debugger' ;
1419import { PTVSD_PATH } from '../../client/debugger/Common/constants' ;
15- import { DebugOptions } from '../../client/debugger/Common/Contracts' ;
20+ import { AttachRequestArguments , DebugOptions } from '../../client/debugger/Common/Contracts' ;
21+ import { IServiceContainer } from '../../client/ioc/types' ;
1622import { sleep } from '../common' ;
17- import { initialize , IS_APPVEYOR , IS_MULTI_ROOT_TEST , TEST_DEBUGGER } from '../initialize' ;
23+ import { initialize , IS_MULTI_ROOT_TEST , TEST_DEBUGGER } from '../initialize' ;
1824import { continueDebugging , createDebugAdapter } from './utils' ;
1925
2026const fileToDebug = path . join ( EXTENSION_ROOT_DIR , 'src' , 'testMultiRootWkspc' , 'workspace5' , 'remoteDebugger-start-with-ptvsd.py' ) ;
2127
2228suite ( 'Attach Debugger - Experimental' , ( ) => {
2329 let debugClient : DebugClient ;
24- let procToKill : ChildProcess ;
30+ let proc : ChildProcess ;
2531 suiteSetup ( initialize ) ;
2632
2733 setup ( async function ( ) {
2834 if ( ! IS_MULTI_ROOT_TEST || ! TEST_DEBUGGER ) {
2935 this . skip ( ) ;
3036 }
37+ this . timeout ( 30000 ) ;
3138 const coverageDirectory = path . join ( EXTENSION_ROOT_DIR , 'debug_coverage_attach_ptvsd' ) ;
3239 debugClient = await createDebugAdapter ( coverageDirectory ) ;
3340 } ) ;
@@ -37,27 +44,23 @@ suite('Attach Debugger - Experimental', () => {
3744 try {
3845 await debugClient . stop ( ) . catch ( ( ) => { } ) ;
3946 } catch ( ex ) { }
40- if ( procToKill ) {
47+ if ( proc ) {
4148 try {
42- procToKill . kill ( ) ;
49+ proc . kill ( ) ;
4350 } catch { }
4451 }
4552 } ) ;
46- test ( 'Confirm we are able to attach to a running program' , async function ( ) {
47- this . timeout ( 20000 ) ;
48- // Lets skip this test on AppVeyor (very flaky on AppVeyor).
49- if ( IS_APPVEYOR ) {
50- return ;
51- }
52-
53+ async function testAttachingToRemoteProcess ( localRoot : string , remoteRoot : string , isLocalHostWindows : boolean ) {
54+ const localHostPathSeparator = isLocalHostWindows ? '\\' : '/' ;
5355 const port = await getFreePort ( { host : 'localhost' , port : 3000 } ) ;
54- const customEnv = { ...process . env } ;
56+ const env = { ...process . env } ;
5557
5658 // Set the path for PTVSD to be picked up.
5759 // tslint:disable-next-line:no-string-literal
58- customEnv [ 'PYTHONPATH' ] = PTVSD_PATH ;
60+ env [ 'PYTHONPATH' ] = PTVSD_PATH ;
5961 const pythonArgs = [ '-m' , 'ptvsd' , '--server' , '--port' , `${ port } ` , '--file' , fileToDebug . fileToCommandArgument ( ) ] ;
60- procToKill = spawn ( 'python' , pythonArgs , { env : customEnv , cwd : path . dirname ( fileToDebug ) } ) ;
62+ proc = spawn ( 'python' , pythonArgs , { env : env , cwd : path . dirname ( fileToDebug ) } ) ;
63+ await sleep ( 3000 ) ;
6164
6265 // Send initialize, attach
6366 const initializePromise = debugClient . initializeRequest ( {
@@ -69,15 +72,25 @@ suite('Attach Debugger - Experimental', () => {
6972 supportsVariableType : true ,
7073 supportsVariablePaging : true
7174 } ) ;
72- const attachPromise = debugClient . attachRequest ( {
73- localRoot : path . dirname ( fileToDebug ) ,
74- remoteRoot : path . dirname ( fileToDebug ) ,
75+ const options : AttachRequestArguments & DebugConfiguration = {
76+ name : 'attach' ,
77+ request : 'attach' ,
78+ localRoot,
79+ remoteRoot,
7580 type : 'pythonExperimental' ,
7681 port : port ,
7782 host : 'localhost' ,
78- logToFile : false ,
83+ logToFile : true ,
7984 debugOptions : [ DebugOptions . RedirectOutput ]
80- } ) ;
85+ } ;
86+ const platformService = TypeMoq . Mock . ofType < IPlatformService > ( ) ;
87+ platformService . setup ( p => p . isWindows ) . returns ( ( ) => isLocalHostWindows ) ;
88+ const serviceContainer = TypeMoq . Mock . ofType < IServiceContainer > ( ) ;
89+ serviceContainer . setup ( c => c . get ( IPlatformService , TypeMoq . It . isAny ( ) ) ) . returns ( ( ) => platformService . object ) ;
90+ const configProvider = new PythonV2DebugConfigurationProvider ( serviceContainer . object ) ;
91+
92+ await configProvider . resolveDebugConfiguration ( { index : 0 , name : 'root' , uri : Uri . file ( localRoot ) } , options ) ;
93+ const attachPromise = debugClient . attachRequest ( options ) ;
8194
8295 await Promise . all ( [
8396 initializePromise ,
@@ -90,7 +103,9 @@ suite('Attach Debugger - Experimental', () => {
90103 const stdOutPromise = debugClient . assertOutput ( 'stdout' , 'this is stdout' ) ;
91104 const stdErrPromise = debugClient . assertOutput ( 'stderr' , 'this is stderr' ) ;
92105
93- const breakpointLocation = { path : fileToDebug , column : 1 , line : 12 } ;
106+ // Don't use path utils, as we're building the paths manually (mimic windows paths on unix test servers and vice versa).
107+ const localFileName = `${ localRoot } ${ localHostPathSeparator } ${ path . basename ( fileToDebug ) } ` ;
108+ const breakpointLocation = { path : localFileName , column : 1 , line : 12 } ;
94109 const breakpointPromise = debugClient . setBreakpointsRequest ( {
95110 lines : [ breakpointLocation . line ] ,
96111 breakpoints : [ { line : breakpointLocation . line , column : breakpointLocation . column } ] ,
@@ -111,5 +126,14 @@ suite('Attach Debugger - Experimental', () => {
111126 debugClient . waitForEvent ( 'exited' ) ,
112127 debugClient . waitForEvent ( 'terminated' )
113128 ] ) ;
129+ }
130+ test ( 'Confirm we are able to attach to a running program' , async ( ) => {
131+ await testAttachingToRemoteProcess ( path . dirname ( fileToDebug ) , path . dirname ( fileToDebug ) , IS_WINDOWS ) ;
132+ } ) ;
133+ test ( 'Confirm local and remote paths are translated' , async ( ) => {
134+ // If tests are running on windows, then treat debug client as a unix client and remote process as current OS.
135+ const isLocalHostWindows = ! IS_WINDOWS ;
136+ const localWorkspace = isLocalHostWindows ? 'C:\\Project\\src' : '/home/user/Desktop/project/src' ;
137+ await testAttachingToRemoteProcess ( localWorkspace , path . dirname ( fileToDebug ) , isLocalHostWindows ) ;
114138 } ) ;
115139} ) ;
0 commit comments