@@ -23,6 +23,15 @@ function addSetting(key: string, value: any) {
23
23
mockedKVs . push ( createMockedKeyValue ( { key, value } ) ) ;
24
24
}
25
25
26
+ let listKvRequestCount = 0 ;
27
+ const listKvCallback = ( ) => {
28
+ listKvRequestCount ++ ;
29
+ } ;
30
+ let getKvRequestCount = 0 ;
31
+ const getKvCallback = ( ) => {
32
+ getKvRequestCount ++ ;
33
+ } ;
34
+
26
35
describe ( "dynamic refresh" , function ( ) {
27
36
this . timeout ( 10000 ) ;
28
37
@@ -32,12 +41,14 @@ describe("dynamic refresh", function () {
32
41
{ value : "40" , key : "app.settings.fontSize" } ,
33
42
{ value : "30" , key : "app.settings.fontSize" , label : "prod" }
34
43
] . map ( createMockedKeyValue ) ;
35
- mockAppConfigurationClientListConfigurationSettings ( mockedKVs ) ;
36
- mockAppConfigurationClientGetConfigurationSetting ( mockedKVs ) ;
44
+ mockAppConfigurationClientListConfigurationSettings ( [ mockedKVs ] , listKvCallback ) ;
45
+ mockAppConfigurationClientGetConfigurationSetting ( mockedKVs , getKvCallback ) ;
37
46
} ) ;
38
47
39
48
afterEach ( ( ) => {
40
49
restoreMocks ( ) ;
50
+ listKvRequestCount = 0 ;
51
+ getKvRequestCount = 0 ;
41
52
} ) ;
42
53
43
54
it ( "should throw error when refresh is not enabled but refresh is called" , async ( ) => {
@@ -139,6 +150,8 @@ describe("dynamic refresh", function () {
139
150
]
140
151
}
141
152
} ) ;
153
+ expect ( listKvRequestCount ) . eq ( 1 ) ;
154
+ expect ( getKvRequestCount ) . eq ( 0 ) ;
142
155
expect ( settings ) . not . undefined ;
143
156
expect ( settings . get ( "app.settings.fontColor" ) ) . eq ( "red" ) ;
144
157
expect ( settings . get ( "app.settings.fontSize" ) ) . eq ( "40" ) ;
@@ -149,10 +162,14 @@ describe("dynamic refresh", function () {
149
162
// within refreshInterval, should not really refresh
150
163
await settings . refresh ( ) ;
151
164
expect ( settings . get ( "app.settings.fontColor" ) ) . eq ( "red" ) ;
165
+ expect ( listKvRequestCount ) . eq ( 1 ) ; // no more request should be sent during the refresh interval
166
+ expect ( getKvRequestCount ) . eq ( 0 ) ; // no more request should be sent during the refresh interval
152
167
153
168
// after refreshInterval, should really refresh
154
169
await sleepInMs ( 2 * 1000 + 1 ) ;
155
170
await settings . refresh ( ) ;
171
+ expect ( listKvRequestCount ) . eq ( 2 ) ;
172
+ expect ( getKvRequestCount ) . eq ( 1 ) ;
156
173
expect ( settings . get ( "app.settings.fontColor" ) ) . eq ( "blue" ) ;
157
174
} ) ;
158
175
@@ -167,18 +184,22 @@ describe("dynamic refresh", function () {
167
184
]
168
185
}
169
186
} ) ;
187
+ expect ( listKvRequestCount ) . eq ( 1 ) ;
188
+ expect ( getKvRequestCount ) . eq ( 0 ) ;
170
189
expect ( settings ) . not . undefined ;
171
190
expect ( settings . get ( "app.settings.fontColor" ) ) . eq ( "red" ) ;
172
191
expect ( settings . get ( "app.settings.fontSize" ) ) . eq ( "40" ) ;
173
192
174
193
// delete setting 'app.settings.fontColor'
175
194
const newMockedKVs = mockedKVs . filter ( elem => elem . key !== "app.settings.fontColor" ) ;
176
195
restoreMocks ( ) ;
177
- mockAppConfigurationClientListConfigurationSettings ( newMockedKVs ) ;
178
- mockAppConfigurationClientGetConfigurationSetting ( newMockedKVs ) ;
196
+ mockAppConfigurationClientListConfigurationSettings ( [ newMockedKVs ] , listKvCallback ) ;
197
+ mockAppConfigurationClientGetConfigurationSetting ( newMockedKVs , getKvCallback ) ;
179
198
180
199
await sleepInMs ( 2 * 1000 + 1 ) ;
181
200
await settings . refresh ( ) ;
201
+ expect ( listKvRequestCount ) . eq ( 2 ) ;
202
+ expect ( getKvRequestCount ) . eq ( 2 ) ; // one conditional request to detect change and one request as part of loading all kvs (because app.settings.fontColor doesn't exist in the response of listKv request)
182
203
expect ( settings . get ( "app.settings.fontColor" ) ) . eq ( undefined ) ;
183
204
} ) ;
184
205
@@ -193,13 +214,17 @@ describe("dynamic refresh", function () {
193
214
]
194
215
}
195
216
} ) ;
217
+ expect ( listKvRequestCount ) . eq ( 1 ) ;
218
+ expect ( getKvRequestCount ) . eq ( 0 ) ;
196
219
expect ( settings ) . not . undefined ;
197
220
expect ( settings . get ( "app.settings.fontColor" ) ) . eq ( "red" ) ;
198
221
expect ( settings . get ( "app.settings.fontSize" ) ) . eq ( "40" ) ;
199
222
200
223
updateSetting ( "app.settings.fontSize" , "50" ) ; // unwatched setting
201
224
await sleepInMs ( 2 * 1000 + 1 ) ;
202
225
await settings . refresh ( ) ;
226
+ expect ( listKvRequestCount ) . eq ( 1 ) ;
227
+ expect ( getKvRequestCount ) . eq ( 1 ) ;
203
228
expect ( settings . get ( "app.settings.fontSize" ) ) . eq ( "40" ) ;
204
229
} ) ;
205
230
@@ -215,6 +240,8 @@ describe("dynamic refresh", function () {
215
240
]
216
241
}
217
242
} ) ;
243
+ expect ( listKvRequestCount ) . eq ( 1 ) ;
244
+ expect ( getKvRequestCount ) . eq ( 0 ) ;
218
245
expect ( settings ) . not . undefined ;
219
246
expect ( settings . get ( "app.settings.fontColor" ) ) . eq ( "red" ) ;
220
247
expect ( settings . get ( "app.settings.fontSize" ) ) . eq ( "40" ) ;
@@ -224,6 +251,8 @@ describe("dynamic refresh", function () {
224
251
updateSetting ( "app.settings.fontSize" , "50" ) ;
225
252
await sleepInMs ( 2 * 1000 + 1 ) ;
226
253
await settings . refresh ( ) ;
254
+ expect ( listKvRequestCount ) . eq ( 2 ) ;
255
+ expect ( getKvRequestCount ) . eq ( 2 ) ; // two getKv request for two watched settings
227
256
expect ( settings . get ( "app.settings.fontSize" ) ) . eq ( "50" ) ;
228
257
expect ( settings . get ( "app.settings.bgColor" ) ) . eq ( "white" ) ;
229
258
} ) ;
@@ -309,6 +338,8 @@ describe("dynamic refresh", function () {
309
338
]
310
339
}
311
340
} ) ;
341
+ expect ( listKvRequestCount ) . eq ( 1 ) ;
342
+ expect ( getKvRequestCount ) . eq ( 1 ) ; // app.settings.bgColor doesn't exist in the response of listKv request, so an additional getKv request is made to get it.
312
343
expect ( settings ) . not . undefined ;
313
344
expect ( settings . get ( "app.settings.fontColor" ) ) . eq ( "red" ) ;
314
345
expect ( settings . get ( "app.settings.fontSize" ) ) . eq ( "40" ) ;
@@ -317,10 +348,45 @@ describe("dynamic refresh", function () {
317
348
updateSetting ( "app.settings.fontColor" , "blue" ) ;
318
349
await sleepInMs ( 2 * 1000 + 1 ) ;
319
350
await settings . refresh ( ) ;
351
+ expect ( listKvRequestCount ) . eq ( 1 ) ;
352
+ expect ( getKvRequestCount ) . eq ( 2 ) ;
320
353
// should not refresh
321
354
expect ( settings . get ( "app.settings.fontColor" ) ) . eq ( "red" ) ;
322
355
} ) ;
323
356
357
+ it ( "should not refresh any more when there is refresh in progress" , async ( ) => {
358
+ const connectionString = createMockedConnectionString ( ) ;
359
+ const settings = await load ( connectionString , {
360
+ refreshOptions : {
361
+ enabled : true ,
362
+ refreshIntervalInMs : 2000 ,
363
+ watchedSettings : [
364
+ { key : "app.settings.fontColor" }
365
+ ]
366
+ }
367
+ } ) ;
368
+ expect ( listKvRequestCount ) . eq ( 1 ) ;
369
+ expect ( getKvRequestCount ) . eq ( 0 ) ;
370
+ expect ( settings ) . not . undefined ;
371
+ expect ( settings . get ( "app.settings.fontColor" ) ) . eq ( "red" ) ;
372
+
373
+ // change setting
374
+ updateSetting ( "app.settings.fontColor" , "blue" ) ;
375
+
376
+ // after refreshInterval, should really refresh
377
+ await sleepInMs ( 2 * 1000 + 1 ) ;
378
+ for ( let i = 0 ; i < 5 ; i ++ ) { // in practice, refresh should not be used in this way
379
+ settings . refresh ( ) ; // refresh "concurrently"
380
+ }
381
+ expect ( listKvRequestCount ) . to . be . at . most ( 2 ) ;
382
+ expect ( getKvRequestCount ) . to . be . at . most ( 1 ) ;
383
+
384
+ await sleepInMs ( 1000 ) ; // wait for all 5 refresh attempts to finish
385
+
386
+ expect ( listKvRequestCount ) . eq ( 2 ) ;
387
+ expect ( getKvRequestCount ) . eq ( 1 ) ;
388
+ expect ( settings . get ( "app.settings.fontColor" ) ) . eq ( "blue" ) ;
389
+ } ) ;
324
390
} ) ;
325
391
326
392
describe ( "dynamic refresh feature flags" , function ( ) {
@@ -331,14 +397,16 @@ describe("dynamic refresh feature flags", function () {
331
397
332
398
afterEach ( ( ) => {
333
399
restoreMocks ( ) ;
400
+ listKvRequestCount = 0 ;
401
+ getKvRequestCount = 0 ;
334
402
} ) ;
335
403
336
404
it ( "should refresh feature flags when enabled" , async ( ) => {
337
405
mockedKVs = [
338
406
createMockedFeatureFlag ( "Beta" , { enabled : true } )
339
407
] ;
340
- mockAppConfigurationClientListConfigurationSettings ( mockedKVs ) ;
341
- mockAppConfigurationClientGetConfigurationSetting ( mockedKVs ) ;
408
+ mockAppConfigurationClientListConfigurationSettings ( [ mockedKVs ] , listKvCallback ) ;
409
+ mockAppConfigurationClientGetConfigurationSetting ( mockedKVs , getKvCallback ) ;
342
410
343
411
const connectionString = createMockedConnectionString ( ) ;
344
412
const settings = await load ( connectionString , {
@@ -353,6 +421,8 @@ describe("dynamic refresh feature flags", function () {
353
421
}
354
422
}
355
423
} ) ;
424
+ expect ( listKvRequestCount ) . eq ( 2 ) ; // one listKv request for kvs and one listKv request for feature flags
425
+ expect ( getKvRequestCount ) . eq ( 0 ) ;
356
426
expect ( settings ) . not . undefined ;
357
427
expect ( settings . get ( "feature_management" ) ) . not . undefined ;
358
428
expect ( settings . get < any > ( "feature_management" ) . feature_flags ) . not . undefined ;
@@ -371,6 +441,8 @@ describe("dynamic refresh feature flags", function () {
371
441
372
442
await sleepInMs ( 2 * 1000 + 1 ) ;
373
443
await settings . refresh ( ) ;
444
+ expect ( listKvRequestCount ) . eq ( 4 ) ; // 2 + 2 more requests: one conditional request to detect change and one request to reload all feature flags
445
+ expect ( getKvRequestCount ) . eq ( 0 ) ;
374
446
375
447
expect ( settings . get < any > ( "feature_management" ) . feature_flags [ 0 ] . id ) . eq ( "Beta" ) ;
376
448
expect ( settings . get < any > ( "feature_management" ) . feature_flags [ 0 ] . enabled ) . eq ( false ) ;
@@ -387,8 +459,8 @@ describe("dynamic refresh feature flags", function () {
387
459
createMockedFeatureFlag ( "Beta_1" , { enabled : true } ) ,
388
460
createMockedFeatureFlag ( "Beta_2" , { enabled : true } ) ,
389
461
] ;
390
- mockAppConfigurationClientListConfigurationSettings ( page1 , page2 ) ;
391
- mockAppConfigurationClientGetConfigurationSetting ( [ ...page1 , ...page2 ] ) ;
462
+ mockAppConfigurationClientListConfigurationSettings ( [ page1 , page2 ] , listKvCallback ) ;
463
+ mockAppConfigurationClientGetConfigurationSetting ( [ ...page1 , ...page2 ] , getKvCallback ) ;
392
464
393
465
const connectionString = createMockedConnectionString ( ) ;
394
466
const settings = await load ( connectionString , {
@@ -403,6 +475,8 @@ describe("dynamic refresh feature flags", function () {
403
475
}
404
476
}
405
477
} ) ;
478
+ expect ( listKvRequestCount ) . eq ( 2 ) ;
479
+ expect ( getKvRequestCount ) . eq ( 0 ) ;
406
480
407
481
let refreshSuccessfulCount = 0 ;
408
482
settings . onRefresh ( ( ) => {
@@ -411,16 +485,20 @@ describe("dynamic refresh feature flags", function () {
411
485
412
486
await sleepInMs ( 2 * 1000 + 1 ) ;
413
487
await settings . refresh ( ) ;
488
+ expect ( listKvRequestCount ) . eq ( 3 ) ; // one conditional request to detect change
489
+ expect ( getKvRequestCount ) . eq ( 0 ) ;
414
490
expect ( refreshSuccessfulCount ) . eq ( 0 ) ; // no change in feature flags, because page etags are the same.
415
491
416
492
// change feature flag Beta_1 to false
417
493
page2 [ 0 ] = createMockedFeatureFlag ( "Beta_1" , { enabled : false } ) ;
418
494
restoreMocks ( ) ;
419
- mockAppConfigurationClientListConfigurationSettings ( page1 , page2 ) ;
420
- mockAppConfigurationClientGetConfigurationSetting ( [ ...page1 , ...page2 ] ) ;
495
+ mockAppConfigurationClientListConfigurationSettings ( [ page1 , page2 ] , listKvCallback ) ;
496
+ mockAppConfigurationClientGetConfigurationSetting ( [ ...page1 , ...page2 ] , getKvCallback ) ;
421
497
422
498
await sleepInMs ( 2 * 1000 + 1 ) ;
423
499
await settings . refresh ( ) ;
500
+ expect ( listKvRequestCount ) . eq ( 5 ) ; // 3 + 2 more requests: one conditional request to detect change and one request to reload all feature flags
501
+ expect ( getKvRequestCount ) . eq ( 0 ) ;
424
502
expect ( refreshSuccessfulCount ) . eq ( 1 ) ; // change in feature flags, because page etags are different.
425
503
} ) ;
426
504
} ) ;
0 commit comments