/* @flow */ /*eslint-env browser,jasmine */ // returns a random element of o // works on Object, and Array function getRandom (o) { if (o instanceof Array) { return o[Math.floor(Math.random() * o.length)]; } else if (o.constructor === Object) { var ks = []; for (var key in o) { keys.push(key); } return o[getRandom(ks)]; } } function getRandomNumber(n) { if (n == null) { n = 9999; } return Math.floor(Math.random() * n); } var keys = ["a", "b", "c", "d", "e", "f", 1, 2, 3, 4, 5, 6]; var numberOfTests = 500; function applyRandomTransactions (users, transactions) { function* randomTransaction (root) { var f = getRandom(transactions); yield* f(root); } for(var i = 0; i < numberOfTests; i++) { var r = getRandomNumber(100); if (r >= 50) { users[0].connector.flushOne(); } else { getRandom(users).transact(randomTransaction); } } } function compareAllUsers(users){ var s1, s2; function* t1(){ s1 = yield* this.getStateSet(); } function* t2(){ s2 = yield* this.getStateSet(); } users[0].connector.flushAll(); for (var uid = 0; uid + 1 < users.length; uid++) { var u1 = users[uid]; var u2 = users[uid + 1]; u1.transact(t1); u2.transact(t2); expect(s1).toEqual(s2); var db1 = u1.db.os; var db2 = u2.db.os; for (var key in db1) { expect(db1[key]).toEqual(db2[key]); } } } describe("Yjs", function(){ jasmine.DEFAULT_TIMEOUT_INTERVAL = 500; beforeEach(function(){ this.users = []; for (var i = 0; i < 5; i++) { this.users.push(new Y({ db: { name: "Memory" }, connector: { name: "Test", debug: false } })); } }); afterEach(function(){ for (var y of this.users) { y.destroy(); } this.users = []; }); describe("Basic tests", function(){ it("There is an initial Map type", function(){ var y = this.users[0]; y.transact(function*(root){ expect(root).not.toBeUndefined(); }); }); it("Basic get&set of Map property (converge via sync)", function(){ var y = this.users[0]; y.transact(function*(root){ yield* root.val("stuff", "stuffy"); expect(yield* root.val("stuff")).toEqual("stuffy"); }); y.connector.flushAll(); var transaction = function*(root){ expect(yield* root.val("stuff")).toEqual("stuffy"); }; for (var key in this.users) { var u = this.users[key]; u.transact(transaction); } }); it("Basic get&set of Map property (converge via update)", function(){ var y = this.users[0]; y.connector.flushAll(); y.transact(function*(root){ yield* root.val("stuff", "stuffy"); expect(yield* root.val("stuff")).toEqual("stuffy"); }); var transaction = function*(root){ expect(yield* root.val("stuff")).toEqual("stuffy"); }; y.connector.flushAll(); for (var key in this.users) { var u = this.users[key]; u.transact(transaction); } }); it("Basic get&set of Map property (handle conflict)", function(){ var y = this.users[0]; y.connector.flushAll(); this.users[0].transact(function*(root){ yield* root.val("stuff", "c0"); }); this.users[1].transact(function*(root){ yield* root.val("stuff", "c1"); }); var transaction = function*(root){ expect(yield* root.val("stuff")).toEqual("c0"); }; y.connector.flushAll(); for (var key in this.users) { var u = this.users[key]; u.transact(transaction); } }); it("Basic get&set of Map property (handle three conflicts)", function(){ var y = this.users[0]; y.connector.flushAll(); this.users[0].transact(function*(root){ yield* root.val("stuff", "c0"); }); this.users[1].transact(function*(root){ yield* root.val("stuff", "c1"); }); this.users[2].transact(function*(root){ yield* root.val("stuff", "c2"); }); this.users[3].transact(function*(root){ yield* root.val("stuff", "c3"); }); y.connector.flushAll(); var transaction = function*(root){ expect(yield* root.val("stuff")).toEqual("c0"); }; for (var key in this.users) { var u = this.users[key]; u.transact(transaction); } }); }); it("can create a List type", function(){ var y = this.users[0]; y.transact(function*(root){ var list = yield* Y.List(); yield* root.val("list", list); yield* list.insert(0, [1, 2, 3, 4]); expect(yield* root.val("list")).not.toBeUndefined(); }); y.connector.flushAll(); function* transaction (root) { var list = yield* root.val("list"); expect(yield* list.val()).toEqual([1, 2, 3, 4]); } for (var u of this.users) { u.transact(transaction); } }); describe("Map random tests", function(){ var randomMapTransactions = [ function* set (map) { yield* map.val("getRandom(keys)", getRandomNumber()); } ]; it(`succeed after ${numberOfTests} actions with flush before transactions`, function(){ this.users[0].connector.flushAll(); // TODO: Remove!! applyRandomTransactions(this.users, randomMapTransactions); compareAllUsers(this.users); }); it(`succeed after ${numberOfTests} actions without flush before transactions`, function(){ applyRandomTransactions(this.users, randomMapTransactions); compareAllUsers(this.users); }); }); describe("Map debug tests", function(){ beforeEach(function(){ this.u1 = this.users[0]; this.u2 = this.users[1]; this.u3 = this.users[2]; }); it("concurrent insertions #1", function(){ this.u1.transact(function*(root){ var op = { content: 1, left: null, right: null, parent: root._model, parentSub: "a" }; Struct.Insert.create.call(this, op); }); compareAllUsers(this.users); }); }); });