From 01af3d50d91583a904d9aab8b849d0646338b41e Mon Sep 17 00:00:00 2001 From: Anton Golub Date: Tue, 21 May 2024 10:46:38 +0300 Subject: [PATCH] feat: expose signal prop from ProcessPromise (#816) * feat: provide format methods for `ProcessPromise` continues #811 relates #764 * feat: expose abortion signal from `ProcessPromise` --- src/core.ts | 9 ++++++++- test/core.test.js | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/src/core.ts b/src/core.ts index 80a1009290..aa6cf9bfdc 100644 --- a/src/core.ts +++ b/src/core.ts @@ -238,7 +238,7 @@ export class ProcessPromise extends Promise { this._from = from this._resolve = resolve this._reject = reject - this._snapshot = { ...options } + this._snapshot = { ac: new AbortController(), ...options } } run(): ProcessPromise { @@ -448,12 +448,19 @@ export class ProcessPromise extends Promise { } abort(reason?: string) { + if (this.signal !== this._snapshot.ac?.signal) + throw new Error('The signal is controlled by another process.') + if (!this.child) throw new Error('Trying to abort a process without creating one.') this._zurk?.ac.abort(reason) } + get signal() { + return this._snapshot.signal || this._snapshot.ac?.signal + } + async kill(signal = 'SIGTERM'): Promise { if (!this.child) throw new Error('Trying to kill a process without creating one.') diff --git a/test/core.test.js b/test/core.test.js index 515670e660..4904b70cfd 100644 --- a/test/core.test.js +++ b/test/core.test.js @@ -358,6 +358,45 @@ describe('core', () => { assert.match(message, /The operation was aborted/) } }) + + test('exposes `signal` property', async () => { + const ac = new AbortController() + const p = $({ ac, detached: true })`echo test` + + assert.equal(p.signal, ac.signal) + await p + }) + + test('throws if the signal was previously aborted', async () => { + const ac = new AbortController() + const { signal } = ac + ac.abort('reason') + + try { + await $({ signal, detached: true })`sleep 999` + } catch ({ message }) { + assert.match(message, /The operation was aborted/) + } + }) + + test('throws if the signal is controlled by another process', async () => { + const ac = new AbortController() + const { signal } = ac + const p = $({ signal })`sleep 999` + + try { + p.abort() + } catch ({ message }) { + assert.match(message, /The signal is controlled by another process./) + } + + try { + ac.abort() + await p + } catch ({ message }) { + assert.match(message, /The operation was aborted/) + } + }) }) describe('kill()', () => {