Commit 01af3d5
Changed files (2)
src
test
src/core.ts
@@ -238,7 +238,7 @@ export class ProcessPromise extends Promise<ProcessOutput> {
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<ProcessOutput> {
}
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<void> {
if (!this.child)
throw new Error('Trying to kill a process without creating one.')
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()', () => {