diff --git a/src/client/testing/testController/common/utils.ts b/src/client/testing/testController/common/utils.ts index 9d426dc60ffa..232aaccd5341 100644 --- a/src/client/testing/testController/common/utils.ts +++ b/src/client/testing/testController/common/utils.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. import * as net from 'net'; -import { traceLog } from '../../../logging'; +import { traceError, traceLog, traceVerbose } from '../../../logging'; import { EnableTestAdapterRewrite } from '../../../common/experiments/groups'; import { IExperimentService } from '../../../common/types'; @@ -62,38 +62,52 @@ export function pythonTestAdapterRewriteEnabled(serviceContainer: IServiceContai return experiment.inExperimentSync(EnableTestAdapterRewrite.experiment); } -export const startTestIdServer = (testIds: string[]): Promise => - new Promise((resolve, reject) => { - const server = net.createServer((socket: net.Socket) => { - // Convert the test_ids array to JSON - const testData = JSON.stringify(testIds); +export async function startTestIdServer(testIds: string[]): Promise { + const startServer = (): Promise => + new Promise((resolve, reject) => { + const server = net.createServer((socket: net.Socket) => { + // Convert the test_ids array to JSON + const testData = JSON.stringify(testIds); - // Create the headers - const headers = [`Content-Length: ${Buffer.byteLength(testData)}`, 'Content-Type: application/json']; + // Create the headers + const headers = [`Content-Length: ${Buffer.byteLength(testData)}`, 'Content-Type: application/json']; - // Create the payload by concatenating the headers and the test data - const payload = `${headers.join('\r\n')}\r\n\r\n${testData}`; + // Create the payload by concatenating the headers and the test data + const payload = `${headers.join('\r\n')}\r\n\r\n${testData}`; - // Send the payload to the socket - socket.write(payload); + // Send the payload to the socket + socket.write(payload); - // Handle socket events - socket.on('data', (data) => { - traceLog('Received data:', data.toString()); + // Handle socket events + socket.on('data', (data) => { + traceLog('Received data:', data.toString()); + }); + + socket.on('end', () => { + traceLog('Client disconnected'); + }); }); - socket.on('end', () => { - traceLog('Client disconnected'); + server.listen(0, () => { + const { port } = server.address() as net.AddressInfo; + traceLog(`Server listening on port ${port}`); + resolve(port); }); - }); - server.listen(0, () => { - const { port } = server.address() as net.AddressInfo; - traceLog(`Server listening on port ${port}`); - resolve(port); + server.on('error', (error: Error) => { + reject(error); + }); }); - server.on('error', (error: Error) => { - reject(error); + // Start the server and wait until it is listening + await startServer() + .then((assignedPort) => { + traceVerbose(`Server started for pytest test ids server and listening on port ${assignedPort}`); + return assignedPort; + // if (spawnOptions.extraVariables) spawnOptions.extraVariables.RUN_TEST_IDS_PORT = pytestRunTestIdsPort; + }) + .catch((error) => { + traceError('Error starting server for pytest test ids server:', error); }); - }); + return 0; +} diff --git a/src/client/testing/testController/pytest/pytestExecutionAdapter.ts b/src/client/testing/testController/pytest/pytestExecutionAdapter.ts index 9c8a42ae097f..1bf032b9b594 100644 --- a/src/client/testing/testController/pytest/pytestExecutionAdapter.ts +++ b/src/client/testing/testController/pytest/pytestExecutionAdapter.ts @@ -118,17 +118,9 @@ export class PytestTestExecutionAdapter implements ITestExecutionAdapter { } traceLog(`Running PYTEST execution for the following test ids: ${testIds}`); - let pytestRunTestIdsPort: string | undefined; - await startTestIdServer(testIds) - .then((assignedPort) => { - traceVerbose(`Server started for pytest test ids server and listening on port ${assignedPort}`); - pytestRunTestIdsPort = assignedPort.toString(); - if (spawnOptions.extraVariables) - spawnOptions.extraVariables.RUN_TEST_IDS_PORT = pytestRunTestIdsPort; - }) - .catch((error) => { - traceError('Error starting server for pytest test ids server:', error); - }); + const pytestRunTestIdsPort = await startTestIdServer(testIds); + if (spawnOptions.extraVariables) + spawnOptions.extraVariables.RUN_TEST_IDS_PORT = pytestRunTestIdsPort.toString(); if (debugBool) { const pytestPort = this.testServer.getPort().toString(); @@ -140,7 +132,7 @@ export class PytestTestExecutionAdapter implements ITestExecutionAdapter { testProvider: PYTEST_PROVIDER, pytestPort, pytestUUID, - runTestIdsPort: pytestRunTestIdsPort, + runTestIdsPort: pytestRunTestIdsPort.toString(), }; traceInfo(`Running DEBUG pytest with arguments: ${testArgs.join(' ')}\r\n`); await debugLauncher!.launchDebugger(launchOptions, () => { diff --git a/src/client/testing/testController/unittest/testExecutionAdapter.ts b/src/client/testing/testController/unittest/testExecutionAdapter.ts index a85490c30bc8..d43832e36a1c 100644 --- a/src/client/testing/testController/unittest/testExecutionAdapter.ts +++ b/src/client/testing/testController/unittest/testExecutionAdapter.ts @@ -15,7 +15,7 @@ import { TestCommandOptions, TestExecutionCommand, } from '../common/types'; -import { traceLog, traceError } from '../../../logging'; +import { traceLog } from '../../../logging'; import { startTestIdServer } from '../common/utils'; /** @@ -77,19 +77,9 @@ export class UnittestTestExecutionAdapter implements ITestExecutionAdapter { this.promiseMap.set(uuid, deferred); traceLog(`Running UNITTEST execution for the following test ids: ${testIds}`); - let runTestIdsPort: string | undefined; - await startTestIdServer(testIds) - .then((assignedPort) => { - traceLog(`Server started and listening on port ${assignedPort}`); - runTestIdsPort = assignedPort.toString(); - // Send test command to server. - // Server fire onDataReceived event once it gets response. - }) - .catch((error) => { - traceError('Error starting server:', error); - }); + const runTestIdsPort = await startTestIdServer(testIds); - await this.testServer.sendCommand(options, runTestIdsPort, () => { + await this.testServer.sendCommand(options, runTestIdsPort.toString(), () => { // disposable.dispose(); deferred.resolve(); }); diff --git a/src/test/testing/testController/pytest/pytestExecutionAdapter.unit.test.ts b/src/test/testing/testController/pytest/pytestExecutionAdapter.unit.test.ts index 5e7a32ddc9e1..f60429d38e5b 100644 --- a/src/test/testing/testController/pytest/pytestExecutionAdapter.unit.test.ts +++ b/src/test/testing/testController/pytest/pytestExecutionAdapter.unit.test.ts @@ -1,141 +1,152 @@ -// /* eslint-disable @typescript-eslint/no-explicit-any */ -// // Copyright (c) Microsoft Corporation. All rights reserved. -// // Licensed under the MIT License. -// import * as assert from 'assert'; -// import { TestRun, Uri } from 'vscode'; -// import * as typeMoq from 'typemoq'; -// import { IConfigurationService, ITestOutputChannel } from '../../../../client/common/types'; -// import { ITestServer } from '../../../../client/testing/testController/common/types'; -// import { -// IPythonExecutionFactory, -// IPythonExecutionService, -// SpawnOptions, -// } from '../../../../client/common/process/types'; -// import { createDeferred, Deferred } from '../../../../client/common/utils/async'; -// import { PytestTestExecutionAdapter } from '../../../../client/testing/testController/pytest/pytestExecutionAdapter'; -// import { ITestDebugLauncher, LaunchOptions } from '../../../../client/testing/common/types'; +/* eslint-disable @typescript-eslint/no-explicit-any */ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +import * as assert from 'assert'; +import { TestRun, Uri } from 'vscode'; +import * as typeMoq from 'typemoq'; +import * as sinon from 'sinon'; +import * as path from 'path'; +import { IConfigurationService, ITestOutputChannel } from '../../../../client/common/types'; +import { ITestServer } from '../../../../client/testing/testController/common/types'; +import { + IPythonExecutionFactory, + IPythonExecutionService, + SpawnOptions, +} from '../../../../client/common/process/types'; +import { createDeferred, Deferred } from '../../../../client/common/utils/async'; +import { PytestTestExecutionAdapter } from '../../../../client/testing/testController/pytest/pytestExecutionAdapter'; +import { ITestDebugLauncher, LaunchOptions } from '../../../../client/testing/common/types'; +import * as util from '../../../../client/testing/testController/common/utils'; +import { EXTENSION_ROOT_DIR } from '../../../../client/constants'; -// suite('pytest test execution adapter', () => { -// let testServer: typeMoq.IMock; -// let configService: IConfigurationService; -// let execFactory = typeMoq.Mock.ofType(); -// let adapter: PytestTestExecutionAdapter; -// let execService: typeMoq.IMock; -// let deferred: Deferred; -// let debugLauncher: typeMoq.IMock; -// setup(() => { -// testServer = typeMoq.Mock.ofType(); -// testServer.setup((t) => t.getPort()).returns(() => 12345); -// testServer -// .setup((t) => t.onRunDataReceived(typeMoq.It.isAny(), typeMoq.It.isAny())) -// .returns(() => ({ -// dispose: () => { -// /* no-body */ -// }, -// })); -// configService = ({ -// getSettings: () => ({ -// testing: { pytestArgs: ['.'] }, -// }), -// isTestExecution: () => false, -// } as unknown) as IConfigurationService; -// execFactory = typeMoq.Mock.ofType(); -// execService = typeMoq.Mock.ofType(); -// debugLauncher = typeMoq.Mock.ofType(); -// execFactory -// .setup((x) => x.createActivatedEnvironment(typeMoq.It.isAny())) -// .returns(() => Promise.resolve(execService.object)); -// deferred = createDeferred(); -// execService -// .setup((x) => x.exec(typeMoq.It.isAny(), typeMoq.It.isAny())) -// .returns(() => { -// deferred.resolve(); -// return Promise.resolve({ stdout: '{}' }); -// }); -// debugLauncher -// .setup((d) => d.launchDebugger(typeMoq.It.isAny(), typeMoq.It.isAny())) -// .returns(() => { -// deferred.resolve(); -// return Promise.resolve(); -// }); -// execFactory.setup((p) => ((p as unknown) as any).then).returns(() => undefined); -// execService.setup((p) => ((p as unknown) as any).then).returns(() => undefined); -// debugLauncher.setup((p) => ((p as unknown) as any).then).returns(() => undefined); -// }); -// test('pytest execution called with correct args', async () => { -// const uri = Uri.file('/my/test/path/'); -// const uuid = 'uuid123'; -// // const data = { status: 'success' }; -// testServer -// .setup((t) => t.onDiscoveryDataReceived(typeMoq.It.isAny(), typeMoq.It.isAny())) -// .returns(() => ({ -// dispose: () => { -// /* no-body */ -// }, -// })); -// testServer.setup((t) => t.createUUID(typeMoq.It.isAny())).returns(() => uuid); -// const outputChannel = typeMoq.Mock.ofType(); -// const testRun = typeMoq.Mock.ofType(); -// adapter = new PytestTestExecutionAdapter(testServer.object, configService, outputChannel.object); -// await adapter.runTests(uri, [], false, testRun.object, execFactory.object); +suite('pytest test execution adapter', () => { + let testServer: typeMoq.IMock; + let configService: IConfigurationService; + let execFactory = typeMoq.Mock.ofType(); + let adapter: PytestTestExecutionAdapter; + let execService: typeMoq.IMock; + let deferred: Deferred; + let debugLauncher: typeMoq.IMock; + (global as any).EXTENSION_ROOT_DIR = EXTENSION_ROOT_DIR; + let myTestPath: string; -// const expectedArgs = [ -// '/Users/eleanorboyd/vscode-python/pythonFiles/vscode_pytest/run_pytest_script.py', -// '--rootdir', -// '/my/test/path/', -// ]; -// const expectedExtraVariables = { -// PYTHONPATH: '/Users/eleanorboyd/vscode-python/pythonFiles', -// TEST_UUID: 'uuid123', -// TEST_PORT: '12345', -// }; -// execService.verify( -// (x) => -// x.exec( -// expectedArgs, -// typeMoq.It.is((options) => { -// assert.equal(options.extraVariables?.PYTHONPATH, expectedExtraVariables.PYTHONPATH); -// assert.equal(options.extraVariables?.TEST_UUID, expectedExtraVariables.TEST_UUID); -// assert.equal(options.extraVariables?.TEST_PORT, expectedExtraVariables.TEST_PORT); -// assert.strictEqual(typeof options.extraVariables?.RUN_TEST_IDS_PORT, 'string'); -// assert.equal(options.cwd, uri.fsPath); -// assert.equal(options.throwOnStdErr, true); -// return true; -// }), -// ), -// typeMoq.Times.once(), -// ); -// }); -// test('Debug launched correctly for pytest', async () => { -// const uri = Uri.file('/my/test/path/'); -// const uuid = 'uuid123'; -// testServer -// .setup((t) => t.onDiscoveryDataReceived(typeMoq.It.isAny(), typeMoq.It.isAny())) -// .returns(() => ({ -// dispose: () => { -// /* no-body */ -// }, -// })); -// testServer.setup((t) => t.createUUID(typeMoq.It.isAny())).returns(() => uuid); -// const outputChannel = typeMoq.Mock.ofType(); -// const testRun = typeMoq.Mock.ofType(); -// adapter = new PytestTestExecutionAdapter(testServer.object, configService, outputChannel.object); -// await adapter.runTests(uri, [], true, testRun.object, execFactory.object, debugLauncher.object); -// debugLauncher.verify( -// (x) => -// x.launchDebugger( -// typeMoq.It.is((launchOptions) => { -// assert.equal(launchOptions.cwd, uri.fsPath); -// assert.deepEqual(launchOptions.args, ['--rootdir', '/my/test/path/', '--capture', 'no']); -// assert.equal(launchOptions.testProvider, 'pytest'); -// assert.equal(launchOptions.pytestPort, '12345'); -// assert.equal(launchOptions.pytestUUID, 'uuid123'); -// assert.strictEqual(typeof launchOptions.runTestIdsPort, 'string'); -// return true; -// }), -// typeMoq.It.isAny(), -// ), -// typeMoq.Times.once(), -// ); -// }); -// }); + setup(() => { + testServer = typeMoq.Mock.ofType(); + testServer.setup((t) => t.getPort()).returns(() => 12345); + testServer + .setup((t) => t.onRunDataReceived(typeMoq.It.isAny(), typeMoq.It.isAny())) + .returns(() => ({ + dispose: () => { + /* no-body */ + }, + })); + configService = ({ + getSettings: () => ({ + testing: { pytestArgs: ['.'] }, + }), + isTestExecution: () => false, + } as unknown) as IConfigurationService; + execFactory = typeMoq.Mock.ofType(); + execService = typeMoq.Mock.ofType(); + debugLauncher = typeMoq.Mock.ofType(); + execFactory + .setup((x) => x.createActivatedEnvironment(typeMoq.It.isAny())) + .returns(() => Promise.resolve(execService.object)); + deferred = createDeferred(); + execService + .setup((x) => x.exec(typeMoq.It.isAny(), typeMoq.It.isAny())) + .returns(() => { + deferred.resolve(); + return Promise.resolve({ stdout: '{}' }); + }); + debugLauncher + .setup((d) => d.launchDebugger(typeMoq.It.isAny(), typeMoq.It.isAny())) + .returns(() => { + deferred.resolve(); + return Promise.resolve(); + }); + sinon.stub(util, 'startTestIdServer').returns(Promise.resolve(54321)); + + execFactory.setup((p) => ((p as unknown) as any).then).returns(() => undefined); + execService.setup((p) => ((p as unknown) as any).then).returns(() => undefined); + debugLauncher.setup((p) => ((p as unknown) as any).then).returns(() => undefined); + myTestPath = path.join('/', 'my', 'test', 'path', '/'); + }); + teardown(() => { + sinon.restore(); + }); + test('pytest execution called with correct args', async () => { + const uri = Uri.file(myTestPath); + const uuid = 'uuid123'; + testServer + .setup((t) => t.onDiscoveryDataReceived(typeMoq.It.isAny(), typeMoq.It.isAny())) + .returns(() => ({ + dispose: () => { + /* no-body */ + }, + })); + testServer.setup((t) => t.createUUID(typeMoq.It.isAny())).returns(() => uuid); + const outputChannel = typeMoq.Mock.ofType(); + const testRun = typeMoq.Mock.ofType(); + adapter = new PytestTestExecutionAdapter(testServer.object, configService, outputChannel.object); + await adapter.runTests(uri, [], false, testRun.object, execFactory.object); + + const pathToPythonFiles = path.join(EXTENSION_ROOT_DIR, 'pythonFiles'); + const pathToPythonScript = path.join(pathToPythonFiles, 'vscode_pytest', 'run_pytest_script.py'); + const expectedArgs = [pathToPythonScript, '--rootdir', myTestPath]; + const expectedExtraVariables = { + PYTHONPATH: pathToPythonFiles, + TEST_UUID: 'uuid123', + TEST_PORT: '12345', + }; + // execService.verify((x) => x.exec(expectedArgs, typeMoq.It.isAny()), typeMoq.Times.once()); + execService.verify( + (x) => + x.exec( + expectedArgs, + typeMoq.It.is((options) => { + assert.equal(options.extraVariables?.PYTHONPATH, expectedExtraVariables.PYTHONPATH); + assert.equal(options.extraVariables?.TEST_UUID, expectedExtraVariables.TEST_UUID); + assert.equal(options.extraVariables?.TEST_PORT, expectedExtraVariables.TEST_PORT); + assert.equal(options.extraVariables?.RUN_TEST_IDS_PORT, '54321'); + assert.equal(options.cwd, uri.fsPath); + assert.equal(options.throwOnStdErr, true); + return true; + }), + ), + typeMoq.Times.once(), + ); + }); + test('Debug launched correctly for pytest', async () => { + const uri = Uri.file(myTestPath); + const uuid = 'uuid123'; + testServer + .setup((t) => t.onDiscoveryDataReceived(typeMoq.It.isAny(), typeMoq.It.isAny())) + .returns(() => ({ + dispose: () => { + /* no-body */ + }, + })); + testServer.setup((t) => t.createUUID(typeMoq.It.isAny())).returns(() => uuid); + const outputChannel = typeMoq.Mock.ofType(); + const testRun = typeMoq.Mock.ofType(); + adapter = new PytestTestExecutionAdapter(testServer.object, configService, outputChannel.object); + await adapter.runTests(uri, [], true, testRun.object, execFactory.object, debugLauncher.object); + debugLauncher.verify( + (x) => + x.launchDebugger( + typeMoq.It.is((launchOptions) => { + assert.equal(launchOptions.cwd, uri.fsPath); + assert.deepEqual(launchOptions.args, ['--rootdir', myTestPath, '--capture', 'no']); + assert.equal(launchOptions.testProvider, 'pytest'); + assert.equal(launchOptions.pytestPort, '12345'); + assert.equal(launchOptions.pytestUUID, 'uuid123'); + assert.strictEqual(launchOptions.runTestIdsPort, '54321'); + return true; + }), + typeMoq.It.isAny(), + ), + typeMoq.Times.once(), + ); + }); +}); diff --git a/src/test/testing/testController/unittest/testExecutionAdapter.unit.test.ts b/src/test/testing/testController/unittest/testExecutionAdapter.unit.test.ts index e5495629bf28..7db287a3355c 100644 --- a/src/test/testing/testController/unittest/testExecutionAdapter.unit.test.ts +++ b/src/test/testing/testController/unittest/testExecutionAdapter.unit.test.ts @@ -1,118 +1,64 @@ -// // Copyright (c) Microsoft Corporation. All rights reserved. -// // Licensed under the MIT License. - -// import * as assert from 'assert'; -// import * as path from 'path'; -// import * as typemoq from 'typemoq'; -// import { Uri } from 'vscode'; -// import { IConfigurationService, ITestOutputChannel } from '../../../../client/common/types'; -// import { EXTENSION_ROOT_DIR } from '../../../../client/constants'; -// import { ITestServer, TestCommandOptions } from '../../../../client/testing/testController/common/types'; -// import { UnittestTestExecutionAdapter } from '../../../../client/testing/testController/unittest/testExecutionAdapter'; - -// suite('Unittest test execution adapter', () => { -// let stubConfigSettings: IConfigurationService; -// let outputChannel: typemoq.IMock; - -// setup(() => { -// stubConfigSettings = ({ -// getSettings: () => ({ -// testing: { unittestArgs: ['-v', '-s', '.', '-p', 'test*'] }, -// }), -// } as unknown) as IConfigurationService; -// outputChannel = typemoq.Mock.ofType(); -// }); - -// test('runTests should send the run command to the test server', async () => { -// let options: TestCommandOptions | undefined; - -// const stubTestServer = ({ -// sendCommand(opt: TestCommandOptions, runTestIdPort?: string): Promise { -// delete opt.outChannel; -// options = opt; -// assert(runTestIdPort !== undefined); -// return Promise.resolve(); -// }, -// onDataReceived: () => { -// // no body -// }, -// createUUID: () => '123456789', -// } as unknown) as ITestServer; - -// const uri = Uri.file('/foo/bar'); -// const script = path.join(EXTENSION_ROOT_DIR, 'pythonFiles', 'unittestadapter', 'execution.py'); - -// const adapter = new UnittestTestExecutionAdapter(stubTestServer, stubConfigSettings, outputChannel.object); -// adapter.runTests(uri, [], false).then(() => { -// const expectedOptions: TestCommandOptions = { -// workspaceFolder: uri, -// command: { script, args: ['--udiscovery', '-v', '-s', '.', '-p', 'test*'] }, -// cwd: uri.fsPath, -// uuid: '123456789', -// debugBool: false, -// testIds: [], -// }; -// assert.deepStrictEqual(options, expectedOptions); -// }); -// }); -// test("onDataReceivedHandler should parse the data if the cwd from the payload matches the test adapter's cwd", async () => { -// const stubTestServer = ({ -// sendCommand(): Promise { -// return Promise.resolve(); -// }, -// onDataReceived: () => { -// // no body -// }, -// createUUID: () => '123456789', -// } as unknown) as ITestServer; - -// const uri = Uri.file('/foo/bar'); -// const data = { status: 'success' }; -// const uuid = '123456789'; - -// const adapter = new UnittestTestExecutionAdapter(stubTestServer, stubConfigSettings, outputChannel.object); - -// // triggers runTests flow which will run onDataReceivedHandler and the -// // promise resolves into the parsed data. -// const promise = adapter.runTests(uri, [], false); - -// adapter.onDataReceivedHandler({ uuid, data: JSON.stringify(data) }); - -// const result = await promise; - -// assert.deepStrictEqual(result, data); -// }); -// test("onDataReceivedHandler should ignore the data if the cwd from the payload does not match the test adapter's cwd", async () => { -// const correctUuid = '123456789'; -// const incorrectUuid = '987654321'; -// const stubTestServer = ({ -// sendCommand(): Promise { -// return Promise.resolve(); -// }, -// onDataReceived: () => { -// // no body -// }, -// createUUID: () => correctUuid, -// } as unknown) as ITestServer; - -// const uri = Uri.file('/foo/bar'); - -// const adapter = new UnittestTestExecutionAdapter(stubTestServer, stubConfigSettings, outputChannel.object); - -// // triggers runTests flow which will run onDataReceivedHandler and the -// // promise resolves into the parsed data. -// const promise = adapter.runTests(uri, [], false); - -// const data = { status: 'success' }; -// // will not resolve due to incorrect UUID -// adapter.onDataReceivedHandler({ uuid: incorrectUuid, data: JSON.stringify(data) }); - -// const nextData = { status: 'error' }; -// // will resolve and nextData will be returned as result -// adapter.onDataReceivedHandler({ uuid: correctUuid, data: JSON.stringify(nextData) }); - -// const result = await promise; - -// assert.deepStrictEqual(result, nextData); -// }); -// }); +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import * as assert from 'assert'; +import * as path from 'path'; +import * as typemoq from 'typemoq'; +import { Uri } from 'vscode'; +import * as sinon from 'sinon'; +import { IConfigurationService, ITestOutputChannel } from '../../../../client/common/types'; +import { EXTENSION_ROOT_DIR } from '../../../../client/constants'; +import { ITestServer, TestCommandOptions } from '../../../../client/testing/testController/common/types'; +import { UnittestTestExecutionAdapter } from '../../../../client/testing/testController/unittest/testExecutionAdapter'; +import * as util from '../../../../client/testing/testController/common/utils'; + +suite('Unittest test execution adapter', () => { + let stubConfigSettings: IConfigurationService; + let outputChannel: typemoq.IMock; + + setup(() => { + stubConfigSettings = ({ + getSettings: () => ({ + testing: { unittestArgs: ['-v', '-s', '.', '-p', 'test*'] }, + }), + } as unknown) as IConfigurationService; + outputChannel = typemoq.Mock.ofType(); + sinon.stub(util, 'startTestIdServer').returns(Promise.resolve(54321)); + }); + teardown(() => { + sinon.restore(); + }); + + test('runTests should send the run command to the test server', async () => { + let options: TestCommandOptions | undefined; + + const stubTestServer = ({ + sendCommand(opt: TestCommandOptions, runTestIdPort?: string): Promise { + delete opt.outChannel; + options = opt; + assert(runTestIdPort !== undefined); + return Promise.resolve(); + }, + onRunDataReceived: () => { + // no body + }, + createUUID: () => '123456789', + } as unknown) as ITestServer; + + const uri = Uri.file('/foo/bar'); + const script = path.join(EXTENSION_ROOT_DIR, 'pythonFiles', 'unittestadapter', 'execution.py'); + + const adapter = new UnittestTestExecutionAdapter(stubTestServer, stubConfigSettings, outputChannel.object); + adapter.runTests(uri, [], false).then(() => { + const expectedOptions: TestCommandOptions = { + workspaceFolder: uri, + command: { script, args: ['--udiscovery', '-v', '-s', '.', '-p', 'test*'] }, + cwd: uri.fsPath, + uuid: '123456789', + debugBool: false, + testIds: [], + }; + assert.deepStrictEqual(options, expectedOptions); + }); + }); +});