@@ -6,16 +6,25 @@ The first tests are initially similar to those for dstream.test.ts, but with
6
6
7
7
DEVELOPMENT:
8
8
9
- pnpm test estream.test.ts
9
+ pnpm test ./dstream- estream.test.ts
10
10
11
11
*/
12
12
13
+ import { connect , before , after } from "@cocalc/backend/conat/test/setup" ;
13
14
import { createDstreamEphemeral as create } from "./util" ;
14
15
import { dstream as createDstream0 } from "@cocalc/backend/conat/sync" ;
15
16
import { once } from "@cocalc/util/async-utils" ;
16
17
18
+ beforeAll ( before ) ;
19
+
17
20
async function createDstream < T > ( opts ) {
18
- return await createDstream0 < T > ( { ephemeral : true , leader : true , ...opts } ) ;
21
+ return await createDstream0 < T > ( {
22
+ noCache : true ,
23
+ noAutosave : true ,
24
+ ephemeral : true ,
25
+ leader : true ,
26
+ ...opts ,
27
+ } ) ;
19
28
}
20
29
21
30
describe ( "create a dstream and do some basic operations" , ( ) => {
@@ -65,14 +74,11 @@ describe("create a dstream and do some basic operations", () => {
65
74
describe ( "create two dstreams and observe sync between them" , ( ) => {
66
75
const name = `test-${ Math . random ( ) } ` ;
67
76
let s1 , s2 ;
77
+ let client2 ;
68
78
it ( "creates two distinct dstream objects s1 and s2 with the same name" , async ( ) => {
69
- s1 = await createDstream ( { name, noAutosave : true , noCache : true } ) ;
70
- s2 = await createDstream ( {
71
- name,
72
- noAutosave : true ,
73
- noCache : true ,
74
- leader : false ,
75
- } ) ;
79
+ client2 = connect ( ) ;
80
+ s1 = await createDstream ( { name } ) ;
81
+ s2 = await createDstream ( { client : client2 , name, leader : false } ) ;
76
82
// definitely distinct
77
83
expect ( s1 === s2 ) . toBe ( false ) ;
78
84
} ) ;
@@ -108,21 +114,50 @@ describe("create two dstreams and observe sync between them", () => {
108
114
expect ( s2 . getAll ( ) ) . toEqual ( [ "hello" , "hi from s2" ] ) ;
109
115
} ) ;
110
116
111
- it ( "write to s1 and s2 and save at the same time and see some 'random choice' of order gets imposed by the server" , async ( ) => {
117
+ it ( "cleans up" , ( ) => {
118
+ s1 . close ( ) ;
119
+ s2 . close ( ) ;
120
+ client2 . close ( ) ;
121
+ } ) ;
122
+ } ) ;
123
+
124
+ describe ( "create two dstreams and test sync with parallel save" , ( ) => {
125
+ const name = `test-${ Math . random ( ) } ` ;
126
+ let s1 , s2 ;
127
+ let client2 ;
128
+ it ( "creates two distinct dstream objects s1 and s2 with the same name" , async ( ) => {
129
+ client2 = connect ( ) ;
130
+ s1 = await createDstream ( { name } ) ;
131
+ s2 = await createDstream ( { client : client2 , name, leader : false } ) ;
132
+ // definitely distinct
133
+ expect ( s1 === s2 ) . toBe ( false ) ;
134
+ } ) ;
135
+
136
+ it ( "write to s1 and s2 and save at the same time" , async ( ) => {
112
137
s1 . push ( "s1" ) ;
113
138
s2 . push ( "s2" ) ;
114
139
// our changes are reflected locally
115
- expect ( s1 . getAll ( ) ) . toEqual ( [ "hello" , "hi from s2" , " s1"] ) ;
116
- expect ( s2 . getAll ( ) ) . toEqual ( [ "hello" , "hi from s2" , " s2"] ) ;
140
+ expect ( s1 . getAll ( ) ) . toEqual ( [ "s1" ] ) ;
141
+ expect ( s2 . getAll ( ) ) . toEqual ( [ "s2" ] ) ;
117
142
// now kick off the two saves *in parallel*
118
143
s1 . save ( ) ;
119
144
s2 . save ( ) ;
120
145
await once ( s1 , "change" ) ;
121
- while ( s2 . length != s1 . length ) {
122
- await once ( s2 , "change" ) ;
146
+ while ( s2 . length != 2 || s1 . length != 2 ) {
147
+ if ( s1 . length > 2 || s2 . length > 2 ) {
148
+ throw Error ( "bug" ) ;
149
+ }
150
+ if ( s2 . length < 2 ) {
151
+ await once ( s2 , "change" ) ;
152
+ } else if ( s1 . length < 2 ) {
153
+ await once ( s1 , "change" ) ;
154
+ }
123
155
}
124
156
expect ( s1 . getAll ( ) ) . toEqual ( s2 . getAll ( ) ) ;
125
- expect ( s1 . getAll ( ) ) . toEqual ( [ "hello" , "hi from s2" , "s1" , "s2" ] ) ;
157
+ } ) ;
158
+
159
+ it ( "cleans up" , ( ) => {
160
+ client2 . close ( ) ;
126
161
} ) ;
127
162
} ) ;
128
163
@@ -195,7 +230,9 @@ describe("testing start_seq", () => {
195
230
196
231
let t ;
197
232
it ( "it opens another copy of the stream, but starting with the last sequence number, so only one message" , async ( ) => {
233
+ const client = connect ( ) ;
198
234
t = await createDstream ( {
235
+ client,
199
236
name,
200
237
noAutosave : true ,
201
238
leader : false ,
@@ -227,8 +264,9 @@ describe("a little bit of a stress test", () => {
227
264
s . push ( { i } ) ;
228
265
}
229
266
expect ( s . length ) . toBe ( count ) ;
230
- // NOTE: warning -- this is **MUCH SLOWER**, e.g., 10x slower,
231
- // running under jest, hence why count is small.
267
+ // [ ] TODO rewrite this save to send everything in a single message
268
+ // which gets chunked, will we be much faster, then change the count
269
+ // above to 1000 or 10000.
232
270
await s . save ( ) ;
233
271
expect ( s . length ) . toBe ( count ) ;
234
272
} ) ;
@@ -249,50 +287,52 @@ describe("dstream typescript test", () => {
249
287
} ) ;
250
288
} ) ;
251
289
252
- import { numSubscriptions } from "@cocalc/conat/client" ;
290
+ describe ( "ensure there isn't a really obvious subscription leak" , ( ) => {
291
+ let client ;
253
292
254
- describe ( "ensure there are no NATS subscription leaks" , ( ) => {
255
- // There is some slight slack at some point due to the clock stuff,
256
- // inventory, etc. It is constant and small, whereas we allocate
257
- // a large number of kv's in the test.
258
- const SLACK = 4 ;
293
+ it ( "create a client, which initially has only one subscription (the inbox)" , async ( ) => {
294
+ client = connect ( ) ;
295
+ expect ( client . numSubscriptions ( ) ) . toBe ( 1 ) ;
296
+ } ) ;
259
297
260
- it ( "creates and closes many kv's and checks there is no leak" , async ( ) => {
261
- const before = numSubscriptions ( ) ;
262
- const COUNT = 20 ;
298
+ const count = 100 ;
299
+ it ( `creates and closes ${ count } streams and checks there is no leak` , async ( ) => {
300
+ const before = client . numSubscriptions ( ) ;
263
301
// create
264
302
const a : any = [ ] ;
265
- for ( let i = 0 ; i < COUNT ; i ++ ) {
303
+ for ( let i = 0 ; i < count ; i ++ ) {
266
304
a [ i ] = await createDstream ( {
267
305
name : `${ Math . random ( ) } ` ,
268
- noAutosave : true ,
269
306
} ) ;
270
307
}
271
- for ( let i = 0 ; i < COUNT ; i ++ ) {
308
+ for ( let i = 0 ; i < count ; i ++ ) {
272
309
await a [ i ] . close ( ) ;
273
310
}
274
- const after = numSubscriptions ( ) ;
275
- expect ( Math . abs ( after - before ) ) . toBeLessThan ( SLACK ) ;
311
+ const after = client . numSubscriptions ( ) ;
312
+ expect ( after ) . toBe ( before ) ;
313
+
314
+ // also check count on server went down.
315
+ expect ( ( await client . getSubscriptions ( ) ) . size ) . toBe ( before ) ;
276
316
} ) ;
277
317
278
- it ( "does another leak test, but with a set operation each time" , async ( ) => {
279
- const before = numSubscriptions ( ) ;
280
- const COUNT = 20 ;
318
+ it ( "does another leak test, but with a publish operation each time" , async ( ) => {
319
+ const before = client . numSubscriptions ( ) ;
281
320
// create
282
321
const a : any = [ ] ;
283
- for ( let i = 0 ; i < COUNT ; i ++ ) {
322
+ for ( let i = 0 ; i < count ; i ++ ) {
284
323
a [ i ] = await createDstream ( {
285
324
name : `${ Math . random ( ) } ` ,
286
325
noAutosave : true ,
287
326
} ) ;
288
327
a [ i ] . publish ( i ) ;
289
328
await a [ i ] . save ( ) ;
290
329
}
291
- for ( let i = 0 ; i < COUNT ; i ++ ) {
292
- await a [ i ] . purge ( ) ;
330
+ for ( let i = 0 ; i < count ; i ++ ) {
293
331
await a [ i ] . close ( ) ;
294
332
}
295
- const after = numSubscriptions ( ) ;
296
- expect ( Math . abs ( after - before ) ) . toBeLessThan ( SLACK ) ;
333
+ const after = client . numSubscriptions ( ) ;
334
+ expect ( after ) . toBe ( before ) ;
297
335
} ) ;
298
336
} ) ;
337
+
338
+ afterAll ( after ) ;
0 commit comments