Skip to content

Commit 260c114

Browse files
Refactor (for clarity) the venv creation testing helper.
1 parent a3ef492 commit 260c114

File tree

1 file changed

+63
-25
lines changed

1 file changed

+63
-25
lines changed

src/test/interpreters/locators/workspaceVirtualEnvService.test.ts

Lines changed: 63 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import { expect } from 'chai';
88
import { exec } from 'child_process';
99
import * as path from 'path';
10+
import { promisify } from 'util';
1011
import { Uri } from 'vscode';
1112
import '../../../client/common/extensions';
1213
import { createDeferredFromPromise, Deferred } from '../../../client/common/utils/async';
@@ -24,16 +25,66 @@ import { IS_MULTI_ROOT_TEST } from '../../constants';
2425
import { sleep } from '../../core';
2526
import { initialize, multirootPath } from '../../initialize';
2627

28+
const execAsync = promisify(exec);
29+
async function run(argv: string[], cwd: string) {
30+
const cmdline = argv.join(' ');
31+
const { stderr } = await execAsync(cmdline, {
32+
cwd: cwd
33+
});
34+
if (stderr && stderr.length > 0) {
35+
throw Error(stderr);
36+
}
37+
}
38+
39+
class Venvs {
40+
constructor(
41+
private readonly cwd: string,
42+
private readonly prefix = '.venv-'
43+
) { }
44+
45+
public async create(name: string): Promise<string> {
46+
const venvRoot = this.resolve(name);
47+
const argv = [
48+
PYTHON_PATH.fileToCommandArgument(),
49+
'-m', 'venv',
50+
venvRoot
51+
];
52+
try {
53+
await run(argv, this.cwd);
54+
} catch (err) {
55+
throw new Error(`Failed to create Env ${path.basename(venvRoot)}, ${PYTHON_PATH}, Error: ${err}`);
56+
}
57+
return venvRoot;
58+
}
59+
60+
public async cleanUp() {
61+
const globPattern = path.join(this.cwd, `${this.prefix}*`);
62+
await deleteFiles(globPattern);
63+
}
64+
65+
private getID(name: string): string {
66+
// Ensure env is random to avoid conflicts in tests (currupting test data).
67+
const now = new Date().getTime().toString();
68+
return `${this.prefix}${name}${now}`;
69+
}
70+
71+
private resolve(name: string): string {
72+
const id = this.getID(name);
73+
return path.join(this.cwd, id);
74+
}
75+
}
76+
2777
const timeoutMs = IS_CI_SERVER ? 60_000 : 15_000;
2878
suite('Interpreters - Workspace VirtualEnv Service', function() {
2979
this.timeout(timeoutMs);
3080
this.retries(0);
3181

32-
let locator: IInterpreterLocatorService;
3382
const workspaceUri = IS_MULTI_ROOT_TEST ? Uri.file(path.join(multirootPath, 'workspace3')) : rootWorkspaceUri!;
3483
const workspace4 = Uri.file(path.join(multirootPath, 'workspace4'));
35-
const venvPrefix = '.venv';
84+
const venvs = new Venvs(workspaceUri.fsPath);
85+
3686
let serviceContainer: IServiceContainer;
87+
let locator: IInterpreterLocatorService;
3788

3889
async function manuallyTriggerFSWatcher(deferred: Deferred<void>) {
3990
// Monitoring files on virtualized environments can be finicky...
@@ -51,7 +102,8 @@ suite('Interpreters - Workspace VirtualEnv Service', function() {
51102
await sleep(1000);
52103
}
53104
}
54-
async function waitForInterpreterToBeDetected(envNameToLookFor: string) {
105+
async function waitForInterpreterToBeDetected(venvRoot: string) {
106+
const envNameToLookFor = path.basename(venvRoot);
55107
const predicate = async () => {
56108
const items = await locator.getInterpreters(workspaceUri);
57109
return items.some(item => item.envName === envNameToLookFor);
@@ -66,24 +118,7 @@ suite('Interpreters - Workspace VirtualEnv Service', function() {
66118
await deferred.promise;
67119
}
68120
async function createVirtualEnvironment(envSuffix: string) {
69-
// Ensure env is random to avoid conflicts in tests (currupting test data).
70-
const envName = `${venvPrefix}${envSuffix}${new Date().getTime().toString()}`;
71-
return new Promise<string>((resolve, reject) => {
72-
exec(
73-
`${PYTHON_PATH.fileToCommandArgument()} -m venv ${envName}`,
74-
{ cwd: workspaceUri.fsPath },
75-
(ex, _, stderr) => {
76-
if (ex) {
77-
return reject(ex);
78-
}
79-
if (stderr && stderr.length > 0) {
80-
reject(new Error(`Failed to create Env ${envName}, ${PYTHON_PATH}, Error: ${stderr}`));
81-
} else {
82-
resolve(envName);
83-
}
84-
}
85-
);
86-
});
121+
return venvs.create(envSuffix);
87122
}
88123

89124
suiteSetup(async function() {
@@ -99,12 +134,12 @@ suite('Interpreters - Workspace VirtualEnv Service', function() {
99134
);
100135
// This test is required, we need to wait for interpreter listing completes,
101136
// before proceeding with other tests.
102-
await deleteFiles(path.join(workspaceUri.fsPath, `${venvPrefix}*`));
137+
await venvs.cleanUp();
103138
await locator.getInterpreters(workspaceUri);
104139
});
105140

106-
suiteTeardown(async () => deleteFiles(path.join(workspaceUri.fsPath, `${venvPrefix}*`)));
107-
teardown(async () => deleteFiles(path.join(workspaceUri.fsPath, `${venvPrefix}*`)));
141+
suiteTeardown(async () => venvs.cleanUp());
142+
teardown(async () => venvs.cleanUp());
108143

109144
test('Detect Virtual Environment', async () => {
110145
const envName = await createVirtualEnvironment('one');
@@ -132,7 +167,10 @@ suite('Interpreters - Workspace VirtualEnv Service', function() {
132167
createVirtualEnvironment('first3'),
133168
createVirtualEnvironment('second3')
134169
]);
135-
await Promise.all([waitForInterpreterToBeDetected(env1), waitForInterpreterToBeDetected(env2)]);
170+
await Promise.all([
171+
waitForInterpreterToBeDetected(env1),
172+
waitForInterpreterToBeDetected(env2)
173+
]);
136174

137175
// Workspace4 should still not have any interpreters.
138176
items4 = await locator.getInterpreters(workspace4);

0 commit comments

Comments
 (0)