Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Merge branch 'develop-perf' of git://github.com/yahoo/mojito into par…

…tials
  • Loading branch information...
commit e6499c55ef3a848244cfc4b90b0d350347810450 2 parents 5948e36 + a691fcc
Caridy Patino authored November 19, 2012
21  examples/newsboxes/mojits/Read/tests/controller.common-tests.js
@@ -222,6 +222,9 @@ YUI.add('ReadController-tests', function(Y) {
222 222
 
223 223
         return {
224 224
             config: {
  225
+                getAppConfig: function() {
  226
+                    return {spaceid: '999', limit: 10};
  227
+                },
225 228
                 getDefinition: function(ignored) {
226 229
                     return _definitions;
227 230
                 }
@@ -235,10 +238,12 @@ YUI.add('ReadController-tests', function(Y) {
235 238
                 }
236 239
             },
237 240
             models: {
238  
-                rss: {
239  
-                    get: function(feedmeta, cb) {
240  
-                        cb(null, feedmeta, boomtown_vudata_out);
241  
-                    }
  241
+                get: function() {
  242
+                    return {
  243
+                        get: function(feedmeta, cb) {
  244
+                            cb(null, feedmeta, boomtown_vudata_out);
  245
+                        }
  246
+                    };
242 247
                 }
243 248
             }
244 249
         };
@@ -295,14 +300,20 @@ YUI.add('ReadController-tests', function(Y) {
295 300
         },
296 301
 
297 302
         'compose spaceid set': function() {
  303
+            controller.config = controller.config || {};
  304
+            controller.config.spaceid = '999';
298 305
             A.areSame('999', controller.compose(boomtown_feedmeta, boomtown_stories_in).spaceid);
299 306
         },
300 307
 
301 308
         'compose feedname': function() {
  309
+            controller.config = controller.config || {};
  310
+            controller.config.spaceid = '999';
302 311
             A.areSame('BoomTown', controller.compose(boomtown_feedmeta, boomtown_stories_in).feedname);
303 312
         },
304 313
 
305 314
         'compose navdots for every story': function() {
  315
+            controller.config = controller.config || {};
  316
+            controller.config.spaceid = '999';
306 317
             var vu = controller.compose(boomtown_feedmeta, boomtown_stories_in);
307 318
 
308 319
             A.areSame(10, vu.navdots.length);
@@ -310,6 +321,8 @@ YUI.add('ReadController-tests', function(Y) {
310 321
         },
311 322
 
312 323
         'compose adds css': function() {
  324
+            controller.config = controller.config || {};
  325
+            controller.config.spaceid = '999';
313 326
             var vu = controller.compose(boomtown_feedmeta, boomtown_stories_in);
314 327
             Y.each(vu.stories, function(story, i) {
315 328
                 A.isTypeOf('string', story.css_style);
2  examples/newsboxes/mojits/Read/tests/rss.common-tests.js
@@ -152,7 +152,7 @@ YUI.add('ReadModelRss-tests', function(Y, NAME) {
152 152
     suite.add(new YUITest.TestCase({
153 153
         name: 'rss model tests',
154 154
         setUp: function() {
155  
-            rss = Y.mojito.models.rss;
  155
+            rss = Y.mojito.models.ReadModelRss;
156 156
             rss.init({limit: 10});
157 157
         },
158 158
 
72  lib/app/autoload/dispatch.common.js → lib/app/autoload/dispatch.client.js
@@ -18,6 +18,12 @@ YUI.add('mojito-dispatcher', function (Y, NAME) {
18 18
 
19 19
     'use strict';
20 20
 
  21
+    // on the server side, controllers are stateless, but on
  22
+    // the client, things are different, we can cache them by
  23
+    // instanceId to re-use them when possible.
  24
+    var _cacheInstances = {},
  25
+        _cacheControllers = {};
  26
+
21 27
     Y.namespace('mojito').Dispatcher = {
22 28
 
23 29
         /**
@@ -60,17 +66,11 @@ YUI.add('mojito-dispatcher', function (Y, NAME) {
60 66
                 instance = command.instance,
61 67
                 modules = [];
62 68
 
63  
-            // For performance reasons we don't want to support
64  
-            // this ondemand "use" in the server side since
65  
-            // all the requirements are already in place.
66  
-            if (command.context.runtime === 'server') {
67  
-                adapter.error(new Error('Invalid controller name [' +
68  
-                    instance.controller + '] for mojit [' +
69  
-                    instance.type + '].'));
70  
-                return;
71  
-            }
  69
+            // TODO: part of the optimization here can be to
  70
+            // avoid calling use when the controller already exists.
72 71
 
73  
-            // attach controller to Y ondemand
  72
+            // use controller's yui module name to attach
  73
+            // the controller to Y ondemand
74 74
             modules.push(instance.controller);
75 75
 
76 76
             // TODO: this is a hack to attach the correct engine, the problem
@@ -105,23 +105,32 @@ YUI.add('mojito-dispatcher', function (Y, NAME) {
105 105
          */
106 106
         _createActionContext: function (command, adapter) {
107 107
             var ac,
108  
-                controller = Y.mojito.controllers[command.instance.controller],
109 108
                 perf = Y.mojito.perf.timeline('mojito', 'ac:ctor',
110 109
                     'create ControllerContext', command);
111 110
 
  111
+            // the controller is not stateless on the client, we
  112
+            // store it for re-use.
  113
+            // TODO: we need to find a way to clean this for apps
  114
+            // that attent to create and destroy mojits from the page
  115
+            // but maybe we can just wait for the YAF refactor.
  116
+            if (!_cacheControllers[command.instance.instanceId]) {
  117
+                _cacheControllers[command.instance.instanceId] =
  118
+                    Y.mojito.util.heir(Y.mojito.controllers[command.instance.controller]);
  119
+            }
  120
+
112 121
             // Note that creation of an ActionContext current causes
113 122
             // immediate invocation of the dispatch() call.
114 123
             try {
115 124
                 ac = new Y.mojito.ActionContext({
116 125
                     command: command,
117  
-                    controller: Y.mojito.util.heir(controller),
  126
+                    controller: _cacheControllers[command.instance.instanceId],
118 127
                     dispatcher: this,         // NOTE passing dispatcher.
119 128
                     adapter: adapter,
120 129
                     store: this.store
121 130
                 });
122 131
             } catch (e) {
123 132
                 Y.log('Error from dispatch on instance \'' +
124  
-                    (command.instance.id || '@' + command.instance.type) +
  133
+                    (command.instance.base || '@' + command.instance.type) +
125 134
                     '\':', 'error', NAME);
126 135
                 Y.log(e.message, 'error', NAME);
127 136
                 Y.log(e.stack, 'error', NAME);
@@ -146,8 +155,8 @@ YUI.add('mojito-dispatcher', function (Y, NAME) {
146 155
 
147 156
             } else {
148 157
 
149  
-                adapter.error(new Error('RPC tunnel is not available in the ' +
150  
-                    command.context.runtime + ' runtime.'));
  158
+                adapter.error(new Error('RPC tunnel is not available in the [' +
  159
+                    command.context.runtime + '] runtime.'));
151 160
 
152 161
             }
153 162
         },
@@ -171,11 +180,22 @@ YUI.add('mojito-dispatcher', function (Y, NAME) {
171 180
             store.validateContext(command.context);
172 181
 
173 182
             if (command.rpc) {
174  
-                // forcing to dispatch command through RPC tunnel
  183
+                Y.log('Command with rpc flag, dispatching through RPC tunnel',
  184
+                    'info', NAME);
175 185
                 this.rpc(command, adapter);
176 186
                 return;
177 187
             }
178 188
 
  189
+            if (command.instance.instanceId && _cacheInstances[command.instance.instanceId]) {
  190
+                Y.log('Re-using instance with instanceId=' +
  191
+                    command.instance.instanceId, 'info', NAME);
  192
+                command.instance = _cacheInstances[command.instance.instanceId];
  193
+                this._useController(command, adapter);
  194
+                return;
  195
+            }
  196
+
  197
+            // if no rpc flag and no instance cached, we try to
  198
+            // expand the instance before creating the ActionContext.
179 199
             store.expandInstance(command.instance, command.context,
180 200
                 function (err, instance) {
181 201
 
@@ -199,19 +219,19 @@ YUI.add('mojito-dispatcher', function (Y, NAME) {
199 219
 
200 220
                     }
201 221
 
  222
+                    // the instance is not stateless on the client, we
  223
+                    // store it for re-use.
  224
+                    // TODO: we need to find a way to clean this for apps
  225
+                    // that attent to create and destroy mojits from the page
  226
+                    // but maybe we can just wait for the YAF refactor.
  227
+                    _cacheInstances[instance.instanceId] = instance;
  228
+
202 229
                     // We replace the given instance with the expanded instance.
203 230
                     command.instance = instance;
204 231
 
205  
-                    // if this controller does not exist yet, we should try
206  
-                    // to require it along with it depedencies.
207  
-                    if (!Y.mojito.controllers[instance.controller]) {
208  
-                        // requiring the controller and its dependencies
209  
-                        // before dispatching AC
210  
-                        my._useController(command, adapter);
211  
-                    } else {
212  
-                        // dispatching AC
213  
-                        my._createActionContext(command, adapter);
214  
-                    }
  232
+                    // requiring the controller and its dependencies
  233
+                    // before dispatching AC
  234
+                    my._useController(command, adapter);
215 235
 
216 236
                 });
217 237
         }
163  lib/app/autoload/dispatch.server.js
... ...
@@ -0,0 +1,163 @@
  1
+/*
  2
+ * Copyright (c) 2011-2012, Yahoo! Inc.  All rights reserved.
  3
+ * Copyrights licensed under the New BSD License.
  4
+ * See the accompanying LICENSE file for terms.
  5
+ */
  6
+
  7
+/*jslint anon:true, nomen:true*/
  8
+/*global YUI*/
  9
+
  10
+
  11
+/**
  12
+ * This object is responsible for running mojits.
  13
+ * @class MojitoDispatcher
  14
+ * @static
  15
+ * @public
  16
+ */
  17
+YUI.add('mojito-dispatcher', function (Y, NAME) {
  18
+
  19
+    'use strict';
  20
+
  21
+    Y.namespace('mojito').Dispatcher = {
  22
+
  23
+        /**
  24
+         * Initializes the dispatcher instance.
  25
+         * @method init
  26
+         * @public
  27
+         * @param {Y.mojito.ResourceStore} resourceStore the store to use.
  28
+         * @param {Y.mojito.TunnelClient} rpcTunnel optional tunnel client for RPC calls
  29
+         * @return {Y.mojito.Dispatcher}
  30
+         */
  31
+        init: function (resourceStore, rpcTunnel) {
  32
+
  33
+            if (!resourceStore) {
  34
+                throw new Error(
  35
+                    'Mojito cannot instantiate without a resource store.'
  36
+                );
  37
+            }
  38
+
  39
+            // Cache parameters as instance variables for the dispatch() call to
  40
+            // reference.
  41
+            this.store = resourceStore;
  42
+            this.tunnel = rpcTunnel;
  43
+
  44
+            Y.log('Dispatcher created', 'debug', NAME);
  45
+
  46
+            return this;
  47
+        },
  48
+
  49
+        /**
  50
+         * Create AC object for a particular controller.
  51
+         * @method _createActionContext
  52
+         * @protected
  53
+         * @param {object} command the command to dispatch
  54
+         * @param {OutputAdapter} adapter the output adapter
  55
+         */
  56
+        _createActionContext: function (command, adapter) {
  57
+            var ac,
  58
+                controller = Y.mojito.controllers[command.instance.controller],
  59
+                perf = Y.mojito.perf.timeline('mojito', 'ac:ctor',
  60
+                    'create ControllerContext', command);
  61
+
  62
+            // Note that creation of an ActionContext current causes
  63
+            // immediate invocation of the dispatch() call.
  64
+            try {
  65
+                ac = new Y.mojito.ActionContext({
  66
+                    command: command,
  67
+                    controller: Y.mojito.util.heir(controller),
  68
+                    dispatcher: this,         // NOTE passing dispatcher.
  69
+                    adapter: adapter,
  70
+                    store: this.store
  71
+                });
  72
+            } catch (e) {
  73
+                Y.log('Error from dispatch on instance \'' +
  74
+                    (command.instance.id || '@' + command.instance.type) +
  75
+                    '\':', 'error', NAME);
  76
+                Y.log(e.message, 'error', NAME);
  77
+                Y.log(e.stack, 'error', NAME);
  78
+                adapter.error(e);
  79
+            }
  80
+            perf.done(); // closing the 'ac:ctor' timeline
  81
+        },
  82
+
  83
+        /**
  84
+         * Executes a command in a remote runtime if possible.
  85
+         * @method rpc
  86
+         * @public
  87
+         * @param {object} command the command to dispatch
  88
+         * @param {OutputAdapter} adapter the output adapter
  89
+         */
  90
+        rpc: function (command, adapter) {
  91
+            if (this.tunnel) {
  92
+
  93
+                Y.log('Dispatching instance "' + (command.instance.base || '@' +
  94
+                    command.instance.type) + '" through RPC tunnel.', 'info', NAME);
  95
+                this.tunnel.rpc(command, adapter);
  96
+
  97
+            } else {
  98
+
  99
+                adapter.error(new Error('RPC tunnel is not available in the ' +
  100
+                    command.context.runtime + ' runtime.'));
  101
+
  102
+            }
  103
+        },
  104
+
  105
+        /**
  106
+         * Dispatch a command in the current runtime, or fallback
  107
+         * to a remote runtime when posible.
  108
+         * @method dispatch
  109
+         * @public
  110
+         * @param {object} command the command to dispatch
  111
+         * @param {OutputAdapter} adapter the output adapter
  112
+         */
  113
+        dispatch: function (command, adapter) {
  114
+
  115
+            var my = this,
  116
+                store = this.store,
  117
+                perf = Y.mojito.perf.timeline('mojito',
  118
+                    'dispatch:expandInstance',
  119
+                    'gather details about mojit', command);
  120
+
  121
+            store.validateContext(command.context);
  122
+
  123
+            if (command.rpc) {
  124
+                // forcing to dispatch command through RPC tunnel
  125
+                this.rpc(command, adapter);
  126
+                return;
  127
+            }
  128
+
  129
+            store.expandInstance(command.instance, command.context,
  130
+                function (err, instance) {
  131
+
  132
+                    perf.done(); // closing 'dispatch:expandInstance' timeline
  133
+
  134
+                    if (err || !instance || !instance.controller) {
  135
+
  136
+                        adapter.error(new Error('Cannot expand instance [' + (command.instance.base || '@' +
  137
+                            command.instance.type) + '], or instance.controller is undefined'));
  138
+                        return;
  139
+
  140
+                    }
  141
+
  142
+                    // We replace the given instance with the expanded instance.
  143
+                    command.instance = instance;
  144
+
  145
+                    if (!Y.mojito.controllers[instance.controller]) {
  146
+                        // the controller was not found, we should halt
  147
+                        adapter.error(new Error('Invalid controller name [' +
  148
+                            command.instance.controller + '] for mojit [' +
  149
+                            command.instance.type + '].'));
  150
+                    } else {
  151
+                        // dispatching AC
  152
+                        my._createActionContext(command, adapter);
  153
+                    }
  154
+
  155
+                });
  156
+        }
  157
+
  158
+    };
  159
+
  160
+}, '0.1.0', {requires: [
  161
+    'mojito-action-context',
  162
+    'mojito-util'
  163
+]});
2  lib/management/yui-module-configurator.js
@@ -118,7 +118,7 @@ module.exports = function(dir, excludes) {
118 118
         return modules;
119 119
     }
120 120
 
121  
-    if (Y.Lang.isArray(dir)) {
  121
+    if (!Y.Lang.isArray(dir)) {
122 122
         dir = [dir];
123 123
     }
124 124
 
16  tests/run.js
@@ -203,7 +203,7 @@ function deploy (cmd, callback) {
203 203
             }
204 204
         })(apps[i]);
205 205
     }
206  
-    async.series(appSeries, callback);
  206
+    async.parallel(appSeries, callback);
207 207
 }
208 208
 
209 209
 function startArrowSelenium (cmd, callback) {
@@ -319,14 +319,20 @@ function runMojitoApp (cliOptions, basePath, path, port, params, callback) {
319 319
     }
320 320
     */
321 321
 
  322
+    var p, listener;
  323
+    listener = function(data) {
  324
+        if (data.toString().match(/Mojito started /)) {
  325
+            p.stdout.removeListener('data', listener);
  326
+            console.log('Started ' + path + ' at port ' + port + ' with params ' + (params || 'empty'));
  327
+            callback();
  328
+        }
  329
+    }
322 330
     params = params || '';
323 331
     console.log('Starting ' + path + ' at port ' + port + ' with params ' + (params || 'empty'));
324  
-    var p = runCommand(basePath + '/' + path, cwd + "/../bin/mojito", ["start", port, "--context", params], function () {});
  332
+    p = runCommand(basePath + '/' + path, cwd + "/../bin/mojito", ["start", port, "--context", params], function () {});
325 333
     pids.push(p.pid);
326 334
     pidNames[p.pid] = libpath.basename(path) + ':' + port + (params ? '?' + params : '');
327  
-    // Give each app a second to start
328  
-    setTimeout(function () { callback(null) }, 1000);
329  
-
  335
+    p.stdout.on('data', listener);
330 336
     if (cliOptions.debugApps) {
331 337
         p.stdout.on('data', function(data) {
332 338
             console.error('---DEBUG ' + port + ' STDOUT--- ' + data.toString());
16  tests/unit/lib/app/autoload/autoload_test_descriptor.json
@@ -16,13 +16,21 @@
16 16
                 },
17 17
                 "group": "fw,unit,client,server"
18 18
             },
19  
-            "dispatch.common": {
  19
+            "dispatch.server": {
20 20
                 "params": {
21 21
                     "page": "$$config.base$$/mojito-test.html",
22  
-                    "lib": "$$config.lib$$/app/autoload/action-context.common.js,./../../../../../lib/app/autoload/dispatch.common.js",
23  
-                    "test": "./test-dispatch.common.js"
  22
+                    "lib": "$$config.lib$$/app/autoload/action-context.common.js,./../../../../../lib/app/autoload/dispatch.server.js",
  23
+                    "test": "./test-dispatch.server.js"
24 24
                 },
25  
-                "group": "fw,unit,client,server"
  25
+                "group": "fw,unit,server"
  26
+            },
  27
+            "dispatch.client": {
  28
+                "params": {
  29
+                    "page": "$$config.base$$/mojito-test.html",
  30
+                    "lib": "$$config.lib$$/app/autoload/action-context.common.js,./../../../../../lib/app/autoload/dispatch.client.js",
  31
+                    "test": "./test-dispatch.client.js"
  32
+                },
  33
+                "group": "fw,unit,client"
26 34
             },
27 35
             "mojit-proxy.client": {
28 36
                 "params": {
267  tests/unit/lib/app/autoload/test-dispatch.client.js
... ...
@@ -0,0 +1,267 @@
  1
+/*
  2
+ * Copyright (c) 2011-2012, Yahoo! Inc.  All rights reserved.
  3
+ * Copyrights licensed under the New BSD License.
  4
+ * See the accompanying LICENSE file for terms.
  5
+ */
  6
+YUI.add('mojito-dispatcher-client-tests', function(Y, NAME) {
  7
+
  8
+    var suite = new Y.Test.Suite(NAME),
  9
+        A = Y.Assert,
  10
+        dispatcher = Y.mojito.Dispatcher,
  11
+        store,
  12
+        command,
  13
+        adapter;
  14
+
  15
+    suite.add(new Y.Test.Case({
  16
+
  17
+        name: 'dispatch',
  18
+
  19
+        'setUp': function() {
  20
+            store = {
  21
+                getAppConfig: function() {
  22
+                    return { yui: { dependencyCalculations: 'ondemand' } };
  23
+                },
  24
+                getStaticContext: function () {
  25
+                },
  26
+                getRoutes: function() {
  27
+                },
  28
+                validateContext: function() {
  29
+                },
  30
+                expandInstance: function(instance, context, cb) {
  31
+                    cb(null, {
  32
+                        type: instance.type,
  33
+                        id: 'xyz123',
  34
+                        instanceId: 'xyz123',
  35
+                        'controller-module': 'dispatch',
  36
+                        yui: {
  37
+                            config: {},
  38
+                            langs: [],
  39
+                            requires: [],
  40
+                            sorted: ['mojito', 'mojito-action-context'],
  41
+                            sortedPaths: {}
  42
+                        }
  43
+                    });
  44
+                }
  45
+            };
  46
+
  47
+            command = {
  48
+                action: 'index',
  49
+                instance: {
  50
+                    type: 'M'
  51
+                },
  52
+                context: {
  53
+                    lang: 'klingon',
  54
+                    langs: 'klingon'
  55
+                }
  56
+            };
  57
+
  58
+            adapter = {};
  59
+        },
  60
+
  61
+        'tearDown': function() {
  62
+            store = null;
  63
+            command = null;
  64
+            adapter = null;
  65
+        },
  66
+
  67
+        'test rpc with tunnel': function () {
  68
+            var tunnel,
  69
+                tunnelCommand;
  70
+
  71
+            tunnel = {
  72
+                rpc: function (c, a) {
  73
+                    tunnelCommand = c;
  74
+                }
  75
+            };
  76
+            dispatcher.init(store, tunnel);
  77
+            dispatcher.rpc(command, {
  78
+                error: function () {
  79
+                    A.fail('tunnel should be called instead');
  80
+                }
  81
+            });
  82
+            A.areSame(command, tunnelCommand, 'delegate command to tunnel');
  83
+        },
  84
+
  85
+        'test rpc without tunnel available': function () {
  86
+            var tunnel,
  87
+                errorTriggered,
  88
+                tunnelCommand;
  89
+
  90
+            tunnel = null;
  91
+            errorTriggered = false;
  92
+            dispatcher.init(store, tunnel);
  93
+            dispatcher.rpc(command, {
  94
+                error: function () {
  95
+                    errorTriggered = true;
  96
+                }
  97
+            });
  98
+            A.isTrue(errorTriggered, 'if tunnel is not set, it should call adapter.error');
  99
+        },
  100
+
  101
+        'test dispatch with command.rpc=1': function () {
  102
+            var tunnel,
  103
+                tunnelCommand;
  104
+
  105
+            tunnel = {
  106
+                rpc: function (c, a) {
  107
+                    tunnelCommand = c;
  108
+                }
  109
+            };
  110
+            command.rpc = 1;
  111
+            dispatcher.init(store, tunnel);
  112
+            dispatcher.rpc(command, {
  113
+                error: function () {
  114
+                    A.fail('tunnel should be called instead');
  115
+                }
  116
+            });
  117
+            A.areSame(command, tunnelCommand, 'delegate command to tunnel');
  118
+        },
  119
+
  120
+        'test dispatch with invalid mojit': function () {
  121
+            var tunnel,
  122
+                tunnelCommand;
  123
+
  124
+            tunnel = {
  125
+                rpc: function (c, a) {
  126
+                    tunnelCommand = c;
  127
+                }
  128
+            };
  129
+            dispatcher.init(store, tunnel);
  130
+            // if the expandInstance calls with an error, the tunnel
  131
+            // should be tried.
  132
+            store.expandInstance = function (instance, context, callback) {
  133
+                callback({error: 1});
  134
+            };
  135
+            dispatcher.dispatch(command, {
  136
+                error: function () {
  137
+                    A.fail('tunnel should be called instead');
  138
+                }
  139
+            });
  140
+            A.areSame(command, tunnelCommand, 'delegate command to tunnel');
  141
+        },
  142
+
  143
+        'test dispatch with valid controller': function () {
  144
+            var tunnel,
  145
+                useCommand,
  146
+                _useController = dispatcher._useController;
  147
+
  148
+            dispatcher.init(store, tunnel);
  149
+            // if the expandInstance calls with an error, the tunnel
  150
+            // should be tried.
  151
+            store.expandInstance = function (instance, context, callback) {
  152
+                instance.controller = 'foo';
  153
+                Y.mojito.controllers[instance.controller] = {
  154
+                    fakeController: true
  155
+                };
  156
+                callback(null, instance);
  157
+            };
  158
+            dispatcher._useController = function (c) {
  159
+                useCommand = c;
  160
+            };
  161
+            dispatcher.dispatch(command, {
  162
+                error: function () {
  163
+                    A.fail('_useController should be called instead');
  164
+                }
  165
+            });
  166
+            A.areSame(command, useCommand, '_useController should be issued to attach modules.');
  167
+
  168
+            // restoring references
  169
+            dispatcher._useController = _useController;
  170
+        },
  171
+
  172
+        'test dispatch with invalid controller': function () {
  173
+            var tunnel,
  174
+                useCommand,
  175
+                acCommand,
  176
+                _createActionContext = dispatcher._createActionContext,
  177
+                _useController = dispatcher._useController;
  178
+
  179
+            dispatcher.init(store, tunnel);
  180
+            // if the expandInstance calls with an error, the tunnel
  181
+            // should be tried.
  182
+            store.expandInstance = function (instance, context, callback) {
  183
+                instance.controller = 'foo';
  184
+                Y.mojito.controllers[instance.controller] = null;
  185
+                callback(null, instance);
  186
+            };
  187
+            dispatcher._useController = function (c) {
  188
+                useCommand = c;
  189
+            };
  190
+            dispatcher._createActionContext = function (c) {
  191
+                A.fail('_createActionContext should be called instead');
  192
+            };
  193
+            dispatcher.dispatch(command, {
  194
+                error: function () {
  195
+                    A.fail('_useController should be called instead');
  196
+                }
  197
+            });
  198
+            A.areSame(command, useCommand, '_useController should be called based on the original command');
  199
+
  200
+            // restoring references
  201
+            dispatcher._createActionContext = _createActionContext;
  202
+            dispatcher._useController = _useController;
  203
+        },
  204
+
  205
+        'test instance caching workflow': function () {
  206
+            var tunnel,
  207
+                useCommand,
  208
+                _useController = dispatcher._useController;
  209
+
  210
+            dispatcher.init(store, tunnel);
  211
+            // if the expandInstance calls with an error, the tunnel
  212
+            // should be tried.
  213
+            store.expandInstance = function (instance, context, callback) {
  214
+                instance.controller = 'foo';
  215
+                Y.mojito.controllers[instance.controller] = {
  216
+                    foo: function () {
  217
+                        // synthetic controller
  218
+                    },
  219
+                    bar: function () {
  220
+                        // synthetic controller
  221
+                    }
  222
+                };
  223
+                callback(null, instance);
  224
+            };
  225
+            dispatcher._useController = function (c) {
  226
+                useCommand = c;
  227
+            };
  228
+            dispatcher.dispatch({
  229
+                action: 'foo',
  230
+                instance: {
  231
+                    instanceId: 123,
  232
+                    type: 'M'
  233
+                }
  234
+            }, {
  235
+                error: function () {
  236
+                    A.fail('_useController should be called instead');
  237
+                }
  238
+            });
  239
+            A.areSame(123, useCommand.instance.instanceId, 'instanceId should be preserved during the first round.');
  240
+
  241
+            // triggering the second round
  242
+            useCommand.instance.cacheFlag = true;
  243
+            useCommand = null;
  244
+            dispatcher.dispatch({
  245
+                action: 'bar',
  246
+                instance: {
  247
+                    instanceId: 123,
  248
+                    type: 'M'
  249
+                }
  250
+            }, {
  251
+                error: function () {
  252
+                    A.fail('_useController should be called instead');
  253
+                }
  254
+            });
  255
+            A.areSame(123, useCommand.instance.instanceId, 'instanceId should be preserved during the second round.');
  256
+            A.isTrue(useCommand.instance.cacheFlag, 'command.instance should be re-use if the instanceId is the same.');
  257
+
  258
+            // restoring references
  259
+            dispatcher._useController = _useController;
  260
+        }
  261
+
  262
+    }));
  263
+
  264
+
  265
+    Y.Test.Runner.add(suite);
  266
+
  267
+}, '0.0.1', {requires: ['mojito-dispatcher']});
50  tests/unit/lib/app/autoload/test-dispatch.common.js → tests/unit/lib/app/autoload/test-dispatch.server.js
@@ -3,7 +3,7 @@
3 3
  * Copyrights licensed under the New BSD License.
4 4
  * See the accompanying LICENSE file for terms.
5 5
  */
6  
-YUI.add('mojito-dispatcher-tests', function(Y, NAME) {
  6
+YUI.add('mojito-dispatcher-server-tests', function(Y, NAME) {
7 7
 
8 8
     var suite = new Y.Test.Suite(NAME),
9 9
         A = Y.Assert,
@@ -119,36 +119,10 @@ YUI.add('mojito-dispatcher-tests', function(Y, NAME) {
119 119
             A.areSame(command, tunnelCommand, 'delegate command to tunnel');
120 120
         },
121 121
 
122  
-        'test dispatch with invalid mojit': function () {
123  
-            var tunnel,
124  
-                tunnelCommand;
125  
-
126  
-            tunnel = {
127  
-                rpc: function (c, a) {
128  
-                    tunnelCommand = c;
129  
-                }
130  
-            };
131  
-            errorTriggered = false;
132  
-            dispatcher.init(store, tunnel);
133  
-            // if the expandInstance calls with an error, the tunnel
134  
-            // should be tried.
135  
-            store.expandInstance = function (instance, context, callback) {
136  
-                callback({error: 1});
137  
-            };
138  
-            dispatcher.dispatch(command, {
139  
-                error: function () {
140  
-                    A.fail('tunnel should be called instead');
141  
-                }
142  
-            });
143  
-            A.areSame(command, tunnelCommand, 'delegate command to tunnel');
144  
-        },
145  
-
146 122
         'test dispatch with valid controller': function () {
147 123
             var tunnel,
148  
-                useCommand,
149 124
                 acCommand,
150  
-                _createActionContext = dispatcher._createActionContext,
151  
-                _useController = dispatcher._useController;
  125
+                _createActionContext = dispatcher._createActionContext;
152 126
 
153 127
             errorTriggered = false;
154 128
             dispatcher.init(store, tunnel);
@@ -161,9 +135,6 @@ YUI.add('mojito-dispatcher-tests', function(Y, NAME) {
161 135
                 };
162 136
                 callback(null, instance);
163 137
             };
164  
-            dispatcher._useController = function (c) {
165  
-                A.fail('_createActionContext should be called instead');
166  
-            };
167 138
             dispatcher._createActionContext = function (c) {
168 139
                 acCommand = c;
169 140
             };
@@ -176,15 +147,12 @@ YUI.add('mojito-dispatcher-tests', function(Y, NAME) {
176 147
 
177 148
             // restoring references
178 149
             dispatcher._createActionContext = _createActionContext;
179  
-            dispatcher._useController = _useController;
180 150
         },
181 151
 
182 152
         'test dispatch with invalid controller': function () {
183 153
             var tunnel,
184  
-                useCommand,
185  
-                acCommand,
186  
-                _createActionContext = dispatcher._createActionContext,
187  
-                _useController = dispatcher._useController;
  154
+                adapterErrorCalled,
  155
+                _createActionContext = dispatcher._createActionContext;
188 156
 
189 157
             errorTriggered = false;
190 158
             dispatcher.init(store, tunnel);
@@ -195,22 +163,18 @@ YUI.add('mojito-dispatcher-tests', function(Y, NAME) {
195 163
                 Y.mojito.controllers[instance.controller] = null;
196 164
                 callback(null, instance);
197 165
             };
198  
-            dispatcher._useController = function (c) {
199  
-                useCommand = c;
200  
-            };
201 166
             dispatcher._createActionContext = function (c) {
202  
-                A.fail('_createActionContext should be called instead');
  167
+                A.fail('adapter.error should be called instead');
203 168
             };
204 169
             dispatcher.dispatch(command, {
205 170
                 error: function () {
206  
-                    A.fail('_useController should be called instead');
  171
+                    adapterErrorCalled = true;
207 172
                 }
208 173
             });
209  
-            A.areSame(command, useCommand, '_useController should be called based on the original command');
  174
+            A.isTrue(adapterErrorCalled, 'adapter.error should be called for invalid controllers');
210 175
 
211 176
             // restoring references
212 177
             dispatcher._createActionContext = _createActionContext;
213  
-            dispatcher._useController = _useController;
214 178
         }
215 179
 
216 180
     }));

0 notes on commit e6499c5

Please sign in to comment.
Something went wrong with that request. Please try again.