@@ -61,251 +61,293 @@ describe.each([[StoreType.Memory], [StoreType.IndexedDB]])("queueToDevice (%s st
61
61
let httpBackend : MockHttpBackend ;
62
62
let client : MatrixClient ;
63
63
64
- beforeEach ( async function ( ) {
65
- jest . runOnlyPendingTimers ( ) ;
66
- jest . useRealTimers ( ) ;
67
- httpBackend = new MockHttpBackend ( ) ;
68
-
69
- let store : IStore ;
70
- if ( storeType === StoreType . IndexedDB ) {
71
- const idbStore = new IndexedDBStore ( { indexedDB : fakeIndexedDB } ) ;
72
- await idbStore . startup ( ) ;
73
- store = idbStore ;
74
- } else {
75
- store = new MemoryStore ( ) ;
76
- }
77
-
78
- client = new MatrixClient ( {
79
- baseUrl : "https://my.home.server" ,
80
- accessToken : "my.access.token" ,
81
- fetchFn : httpBackend . fetchFn as typeof global . fetch ,
82
- store,
64
+ /**
65
+ * We need to split the tests into regular ones (these) and ones that use fake timers,
66
+ * because the fake indexeddb uses timers too and appears make tests cause other tests
67
+ * to fail if we keep enabling/disabling fake timers within the same test suite.
68
+ */
69
+ describe ( "non-timed tests" , ( ) => {
70
+ beforeEach ( async function ( ) {
71
+ httpBackend = new MockHttpBackend ( ) ;
72
+
73
+ let store : IStore ;
74
+ if ( storeType === StoreType . IndexedDB ) {
75
+ const idbStore = new IndexedDBStore ( { indexedDB : fakeIndexedDB } ) ;
76
+ await idbStore . startup ( ) ;
77
+ store = idbStore ;
78
+ } else {
79
+ store = new MemoryStore ( ) ;
80
+ }
81
+
82
+ client = new MatrixClient ( {
83
+ baseUrl : "https://my.home.server" ,
84
+ accessToken : "my.access.token" ,
85
+ fetchFn : httpBackend . fetchFn as typeof global . fetch ,
86
+ store,
87
+ } ) ;
83
88
} ) ;
84
- } ) ;
85
-
86
- afterEach ( function ( ) {
87
- jest . useRealTimers ( ) ;
88
- client . stopClient ( ) ;
89
- } ) ;
90
89
91
- it ( "sends a to-device message" , async function ( ) {
92
- httpBackend
93
- . when ( "PUT" , "/sendToDevice/org.example.foo/" )
94
- . check ( ( request ) => {
95
- expect ( request . data ) . toEqual ( EXPECTED_BODY ) ;
96
- } )
97
- . respond ( 200 , { } ) ;
98
-
99
- await client . queueToDevice ( {
100
- eventType : "org.example.foo" ,
101
- batch : [ FAKE_MSG ] ,
90
+ afterEach ( function ( ) {
91
+ client . stopClient ( ) ;
102
92
} ) ;
103
93
104
- await httpBackend . flushAllExpected ( ) ;
105
- // let the code handle the response to the request so we don't get
106
- // log output after the test has finished (apparently stopping the
107
- // client in aftereach is not sufficient.)
108
- await flushPromises ( ) ;
109
- } ) ;
110
-
111
- it ( "retries on error" , async function ( ) {
112
- jest . useFakeTimers ( ) ;
113
-
114
- httpBackend . when ( "PUT" , "/sendToDevice/org.example.foo/" ) . respond ( 500 ) ;
115
-
116
- httpBackend
117
- . when ( "PUT" , "/sendToDevice/org.example.foo/" )
118
- . check ( ( request ) => {
119
- expect ( request . data ) . toEqual ( EXPECTED_BODY ) ;
120
- } )
121
- . respond ( 200 , { } ) ;
94
+ it ( "sends a to-device message" , async function ( ) {
95
+ httpBackend
96
+ . when ( "PUT" , "/sendToDevice/org.example.foo/" )
97
+ . check ( ( request ) => {
98
+ expect ( request . data ) . toEqual ( EXPECTED_BODY ) ;
99
+ } )
100
+ . respond ( 200 , { } ) ;
101
+
102
+ await client . queueToDevice ( {
103
+ eventType : "org.example.foo" ,
104
+ batch : [ FAKE_MSG ] ,
105
+ } ) ;
122
106
123
- await client . queueToDevice ( {
124
- eventType : "org.example.foo" ,
125
- batch : [ FAKE_MSG ] ,
107
+ await httpBackend . flushAllExpected ( ) ;
108
+ // let the code handle the response to the request so we don't get
109
+ // log output after the test has finished (apparently stopping the
110
+ // client in aftereach is not sufficient.)
111
+ await flushPromises ( ) ;
126
112
} ) ;
127
- await flushAndRunTimersUntil ( ( ) => httpBackend . requests . length > 0 ) ;
128
- expect ( httpBackend . flushSync ( undefined , 1 ) ) . toEqual ( 1 ) ;
129
113
130
- await flushAndRunTimersUntil ( ( ) => httpBackend . requests . length > 0 ) ;
114
+ it ( "retries on retryImmediately()" , async function ( ) {
115
+ httpBackend . when ( "GET" , "/_matrix/client/versions" ) . respond ( 200 , {
116
+ versions : [ "v1.1" ] ,
117
+ } ) ;
131
118
132
- expect ( httpBackend . flushSync ( undefined , 1 ) ) . toEqual ( 1 ) ;
119
+ await Promise . all ( [ client . startClient ( ) , httpBackend . flush ( undefined , 1 , 20 ) ] ) ;
133
120
134
- // flush, as per comment in first test
135
- await flushPromises ( ) ;
136
- } ) ;
121
+ httpBackend . when ( "PUT" , "/sendToDevice/org.example.foo/" ) . respond ( 500 ) ;
122
+
123
+ httpBackend . when ( "PUT" , "/sendToDevice/org.example.foo/" ) . respond ( 200 , { } ) ;
137
124
138
- it ( "stops retrying on 4xx errors" , async function ( ) {
139
- jest . useFakeTimers ( ) ;
125
+ await client . queueToDevice ( {
126
+ eventType : "org.example.foo" ,
127
+ batch : [ FAKE_MSG ] ,
128
+ } ) ;
129
+ expect ( await httpBackend . flush ( undefined , 1 , 1 ) ) . toEqual ( 1 ) ;
130
+ await flushPromises ( ) ;
140
131
141
- httpBackend . when ( "PUT" , "/sendToDevice/org.example.foo/" ) . respond ( 400 ) ;
132
+ client . retryImmediately ( ) ;
142
133
143
- await client . queueToDevice ( {
144
- eventType : "org.example.foo" ,
145
- batch : [ FAKE_MSG ] ,
134
+ // longer timeout here to try & avoid flakiness
135
+ expect ( await httpBackend . flush ( undefined , 1 , 3000 ) ) . toEqual ( 1 ) ;
146
136
} ) ;
147
- await flushAndRunTimersUntil ( ( ) => httpBackend . requests . length > 0 ) ;
148
- expect ( httpBackend . flushSync ( undefined , 1 ) ) . toEqual ( 1 ) ;
149
137
150
- // Asserting that another request is never made is obviously
151
- // a bit tricky - we just flush the queue what should hopefully
152
- // be plenty of times and assert that nothing comes through.
153
- let tries = 0 ;
154
- await flushAndRunTimersUntil ( ( ) => ++ tries === 10 ) ;
138
+ it ( "retries on when client is started" , async function ( ) {
139
+ httpBackend . when ( "GET" , "/_matrix/client/versions" ) . respond ( 200 , {
140
+ versions : [ "v1.1" ] ,
141
+ } ) ;
155
142
156
- expect ( httpBackend . requests . length ) . toEqual ( 0 ) ;
157
- } ) ;
143
+ await Promise . all ( [ client . startClient ( ) , httpBackend . flush ( "/_matrix/client/versions" , 1 , 20 ) ] ) ;
158
144
159
- it ( "honours ratelimiting" , async function ( ) {
160
- jest . useFakeTimers ( ) ;
145
+ httpBackend . when ( "PUT" , "/sendToDevice/org.example.foo/" ) . respond ( 500 ) ;
161
146
162
- // pick something obscure enough it's unlikley to clash with a
163
- // retry delay the algorithm uses anyway
164
- const retryDelay = 279 * 1000 ;
147
+ httpBackend . when ( "PUT" , "/sendToDevice/org.example.foo/" ) . respond ( 200 , { } ) ;
165
148
166
- httpBackend . when ( "PUT" , "/sendToDevice/org.example.foo/" ) . respond ( 429 , {
167
- errcode : "M_LIMIT_EXCEEDED" ,
168
- retry_after_ms : retryDelay ,
169
- } ) ;
149
+ await client . queueToDevice ( {
150
+ eventType : "org.example.foo" ,
151
+ batch : [ FAKE_MSG ] ,
152
+ } ) ;
153
+ expect ( await httpBackend . flush ( undefined , 1 , 1 ) ) . toEqual ( 1 ) ;
154
+ await flushPromises ( ) ;
170
155
171
- httpBackend . when ( "PUT" , "/sendToDevice/org.example.foo/" ) . respond ( 200 , { } ) ;
156
+ client . stopClient ( ) ;
157
+ await Promise . all ( [ client . startClient ( ) , httpBackend . flush ( "/_matrix/client/versions" , 1 , 20 ) ] ) ;
172
158
173
- await client . queueToDevice ( {
174
- eventType : "org.example.foo" ,
175
- batch : [ FAKE_MSG ] ,
159
+ expect ( await httpBackend . flush ( undefined , 1 , 20 ) ) . toEqual ( 1 ) ;
176
160
} ) ;
177
- await flushAndRunTimersUntil ( ( ) => httpBackend . requests . length > 0 ) ;
178
- expect ( httpBackend . flushSync ( undefined , 1 ) ) . toEqual ( 1 ) ;
179
- await flushPromises ( ) ;
180
161
181
- logger . info ( "Advancing clock to just before expected retry time..." ) ;
162
+ it ( "retries when a message is retried" , async function ( ) {
163
+ httpBackend . when ( "GET" , "/_matrix/client/versions" ) . respond ( 200 , {
164
+ versions : [ "v1.1" ] ,
165
+ } ) ;
182
166
183
- jest . advanceTimersByTime ( retryDelay - 1000 ) ;
184
- await flushPromises ( ) ;
167
+ await Promise . all ( [ client . startClient ( ) , httpBackend . flush ( undefined , 1 , 20 ) ] ) ;
185
168
186
- expect ( httpBackend . requests . length ) . toEqual ( 0 ) ;
169
+ httpBackend . when ( "PUT" , "/sendToDevice/org.example.foo/" ) . respond ( 500 ) ;
187
170
188
- logger . info ( "Advancing clock past expected retry time..." ) ;
171
+ httpBackend . when ( "PUT" , "/sendToDevice/org.example.foo/" ) . respond ( 200 , { } ) ;
189
172
190
- jest . advanceTimersByTime ( 2000 ) ;
191
- await flushPromises ( ) ;
173
+ await client . queueToDevice ( {
174
+ eventType : "org.example.foo" ,
175
+ batch : [ FAKE_MSG ] ,
176
+ } ) ;
192
177
193
- expect ( httpBackend . flushSync ( undefined , 1 ) ) . toEqual ( 1 ) ;
194
- } ) ;
178
+ expect ( await httpBackend . flush ( undefined , 1 , 20 ) ) . toEqual ( 1 ) ;
179
+ await flushPromises ( ) ;
180
+
181
+ const dummyEvent = new MatrixEvent ( {
182
+ event_id : "!fake:example.org" ,
183
+ } ) ;
184
+ const mockRoom = {
185
+ updatePendingEvent : jest . fn ( ) ,
186
+ hasEncryptionStateEvent : jest . fn ( ) . mockReturnValue ( false ) ,
187
+ } as unknown as Room ;
188
+ client . resendEvent ( dummyEvent , mockRoom ) ;
195
189
196
- it ( "retries on retryImmediately()" , async function ( ) {
197
- httpBackend . when ( "GET" , "/_matrix/client/versions" ) . respond ( 200 , {
198
- versions : [ "v1.1" ] ,
190
+ expect ( await httpBackend . flush ( undefined , 1 , 20 ) ) . toEqual ( 1 ) ;
199
191
} ) ;
200
192
201
- await Promise . all ( [ client . startClient ( ) , httpBackend . flush ( undefined , 1 , 20 ) ] ) ;
193
+ it ( "splits many messages into multiple HTTP requests" , async function ( ) {
194
+ const batch : ToDeviceBatch = {
195
+ eventType : "org.example.foo" ,
196
+ batch : [ ] ,
197
+ } ;
198
+
199
+ for ( let i = 0 ; i <= 20 ; ++ i ) {
200
+ batch . batch . push ( {
201
+ userId : `@user${ i } :example.org` ,
202
+ deviceId : FAKE_DEVICE_ID ,
203
+ payload : FAKE_PAYLOAD ,
204
+ } ) ;
205
+ }
206
+
207
+ const expectedCounts = [ 20 , 1 ] ;
208
+ httpBackend
209
+ . when ( "PUT" , "/sendToDevice/org.example.foo/" )
210
+ . check ( ( request ) => {
211
+ expect (
212
+ removeElement ( expectedCounts , ( c ) => c === Object . keys ( request . data . messages ) . length ) ,
213
+ ) . toBeTruthy ( ) ;
214
+ } )
215
+ . respond ( 200 , { } ) ;
216
+ httpBackend
217
+ . when ( "PUT" , "/sendToDevice/org.example.foo/" )
218
+ . check ( ( request ) => {
219
+ expect ( Object . keys ( request . data . messages ) . length ) . toEqual ( 1 ) ;
220
+ } )
221
+ . respond ( 200 , { } ) ;
222
+
223
+ await client . queueToDevice ( batch ) ;
224
+ await httpBackend . flushAllExpected ( ) ;
225
+
226
+ // flush, as per comment in first test
227
+ await flushPromises ( ) ;
228
+ } ) ;
229
+ } ) ;
202
230
203
- httpBackend . when ( "PUT" , "/sendToDevice/org.example.foo/" ) . respond ( 500 ) ;
231
+ describe ( "async tests" , ( ) => {
232
+ beforeAll ( ( ) => {
233
+ jest . useFakeTimers ( ) ;
234
+ } ) ;
204
235
205
- httpBackend . when ( "PUT" , "/sendToDevice/org.example.foo/" ) . respond ( 200 , { } ) ;
236
+ afterAll ( ( ) => {
237
+ jest . useRealTimers ( ) ;
238
+ } ) ;
206
239
207
- await client . queueToDevice ( {
208
- eventType : "org.example.foo" ,
209
- batch : [ FAKE_MSG ] ,
240
+ beforeEach ( async function ( ) {
241
+ httpBackend = new MockHttpBackend ( ) ;
242
+
243
+ let store : IStore ;
244
+ if ( storeType === StoreType . IndexedDB ) {
245
+ const idbStore = new IndexedDBStore ( { indexedDB : fakeIndexedDB } ) ;
246
+ let storeStarted = false ;
247
+ idbStore . startup ( ) . then ( ( ) => {
248
+ storeStarted = true ;
249
+ } ) ;
250
+ await flushAndRunTimersUntil ( ( ) => storeStarted ) ;
251
+ store = idbStore ;
252
+ } else {
253
+ store = new MemoryStore ( ) ;
254
+ }
255
+
256
+ client = new MatrixClient ( {
257
+ baseUrl : "https://my.home.server" ,
258
+ accessToken : "my.access.token" ,
259
+ fetchFn : httpBackend . fetchFn as typeof global . fetch ,
260
+ store,
261
+ } ) ;
210
262
} ) ;
211
- expect ( await httpBackend . flush ( undefined , 1 , 1 ) ) . toEqual ( 1 ) ;
212
- await flushPromises ( ) ;
213
263
214
- client . retryImmediately ( ) ;
264
+ afterEach ( function ( ) {
265
+ client . stopClient ( ) ;
266
+ } ) ;
215
267
216
- // longer timeout here to try & avoid flakiness
217
- expect ( await httpBackend . flush ( undefined , 1 , 3000 ) ) . toEqual ( 1 ) ;
218
- } ) ;
268
+ it ( "retries on error" , async function ( ) {
269
+ httpBackend . when ( "PUT" , "/sendToDevice/org.example.foo/" ) . respond ( 500 ) ;
219
270
220
- it ( "retries on when client is started" , async function ( ) {
221
- httpBackend . when ( "GET" , "/_matrix/client/versions" ) . respond ( 200 , {
222
- versions : [ "v1.1" ] ,
223
- } ) ;
271
+ httpBackend
272
+ . when ( "PUT" , "/sendToDevice/org.example.foo/" )
273
+ . check ( ( request ) => {
274
+ expect ( request . data ) . toEqual ( EXPECTED_BODY ) ;
275
+ } )
276
+ . respond ( 200 , { } ) ;
224
277
225
- await Promise . all ( [ client . startClient ( ) , httpBackend . flush ( "/_matrix/client/versions" , 1 , 20 ) ] ) ;
278
+ client
279
+ . queueToDevice ( {
280
+ eventType : "org.example.foo" ,
281
+ batch : [ FAKE_MSG ] ,
282
+ } )
283
+ . then ( ) ;
284
+ await flushAndRunTimersUntil ( ( ) => httpBackend . requests . length > 0 ) ;
285
+ expect ( httpBackend . flushSync ( undefined , 1 ) ) . toEqual ( 1 ) ;
226
286
227
- httpBackend . when ( "PUT" , "/sendToDevice/org.example.foo/" ) . respond ( 500 ) ;
287
+ await flushAndRunTimersUntil ( ( ) => httpBackend . requests . length > 0 ) ;
228
288
229
- httpBackend . when ( "PUT" , "/sendToDevice/org.example.foo/" ) . respond ( 200 , { } ) ;
289
+ expect ( httpBackend . flushSync ( undefined , 1 ) ) . toEqual ( 1 ) ;
230
290
231
- await client . queueToDevice ( {
232
- eventType : "org.example.foo" ,
233
- batch : [ FAKE_MSG ] ,
291
+ // flush, as per comment in first test
292
+ await flushPromises ( ) ;
234
293
} ) ;
235
- expect ( await httpBackend . flush ( undefined , 1 , 1 ) ) . toEqual ( 1 ) ;
236
- await flushPromises ( ) ;
237
294
238
- client . stopClient ( ) ;
239
- await Promise . all ( [ client . startClient ( ) , httpBackend . flush ( "/_matrix/client/versions" , 1 , 20 ) ] ) ;
295
+ it ( "stops retrying on 4xx errors" , async function ( ) {
296
+ httpBackend . when ( "PUT" , "/sendToDevice/org.example.foo/" ) . respond ( 400 ) ;
297
+
298
+ client
299
+ . queueToDevice ( {
300
+ eventType : "org.example.foo" ,
301
+ batch : [ FAKE_MSG ] ,
302
+ } )
303
+ . then ( ) ;
304
+ await flushAndRunTimersUntil ( ( ) => httpBackend . requests . length > 0 ) ;
305
+ expect ( httpBackend . flushSync ( undefined , 1 ) ) . toEqual ( 1 ) ;
306
+
307
+ // Asserting that another request is never made is obviously
308
+ // a bit tricky - we just flush the queue what should hopefully
309
+ // be plenty of times and assert that nothing comes through.
310
+ let tries = 0 ;
311
+ await flushAndRunTimersUntil ( ( ) => ++ tries === 10 ) ;
312
+
313
+ expect ( httpBackend . requests . length ) . toEqual ( 0 ) ;
314
+ } ) ;
240
315
241
- expect ( await httpBackend . flush ( undefined , 1 , 20 ) ) . toEqual ( 1 ) ;
242
- } ) ;
316
+ it ( "honours ratelimiting" , async function ( ) {
317
+ // pick something obscure enough it's unlikley to clash with a
318
+ // retry delay the algorithm uses anyway
319
+ const retryDelay = 279 * 1000 ;
243
320
244
- it ( "retries when a message is retried" , async function ( ) {
245
- httpBackend . when ( "GET" , "/_matrix/client/versions" ) . respond ( 200 , {
246
- versions : [ "v1.1" ] ,
247
- } ) ;
321
+ httpBackend . when ( "PUT" , "/sendToDevice/org.example.foo/" ) . respond ( 429 , {
322
+ errcode : "M_LIMIT_EXCEEDED" ,
323
+ retry_after_ms : retryDelay ,
324
+ } ) ;
248
325
249
- await Promise . all ( [ client . startClient ( ) , httpBackend . flush ( undefined , 1 , 20 ) ] ) ;
326
+ httpBackend . when ( "PUT" , "/sendToDevice/org.example.foo/" ) . respond ( 200 , { } ) ;
250
327
251
- httpBackend . when ( "PUT" , "/sendToDevice/org.example.foo/" ) . respond ( 500 ) ;
328
+ client
329
+ . queueToDevice ( {
330
+ eventType : "org.example.foo" ,
331
+ batch : [ FAKE_MSG ] ,
332
+ } )
333
+ . then ( ) ;
334
+ await flushAndRunTimersUntil ( ( ) => httpBackend . requests . length > 0 ) ;
335
+ expect ( httpBackend . flushSync ( undefined , 1 ) ) . toEqual ( 1 ) ;
336
+ await flushPromises ( ) ;
252
337
253
- httpBackend . when ( "PUT" , "/sendToDevice/org.example.foo/" ) . respond ( 200 , { } ) ;
338
+ logger . info ( "Advancing clock to just before expected retry time..." ) ;
254
339
255
- await client . queueToDevice ( {
256
- eventType : "org.example.foo" ,
257
- batch : [ FAKE_MSG ] ,
258
- } ) ;
340
+ jest . advanceTimersByTime ( retryDelay - 1000 ) ;
341
+ await flushPromises ( ) ;
259
342
260
- expect ( await httpBackend . flush ( undefined , 1 , 20 ) ) . toEqual ( 1 ) ;
261
- await flushPromises ( ) ;
343
+ expect ( httpBackend . requests . length ) . toEqual ( 0 ) ;
262
344
263
- const dummyEvent = new MatrixEvent ( {
264
- event_id : "!fake:example.org" ,
265
- } ) ;
266
- const mockRoom = {
267
- updatePendingEvent : jest . fn ( ) ,
268
- hasEncryptionStateEvent : jest . fn ( ) . mockReturnValue ( false ) ,
269
- } as unknown as Room ;
270
- client . resendEvent ( dummyEvent , mockRoom ) ;
345
+ logger . info ( "Advancing clock past expected retry time..." ) ;
271
346
272
- expect ( await httpBackend . flush ( undefined , 1 , 20 ) ) . toEqual ( 1 ) ;
273
- } ) ;
347
+ jest . advanceTimersByTime ( 2000 ) ;
348
+ await flushPromises ( ) ;
274
349
275
- it ( "splits many messages into multiple HTTP requests" , async function ( ) {
276
- const batch : ToDeviceBatch = {
277
- eventType : "org.example.foo" ,
278
- batch : [ ] ,
279
- } ;
280
-
281
- for ( let i = 0 ; i <= 20 ; ++ i ) {
282
- batch . batch . push ( {
283
- userId : `@user${ i } :example.org` ,
284
- deviceId : FAKE_DEVICE_ID ,
285
- payload : FAKE_PAYLOAD ,
286
- } ) ;
287
- }
288
-
289
- const expectedCounts = [ 20 , 1 ] ;
290
- httpBackend
291
- . when ( "PUT" , "/sendToDevice/org.example.foo/" )
292
- . check ( ( request ) => {
293
- expect (
294
- removeElement ( expectedCounts , ( c ) => c === Object . keys ( request . data . messages ) . length ) ,
295
- ) . toBeTruthy ( ) ;
296
- } )
297
- . respond ( 200 , { } ) ;
298
- httpBackend
299
- . when ( "PUT" , "/sendToDevice/org.example.foo/" )
300
- . check ( ( request ) => {
301
- expect ( Object . keys ( request . data . messages ) . length ) . toEqual ( 1 ) ;
302
- } )
303
- . respond ( 200 , { } ) ;
304
-
305
- await client . queueToDevice ( batch ) ;
306
- await httpBackend . flushAllExpected ( ) ;
307
-
308
- // flush, as per comment in first test
309
- await flushPromises ( ) ;
350
+ expect ( httpBackend . flushSync ( undefined , 1 ) ) . toEqual ( 1 ) ;
351
+ } ) ;
310
352
} ) ;
311
353
} ) ;
0 commit comments