@@ -22,7 +22,6 @@ const {
22
22
MapPrototypeSet,
23
23
MathCeil,
24
24
ObjectKeys,
25
- ObjectHasOwn,
26
25
ObjectPrototypeIsPrototypeOf,
27
26
Promise,
28
27
SafeArrayIterator,
@@ -151,26 +150,14 @@ const OP_DETAILS = {
151
150
"op_ws_send_pong" : [ "send a message on a WebSocket" , "closing a `WebSocket` or `WebSocketStream`" ] ,
152
151
} ;
153
152
154
- function collectReliableOpMetrics ( ) {
155
- let metrics = core . metrics ( ) ;
156
- if ( metrics . opsDispatched > metrics . opsCompleted ) {
157
- // If there are still async ops pending, we drain the event loop to the
158
- // point where all ops that can return `Poll::Ready` have done so, to ensure
159
- // that any ops are ready because of user cleanup code are completed.
160
- const hasPendingWorkerOps = metrics . ops . op_host_recv_message && (
161
- metrics . ops . op_host_recv_message . opsDispatched >
162
- metrics . ops . op_host_recv_message . opsCompleted ||
163
- metrics . ops . op_host_recv_ctrl . opsDispatched >
164
- metrics . ops . op_host_recv_ctrl . opsCompleted
165
- ) ;
166
- return opSanitizerDelay ( hasPendingWorkerOps ) . then ( ( ) => {
167
- metrics = core . metrics ( ) ;
168
- const traces = new Map ( core . opCallTraces ) ;
169
- return { metrics, traces } ;
170
- } ) ;
171
- }
172
- const traces = new Map ( core . opCallTraces ) ;
173
- return { metrics, traces } ;
153
+ let opIdHostRecvMessage = - 1 ;
154
+ let opIdHostRecvCtrl = - 1 ;
155
+ let opNames = null ;
156
+
157
+ function populateOpNames ( ) {
158
+ opNames = core . ops . op_op_names ( ) ;
159
+ opIdHostRecvMessage = opNames . indexOf ( "op_host_recv_message" ) ;
160
+ opIdHostRecvCtrl = opNames . indexOf ( "op_host_recv_ctrl" ) ;
174
161
}
175
162
176
163
// Wrap test function in additional assertion that makes sure
@@ -181,50 +168,61 @@ function collectReliableOpMetrics() {
181
168
function assertOps ( fn ) {
182
169
/** @param desc {TestDescription | TestStepDescription} */
183
170
return async function asyncOpSanitizer ( desc ) {
184
- let metrics = collectReliableOpMetrics ( ) ;
185
- if ( metrics . then ) {
186
- // We're delaying so await to get the result asynchronously.
187
- metrics = await metrics ;
171
+ if ( opNames === null ) populateOpNames ( ) ;
172
+ const res = core . ops . op_test_op_sanitizer_collect (
173
+ desc . id ,
174
+ false ,
175
+ opIdHostRecvMessage ,
176
+ opIdHostRecvCtrl ,
177
+ ) ;
178
+ if ( res !== 0 ) {
179
+ await opSanitizerDelay ( res === 2 ) ;
180
+ core . ops . op_test_op_sanitizer_collect (
181
+ desc . id ,
182
+ true ,
183
+ opIdHostRecvMessage ,
184
+ opIdHostRecvCtrl ,
185
+ ) ;
188
186
}
189
- const { metrics : pre , traces : preTraces } = metrics ;
190
- let post ;
187
+ const preTraces = new Map ( core . opCallTraces ) ;
191
188
let postTraces ;
189
+ let report = null ;
192
190
193
191
try {
194
192
const innerResult = await fn ( desc ) ;
195
193
if ( innerResult ) return innerResult ;
196
194
} finally {
197
- let metrics = collectReliableOpMetrics ( ) ;
198
- if ( metrics . then ) {
199
- // We're delaying so await to get the result asynchronously.
200
- metrics = await metrics ;
195
+ let res = core . ops . op_test_op_sanitizer_finish (
196
+ desc . id ,
197
+ false ,
198
+ opIdHostRecvMessage ,
199
+ opIdHostRecvCtrl ,
200
+ ) ;
201
+ if ( res === 1 || res === 2 ) {
202
+ await opSanitizerDelay ( res === 2 ) ;
203
+ res = core . ops . op_test_op_sanitizer_finish (
204
+ desc . id ,
205
+ true ,
206
+ opIdHostRecvMessage ,
207
+ opIdHostRecvCtrl ,
208
+ ) ;
209
+ }
210
+ postTraces = new Map ( core . opCallTraces ) ;
211
+ if ( res === 3 ) {
212
+ report = core . ops . op_test_op_sanitizer_report ( desc . id ) ;
201
213
}
202
- ( { metrics : post , traces : postTraces } = metrics ) ;
203
214
}
204
215
205
- // We're checking diff because one might spawn HTTP server in the background
206
- // that will be a pending async op before test starts.
207
- const dispatchedDiff = post . opsDispatchedAsync - pre . opsDispatchedAsync ;
208
- const completedDiff = post . opsCompletedAsync - pre . opsCompletedAsync ;
209
-
210
- if ( dispatchedDiff === completedDiff ) return null ;
216
+ if ( report === null ) return null ;
211
217
212
218
const details = [ ] ;
213
- for ( const key in post . ops ) {
214
- if ( ! ObjectHasOwn ( post . ops , key ) ) {
215
- continue ;
216
- }
217
- const preOp = pre . ops [ key ] ??
218
- { opsDispatchedAsync : 0 , opsCompletedAsync : 0 } ;
219
- const postOp = post . ops [ key ] ;
220
- const dispatchedDiff = postOp . opsDispatchedAsync -
221
- preOp . opsDispatchedAsync ;
222
- const completedDiff = postOp . opsCompletedAsync -
223
- preOp . opsCompletedAsync ;
224
-
225
- if ( dispatchedDiff > completedDiff ) {
226
- const [ name , hint ] = OP_DETAILS [ key ] || [ key , null ] ;
227
- const count = dispatchedDiff - completedDiff ;
219
+ for ( const opReport of report ) {
220
+ const opName = opNames [ opReport . id ] ;
221
+ const diff = opReport . diff ;
222
+
223
+ if ( diff > 0 ) {
224
+ const [ name , hint ] = OP_DETAILS [ opName ] || [ opName , null ] ;
225
+ const count = diff ;
228
226
let message = `${ count } async operation${
229
227
count === 1 ? "" : "s"
230
228
} to ${ name } ${
@@ -234,8 +232,8 @@ function assertOps(fn) {
234
232
message += ` This is often caused by not ${ hint } .` ;
235
233
}
236
234
const traces = [ ] ;
237
- for ( const [ id , { opName, stack } ] of postTraces ) {
238
- if ( opName !== key ) continue ;
235
+ for ( const [ id , { opName : traceOpName , stack } ] of postTraces ) {
236
+ if ( traceOpName !== opName ) continue ;
239
237
if ( MapPrototypeHas ( preTraces , id ) ) continue ;
240
238
ArrayPrototypePush ( traces , stack ) ;
241
239
}
@@ -247,9 +245,9 @@ function assertOps(fn) {
247
245
message += ArrayPrototypeJoin ( traces , "\n\n" ) ;
248
246
}
249
247
ArrayPrototypePush ( details , message ) ;
250
- } else if ( dispatchedDiff < completedDiff ) {
251
- const [ name , hint ] = OP_DETAILS [ key ] || [ key , null ] ;
252
- const count = completedDiff - dispatchedDiff ;
248
+ } else if ( diff < 0 ) {
249
+ const [ name , hint ] = OP_DETAILS [ opName ] || [ opName , null ] ;
250
+ const count = - diff ;
253
251
let message = `${ count } async operation${
254
252
count === 1 ? "" : "s"
255
253
} to ${ name } ${
@@ -261,8 +259,8 @@ function assertOps(fn) {
261
259
message += ` This is often caused by not ${ hint } .` ;
262
260
}
263
261
const traces = [ ] ;
264
- for ( const [ id , { opName, stack } ] of preTraces ) {
265
- if ( opName !== key ) continue ;
262
+ for ( const [ id , { opName : traceOpName , stack } ] of preTraces ) {
263
+ if ( opName !== traceOpName ) continue ;
266
264
if ( MapPrototypeHas ( postTraces , id ) ) continue ;
267
265
ArrayPrototypePush ( traces , stack ) ;
268
266
}
@@ -274,6 +272,8 @@ function assertOps(fn) {
274
272
message += ArrayPrototypeJoin ( traces , "\n\n" ) ;
275
273
}
276
274
ArrayPrototypePush ( details , message ) ;
275
+ } else {
276
+ throw new Error ( "unreachable" ) ;
277
277
}
278
278
}
279
279
0 commit comments