Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 26 additions & 7 deletions src/test/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -459,20 +459,39 @@ export async function waitForCondition(
errorMessage: string,
): Promise<void> {
return new Promise<void>(async (resolve, reject) => {
const startTime = Date.now();
let checkCount = 0;
const timeout = setTimeout(() => {
clearTimeout(timeout);

// eslint-disable-next-line @typescript-eslint/no-use-before-define
clearTimeout(timer);
reject(new Error(errorMessage));
clearInterval(timer);
const elapsed = Date.now() - startTime;
const detailedError = `${errorMessage} (waited ${elapsed}ms, checked ${checkCount} times)`;
console.error(`[waitForCondition] Timeout: ${detailedError}`);
reject(new Error(detailedError));
}, timeoutMs);
const timer = setInterval(async () => {
if (!(await condition().catch(() => false))) {
return;
checkCount++;
try {
const result = await condition();
if (!result) {
return;
}
clearTimeout(timeout);
clearInterval(timer);
const elapsed = Date.now() - startTime;
if (IS_SMOKE_TEST) {
console.log(`[waitForCondition] Condition met after ${elapsed}ms (${checkCount} checks)`);
}
resolve();
} catch (error) {
// Condition check threw an error, log it but continue checking
if (checkCount % 100 === 0) {
// Log every 100 checks
console.error(`[waitForCondition] Error checking condition (check #${checkCount}): ${error}`);
}
}
clearTimeout(timeout);
clearTimeout(timer);
resolve();
}, 10);
});
}
Expand Down
89 changes: 87 additions & 2 deletions src/test/smoke/runInTerminal.smoke.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,100 @@ suite('Smoke Test: Run Python File In Terminal', () => {
'smokeTests',
'testExecInTerminal.log',
);

console.log(`[runInTerminal.smoke] Test starting`);
console.log(`[runInTerminal.smoke] Python file: ${file}`);
console.log(`[runInTerminal.smoke] Output file: ${outputFile}`);
console.log(`[runInTerminal.smoke] Python file exists: ${await fs.pathExists(file)}`);

if (await fs.pathExists(outputFile)) {
console.log(`[runInTerminal.smoke] Output file already exists, deleting...`);
await fs.unlink(outputFile);
console.log(`[runInTerminal.smoke] Output file deleted`);
} else {
console.log(`[runInTerminal.smoke] Output file does not exist (clean state)`);
}

const textDocument = await openFile(file);
console.log(`[runInTerminal.smoke] File opened in editor`);

// Check active terminals before execution
const terminalsBefore = vscode.window.terminals.length;
console.log(`[runInTerminal.smoke] Number of terminals before execution: ${terminalsBefore}`);

// On Windows, if terminals exist from previous tests, they may not be ready for new commands
// Give them time to fully initialize before sending commands
if (terminalsBefore > 0 && process.platform === 'win32') {
console.log(
`[runInTerminal.smoke] Windows detected with ${terminalsBefore} existing terminals, waiting 3s for terminal readiness...`,
);
await new Promise((resolve) => setTimeout(resolve, 3000));
}

const startTime = Date.now();
console.log(`[runInTerminal.smoke] Executing 'python.execInTerminal' command at ${new Date().toISOString()}`);

await vscode.commands.executeCommand<void>('python.execInTerminal', textDocument.uri).then(undefined, (err) => {
console.error(`[runInTerminal.smoke] Command failed with error: ${err}`);
assert.fail(`Something went wrong running the Python file in the terminal: ${err}`);
});
const checkIfFileHasBeenCreated = () => fs.pathExists(outputFile);
await waitForCondition(checkIfFileHasBeenCreated, 30_000, `"${outputFile}" file not created`);
const commandCompleteTime = Date.now();
console.log(`[runInTerminal.smoke] Command completed in ${commandCompleteTime - startTime}ms`);

// Check active terminals after execution
const terminalsAfter = vscode.window.terminals.length;
console.log(`[runInTerminal.smoke] Number of terminals after execution: ${terminalsAfter}`);
if (vscode.window.activeTerminal) {
console.log(`[runInTerminal.smoke] Active terminal name: ${vscode.window.activeTerminal.name}`);
}

// Add additional wait to allow terminal to start processing
// Windows may need more time for terminal to initialize and start executing
const isWindows = process.platform === 'win32';
const initialWaitTime = isWindows ? 2000 : 1000;
console.log(
`[runInTerminal.smoke] Waiting ${initialWaitTime}ms for terminal to start processing (isWindows: ${isWindows})...`,
);
await new Promise((resolve) => setTimeout(resolve, initialWaitTime));

// Verify the working directory matches expected
const expectedDir = path.dirname(outputFile);
console.log(`[runInTerminal.smoke] Expected output directory: ${expectedDir}`);
console.log(`[runInTerminal.smoke] Directory exists: ${await fs.pathExists(expectedDir)}`);

let checkCount = 0;
const checkIfFileHasBeenCreated = async () => {
checkCount++;
const exists = await fs.pathExists(outputFile);
if (checkCount % 100 === 0) {
// Log every 100 checks (~1 second)
const elapsed = Date.now() - startTime;
console.log(`[runInTerminal.smoke] File check #${checkCount} at ${elapsed}ms: ${exists}`);
}
return exists;
};

try {
await waitForCondition(checkIfFileHasBeenCreated, 30_000, `"${outputFile}" file not created`);
const totalTime = Date.now() - startTime;
console.log(`[runInTerminal.smoke] SUCCESS: File created after ${totalTime}ms (${checkCount} checks)`);
} catch (error) {
const totalTime = Date.now() - startTime;
console.error(`[runInTerminal.smoke] FAILURE after ${totalTime}ms (${checkCount} checks)`);
console.error(`[runInTerminal.smoke] Output file exists: ${await fs.pathExists(outputFile)}`);
console.error(`[runInTerminal.smoke] Number of terminals: ${vscode.window.terminals.length}`);

// List directory contents to see if file is there
const dir = path.dirname(outputFile);
try {
const fsModule = await import('fs');
const files = fsModule.readdirSync(dir);
console.error(`[runInTerminal.smoke] Directory contents (${dir}):`, files);
} catch (e) {
console.error(`[runInTerminal.smoke] Failed to list directory: ${e}`);
}

throw error;
}
});
});
175 changes: 171 additions & 4 deletions src/test/smoke/smartSend.smoke.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ suite('Smoke Test: Run Smart Selection and Advance Cursor', async () => {
return this.skip();
}
await initialize();
// Ensure the environments extension is not used for this test
// execSelectionInTerminal was not updated to use the envs extension API
// when execInTerminal was updated in commit e78934859
await vscode.workspace
.getConfiguration('python')
.update('useEnvironmentsExtension', false, vscode.ConfigurationTarget.Global);
return undefined;
});

Expand All @@ -35,33 +41,190 @@ suite('Smoke Test: Run Smart Selection and Advance Cursor', async () => {
'smart_send_smoke.txt',
);

console.log(`[smartSend.smoke] Test starting`);
console.log(`[smartSend.smoke] Python file: ${file}`);
console.log(`[smartSend.smoke] Output file: ${outputFile}`);
console.log(`[smartSend.smoke] Python file exists: ${await fs.pathExists(file)}`);

const outputFileExistsBefore = await fs.pathExists(outputFile);
console.log(`[smartSend.smoke] Output file exists before cleanup: ${outputFileExistsBefore}`);
await fs.remove(outputFile);
console.log(`[smartSend.smoke] Output file removed`);

const textDocument = await openFile(file);
console.log(`[smartSend.smoke] File opened in editor`);
console.log(`[smartSend.smoke] Document has ${textDocument.lineCount} lines`);
console.log(`[smartSend.smoke] First 5 lines of file:`);
for (let i = 0; i < Math.min(5, textDocument.lineCount); i++) {
console.log(`[smartSend.smoke] Line ${i}: ${textDocument.lineAt(i).text}`);
}

if (vscode.window.activeTextEditor) {
const myPos = new vscode.Position(0, 0);
vscode.window.activeTextEditor!.selections = [new vscode.Selection(myPos, myPos)];
// Select the entire file content to execute
// The implementation of execSelectionInTerminal with empty selection only runs the current line,
// not smart selection. So we need to select the actual code we want to execute.
const document = vscode.window.activeTextEditor.document;
const fullRange = new vscode.Range(
document.lineAt(0).range.start,
document.lineAt(document.lineCount - 1).range.end,
);
vscode.window.activeTextEditor.selection = new vscode.Selection(fullRange.start, fullRange.end);

const selectedText = vscode.window.activeTextEditor.document.getText(
vscode.window.activeTextEditor.selection,
);
console.log(
`[smartSend.smoke] Selected entire file (${selectedText.split('\n').length} lines, ${
selectedText.length
} chars)`,
);

// Wait a bit for the editor state to settle
console.log(`[smartSend.smoke] Waiting 500ms for editor state to settle...`);
await new Promise((resolve) => setTimeout(resolve, 500));
}

const terminalsBefore = vscode.window.terminals.length;
console.log(`[smartSend.smoke] Number of terminals before execution: ${terminalsBefore}`);

// On Windows, if terminals exist from previous tests, they may not be ready for new commands
// Give them time to fully initialize before sending commands
if (terminalsBefore > 0 && process.platform === 'win32') {
console.log(
`[smartSend.smoke] Windows detected with ${terminalsBefore} existing terminals, waiting 3s for terminal readiness...`,
);
await new Promise((resolve) => setTimeout(resolve, 3000));
}

// Verify the active editor is correct before executing command
if (vscode.window.activeTextEditor) {
console.log(
`[smartSend.smoke] Active editor before command: ${vscode.window.activeTextEditor.document.uri.fsPath}`,
);
console.log(
`[smartSend.smoke] Active editor language: ${vscode.window.activeTextEditor.document.languageId}`,
);
} else {
console.error(`[smartSend.smoke] ERROR: No active text editor before command!`);
}

const startTime = Date.now();
console.log(
`[smartSend.smoke] Executing first 'python.execSelectionInTerminal' command at ${new Date().toISOString()}`,
);
console.log(`[smartSend.smoke] Passing document URI to execSelectionInTerminal: ${textDocument.uri.fsPath}`);

await vscode.commands
.executeCommand<void>('python.execSelectionInTerminal', textDocument.uri)
.then(undefined, (err) => {
console.error(`[smartSend.smoke] First command failed: ${err}`);
assert.fail(`Something went wrong running the Python file in the terminal: ${err}`);
});
const firstCmdTime = Date.now();
console.log(`[smartSend.smoke] First command completed in ${firstCmdTime - startTime}ms`);

const checkIfFileHasBeenCreated = () => fs.pathExists(outputFile);
await waitForCondition(checkIfFileHasBeenCreated, 20_000, `"${outputFile}" file not created`);
// Check if smart selection changed the selection
if (vscode.window.activeTextEditor) {
const selectionAfterCmd = vscode.window.activeTextEditor.selection;
const selectedText = vscode.window.activeTextEditor.document.getText(selectionAfterCmd);
console.log(
`[smartSend.smoke] Selection after command - start: (${selectionAfterCmd.start.line}, ${selectionAfterCmd.start.character}), end: (${selectionAfterCmd.end.line}, ${selectionAfterCmd.end.character})`,
);
console.log(
`[smartSend.smoke] Selected text after command (first 100 chars): "${selectedText
.substring(0, 100)
.replace(/\n/g, '\\n')}"`,
);
console.log(
`[smartSend.smoke] Active editor document URI: ${vscode.window.activeTextEditor.document.uri.fsPath}`,
);
} else {
console.error(`[smartSend.smoke] WARNING: No active text editor after command execution!`);
}

const terminalsAfter = vscode.window.terminals.length;
console.log(`[smartSend.smoke] Number of terminals after first execution: ${terminalsAfter}`);
if (vscode.window.activeTerminal) {
console.log(`[smartSend.smoke] Active terminal name: ${vscode.window.activeTerminal.name}`);
}

// Add additional wait to allow terminal to start processing
// Windows may need more time for terminal to initialize and start executing
const isWindows = process.platform === 'win32';
const initialWaitTime = isWindows ? 2000 : 1000;
console.log(
`[smartSend.smoke] Waiting ${initialWaitTime}ms for terminal to start processing (isWindows: ${isWindows})...`,
);
await new Promise((resolve) => setTimeout(resolve, initialWaitTime));

// Verify the working directory matches expected
const expectedDir = path.dirname(outputFile);
console.log(`[smartSend.smoke] Expected output directory: ${expectedDir}`);
console.log(`[smartSend.smoke] Directory exists: ${await fs.pathExists(expectedDir)}`);

let checkCount = 0;
const checkIfFileHasBeenCreated = async () => {
checkCount++;
const exists = await fs.pathExists(outputFile);
if (checkCount % 100 === 0) {
// Log every 100 checks (~1 second)
const elapsed = Date.now() - startTime;
console.log(`[smartSend.smoke] File creation check #${checkCount} at ${elapsed}ms: ${exists}`);
}
return exists;
};

try {
await waitForCondition(checkIfFileHasBeenCreated, 20_000, `"${outputFile}" file not created`);
const createTime = Date.now() - startTime;
console.log(`[smartSend.smoke] SUCCESS: File created after ${createTime}ms (${checkCount} checks)`);
} catch (error) {
const totalTime = Date.now() - startTime;
console.error(`[smartSend.smoke] FAILURE: File not created after ${totalTime}ms (${checkCount} checks)`);
console.error(`[smartSend.smoke] Output file exists: ${await fs.pathExists(outputFile)}`);
console.error(`[smartSend.smoke] Number of terminals: ${vscode.window.terminals.length}`);

// Check final editor state
if (vscode.window.activeTextEditor) {
console.error(
`[smartSend.smoke] Final active editor: ${vscode.window.activeTextEditor.document.uri.fsPath}`,
);
const finalSelection = vscode.window.activeTextEditor.selection;
console.error(
`[smartSend.smoke] Final selection - start: (${finalSelection.start.line}, ${finalSelection.start.character}), end: (${finalSelection.end.line}, ${finalSelection.end.character})`,
);
}

// List directory contents
const dir = path.dirname(outputFile);
try {
const fsModule = await import('fs');
const files = fsModule.readdirSync(dir);
console.error(`[smartSend.smoke] Directory contents (${dir}):`, files);
} catch (e) {
console.error(`[smartSend.smoke] Failed to list directory: ${e}`);
}

throw error;
}

console.log(`[smartSend.smoke] Executing second 'python.execSelectionInTerminal' command`);
await vscode.commands
.executeCommand<void>('python.execSelectionInTerminal', textDocument.uri)
.then(undefined, (err) => {
console.error(`[smartSend.smoke] Second command failed: ${err}`);
assert.fail(`Something went wrong running the Python file in the terminal: ${err}`);
});
console.log(`[smartSend.smoke] Second command completed`);

console.log(`[smartSend.smoke] Executing third 'python.execSelectionInTerminal' command`);
await vscode.commands
.executeCommand<void>('python.execSelectionInTerminal', textDocument.uri)
.then(undefined, (err) => {
console.error(`[smartSend.smoke] Third command failed: ${err}`);
assert.fail(`Something went wrong running the Python file in the terminal: ${err}`);
});
console.log(`[smartSend.smoke] Third command completed`);

async function wait() {
return new Promise<void>((resolve) => {
Expand All @@ -71,12 +234,16 @@ suite('Smoke Test: Run Smart Selection and Advance Cursor', async () => {
});
}

console.log(`[smartSend.smoke] Waiting 10s for file deletion to complete...`);
await wait();

const deletedFile = !(await fs.pathExists(outputFile));
console.log(`[smartSend.smoke] File exists after deletion commands: ${!deletedFile}`);
if (deletedFile) {
console.log(`[smartSend.smoke] SUCCESS: File has been deleted as expected`);
assert.ok(true, `"${outputFile}" file has been deleted`);
} else {
console.error(`[smartSend.smoke] FAILURE: File still exists`);
assert.fail(`"${outputFile}" file still exists`);
}
});
Expand Down
21 changes: 18 additions & 3 deletions src/testMultiRootWkspc/smokeTests/create_delete_file.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
with open('smart_send_smoke.txt', 'w') as f:
f.write('This is for smart send smoke test')
import os

os.remove('smart_send_smoke.txt')
# Use absolute path to avoid working directory issues
script_dir = os.path.dirname(os.path.abspath(__file__))
file_path = os.path.join(script_dir, 'smart_send_smoke.txt')

# For debugging: print working directory and file path
print(f"Working directory: {os.getcwd()}", flush=True)
print(f"File path: {file_path}", flush=True)
print(f"Script location: {os.path.abspath(__file__)}", flush=True)

with open(file_path, 'w') as f:
f.write('This is for smart send smoke test')
f.flush() # Explicitly flush to ensure write completes

print(f"Successfully created {file_path}", flush=True)

print(f"About to delete {file_path}", flush=True)
os.remove(file_path)
print(f"Successfully deleted {file_path}", flush=True)
Loading
Loading