mirror of
https://github.com/Microsoft/vscode
synced 2024-08-27 21:09:43 +00:00
Merge pull request #139234 from microsoft/tyriar/120077
Use async/await in env var tests and improve polling
This commit is contained in:
commit
927096c078
|
@ -3,9 +3,9 @@
|
||||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { deepEqual, deepStrictEqual, doesNotThrow, equal, strictEqual, throws } from 'assert';
|
import { deepStrictEqual, doesNotThrow, equal, strictEqual, throws } from 'assert';
|
||||||
import { ConfigurationTarget, Disposable, env, EnvironmentVariableMutator, EnvironmentVariableMutatorType, EventEmitter, ExtensionContext, extensions, ExtensionTerminalOptions, Pseudoterminal, Terminal, TerminalDimensions, TerminalOptions, TerminalState, UIKind, window, workspace } from 'vscode';
|
import { ConfigurationTarget, Disposable, env, EnvironmentVariableMutator, EnvironmentVariableMutatorType, EventEmitter, ExtensionContext, extensions, ExtensionTerminalOptions, Pseudoterminal, Terminal, TerminalDimensions, TerminalOptions, TerminalState, UIKind, window, workspace } from 'vscode';
|
||||||
import { assertNoRpc } from '../utils';
|
import { assertNoRpc, poll } from '../utils';
|
||||||
|
|
||||||
// Disable terminal tests:
|
// Disable terminal tests:
|
||||||
// - Web https://github.com/microsoft/vscode/issues/92826
|
// - Web https://github.com/microsoft/vscode/issues/92826
|
||||||
|
@ -220,7 +220,7 @@ import { assertNoRpc } from '../utils';
|
||||||
await new Promise<void>(r => {
|
await new Promise<void>(r => {
|
||||||
disposables.push(window.onDidCloseTerminal(t => {
|
disposables.push(window.onDidCloseTerminal(t => {
|
||||||
if (t === terminal) {
|
if (t === terminal) {
|
||||||
deepEqual(t.exitStatus, { code: undefined });
|
deepStrictEqual(t.exitStatus, { code: undefined });
|
||||||
r();
|
r();
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
@ -364,13 +364,13 @@ import { assertNoRpc } from '../utils';
|
||||||
closeEvents.push(e.name);
|
closeEvents.push(e.name);
|
||||||
try {
|
try {
|
||||||
if (closeEvents.length === 1) {
|
if (closeEvents.length === 1) {
|
||||||
deepEqual(openEvents, ['test1']);
|
deepStrictEqual(openEvents, ['test1']);
|
||||||
deepEqual(dataEvents, [{ name: 'test1', data: 'write1' }]);
|
deepStrictEqual(dataEvents, [{ name: 'test1', data: 'write1' }]);
|
||||||
deepEqual(closeEvents, ['test1']);
|
deepStrictEqual(closeEvents, ['test1']);
|
||||||
} else if (closeEvents.length === 2) {
|
} else if (closeEvents.length === 2) {
|
||||||
deepEqual(openEvents, ['test1', 'test2']);
|
deepStrictEqual(openEvents, ['test1', 'test2']);
|
||||||
deepEqual(dataEvents, [{ name: 'test1', data: 'write1' }, { name: 'test2', data: 'write2' }]);
|
deepStrictEqual(dataEvents, [{ name: 'test1', data: 'write1' }, { name: 'test2', data: 'write2' }]);
|
||||||
deepEqual(closeEvents, ['test1', 'test2']);
|
deepStrictEqual(closeEvents, ['test1', 'test2']);
|
||||||
}
|
}
|
||||||
resolveOnceClosed!();
|
resolveOnceClosed!();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -667,29 +667,8 @@ import { assertNoRpc } from '../utils';
|
||||||
});
|
});
|
||||||
|
|
||||||
suite('environmentVariableCollection', () => {
|
suite('environmentVariableCollection', () => {
|
||||||
test.skip('should have collection variables apply to terminals immediately after setting', (done) => {
|
test('should have collection variables apply to terminals immediately after setting', async () => {
|
||||||
// Text to match on before passing the test
|
// Setup collection and create terminal
|
||||||
const expectedText = [
|
|
||||||
'~a2~',
|
|
||||||
'b1~b2~',
|
|
||||||
'~c2~c1'
|
|
||||||
];
|
|
||||||
let data = '';
|
|
||||||
disposables.push(window.onDidWriteTerminalData(e => {
|
|
||||||
if (terminal !== e.terminal) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
data += sanitizeData(e.data);
|
|
||||||
// Multiple expected could show up in the same data event
|
|
||||||
while (expectedText.length > 0 && data.indexOf(expectedText[0]) >= 0) {
|
|
||||||
expectedText.shift();
|
|
||||||
// Check if all string are found, if so finish the test
|
|
||||||
if (expectedText.length === 0) {
|
|
||||||
disposables.push(window.onDidCloseTerminal(() => done()));
|
|
||||||
terminal.dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
const collection = extensionContext.environmentVariableCollection;
|
const collection = extensionContext.environmentVariableCollection;
|
||||||
disposables.push({ dispose: () => collection.clear() });
|
disposables.push({ dispose: () => collection.clear() });
|
||||||
collection.replace('A', '~a2~');
|
collection.replace('A', '~a2~');
|
||||||
|
@ -702,6 +681,16 @@ import { assertNoRpc } from '../utils';
|
||||||
C: 'c1'
|
C: 'c1'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Listen for all data events
|
||||||
|
let data = '';
|
||||||
|
disposables.push(window.onDidWriteTerminalData(e => {
|
||||||
|
if (terminal !== e.terminal) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
data += sanitizeData(e.data);
|
||||||
|
}));
|
||||||
|
|
||||||
// Run both PowerShell and sh commands, errors don't matter we're just looking for
|
// Run both PowerShell and sh commands, errors don't matter we're just looking for
|
||||||
// the correct output
|
// the correct output
|
||||||
terminal.sendText('$env:A');
|
terminal.sendText('$env:A');
|
||||||
|
@ -710,31 +699,21 @@ import { assertNoRpc } from '../utils';
|
||||||
terminal.sendText('echo $B');
|
terminal.sendText('echo $B');
|
||||||
terminal.sendText('$env:C');
|
terminal.sendText('$env:C');
|
||||||
terminal.sendText('echo $C');
|
terminal.sendText('echo $C');
|
||||||
|
|
||||||
|
// Poll for the echo results to show up
|
||||||
|
await poll<void>(() => Promise.resolve(), () => data.includes('~a2~'), '~a2~ should be printed');
|
||||||
|
await poll<void>(() => Promise.resolve(), () => data.includes('b1~b2~'), 'b1~b2~ should be printed');
|
||||||
|
await poll<void>(() => Promise.resolve(), () => data.includes('~c2~c1'), '~c2~c1 should be printed');
|
||||||
|
|
||||||
|
// Wait for terminal to be disposed
|
||||||
|
await new Promise<void>(r => {
|
||||||
|
disposables.push(window.onDidCloseTerminal(() => r()));
|
||||||
|
terminal.dispose();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should have collection variables apply to environment variables that don\'t exist', (done) => {
|
test('should have collection variables apply to environment variables that don\'t exist', async () => {
|
||||||
// Text to match on before passing the test
|
// Setup collection and create terminal
|
||||||
const expectedText = [
|
|
||||||
'~a2~',
|
|
||||||
'~b2~',
|
|
||||||
'~c2~'
|
|
||||||
];
|
|
||||||
let data = '';
|
|
||||||
disposables.push(window.onDidWriteTerminalData(e => {
|
|
||||||
if (terminal !== e.terminal) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
data += sanitizeData(e.data);
|
|
||||||
// Multiple expected could show up in the same data event
|
|
||||||
while (expectedText.length > 0 && data.indexOf(expectedText[0]) >= 0) {
|
|
||||||
expectedText.shift();
|
|
||||||
// Check if all string are found, if so finish the test
|
|
||||||
if (expectedText.length === 0) {
|
|
||||||
disposables.push(window.onDidCloseTerminal(() => done()));
|
|
||||||
terminal.dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
const collection = extensionContext.environmentVariableCollection;
|
const collection = extensionContext.environmentVariableCollection;
|
||||||
disposables.push({ dispose: () => collection.clear() });
|
disposables.push({ dispose: () => collection.clear() });
|
||||||
collection.replace('A', '~a2~');
|
collection.replace('A', '~a2~');
|
||||||
|
@ -747,6 +726,16 @@ import { assertNoRpc } from '../utils';
|
||||||
C: null
|
C: null
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Listen for all data events
|
||||||
|
let data = '';
|
||||||
|
disposables.push(window.onDidWriteTerminalData(e => {
|
||||||
|
if (terminal !== e.terminal) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
data += sanitizeData(e.data);
|
||||||
|
}));
|
||||||
|
|
||||||
// Run both PowerShell and sh commands, errors don't matter we're just looking for
|
// Run both PowerShell and sh commands, errors don't matter we're just looking for
|
||||||
// the correct output
|
// the correct output
|
||||||
terminal.sendText('$env:A');
|
terminal.sendText('$env:A');
|
||||||
|
@ -755,30 +744,21 @@ import { assertNoRpc } from '../utils';
|
||||||
terminal.sendText('echo $B');
|
terminal.sendText('echo $B');
|
||||||
terminal.sendText('$env:C');
|
terminal.sendText('$env:C');
|
||||||
terminal.sendText('echo $C');
|
terminal.sendText('echo $C');
|
||||||
|
|
||||||
|
// Poll for the echo results to show up
|
||||||
|
await poll<void>(() => Promise.resolve(), () => data.includes('~a2~'), '~a2~ should be printed');
|
||||||
|
await poll<void>(() => Promise.resolve(), () => data.includes('~b2~'), '~b2~ should be printed');
|
||||||
|
await poll<void>(() => Promise.resolve(), () => data.includes('~c2~'), '~c2~ should be printed');
|
||||||
|
|
||||||
|
// Wait for terminal to be disposed
|
||||||
|
await new Promise<void>(r => {
|
||||||
|
disposables.push(window.onDidCloseTerminal(() => r()));
|
||||||
|
terminal.dispose();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test.skip('should respect clearing entries', (done) => {
|
test('should respect clearing entries', async () => {
|
||||||
// Text to match on before passing the test
|
// Setup collection and create terminal
|
||||||
const expectedText = [
|
|
||||||
'~a1~',
|
|
||||||
'~b1~'
|
|
||||||
];
|
|
||||||
let data = '';
|
|
||||||
disposables.push(window.onDidWriteTerminalData(e => {
|
|
||||||
if (terminal !== e.terminal) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
data += sanitizeData(e.data);
|
|
||||||
// Multiple expected could show up in the same data event
|
|
||||||
while (expectedText.length > 0 && data.indexOf(expectedText[0]) >= 0) {
|
|
||||||
expectedText.shift();
|
|
||||||
// Check if all string are found, if so finish the test
|
|
||||||
if (expectedText.length === 0) {
|
|
||||||
disposables.push(window.onDidCloseTerminal(() => done()));
|
|
||||||
terminal.dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
const collection = extensionContext.environmentVariableCollection;
|
const collection = extensionContext.environmentVariableCollection;
|
||||||
disposables.push({ dispose: () => collection.clear() });
|
disposables.push({ dispose: () => collection.clear() });
|
||||||
collection.replace('A', '~a2~');
|
collection.replace('A', '~a2~');
|
||||||
|
@ -790,36 +770,36 @@ import { assertNoRpc } from '../utils';
|
||||||
B: '~b1~'
|
B: '~b1~'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// Run both PowerShell and sh commands, errors don't matter we're just looking for
|
|
||||||
// the correct output
|
|
||||||
terminal.sendText('$env:A');
|
|
||||||
terminal.sendText('echo $A');
|
|
||||||
terminal.sendText('$env:B');
|
|
||||||
terminal.sendText('echo $B');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should respect deleting entries', (done) => {
|
// Listen for all data events
|
||||||
// Text to match on before passing the test
|
|
||||||
const expectedText = [
|
|
||||||
'~a1~',
|
|
||||||
'~b2~'
|
|
||||||
];
|
|
||||||
let data = '';
|
let data = '';
|
||||||
disposables.push(window.onDidWriteTerminalData(e => {
|
disposables.push(window.onDidWriteTerminalData(e => {
|
||||||
if (terminal !== e.terminal) {
|
if (terminal !== e.terminal) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
data += sanitizeData(e.data);
|
data += sanitizeData(e.data);
|
||||||
// Multiple expected could show up in the same data event
|
|
||||||
while (expectedText.length > 0 && data.indexOf(expectedText[0]) >= 0) {
|
|
||||||
expectedText.shift();
|
|
||||||
// Check if all string are found, if so finish the test
|
|
||||||
if (expectedText.length === 0) {
|
|
||||||
disposables.push(window.onDidCloseTerminal(() => done()));
|
|
||||||
terminal.dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// Run both PowerShell and sh commands, errors don't matter we're just looking for
|
||||||
|
// the correct output
|
||||||
|
terminal.sendText('$env:A');
|
||||||
|
terminal.sendText('echo $A');
|
||||||
|
terminal.sendText('$env:B');
|
||||||
|
terminal.sendText('echo $B');
|
||||||
|
|
||||||
|
// Poll for the echo results to show up
|
||||||
|
await poll<void>(() => Promise.resolve(), () => data.includes('~a1~'), '~a1~ should be printed');
|
||||||
|
await poll<void>(() => Promise.resolve(), () => data.includes('~b1~'), '~b1~ should be printed');
|
||||||
|
|
||||||
|
// Wait for terminal to be disposed
|
||||||
|
await new Promise<void>(r => {
|
||||||
|
disposables.push(window.onDidCloseTerminal(() => r()));
|
||||||
|
terminal.dispose();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should respect deleting entries', async () => {
|
||||||
|
// Setup collection and create terminal
|
||||||
const collection = extensionContext.environmentVariableCollection;
|
const collection = extensionContext.environmentVariableCollection;
|
||||||
disposables.push({ dispose: () => collection.clear() });
|
disposables.push({ dispose: () => collection.clear() });
|
||||||
collection.replace('A', '~a2~');
|
collection.replace('A', '~a2~');
|
||||||
|
@ -831,12 +811,32 @@ import { assertNoRpc } from '../utils';
|
||||||
B: '~b2~'
|
B: '~b2~'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Listen for all data events
|
||||||
|
let data = '';
|
||||||
|
disposables.push(window.onDidWriteTerminalData(e => {
|
||||||
|
if (terminal !== e.terminal) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
data += sanitizeData(e.data);
|
||||||
|
}));
|
||||||
|
|
||||||
// Run both PowerShell and sh commands, errors don't matter we're just looking for
|
// Run both PowerShell and sh commands, errors don't matter we're just looking for
|
||||||
// the correct output
|
// the correct output
|
||||||
terminal.sendText('$env:A');
|
terminal.sendText('$env:A');
|
||||||
terminal.sendText('echo $A');
|
terminal.sendText('echo $A');
|
||||||
terminal.sendText('$env:B');
|
terminal.sendText('$env:B');
|
||||||
terminal.sendText('echo $B');
|
terminal.sendText('echo $B');
|
||||||
|
|
||||||
|
// Poll for the echo results to show up
|
||||||
|
await poll<void>(() => Promise.resolve(), () => data.includes('~a1~'), '~a1~ should be printed');
|
||||||
|
await poll<void>(() => Promise.resolve(), () => data.includes('~b2~'), '~b2~ should be printed');
|
||||||
|
|
||||||
|
// Wait for terminal to be disposed
|
||||||
|
await new Promise<void>(r => {
|
||||||
|
disposables.push(window.onDidCloseTerminal(() => r()));
|
||||||
|
terminal.dispose();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('get and forEach should work', () => {
|
test('get and forEach should work', () => {
|
||||||
|
@ -847,14 +847,14 @@ import { assertNoRpc } from '../utils';
|
||||||
collection.prepend('C', '~c2~');
|
collection.prepend('C', '~c2~');
|
||||||
|
|
||||||
// Verify get
|
// Verify get
|
||||||
deepEqual(collection.get('A'), { value: '~a2~', type: EnvironmentVariableMutatorType.Replace });
|
deepStrictEqual(collection.get('A'), { value: '~a2~', type: EnvironmentVariableMutatorType.Replace });
|
||||||
deepEqual(collection.get('B'), { value: '~b2~', type: EnvironmentVariableMutatorType.Append });
|
deepStrictEqual(collection.get('B'), { value: '~b2~', type: EnvironmentVariableMutatorType.Append });
|
||||||
deepEqual(collection.get('C'), { value: '~c2~', type: EnvironmentVariableMutatorType.Prepend });
|
deepStrictEqual(collection.get('C'), { value: '~c2~', type: EnvironmentVariableMutatorType.Prepend });
|
||||||
|
|
||||||
// Verify forEach
|
// Verify forEach
|
||||||
const entries: [string, EnvironmentVariableMutator][] = [];
|
const entries: [string, EnvironmentVariableMutator][] = [];
|
||||||
collection.forEach((v, m) => entries.push([v, m]));
|
collection.forEach((v, m) => entries.push([v, m]));
|
||||||
deepEqual(entries, [
|
deepStrictEqual(entries, [
|
||||||
['A', { value: '~a2~', type: EnvironmentVariableMutatorType.Replace }],
|
['A', { value: '~a2~', type: EnvironmentVariableMutatorType.Replace }],
|
||||||
['B', { value: '~b2~', type: EnvironmentVariableMutatorType.Append }],
|
['B', { value: '~b2~', type: EnvironmentVariableMutatorType.Append }],
|
||||||
['C', { value: '~c2~', type: EnvironmentVariableMutatorType.Prepend }]
|
['C', { value: '~c2~', type: EnvironmentVariableMutatorType.Prepend }]
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import * as assert from 'assert';
|
import * as assert from 'assert';
|
||||||
|
import { EOL } from 'os';
|
||||||
import * as crypto from 'crypto';
|
import * as crypto from 'crypto';
|
||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import { TestFS } from './memfs';
|
import { TestFS } from './memfs';
|
||||||
|
@ -150,3 +151,35 @@ export function suiteRepeat(n: number, description: string, callback: (this: any
|
||||||
suite(`${description} (iteration ${i})`, callback);
|
suite(`${description} (iteration ${i})`, callback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function poll<T>(
|
||||||
|
fn: () => Thenable<T>,
|
||||||
|
acceptFn: (result: T) => boolean,
|
||||||
|
timeoutMessage: string,
|
||||||
|
retryCount: number = 200,
|
||||||
|
retryInterval: number = 100 // millis
|
||||||
|
): Promise<T> {
|
||||||
|
let trial = 1;
|
||||||
|
let lastError: string = '';
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
if (trial > retryCount) {
|
||||||
|
throw new Error(`Timeout: ${timeoutMessage} after ${(retryCount * retryInterval) / 1000} seconds.\r${lastError}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
let result;
|
||||||
|
try {
|
||||||
|
result = await fn();
|
||||||
|
if (acceptFn(result)) {
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
lastError = 'Did not pass accept function';
|
||||||
|
}
|
||||||
|
} catch (e: any) {
|
||||||
|
lastError = Array.isArray(e.stack) ? e.stack.join(EOL) : e.stack;
|
||||||
|
}
|
||||||
|
|
||||||
|
await new Promise(resolve => setTimeout(resolve, retryInterval));
|
||||||
|
trial++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue