Skip to content

Commit b6f64c7

Browse files
committed
Use monotonic clock in tests for measuring elapsed time + increase the tolerance of time-sensitive tests
1 parent 110b4c2 commit b6f64c7

File tree

6 files changed

+41
-38
lines changed

6 files changed

+41
-38
lines changed

test/ConfigCatClientTests.ts

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import { isWeakRefAvailable, setupPolyfills } from "#lib/Polyfills";
1515
import { Config, IConfig, ProjectConfig, SettingValue, SettingValueContainer } from "#lib/ProjectConfig";
1616
import { EvaluateContext, IEvaluateResult, IEvaluationDetails, IRolloutEvaluator } from "#lib/RolloutEvaluator";
1717
import { User } from "#lib/User";
18-
import { delay } from "#lib/Utils";
18+
import { delay, getMonotonicTimeMs } from "#lib/Utils";
1919
import "./helpers/ConfigCatClientCacheExtensions";
2020

2121
describe("ConfigCatClient", () => {
@@ -195,7 +195,7 @@ describe("ConfigCatClient", () => {
195195

196196
const key = "notexists";
197197
const defaultValue = false;
198-
const timestamp = new Date().getTime();
198+
const timestamp = ProjectConfig.generateTimestamp();
199199

200200
const configFetcherClass = FakeConfigFetcherWithTwoKeys;
201201
const cachedPc = new ProjectConfig(configFetcherClass.configJson, Config.deserialize(configFetcherClass.configJson), timestamp, "etag");
@@ -238,7 +238,7 @@ describe("ConfigCatClient", () => {
238238

239239
const key = "debug";
240240
const defaultValue = false;
241-
const timestamp = new Date().getTime();
241+
const timestamp = ProjectConfig.generateTimestamp();
242242

243243
const configFetcherClass = FakeConfigFetcherWithTwoKeys;
244244
const cachedPc = new ProjectConfig(configFetcherClass.configJson, Config.deserialize(configFetcherClass.configJson), timestamp, "etag");
@@ -281,7 +281,7 @@ describe("ConfigCatClient", () => {
281281

282282
const key = "debug";
283283
const defaultValue = "N/A";
284-
const timestamp = new Date().getTime();
284+
const timestamp = ProjectConfig.generateTimestamp();
285285

286286
const configFetcherClass = FakeConfigFetcherWithRules;
287287
const cachedPc = new ProjectConfig(configFetcherClass.configJson, Config.deserialize(configFetcherClass.configJson), timestamp, "etag");
@@ -327,7 +327,7 @@ describe("ConfigCatClient", () => {
327327

328328
const key = "string25Cat25Dog25Falcon25Horse";
329329
const defaultValue = "N/A";
330-
const timestamp = new Date().getTime();
330+
const timestamp = ProjectConfig.generateTimestamp();
331331

332332
const configFetcherClass = FakeConfigFetcherWithPercentageOptions;
333333
const cachedPc = new ProjectConfig(configFetcherClass.configJson, Config.deserialize(configFetcherClass.configJson), timestamp, "etag");
@@ -372,7 +372,7 @@ describe("ConfigCatClient", () => {
372372

373373
const key = "debug";
374374
const defaultValue = false;
375-
const timestamp = new Date().getTime();
375+
const timestamp = ProjectConfig.generateTimestamp();
376376

377377
const configFetcherClass = FakeConfigFetcherWithTwoKeys;
378378
const cachedPc = new ProjectConfig(configFetcherClass.configJson, Config.deserialize(configFetcherClass.configJson), timestamp, "etag");
@@ -427,7 +427,7 @@ describe("ConfigCatClient", () => {
427427

428428
// Arrange
429429

430-
const timestamp = new Date().getTime();
430+
const timestamp = ProjectConfig.generateTimestamp();
431431

432432
const configFetcherClass = FakeConfigFetcherWithTwoKeys;
433433
const cachedPc = new ProjectConfig(configFetcherClass.configJson, Config.deserialize(configFetcherClass.configJson), timestamp, "etag");
@@ -479,7 +479,7 @@ describe("ConfigCatClient", () => {
479479

480480
// Arrange
481481

482-
const timestamp = new Date().getTime();
482+
const timestamp = ProjectConfig.generateTimestamp();
483483

484484
const configFetcherClass = FakeConfigFetcherWithTwoKeys;
485485
const cachedPc = new ProjectConfig(configFetcherClass.configJson, Config.deserialize(configFetcherClass.configJson), timestamp, "etag");
@@ -585,13 +585,13 @@ describe("ConfigCatClient", () => {
585585
const configCatKernel = createKernel({ configFetcher: new FakeConfigFetcher(500) });
586586
const options: AutoPollOptions = createAutoPollOptions("APIKEY", { maxInitWaitTimeSeconds }, configCatKernel);
587587

588-
const startDate: number = new Date().getTime();
588+
const startTime: number = getMonotonicTimeMs();
589589
const client: IConfigCatClient = new ConfigCatClient(options, configCatKernel);
590590
const actualValue = await client.getValueAsync("debug", false);
591-
const elapsedMilliseconds: number = new Date().getTime() - startDate;
591+
const elapsedMilliseconds: number = getMonotonicTimeMs() - startTime;
592592

593593
assert.isAtLeast(elapsedMilliseconds, 500 - 25); // 25 ms for tolerance
594-
assert.isAtMost(elapsedMilliseconds, maxInitWaitTimeSeconds * 1000 + 75); // 75 ms for tolerance
594+
assert.isAtMost(elapsedMilliseconds, maxInitWaitTimeSeconds * 1000 + 100); // 100 ms for tolerance
595595
assert.equal(actualValue, true);
596596

597597
client.dispose();
@@ -609,13 +609,13 @@ describe("ConfigCatClient", () => {
609609
const configCatKernel = createKernel({ configFetcher });
610610
const options: AutoPollOptions = createAutoPollOptions("APIKEY", { maxInitWaitTimeSeconds }, configCatKernel);
611611

612-
const startDate: number = new Date().getTime();
612+
const startTime: number = getMonotonicTimeMs();
613613
const client: IConfigCatClient = new ConfigCatClient(options, configCatKernel);
614614
const actualDetails = await client.getValueDetailsAsync("debug", false);
615-
const elapsedMilliseconds: number = new Date().getTime() - startDate;
615+
const elapsedMilliseconds: number = getMonotonicTimeMs() - startTime;
616616

617617
assert.isAtLeast(elapsedMilliseconds, 500 - 25); // 25 ms for tolerance
618-
assert.isAtMost(elapsedMilliseconds, configFetchDelay * 2 + 75); // 75 ms for tolerance
618+
assert.isAtMost(elapsedMilliseconds, configFetchDelay * 2 + 100); // 100 ms for tolerance
619619
assert.equal(actualDetails.isDefaultValue, true);
620620
assert.equal(actualDetails.value, false);
621621

@@ -630,13 +630,13 @@ describe("ConfigCatClient", () => {
630630
const configCatKernel = createKernel({ configFetcher: new FakeConfigFetcherWithNullNewConfig(10000) });
631631
const options: AutoPollOptions = createAutoPollOptions("APIKEY", { maxInitWaitTimeSeconds }, configCatKernel);
632632

633-
const startDate: number = new Date().getTime();
633+
const startTime: number = getMonotonicTimeMs();
634634
const client: IConfigCatClient = new ConfigCatClient(options, configCatKernel);
635635
const actualValue = await client.getValueAsync("debug", false);
636-
const elapsedMilliseconds: number = new Date().getTime() - startDate;
636+
const elapsedMilliseconds: number = getMonotonicTimeMs() - startTime;
637637

638638
assert.isAtLeast(elapsedMilliseconds, (maxInitWaitTimeSeconds * 1000) - 25); // 25 ms for tolerance
639-
assert.isAtMost(elapsedMilliseconds, (maxInitWaitTimeSeconds * 1000) + 75); // 75 ms for tolerance
639+
assert.isAtMost(elapsedMilliseconds, (maxInitWaitTimeSeconds * 1000) + 100); // 100 ms for tolerance
640640
assert.equal(actualValue, false);
641641

642642
client.dispose();
@@ -671,13 +671,13 @@ describe("ConfigCatClient", () => {
671671
const configCatKernel = createKernel({ configFetcher });
672672
const options: AutoPollOptions = createAutoPollOptions("APIKEY", { maxInitWaitTimeSeconds }, configCatKernel);
673673

674-
const startDate: number = new Date().getTime();
674+
const startTime: number = getMonotonicTimeMs();
675675
const client: IConfigCatClient = new ConfigCatClient(options, configCatKernel);
676676
const state = await client.waitForReady();
677-
const elapsedMilliseconds: number = new Date().getTime() - startDate;
677+
const elapsedMilliseconds: number = getMonotonicTimeMs() - startTime;
678678

679679
assert.isAtLeast(elapsedMilliseconds, (maxInitWaitTimeSeconds * 1000) - 25); // 25 ms for tolerance
680-
assert.isAtMost(elapsedMilliseconds, (maxInitWaitTimeSeconds * 1000) + 75); // 75 ms for tolerance
680+
assert.isAtMost(elapsedMilliseconds, (maxInitWaitTimeSeconds * 1000) + 100); // 100 ms for tolerance
681681

682682
assert.equal(state, ClientCacheState.NoFlagData);
683683

@@ -704,13 +704,13 @@ describe("ConfigCatClient", () => {
704704
cache: new FakeExternalCacheWithInitialData(120_000),
705705
}, configCatKernel);
706706

707-
const startDate: number = new Date().getTime();
707+
const startTime: number = getMonotonicTimeMs();
708708
const client: IConfigCatClient = new ConfigCatClient(options, configCatKernel);
709709
const state = await client.waitForReady();
710-
const elapsedMilliseconds: number = new Date().getTime() - startDate;
710+
const elapsedMilliseconds: number = getMonotonicTimeMs() - startTime;
711711

712712
assert.isAtLeast(elapsedMilliseconds, (maxInitWaitTimeSeconds * 1000) - 25); // 25 ms for tolerance
713-
assert.isAtMost(elapsedMilliseconds, (maxInitWaitTimeSeconds * 1000) + 75); // 75 ms for tolerance
713+
assert.isAtMost(elapsedMilliseconds, (maxInitWaitTimeSeconds * 1000) + 100); // 100 ms for tolerance
714714

715715
assert.equal(state, ClientCacheState.HasCachedFlagDataOnly);
716716

@@ -948,7 +948,7 @@ describe("ConfigCatClient", () => {
948948

949949
const configFetcher = new FakeConfigFetcher(500);
950950
const configJson = "{\"f\": { \"debug\": { \"v\": { \"b\": false }, \"i\": \"abcdefgh\", \"t\": 0, \"p\": [], \"r\": [] } } }";
951-
const configCache = new FakeCache(new ProjectConfig(configJson, Config.deserialize(configJson), new Date().getTime() - 10000000, "etag2"));
951+
const configCache = new FakeCache(new ProjectConfig(configJson, Config.deserialize(configJson), ProjectConfig.generateTimestamp() - 10000000, "etag2"));
952952
const configCatKernel = createKernel({ configFetcher, defaultCacheFactory: () => configCache });
953953
const options: AutoPollOptions = createAutoPollOptions("APIKEY", { maxInitWaitTimeSeconds: 10 }, configCatKernel);
954954
const client: IConfigCatClient = new ConfigCatClient(options, configCatKernel);
@@ -963,7 +963,7 @@ describe("ConfigCatClient", () => {
963963

964964
const configFetcher = new FakeConfigFetcher(500);
965965
const configJson = "{\"f\": { \"debug\": { \"v\": { \"b\": false }, \"i\": \"abcdefgh\", \"t\": 0, \"p\": [], \"r\": [] } } }";
966-
const configCache = new FakeCache(new ProjectConfig(configJson, Config.deserialize(configJson), new Date().getTime() - 10000000, "etag2"));
966+
const configCache = new FakeCache(new ProjectConfig(configJson, Config.deserialize(configJson), ProjectConfig.generateTimestamp() - 10000000, "etag2"));
967967
const configCatKernel = createKernel({ configFetcher, defaultCacheFactory: () => configCache });
968968
const options: AutoPollOptions = createAutoPollOptions("APIKEY", { maxInitWaitTimeSeconds: 10 }, configCatKernel);
969969
const client: IConfigCatClient = new ConfigCatClient(options, configCatKernel);

test/ConfigServiceBaseTests.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ describe("ConfigServiceBaseTests", () => {
176176

177177
const projectConfigNew: ProjectConfig = createConfigFromFetchResult(frNew);
178178

179-
const time: number = new Date().getTime();
179+
const time: number = ProjectConfig.generateTimestamp();
180180
const projectConfigOld: ProjectConfig = createConfigFromFetchResult(frOld).with(time - (1.5 * pollInterval * 1000) + 0.5 * POLL_EXPIRATION_TOLERANCE_MS);
181181

182182
const cache = new InMemoryConfigCache();
@@ -224,7 +224,7 @@ describe("ConfigServiceBaseTests", () => {
224224

225225
const pollInterval = 10;
226226

227-
const time: number = new Date().getTime();
227+
const time: number = ProjectConfig.generateTimestamp();
228228
const projectConfigOld = createConfigFromFetchResult(frOld).with(time - (pollInterval * 1000) + 0.5 * POLL_EXPIRATION_TOLERANCE_MS);
229229

230230
const cache = new InMemoryConfigCache();
@@ -315,7 +315,7 @@ describe("ConfigServiceBaseTests", () => {
315315
// Arrange
316316

317317
const cacheTimeToLiveSeconds = 10;
318-
const oldConfig: ProjectConfig = createProjectConfig("oldConfig").with(new Date().getTime() - (cacheTimeToLiveSeconds * 1000) - 1000);
318+
const oldConfig: ProjectConfig = createProjectConfig("oldConfig").with(ProjectConfig.generateTimestamp() - (cacheTimeToLiveSeconds * 1000) - 1000);
319319

320320
const fr: FetchResult = createFetchResult("newConfig");
321321

@@ -358,7 +358,7 @@ describe("ConfigServiceBaseTests", () => {
358358

359359
// Arrange
360360

361-
const config: ProjectConfig = createProjectConfig().with(new Date().getTime());
361+
const config: ProjectConfig = createProjectConfig().with(ProjectConfig.generateTimestamp());
362362

363363
const fetcherMock = new Mock<IConfigFetcher>();
364364

@@ -392,7 +392,7 @@ describe("ConfigServiceBaseTests", () => {
392392

393393
// Arrange
394394

395-
const config: ProjectConfig = createProjectConfig().with(new Date().getTime() - 1000);
395+
const config: ProjectConfig = createProjectConfig().with(ProjectConfig.generateTimestamp() - 1000);
396396

397397
const fr: FetchResult = createFetchResult();
398398

@@ -433,7 +433,7 @@ describe("ConfigServiceBaseTests", () => {
433433

434434
// Arrange
435435

436-
const config: ProjectConfig = createProjectConfig().with(new Date().getTime() - 1000);
436+
const config: ProjectConfig = createProjectConfig().with(ProjectConfig.generateTimestamp() - 1000);
437437

438438
const fr: FetchResult = createFetchResult();
439439

test/browser/HttpTests.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import * as mockxmlhttprequest from "mock-xmlhttprequest";
33
import { FakeLogger } from "../helpers/fakes";
44
import { platform } from ".";
55
import { LogLevel } from "#lib";
6+
import { getMonotonicTimeMs } from "#lib/Utils";
67

78
describe("HTTP tests", () => {
89
const sdkKey = "configcat-sdk-1/PKDVCLf-Hq-h-kCzMp-L7Q/AG6C1ngVb0CvM07un6JisQ";
@@ -25,9 +26,9 @@ describe("HTTP tests", () => {
2526
baseUrl,
2627
logger,
2728
});
28-
const startTime = new Date().getTime();
29+
const startTime = getMonotonicTimeMs();
2930
await client.forceRefreshAsync();
30-
const duration = new Date().getTime() - startTime;
31+
const duration = getMonotonicTimeMs() - startTime;
3132
assert.isTrue(duration > 1000 && duration < 2000);
3233

3334
const defaultValue = "NOT_CAT";

test/chromium-extension/HttpTests.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import fetchMock from "fetch-mock";
33
import { FakeLogger } from "../helpers/fakes";
44
import { platform } from ".";
55
import { LogLevel } from "#lib";
6+
import { getMonotonicTimeMs } from "#lib/Utils";
67

78
describe("HTTP tests", () => {
89
const sdkKey = "PKDVCLf-Hq-h-kCzMp-L7Q/psuH7BGHoUmdONrzzUOY7A";
@@ -23,9 +24,9 @@ describe("HTTP tests", () => {
2324
baseUrl,
2425
logger,
2526
});
26-
const startTime = new Date().getTime();
27+
const startTime = getMonotonicTimeMs();
2728
await client.forceRefreshAsync();
28-
const duration = new Date().getTime() - startTime;
29+
const duration = getMonotonicTimeMs() - startTime;
2930
assert.isTrue(duration > 1000 && duration < 2000);
3031

3132
const defaultValue = "NOT_CAT";

test/helpers/fakes.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ export class FakeExternalCacheWithInitialData implements IConfigCatCache {
111111
}
112112
get(key: string): string | Promise<string | null | undefined> | null | undefined {
113113
const cachedJson = '{"f":{"debug":{"t":0,"v":{"b":true},"i":"abcdefgh"}}}';
114-
const config = new ProjectConfig(cachedJson, JSON.parse(cachedJson), (new Date().getTime()) - this.expirationDelta, "\"ETAG\"");
114+
const config = new ProjectConfig(cachedJson, JSON.parse(cachedJson), ProjectConfig.generateTimestamp() - this.expirationDelta, "\"ETAG\"");
115115
return ProjectConfig.serialize(config);
116116
}
117117

test/node/HttpTests.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import * as mockttp from "mockttp";
33
import { FakeLogger } from "../helpers/fakes";
44
import { platform } from ".";
55
import { LogLevel } from "#lib";
6+
import { getMonotonicTimeMs } from "#lib/Utils";
67

78
// If the tests are failing with strange https or proxy errors, it is most likely that the local .key and .pem files are expired.
89
// You can regenerate them anytime (./test/cert/regenerate.md).
@@ -31,9 +32,9 @@ describe("HTTP tests", () => {
3132
baseUrl: server.url,
3233
logger,
3334
});
34-
const startTime = new Date().getTime();
35+
const startTime = getMonotonicTimeMs();
3536
await client.forceRefreshAsync();
36-
const duration = new Date().getTime() - startTime;
37+
const duration = getMonotonicTimeMs() - startTime;
3738
assert.isTrue(duration > 1000 && duration < 2000);
3839

3940
const defaultValue = "NOT_CAT";

0 commit comments

Comments
 (0)