deno.land / x / replicache@v10.0.0-beta.0 / sync / push.test.ts
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260import {LogContext} from '@rocicorp/logger';import {expect} from '@esm-bundle/chai';import * as dag from '../dag/mod';import {DEFAULT_HEAD_NAME} from '../db/commit';import {fromWhence, whenceHead} from '../db/read';import { addGenesis, addIndexChange, addLocal, addSnapshot, Chain,} from '../db/test-helpers';import type {HTTPRequestInfo} from '../http-request-info';import {SYNC_HEAD_NAME} from './sync-head-name';import {push, PushRequest, PUSH_VERSION} from './push';import type {Pusher} from '../pusher';
type FakePusherArgs = { expPush: boolean; expPushReq?: PushRequest; expPushURL: string; expAuth: string; expRequestID: string; err?: string;};
function makeFakePusher(options: FakePusherArgs): Pusher { return async (req: Request): Promise<HTTPRequestInfo> => { expect(options.expPush).to.be.true;
const pushReq = await req.json();
if (options.expPushReq) { expect(options.expPushReq).to.deep.equal(pushReq); expect(new URL(options.expPushURL, location.href).toString()).to.equal( req.url, ); expect(options.expAuth).to.equal(req.headers.get('Authorization')); expect(options.expRequestID).to.equal( req.headers.get('X-Replicache-RequestID'), ); }
if (options.err) { if (options.err === 'FetchNotOk(500)') { return { httpStatusCode: 500, errorMessage: 'Fetch not OK', }; } else { throw new Error('not implented'); } }
return { httpStatusCode: 200, errorMessage: '', }; };}
test('try push', async () => { const store = new dag.TestStore(); const lc = new LogContext(); const chain: Chain = []; await addGenesis(chain, store); await addSnapshot(chain, store, [['foo', 'bar']]); // chain[2] is an index change await addIndexChange(chain, store); const startingNumCommits = chain.length;
const requestID = 'request_id'; const profileID = 'test_profile_id'; const clientID = 'test_client_id';
const auth = 'auth';
// Push const pushURL = 'push_url'; const pushSchemaVersion = 'pushSchemaVersion';
type Case = { name: string;
// Push expectations. numPendingMutations: number; expPushReq: PushRequest | undefined; pushResult: undefined | 'ok' | {error: string}; expBatchPushInfo: HTTPRequestInfo | undefined; }; const cases: Case[] = [ { name: '0 pending', numPendingMutations: 0, expPushReq: undefined, pushResult: undefined, expBatchPushInfo: undefined, }, { name: '1 pending', numPendingMutations: 1, expPushReq: { profileID, clientID, mutations: [ { id: 2, name: 'mutator_name_3', args: [3], timestamp: 42, }, ], pushVersion: PUSH_VERSION, schemaVersion: pushSchemaVersion, }, pushResult: 'ok', expBatchPushInfo: { httpStatusCode: 200, errorMessage: '', }, }, { name: '2 pending', numPendingMutations: 2, expPushReq: { profileID, clientID, mutations: [ // These mutations aren't actually added to the chain until the test // case runs, but we happen to know how they are created by the db // test helpers so we use that knowledge here. { id: 2, name: 'mutator_name_3', args: [3], timestamp: 42, }, { id: 3, name: 'mutator_name_5', args: [5], timestamp: 42, }, ], pushVersion: PUSH_VERSION, schemaVersion: pushSchemaVersion, }, pushResult: 'ok', expBatchPushInfo: { httpStatusCode: 200, errorMessage: '', }, }, { name: '2 mutations to push, push errors', numPendingMutations: 2, expPushReq: { profileID, clientID, mutations: [ // These mutations aren't actually added to the chain until the test // case runs, but we happen to know how they are created by the db // test helpers so we use that knowledge here. { id: 2, name: 'mutator_name_3', args: [3], timestamp: 42, }, { id: 3, name: 'mutator_name_5', args: [5], timestamp: 42, }, ], pushVersion: PUSH_VERSION, schemaVersion: pushSchemaVersion, }, pushResult: {error: 'FetchNotOk(500)'}, expBatchPushInfo: { httpStatusCode: 500, errorMessage: 'Fetch not OK', }, }, ];
for (const c of cases) { // Reset state of the store. chain.length = startingNumCommits; await store.withWrite(async w => { await w.setHead(DEFAULT_HEAD_NAME, chain[chain.length - 1].chunk.hash); await w.removeHead(SYNC_HEAD_NAME); await w.commit(); }); for (let i = 0; i < c.numPendingMutations; i++) { await addLocal(chain, store); await addIndexChange(chain, store); }
// There was an index added after the snapshot, and one for each local // commit. Here we scan to ensure that we get values when scanning using one // of the indexes created. We do this because after calling begin_sync we // check that the index no longer returns values, demonstrating that it was // rebuilt. if (c.numPendingMutations > 0) { await store.withRead(async dagRead => { const read = await fromWhence(whenceHead(DEFAULT_HEAD_NAME), dagRead); let got = false;
const indexMap = await read.getMapForIndex('2');
// eslint-disable-next-line @typescript-eslint/no-unused-vars for await (const _ of indexMap.scan('')) { got = true; break; } expect(got).to.be.true; }); }
// See explanation in FakePusher for why we do this dance with the // push_result. const [expPush, pushErr] = (() => { switch (c.pushResult) { case undefined: return [false, undefined] as const; case 'ok': return [true, undefined] as const; default: return [true, c.pushResult.error] as const; } })();
const pusher = makeFakePusher({ expPush, expPushReq: c.expPushReq, expPushURL: pushURL, expAuth: auth, expRequestID: requestID, err: pushErr, });
const clientID = 'test_client_id'; const batchPushInfo = await push( requestID, store, lc, profileID, clientID, pusher, pushURL, auth, pushSchemaVersion, );
expect(batchPushInfo).to.deep.equal(c.expBatchPushInfo, `name: ${c.name}`); }});
Version Info