Fix Chrome not being killed when disconnecting while it's paused

- And tests not killing chrome
- And the launch test mocking the wrong thing
This commit is contained in:
Rob Lourens 2017-04-11 22:51:53 -07:00
Родитель fd7e7f6fd1
Коммит cdfd7b81bc
2 изменённых файлов: 31 добавлений и 17 удалений

Просмотреть файл

@ -6,7 +6,7 @@ import * as os from 'os';
import * as path from 'path';
import {ChromeDebugAdapter as CoreDebugAdapter, logger, utils as coreUtils, ISourceMapPathOverrides, stoppedEvent} from 'vscode-chrome-debug-core';
import {spawn, ChildProcess, fork, exec} from 'child_process';
import {spawn, ChildProcess, fork, execSync} from 'child_process';
import Crdp from 'chrome-remote-debug-protocol';
import {DebugProtocol} from 'vscode-debugprotocol';
@ -146,13 +146,19 @@ export class ChromeDebugAdapter extends CoreDebugAdapter {
}
public disconnect(): void {
if (this._chromeProc && !this._hasTerminated) {
const hadTerminated = this._hasTerminated;
// Disconnect before killing Chrome, because running "taskkill" when it's paused sometimes doesn't kill it
super.disconnect();
if (this._chromeProc && !hadTerminated) {
// Only kill Chrome if the 'disconnect' originated from vscode. If we previously terminated
// due to Chrome shutting down, or devtools taking over, don't kill Chrome.
if (coreUtils.getPlatform() === coreUtils.Platform.Windows && this._chromePID) {
// Run synchronously because this process may be killed before exec() would run
const taskkillCmd = `taskkill /F /T /PID ${this._chromePID}`;
logger.log(`Killing Chrome process by pid: ${taskkillCmd}`);
exec(taskkillCmd, (err, stdout, stderr) => { });
execSync(taskkillCmd);
} else {
logger.log('Killing Chrome process');
this._chromeProc.kill('SIGINT');
@ -160,8 +166,6 @@ export class ChromeDebugAdapter extends CoreDebugAdapter {
}
this._chromeProc = null;
return super.disconnect();
}
/**
@ -173,8 +177,7 @@ export class ChromeDebugAdapter extends CoreDebugAdapter {
private spawnChrome(chromePath: string, chromeArgs: string[]): ChildProcess {
if (coreUtils.getPlatform() === coreUtils.Platform.Windows) {
const spawnChromePath = path.join(__dirname, 'chromeSpawnHelper.js');
const chromeProc = fork(spawnChromePath, [chromePath, ...chromeArgs], { execArgv: [], silent: true });
const chromeProc = fork(getChromeSpawnHelperPath(), [chromePath, ...chromeArgs], { execArgv: [], silent: true });
chromeProc.unref();
chromeProc.on('message', data => {
@ -237,3 +240,12 @@ export function resolveWebRootPattern(webRoot: string, sourceMapPathOverrides: I
return resolvedOverrides;
}
function getChromeSpawnHelperPath(): string {
if (path.basename(__dirname) === 'src') {
// For tests
return path.join(__dirname, '../chromeSpawnHelper.js');
} else {
return path.join(__dirname, 'chromeSpawnHelper.js');
}
}

Просмотреть файл

@ -68,33 +68,35 @@ suite('ChromeDebugAdapter', () => {
});
suite('launch()', () => {
let originalSpawn: any;
let originalFork: any;
let originalStatSync: any;
teardown(() => {
// Hacky mock cleanup
require('child_process').spawn = originalSpawn;
require('child_process').spawn = originalFork;
require('fs').statSync = originalStatSync;
})
test('launches with minimal correct args', () => {
let spawnCalled = false;
function spawn(chromePath: string, args: string[]): any {
let forkCalled = false;
function fork(chromeSpawnHelperPath: string, [chromePath, ...args]: string[]): any {
// Just assert that the chrome path is some string with 'chrome' in the path, and there are >0 args
assert(chromeSpawnHelperPath.indexOf('chromeSpawnHelper.js') >= 0);
assert(chromePath.toLowerCase().indexOf('chrome') >= 0);
assert(args.indexOf('--remote-debugging-port=9222') >= 0);
assert(args.indexOf('file:///c:/path%20with%20space/index.html') >= 0);
assert(args.indexOf('abc') >= 0);
assert(args.indexOf('def') >= 0);
spawnCalled = true;
forkCalled = true;
return { on: () => { }, unref: () => { } };
const stdio = { on: () => { } };
return { on: () => { }, unref: () => { }, stdout: stdio, stderr: stdio };
}
// Mock spawn for chrome process, and 'fs' for finding chrome.exe.
// Mock fork for chrome process, and 'fs' for finding chrome.exe.
// These are mocked as empty above - note that it's too late for mockery here.
originalSpawn = require('child_process').spawn;
require('child_process').spawn = spawn;
originalFork = require('child_process').fork;
require('child_process').fork = fork;
originalStatSync = require('fs').statSync;
require('fs').statSync = () => true;
@ -108,7 +110,7 @@ suite('ChromeDebugAdapter', () => {
.returns(() => Promise.resolve<any>({ result: { type: 'string', value: '123' }}));
return chromeDebugAdapter.launch({ file: 'c:\\path with space\\index.html', runtimeArgs: ['abc', 'def'] })
.then(() => assert(spawnCalled));
.then(() => assert(forkCalled));
});
});