rxdb
Version:
A local-first realtime NoSQL Database for JavaScript applications - https://rxdb.info/
179 lines (167 loc) • 8.11 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.runReplicationBaseTestSuite = runReplicationBaseTestSuite;
var _assert = _interopRequireDefault(require("assert"));
var _asyncTestUtil = require("async-test-util");
var _index = require("../utils/index.js");
var humansCollection = _interopRequireWildcard(require("./humans-collection.js"));
var schemaObjects = _interopRequireWildcard(require("./schema-objects.js"));
var _testUtil = require("./test-util.js");
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
/**
* Base test suite for replication plugins.
* All replication plugins should run these tests
* to ensure consistent behavior across different backends.
*
* The tests use HumanDocumentType (passportId, firstName, lastName, age)
* with humansCollection.create() for collection creation.
*/
/**
* Runs the base test suite for a replication plugin.
* Call this inside a describe() block in your replication test file.
*
* The config callbacks should target a shared server endpoint.
* Each test calls cleanUpServer() at the start to ensure a clean state.
*
* @example
* ```ts
* describe('replication-nats.test.ts', () => {
* runReplicationBaseTestSuite({
* startReplication: (collection) => syncNats(collection, natsName),
* syncOnce: (collection) => syncOnceNats(collection, natsName),
* getAllServerDocs: () => getAllDocsOfServer(natsName),
* cleanUpServer: async () => { ... },
* softDeletes: true,
* isDeleted: (doc) => doc._deleted,
* getPrimaryOfServerDoc: (doc) => doc.passportId,
* });
* });
* ```
*/
function runReplicationBaseTestSuite(config) {
var waitTime = config.waitTime || 0;
describe('base test suite', () => {
describe('live replication', () => {
it('push replication to client-server', async () => {
await config.cleanUpServer();
var collection = await humansCollection.create(2, undefined, false);
var replicationState = config.startReplication(collection);
(0, _testUtil.ensureReplicationHasNoErrors)(replicationState);
await replicationState.awaitInitialReplication();
var docsOnServer = await config.getAllServerDocs();
_assert.default.strictEqual(docsOnServer.length, 2);
// insert another one
await collection.insert(schemaObjects.humanData());
await replicationState.awaitInSync();
docsOnServer = await config.getAllServerDocs();
_assert.default.strictEqual(docsOnServer.length, 3);
// update one
var doc = await collection.findOne().exec(true);
await doc.incrementalPatch({
age: 100
});
await replicationState.awaitInSync();
docsOnServer = await config.getAllServerDocs();
_assert.default.strictEqual(docsOnServer.length, 3);
var serverDoc = (0, _index.ensureNotFalsy)(docsOnServer.find(d => config.getPrimaryOfServerDoc(d) === doc.primary));
_assert.default.strictEqual(serverDoc.age, 100);
// delete one
await doc.getLatest().remove();
await replicationState.awaitInSync();
docsOnServer = await config.getAllServerDocs();
if (config.softDeletes) {
_assert.default.strictEqual(docsOnServer.length, 3);
_assert.default.ok(docsOnServer.find(d => config.isDeleted(d)));
} else {
_assert.default.strictEqual(docsOnServer.length, 2);
}
await collection.database.close();
});
it('two collections', async () => {
await config.cleanUpServer();
var collectionA = await humansCollection.create(0, undefined, false);
await collectionA.insert(schemaObjects.humanData('1aaa'));
var collectionB = await humansCollection.create(0, undefined, false);
await collectionB.insert(schemaObjects.humanData('1bbb'));
var replicationStateA = config.startReplication(collectionA);
(0, _testUtil.ensureReplicationHasNoErrors)(replicationStateA);
await replicationStateA.awaitInitialReplication();
var replicationStateB = config.startReplication(collectionB);
(0, _testUtil.ensureReplicationHasNoErrors)(replicationStateB);
await replicationStateB.awaitInitialReplication();
if (waitTime) {
await (0, _asyncTestUtil.wait)(waitTime);
}
await replicationStateA.awaitInSync();
await (0, _testUtil.awaitCollectionsHaveEqualState)(collectionA, collectionB, 'init sync');
// insert one
await collectionA.insert(schemaObjects.humanData('insert-a'));
await replicationStateA.awaitInSync();
await replicationStateB.awaitInSync();
if (waitTime) {
await (0, _asyncTestUtil.wait)(waitTime);
}
await (0, _testUtil.awaitCollectionsHaveEqualState)(collectionA, collectionB, 'after insert');
// delete one
await collectionB.findOne().remove();
await replicationStateB.awaitInSync();
await replicationStateA.awaitInSync();
if (waitTime) {
await (0, _asyncTestUtil.wait)(waitTime);
}
await (0, _testUtil.awaitCollectionsHaveEqualState)(collectionA, collectionB, 'after deletion');
// insert many
await collectionA.bulkInsert(new Array(10).fill(0).map(() => schemaObjects.humanData(undefined, undefined, 'bulk-insert-A')));
await replicationStateA.awaitInSync();
await replicationStateB.awaitInSync();
if (waitTime) {
await (0, _asyncTestUtil.wait)(waitTime);
}
await (0, _testUtil.awaitCollectionsHaveEqualState)(collectionA, collectionB, 'after insert many');
// insert at both collections at the same time
await Promise.all([collectionA.insert(schemaObjects.humanData('insert-parallel-a')), collectionB.insert(schemaObjects.humanData('insert-parallel-b'))]);
await replicationStateA.awaitInSync();
await replicationStateB.awaitInSync();
await replicationStateA.awaitInSync();
await replicationStateB.awaitInSync();
if (waitTime) {
await (0, _asyncTestUtil.wait)(waitTime);
}
await (0, _testUtil.awaitCollectionsHaveEqualState)(collectionA, collectionB, 'after insert both at same time');
await collectionA.database.close();
await collectionB.database.close();
});
});
describe('conflict handling', () => {
it('should keep the master state as default conflict handler', async () => {
await config.cleanUpServer();
var c1 = await humansCollection.create(1);
var c2 = await humansCollection.create(0);
await config.syncOnce(c1);
await config.syncOnce(c2);
var doc1 = await c1.findOne().exec(true);
var doc2 = await c2.findOne().exec(true);
// make update on both sides
await doc1.incrementalPatch({
firstName: 'c1'
});
await doc2.incrementalPatch({
firstName: 'c2'
});
await config.syncOnce(c2);
// cause conflict
await config.syncOnce(c1);
/**
* Must have kept the master state c2
*/
_assert.default.strictEqual(doc1.getLatest().firstName, 'c2');
await c1.database.close();
await c2.database.close();
});
});
});
}
//# sourceMappingURL=replication-base-test-suite.js.map