archive old auto-verifier tests

This commit is contained in:
Michael Peters 2022-10-03 20:56:36 -07:00
parent f3067fa9f1
commit b49dfe3187
2 changed files with 729 additions and 729 deletions

View File

@ -0,0 +1,729 @@
/* eslint-disable @typescript-eslint/no-empty-function */
import { AutoVerifier } from '../../webapp/auto-verifier';
function sleep(ms: number): Promise<void> {
if (ms === 0) return;
return new Promise(resolve => {
setTimeout(resolve, ms);
});
}
// disjoint the current async function to allow other promises to be handled before the next lines are run
async function disjoint() {
await sleep(0);
}
type QueryablePromise<T> = Promise<T> & { isPending: () => boolean; isRejected: () => boolean; isFulfilled: () => boolean };
/**
* this function allow you to modify a JS Promise by adding some status properties.
* Based on: http://stackoverflow.com/questions/21485545/is-there-a-way-to-tell-if-an-es6-promise-is-fulfilled-rejected-resolved
* But modified according to the specs of promises : https://promisesaplus.com/
*/
function makeQuerablePromise<T>(promise: Promise<T>) {
// set initial state
let isPending = true;
let isRejected = false;
let isFulfilled = false;
// observe the promise, saving the fulfillment in a closure scope.
const result = promise.then(
v => {
isFulfilled = true;
isPending = false;
return v;
},
e => {
isRejected = true;
isPending = false;
throw e;
},
);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(result as any).isFulfilled = function () {
return isFulfilled;
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(result as any).isPending = function () {
return isPending;
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(result as any).isRejected = function () {
return isRejected;
};
return result as QueryablePromise<T>;
}
class AutoVerifierTest {
static createSimple<T>(primaryResult: T, trustedResult: T): AutoVerifier<T> {
return new AutoVerifier<T>(
async () => primaryResult,
async () => trustedResult,
async (_primaryResult: T | null, _trustedResult: T | null) => true,
);
}
static createPromises<T>(
primaryResult: T | null,
trustedResult: T | null,
primaryDelay: number,
trustedDelay: number,
verifyDelay: number,
primaryFail = false,
trustedFail = false,
): {
primaryPromise: QueryablePromise<T | null>; // resolves BEFORE the function returns
trustedPromise: QueryablePromise<T | null>; // resolves BEFORE the function returns
verifyPromise: QueryablePromise<{ primaryResult: T | null; trustedResult: T | null }>; // resolves AFTER function returns
verifier: AutoVerifier<T>;
} {
let primaryResolve = (value: T | null) => {
/* */
};
let trustedResolve = (value: T | null) => {
/* */
};
let verifyResolve = (value: { primaryResult: T | null; trustedResult: T | null }) => {
/* */
};
const primaryPromise = new Promise<T | null>((resolve, reject) => {
primaryResolve = resolve;
});
const trustedPromise = new Promise<T | null>((resolve, reject) => {
trustedResolve = resolve;
});
const verifyPromise = new Promise<{ primaryResult: T | null; trustedResult: T | null }>(resolve => {
verifyResolve = resolve;
});
const verifier = new AutoVerifier<T>(
async () => {
await sleep(primaryDelay);
if (primaryFail) {
primaryResolve(null);
throw new Error('primary reject');
} else {
const result = primaryResult;
primaryResolve(result);
await disjoint(); // if you need to know what this does you will not be happy :)
return result;
}
},
async () => {
await sleep(trustedDelay);
if (trustedFail) {
trustedResolve(null);
throw new Error('trusted reject');
} else {
const result = trustedResult;
trustedResolve(result);
await disjoint();
return result;
}
},
async (primaryResult: T | null, trustedResult: T | null) => {
await sleep(verifyDelay);
if (primaryResult !== null && trustedResult !== null && primaryResult !== trustedResult) verifier.unverify(); // auto-unverify if not equal
(async () => {
await disjoint();
verifyResolve({ primaryResult, trustedResult });
})();
},
);
return {
primaryPromise: makeQuerablePromise(primaryPromise),
trustedPromise: makeQuerablePromise(trustedPromise),
verifyPromise: makeQuerablePromise(verifyPromise),
verifier,
};
}
}
describe('basic functionality', () => {
test('basic functionality', async () => {
const verifier = AutoVerifierTest.createSimple(2, 2);
expect(verifier.trustedPromise === null);
expect(verifier.trustedStatus === 'none');
const result = await verifier.fetchAndVerifyIfNeeded();
expect(result).toBe(2);
});
});
describe('promise order tests', () => {
test('normal verification', async () => {
const { primaryPromise, trustedPromise, verifyPromise, verifier } = AutoVerifierTest.createPromises(2, 2, 35, 65, 15);
expect(primaryPromise.isFulfilled()).toBe(false);
expect(trustedPromise.isFulfilled()).toBe(false);
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedPromise).toBe(null);
expect(verifier.trustedStatus).toBe('none');
const fetchPromise = makeQuerablePromise(verifier.fetchAndVerifyIfNeeded());
expect(verifier.trustedPromise !== null);
expect(verifier.trustedStatus === 'fetching');
const primaryResult = await primaryPromise;
expect(primaryResult).toBe(2);
expect(fetchPromise.isFulfilled()).toBe(false);
expect(primaryPromise.isFulfilled()).toBe(true);
expect(trustedPromise.isFulfilled()).toBe(false); // since 35ms < 65ms
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedStatus).toBe('fetching');
await fetchPromise;
expect(fetchPromise.isFulfilled()).toBe(true);
expect(trustedPromise.isFulfilled()).toBe(false); // since 35ms < 65ms
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedStatus).toBe('verifying');
const trustedResult = await trustedPromise;
expect(trustedResult).toBe(2);
expect(trustedPromise.isFulfilled()).toBe(true);
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedStatus).toBe('verifying');
const verification = await verifyPromise;
expect(verification.primaryResult).toBe(2);
expect(verification.trustedResult).toBe(2);
expect(verifyPromise.isFulfilled()).toBe(true);
expect(verifier.trustedStatus).toBe('verified');
});
test('odd-ordered verification', async () => {
const { primaryPromise, trustedPromise, verifyPromise, verifier } = AutoVerifierTest.createPromises(2, 2, 65, 35, 15);
expect(primaryPromise.isFulfilled()).toBe(false);
expect(trustedPromise.isFulfilled()).toBe(false);
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedPromise).toBe(null);
expect(verifier.trustedStatus).toBe('none');
const fetchPromise = makeQuerablePromise(verifier.fetchAndVerifyIfNeeded());
expect(verifier.trustedPromise !== null);
expect(verifier.trustedStatus === 'fetching');
const primaryResult = await primaryPromise;
expect(primaryResult).toBe(2);
expect(primaryPromise.isFulfilled()).toBe(true);
expect(trustedPromise.isFulfilled()).toBe(true); // since 65ms > 35ms
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedStatus).toBe('fetching');
await fetchPromise;
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedStatus).toBe('verifying');
const trustedResult = await trustedPromise; // note: this is already fulfilled
expect(trustedResult).toBe(2);
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedStatus).toBe('verifying');
const verification = await verifyPromise;
expect(verification.primaryResult).toBe(2);
expect(verification.trustedResult).toBe(2);
expect(verifyPromise.isFulfilled()).toBe(true);
expect(verifier.trustedStatus).toBe('verified');
});
test('normal trusted override', async () => {
const { primaryPromise, trustedPromise, verifyPromise, verifier } = AutoVerifierTest.createPromises(null, 3, 35, 65, 15);
expect(primaryPromise.isFulfilled()).toBe(false);
expect(trustedPromise.isFulfilled()).toBe(false);
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedPromise).toBe(null);
expect(verifier.trustedStatus).toBe('none');
const fetchPromise = makeQuerablePromise(verifier.fetchAndVerifyIfNeeded());
expect(verifier.trustedPromise !== null);
expect(verifier.trustedStatus === 'fetching');
const primaryResult = await primaryPromise;
expect(primaryResult).toBe(null);
expect(fetchPromise.isFulfilled()).toBe(false);
expect(primaryPromise.isFulfilled()).toBe(true);
expect(trustedPromise.isFulfilled()).toBe(false); // since 35ms < 65ms
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedStatus).toBe('fetching');
const trustedResult = await trustedPromise;
expect(trustedResult).toBe(3);
expect(fetchPromise.isFulfilled()).toBe(false);
expect(trustedPromise.isFulfilled()).toBe(true);
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedStatus).toBe('verifying');
const verification = await verifyPromise;
expect(verification.primaryResult).toBe(null);
expect(verification.trustedResult).toBe(3);
expect(fetchPromise.isFulfilled()).toBe(true); // since verifyPromise is called AFTER
expect(verifyPromise.isFulfilled()).toBe(true);
expect(verifier.trustedStatus).toBe('verified'); // does not get auto unverified
const result = await fetchPromise;
expect(result).toBe(3);
});
test('normal invalidation', async () => {
const { primaryPromise, trustedPromise, verifyPromise, verifier } = AutoVerifierTest.createPromises(2, 3, 35, 65, 15);
expect(primaryPromise.isFulfilled()).toBe(false);
expect(trustedPromise.isFulfilled()).toBe(false);
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedPromise).toBe(null);
expect(verifier.trustedStatus).toBe('none');
const fetchPromise = makeQuerablePromise(verifier.fetchAndVerifyIfNeeded());
expect(verifier.trustedPromise !== null);
expect(verifier.trustedStatus === 'fetching');
const primaryResult = await primaryPromise;
expect(primaryResult).toBe(2);
expect(fetchPromise.isFulfilled()).toBe(false);
expect(primaryPromise.isFulfilled()).toBe(true);
expect(trustedPromise.isFulfilled()).toBe(false); // since 35ms < 65ms
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedStatus).toBe('fetching');
await fetchPromise;
expect(fetchPromise.isFulfilled()).toBe(true);
expect(trustedPromise.isFulfilled()).toBe(false); // since 35ms < 65ms
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedStatus).toBe('verifying');
const trustedResult = await trustedPromise;
expect(trustedResult).toBe(3);
expect(trustedPromise.isFulfilled()).toBe(true);
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedStatus).toBe('verifying');
const verification = await verifyPromise;
expect(verification.primaryResult).toBe(2);
expect(verification.trustedResult).toBe(3);
expect(verifyPromise.isFulfilled()).toBe(true);
expect(verifier.trustedStatus).toBe('none'); // gets auto unverified
});
test('odd-ordered invalidation', async () => {
const { primaryPromise, trustedPromise, verifyPromise, verifier } = AutoVerifierTest.createPromises(2, 3, 65, 35, 15);
expect(primaryPromise.isFulfilled()).toBe(false);
expect(trustedPromise.isFulfilled()).toBe(false);
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedPromise).toBe(null);
expect(verifier.trustedStatus).toBe('none');
const fetchPromise = makeQuerablePromise(verifier.fetchAndVerifyIfNeeded());
expect(verifier.trustedPromise !== null);
expect(verifier.trustedStatus === 'fetching');
const primaryResult = await primaryPromise;
expect(primaryResult).toBe(2);
expect(fetchPromise.isFulfilled()).toBe(false);
expect(primaryPromise.isFulfilled()).toBe(true);
expect(trustedPromise.isFulfilled()).toBe(true); // since 65ms > 35ms
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedStatus).toBe('fetching');
await fetchPromise;
expect(fetchPromise.isFulfilled()).toBe(true);
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedStatus).toBe('verifying');
const trustedResult = await trustedPromise; // note: this is already fulfilled
expect(trustedResult).toBe(3);
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedStatus).toBe('verifying');
const verification = await verifyPromise;
expect(verification.primaryResult).toBe(2);
expect(verification.trustedResult).toBe(3);
expect(verifyPromise.isFulfilled()).toBe(true);
expect(verifier.trustedStatus).toBe('none'); // gets auto unverified
});
test('normal unverification during primary func', async () => {
const { primaryPromise, trustedPromise, verifyPromise, verifier } = AutoVerifierTest.createPromises(2, 2, 35, 65, 15);
expect(primaryPromise.isFulfilled()).toBe(false);
expect(trustedPromise.isFulfilled()).toBe(false);
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedPromise).toBe(null);
expect(verifier.trustedStatus).toBe('none');
const fetchPromise = makeQuerablePromise(verifier.fetchAndVerifyIfNeeded());
expect(verifier.trustedPromise !== null);
expect(verifier.trustedStatus === 'fetching');
const primaryResult = await primaryPromise;
expect(primaryResult).toBe(2);
expect(fetchPromise.isFulfilled()).toBe(false);
expect(primaryPromise.isFulfilled()).toBe(true);
expect(trustedPromise.isFulfilled()).toBe(false); // since 35ms < 65ms
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedStatus).toBe('fetching');
verifier.unverify(); // keep in mind this is still during the primary func since this is before we await the fetchPromise
expect(verifier.trustedPromise).toBe(null);
expect(verifier.trustedStatus).toBe('none');
await fetchPromise;
expect(fetchPromise.isFulfilled()).toBe(true);
expect(trustedPromise.isFulfilled()).toBe(false); // since 35ms < 65ms
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedStatus).toBe('verifying');
const trustedResult = await trustedPromise;
expect(trustedResult).toBe(2);
expect(trustedPromise.isFulfilled()).toBe(true);
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedStatus).toBe('verifying');
const verification = await verifyPromise;
expect(verification.primaryResult).toBe(2);
expect(verification.trustedResult).toBe(2);
expect(verifyPromise.isFulfilled()).toBe(true);
expect(verifier.trustedStatus).toBe('verified');
});
test('odd-ordered unverification during primary func', async () => {
const { primaryPromise, trustedPromise, verifyPromise, verifier } = AutoVerifierTest.createPromises(2, 2, 65, 35, 15);
expect(primaryPromise.isFulfilled()).toBe(false);
expect(trustedPromise.isFulfilled()).toBe(false);
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedPromise).toBe(null);
expect(verifier.trustedStatus).toBe('none');
const fetchPromise = makeQuerablePromise(verifier.fetchAndVerifyIfNeeded());
expect(verifier.trustedPromise !== null);
expect(verifier.trustedStatus === 'fetching');
const primaryResult = await primaryPromise;
expect(primaryResult).toBe(2);
expect(fetchPromise.isFulfilled()).toBe(false);
expect(primaryPromise.isFulfilled()).toBe(true);
expect(trustedPromise.isFulfilled()).toBe(true); // since 65ms > 35ms
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedStatus).toBe('fetching');
verifier.unverify();
expect(verifier.trustedPromise).toBe(null);
expect(verifier.trustedStatus).toBe('none');
await fetchPromise;
expect(fetchPromise.isFulfilled()).toBe(true);
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedStatus).toBe('verifying');
const trustedResult = await trustedPromise; // note: this is already fulfilled
expect(trustedResult).toBe(2);
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedStatus).toBe('verifying');
const verification = await verifyPromise;
expect(verification.primaryResult).toBe(2);
expect(verification.trustedResult).toBe(2);
expect(verifyPromise.isFulfilled()).toBe(true);
expect(verifier.trustedStatus).toBe('verified');
});
test('normal unverification during trusted func', async () => {
const { primaryPromise, trustedPromise, verifyPromise, verifier } = AutoVerifierTest.createPromises(2, 2, 35, 65, 15);
expect(primaryPromise.isFulfilled()).toBe(false);
expect(trustedPromise.isFulfilled()).toBe(false);
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedPromise).toBe(null);
expect(verifier.trustedStatus).toBe('none');
const fetchPromise = makeQuerablePromise(verifier.fetchAndVerifyIfNeeded());
expect(verifier.trustedPromise !== null);
expect(verifier.trustedStatus === 'fetching');
const primaryResult = await primaryPromise;
expect(primaryResult).toBe(2);
expect(fetchPromise.isFulfilled()).toBe(false);
expect(primaryPromise.isFulfilled()).toBe(true);
expect(trustedPromise.isFulfilled()).toBe(false); // since 35ms < 65ms
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedStatus).toBe('fetching');
await fetchPromise;
expect(fetchPromise.isFulfilled()).toBe(true);
expect(trustedPromise.isFulfilled()).toBe(false); // since 35ms < 65ms
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedStatus).toBe('verifying');
verifier.unverify();
expect(verifier.trustedPromise).toBe(null);
expect(verifier.trustedStatus).toBe('none');
const trustedResult = await trustedPromise;
expect(trustedResult).toBe(2);
expect(trustedPromise.isFulfilled()).toBe(true);
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedStatus).toBe('none');
// verification will not happen since the verifier.trustedPromise is null and we already returned
});
test('normal unverification during primary func with trusted override', async () => {
const { primaryPromise, trustedPromise, verifyPromise, verifier } = AutoVerifierTest.createPromises(null, 2, 35, 65, 15);
expect(primaryPromise.isFulfilled()).toBe(false);
expect(trustedPromise.isFulfilled()).toBe(false);
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedPromise).toBe(null);
expect(verifier.trustedStatus).toBe('none');
const fetchPromise = makeQuerablePromise(verifier.fetchAndVerifyIfNeeded());
expect(verifier.trustedPromise !== null);
expect(verifier.trustedStatus === 'fetching');
const primaryResult = await primaryPromise;
expect(primaryResult).toBe(null);
expect(fetchPromise.isFulfilled()).toBe(false);
expect(primaryPromise.isFulfilled()).toBe(true);
expect(trustedPromise.isFulfilled()).toBe(false); // since 35ms < 65ms
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedStatus).toBe('fetching');
verifier.unverify(); // keep in mind this is still during the primary func since this is before we await the fetchPromise
expect(verifier.trustedPromise).toBe(null);
expect(verifier.trustedStatus).toBe('none');
const trustedResult = await trustedPromise;
expect(trustedResult).toBe(2);
expect(fetchPromise.isFulfilled()).toBe(false);
expect(trustedPromise.isFulfilled()).toBe(true);
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedStatus).toBe('verifying');
const verification = await verifyPromise;
expect(verification.primaryResult).toBe(null);
expect(verification.trustedResult).toBe(2);
expect(fetchPromise.isFulfilled()).toBe(true); // since verifyPromise occurs AFTER it returns
expect(verifyPromise.isFulfilled()).toBe(true);
expect(verifier.trustedStatus).toBe('verified');
const fetchResult = await fetchPromise;
expect(fetchResult).toBe(2);
expect(fetchPromise.isFulfilled()).toBe(true);
});
test('normal unverification during trusted func with trusted override', async () => {
const { primaryPromise, trustedPromise, verifyPromise, verifier } = AutoVerifierTest.createPromises(null, 2, 35, 65, 15);
expect(primaryPromise.isFulfilled()).toBe(false);
expect(trustedPromise.isFulfilled()).toBe(false);
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedPromise).toBe(null);
expect(verifier.trustedStatus).toBe('none');
const fetchPromise = makeQuerablePromise(verifier.fetchAndVerifyIfNeeded());
expect(verifier.trustedPromise !== null);
expect(verifier.trustedStatus === 'fetching');
const primaryResult = await primaryPromise;
expect(primaryResult).toBe(null);
expect(fetchPromise.isFulfilled()).toBe(false);
expect(primaryPromise.isFulfilled()).toBe(true);
expect(trustedPromise.isFulfilled()).toBe(false); // since 35ms < 65ms
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedStatus).toBe('fetching');
const trustedResult = await trustedPromise;
expect(trustedResult).toBe(2);
verifier.unverify(); // keep in mind this is still during the trusted func since this is before we await the fetchPromise
expect(verifier.trustedPromise).toBe(null);
expect(verifier.trustedStatus).toBe('none');
expect(fetchPromise.isFulfilled()).toBe(false);
expect(trustedPromise.isFulfilled()).toBe(true);
expect(verifyPromise.isFulfilled()).toBe(false);
// this will resolve with null since we got unverified during the fetch
const fetchResult = await fetchPromise;
expect(fetchResult).toBe(null);
expect(fetchPromise.isFulfilled()).toBe(true);
});
});
describe('error tests', () => {
test('primary error', async () => {
const { primaryPromise, trustedPromise, verifyPromise, verifier } = AutoVerifierTest.createPromises(2, 2, 35, 65, 15, true, false);
expect.assertions(3);
try {
await verifier.fetchAndVerifyIfNeeded();
} catch (e) {
expect(e).toBeDefined();
}
await primaryPromise;
await trustedPromise;
await disjoint();
expect(verifier.trustedPromise).toBe(null);
expect(verifier.trustedStatus).toBe('none');
});
test('trusted error thrown out', async () => {
const { primaryPromise, trustedPromise, verifyPromise, verifier } = AutoVerifierTest.createPromises(2, 2, 35, 65, 15, false, true);
await verifier.fetchAndVerifyIfNeeded();
await primaryPromise;
await trustedPromise;
await disjoint();
await disjoint(); // :D since trustedPromise happens BEFORE
expect(verifier.trustedPromise).toBe(null);
expect(verifier.trustedStatus).toBe('none');
});
test('trusted error considered since null primary result', async () => {
const { primaryPromise, trustedPromise, verifyPromise, verifier } = AutoVerifierTest.createPromises(null, 2, 35, 65, 15, false, true);
expect.assertions(3);
try {
await verifier.fetchAndVerifyIfNeeded();
} catch (e) {
expect(e).toBeDefined();
}
await primaryPromise;
await trustedPromise;
await disjoint();
expect(verifier.trustedPromise).toBe(null);
expect(verifier.trustedStatus).toBe('none');
});
test('both error only one exception', async () => {
const { primaryPromise, trustedPromise, verifyPromise, verifier } = AutoVerifierTest.createPromises(2, 2, 35, 65, 15, true, true);
expect.assertions(3);
try {
await verifier.fetchAndVerifyIfNeeded();
} catch (e) {
expect(e).toBeDefined();
}
await primaryPromise;
await trustedPromise;
await disjoint();
expect(verifier.trustedPromise).toBe(null);
expect(verifier.trustedStatus).toBe('none');
});
});
describe('deduplication', () => {
test('primary deduplication', async () => {
const { primaryPromise, trustedPromise, verifyPromise, verifier } = AutoVerifierTest.createPromises(2, 3, 35, 65, 15);
await Promise.all([
(async () => {
const fetchResult = await verifier.fetchAndVerifyIfNeeded();
expect(fetchResult).toBe(2);
})(),
(async () => {
const fetchResult = await verifier.fetchAndVerifyIfNeeded();
expect(fetchResult).toBe(2);
})(),
]);
});
test('trusted deduplication', async () => {
const { primaryPromise, trustedPromise, verifyPromise, verifier } = AutoVerifierTest.createPromises(null, 3, 35, 65, 15);
await Promise.all([
(async () => {
const fetchResult = await verifier.fetchAndVerifyIfNeeded();
expect(fetchResult).toBe(3);
})(),
(async () => {
const fetchResult = await verifier.fetchAndVerifyIfNeeded();
expect(fetchResult).toBe(3);
})(),
]);
// doesn't really test it but it gets the code coverage B)
});
test('trusted deduplication with unverification', async () => {
const { primaryPromise, trustedPromise, verifyPromise, verifier } = AutoVerifierTest.createPromises(null, 3, 35, 65, 15);
await Promise.all([
(async () => {
const fetchPromise = verifier.fetchAndVerifyIfNeeded();
const fetchResult = await fetchPromise;
expect(fetchResult).toBe(null);
})(),
(async () => {
const fetchPromise = verifier.fetchAndVerifyIfNeeded();
await trustedPromise;
verifier.unverify();
const fetchResult = await fetchPromise;
expect(fetchResult).toBe(null);
})(),
]);
});
});
// TODO: changesFunc
// TODO: Standard autoverifiers?

View File

@ -1,729 +0,0 @@
/* eslint-disable @typescript-eslint/no-empty-function */
import { AutoVerifier } from '../../webapp/auto-verifier';
function sleep(ms: number): Promise<void> {
if (ms === 0) return;
return new Promise(resolve => {
setTimeout(resolve, ms);
});
}
// disjoint the current async function to allow other promises to be handled before the next lines are run
async function disjoint() {
await sleep(0);
}
type QueryablePromise<T> = Promise<T> & { isPending: () => boolean; isRejected: () => boolean; isFulfilled: () => boolean };
/**
* this function allow you to modify a JS Promise by adding some status properties.
* Based on: http://stackoverflow.com/questions/21485545/is-there-a-way-to-tell-if-an-es6-promise-is-fulfilled-rejected-resolved
* But modified according to the specs of promises : https://promisesaplus.com/
*/
function makeQuerablePromise<T>(promise: Promise<T>) {
// set initial state
let isPending = true;
let isRejected = false;
let isFulfilled = false;
// observe the promise, saving the fulfillment in a closure scope.
const result = promise.then(
v => {
isFulfilled = true;
isPending = false;
return v;
},
e => {
isRejected = true;
isPending = false;
throw e;
},
);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(result as any).isFulfilled = function () {
return isFulfilled;
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(result as any).isPending = function () {
return isPending;
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(result as any).isRejected = function () {
return isRejected;
};
return result as QueryablePromise<T>;
}
class AutoVerifierTest {
static createSimple<T>(primaryResult: T, trustedResult: T): AutoVerifier<T> {
return new AutoVerifier<T>(
async () => primaryResult,
async () => trustedResult,
async (_primaryResult: T | null, _trustedResult: T | null) => true,
);
}
static createPromises<T>(
primaryResult: T | null,
trustedResult: T | null,
primaryDelay: number,
trustedDelay: number,
verifyDelay: number,
primaryFail = false,
trustedFail = false,
): {
primaryPromise: QueryablePromise<T | null>; // resolves BEFORE the function returns
trustedPromise: QueryablePromise<T | null>; // resolves BEFORE the function returns
verifyPromise: QueryablePromise<{ primaryResult: T | null; trustedResult: T | null }>; // resolves AFTER function returns
verifier: AutoVerifier<T>;
} {
let primaryResolve = (value: T | null) => {
/* */
};
let trustedResolve = (value: T | null) => {
/* */
};
let verifyResolve = (value: { primaryResult: T | null; trustedResult: T | null }) => {
/* */
};
const primaryPromise = new Promise<T | null>((resolve, reject) => {
primaryResolve = resolve;
});
const trustedPromise = new Promise<T | null>((resolve, reject) => {
trustedResolve = resolve;
});
const verifyPromise = new Promise<{ primaryResult: T | null; trustedResult: T | null }>(resolve => {
verifyResolve = resolve;
});
const verifier = new AutoVerifier<T>(
async () => {
await sleep(primaryDelay);
if (primaryFail) {
primaryResolve(null);
throw new Error('primary reject');
} else {
const result = primaryResult;
primaryResolve(result);
await disjoint(); // if you need to know what this does you will not be happy :)
return result;
}
},
async () => {
await sleep(trustedDelay);
if (trustedFail) {
trustedResolve(null);
throw new Error('trusted reject');
} else {
const result = trustedResult;
trustedResolve(result);
await disjoint();
return result;
}
},
async (primaryResult: T | null, trustedResult: T | null) => {
await sleep(verifyDelay);
if (primaryResult !== null && trustedResult !== null && primaryResult !== trustedResult) verifier.unverify(); // auto-unverify if not equal
(async () => {
await disjoint();
verifyResolve({ primaryResult, trustedResult });
})();
},
);
return {
primaryPromise: makeQuerablePromise(primaryPromise),
trustedPromise: makeQuerablePromise(trustedPromise),
verifyPromise: makeQuerablePromise(verifyPromise),
verifier,
};
}
}
describe('basic functionality', () => {
test('basic functionality', async () => {
const verifier = AutoVerifierTest.createSimple(2, 2);
expect(verifier.trustedPromise === null);
expect(verifier.trustedStatus === 'none');
const result = await verifier.fetchAndVerifyIfNeeded();
expect(result).toBe(2);
});
});
describe('promise order tests', () => {
test('normal verification', async () => {
const { primaryPromise, trustedPromise, verifyPromise, verifier } = AutoVerifierTest.createPromises(2, 2, 35, 65, 15);
expect(primaryPromise.isFulfilled()).toBe(false);
expect(trustedPromise.isFulfilled()).toBe(false);
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedPromise).toBe(null);
expect(verifier.trustedStatus).toBe('none');
const fetchPromise = makeQuerablePromise(verifier.fetchAndVerifyIfNeeded());
expect(verifier.trustedPromise !== null);
expect(verifier.trustedStatus === 'fetching');
const primaryResult = await primaryPromise;
expect(primaryResult).toBe(2);
expect(fetchPromise.isFulfilled()).toBe(false);
expect(primaryPromise.isFulfilled()).toBe(true);
expect(trustedPromise.isFulfilled()).toBe(false); // since 35ms < 65ms
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedStatus).toBe('fetching');
await fetchPromise;
expect(fetchPromise.isFulfilled()).toBe(true);
expect(trustedPromise.isFulfilled()).toBe(false); // since 35ms < 65ms
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedStatus).toBe('verifying');
const trustedResult = await trustedPromise;
expect(trustedResult).toBe(2);
expect(trustedPromise.isFulfilled()).toBe(true);
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedStatus).toBe('verifying');
const verification = await verifyPromise;
expect(verification.primaryResult).toBe(2);
expect(verification.trustedResult).toBe(2);
expect(verifyPromise.isFulfilled()).toBe(true);
expect(verifier.trustedStatus).toBe('verified');
});
test('odd-ordered verification', async () => {
const { primaryPromise, trustedPromise, verifyPromise, verifier } = AutoVerifierTest.createPromises(2, 2, 65, 35, 15);
expect(primaryPromise.isFulfilled()).toBe(false);
expect(trustedPromise.isFulfilled()).toBe(false);
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedPromise).toBe(null);
expect(verifier.trustedStatus).toBe('none');
const fetchPromise = makeQuerablePromise(verifier.fetchAndVerifyIfNeeded());
expect(verifier.trustedPromise !== null);
expect(verifier.trustedStatus === 'fetching');
const primaryResult = await primaryPromise;
expect(primaryResult).toBe(2);
expect(primaryPromise.isFulfilled()).toBe(true);
expect(trustedPromise.isFulfilled()).toBe(true); // since 65ms > 35ms
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedStatus).toBe('fetching');
await fetchPromise;
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedStatus).toBe('verifying');
const trustedResult = await trustedPromise; // note: this is already fulfilled
expect(trustedResult).toBe(2);
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedStatus).toBe('verifying');
const verification = await verifyPromise;
expect(verification.primaryResult).toBe(2);
expect(verification.trustedResult).toBe(2);
expect(verifyPromise.isFulfilled()).toBe(true);
expect(verifier.trustedStatus).toBe('verified');
});
test('normal trusted override', async () => {
const { primaryPromise, trustedPromise, verifyPromise, verifier } = AutoVerifierTest.createPromises(null, 3, 35, 65, 15);
expect(primaryPromise.isFulfilled()).toBe(false);
expect(trustedPromise.isFulfilled()).toBe(false);
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedPromise).toBe(null);
expect(verifier.trustedStatus).toBe('none');
const fetchPromise = makeQuerablePromise(verifier.fetchAndVerifyIfNeeded());
expect(verifier.trustedPromise !== null);
expect(verifier.trustedStatus === 'fetching');
const primaryResult = await primaryPromise;
expect(primaryResult).toBe(null);
expect(fetchPromise.isFulfilled()).toBe(false);
expect(primaryPromise.isFulfilled()).toBe(true);
expect(trustedPromise.isFulfilled()).toBe(false); // since 35ms < 65ms
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedStatus).toBe('fetching');
const trustedResult = await trustedPromise;
expect(trustedResult).toBe(3);
expect(fetchPromise.isFulfilled()).toBe(false);
expect(trustedPromise.isFulfilled()).toBe(true);
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedStatus).toBe('verifying');
const verification = await verifyPromise;
expect(verification.primaryResult).toBe(null);
expect(verification.trustedResult).toBe(3);
expect(fetchPromise.isFulfilled()).toBe(true); // since verifyPromise is called AFTER
expect(verifyPromise.isFulfilled()).toBe(true);
expect(verifier.trustedStatus).toBe('verified'); // does not get auto unverified
const result = await fetchPromise;
expect(result).toBe(3);
});
test('normal invalidation', async () => {
const { primaryPromise, trustedPromise, verifyPromise, verifier } = AutoVerifierTest.createPromises(2, 3, 35, 65, 15);
expect(primaryPromise.isFulfilled()).toBe(false);
expect(trustedPromise.isFulfilled()).toBe(false);
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedPromise).toBe(null);
expect(verifier.trustedStatus).toBe('none');
const fetchPromise = makeQuerablePromise(verifier.fetchAndVerifyIfNeeded());
expect(verifier.trustedPromise !== null);
expect(verifier.trustedStatus === 'fetching');
const primaryResult = await primaryPromise;
expect(primaryResult).toBe(2);
expect(fetchPromise.isFulfilled()).toBe(false);
expect(primaryPromise.isFulfilled()).toBe(true);
expect(trustedPromise.isFulfilled()).toBe(false); // since 35ms < 65ms
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedStatus).toBe('fetching');
await fetchPromise;
expect(fetchPromise.isFulfilled()).toBe(true);
expect(trustedPromise.isFulfilled()).toBe(false); // since 35ms < 65ms
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedStatus).toBe('verifying');
const trustedResult = await trustedPromise;
expect(trustedResult).toBe(3);
expect(trustedPromise.isFulfilled()).toBe(true);
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedStatus).toBe('verifying');
const verification = await verifyPromise;
expect(verification.primaryResult).toBe(2);
expect(verification.trustedResult).toBe(3);
expect(verifyPromise.isFulfilled()).toBe(true);
expect(verifier.trustedStatus).toBe('none'); // gets auto unverified
});
test('odd-ordered invalidation', async () => {
const { primaryPromise, trustedPromise, verifyPromise, verifier } = AutoVerifierTest.createPromises(2, 3, 65, 35, 15);
expect(primaryPromise.isFulfilled()).toBe(false);
expect(trustedPromise.isFulfilled()).toBe(false);
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedPromise).toBe(null);
expect(verifier.trustedStatus).toBe('none');
const fetchPromise = makeQuerablePromise(verifier.fetchAndVerifyIfNeeded());
expect(verifier.trustedPromise !== null);
expect(verifier.trustedStatus === 'fetching');
const primaryResult = await primaryPromise;
expect(primaryResult).toBe(2);
expect(fetchPromise.isFulfilled()).toBe(false);
expect(primaryPromise.isFulfilled()).toBe(true);
expect(trustedPromise.isFulfilled()).toBe(true); // since 65ms > 35ms
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedStatus).toBe('fetching');
await fetchPromise;
expect(fetchPromise.isFulfilled()).toBe(true);
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedStatus).toBe('verifying');
const trustedResult = await trustedPromise; // note: this is already fulfilled
expect(trustedResult).toBe(3);
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedStatus).toBe('verifying');
const verification = await verifyPromise;
expect(verification.primaryResult).toBe(2);
expect(verification.trustedResult).toBe(3);
expect(verifyPromise.isFulfilled()).toBe(true);
expect(verifier.trustedStatus).toBe('none'); // gets auto unverified
});
test('normal unverification during primary func', async () => {
const { primaryPromise, trustedPromise, verifyPromise, verifier } = AutoVerifierTest.createPromises(2, 2, 35, 65, 15);
expect(primaryPromise.isFulfilled()).toBe(false);
expect(trustedPromise.isFulfilled()).toBe(false);
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedPromise).toBe(null);
expect(verifier.trustedStatus).toBe('none');
const fetchPromise = makeQuerablePromise(verifier.fetchAndVerifyIfNeeded());
expect(verifier.trustedPromise !== null);
expect(verifier.trustedStatus === 'fetching');
const primaryResult = await primaryPromise;
expect(primaryResult).toBe(2);
expect(fetchPromise.isFulfilled()).toBe(false);
expect(primaryPromise.isFulfilled()).toBe(true);
expect(trustedPromise.isFulfilled()).toBe(false); // since 35ms < 65ms
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedStatus).toBe('fetching');
verifier.unverify(); // keep in mind this is still during the primary func since this is before we await the fetchPromise
expect(verifier.trustedPromise).toBe(null);
expect(verifier.trustedStatus).toBe('none');
await fetchPromise;
expect(fetchPromise.isFulfilled()).toBe(true);
expect(trustedPromise.isFulfilled()).toBe(false); // since 35ms < 65ms
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedStatus).toBe('verifying');
const trustedResult = await trustedPromise;
expect(trustedResult).toBe(2);
expect(trustedPromise.isFulfilled()).toBe(true);
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedStatus).toBe('verifying');
const verification = await verifyPromise;
expect(verification.primaryResult).toBe(2);
expect(verification.trustedResult).toBe(2);
expect(verifyPromise.isFulfilled()).toBe(true);
expect(verifier.trustedStatus).toBe('verified');
});
test('odd-ordered unverification during primary func', async () => {
const { primaryPromise, trustedPromise, verifyPromise, verifier } = AutoVerifierTest.createPromises(2, 2, 65, 35, 15);
expect(primaryPromise.isFulfilled()).toBe(false);
expect(trustedPromise.isFulfilled()).toBe(false);
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedPromise).toBe(null);
expect(verifier.trustedStatus).toBe('none');
const fetchPromise = makeQuerablePromise(verifier.fetchAndVerifyIfNeeded());
expect(verifier.trustedPromise !== null);
expect(verifier.trustedStatus === 'fetching');
const primaryResult = await primaryPromise;
expect(primaryResult).toBe(2);
expect(fetchPromise.isFulfilled()).toBe(false);
expect(primaryPromise.isFulfilled()).toBe(true);
expect(trustedPromise.isFulfilled()).toBe(true); // since 65ms > 35ms
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedStatus).toBe('fetching');
verifier.unverify();
expect(verifier.trustedPromise).toBe(null);
expect(verifier.trustedStatus).toBe('none');
await fetchPromise;
expect(fetchPromise.isFulfilled()).toBe(true);
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedStatus).toBe('verifying');
const trustedResult = await trustedPromise; // note: this is already fulfilled
expect(trustedResult).toBe(2);
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedStatus).toBe('verifying');
const verification = await verifyPromise;
expect(verification.primaryResult).toBe(2);
expect(verification.trustedResult).toBe(2);
expect(verifyPromise.isFulfilled()).toBe(true);
expect(verifier.trustedStatus).toBe('verified');
});
test('normal unverification during trusted func', async () => {
const { primaryPromise, trustedPromise, verifyPromise, verifier } = AutoVerifierTest.createPromises(2, 2, 35, 65, 15);
expect(primaryPromise.isFulfilled()).toBe(false);
expect(trustedPromise.isFulfilled()).toBe(false);
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedPromise).toBe(null);
expect(verifier.trustedStatus).toBe('none');
const fetchPromise = makeQuerablePromise(verifier.fetchAndVerifyIfNeeded());
expect(verifier.trustedPromise !== null);
expect(verifier.trustedStatus === 'fetching');
const primaryResult = await primaryPromise;
expect(primaryResult).toBe(2);
expect(fetchPromise.isFulfilled()).toBe(false);
expect(primaryPromise.isFulfilled()).toBe(true);
expect(trustedPromise.isFulfilled()).toBe(false); // since 35ms < 65ms
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedStatus).toBe('fetching');
await fetchPromise;
expect(fetchPromise.isFulfilled()).toBe(true);
expect(trustedPromise.isFulfilled()).toBe(false); // since 35ms < 65ms
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedStatus).toBe('verifying');
verifier.unverify();
expect(verifier.trustedPromise).toBe(null);
expect(verifier.trustedStatus).toBe('none');
const trustedResult = await trustedPromise;
expect(trustedResult).toBe(2);
expect(trustedPromise.isFulfilled()).toBe(true);
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedStatus).toBe('none');
// verification will not happen since the verifier.trustedPromise is null and we already returned
});
test('normal unverification during primary func with trusted override', async () => {
const { primaryPromise, trustedPromise, verifyPromise, verifier } = AutoVerifierTest.createPromises(null, 2, 35, 65, 15);
expect(primaryPromise.isFulfilled()).toBe(false);
expect(trustedPromise.isFulfilled()).toBe(false);
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedPromise).toBe(null);
expect(verifier.trustedStatus).toBe('none');
const fetchPromise = makeQuerablePromise(verifier.fetchAndVerifyIfNeeded());
expect(verifier.trustedPromise !== null);
expect(verifier.trustedStatus === 'fetching');
const primaryResult = await primaryPromise;
expect(primaryResult).toBe(null);
expect(fetchPromise.isFulfilled()).toBe(false);
expect(primaryPromise.isFulfilled()).toBe(true);
expect(trustedPromise.isFulfilled()).toBe(false); // since 35ms < 65ms
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedStatus).toBe('fetching');
verifier.unverify(); // keep in mind this is still during the primary func since this is before we await the fetchPromise
expect(verifier.trustedPromise).toBe(null);
expect(verifier.trustedStatus).toBe('none');
const trustedResult = await trustedPromise;
expect(trustedResult).toBe(2);
expect(fetchPromise.isFulfilled()).toBe(false);
expect(trustedPromise.isFulfilled()).toBe(true);
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedStatus).toBe('verifying');
const verification = await verifyPromise;
expect(verification.primaryResult).toBe(null);
expect(verification.trustedResult).toBe(2);
expect(fetchPromise.isFulfilled()).toBe(true); // since verifyPromise occurs AFTER it returns
expect(verifyPromise.isFulfilled()).toBe(true);
expect(verifier.trustedStatus).toBe('verified');
const fetchResult = await fetchPromise;
expect(fetchResult).toBe(2);
expect(fetchPromise.isFulfilled()).toBe(true);
});
test('normal unverification during trusted func with trusted override', async () => {
const { primaryPromise, trustedPromise, verifyPromise, verifier } = AutoVerifierTest.createPromises(null, 2, 35, 65, 15);
expect(primaryPromise.isFulfilled()).toBe(false);
expect(trustedPromise.isFulfilled()).toBe(false);
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedPromise).toBe(null);
expect(verifier.trustedStatus).toBe('none');
const fetchPromise = makeQuerablePromise(verifier.fetchAndVerifyIfNeeded());
expect(verifier.trustedPromise !== null);
expect(verifier.trustedStatus === 'fetching');
const primaryResult = await primaryPromise;
expect(primaryResult).toBe(null);
expect(fetchPromise.isFulfilled()).toBe(false);
expect(primaryPromise.isFulfilled()).toBe(true);
expect(trustedPromise.isFulfilled()).toBe(false); // since 35ms < 65ms
expect(verifyPromise.isFulfilled()).toBe(false);
expect(verifier.trustedStatus).toBe('fetching');
const trustedResult = await trustedPromise;
expect(trustedResult).toBe(2);
verifier.unverify(); // keep in mind this is still during the trusted func since this is before we await the fetchPromise
expect(verifier.trustedPromise).toBe(null);
expect(verifier.trustedStatus).toBe('none');
expect(fetchPromise.isFulfilled()).toBe(false);
expect(trustedPromise.isFulfilled()).toBe(true);
expect(verifyPromise.isFulfilled()).toBe(false);
// this will resolve with null since we got unverified during the fetch
const fetchResult = await fetchPromise;
expect(fetchResult).toBe(null);
expect(fetchPromise.isFulfilled()).toBe(true);
});
});
describe('error tests', () => {
test('primary error', async () => {
const { primaryPromise, trustedPromise, verifyPromise, verifier } = AutoVerifierTest.createPromises(2, 2, 35, 65, 15, true, false);
expect.assertions(3);
try {
await verifier.fetchAndVerifyIfNeeded();
} catch (e) {
expect(e).toBeDefined();
}
await primaryPromise;
await trustedPromise;
await disjoint();
expect(verifier.trustedPromise).toBe(null);
expect(verifier.trustedStatus).toBe('none');
});
test('trusted error thrown out', async () => {
const { primaryPromise, trustedPromise, verifyPromise, verifier } = AutoVerifierTest.createPromises(2, 2, 35, 65, 15, false, true);
await verifier.fetchAndVerifyIfNeeded();
await primaryPromise;
await trustedPromise;
await disjoint();
await disjoint(); // :D since trustedPromise happens BEFORE
expect(verifier.trustedPromise).toBe(null);
expect(verifier.trustedStatus).toBe('none');
});
test('trusted error considered since null primary result', async () => {
const { primaryPromise, trustedPromise, verifyPromise, verifier } = AutoVerifierTest.createPromises(null, 2, 35, 65, 15, false, true);
expect.assertions(3);
try {
await verifier.fetchAndVerifyIfNeeded();
} catch (e) {
expect(e).toBeDefined();
}
await primaryPromise;
await trustedPromise;
await disjoint();
expect(verifier.trustedPromise).toBe(null);
expect(verifier.trustedStatus).toBe('none');
});
test('both error only one exception', async () => {
const { primaryPromise, trustedPromise, verifyPromise, verifier } = AutoVerifierTest.createPromises(2, 2, 35, 65, 15, true, true);
expect.assertions(3);
try {
await verifier.fetchAndVerifyIfNeeded();
} catch (e) {
expect(e).toBeDefined();
}
await primaryPromise;
await trustedPromise;
await disjoint();
expect(verifier.trustedPromise).toBe(null);
expect(verifier.trustedStatus).toBe('none');
});
});
describe('deduplication', () => {
test('primary deduplication', async () => {
const { primaryPromise, trustedPromise, verifyPromise, verifier } = AutoVerifierTest.createPromises(2, 3, 35, 65, 15);
await Promise.all([
(async () => {
const fetchResult = await verifier.fetchAndVerifyIfNeeded();
expect(fetchResult).toBe(2);
})(),
(async () => {
const fetchResult = await verifier.fetchAndVerifyIfNeeded();
expect(fetchResult).toBe(2);
})(),
]);
});
test('trusted deduplication', async () => {
const { primaryPromise, trustedPromise, verifyPromise, verifier } = AutoVerifierTest.createPromises(null, 3, 35, 65, 15);
await Promise.all([
(async () => {
const fetchResult = await verifier.fetchAndVerifyIfNeeded();
expect(fetchResult).toBe(3);
})(),
(async () => {
const fetchResult = await verifier.fetchAndVerifyIfNeeded();
expect(fetchResult).toBe(3);
})(),
]);
// doesn't really test it but it gets the code coverage B)
});
test('trusted deduplication with unverification', async () => {
const { primaryPromise, trustedPromise, verifyPromise, verifier } = AutoVerifierTest.createPromises(null, 3, 35, 65, 15);
await Promise.all([
(async () => {
const fetchPromise = verifier.fetchAndVerifyIfNeeded();
const fetchResult = await fetchPromise;
expect(fetchResult).toBe(null);
})(),
(async () => {
const fetchPromise = verifier.fetchAndVerifyIfNeeded();
await trustedPromise;
verifier.unverify();
const fetchResult = await fetchPromise;
expect(fetchResult).toBe(null);
})(),
]);
});
});
// TODO: changesFunc
// TODO: Standard autoverifiers?