@@ -37,7 +37,10 @@ function getExportNameAndPath(sessionId: string, timestamp: number) {
37
37
} ;
38
38
}
39
39
40
- function createDummyFindCursor ( dataArray : unknown [ ] , chunkPushTimeoutMs ?: number ) : FindCursor {
40
+ function createDummyFindCursor (
41
+ dataArray : unknown [ ] ,
42
+ chunkPushTimeoutMs ?: number
43
+ ) : { cursor : FindCursor ; cursorCloseNotification : Promise < void > } {
41
44
let index = 0 ;
42
45
const readable = new Readable ( {
43
46
objectMode : true ,
@@ -56,14 +59,26 @@ function createDummyFindCursor(dataArray: unknown[], chunkPushTimeoutMs?: number
56
59
} ,
57
60
} ) ;
58
61
62
+ let notifyClose : ( ) => Promise < void > ;
63
+ const cursorCloseNotification = new Promise < void > ( ( resolve ) => {
64
+ notifyClose = async ( ) => {
65
+ await timeout ( 10 ) ;
66
+ resolve ( ) ;
67
+ } ;
68
+ } ) ;
69
+ readable . once ( "close" , ( ) => void notifyClose ?.( ) ) ;
70
+
59
71
return {
60
- stream ( ) {
61
- return readable ;
62
- } ,
63
- close ( ) {
64
- return Promise . resolve ( readable . destroy ( ) ) ;
65
- } ,
66
- } as unknown as FindCursor ;
72
+ cursor : {
73
+ stream ( ) {
74
+ return readable ;
75
+ } ,
76
+ close ( ) {
77
+ return Promise . resolve ( readable . destroy ( ) ) ;
78
+ } ,
79
+ } as unknown as FindCursor ,
80
+ cursorCloseNotification,
81
+ } ;
67
82
}
68
83
69
84
async function fileExists ( filePath : string ) {
@@ -92,21 +107,22 @@ describe("SessionExportsManager unit test", () => {
92
107
// This export will finish in at-least 1 second
93
108
const { exportName : exportName1 } = getExportNameAndPath ( session . sessionId , Date . now ( ) ) ;
94
109
manager . createJSONExport ( {
95
- input : createDummyFindCursor ( [ { name : "Test1" } ] , 1000 ) ,
110
+ input : createDummyFindCursor ( [ { name : "Test1" } ] , 1000 ) . cursor ,
96
111
exportName : exportName1 ,
97
112
jsonExportFormat : "relaxed" ,
98
113
} ) ;
99
114
100
115
// This export will finish way sooner than the first one
101
116
const { exportName : exportName2 } = getExportNameAndPath ( session . sessionId , Date . now ( ) ) ;
117
+ const { cursor, cursorCloseNotification } = createDummyFindCursor ( [ { name : "Test1" } ] ) ;
102
118
manager . createJSONExport ( {
103
- input : createDummyFindCursor ( [ { name : "Test1" } ] ) ,
119
+ input : cursor ,
104
120
exportName : exportName2 ,
105
121
jsonExportFormat : "relaxed" ,
106
122
} ) ;
107
123
108
124
// Small timeout to let the second export finish
109
- await timeout ( 10 ) ;
125
+ await cursorCloseNotification ;
110
126
expect ( manager . availableExports ) . toHaveLength ( 1 ) ;
111
127
expect ( manager . availableExports [ 0 ] ?. exportName ) . toEqual ( exportName2 ) ;
112
128
} ) ;
@@ -119,42 +135,40 @@ describe("SessionExportsManager unit test", () => {
119
135
120
136
it ( "should throw if the resource is still being generated" , async ( ) => {
121
137
const { exportName } = getExportNameAndPath ( session . sessionId , Date . now ( ) ) ;
122
- const inputCursor = createDummyFindCursor ( [ { name : "Test1" } ] , 100 ) ;
138
+ const { cursor } = createDummyFindCursor ( [ { name : "Test1" } ] , 100 ) ;
123
139
manager . createJSONExport ( {
124
- input : inputCursor ,
140
+ input : cursor ,
125
141
exportName,
126
142
jsonExportFormat : "relaxed" ,
127
143
} ) ;
128
- // Small timeout but it won't be sufficient and the export
129
- // generation will still be in progress
130
- await timeout ( 10 ) ;
144
+ // note that we do not wait for cursor close
131
145
await expect ( ( ) => manager . readExport ( exportName ) ) . rejects . toThrow (
132
146
"Requested export is still being generated!"
133
147
) ;
134
148
} ) ;
135
149
136
150
it ( "should return the resource content if the resource is ready to be consumed" , async ( ) => {
137
151
const { exportName } = getExportNameAndPath ( session . sessionId , Date . now ( ) ) ;
138
- const inputCursor = createDummyFindCursor ( [ ] ) ;
152
+ const { cursor , cursorCloseNotification } = createDummyFindCursor ( [ ] ) ;
139
153
manager . createJSONExport ( {
140
- input : inputCursor ,
154
+ input : cursor ,
141
155
exportName,
142
156
jsonExportFormat : "relaxed" ,
143
157
} ) ;
144
- // Small timeout to account for async operation
145
- await timeout ( 10 ) ;
158
+ await cursorCloseNotification ;
146
159
expect ( await manager . readExport ( exportName ) ) . toEqual ( "[]" ) ;
147
160
} ) ;
148
161
} ) ;
149
162
150
163
describe ( "#createJSONExport" , ( ) => {
151
- let inputCursor : FindCursor ;
164
+ let cursor : FindCursor ;
165
+ let cursorCloseNotification : Promise < void > ;
152
166
let exportName : string ;
153
167
let exportPath : string ;
154
168
let exportURI : string ;
155
169
beforeEach ( ( ) => {
156
- void inputCursor ?. close ( ) ;
157
- inputCursor = createDummyFindCursor ( [
170
+ void cursor ?. close ( ) ;
171
+ ( { cursor , cursorCloseNotification } = createDummyFindCursor ( [
158
172
{
159
173
name : "foo" ,
160
174
longNumber : Long . fromNumber ( 12 ) ,
@@ -163,22 +177,21 @@ describe("SessionExportsManager unit test", () => {
163
177
name : "bar" ,
164
178
longNumber : Long . fromNumber ( 123456 ) ,
165
179
} ,
166
- ] ) ;
180
+ ] ) ) ;
167
181
( { exportName, exportPath, exportURI } = getExportNameAndPath ( session . sessionId , Date . now ( ) ) ) ;
168
182
} ) ;
169
183
170
184
describe ( "when cursor is empty" , ( ) => {
171
185
it ( "should create an empty export" , async ( ) => {
172
- inputCursor = createDummyFindCursor ( [ ] ) ;
186
+ const { cursor , cursorCloseNotification } = createDummyFindCursor ( [ ] ) ;
173
187
174
188
const emitSpy = vi . spyOn ( manager , "emit" ) ;
175
189
manager . createJSONExport ( {
176
- input : inputCursor ,
190
+ input : cursor ,
177
191
exportName,
178
192
jsonExportFormat : "relaxed" ,
179
193
} ) ;
180
- // Small timeout to account for async operation
181
- await timeout ( 10 ) ;
194
+ await cursorCloseNotification ;
182
195
183
196
// Updates available export
184
197
const availableExports = manager . availableExports ;
@@ -206,12 +219,11 @@ describe("SessionExportsManager unit test", () => {
206
219
it ( "should export relaxed json, update available exports and emit export-available event" , async ( ) => {
207
220
const emitSpy = vi . spyOn ( manager , "emit" ) ;
208
221
manager . createJSONExport ( {
209
- input : inputCursor ,
222
+ input : cursor ,
210
223
exportName,
211
224
jsonExportFormat : "relaxed" ,
212
225
} ) ;
213
- // Small timeout to account for async operation
214
- await timeout ( 10 ) ;
226
+ await cursorCloseNotification ;
215
227
216
228
const expectedExportName = exportName . endsWith ( ".json" ) ? exportName : `${ exportName } .json` ;
217
229
// Updates available export
@@ -241,12 +253,11 @@ describe("SessionExportsManager unit test", () => {
241
253
it ( "should export canonical json, update available exports and emit export-available event" , async ( ) => {
242
254
const emitSpy = vi . spyOn ( manager , "emit" ) ;
243
255
manager . createJSONExport ( {
244
- input : inputCursor ,
256
+ input : cursor ,
245
257
exportName,
246
258
jsonExportFormat : "canonical" ,
247
259
} ) ;
248
- // Small timeout to account for async operation
249
- await timeout ( 50 ) ;
260
+ await cursorCloseNotification ;
250
261
251
262
const expectedExportName = exportName . endsWith ( ".json" ) ? exportName : `${ exportName } .json` ;
252
263
// Updates available export
@@ -302,12 +313,11 @@ describe("SessionExportsManager unit test", () => {
302
313
} ) ;
303
314
} ;
304
315
manager . createJSONExport ( {
305
- input : inputCursor ,
316
+ input : cursor ,
306
317
exportName,
307
318
jsonExportFormat : "relaxed" ,
308
319
} ) ;
309
- // Small timeout to account for async operation
310
- await timeout ( 50 ) ;
320
+ await cursorCloseNotification ;
311
321
312
322
// Because the export was never populated in the available exports.
313
323
await expect ( ( ) => manager . readExport ( exportName ) ) . rejects . toThrow (
@@ -321,10 +331,11 @@ describe("SessionExportsManager unit test", () => {
321
331
} ) ;
322
332
323
333
describe ( "#cleanupExpiredExports" , ( ) => {
324
- let input : FindCursor ;
334
+ let cursor : FindCursor ;
335
+ let cursorCloseNotification : Promise < void > ;
325
336
beforeEach ( ( ) => {
326
- void input ?. close ( ) ;
327
- input = createDummyFindCursor ( [
337
+ void cursor ?. close ( ) ;
338
+ ( { cursor , cursorCloseNotification } = createDummyFindCursor ( [
328
339
{
329
340
name : "foo" ,
330
341
longNumber : Long . fromNumber ( 12 ) ,
@@ -333,7 +344,7 @@ describe("SessionExportsManager unit test", () => {
333
344
name : "bar" ,
334
345
longNumber : Long . fromNumber ( 123456 ) ,
335
346
} ,
336
- ] ) ;
347
+ ] ) ) ;
337
348
} ) ;
338
349
339
350
it ( "should not clean up in-progress exports" , async ( ) => {
@@ -347,8 +358,9 @@ describe("SessionExportsManager unit test", () => {
347
358
} ,
348
359
new CompositeLogger ( )
349
360
) ;
361
+ const { cursor } = createDummyFindCursor ( [ { name : "Test" } ] , 2000 ) ;
350
362
manager . createJSONExport ( {
351
- input : createDummyFindCursor ( [ { name : "Test" } ] , 2000 ) ,
363
+ input : cursor ,
352
364
exportName,
353
365
jsonExportFormat : "relaxed" ,
354
366
} ) ;
@@ -374,13 +386,11 @@ describe("SessionExportsManager unit test", () => {
374
386
new CompositeLogger ( )
375
387
) ;
376
388
manager . createJSONExport ( {
377
- input,
389
+ input : cursor ,
378
390
exportName,
379
391
jsonExportFormat : "relaxed" ,
380
392
} ) ;
381
- // Small timeout to account for async operation and let export
382
- // finish
383
- await timeout ( 10 ) ;
393
+ await cursorCloseNotification ;
384
394
385
395
expect ( manager . availableExports ) . toContainEqual (
386
396
expect . objectContaining ( {
0 commit comments