[FIX] web: prevent race condition with client actions

Here is the issue that initiated this work: the bank reconciliation tour
sometimes failed in community.  The reason was that the discuss client
action seemed to be loaded after the tour started, and interfered with
the second step of the tour.

What happened exactly was the following:
- web client is loaded
- initial action is starting (but not complete) (this is discuss)
- tour manager is loaded and starts the reconciliation tour
- the reconciliation tour changes the url to trigger an hash change
- the web client calls loadState on the action manager
- the action manager perform a doAction with the tour url
- the discuss client action is now ready, and replace the reconciliation
  action
- the tour is broken.

The underlying cause is really a generic problem: the action manager
does not add the client action starting process in its 'dropprevious'
concurrency primitive.  This is probably not really an issue for the
act_window actions, since they have custom loading code that make sure
the loading process is put in the drop previous, but it is definitely a
problem for all client actions.

The solution is quite simple, and should also protect the act window
renderers: put the action controller in the drop previous
This commit is contained in:
Géry Debongnie
2018-04-12 17:05:25 +02:00
parent be48c26c24
commit fddf2a722e
2 changed files with 30 additions and 1 deletions
@@ -335,7 +335,7 @@ var ActionManager = Widget.extend({
// communicate its status
widget.set_cp_bus(self.controlPanel.get_bus());
}
return self._startController(controller);
return self.dp.add(self._startController(controller));
})
.then(function (controller) {
if (self.currentDialogController) {
@@ -3065,6 +3065,35 @@ QUnit.module('ActionManager', {
actionManager.destroy();
});
});
QUnit.test('properly drop client actions after new action is initiated', function (assert) {
assert.expect(1);
var slowWillStartDef = $.Deferred();
var ClientAction = AbstractAction.extend({
willStart: function () {
return slowWillStartDef;
},
});
core.action_registry.add('slowAction', ClientAction);
var actionManager = createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
});
actionManager.doAction('slowAction');
actionManager.doAction(4);
slowWillStartDef.resolve();
assert.strictEqual(actionManager.$('.o_kanban_view').length, 1,
'should have loaded a kanban view');
actionManager.destroy();
delete core.action_registry.map.slowAction;
});
});
});