33
44import { Uri } from 'vscode' ;
55import * as path from 'path' ;
6+ import * as net from 'net' ;
67import { IConfigurationService , ITestOutputChannel } from '../../../common/types' ;
78import { createDeferred , Deferred } from '../../../common/utils/async' ;
8- import { traceVerbose } from '../../../logging' ;
9+ import { traceLog , traceVerbose } from '../../../logging' ;
910import { DataReceivedEvent , ExecutionTestPayload , ITestExecutionAdapter , ITestServer } from '../common/types' ;
1011import {
1112 ExecutionFactoryCreateWithEnvironmentOptions ,
@@ -90,6 +91,7 @@ export class PytestTestExecutionAdapter implements ITestExecutionAdapter {
9091 TEST_PORT : this . testServer . getPort ( ) . toString ( ) ,
9192 } ,
9293 outputChannel : this . outputChannel ,
94+ stdinStr : testIds . toString ( ) ,
9395 } ;
9496
9597 // Create the Python environment in which to execute the command.
@@ -114,7 +116,48 @@ export class PytestTestExecutionAdapter implements ITestExecutionAdapter {
114116 if ( debugBool && ! testArgs . some ( ( a ) => a . startsWith ( '--capture' ) || a === '-s' ) ) {
115117 testArgs . push ( '--capture' , 'no' ) ;
116118 }
117- const pluginArgs = [ '-p' , 'vscode_pytest' , '-v' ] . concat ( testArgs ) . concat ( testIds ) ;
119+ const pluginArgs = [ '-p' , 'vscode_pytest' ] . concat ( testArgs ) . concat ( testIds ) ;
120+ const scriptPath = path . join ( fullPluginPath , 'vscode_pytest' , 'run_pytest_script.py' ) ;
121+ const runArgs = [ scriptPath , ...testArgs ] ;
122+
123+ const testData = JSON . stringify ( testIds ) ;
124+ const headers = [ `Content-Length: ${ Buffer . byteLength ( testData ) } ` , 'Content-Type: application/json' ] ;
125+ const payload = `${ headers . join ( '\r\n' ) } \r\n\r\n${ testData } ` ;
126+
127+ const startServer = ( ) : Promise < number > =>
128+ new Promise ( ( resolve , reject ) => {
129+ const server = net . createServer ( ( socket : net . Socket ) => {
130+ socket . on ( 'end' , ( ) => {
131+ traceLog ( 'Client disconnected' ) ;
132+ } ) ;
133+ } ) ;
134+
135+ server . listen ( 0 , ( ) => {
136+ const { port } = server . address ( ) as net . AddressInfo ;
137+ traceLog ( `Server listening on port ${ port } ` ) ;
138+ resolve ( port ) ;
139+ } ) ;
140+
141+ server . on ( 'error' , ( error : Error ) => {
142+ reject ( error ) ;
143+ } ) ;
144+ server . on ( 'connection' , ( socket : net . Socket ) => {
145+ socket . write ( payload ) ;
146+ traceLog ( 'payload sent' , payload ) ;
147+ } ) ;
148+ } ) ;
149+
150+ // Start the server and wait until it is listening
151+ await startServer ( )
152+ . then ( ( assignedPort ) => {
153+ traceLog ( `Server started and listening on port ${ assignedPort } ` ) ;
154+ if ( spawnOptions . extraVariables )
155+ spawnOptions . extraVariables . RUN_TEST_IDS_PORT = assignedPort . toString ( ) ;
156+ } )
157+ . catch ( ( error ) => {
158+ console . error ( 'Error starting server:' , error ) ;
159+ } ) ;
160+
118161 if ( debugBool ) {
119162 const pytestPort = this . testServer . getPort ( ) . toString ( ) ;
120163 const pytestUUID = uuid . toString ( ) ;
@@ -129,9 +172,10 @@ export class PytestTestExecutionAdapter implements ITestExecutionAdapter {
129172 console . debug ( `Running debug test with arguments: ${ pluginArgs . join ( ' ' ) } \r\n` ) ;
130173 await debugLauncher ! . launchDebugger ( launchOptions ) ;
131174 } else {
132- const runArgs = [ '-m' , 'pytest' ] . concat ( pluginArgs ) ;
133- console . debug ( `Running test with arguments: ${ runArgs . join ( ' ' ) } \r\n` ) ;
134- execService ?. exec ( runArgs , spawnOptions ) ;
175+ await execService ?. exec ( runArgs , spawnOptions ) . catch ( ( ex ) => {
176+ console . debug ( `Error while running tests: ${ testIds } \r\n${ ex } \r\n\r\n` ) ;
177+ return Promise . reject ( ex ) ;
178+ } ) ;
135179 }
136180 } catch ( ex ) {
137181 console . debug ( `Error while running tests: ${ testIds } \r\n${ ex } \r\n\r\n` ) ;
0 commit comments