Best JavaScript code snippet using argos
Synchronizer.js
Source:Synchronizer.js
1var should = require("should");2var JsonUtil = require("./JsonUtil");3var Logger = require("./Logger");4// JSON messages synchronize base and clone.5// Messages are created by createSyncRequest()6// and returned by sync():7// createSyncRequest() => message8// sync(message) => newMessage9//10// ATTRIBUTES11// ---------- 12// op: message operation13// newRev: model snapshot revision14// syncRev: cloned base model revision 15// model: full synchronization data16// diff: differential synchronization data 17// text: message text18//19// STATES20// ------21// S0 Uninitialized22// SB Base23// SBD Base (with changes)24// SC Synchronized clone25// SCX Synchronized clone (stale)26// SCD Synchronized clone (with changes)27// SCDX Synchronized clone (stale with changes)28//29// OP newRev syncRev model diff DESCRIPTION30// ------------------------------------------------------------31// CLONE clone synchronization request32// RETRY retry later33// SYNC RRR MMM synchronize clone with model MMM and syncRev RRR34// UPDB SSS request update for clone35// UPDB SSS DDD request update for clone; update base with clone changes DDD 36// UPDC RRR SSS DDD update clone with new syncRev RRR and base changes DDD since SSS 37// UPDC RRR SSS update clone with new syncRev RRR; no base changes for clone38// STALE RRR MMM synchronize stale clone with model MMM and syncRev RRR39// ERR sadness and disaster40// OK SSS no action required (clone synchronized response)41// IDLE enter idle state and only createSyncRequests() if clone has changes or is watching base42(function(exports) {43 var verboseLogger = new Logger({44 logLevel: "debug"45 });46 function Synchronizer(model, options) {47 var that = this;48 options = options || {};49 that.model = model;50 that.idle = false;51 (typeof options.beforeUpdate === 'function') && (that.beforeUpdate = options.beforeUpdate);52 (typeof options.afterUpdate === 'function') && (that.afterUpdate = options.afterUpdate);53 (typeof options.beforeRebase === 'function') && (that.beforeRebase = options.beforeRebase);54 that.baseRev = 0;55 if (options.verbose) {56 that.verbose = options.verbose;57 }58 return that;59 }60 Synchronizer.prototype.createSyncRequest = function(options) {61 var that = this;62 if (that.baseRev === 0) {63 return {64 op: Synchronizer.OP_CLONE,65 };66 }67 options = options || {};68 var snapshot = JSON.stringify(that.model);69 if (snapshot === that.baseSnapshot) { // no clone changes70 if (that.idle && !options.pollBase) {71 return null;72 }73 that.idle = false;74 return {75 op: Synchronizer.OP_UPDB,76 syncRev: that.syncRev,77 };78 }79 that.idle = false;80 var diff = JsonUtil.diffUpsert(that.model, that.baseModel, {81 filter$: true,82 });83 if (diff == null) {84 that.rebase(); // clone has been edited without differences85 return {86 op: Synchronizer.OP_UPDB,87 syncRev: that.syncRev,88 };89 }90 return {91 op: Synchronizer.OP_UPDB,92 syncRev: that.syncRev,93 diff: diff,94 };95 }96 Synchronizer.prototype.rebase = function() {97 var that = this;98 var snapshot = JSON.stringify(that.model);99 if (snapshot != that.baseSnapshot) {100 that.beforeRebase && that.beforeRebase(that.model);101 that.baseSnapshot = JSON.stringify(that.model); // include decorations102 that.baseModel = JSON.parse(that.baseSnapshot);103 that.baseRev = Synchronizer.revision(that.baseSnapshot);104 }105 return that;106 }107 Synchronizer.prototype.createErrorResponse = function(request, text) {108 var that = this;109 that.verbose && verboseLogger.debug("Synchronizer.createErrorResponse() text:", text,110 " request:", JSON.stringify(request));111 return {112 op: Synchronizer.OP_ERR,113 text: text,114 }115 }116 Synchronizer.prototype.sync_clone = function(request) {117 var that = this;118 if (request.op !== Synchronizer.OP_CLONE) {119 return null;120 }121 if (that.baseRev === 0 || that.baseRev == null) {122 return {123 op: Synchronizer.OP_RETRY,124 text: Synchronizer.TEXT_RETRY,125 }126 }127 that.rebase();128 //that.verbose && verboseLogger.debug("Synchronizer.sync_clone() baseRev:", that.baseRev);129 return {130 op: Synchronizer.OP_SYNC,131 newRev: that.baseRev,132 text: Synchronizer.TEXT_SYNC,133 model: that.model,134 }135 }136 Synchronizer.prototype.sync_echo = function(request, op) {137 var that = this;138 if (request.op !== op) {139 return null;140 }141 return request;142 }143 Synchronizer.prototype.sync_idle = function(request) {144 var that = this;145 if (request.op !== Synchronizer.OP_IDLE) {146 return null;147 }148 that.idle = true;149 return request;150 }151 Synchronizer.prototype.sync_sync = function(request) {152 var that = this;153 if (request.op !== Synchronizer.OP_SYNC) {154 return null;155 }156 if (!request.hasOwnProperty("model")) {157 return that.createErrorResponse(request, Synchronizer.ERR_MODEL);158 } else if (!request.hasOwnProperty("newRev")) {159 return that.createErrorResponse(request, Synchronizer.ERR_NEWREV);160 }161 that.update(request.model);162 that.rebase();163 that.syncRev = request.newRev;164 return {165 op: Synchronizer.OP_OK,166 text: Synchronizer.TEXT_CLONED,167 syncRev: that.syncRev,168 };169 }170 Synchronizer.prototype.sync_stale = function(request) {171 var that = this;172 if (request.op !== Synchronizer.OP_STALE) {173 return null;174 }175 if (!request.hasOwnProperty("model")) {176 return that.createErrorResponse(request, Synchronizer.ERR_MODEL);177 } else if (!request.hasOwnProperty("newRev")) {178 return that.createErrorResponse(request, Synchronizer.ERR_NEWREV);179 }180 // TODO: Deal with stale model181 // for now, slam and hope for the best (ugly)182 that.update(request.model);183 that.rebase(); // TODO: new clone structures won't get sync'd184 that.syncRev = request.newRev;185 return {186 op: Synchronizer.OP_OK,187 text: Synchronizer.TEXT_CLONED,188 syncRev: that.syncRev,189 };190 }191 Synchronizer.prototype.sync_updb = function(request) {192 var that = this;193 if (request.op !== Synchronizer.OP_UPDB) {194 return null;195 }196 if (!request.hasOwnProperty("syncRev")) {197 return that.createErrorResponse(request, Synchronizer.ERR_SYNCREV);198 }199 if (request.syncRev !== that.baseRev) {200 that.rebase();201 return {202 op: Synchronizer.OP_STALE,203 text: Synchronizer.TEXT_STALE,204 newRev: that.baseRev,205 model: that.baseModel,206 }207 }208 var response = {};209 var baseModel = that.baseModel;210 that.update(request.diff);211 request.diff && JsonUtil.applyJson(baseModel, request.diff);212 that.rebase();213 var diff = JsonUtil.diffUpsert(that.model, baseModel);214 //console.log("UPDATE model:" + JSON.stringify(that.model), " baseModel:" + JSON.stringify(baseModel));215 if (diff == null) {216 if (request.diff) {217 response.op = Synchronizer.OP_UPDC;218 response.text = Synchronizer.TEXT_UPDB;219 response.syncRev = request.syncRev;220 response.newRev = that.baseRev;221 } else {222 response.op = Synchronizer.OP_IDLE;223 response.text = Synchronizer.TEXT_IDLE;224 }225 response.syncRev = request.syncRev;226 } else {227 response.op = Synchronizer.OP_UPDC;228 response.diff = diff;229 response.text = Synchronizer.TEXT_UPDC;230 response.syncRev = request.syncRev;231 response.newRev = that.baseRev;232 }233 return response;234 }235 Synchronizer.prototype.sync_updc = function(request) {236 var that = this;237 if (request.op !== Synchronizer.OP_UPDC) {238 return null;239 }240 if (!request.hasOwnProperty("newRev")) {241 return that.createErrorResponse(request, Synchronizer.ERR_NEWREV);242 } else if (!request.hasOwnProperty("syncRev")) {243 return that.createErrorResponse(request, Synchronizer.ERR_SYNCREV);244 } else if (request.syncRev !== that.syncRev) {245 return that.createErrorResponse(request, Synchronizer.ERR_STALE);246 }247 var response = {};248 that.syncRev = request.newRev;249 response.syncRev = that.syncRev;250 that.update(request.diff);251 that.rebase();252 response.op = Synchronizer.OP_OK;253 response.text = Synchronizer.TEXT_SYNC;254 return response;255 }256 Synchronizer.prototype.sync = function(request) {257 var that = this;258 request = request || {259 op: Synchronizer.OP_CLONE,260 };261 if (request.op == null) {262 return that.createErrorResponse(request, Synchronizer.ERR_OP);263 }264 var response = that.sync_clone(request) ||265 that.sync_echo(request, Synchronizer.OP_ERR) ||266 that.sync_echo(request, Synchronizer.OP_OK) ||267 that.sync_echo(request, Synchronizer.OP_RETRY) ||268 that.sync_idle(request) ||269 that.sync_updb(request) ||270 that.sync_updc(request) ||271 that.sync_stale(request) ||272 that.sync_sync(request);273 if (!response) {274 throw new Error("Synchronizer.sync() unhandled request:" + JSON.stringify(request));275 }276 return response;277 }278 Synchronizer.prototype.update = function(diff) {279 var that = this;280 that.beforeUpdate && that.beforeUpdate(diff);281 diff && JsonUtil.applyJson(that.model, diff);282 that.afterUpdate && that.afterUpdate(diff);283 return that;284 }285 Synchronizer.TEXT_RETRY = "Retry: base model uninitialized";286 Synchronizer.TEXT_STALE = "Stale: B#>C UPDB ignored. Response includes base model";287 Synchronizer.TEXT_SYNC = "SyncBC: B<=>C models updated and synchronized";288 Synchronizer.TEXT_UPDB = "SyncB: B<=C models updated and synchronized";289 Synchronizer.TEXT_UPDC = "UPDC: B=>C base updated; clone synchronization pending";290 Synchronizer.TEXT_REBASE = "Rebase: B!>C stale request ignored";291 Synchronizer.TEXT_CLONED = "Cloned: B>>C base model cloned and synchronized";292 Synchronizer.TEXT_IDLE = "Idle: no changes to base or clone models";293 Synchronizer.ERR_OP = "Error: op expected";294 Synchronizer.ERR_MODEL = "Error: model expected";295 Synchronizer.ERR_NEWREV = "Error: newRev expected";296 Synchronizer.ERR_SYNCREV = "Error: syncRev expected";297 Synchronizer.ERR_DIFF = "Error: diff expected";298 Synchronizer.ERR_STALE = "Error: unknown syncRev for clone";299 Synchronizer.OP_CLONE = "CLONE";300 Synchronizer.OP_RETRY = "RETRY";301 Synchronizer.OP_SYNC = "SYNC";302 Synchronizer.OP_STALE = "STALE";303 Synchronizer.OP_UPDB = "UPDB";304 Synchronizer.OP_UPDC = "UPDC";305 Synchronizer.OP_OK = "OK";306 Synchronizer.OP_IDLE = "IDLE";307 Synchronizer.OP_ERR = "ERR";308 Synchronizer.revision = function(model) {309 if (typeof model === 'string') {310 var json = model;311 } else {312 var json = model == null ? "" : JSON.stringify(model);313 }314 if (json.length === 0) {315 return 0;316 }317 var sum1 = 0;318 var sum2 = 0;319 var sum3 = 0;320 var sum5 = 0;321 var sum7 = 0;322 var sum11 = 0;323 var sum13 = 0;324 for (var i = json.length; i-- > 0;) {325 var code = json.charCodeAt(i);326 sum1 += code;327 (i % 2 === 0) && (sum2 += code);328 (i % 3 === 0) && (sum3 += code);329 (i % 5 === 0) && (sum5 += code);330 (i % 7 === 0) && (sum7 += code);331 (i % 11 === 0) && (sum11 += code);332 (i % 13 === 0) && (sum13 += code);333 }334 var result = (json.length + 1) / (sum1 + 1) + ((sum2 << 2) ^ (sum3 << 3) ^ (sum5 << 5) ^ (sum7 << 7) ^ (sum11 << 11) ^ (sum13 << 13));335 //console.log("Synchronizer.revision()", result, " json:", json);336 return result;337 }338 module.exports = exports.Synchronizer = Synchronizer;339})(typeof exports === "object" ? exports : (exports = {}));340// mocha -R min --inline-diffs *.js341(typeof describe === 'function') && describe("Synchronizer", function() {342 var Synchronizer = exports.Synchronizer;343 var beforeRebase = function(model) {344 model.d = model.d ? model.d + 10 : 10;345 }346 var baseOptions = {347 verbose: true,348 beforeRebase: beforeRebase,349 };350 var testScenario = function(isRebase, isSync, isbeforeRebase, beforeUpdate, afterUpdate, baseModel) {351 baseModel = baseModel || JSON.parse('{"a": 1}');352 var scenario = {353 baseModel: baseModel,354 cloneModel: {},355 };356 var baseOptions = {357 verbose: true,358 };359 var cloneOptions = {360 beforeUpdate: beforeUpdate,361 afterUpdate: afterUpdate,362 };363 beforeUpdate && (typeof beforeUpdate).should.equal("function");364 afterUpdate && (typeof afterUpdate).should.equal("function");365 isbeforeRebase != false && (baseOptions.beforeRebase = beforeRebase);366 scenario.baseSync = new Synchronizer(scenario.baseModel, baseOptions);367 scenario.cloneSync = new Synchronizer(scenario.cloneModel, cloneOptions);368 isRebase && scenario.baseSync.rebase();369 if (isSync) {370 scenario.cloneSync.sync(371 scenario.baseSync.sync(372 scenario.cloneSync.createSyncRequest()));373 should.deepEqual(scenario.cloneModel, scenario.baseModel);374 }375 return scenario;376 }377 it("createSyncRequest() returns synchronization request or null", function() {378 var baseModel = {379 a: 1,380 b: 2,381 c: 3,382 };383 var baseSync = new Synchronizer(baseModel);384 baseSync.rebase();385 var cloneModel = {};386 var cloneSync = new Synchronizer(cloneModel);387 var messages = [];388 messages.push(cloneSync.createSyncRequest());389 should.deepEqual(messages[0], {390 op: Synchronizer.OP_CLONE,391 });392 messages.push(baseSync.sync(messages[messages.length - 1]));393 messages.push(cloneSync.sync(messages[messages.length - 1]));394 should.deepEqual(cloneModel, {395 a: 1,396 b: 2,397 c: 3,398 });399 var cloneBaseRev = cloneSync.baseRev;400 should.deepEqual(cloneSync.createSyncRequest(), {401 op: Synchronizer.OP_UPDB,402 syncRev: cloneSync.syncRev,403 });404 cloneBaseRev.should.equal(cloneSync.baseRev);405 // baseRev changes, but not content406 delete cloneModel.a;407 delete cloneModel.b;408 delete cloneModel.c;409 cloneModel.b = 2; // change creation order410 cloneModel.c = 3; // change creation order411 cloneModel.a = 1; // change creation order412 should.deepEqual(cloneSync.createSyncRequest(), {413 op: Synchronizer.OP_UPDB,414 syncRev: cloneSync.syncRev,415 });416 cloneBaseRev.should.not.equal(cloneSync.baseRev); // different serialization of same content417 // baseRev and content changes418 cloneModel.a = 10;419 should.deepEqual(cloneSync.createSyncRequest(), {420 op: Synchronizer.OP_UPDB,421 syncRev: cloneSync.syncRev,422 diff: {423 a: 10,424 },425 });426 });427 it("sync() returns initial synchronization model", function() {428 var baseModel = {429 a: 1,430 };431 var syncBase = new Synchronizer(baseModel, baseOptions);432 var expected1 = {433 op: Synchronizer.OP_RETRY,434 text: Synchronizer.TEXT_RETRY,435 };436 should.deepEqual(syncBase.sync(), expected1);437 should.deepEqual(syncBase.sync(), expected1); // idempotent438 // base model changes but remains uninitialized439 baseModel.a = 2;440 should.deepEqual(syncBase.sync(), expected1);441 should.deepEqual(syncBase.sync(), expected1); // idempotent442 // rebase() marks first synchronizable version443 should.deepEqual(syncBase.rebase(), syncBase);444 var modelExpected = {445 a: 2,446 d: 10,447 };448 should.deepEqual(syncBase.sync(), {449 op: Synchronizer.OP_SYNC,450 newRev: syncBase.baseRev,451 text: Synchronizer.TEXT_SYNC,452 model: modelExpected,453 });454 // base model changes 455 baseModel.a = 3;456 var modelExpected3 = {457 a: 3,458 d: 20,459 };460 var expected3 = {461 op: Synchronizer.OP_SYNC,462 text: Synchronizer.TEXT_SYNC,463 newRev: Synchronizer.revision(modelExpected3),464 model: modelExpected3,465 };466 should.deepEqual(syncBase.sync(), expected3);467 should.deepEqual(syncBase.sync(), expected3); // idempotent468 });469 it("rebase() marks model as initialized", function() {470 var baseModel = {471 a: 1,472 };473 var syncBase = new Synchronizer(baseModel, baseOptions);474 var modelExpected = {475 a: 1,476 d: 10,477 };478 var expected1 = {479 op: Synchronizer.OP_SYNC,480 text: Synchronizer.TEXT_SYNC,481 newRev: Synchronizer.revision(modelExpected),482 model: modelExpected,483 }484 should.deepEqual(syncBase.rebase(), syncBase);485 should.deepEqual(syncBase.sync(), expected1);486 });487 it("sync(initial) initializes clone model", function() {488 var baseModel = {489 a: {490 aa: 1491 },492 };493 var syncBase = new Synchronizer(baseModel, baseOptions);494 var clonea = {495 aa: 2,496 };497 var cloneModel = {498 a: clonea,499 };500 var syncClone = new Synchronizer(cloneModel);501 // nothing should happen with uninitialized models502 var initial = syncBase.sync();503 var expected1 = {504 op: Synchronizer.OP_RETRY,505 text: Synchronizer.TEXT_RETRY,506 };507 should.deepEqual(initial, expected1);508 should.deepEqual(syncClone.sync(initial), expected1);509 should.deepEqual(syncClone.sync(initial), expected1); // idempotent510 syncBase.rebase();511 // error message512 should.deepEqual(syncClone.sync({513 newRev: 1,514 }), {515 op: Synchronizer.OP_ERR,516 text: Synchronizer.ERR_OP,517 });518 should.deepEqual(syncClone.sync({519 op: Synchronizer.OP_SYNC,520 newRev: 1,521 }), {522 op: Synchronizer.OP_ERR,523 text: Synchronizer.ERR_MODEL524 });525 should.deepEqual(syncClone.sync({526 op: Synchronizer.OP_SYNC,527 model: {},528 }), {529 op: Synchronizer.OP_ERR,530 text: Synchronizer.ERR_NEWREV,531 });532 // synchronize to base model533 clonea.aa.should.equal(2);534 initial = syncBase.sync(); // OP_SYNC535 var expectedSync = {536 op: Synchronizer.OP_OK,537 syncRev: syncBase.baseRev,538 text: Synchronizer.TEXT_CLONED,539 };540 should.deepEqual(syncClone.sync(initial), expectedSync);541 should.deepEqual(cloneModel, baseModel);542 //JSON.stringify(cloneModel).should.equal(JSON.stringify(baseModel));543 syncBase.baseRev.should.equal(syncClone.baseRev);544 // IMPORTANT: synchronization should maintain clone structure545 clonea.aa.should.equal(1);546 should.deepEqual(syncClone.sync(initial), expectedSync); // idempotent547 // re-synchronizate after clone changes 548 cloneModel.a.aa = 11;549 cloneModel.c = 3;550 should.deepEqual(syncClone.sync(initial), expectedSync);551 cloneModel.a.aa.should.equal(1); // synchronize overwrites change to base model attribute552 cloneModel.c.should.equal(3); // synchronize ignores non base model attribute553 });554 it("revision(model) returns the revision hash code for the given model", function() {555 var j1 = {556 a: 1,557 };558 Synchronizer.revision({559 a: 1560 }).should.equal(827036.0153550864);561 Synchronizer.revision(JSON.stringify(j1)).should.equal(827036.0153550864);562 Synchronizer.revision("").should.equal(0);563 Synchronizer.revision().should.equal(0);564 });565 it("3-step synchronization should initialize clone", function() {566 var so = testScenario(true, false);567 var messages = [];568 messages.push(so.cloneSync.createSyncRequest()); // step 1569 messages.push(so.baseSync.sync(messages[0])); // step 2570 messages.push(so.cloneSync.sync(messages[1])); // step 3571 should.deepEqual(messages[0], {572 op: Synchronizer.OP_CLONE,573 });574 var model2 = {575 a: 1,576 d: 10,577 };578 should.deepEqual(messages[1], {579 op: Synchronizer.OP_SYNC,580 text: Synchronizer.TEXT_SYNC,581 newRev: so.baseSync.baseRev,582 model: model2,583 });584 so.baseSync.baseRev.should.equal(Synchronizer.revision(model2));585 should.deepEqual(messages[2], {586 op: Synchronizer.OP_OK,587 text: Synchronizer.TEXT_CLONED,588 syncRev: so.baseSync.baseRev,589 });590 should.deepEqual(so.cloneModel, so.baseModel);591 should.deepEqual(so.baseModel, {592 a: 1,593 d: 10,594 });595 so.cloneSync.syncRev.should.equal(so.baseSync.baseRev);596 });597 it("3-step synchronization accepts clone-only change", function() {598 var so = testScenario(true, true, false);599 var syncRev1 = so.cloneSync.syncRev; // initial syncRev600 so.cloneModel.b = 2; // clone change601 var messages = [];602 messages.push(so.cloneSync.createSyncRequest()); // step 1603 messages.push(so.baseSync.sync(messages[messages.length - 1])); // step 2604 messages.push(so.cloneSync.sync(messages[messages.length - 1])); // step 3605 messages.push(so.cloneSync.createSyncRequest()); // step 1606 messages.push(so.baseSync.sync(messages[messages.length - 1])); // step 2607 messages.push(so.cloneSync.sync(messages[messages.length - 1])); // step 3608 should.deepEqual(messages[0], {609 op: Synchronizer.OP_UPDB,610 syncRev: syncRev1,611 diff: {612 b: 2, // clone change613 }614 });615 should.deepEqual(messages[1], {616 op: Synchronizer.OP_UPDC,617 text: Synchronizer.TEXT_UPDB,618 syncRev: messages[0].syncRev,619 newRev: so.baseSync.baseRev,620 });621 should.deepEqual(messages[2], {622 op: Synchronizer.OP_OK,623 text: Synchronizer.TEXT_SYNC,624 syncRev: so.baseSync.baseRev,625 });626 should.deepEqual(so.cloneModel, so.baseModel);627 });628 it("beforeRebase callback may change base and require clone update", function() {629 var so = testScenario(true, true);630 var syncRev1 = so.cloneSync.syncRev; // initial syncRev631 so.cloneModel.b = 2; // clone change632 var messages = [];633 messages.push(so.cloneSync.createSyncRequest()); // step 1634 messages.push(so.baseSync.sync(messages[0])); // step 2635 messages.push(so.cloneSync.sync(messages[1])); // step 3636 should.deepEqual(messages[0], {637 op: Synchronizer.OP_UPDB,638 syncRev: syncRev1,639 diff: {640 b: 2, // clone change641 }642 });643 should.deepEqual(messages[1], {644 op: Synchronizer.OP_UPDC,645 text: Synchronizer.TEXT_UPDC,646 syncRev: messages[0].syncRev,647 newRev: so.baseSync.baseRev,648 diff: {649 d: 20, // base decoration 650 }651 });652 should.deepEqual(messages[2], {653 op: Synchronizer.OP_OK,654 text: Synchronizer.TEXT_SYNC,655 syncRev: so.baseSync.baseRev,656 });657 should.deepEqual(so.cloneModel, so.baseModel);658 });659 it("3-step synchronization enter idle state if base and clone have no changes", function() {660 var so = testScenario(true, true);661 var messages = [];662 messages.push(so.cloneSync.createSyncRequest()); // step 1663 messages.push(so.baseSync.sync(messages[0])); // step 2664 messages.push(so.cloneSync.sync(messages[1])); // step 3665 should.deepEqual(messages[0], {666 op: Synchronizer.OP_UPDB,667 syncRev: so.cloneSync.syncRev,668 });669 should.deepEqual(messages[1], {670 op: Synchronizer.OP_IDLE,671 text: Synchronizer.TEXT_IDLE,672 syncRev: messages[0].syncRev,673 });674 should.deepEqual(messages[2], {675 op: Synchronizer.OP_IDLE,676 text: Synchronizer.TEXT_IDLE,677 syncRev: messages[0].syncRev,678 });679 should.deepEqual(so.cloneModel, so.baseModel);680 // go silent until change681 should(so.cloneSync.createSyncRequest()).equal(null);682 // pollBase option should create request even if clone hasn't changed683 should.deepEqual(so.cloneSync.createSyncRequest({684 pollBase: true685 }), {686 op: Synchronizer.OP_UPDB,687 syncRev: so.cloneSync.syncRev,688 });689 // clone changes690 so.cloneModel.a = 100;691 should.deepEqual(so.cloneSync.createSyncRequest(), {692 op: Synchronizer.OP_UPDB,693 syncRev: so.cloneSync.syncRev,694 diff: {695 a: 100,696 }697 });698 });699 it("3-step synchronization should handle base changes", function() {700 var so = testScenario(true, true);701 var syncRev1 = so.baseSync.baseRev;702 so.baseModel.a = 11; // base change703 var messages = [];704 messages.push(so.cloneSync.createSyncRequest()); // step 1705 messages.push(so.baseSync.sync(messages[0])); // step 2706 messages.push(so.cloneSync.sync(messages[1])); // step 3707 should.deepEqual(messages[0], {708 op: Synchronizer.OP_UPDB,709 syncRev: syncRev1,710 });711 should.deepEqual(messages[1], {712 op: Synchronizer.OP_UPDC,713 text: Synchronizer.TEXT_UPDC,714 syncRev: messages[0].syncRev,715 newRev: so.baseSync.baseRev,716 diff: {717 a: 11, // base change718 d: 20, // base decoration719 }720 });721 should.deepEqual(messages[2], {722 op: Synchronizer.OP_OK,723 text: Synchronizer.TEXT_SYNC,724 syncRev: so.baseSync.baseRev,725 });726 should.deepEqual(so.cloneModel, so.baseModel);727 should.deepEqual(so.cloneModel, {728 a: 11,729 d: 20,730 });731 });732 it("3-step synchronization should handle base+clone changes", function() {733 var so = testScenario(true, true);734 var syncRev1 = so.baseSync.baseRev;735 so.baseModel.a = 11; // base change736 so.cloneModel.b = 2; // clone change737 var messages = [];738 messages.push(so.cloneSync.createSyncRequest()); // step 1739 messages.push(so.baseSync.sync(messages[0])); // step 2740 messages.push(so.cloneSync.sync(messages[1])); // step 3741 should.deepEqual(messages[0], {742 op: Synchronizer.OP_UPDB,743 syncRev: syncRev1,744 diff: {745 b: 2,746 }747 });748 should.deepEqual(messages[1], {749 op: Synchronizer.OP_UPDC,750 text: Synchronizer.TEXT_UPDC,751 syncRev: messages[0].syncRev,752 newRev: so.baseSync.baseRev,753 diff: {754 a: 11, // base change755 d: 20, // base decoration756 }757 });758 should.deepEqual(messages[2], {759 op: Synchronizer.OP_OK,760 text: Synchronizer.TEXT_SYNC,761 syncRev: so.baseSync.baseRev,762 });763 should.deepEqual(so.cloneModel, so.baseModel);764 should.deepEqual(so.cloneModel, {765 a: 11,766 b: 2,767 d: 20,768 });769 });770 it("3-step synchronization should slam base model over stale clone", function() {771 var so = testScenario(true, true);772 var syncRev1 = so.baseSync.baseRev;773 so.baseModel.a = 11; // base change774 so.baseSync.rebase(); // make clone stale 775 syncRev1.should.not.equal(so.baseSync.baseRev);776 var messages = [];777 messages.push(so.cloneSync.createSyncRequest()); // step 1778 messages.push(so.baseSync.sync(messages[0])); // step 2779 messages.push(so.cloneSync.sync(messages[1])); // step 3780 should.deepEqual(messages[0], {781 op: Synchronizer.OP_UPDB,782 syncRev: syncRev1,783 });784 should.deepEqual(messages[1], {785 op: Synchronizer.OP_STALE,786 text: Synchronizer.TEXT_STALE,787 newRev: so.baseSync.baseRev,788 model: {789 a: 11,790 d: 20,791 }792 });793 should.deepEqual(messages[2], {794 op: Synchronizer.OP_OK,795 text: Synchronizer.TEXT_CLONED,796 syncRev: so.baseSync.baseRev,797 });798 should.deepEqual(so.baseModel, {799 a: 11,800 d: 20,801 });802 should.deepEqual(so.cloneModel, {803 a: 11,804 d: 20,805 });806 });807 it("3-step synchronization of stale clone will be unfriendly to clone changes", function() {808 var so = testScenario(true, true);809 var syncRev1 = so.baseSync.baseRev;810 so.baseModel.a = 11; // base change811 so.baseSync.rebase(); // make clone stale 812 syncRev1.should.not.equal(so.baseSync.baseRev);813 so.cloneModel.a = 10; // clone change814 so.cloneModel.b = 2; // clone change815 var messages = [];816 messages.push(so.cloneSync.createSyncRequest()); // step 1817 messages.push(so.baseSync.sync(messages[0])); // step 2818 messages.push(so.cloneSync.sync(messages[1])); // step 3819 should.deepEqual(messages[0], {820 op: Synchronizer.OP_UPDB,821 syncRev: syncRev1,822 diff: {823 a: 10,824 b: 2,825 }826 });827 should.deepEqual(messages[1], {828 op: Synchronizer.OP_STALE,829 text: Synchronizer.TEXT_STALE,830 newRev: so.baseSync.baseRev,831 model: {832 a: 11,833 d: 20,834 }835 });836 should.deepEqual(messages[2], {837 op: Synchronizer.OP_OK,838 text: Synchronizer.TEXT_CLONED,839 syncRev: so.baseSync.baseRev,840 });841 should.deepEqual(so.baseModel, {842 a: 11,843 d: 20,844 });845 // TODO: The following outcome is ugly846 should.deepEqual(so.cloneModel, {847 a: 11, // base value slammed over clone change (ugh)848 b: 2, // orphaned clone value won't sync till changed (ugh)849 d: 20,850 });851 });852 it("constructor options can specify functions for beforeUpdate and afterUpdate", function() {853 var before = 0;854 var beforeDiff = 0;855 var beforeUpdate = function(diff) {856 before++;857 diff && beforeDiff++;858 }859 var after = 0;860 var afterDiff = 0;861 var afterUpdate = function(diff) {862 after++;863 diff && afterDiff++;864 }865 var so = testScenario(false, false, false, beforeUpdate, afterUpdate);866 should(typeof so.cloneSync.beforeUpdate).equal("function");867 should(typeof so.cloneSync.afterUpdate).equal("function");868 // Uninitialized869 var messages = [];870 messages.push(so.cloneSync.createSyncRequest()); // step 1871 messages.push(so.baseSync.sync(messages[messages.length - 1])); // step 2872 messages.push(so.cloneSync.sync(messages[messages.length - 1])); // step 3873 messages[0].op.should.equal(Synchronizer.OP_CLONE);874 messages[1].op.should.equal(Synchronizer.OP_RETRY);875 messages[2].op.should.equal(Synchronizer.OP_RETRY);876 before.should.equal(0);877 after.should.equal(0);878 // Clone879 so.baseSync.rebase();880 messages.push(so.cloneSync.createSyncRequest()); // step 1881 messages.push(so.baseSync.sync(messages[messages.length - 1])); // step 2882 messages.push(so.cloneSync.sync(messages[messages.length - 1])); // step 3883 messages[3].op.should.equal(Synchronizer.OP_CLONE);884 messages[4].op.should.equal(Synchronizer.OP_SYNC);885 messages[5].op.should.equal(Synchronizer.OP_OK);886 before.should.equal(1);887 after.should.equal(1);888 // Idle889 messages.push(so.cloneSync.createSyncRequest()); // step 1890 messages.push(so.baseSync.sync(messages[messages.length - 1])); // step 2891 messages.push(so.cloneSync.sync(messages[messages.length - 1])); // step 3892 messages[6].op.should.equal(Synchronizer.OP_UPDB);893 messages[7].op.should.equal(Synchronizer.OP_IDLE);894 messages[8].op.should.equal(Synchronizer.OP_IDLE);895 before.should.equal(1);896 after.should.equal(1);897 // Clone changes898 so.cloneModel.b = 2;899 messages.push(so.cloneSync.createSyncRequest()); // step 1900 so.cloneSync.idle.should.equal(false);901 messages.push(so.baseSync.sync(messages[messages.length - 1])); // step 2902 messages.push(so.cloneSync.sync(messages[messages.length - 1])); // step 3903 messages[9].op.should.equal(Synchronizer.OP_UPDB);904 messages[10].op.should.equal(Synchronizer.OP_UPDC);905 should(messages[10].diff == null).True;906 messages[11].op.should.equal(Synchronizer.OP_OK);907 before.should.equal(2);908 beforeDiff.should.equal(1);909 after.should.equal(2);910 afterDiff.should.equal(1);911 // Base changes912 so.baseModel.a = 11;913 messages.push(so.cloneSync.createSyncRequest()); // step 1914 messages.push(so.baseSync.sync(messages[messages.length - 1])); // step 2915 messages.push(so.cloneSync.sync(messages[messages.length - 1])); // step 3916 messages[12].op.should.equal(Synchronizer.OP_UPDB);917 messages[13].op.should.equal(Synchronizer.OP_UPDC);918 messages[14].op.should.equal(Synchronizer.OP_OK);919 before.should.equal(3);920 beforeDiff.should.equal(2);921 after.should.equal(3);922 afterDiff.should.equal(2);923 // Stale clone changes924 so.cloneModel.b = 20;925 so.baseModel.a = 111;926 so.baseSync.rebase();927 messages.push(so.cloneSync.createSyncRequest()); // step 1928 messages.push(so.baseSync.sync(messages[messages.length - 1])); // step 2929 messages.push(so.cloneSync.sync(messages[messages.length - 1])); // step 3930 messages[15].op.should.equal(Synchronizer.OP_UPDB);931 messages[16].op.should.equal(Synchronizer.OP_STALE);932 messages[17].op.should.equal(Synchronizer.OP_OK);933 before.should.equal(4);934 beforeDiff.should.equal(3);935 after.should.equal(4);936 afterDiff.should.equal(3);937 });938 it("3-step synchronization enter idle state if base and clone have no changes", function() {939 var so = testScenario(true, true, false, null, null, {940 a: 1,941 b: [{942 b1x: 20,943 b1y: 21,944 b1z: 22945 }, {946 b2x: 20,947 b2y: 21948 }, {949 b3x: 20,950 b3y: 21951 }, ]952 });953 var messages = [];954 so.baseModel.b[0] = {955 b1z: 22,956 b1x: 20,957 b1y: 21,958 };959 messages.push(so.cloneSync.createSyncRequest()); // step 1960 messages.push(so.baseSync.sync(messages[0])); // step 2961 messages.push(so.cloneSync.sync(messages[1])); // step 3962 should.deepEqual(messages[0], {963 op: Synchronizer.OP_UPDB,964 syncRev: messages[0].syncRev,965 });966 should.deepEqual(messages[1], {967 op: Synchronizer.OP_IDLE,968 text: Synchronizer.TEXT_IDLE,969 syncRev: messages[0].syncRev,970 });971 should.deepEqual(messages[2], {972 op: Synchronizer.OP_IDLE,973 text: Synchronizer.TEXT_IDLE,974 syncRev: messages[0].syncRev,975 });976 should.deepEqual(so.cloneModel, so.baseModel);977 // go silent until change978 should(so.cloneSync.createSyncRequest()).equal(null);979 // pollBase option should create request even if clone hasn't changed980 should.deepEqual(so.cloneSync.createSyncRequest({981 pollBase: true982 }), {983 op: Synchronizer.OP_UPDB,984 syncRev: so.cloneSync.syncRev,985 });986 // clone changes987 so.cloneModel.a = 100;988 should.deepEqual(so.cloneSync.createSyncRequest(), {989 op: Synchronizer.OP_UPDB,990 syncRev: so.cloneSync.syncRev,991 diff: {992 a: 100,993 }994 });995 });...
synchronizer.spec.js
Source:synchronizer.spec.js
1import SynchronizerService from '@/services/synchronizer'2describe('Services > Synchronizer', () => {3 let synchronizer4 beforeEach(() => {5 synchronizer = new SynchronizerService({})6 })7 describe('define', () => {8 const actionId = 'example'9 const actionFn = jest.fn()10 it('should require the `default` mode configuration', () => {11 const config = {12 focus: { interval: 1000 }13 }14 expect(() => synchronizer.define(actionId, config, actionFn)).not.toThrow(/default.*mode/)15 })16 it('should require the `focus` mode configuration', () => {17 const config = {18 default: { interval: 10000 }19 }20 expect(() => synchronizer.define(actionId, config, actionFn)).not.toThrow(/focus.*mode/)21 })22 it('should not allow using 0 as interval', () => {23 const config = {24 default: { interval: 0 },25 focus: { interval: 0 }26 }27 expect(() => synchronizer.define(actionId, config, actionFn)).toThrow(/interval/)28 })29 it('should allow using `null` as interval', () => {30 const config = {31 default: { interval: null },32 focus: { interval: null }33 }34 expect(() => synchronizer.define(actionId, config, actionFn)).not.toThrow()35 })36 it('should store the action by ID', () => {37 const config = {38 default: { interval: 10000 },39 focus: { interval: 1000 }40 }41 synchronizer.define(actionId, config, actionFn)42 expect(synchronizer).toHaveProperty(`actions.${actionId}`, {43 calledAt: 0,44 isCalling: false,45 fn: actionFn,46 ...config47 })48 })49 })50 describe('focus', () => {51 it('should add the actions to the `focused` Array', () => {52 synchronizer.focused = []53 synchronizer.focus('example')54 expect(synchronizer).toHaveProperty('focused', ['example'])55 synchronizer.focused = []56 synchronizer.focus(['example'])57 expect(synchronizer).toHaveProperty('focused', ['example'])58 })59 it('should remove the actions from the `paused` the Array', () => {60 synchronizer.paused = ['example', 'other']61 synchronizer.focus('example')62 expect(synchronizer).toHaveProperty('paused', ['other'])63 synchronizer.paused = ['example', 'other']64 synchronizer.focus(['example'])65 expect(synchronizer).toHaveProperty('paused', ['other'])66 })67 })68 describe('pause', () => {69 it('should add the actions to the `paused` Array', () => {70 synchronizer.paused = []71 synchronizer.pause('example')72 expect(synchronizer).toHaveProperty('paused', ['example'])73 synchronizer.paused = []74 synchronizer.pause(['example'])75 expect(synchronizer).toHaveProperty('paused', ['example'])76 })77 })78 describe('unpause', () => {79 it('should remove the actions from the `paused` the Array', () => {80 synchronizer.paused = ['example', 'other']81 synchronizer.unpause('example')82 expect(synchronizer).toHaveProperty('paused', ['other'])83 synchronizer.paused = ['example', 'other']84 synchronizer.unpause(['example'])85 expect(synchronizer).toHaveProperty('paused', ['other'])86 })87 })...
cart-synchronizer.js
Source:cart-synchronizer.js
1/** @format */2/**3 * External dependencies4 */5import assert from 'assert';6/**7 * Internal dependencies8 */9import CartSynchronizer from '../cart-synchronizer';10import FakeWPCOM from './fake-wpcom';11var TEST_CART_KEY = 91234567890;12var poller = {13 add: function() {},14};15describe( 'cart-synchronizer', () => {16 let applyCoupon, emptyCart;17 beforeAll( () => {18 const cartValues = require( 'lib/cart-values' );19 applyCoupon = cartValues.applyCoupon;20 emptyCart = cartValues.emptyCart;21 } );22 describe( '*before* the first fetch from the server', () => {23 test( 'should *not* allow the value to be read', () => {24 var wpcom = FakeWPCOM(),25 synchronizer = CartSynchronizer( TEST_CART_KEY, wpcom, poller );26 assert.throws( () => {27 synchronizer.getLatestValue();28 }, Error );29 } );30 test( 'should enqueue local changes and POST them after fetching', () => {31 var wpcom = FakeWPCOM(),32 synchronizer = CartSynchronizer( TEST_CART_KEY, wpcom, poller ),33 serverCart = emptyCart( TEST_CART_KEY );34 synchronizer.fetch();35 synchronizer.update( applyCoupon( 'foo' ) );36 assert.throws( () => {37 synchronizer.getLatestValue();38 }, Error );39 wpcom.resolveRequest( 0, serverCart );40 assert.equal( synchronizer.getLatestValue().coupon, 'foo' );41 assert.equal( wpcom.getRequest( 1 ).method, 'POST' );42 assert.equal( wpcom.getRequest( 1 ).cart.coupon, 'foo' );43 wpcom.resolveRequest( 1, applyCoupon( 'bar' )( serverCart ) );44 assert.equal( synchronizer.getLatestValue().coupon, 'bar' );45 } );46 } );47 describe( '*after* the first fetch from the server', () => {48 test( 'should allow the value to be read', () => {49 var wpcom = FakeWPCOM(),50 synchronizer = CartSynchronizer( TEST_CART_KEY, wpcom, poller ),51 serverCart = emptyCart( TEST_CART_KEY );52 synchronizer.fetch();53 wpcom.resolveRequest( 0, serverCart );54 assert.equal( synchronizer.getLatestValue().blog_id, serverCart.blog_id );55 } );56 } );57 test( 'should make local changes visible immediately', () => {58 var wpcom = FakeWPCOM(),59 synchronizer = CartSynchronizer( TEST_CART_KEY, wpcom, poller ),60 serverCart = emptyCart( TEST_CART_KEY );61 synchronizer.fetch();62 wpcom.resolveRequest( 0, serverCart );63 synchronizer.update( applyCoupon( 'foo' ) );64 assert.equal( synchronizer.getLatestValue().coupon, 'foo' );65 } );...
Using AI Code Generation
1var argosy = require('argosy')2var argosyPattern = require('argosy-pattern')3var argosySynchronizer = require('argosy-synchronizer')4var service = argosy()5service.use(argosyPattern({6 add: function (a, b) {7 }8}))9service.use(argosySynchronizer())10service.listen(8000)11var argosy = require('argosy')12var argosySynchronizer = require('argosy-synchronizer')13var service = argosy()14service.use(argosySynchronizer.client())15service.act('role:synchronizer,cmd:subscribe', function (err, reply) {16})17service.listen(8001)18### `argosySynchronizer.client()`
Using AI Code Generation
1var argosy = require('argosy')2var argosyPattern = require('argosy-pattern')3var argosySynchronizer = require('argosy-synchronizer')4var synchronizer = argosySynchronizer()5var service = argosy()6service.pipe(synchronizer).pipe(service)7service.accept({ping: argosyPattern.match.string}, function (msg, cb) {8 cb(null, 'pong')9})10synchronizer.ready(function () {11 console.log('synchronizer ready')12})13synchronizer.ready = function (cb) {14 return new Promise(function (resolve, reject) {15 cb(resolve)16 })17}18synchronizer.ready(function () {19 console.log('synchronizer ready')20})21synchronizer.ready(function () {22 console.log('synchronizer ready')23})24synchronizer.ready = function (cb) {25 return new Promise(function (resolve, reject) {26 cb(resolve)27 })28}29synchronizer.ready(function () {30 console.log('synchronizer ready')31})32synchronizer.ready(function () {33 console.log('synchronizer ready')34})35synchronizer.ready = function (cb) {36 return new Promise(function (resolve, reject) {37 cb(resolve)38 })39}40synchronizer.ready(function () {41 console.log('synchronizer ready')42})43synchronizer.ready(function () {44 console.log('synchronizer ready')45})46synchronizer.ready = function (cb) {47 return new Promise(function (resolve, reject) {48 cb(resolve)49 })50}51synchronizer.ready(function () {52 console.log('synchronizer ready')53})54synchronizer.ready(function () {55 console.log('synchronizer ready')56})57synchronizer.ready = function (cb) {58 return new Promise(function (resolve, reject) {59 cb(resolve)60 })61}62synchronizer.ready(function () {63 console.log('synchronizer ready')64})
Using AI Code Generation
1var argosy = require('argosy')2var synchronizer = require('argosy-pattern/synchronizer')3var pattern = require('argosy-pattern')4var service = argosy()5service.use('hello', synchronizer(pattern({6}, {7})))8service.listen(3000)9var argosy = require('argosy')10var synchronizer = require('argosy-pattern/synchronizer')11var pattern = require('argosy-pattern')12var client = argosy()13client.use('hello', synchronizer(pattern({14}, {15})))16client.on('error', function (err) {17 console.log(err)18})19client.connect(3000)20client.hello({name: 'World'}).then(function (response) {21 console.log(response)22}).catch(function (err) {23 console.log(err)24})
Using AI Code Generation
1var argosy = require('../index.js')()2argosy.pattern('test', function (msg, respond) {3 respond(null, msg)4})5argosy.synchronizer('test', function (msg, respond) {6 respond(null, msg)7})8argosy.synchronizer('test2', function (msg, respond) {9 respond(null, msg)10})11argosy.synchronizer('test3', function (msg, respond) {12 respond(null, msg)13})14argosy.synchronizer('test4', function (msg, respond) {15 respond(null, msg)16})17argosy.synchronizer('test5', function (msg, respond) {18 respond(null, msg)19})20argosy.synchronizer('test6', function (msg, respond) {21 respond(null, msg)22})23argosy.synchronizer('test7', function (msg, respond) {24 respond(null, msg)25})26argosy.synchronizer('test8', function (msg, respond) {27 respond(null, msg)28})29argosy.synchronizer('test9', function (msg, respond) {30 respond(null, msg)31})32argosy.synchronizer('test10', function (msg, respond) {33 respond(null, msg)34})35argosy.synchronizer('test11', function (msg, respond) {36 respond(null, msg)37})38argosy.synchronizer('test12', function (msg, respond) {39 respond(null, msg)40})41argosy.synchronizer('test13', function (msg, respond) {42 respond(null, msg)43})44argosy.synchronizer('test14', function (msg, respond) {45 respond(null, msg)46})47argosy.synchronizer('test15', function (msg, respond) {48 respond(null, msg)49})50argosy.synchronizer('test16', function (msg, respond) {51 respond(null, msg)52})53argosy.synchronizer('test17', function (msg, respond) {54 respond(null, msg)55})56argosy.synchronizer('test18', function (msg, respond) {57 respond(null, msg)58})59argosy.synchronizer('test19', function (msg, respond) {60 respond(null, msg)61})62argosy.synchronizer('test20',
Using AI Code Generation
1var argosy = require('argosy')2var service = argosy()3service.accept({hello: 'world'}, function (msg, cb) {4 cb(null, 'hello world')5})6service.listen(3000)
Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!