-
Notifications
You must be signed in to change notification settings - Fork 163
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Do not allow abort to happen when a close is about to happen #634
Closed
+59
−55
Closed
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -175,22 +175,25 @@ promise_test(t => { | |
return writePromise; | ||
}, 'Aborting a WritableStream causes any outstanding write() promises to be rejected with a TypeError'); | ||
|
||
promise_test(t => { | ||
const ws = new WritableStream(); | ||
promise_test(() => { | ||
const ws = recordingWritableStream(); | ||
const writer = ws.getWriter(); | ||
|
||
const closePromise = writer.close(); | ||
writer.abort(error1); | ||
const abortPromise = writer.abort(error1); | ||
|
||
return Promise.all([ | ||
promise_rejects(t, new TypeError(), writer.closed, 'closed should reject with a TypeError'), | ||
promise_rejects(t, new TypeError(), closePromise, 'close() should reject with a TypeError') | ||
]); | ||
}, 'Closing but then immediately aborting a WritableStream causes the stream to error'); | ||
writer.closed, | ||
closePromise, | ||
abortPromise | ||
]).then(() => { | ||
assert_array_equals(ws.events, ['close']); | ||
}); | ||
}, 'Closing but then immediately aborting a WritableStream results in a successful close and a fulfilled abort()'); | ||
|
||
promise_test(t => { | ||
promise_test(() => { | ||
let resolveClose; | ||
const ws = new WritableStream({ | ||
const ws = recordingWritableStream({ | ||
close() { | ||
return new Promise(resolve => { | ||
resolveClose = resolve; | ||
|
@@ -202,14 +205,20 @@ promise_test(t => { | |
const closePromise = writer.close(); | ||
|
||
return delay(0).then(() => { | ||
writer.abort(error1); | ||
const abortPromise = writer.abort(error1); | ||
resolveClose(); | ||
|
||
return Promise.all([ | ||
promise_rejects(t, new TypeError(), writer.closed, 'closed should reject with a TypeError'), | ||
closePromise | ||
]); | ||
writer.closed, | ||
closePromise, | ||
abortPromise | ||
]) | ||
.then(() => { | ||
assert_array_equals(ws.events, ['close']); | ||
}); | ||
}); | ||
}, 'Closing a WritableStream and aborting it while it closes causes the stream to error'); | ||
}, 'Closing a WritableStream and aborting it while it is in the process of closing results in a successful close and ' + | ||
'fulfilled abort()'); | ||
|
||
promise_test(() => { | ||
const ws = new WritableStream(); | ||
|
@@ -359,41 +368,35 @@ promise_test(t => { | |
|
||
promise_test(() => { | ||
let resolveWrite; | ||
let abort_called = false; | ||
const ws = new WritableStream({ | ||
const ws = recordingWritableStream({ | ||
write() { | ||
return new Promise(resolve => { | ||
resolveWrite = resolve; | ||
}); | ||
}, | ||
abort() { | ||
abort_called = true; | ||
} | ||
}); | ||
|
||
const writer = ws.getWriter(); | ||
return writer.ready.then(() => { | ||
writer.write('a'); | ||
const abortPromise = writer.abort(); | ||
const abortPromise = writer.abort('b'); | ||
return flushAsyncEvents().then(() => { | ||
assert_false(abort_called, 'abort should not be called while write is pending'); | ||
assert_array_equals(ws.events, ['write', 'a'], 'abort should not be called while write is pending'); | ||
resolveWrite(); | ||
return abortPromise.then(() => assert_true(abort_called, 'abort should be called')); | ||
return abortPromise.then(() => { | ||
assert_array_equals(ws.events, ['write', 'a', 'abort', 'b'], 'abort should be called after the write finishes'); | ||
}); | ||
}); | ||
}); | ||
}, 'underlying abort() should not be called until underlying write() completes'); | ||
|
||
promise_test(() => { | ||
let resolveClose; | ||
let abort_called = false; | ||
const ws = new WritableStream({ | ||
const ws = recordingWritableStream({ | ||
close() { | ||
return new Promise(resolve => { | ||
resolveClose = resolve; | ||
}); | ||
}, | ||
abort() { | ||
abort_called = true; | ||
} | ||
}); | ||
|
||
|
@@ -402,56 +405,59 @@ promise_test(() => { | |
writer.close(); | ||
const abortPromise = writer.abort(); | ||
return flushAsyncEvents().then(() => { | ||
assert_false(abort_called, 'abort should not be called while close is pending'); | ||
assert_array_equals(ws.events, ['close'], 'abort should not be called while close is pending'); | ||
resolveClose(); | ||
return abortPromise.then(() => assert_false(abort_called, 'abort should not be called after close completes')); | ||
return abortPromise.then(() => { | ||
assert_array_equals(ws.events, ['close'], 'abort should not be called while close is pending'); | ||
}); | ||
}); | ||
}); | ||
}, 'underlying abort() should not be called if underlying close() has started'); | ||
|
||
promise_test(t => { | ||
let resolveWrite; | ||
let abort_called = false; | ||
const ws = new WritableStream({ | ||
const ws = recordingWritableStream({ | ||
write() { | ||
return new Promise(resolve => { | ||
resolveWrite = resolve; | ||
}); | ||
}, | ||
abort() { | ||
abort_called = true; | ||
} | ||
}); | ||
|
||
const writer = ws.getWriter(); | ||
return writer.ready.then(() => { | ||
writer.write('a'); | ||
const closePromise = writer.close(); | ||
const abortPromise = writer.abort(); | ||
const abortPromise = writer.abort('b'); | ||
|
||
return flushAsyncEvents().then(() => { | ||
assert_false(abort_called, 'abort should not be called while write is pending'); | ||
assert_array_equals(ws.events, ['write', 'a'], 'abort should not be called while write is pending'); | ||
resolveWrite(); | ||
return abortPromise.then(() => { | ||
assert_true(abort_called, 'abort should be called after write completes'); | ||
assert_array_equals(ws.events, ['write', 'a', 'abort', 'b'], 'abort should be called after write completes'); | ||
return promise_rejects(t, new TypeError(), closePromise, 'promise returned by close() should be rejected'); | ||
}); | ||
}); | ||
}); | ||
}, 'underlying abort() should be called while closing if underlying close() has not started yet'); | ||
}, 'an abort() that happens during a write() should trigger the underlying abort() even with a close() queued'); | ||
|
||
promise_test(() => { | ||
const ws = new WritableStream(); | ||
const writer = ws.getWriter(); | ||
return writer.ready.then(() => { | ||
const closePromise = writer.close(); | ||
const abortPromise = writer.abort(); | ||
let closeResolved = false; | ||
Promise.all([ | ||
closePromise.then(() => { closeResolved = true; }), | ||
abortPromise.then(() => { assert_true(closeResolved, 'close() promise should resolve before abort() promise'); }) | ||
]); | ||
const ordering = []; | ||
|
||
return Promise.all([ | ||
closePromise.then(() => { ordering.push('close'); }), | ||
abortPromise.then(() => { ordering.push('abort'); }) | ||
]) | ||
.then(() => { | ||
assert_array_equals(ordering, ['abort', 'close']); | ||
}); | ||
}); | ||
}, 'writer close() promise should resolve before abort() promise'); | ||
}, 'writer abort() promise should fulfill before close() promise (since it bails early)'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not keen on this behaviour. Usually we can rely on abort() to tell us whether the stream was cleaned up or not, but in this case we can't. |
||
|
||
promise_test(t => { | ||
const ws = new WritableStream({ | ||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
close is no longer pending here. Perhaps go back to 'after close completes' wording?