From 4d41dd00877dc7d162b965e7d5b8e1234dd39f3a Mon Sep 17 00:00:00 2001 From: Michael Peters Date: Wed, 5 Oct 2022 21:38:51 -0700 Subject: [PATCH] lazy cache hit/miss tests --- src/client/tests/webapp/auto-verifier.test.ts | 104 +++++++++++++++++- src/client/webapp/auto-verifier.ts | 2 + 2 files changed, 104 insertions(+), 2 deletions(-) diff --git a/src/client/tests/webapp/auto-verifier.test.ts b/src/client/tests/webapp/auto-verifier.test.ts index fc205f9..71e9519 100644 --- a/src/client/tests/webapp/auto-verifier.test.ts +++ b/src/client/tests/webapp/auto-verifier.test.ts @@ -445,6 +445,106 @@ describe('fetchAndVerifyIfNeeded tests', () => { expect(ensureTrustedFuncReadyFunc).toHaveBeenCalledTimes(1); expect(verifyFunc).toHaveBeenCalledTimes(1); }); - // Make sure to do try/catch errors, verification failures, unverifies in the middle - // Lazy verify - primary null and primary with value + + test('primary with null, lazy - lazy cache miss, need to ping server', async () => { + const { + nextPrimary, nextTrusted, nextEnsureTrustedFuncReady, nextVerify, + primaryFunc, trustedFunc, ensureTrustedFuncReadyFunc, verifyFunc + } = getManualsAndMocks(); + + const primary = nextPrimary(); + const trusted = nextTrusted(); + const ensureTrustedFuncReady = nextEnsureTrustedFuncReady(); + const verify = nextVerify(); + + const av = new AutoVerifier(primaryFunc, trustedFunc, ensureTrustedFuncReadyFunc, verifyFunc); + const resultPromise = av.fetchAndVerifyIfNeeded(true); + let result: BasicWE | null | undefined = undefined; + resultPromise.then(value => { result = value; }); + + expect(av.primaryPromise).toBe(primary.promise); + expect(av.trustedPromise).toBe(null); // trustedFunc will never be called + expect(av.trustedStatus).toBe('none'); + expect(primaryFunc).toHaveBeenCalled(); + + expect(trustedFunc).toHaveBeenCalledTimes(0); + expect(ensureTrustedFuncReadyFunc).toHaveBeenCalledTimes(0); + primary.resolve(null); + await disjoint(); + + expect(trustedFunc).toHaveBeenCalled(); + expect(ensureTrustedFuncReadyFunc).toHaveBeenCalled(); + expect(av.primaryPromise).toBe(null); + expect(av.trustedPromise).toBe(trusted.promise); + expect(av.trustedStatus).toBe('verifying'); // notably, we will never publicly see it in 'fetching' + + ensureTrustedFuncReady.resolve(); + await disjoint(); + + expect(av.primaryPromise).toBe(null); + expect(av.trustedPromise).toBe(trusted.promise); + expect(av.trustedStatus).toBe('verifying'); + + expect(verifyFunc).toHaveBeenCalledTimes(0); + trusted.resolve(new BasicWE(2)); + await disjoint(); + + expect(verifyFunc).toHaveBeenCalledWith(null, new BasicWE(2)); + expect(av.primaryPromise).toBe(null); + expect(av.trustedPromise).toBe(trusted.promise); + expect(av.trustedStatus).toBe('verifying'); + + expect(primaryFunc).toHaveBeenCalledTimes(1); + expect(trustedFunc).toHaveBeenCalledTimes(1); + expect(ensureTrustedFuncReadyFunc).toHaveBeenCalledTimes(1); + expect(verifyFunc).toHaveBeenCalledTimes(1); + + expect(result).toBeUndefined(); + verify.resolve(true); + await disjoint(); + + expect(result).toEqual(new BasicWE(2)); + expect(av.primaryPromise).toBe(null); + expect(av.trustedPromise).toBe(trusted.promise); + expect(av.trustedStatus).toBe('verified'); + + expect(primaryFunc).toHaveBeenCalledTimes(1); + expect(trustedFunc).toHaveBeenCalledTimes(1); + expect(ensureTrustedFuncReadyFunc).toHaveBeenCalledTimes(1); + expect(verifyFunc).toHaveBeenCalledTimes(1); + }); + + test('primary with value, lazy - lazy cache hit, no need to ping server', async () => { + const { + nextPrimary, + primaryFunc, trustedFunc, ensureTrustedFuncReadyFunc, verifyFunc + } = getManualsAndMocks(); + + const primary = nextPrimary(); + + const av = new AutoVerifier(primaryFunc, trustedFunc, ensureTrustedFuncReadyFunc, verifyFunc); + const resultPromise = av.fetchAndVerifyIfNeeded(true); + let result: BasicWE | null | undefined = undefined; + resultPromise.then(value => { result = value; }); + + expect(av.primaryPromise).toBe(primary.promise); + expect(av.trustedPromise).toBe(null); // trustedFunc will never be called + expect(av.trustedStatus).toBe('none'); + expect(primaryFunc).toHaveBeenCalled(); + + expect(result).toBeUndefined(); + primary.resolve(new BasicWE(2)); + await disjoint(); + + expect(result).toEqual(new BasicWE(2)); + expect(av.trustedStatus).toBe('none'); + + expect(primaryFunc).toHaveBeenCalledTimes(1); + expect(trustedFunc).toHaveBeenCalledTimes(0); + expect(ensureTrustedFuncReadyFunc).toHaveBeenCalledTimes(0); + expect(verifyFunc).toHaveBeenCalledTimes(0); + }); + + // Make sure to do try/catch errors/rejections, verification failures, unverifies in the middle + // Multiple tryResolveTrustedPromises }); diff --git a/src/client/webapp/auto-verifier.ts b/src/client/webapp/auto-verifier.ts index 77ff7a0..c93e951 100644 --- a/src/client/webapp/auto-verifier.ts +++ b/src/client/webapp/auto-verifier.ts @@ -229,6 +229,7 @@ export class AutoVerifier { return; } } else { + /* istanbul ignore next */ if (debug) LOG.debug(fetchId + ': waiting for trusted to resolve'); } @@ -269,6 +270,7 @@ export class AutoVerifier { new Error(), ); if (this.trustedPromise === null) { + /* istanbul ignore next */ if (debug) LOG.debug(fetchId + ': re-fetching since trustedPromise was null'); this.trustedStatus = 'fetching'; this.trustedPromise = this.trustedFunc();