diff --git a/addons/web/static/src/js/data.js b/addons/web/static/src/js/data.js index 27d4562aafb..55e200a205f 100644 --- a/addons/web/static/src/js/data.js +++ b/addons/web/static/src/js/data.js @@ -1190,6 +1190,46 @@ openerp.web.CompoundDomain = openerp.web.Class.extend({ return this.__eval_context; } }); + +openerp.web.DropMisordered = openerp.web.Class.extend(/** @lends openerp.web.DropMisordered# */{ + /** + * @constructs openerp.web.DropMisordered + * @extends openerp.web.Class + * + * @param {Boolean} [failMisordered=false] whether mis-ordered responses should be failed or just ignored + */ + init: function (failMisordered) { + // local sequence number, for requests sent + this.lsn = 0; + // remote sequence number, seqnum of last received request + this.rsn = -1; + this.failMisordered = failMisordered || false; + }, + /** + * Adds a deferred (usually an async request) to the sequencer + * + * @param {$.Deferred} deferred to ensure add + * @returns {$.Deferred} + */ + add: function (deferred) { + var res = $.Deferred(); + + var self = this, seq = this.lsn++; + deferred.then(function () { + if (seq > self.rsn) { + self.rsn = seq; + res.resolve.apply(res, arguments); + } else if (self.failMisordered) { + res.reject(); + } + }, function () { + res.reject.apply(res, arguments); + }); + + return res.promise(); + } +}); + }; // vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax: diff --git a/addons/web/static/test/rpc.js b/addons/web/static/test/rpc.js new file mode 100644 index 00000000000..7dbd3239abd --- /dev/null +++ b/addons/web/static/test/rpc.js @@ -0,0 +1,130 @@ +$(document).ready(function () { + var openerp; + + module('Misordered resolution management', { + setup: function () { + openerp = window.openerp.init(); + window.openerp.web.core(openerp); + window.openerp.web.data(openerp); + } + }); + test('Resolve all correctly ordered, sync', function () { + var dm = new openerp.web.DropMisordered(), flag = false; + + var d1 = $.Deferred(), d2 = $.Deferred(), + r1 = dm.add(d1), r2 = dm.add(d2); + + $.when(r1, r2).done(function () { + flag = true; + }); + d1.resolve(); + d2.resolve(); + + ok(flag); + }); + test("Don't resolve mis-ordered, sync", function () { + var dm = new openerp.web.DropMisordered(), + done1 = false, done2 = false, + fail1 = false, fail2 = false; + + var d1 = $.Deferred(), d2 = $.Deferred(); + dm.add(d1).then(function () { done1 = true; }, + function () { fail1 = true; }); + dm.add(d2).then(function () { done2 = true; }, + function () { fail2 = true; }); + + d2.resolve(); + d1.resolve(); + + // d1 is in limbo + ok(!done1); + ok(!fail1); + // d2 is resolved + ok(done2); + ok(!fail2); + }); + test('Fail mis-ordered flag, sync', function () { + var dm = new openerp.web.DropMisordered(true), + done1 = false, done2 = false, + fail1 = false, fail2 = false; + + var d1 = $.Deferred(), d2 = $.Deferred(); + dm.add(d1).then(function () { done1 = true; }, + function () { fail1 = true; }); + dm.add(d2).then(function () { done2 = true; }, + function () { fail2 = true; }); + + d2.resolve(); + d1.resolve(); + + // d1 is failed + ok(!done1); + ok(fail1); + // d2 is resolved + ok(done2); + ok(!fail2); + }); + + asyncTest('Resolve all correctly ordered, sync', 1, function () { + var dm = new openerp.web.DropMisordered(); + + var d1 = $.Deferred(), d2 = $.Deferred(), + r1 = dm.add(d1), r2 = dm.add(d2); + + setTimeout(function () { d1.resolve(); }, 100); + setTimeout(function () { d2.resolve(); }, 200); + + $.when(r1, r2).done(function () { + start(); + ok(true); + }); + }); + asyncTest("Don't resolve mis-ordered, sync", 4, function () { + var dm = new openerp.web.DropMisordered(), + done1 = false, done2 = false, + fail1 = false, fail2 = false; + + var d1 = $.Deferred(), d2 = $.Deferred(); + dm.add(d1).then(function () { done1 = true; }, + function () { fail1 = true; }); + dm.add(d2).then(function () { done2 = true; }, + function () { fail2 = true; }); + + setTimeout(function () { d1.resolve(); }, 200); + setTimeout(function () { d2.resolve(); }, 100); + + setTimeout(function () { + start(); + // d1 is in limbo + ok(!done1); + ok(!fail1); + // d2 is resolved + ok(done2); + ok(!fail2); + }, 400); + }); + asyncTest('Fail mis-ordered flag, sync', 4, function () { + var dm = new openerp.web.DropMisordered(true), + done1 = false, done2 = false, + fail1 = false, fail2 = false; + + var d1 = $.Deferred(), d2 = $.Deferred(); + dm.add(d1).then(function () { done1 = true; }, + function () { fail1 = true; }); + dm.add(d2).then(function () { done2 = true; }, + function () { fail2 = true; }); + + setTimeout(function () { d1.resolve(); }, 200); + setTimeout(function () { d2.resolve(); }, 100); + + setTimeout(function () { + start(); + // d1 is failed + ok(!done1); + ok(fail1); + // d2 is resolved + ok(done2); + ok(!fail2); + }, 400); + }); +}); diff --git a/addons/web/static/test/test.html b/addons/web/static/test/test.html index 10c2a2c0ed2..004ba0479e1 100644 --- a/addons/web/static/test/test.html +++ b/addons/web/static/test/test.html @@ -51,4 +51,5 @@ +