Skip to content

Commit 2674842

Browse files
authored
rewrite should respect settings.testing.cwd (#21539)
fixes #21531
1 parent e40fe9d commit 2674842

File tree

8 files changed

+141
-17
lines changed

8 files changed

+141
-17
lines changed

src/client/testing/testController/pytest/pytestDiscoveryAdapter.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,13 @@ export class PytestTestDiscoveryAdapter implements ITestDiscoveryAdapter {
5555
const uuid = this.testServer.createUUID(uri.fsPath);
5656
const settings = this.configSettings.getSettings(uri);
5757
const { pytestArgs } = settings.testing;
58+
const cwd = settings.testing.cwd && settings.testing.cwd.length > 0 ? settings.testing.cwd : uri.fsPath;
5859

5960
const pythonPathParts: string[] = process.env.PYTHONPATH?.split(path.delimiter) ?? [];
6061
const pythonPathCommand = [fullPluginPath, ...pythonPathParts].join(path.delimiter);
6162

6263
const spawnOptions: SpawnOptions = {
63-
cwd: uri.fsPath,
64+
cwd,
6465
throwOnStdErr: true,
6566
extraVariables: {
6667
PYTHONPATH: pythonPathCommand,

src/client/testing/testController/pytest/pytestExecutionAdapter.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,12 +84,13 @@ export class PytestTestExecutionAdapter implements ITestExecutionAdapter {
8484
this.configSettings.isTestExecution();
8585
const settings = this.configSettings.getSettings(uri);
8686
const { pytestArgs } = settings.testing;
87+
const cwd = settings.testing.cwd && settings.testing.cwd.length > 0 ? settings.testing.cwd : uri.fsPath;
8788

8889
const pythonPathParts: string[] = process.env.PYTHONPATH?.split(path.delimiter) ?? [];
8990
const pythonPathCommand = [fullPluginPath, ...pythonPathParts].join(path.delimiter);
9091

9192
const spawnOptions: SpawnOptions = {
92-
cwd: uri.fsPath,
93+
cwd,
9394
throwOnStdErr: true,
9495
extraVariables: {
9596
PYTHONPATH: pythonPathCommand,
@@ -131,7 +132,7 @@ export class PytestTestExecutionAdapter implements ITestExecutionAdapter {
131132
const pytestPort = this.testServer.getPort().toString();
132133
const pytestUUID = uuid.toString();
133134
const launchOptions: LaunchOptions = {
134-
cwd: uri.fsPath,
135+
cwd,
135136
args: testArgs,
136137
token: spawnOptions.token,
137138
testProvider: PYTEST_PROVIDER,
@@ -156,7 +157,7 @@ export class PytestTestExecutionAdapter implements ITestExecutionAdapter {
156157
return Promise.reject(ex);
157158
}
158159

159-
const executionPayload: ExecutionTestPayload = { cwd: uri.fsPath, status: 'success', error: '' };
160+
const executionPayload: ExecutionTestPayload = { cwd, status: 'success', error: '' };
160161
return executionPayload;
161162
}
162163
}

src/client/testing/testController/unittest/testDiscoveryAdapter.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@ import {
1919
* Wrapper class for unittest test discovery. This is where we call `runTestCommand`.
2020
*/
2121
export class UnittestTestDiscoveryAdapter implements ITestDiscoveryAdapter {
22-
private cwd: string | undefined;
23-
2422
constructor(
2523
public testServer: ITestServer,
2624
public configSettings: IConfigurationService,
@@ -31,16 +29,16 @@ export class UnittestTestDiscoveryAdapter implements ITestDiscoveryAdapter {
3129
public async discoverTests(uri: Uri): Promise<DiscoveredTestPayload> {
3230
const settings = this.configSettings.getSettings(uri);
3331
const { unittestArgs } = settings.testing;
32+
const cwd = settings.testing.cwd && settings.testing.cwd.length > 0 ? settings.testing.cwd : uri.fsPath;
3433

3534
const command = buildDiscoveryCommand(unittestArgs);
3635

37-
this.cwd = uri.fsPath;
3836
const uuid = this.testServer.createUUID(uri.fsPath);
3937

4038
const options: TestCommandOptions = {
4139
workspaceFolder: uri,
4240
command,
43-
cwd: this.cwd,
41+
cwd,
4442
uuid,
4543
outChannel: this.outputChannel,
4644
};
@@ -57,7 +55,7 @@ export class UnittestTestDiscoveryAdapter implements ITestDiscoveryAdapter {
5755
// placeholder until after the rewrite is adopted
5856
// TODO: remove after adoption.
5957
const discoveryPayload: DiscoveredTestPayload = {
60-
cwd: uri.fsPath,
58+
cwd,
6159
status: 'success',
6260
};
6361
return discoveryPayload;

src/client/testing/testController/unittest/testExecutionAdapter.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@ import { startTestIdServer } from '../common/utils';
2323
*/
2424

2525
export class UnittestTestExecutionAdapter implements ITestExecutionAdapter {
26-
private cwd: string | undefined;
27-
2826
constructor(
2927
public testServer: ITestServer,
3028
public configSettings: IConfigurationService,
@@ -62,15 +60,15 @@ export class UnittestTestExecutionAdapter implements ITestExecutionAdapter {
6260
debugBool?: boolean,
6361
): Promise<ExecutionTestPayload> {
6462
const settings = this.configSettings.getSettings(uri);
65-
const { cwd, unittestArgs } = settings.testing;
63+
const { unittestArgs } = settings.testing;
64+
const cwd = settings.testing.cwd && settings.testing.cwd.length > 0 ? settings.testing.cwd : uri.fsPath;
6665

6766
const command = buildExecutionCommand(unittestArgs);
68-
this.cwd = cwd || uri.fsPath;
6967

7068
const options: TestCommandOptions = {
7169
workspaceFolder: uri,
7270
command,
73-
cwd: this.cwd,
71+
cwd,
7472
uuid,
7573
debugBool,
7674
testIds,
@@ -87,7 +85,7 @@ export class UnittestTestExecutionAdapter implements ITestExecutionAdapter {
8785
});
8886
// placeholder until after the rewrite is adopted
8987
// TODO: remove after adoption.
90-
const executionPayload: ExecutionTestPayload = { cwd: uri.fsPath, status: 'success', error: '' };
88+
const executionPayload: ExecutionTestPayload = { cwd, status: 'success', error: '' };
9189
return executionPayload;
9290
}
9391
}

src/test/testing/testController/pytest/pytestDiscoveryAdapter.unit.test.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,9 +105,10 @@ suite('pytest test discovery adapter', () => {
105105
});
106106
test('Test discovery correctly pulls pytest args from config service settings', async () => {
107107
// set up a config service with different pytest args
108+
const expectedPathNew = path.join('other', 'path');
108109
const configServiceNew: IConfigurationService = ({
109110
getSettings: () => ({
110-
testing: { pytestArgs: ['.', 'abc', 'xyz'] },
111+
testing: { pytestArgs: ['.', 'abc', 'xyz'], cwd: expectedPathNew },
111112
}),
112113
} as unknown) as IConfigurationService;
113114

@@ -120,7 +121,7 @@ suite('pytest test discovery adapter', () => {
120121
expectedArgs,
121122
typeMoq.It.is<SpawnOptions>((options) => {
122123
assert.deepEqual(options.extraVariables, expectedExtraVariables);
123-
assert.equal(options.cwd, expectedPath);
124+
assert.equal(options.cwd, expectedPathNew);
124125
assert.equal(options.throwOnStdErr, true);
125126
return true;
126127
}),

src/test/testing/testController/pytest/pytestExecutionAdapter.unit.test.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,55 @@ suite('pytest test execution adapter', () => {
138138
typeMoq.Times.once(),
139139
);
140140
});
141+
test('pytest execution respects settings.testing.cwd when present', async () => {
142+
const newCwd = path.join('new', 'path');
143+
configService = ({
144+
getSettings: () => ({
145+
testing: { pytestArgs: ['.'], cwd: newCwd },
146+
}),
147+
isTestExecution: () => false,
148+
} as unknown) as IConfigurationService;
149+
const uri = Uri.file(myTestPath);
150+
const uuid = 'uuid123';
151+
testServer
152+
.setup((t) => t.onDiscoveryDataReceived(typeMoq.It.isAny(), typeMoq.It.isAny()))
153+
.returns(() => ({
154+
dispose: () => {
155+
/* no-body */
156+
},
157+
}));
158+
testServer.setup((t) => t.createUUID(typeMoq.It.isAny())).returns(() => uuid);
159+
const outputChannel = typeMoq.Mock.ofType<ITestOutputChannel>();
160+
const testRun = typeMoq.Mock.ofType<TestRun>();
161+
adapter = new PytestTestExecutionAdapter(testServer.object, configService, outputChannel.object);
162+
await adapter.runTests(uri, [], false, testRun.object, execFactory.object);
163+
164+
const pathToPythonFiles = path.join(EXTENSION_ROOT_DIR, 'pythonFiles');
165+
const pathToPythonScript = path.join(pathToPythonFiles, 'vscode_pytest', 'run_pytest_script.py');
166+
const expectedArgs = [pathToPythonScript, '--rootdir', myTestPath];
167+
const expectedExtraVariables = {
168+
PYTHONPATH: pathToPythonFiles,
169+
TEST_UUID: 'uuid123',
170+
TEST_PORT: '12345',
171+
};
172+
173+
execService.verify(
174+
(x) =>
175+
x.exec(
176+
expectedArgs,
177+
typeMoq.It.is<SpawnOptions>((options) => {
178+
assert.equal(options.extraVariables?.PYTHONPATH, expectedExtraVariables.PYTHONPATH);
179+
assert.equal(options.extraVariables?.TEST_UUID, expectedExtraVariables.TEST_UUID);
180+
assert.equal(options.extraVariables?.TEST_PORT, expectedExtraVariables.TEST_PORT);
181+
assert.equal(options.extraVariables?.RUN_TEST_IDS_PORT, '54321');
182+
assert.equal(options.cwd, newCwd);
183+
assert.equal(options.throwOnStdErr, true);
184+
return true;
185+
}),
186+
),
187+
typeMoq.Times.once(),
188+
);
189+
});
141190
test('Debug launched correctly for pytest', async () => {
142191
const uri = Uri.file(myTestPath);
143192
const uuid = 'uuid123';

src/test/testing/testController/unittest/testDiscoveryAdapter.unit.test.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,41 @@ suite('Unittest test discovery adapter', () => {
5454
uuid: '123456789',
5555
});
5656
});
57+
test('DiscoverTests should respect settings.testings.cwd when present', async () => {
58+
let options: TestCommandOptions | undefined;
59+
stubConfigSettings = ({
60+
getSettings: () => ({
61+
testing: { unittestArgs: ['-v', '-s', '.', '-p', 'test*'], cwd: '/foo' },
62+
}),
63+
} as unknown) as IConfigurationService;
64+
65+
const stubTestServer = ({
66+
sendCommand(opt: TestCommandOptions): Promise<void> {
67+
delete opt.outChannel;
68+
options = opt;
69+
return Promise.resolve();
70+
},
71+
onDiscoveryDataReceived: () => {
72+
// no body
73+
},
74+
createUUID: () => '123456789',
75+
} as unknown) as ITestServer;
76+
77+
const uri = Uri.file('/foo/bar');
78+
const newCwd = '/foo';
79+
const script = path.join(EXTENSION_ROOT_DIR, 'pythonFiles', 'unittestadapter', 'discovery.py');
80+
81+
const adapter = new UnittestTestDiscoveryAdapter(stubTestServer, stubConfigSettings, outputChannel.object);
82+
adapter.discoverTests(uri);
83+
84+
assert.deepStrictEqual(options, {
85+
workspaceFolder: uri,
86+
cwd: newCwd,
87+
command: {
88+
script,
89+
args: ['--udiscovery', '-v', '-s', '.', '-p', 'test*'],
90+
},
91+
uuid: '123456789',
92+
});
93+
});
5794
});

src/test/testing/testController/unittest/testExecutionAdapter.unit.test.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,43 @@ suite('Unittest test execution adapter', () => {
6262
assert.deepStrictEqual(options, expectedOptions);
6363
});
6464
});
65+
test('runTests should respect settings.testing.cwd when present', async () => {
66+
stubConfigSettings = ({
67+
getSettings: () => ({
68+
testing: { unittestArgs: ['-v', '-s', '.', '-p', 'test*'], cwd: '/foo' },
69+
}),
70+
} as unknown) as IConfigurationService;
71+
let options: TestCommandOptions | undefined;
72+
73+
const stubTestServer = ({
74+
sendCommand(opt: TestCommandOptions, runTestIdPort?: string): Promise<void> {
75+
delete opt.outChannel;
76+
options = opt;
77+
assert(runTestIdPort !== undefined);
78+
return Promise.resolve();
79+
},
80+
onRunDataReceived: () => {
81+
// no body
82+
},
83+
createUUID: () => '123456789',
84+
} as unknown) as ITestServer;
85+
86+
const newCwd = '/foo';
87+
const uri = Uri.file('/foo/bar');
88+
const script = path.join(EXTENSION_ROOT_DIR, 'pythonFiles', 'unittestadapter', 'execution.py');
89+
90+
const adapter = new UnittestTestExecutionAdapter(stubTestServer, stubConfigSettings, outputChannel.object);
91+
const testIds = ['test1id', 'test2id'];
92+
adapter.runTests(uri, testIds, false).then(() => {
93+
const expectedOptions: TestCommandOptions = {
94+
workspaceFolder: uri,
95+
command: { script, args: ['--udiscovery', '-v', '-s', '.', '-p', 'test*'] },
96+
cwd: newCwd,
97+
uuid: '123456789',
98+
debugBool: false,
99+
testIds,
100+
};
101+
assert.deepStrictEqual(options, expectedOptions);
102+
});
103+
});
65104
});

0 commit comments

Comments
 (0)