added eventhandler
This commit is contained in:
parent
8e9e62b3d0
commit
8cc374cabb
@ -8,7 +8,7 @@
|
|||||||
"no-underscore-dangle": 0,
|
"no-underscore-dangle": 0,
|
||||||
"no-constant-condition": 0,
|
"no-constant-condition": 0,
|
||||||
"no-empty": 0,
|
"no-empty": 0,
|
||||||
"new-cap": [2, { "capIsNewExceptions": ["List"] }],
|
"new-cap": [2, { "capIsNewExceptions": ["List", "Y"] }],
|
||||||
},
|
},
|
||||||
"parser": "babel-eslint",
|
"parser": "babel-eslint",
|
||||||
"globals": {
|
"globals": {
|
||||||
@ -27,6 +27,7 @@
|
|||||||
"setInterval": true,
|
"setInterval": true,
|
||||||
"Operation": true,
|
"Operation": true,
|
||||||
"getRandom": true,
|
"getRandom": true,
|
||||||
"RBTree": true
|
"RBTree": true,
|
||||||
|
"compareIds": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,15 +9,15 @@ class AbstractTransaction { //eslint-disable-line no-unused-vars
|
|||||||
if (t == null) {
|
if (t == null) {
|
||||||
var op = yield* this.getOperation(id);
|
var op = yield* this.getOperation(id);
|
||||||
if (op != null) {
|
if (op != null) {
|
||||||
t = new Y[op.type].Create(op.id);
|
t = yield* Y[op.type].create(this.store, op.id);
|
||||||
this.store.initializedTypes[sid] = t;
|
this.store.initializedTypes[sid] = t;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
createType (model) {
|
*createType (model) {
|
||||||
var sid = JSON.stringify(model.id);
|
var sid = JSON.stringify(model.id);
|
||||||
var t = new Y[model.type].Create(model.id);
|
var t = yield* Y[model.type].create(this.store, model);
|
||||||
this.store.initializedTypes[sid] = t;
|
this.store.initializedTypes[sid] = t;
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
@ -40,9 +40,8 @@ var Struct = {
|
|||||||
var user = this.store.y.connector.userId;
|
var user = this.store.y.connector.userId;
|
||||||
var state = yield* this.getState(user);
|
var state = yield* this.getState(user);
|
||||||
op.id = [user, state.clock];
|
op.id = [user, state.clock];
|
||||||
if ((yield* this.addOperation(op)) === false) {
|
yield* Struct[op.struct].execute.call(this, op);
|
||||||
throw new Error("This is highly unexpected :(");
|
|
||||||
}
|
|
||||||
this.store.y.connector.broadcast({
|
this.store.y.connector.broadcast({
|
||||||
type: "update",
|
type: "update",
|
||||||
ops: [Struct[op.struct].encode(op)]
|
ops: [Struct[op.struct].encode(op)]
|
||||||
@ -56,11 +55,7 @@ var Struct = {
|
|||||||
throw new Error("You must define a delete target!");
|
throw new Error("You must define a delete target!");
|
||||||
}
|
}
|
||||||
op.struct = "Delete";
|
op.struct = "Delete";
|
||||||
yield* Struct.Operation.create.call(this, op);
|
return yield* Struct.Operation.create.call(this, op);
|
||||||
|
|
||||||
var target = yield* this.getOperation(op.target);
|
|
||||||
target.deleted = true;
|
|
||||||
yield* this.setOperation(target);
|
|
||||||
},
|
},
|
||||||
encode: function (op) {
|
encode: function (op) {
|
||||||
return op;
|
return op;
|
||||||
@ -86,7 +81,7 @@ var Struct = {
|
|||||||
parentSub: string (optional)
|
parentSub: string (optional)
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
create: function*( op: Op ) : Insert {
|
create: function* ( op: Op ) : Insert {
|
||||||
if ( op.left === undefined
|
if ( op.left === undefined
|
||||||
|| op.right === undefined
|
|| op.right === undefined
|
||||||
|| op.parent === undefined ) {
|
|| op.parent === undefined ) {
|
||||||
@ -94,7 +89,7 @@ var Struct = {
|
|||||||
}
|
}
|
||||||
op.origin = op.left;
|
op.origin = op.left;
|
||||||
op.struct = "Insert";
|
op.struct = "Insert";
|
||||||
return op;
|
return yield* Struct.Operation.create.call(this, op);
|
||||||
},
|
},
|
||||||
encode: function(op){
|
encode: function(op){
|
||||||
/*var e = {
|
/*var e = {
|
||||||
@ -253,11 +248,11 @@ var Struct = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
List: {
|
List: {
|
||||||
create: function( op : Op){
|
create: function* ( op : Op){
|
||||||
op.start = null;
|
op.start = null;
|
||||||
op.end = null;
|
op.end = null;
|
||||||
op.struct = "List";
|
op.struct = "List";
|
||||||
return Struct.Operation.create(op);
|
return yield* Struct.Operation.create.call(this, op);
|
||||||
},
|
},
|
||||||
encode: function(op){
|
encode: function(op){
|
||||||
return {
|
return {
|
||||||
@ -358,7 +353,7 @@ var Struct = {
|
|||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
create: function*( op : Op ){
|
create: function* ( op : Op ){
|
||||||
op.map = {};
|
op.map = {};
|
||||||
op.struct = "Map";
|
op.struct = "Map";
|
||||||
return yield* Struct.Operation.create.call(this, op);
|
return yield* Struct.Operation.create.call(this, op);
|
||||||
@ -393,22 +388,6 @@ var Struct = {
|
|||||||
? res.content : yield* this.getType(res.opContent));
|
? res.content : yield* this.getType(res.opContent));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
set: function* (op, name, value) {
|
|
||||||
var right = op.map[name] || null;
|
|
||||||
var insert = {
|
|
||||||
left: null,
|
|
||||||
right: right,
|
|
||||||
parent: op.id,
|
|
||||||
parentSub: name
|
|
||||||
};
|
|
||||||
if ( value != null && value._model != null
|
|
||||||
&& value._model.length === 2) {
|
|
||||||
insert.opContent = value._model;
|
|
||||||
} else {
|
|
||||||
insert.content = value;
|
|
||||||
}
|
|
||||||
yield* Struct.Insert.create.call(this, insert);
|
|
||||||
},
|
|
||||||
delete: function* (op, name) {
|
delete: function* (op, name) {
|
||||||
var v = op.map[name] || null;
|
var v = op.map[name] || null;
|
||||||
if (v != null) {
|
if (v != null) {
|
||||||
|
140
src/Types/Map.js
140
src/Types/Map.js
@ -1,35 +1,116 @@
|
|||||||
|
|
||||||
|
var GeneratorFunction = (function*(){}).constructor;
|
||||||
|
|
||||||
|
class EventHandler {
|
||||||
|
constructor (onevent) {
|
||||||
|
this.waiting = [];
|
||||||
|
this.awaiting = 0;
|
||||||
|
this.onevent = onevent;
|
||||||
|
}
|
||||||
|
receivedOp (op) {
|
||||||
|
if (this.awaiting <= 0) {
|
||||||
|
this.onevent([op]);
|
||||||
|
} else {
|
||||||
|
this.waiting.push(copyObject(op));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
awaitAndPrematurelyCall (op) {
|
||||||
|
this.awaiting++;
|
||||||
|
this.onevent([op]);
|
||||||
|
}
|
||||||
|
awaitedLastOp () {
|
||||||
|
var op = this.waiting.pop();
|
||||||
|
for (var i = this.waiting.length - 1; i >= 0; i--) {
|
||||||
|
var w = this.waiting[i];
|
||||||
|
if (compareIds(op.left, w.id)) {
|
||||||
|
// include the effect of op in w
|
||||||
|
w.right = op.id;
|
||||||
|
// exclude the effect of w in op
|
||||||
|
op.left = w.left;
|
||||||
|
} else if (compareIds(op.right, w.id)) {
|
||||||
|
// similar..
|
||||||
|
w.left = op.id;
|
||||||
|
op.right = w.right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.awaiting--;
|
||||||
|
if (this.awaiting <= 0) {
|
||||||
|
var events = this.waiting;
|
||||||
|
this.waiting = [];
|
||||||
|
this.onevent(events);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
(function(){
|
(function(){
|
||||||
class Map {
|
class Map {
|
||||||
constructor (os, _model) {
|
constructor (os, model) {
|
||||||
this._model = _model;
|
this._model = model.id;
|
||||||
this.os = os;
|
this.os = os;
|
||||||
|
this.map = model.map;
|
||||||
|
this.contents = {};
|
||||||
|
this.opContents = {};
|
||||||
|
this.eventHandler = new EventHandler( ops =>{
|
||||||
|
for (var i in ops) {
|
||||||
|
var op = ops[i];
|
||||||
|
if (op.left === null) {
|
||||||
|
if (op.opContent != null) {
|
||||||
|
this.opContents[op.parentSub] = op.opContent;
|
||||||
|
} else {
|
||||||
|
this.contents[op.parentSub] = op.content;
|
||||||
}
|
}
|
||||||
val () {
|
}
|
||||||
if (arguments.length === 1) {
|
}
|
||||||
if (this.opContents[arguments[0]] == null) {
|
});
|
||||||
return this.contents[arguments[0]];
|
}
|
||||||
|
get (key) {
|
||||||
|
// return property.
|
||||||
|
// if property does not exist, return null
|
||||||
|
// if property is a type, return a promise
|
||||||
|
if (this.opContents[key] == null) {
|
||||||
|
return this.contents[key];
|
||||||
} else {
|
} else {
|
||||||
let def = Promise.defer();
|
let def = Promise.defer();
|
||||||
var oid = this.opContents[arguments[0]];
|
var oid = this.opContents[key];
|
||||||
this.os.requestTransaction(function*(){
|
this.os.requestTransaction(function*(){
|
||||||
def.resolve(yield* this.getType(oid));
|
def.resolve(yield* this.getType(oid));
|
||||||
});
|
});
|
||||||
return def.promise;
|
return def.promise;
|
||||||
}
|
}
|
||||||
} else if (arguments.length === 2) {
|
|
||||||
var key = arguments[0];
|
|
||||||
var value = arguments[1];
|
|
||||||
let def = Promise.defer();
|
|
||||||
var _model = this._model;
|
|
||||||
this.os.requestTransaction(function*(){
|
|
||||||
var model = yield* this.getOperation(_model);
|
|
||||||
def.resolve(yield* Y.Struct.Map.set.call(this, model, key, value));
|
|
||||||
});
|
|
||||||
return def.promise;
|
|
||||||
} else {
|
|
||||||
throw new Error("Implement this case!");
|
|
||||||
}
|
}
|
||||||
|
set (key, value) {
|
||||||
|
// set property.
|
||||||
|
// if property is a type, return a promise
|
||||||
|
// if not, apply immediately on this type an call event
|
||||||
|
|
||||||
|
var right = this.map[key] || null;
|
||||||
|
var insert = {
|
||||||
|
left: null,
|
||||||
|
right: right,
|
||||||
|
parent: this._model,
|
||||||
|
parentSub: key
|
||||||
|
};
|
||||||
|
var def = Promise.defer();
|
||||||
|
if ( value != null && value.constructor === GeneratorFunction) {
|
||||||
|
// construct a new type
|
||||||
|
this.os.requestTransaction(function*(){
|
||||||
|
var type = yield* value.call(this);
|
||||||
|
insert.opContent = type._model;
|
||||||
|
yield* Struct.Insert.create.call(this, insert);
|
||||||
|
def.resolve(type);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
insert.content = value;
|
||||||
|
var eventHandler = this.eventHandler;
|
||||||
|
eventHandler.awaitAndPrematurelyCall(insert);
|
||||||
|
|
||||||
|
this.os.requestTransaction(function*(){
|
||||||
|
yield* Struct.Insert.create.call(this, insert);
|
||||||
|
eventHandler.awaitedLastOp();
|
||||||
|
});
|
||||||
|
def.resolve(value);
|
||||||
|
}
|
||||||
|
return def.promise;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
*delete (key) {
|
*delete (key) {
|
||||||
@ -38,24 +119,15 @@
|
|||||||
yield* Y.Struct.Map.delete.call(t, model, key);
|
yield* Y.Struct.Map.delete.call(t, model, key);
|
||||||
}*/
|
}*/
|
||||||
_changed (op) {
|
_changed (op) {
|
||||||
if (op.left === null) {
|
this.eventHandler.receivedOp(op);
|
||||||
if (op.opContent != null) {
|
|
||||||
this.opContents[op.parentSub] = op.opContent;
|
|
||||||
} else {
|
|
||||||
this.contents[op.parentSub] = op.opContent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Y.Map = function* YMap(){
|
Y.Map = function* YMap(){
|
||||||
var t = yield "transaction";
|
var model = yield* Y.Struct.Map.create.call(this, {type: "Map"});
|
||||||
if (this instanceof Y.AbstractOperationStore) {
|
return yield* this.createType(model);
|
||||||
var model = yield* Y.Struct.map.create.call(t, {type: "Map"});
|
};
|
||||||
return t.createType(model);
|
Y.Map.create = function* YMapCreate(os, model){
|
||||||
} else {
|
return new Map(os, model);
|
||||||
throw new Error("Don't use `new` to create this type!");
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
Y.Map.Create = Map;
|
|
||||||
})();
|
})();
|
||||||
|
23
src/y.js
23
src/y.js
@ -1,11 +1,18 @@
|
|||||||
/* @flow */
|
/* @flow */
|
||||||
|
|
||||||
const GeneratorFunction = (function*(){}).constructor;
|
function Y (opts) {
|
||||||
|
var def = Promise.defer();
|
||||||
|
new YConfig(opts, function(config){ //eslint-disable-line
|
||||||
|
def.resolve(config);
|
||||||
|
});
|
||||||
|
return def.promise;
|
||||||
|
}
|
||||||
|
|
||||||
class Y { //eslint-disable-line no-unused-vars
|
class YConfig { //eslint-disable-line no-unused-vars
|
||||||
constructor (opts) {
|
constructor (opts, callback) {
|
||||||
this.db = new Y[opts.db.name](this, opts.db);
|
this.db = new Y[opts.db.name](this, opts.db);
|
||||||
this.connector = new Y[opts.connector.name](this, opts.connector);
|
this.connector = new Y[opts.connector.name](this, opts.connector);
|
||||||
|
var yconfig = this;
|
||||||
this.db.requestTransaction(function*(){
|
this.db.requestTransaction(function*(){
|
||||||
// create initial Map type
|
// create initial Map type
|
||||||
var model = {
|
var model = {
|
||||||
@ -15,15 +22,11 @@ class Y { //eslint-disable-line no-unused-vars
|
|||||||
map: {}
|
map: {}
|
||||||
};
|
};
|
||||||
yield* this.addOperation(model);
|
yield* this.addOperation(model);
|
||||||
this.createType(model);
|
var root = yield* this.createType(model);
|
||||||
|
this.store.y.root = root;
|
||||||
|
callback(yconfig);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
transact (generator) {
|
|
||||||
if (generator.constructor !== GeneratorFunction) {
|
|
||||||
throw new Error("y.transact requires a Generator function! E.g. function*(){/*..*/}");
|
|
||||||
}
|
|
||||||
this.db.requestTransaction(generator);
|
|
||||||
}
|
|
||||||
destroy () {
|
destroy () {
|
||||||
this.connector.disconnect();
|
this.connector.disconnect();
|
||||||
this.db.removeDatabase();
|
this.db.removeDatabase();
|
||||||
|
255
src/y.spec.js
255
src/y.spec.js
@ -24,9 +24,9 @@ function getRandomNumber(n) {
|
|||||||
var numberOfYMapTests = 30;
|
var numberOfYMapTests = 30;
|
||||||
|
|
||||||
function applyRandomTransactions (users, transactions, numberOfTransactions) {
|
function applyRandomTransactions (users, transactions, numberOfTransactions) {
|
||||||
function* randomTransaction (root) {
|
function randomTransaction (root) {
|
||||||
var f = getRandom(transactions);
|
var f = getRandom(transactions);
|
||||||
yield* f(root);
|
f(root);
|
||||||
}
|
}
|
||||||
for(var i = 0; i < numberOfTransactions; i++) {
|
for(var i = 0; i < numberOfTransactions; i++) {
|
||||||
var r = Math.random();
|
var r = Math.random();
|
||||||
@ -34,7 +34,7 @@ function applyRandomTransactions (users, transactions, numberOfTransactions) {
|
|||||||
// 10% chance to flush
|
// 10% chance to flush
|
||||||
users[0].connector.flushOne();
|
users[0].connector.flushOne();
|
||||||
} else {
|
} else {
|
||||||
getRandom(users).transact(randomTransaction);
|
randomTransaction(getRandom(users).root);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -51,8 +51,8 @@ function compareAllUsers(users){
|
|||||||
for (var uid = 0; uid + 1 < users.length; uid++) {
|
for (var uid = 0; uid + 1 < users.length; uid++) {
|
||||||
var u1 = users[uid];
|
var u1 = users[uid];
|
||||||
var u2 = users[uid + 1];
|
var u2 = users[uid + 1];
|
||||||
u1.transact(t1);
|
u1.db.requestTransaction(t1);
|
||||||
u2.transact(t2);
|
u2.db.requestTransaction(t2);
|
||||||
expect(s1).toEqual(s2);
|
expect(s1).toEqual(s2);
|
||||||
var db1 = [];
|
var db1 = [];
|
||||||
var db2 = [];
|
var db2 = [];
|
||||||
@ -71,10 +71,17 @@ function compareAllUsers(users){
|
|||||||
|
|
||||||
describe("Yjs", function(){
|
describe("Yjs", function(){
|
||||||
jasmine.DEFAULT_TIMEOUT_INTERVAL = 500;
|
jasmine.DEFAULT_TIMEOUT_INTERVAL = 500;
|
||||||
beforeEach(function(){
|
beforeEach(function(done){
|
||||||
|
if (this.users != null) {
|
||||||
|
for (var y of this.users) {
|
||||||
|
y.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
this.users = [];
|
this.users = [];
|
||||||
|
|
||||||
|
var promises = [];
|
||||||
for (var i = 0; i < 5; i++) {
|
for (var i = 0; i < 5; i++) {
|
||||||
this.users.push(new Y({
|
promises.push(Y({
|
||||||
db: {
|
db: {
|
||||||
name: "Memory"
|
name: "Memory"
|
||||||
},
|
},
|
||||||
@ -84,205 +91,142 @@ describe("Yjs", function(){
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
Promise.all(promises).then( users => {
|
||||||
|
this.users = users;
|
||||||
|
done();
|
||||||
});
|
});
|
||||||
afterEach(function(){
|
|
||||||
for (var y of this.users) {
|
|
||||||
y.destroy();
|
|
||||||
}
|
|
||||||
this.users = [];
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Basic tests", function(){
|
describe("Basic tests", function(){
|
||||||
it("There is an initial Map type & it is created only once", function(){
|
|
||||||
var y = this.users[0];
|
|
||||||
var root1;
|
|
||||||
y.transact(function*(root){
|
|
||||||
expect(root).not.toBeUndefined();
|
|
||||||
root1 = root;
|
|
||||||
});
|
|
||||||
y.transact(function*(root2){
|
|
||||||
expect(root1).toBe(root2);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it("Custom Types are created only once", function(){
|
|
||||||
var y = this.users[0];
|
|
||||||
var l1;
|
|
||||||
y.transact(function*(root){
|
|
||||||
var l = yield* Y.List();
|
|
||||||
yield* root.val("list", l);
|
|
||||||
l1 = l;
|
|
||||||
});
|
|
||||||
y.transact(function*(root){
|
|
||||||
expect(l1).toBe(yield* root.val("list"));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Basic get&set of Map property (converge via sync)", function(){
|
it("Basic get&set of Map property (converge via sync)", function(){
|
||||||
var y = this.users[0];
|
var y = this.users[0].root;
|
||||||
y.transact(function*(root){
|
y.set("stuff", "stuffy");
|
||||||
yield* root.val("stuff", "stuffy");
|
expect(y.get("stuff")).toEqual("stuffy");
|
||||||
expect(yield* root.val("stuff")).toEqual("stuffy");
|
|
||||||
});
|
|
||||||
|
|
||||||
y.connector.flushAll();
|
this.users[0].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) {
|
for (var key in this.users) {
|
||||||
var u = this.users[key];
|
var u = this.users[key].root;
|
||||||
u.transact(transaction);
|
expect(u.get("stuff")).toEqual("stuffy");
|
||||||
}
|
}
|
||||||
|
compareAllUsers(this.users);
|
||||||
});
|
});
|
||||||
it("Basic get&set of Map property (handle conflict)", function(){
|
it("Map can set custom types (Map)", function(done){
|
||||||
|
var y = this.users[0].root;
|
||||||
|
y.set("Map", Y.Map).then(function(map) {
|
||||||
|
map.set("one", 1);
|
||||||
|
return y.get("Map");
|
||||||
|
}).then(function(map){
|
||||||
|
expect(map.get("one")).toEqual(1);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it("Basic get&set of Map property (converge via update)", function(done){
|
||||||
|
var u = this.users[0];
|
||||||
|
u.connector.flushAll();
|
||||||
|
var y = u.root;
|
||||||
|
y.set("stuff", "stuffy");
|
||||||
|
expect(y.get("stuff")).toEqual("stuffy");
|
||||||
|
|
||||||
|
u.connector.flushAll();
|
||||||
|
setTimeout(() => {
|
||||||
|
for (var key in this.users) {
|
||||||
|
var r = this.users[key].root;
|
||||||
|
expect(r.get("stuff")).toEqual("stuffy");
|
||||||
|
}
|
||||||
|
done();
|
||||||
|
}, 50);
|
||||||
|
});
|
||||||
|
it("Basic get&set of Map property (handle conflict)", function(done){
|
||||||
var y = this.users[0];
|
var y = this.users[0];
|
||||||
y.connector.flushAll();
|
y.connector.flushAll();
|
||||||
this.users[0].transact(function*(root){
|
y.root.set("stuff", "c0");
|
||||||
yield* root.val("stuff", "c0");
|
|
||||||
});
|
this.users[1].root.set("stuff", "c1");
|
||||||
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();
|
y.connector.flushAll();
|
||||||
|
|
||||||
|
setTimeout( () => {
|
||||||
for (var key in this.users) {
|
for (var key in this.users) {
|
||||||
var u = this.users[key];
|
var u = this.users[key];
|
||||||
u.transact(transaction);
|
expect(u.root.get("stuff")).toEqual("c0");
|
||||||
|
compareAllUsers(this.users);
|
||||||
}
|
}
|
||||||
|
done();
|
||||||
|
}, 50);
|
||||||
});
|
});
|
||||||
it("Basic get&set of Map property (handle three conflicts)", function(){
|
it("Basic get&set of Map property (handle three conflicts)", function(done){
|
||||||
var y = this.users[0];
|
var y = this.users[0];
|
||||||
|
this.users[0].root.set("stuff", "c0");
|
||||||
|
this.users[1].root.set("stuff", "c1");
|
||||||
|
this.users[2].root.set("stuff", "c2");
|
||||||
|
this.users[3].root.set("stuff", "c3");
|
||||||
y.connector.flushAll();
|
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");
|
|
||||||
};
|
|
||||||
|
|
||||||
|
setTimeout( () => {
|
||||||
for (var key in this.users) {
|
for (var key in this.users) {
|
||||||
var u = this.users[key];
|
var u = this.users[key];
|
||||||
u.transact(transaction);
|
expect(u.root.get("stuff")).toEqual("c0");
|
||||||
}
|
}
|
||||||
|
compareAllUsers(this.users);
|
||||||
|
done();
|
||||||
|
}, 50);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("Basic get&set&delete with Map property", function(){
|
|
||||||
var y = this.users[0];
|
|
||||||
y.connector.flushAll();
|
|
||||||
this.users[0].transact(function*(root){
|
|
||||||
yield* root.val("stuff", "c0");
|
|
||||||
});
|
|
||||||
this.users[0].transact(function*(root){
|
|
||||||
yield* root.val("stuff", "c1");
|
|
||||||
});
|
|
||||||
this.users[0].transact(function*(root){
|
|
||||||
yield* root.delete("stuff");
|
|
||||||
});
|
|
||||||
|
|
||||||
y.connector.flushAll();
|
|
||||||
var transaction = function*(root){
|
|
||||||
expect(yield* root.val("stuff")).toBeUndefined();
|
|
||||||
};
|
|
||||||
|
|
||||||
for (var key in this.users) {
|
|
||||||
var u = this.users[key];
|
|
||||||
u.transact(transaction);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
it("List type: can create, insert, and delete elements", 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]);
|
|
||||||
yield* list.delete(1);
|
|
||||||
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, 3, 4]);
|
|
||||||
}
|
|
||||||
for (var u of this.users) {
|
|
||||||
u.transact(transaction);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
describe("Map random tests", function(){
|
describe("Map random tests", function(){
|
||||||
var randomMapTransactions = [
|
var randomMapTransactions = [
|
||||||
function* set (map) {
|
function set (map) {
|
||||||
yield* map.val("somekey", getRandomNumber());
|
map.set("somekey", getRandomNumber());
|
||||||
},
|
},
|
||||||
function* delete_ (map) {
|
function* delete_ (map) {
|
||||||
yield* map.delete("somekey");
|
map.delete("somekey");
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
it(`succeed after ${numberOfYMapTests} actions with flush before transactions`, function(){
|
function compareMapValues(users){
|
||||||
this.users[0].connector.flushAll();
|
|
||||||
applyRandomTransactions(this.users, randomMapTransactions, numberOfYMapTests);
|
|
||||||
compareAllUsers(this.users);
|
|
||||||
var firstMap;
|
var firstMap;
|
||||||
for (var u of this.users) {
|
for (var u of users) {
|
||||||
u.transact(function*(root){//eslint-disable-line
|
var val = u.root.get();
|
||||||
var val = yield* root.val();
|
|
||||||
if (firstMap == null) {
|
if (firstMap == null) {
|
||||||
firstMap = val;
|
firstMap = val;
|
||||||
} else {
|
} else {
|
||||||
expect(val).toEqual(firstMap);
|
expect(val).toEqual(firstMap);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
it(`succeed after ${numberOfYMapTests} actions without flush before transactions`, function(){
|
it(`succeed after ${numberOfYMapTests} actions with flush before transactions`, function(done){
|
||||||
|
this.users[0].connector.flushAll();
|
||||||
applyRandomTransactions(this.users, randomMapTransactions, numberOfYMapTests);
|
applyRandomTransactions(this.users, randomMapTransactions, numberOfYMapTests);
|
||||||
|
setTimeout(()=>{
|
||||||
compareAllUsers(this.users);
|
compareAllUsers(this.users);
|
||||||
|
compareMapValues(this.users);
|
||||||
|
done();
|
||||||
|
}, 500);
|
||||||
|
});
|
||||||
|
it(`succeed after ${numberOfYMapTests} actions without flush before transactions`, function(done){
|
||||||
|
applyRandomTransactions(this.users, randomMapTransactions, numberOfYMapTests);
|
||||||
|
setTimeout(()=>{
|
||||||
|
compareAllUsers(this.users);
|
||||||
|
compareMapValues(this.users);
|
||||||
|
done();
|
||||||
|
}, 500);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
var numberOfYListTests = 100;
|
var numberOfYListTests = 100;
|
||||||
describe("List random tests", function(){
|
describe("List random tests", function(){
|
||||||
var randomListTests = [function* insert (root) {
|
var randomListTests = [function* insert (root) {
|
||||||
var list = yield* root.val("list");
|
var list = yield* root.get("list");
|
||||||
yield* list.insert(Math.floor(Math.random() * 10), [getRandomNumber()]);
|
yield* list.insert(Math.floor(Math.random() * 10), [getRandomNumber()]);
|
||||||
}, function* delete_(root) {
|
}, function* delete_(root) {
|
||||||
var list = yield* root.val("list");
|
var list = yield* root.get("list");
|
||||||
yield* list.delete(Math.floor(Math.random() * 10));
|
yield* list.delete(Math.floor(Math.random() * 10));
|
||||||
}];
|
}];
|
||||||
beforeEach(function(){
|
beforeEach(function(){
|
||||||
this.users[0].transact(function*(root){
|
this.users[0].transact(function*(root){
|
||||||
var list = yield* Y.List();
|
var list = yield* Y.List();
|
||||||
yield* root.val("list", list);
|
yield* root.set("list", list);
|
||||||
});
|
});
|
||||||
this.users[0].connector.flushAll();
|
this.users[0].connector.flushAll();
|
||||||
});
|
});
|
||||||
@ -292,11 +236,11 @@ describe("Yjs", function(){
|
|||||||
compareAllUsers(this.users);
|
compareAllUsers(this.users);
|
||||||
var userList;
|
var userList;
|
||||||
this.users[0].transact(function*(root){
|
this.users[0].transact(function*(root){
|
||||||
var list = yield* root.val("list");
|
var list = yield* root.get("list");
|
||||||
if (userList == null) {
|
if (userList == null) {
|
||||||
userList = yield* list.val();
|
userList = yield* list.get();
|
||||||
} else {
|
} else {
|
||||||
expect(userList).toEqual(yield* list.val());
|
expect(userList).toEqual(yield* list.get());
|
||||||
expect(userList.length > 0).toBeTruthy();
|
expect(userList.length > 0).toBeTruthy();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -323,4 +267,5 @@ describe("Yjs", function(){
|
|||||||
compareAllUsers(this.users);
|
compareAllUsers(this.users);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
*/
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user