fix: ensure the inspector agent is shutdown before cleaning up the node env (#18028)

* fix: ensure the inspector agent is shutdown before cleaning up the node env

* spec: add tests to ensure clean shutdown with connected inspector agent

* Update node_debugger.cc
This commit is contained in:
Samuel Attard 2019-04-30 15:44:40 -07:00 коммит произвёл GitHub
Родитель 4e5a0946c7
Коммит 67b3fbca89
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
6 изменённых файлов: 55 добавлений и 2 удалений

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

@ -101,6 +101,7 @@ int NodeMain(int argc, char* argv[]) {
}
} while (more == true);
node_debugger.Stop();
exit_code = node::EmitExit(env);
node::RunAtExit(env);
gin_env.platform()->DrainTasks(env->isolate());

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

@ -452,6 +452,7 @@ void AtomBrowserMainParts::PostMainMessageLoopRun() {
ui::SetX11ErrorHandlers(X11EmptyErrorHandler, X11EmptyIOErrorHandler);
#endif
node_debugger_->Stop();
js_env_->OnMessageLoopDestroying();
#if defined(OS_MACOSX)

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

@ -58,4 +58,10 @@ void NodeDebugger::Start() {
DCHECK(env_->inspector_agent()->IsListening());
}
void NodeDebugger::Stop() {
auto* inspector = env_->inspector_agent();
if (inspector && inspector->IsListening())
inspector->Stop();
}
} // namespace atom

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

@ -20,6 +20,7 @@ class NodeDebugger {
~NodeDebugger();
void Start();
void Stop();
private:
node::Environment* env_;

3
spec/fixtures/module/delay-exit.js поставляемый Normal file
Просмотреть файл

@ -0,0 +1,3 @@
const { app } = require('electron')
process.on('message', () => app.quit())

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

@ -8,6 +8,8 @@ const os = require('os')
const { ipcRenderer, remote } = require('electron')
const features = process.electronBinding('features')
const { emittedOnce } = require('./events-helpers')
const isCI = remote.getGlobal('isCi')
chai.use(dirtyChai)
@ -231,6 +233,7 @@ describe('node feature', () => {
describe('inspector', () => {
let child = null
let exitPromise = null
beforeEach(function () {
if (!features.isRunAsNodeEnabled()) {
@ -238,8 +241,14 @@ describe('node feature', () => {
}
})
afterEach(() => {
if (child !== null) child.kill()
afterEach(async () => {
if (child && exitPromise) {
const [code, signal] = await exitPromise
expect(signal).to.equal(null)
expect(code).to.equal(0)
} else if (child) {
child.kill()
}
})
it('supports starting the v8 inspector with --inspect/--inspect-brk', (done) => {
@ -275,6 +284,7 @@ describe('node feature', () => {
ELECTRON_RUN_AS_NODE: true
}
})
exitPromise = emittedOnce(child, 'exit')
let output = ''
function cleanup () {
@ -299,6 +309,7 @@ describe('node feature', () => {
it('does not start the v8 inspector when --inspect is after a -- argument', (done) => {
child = ChildProcess.spawn(remote.process.execPath, [path.join(__dirname, 'fixtures', 'module', 'noop.js'), '--', '--inspect'])
exitPromise = emittedOnce(child, 'exit')
let output = ''
function dataListener (data) {
@ -315,6 +326,35 @@ describe('node feature', () => {
})
})
it('does does not crash when quitting with the inspector connected', function (done) {
// IPC Electron child process not supported on Windows
if (process.platform === 'win32') return this.skip()
child = ChildProcess.spawn(remote.process.execPath, [path.join(__dirname, 'fixtures', 'module', 'delay-exit'), '--inspect=0'], {
stdio: ['ipc']
})
exitPromise = emittedOnce(child, 'exit')
let output = ''
function dataListener (data) {
output += data
if (output.trim().startsWith('Debugger listening on ws://') && output.endsWith('\n')) {
const socketMatch = output.trim().match(/(ws:\/\/.+:[0-9]+\/.+?)\n/gm)
if (socketMatch && socketMatch[0]) {
child.stderr.removeListener('data', dataListener)
child.stdout.removeListener('data', dataListener)
const connection = new WebSocket(socketMatch[0])
connection.onopen = () => {
child.send('plz-quit')
done()
}
}
}
}
child.stderr.on('data', dataListener)
child.stdout.on('data', dataListener)
})
it('supports js binding', (done) => {
child = ChildProcess.spawn(process.execPath, ['--inspect', path.join(__dirname, 'fixtures', 'module', 'inspector-binding.js')], {
env: {
@ -322,6 +362,7 @@ describe('node feature', () => {
},
stdio: ['ipc']
})
exitPromise = emittedOnce(child, 'exit')
child.on('message', ({ cmd, debuggerEnabled, success }) => {
if (cmd === 'assert') {