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 @@
+