Merge lp:~benji/juju-gui/megawatcher-propose into lp:juju-gui/experimental
- megawatcher-propose
- Merge into trunk
Status: | Merged |
---|---|
Merged at revision: | 457 |
Proposed branch: | lp:~benji/juju-gui/megawatcher-propose |
Merge into: | lp:juju-gui/experimental |
Diff against target: |
582 lines (+368/-24) 6 files modified
Makefile (+1/-1) app/store/env/go.js (+148/-4) app/store/env/python.js (+12/-0) test/test_env_go.js (+202/-13) test/utils.js (+5/-5) undocumented (+0/-1) |
To merge this branch: | bzr merge lp:~benji/juju-gui/megawatcher-propose |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Juju GUI Hackers | Pending | ||
Review via email: mp+155471@code.launchpad.net |
Commit message
Description of the change
Wire up the first bits of the megawatcher.
There is still much left to do, but what is here works and is reasonably
well tested.
Jeff Pihach (hatch) wrote : | # |
Francesco Banconi (frankban) wrote : | # |
This branch looks good, a solid base for the megawatcher stuff.
LGTM with some questions and comments below.
Thank you.
https:/
File app/store/env/go.js (right):
https:/
app/store/
Can't we just remove this method?
https:/
app/store/
Nice, thanks.
https:/
app/store/
converter(
Very nice and simple.
https:/
app/store/
Just curiosity: why an event is preferred here over directly calling
_handleRpcResponse?
https:/
File test/test_env_go.js (right):
https:/
test/test_
login', function() {
typo: after
https:/
test/test_
Here we could also test that Params.Id is effectively the answer...
https:/
test/test_
'juju-tests-
It seems 'juju-tests-utils' is not really required by this test case.
Ditto for all the converter tests below.
https:/
File undocumented (left):
https:/
undocumented:15: app/store/
Thank you.
Preview Diff
1 | === modified file 'Makefile' |
2 | --- Makefile 2013-03-22 21:22:38 +0000 |
3 | +++ Makefile 2013-03-26 12:15:49 +0000 |
4 | @@ -242,7 +242,7 @@ |
5 | app/assets/javascripts/d3.v2.min.js |
6 | |
7 | gjslint: virtualenv/bin/gjslint |
8 | - virtualenv/bin/gjslint --strict --nojsdoc --jslint_error=all \ |
9 | + virtualenv/bin/gjslint --unix --strict --nojsdoc --jslint_error=all \ |
10 | --custom_jsdoc_tags module,main,class,method,event,property,attribute,submodule,namespace,extends,config,constructor,static,final,readOnly,writeOnce,optional,required,param,return,for,type,private,protected,requires,default,uses,example,chainable,deprecated,since,async,beta,bubbles,extension,extensionfor,extension_for \ |
11 | -x $(LINT_IGNORE) $(JSFILES) |
12 | |
13 | |
14 | === modified file 'app/store/env/go.js' |
15 | --- app/store/env/go.js 2013-03-22 16:52:05 +0000 |
16 | +++ app/store/env/go.js 2013-03-26 12:15:49 +0000 |
17 | @@ -29,6 +29,56 @@ |
18 | |
19 | GoEnvironment.NAME = 'go-env'; |
20 | |
21 | + var entityInfoConverters = { |
22 | + /** |
23 | + Convert a Go style entity info into the expected legacy format. |
24 | + |
25 | + @param {Object} entityInfo The JSON entity information from Go. |
26 | + @return {Object} The legacy JSON data that the GUI expects. |
27 | + */ |
28 | + service: function(entityInfo) { |
29 | + return { |
30 | + id: entityInfo.Name, |
31 | + exposed: entityInfo.Exposed // XXX and more stuff |
32 | + }; |
33 | + }, |
34 | + /** |
35 | + Convert a Go style entity info into the expected legacy format. |
36 | + |
37 | + @param {Object} entityInfo The JSON entity information from Go. |
38 | + @return {Object} The legacy JSON data that the GUI expects. |
39 | + */ |
40 | + unit: function(entityInfo) { |
41 | + return { |
42 | + id: entityInfo.Name, |
43 | + service: entityInfo.Service // XXX and more stuff |
44 | + }; |
45 | + }, |
46 | + /** |
47 | + Convert a Go style entity info into the expected legacy format. |
48 | + |
49 | + @param {Object} entityInfo The JSON entity information from Go. |
50 | + @return {Object} The legacy JSON data that the GUI expects. |
51 | + */ |
52 | + relation: function(entityInfo) { |
53 | + return { |
54 | + id: entityInfo.Key // XXX and more stuff |
55 | + }; |
56 | + }, |
57 | + /** |
58 | + Convert a Go style entity info into the expected legacy format. |
59 | + |
60 | + @param {Object} entityInfo The JSON entity information from Go. |
61 | + @return {Object} The legacy JSON data that the GUI expects. |
62 | + */ |
63 | + machine: function(entityInfo) { |
64 | + return { |
65 | + id: entityInfo.Id, |
66 | + instance_id: entityInfo.InstanceId // XXX and more stuff |
67 | + }; |
68 | + } |
69 | + }; |
70 | + |
71 | Y.extend(GoEnvironment, environments.BaseEnvironment, { |
72 | |
73 | /** |
74 | @@ -41,7 +91,26 @@ |
75 | // Define the default user name for this environment. It will appear as |
76 | // predefined value in the login mask. |
77 | this.defaultUser = 'user-admin'; |
78 | - }, |
79 | + this.on('_rpc_response', this._handleRpcResponse, this); |
80 | + }, |
81 | + |
82 | + /** |
83 | + XXX FAKE FAKE FAKE, does not do anything. |
84 | + |
85 | + Get the available endpoints (by interface) for a collection of |
86 | + services. |
87 | + |
88 | + @method get_endpoints |
89 | + @param {Array} services Zero or more currently deployed services for |
90 | + which the endpoints should be collected. Specifying an empty array |
91 | + indicates that all deployed services should be analyzed. |
92 | + @param {Function} callback A callable that must be called once the |
93 | + operation is performed. |
94 | + @return {undefined} Sends a message to the server only. |
95 | + */ |
96 | + get_endpoints: function(services, callback) { |
97 | + }, |
98 | + |
99 | |
100 | /** |
101 | * See "app.store.env.base.BaseEnvironment.dispatch_result". |
102 | @@ -76,11 +145,83 @@ |
103 | this._txn_callbacks[tid] = callback; |
104 | } |
105 | op.RequestId = tid; |
106 | + if (!op.Params) { |
107 | + op.Params = {}; |
108 | + } |
109 | var msg = Y.JSON.stringify(op); |
110 | this.ws.send(msg); |
111 | }, |
112 | |
113 | /** |
114 | + Begin watching all Juju status. |
115 | + |
116 | + @method _watchAll |
117 | + @private |
118 | + @return {undefined} Sends a message to the server only. |
119 | + */ |
120 | + _watchAll: function() { |
121 | + this._send_rpc( |
122 | + { |
123 | + Type: 'Client', |
124 | + Request: 'WatchAll' |
125 | + }, |
126 | + function(data) { |
127 | + if (data.Error) { |
128 | + console.log('aiiiiie!'); // retry and eventually alert user XXX |
129 | + } else { |
130 | + this._allWatcherId = data.Response.AllWatcherId; |
131 | + this._next(); |
132 | + } |
133 | + } |
134 | + ); |
135 | + }, |
136 | + |
137 | + /** |
138 | + Process an incoming response to an RPC request. |
139 | + |
140 | + @method _handleRpcResponse |
141 | + @param {Object} data The data returned by the server. |
142 | + @return {undefined} Nothing. |
143 | + */ |
144 | + _handleRpcResponse: function(data) { |
145 | + // We do this early to get a response back fast. Might be a bad |
146 | + // idea. :-) |
147 | + this._next(); |
148 | + // data.Deltas has our stuff. We need to translate delta |
149 | + // events based on the deltas we got. |
150 | + var deltas = []; |
151 | + data.Response.Deltas.forEach(function(delta) { |
152 | + var kind = delta[0], operation = delta[1], entityInfo = delta[2]; |
153 | + var converter = entityInfoConverters[kind]; |
154 | + deltas.push([kind, operation, converter(entityInfo)]); |
155 | + }); |
156 | + this.fire('delta', {data: {result: deltas}}); |
157 | + }, |
158 | + |
159 | + /** |
160 | + Get the next batch of deltas from the Juju status. |
161 | + |
162 | + @method _next |
163 | + @private |
164 | + @return {undefined} Sends a message to the server only. |
165 | + */ |
166 | + _next: function() { |
167 | + this._send_rpc({ |
168 | + Type: 'AllWatcher', |
169 | + Request: 'Next', |
170 | + Params: { |
171 | + Id: this._allWatcherId |
172 | + } |
173 | + }, function(data) { |
174 | + if (data.Error) { |
175 | + console.log('aiiiiie!'); // XXX |
176 | + } else { |
177 | + this.fire('_rpc_response', data); |
178 | + } |
179 | + }); |
180 | + }, |
181 | + |
182 | + /** |
183 | * React to the results of sending a login message to the server. |
184 | * |
185 | * @method handleLoginEvent |
186 | @@ -88,10 +229,12 @@ |
187 | * @return {undefined} Nothing. |
188 | */ |
189 | handleLogin: function(data) { |
190 | + this.pendingLoginResponse = false; |
191 | this.userIsAuthenticated = !data.Error; |
192 | if (this.userIsAuthenticated) { |
193 | // If login succeeded retrieve the environment info. |
194 | this.environmentInfo(); |
195 | + this._watchAll(); |
196 | } else { |
197 | // If the credentials were rejected remove them. |
198 | this.setCredentials(null); |
199 | @@ -109,7 +252,7 @@ |
200 | */ |
201 | login: function() { |
202 | // If the user is already authenticated there is nothing to do. |
203 | - if (this.userIsAuthenticated) { |
204 | + if (this.userIsAuthenticated || this.pendingLoginResponse) { |
205 | return; |
206 | } |
207 | var credentials = this.getCredentials(); |
208 | @@ -122,6 +265,7 @@ |
209 | Password: credentials.password |
210 | } |
211 | }, this.handleLogin); |
212 | + this.pendingLoginResponse = true; |
213 | } else { |
214 | console.warn('Attempted login without providing credentials.'); |
215 | this.fire('login', {data: {result: false}}); |
216 | @@ -156,8 +300,7 @@ |
217 | environmentInfo: function() { |
218 | this._send_rpc({ |
219 | Type: 'Client', |
220 | - Request: 'EnvironmentInfo', |
221 | - Params: {} |
222 | + Request: 'EnvironmentInfo' |
223 | }, this.handleEnvironmentInfo); |
224 | }, |
225 | |
226 | @@ -587,6 +730,7 @@ |
227 | }); |
228 | |
229 | environments.GoEnvironment = GoEnvironment; |
230 | + environments.entityInfoConverters = entityInfoConverters; |
231 | |
232 | }, '0.1.0', { |
233 | requires: [ |
234 | |
235 | === modified file 'app/store/env/python.js' |
236 | --- app/store/env/python.js 2013-02-26 20:04:10 +0000 |
237 | +++ app/store/env/python.js 2013-03-26 12:15:49 +0000 |
238 | @@ -367,6 +367,18 @@ |
239 | retry: retry || false}, callback, true); |
240 | }, |
241 | |
242 | + /** |
243 | + Get the available endpoints (by interface) for a collection of |
244 | + services. |
245 | + |
246 | + @method get_endpoints |
247 | + @param {Array} services Zero or more currently deployed services for |
248 | + which the endpoints should be collected. Specifying an empty array |
249 | + indicates that all deployed services should be analyzed. |
250 | + @param {Function} callback A callable that must be called once the |
251 | + operation is performed. |
252 | + @return {undefined} Sends a message to the server only. |
253 | + */ |
254 | get_endpoints: function(services, callback) { |
255 | this._send_rpc({'op': 'get_endpoints', 'service_names': services}, |
256 | callback); |
257 | |
258 | === modified file 'test/test_env_go.js' |
259 | --- test/test_env_go.js 2013-03-22 16:52:05 +0000 |
260 | +++ test/test_env_go.js 2013-03-26 12:15:49 +0000 |
261 | @@ -13,18 +13,16 @@ |
262 | }); |
263 | }); |
264 | |
265 | - beforeEach(function(done) { |
266 | + beforeEach(function() { |
267 | conn = new utils.SocketStub(); |
268 | env = juju.newEnvironment({ |
269 | conn: conn, user: 'user', password: 'password' |
270 | }, 'go'); |
271 | env.connect(); |
272 | - done(); |
273 | }); |
274 | |
275 | - afterEach(function(done) { |
276 | + afterEach(function() { |
277 | env.destroy(); |
278 | - done(); |
279 | }); |
280 | |
281 | it('sends the correct login message', function() { |
282 | @@ -47,7 +45,7 @@ |
283 | assert.isTrue(env.failedAuthentication); |
284 | }); |
285 | |
286 | - it('fires a login event on successful login', function(done) { |
287 | + it('fires a login event on successful login', function() { |
288 | var loginFired = false; |
289 | var result; |
290 | env.on('login', function(evt) { |
291 | @@ -59,10 +57,9 @@ |
292 | conn.msg({RequestId: 1, Response: {}}); |
293 | assert.isTrue(loginFired); |
294 | assert.isTrue(result); |
295 | - done(); |
296 | }); |
297 | |
298 | - it('fires a login event on failed login', function(done) { |
299 | + it('fires a login event on failed login', function() { |
300 | var loginFired = false; |
301 | var result; |
302 | env.on('login', function(evt) { |
303 | @@ -74,7 +71,6 @@ |
304 | conn.msg({RequestId: 1, Error: 'Invalid user or password'}); |
305 | assert.isTrue(loginFired); |
306 | assert.isFalse(result); |
307 | - done(); |
308 | }); |
309 | |
310 | it('avoids sending login requests without credentials', function() { |
311 | @@ -83,20 +79,28 @@ |
312 | assert.equal(0, conn.messages.length); |
313 | }); |
314 | |
315 | - it('calls environmentInfo on successful login', function(done) { |
316 | + it('calls environmentInfo and watchAll ofter login', function() { |
317 | env.login(); |
318 | // Assume login to be the first request. |
319 | conn.msg({RequestId: 1, Response: {}}); |
320 | - var last_message = conn.last_message(); |
321 | + var environmentInfoMessage = conn.last_message(2); |
322 | // EnvironmentInfo is the second request. |
323 | - var expected = { |
324 | + var environmentInfoExpected = { |
325 | Type: 'Client', |
326 | Request: 'EnvironmentInfo', |
327 | RequestId: 2, |
328 | Params: {} |
329 | }; |
330 | - assert.deepEqual(expected, last_message); |
331 | - done(); |
332 | + assert.deepEqual(environmentInfoExpected, environmentInfoMessage); |
333 | + var watchAllMessage = conn.last_message(); |
334 | + // EnvironmentInfo is the second request. |
335 | + var watchAllExpected = { |
336 | + Type: 'Client', |
337 | + Request: 'WatchAll', |
338 | + RequestId: 3, |
339 | + Params: {} |
340 | + }; |
341 | + assert.deepEqual(watchAllExpected, watchAllMessage); |
342 | }); |
343 | |
344 | it('sends the correct request for environment info', function() { |
345 | @@ -651,6 +655,191 @@ |
346 | assert.equal(err, 'service "yoursql" not found'); |
347 | }); |
348 | |
349 | + it('provides for a missing Params', function() { |
350 | + // If no "Params" are provided in an RPC call an empty one is added. |
351 | + var op = {}; |
352 | + env._send_rpc(op); |
353 | + assert.deepEqual(op.Params, {}); |
354 | + }); |
355 | + |
356 | + it('can watch all changes', function() { |
357 | + env._watchAll(); |
358 | + msg = conn.last_message(); |
359 | + assert.equal(msg.Type, 'Client'); |
360 | + assert.equal(msg.Request, 'WatchAll'); |
361 | + }); |
362 | + |
363 | + it('can retrieve the next set of environment changes', function() { |
364 | + // This is normally set by _watchAll, we'll fake it here. |
365 | + env._allWatcherId = 42; |
366 | + env._next(); |
367 | + msg = conn.last_message(); |
368 | + assert.equal(msg.Type, 'AllWatcher'); |
369 | + assert.isTrue('Id' in msg.Params); |
370 | + assert.equal(msg.Request, 'Next'); |
371 | + }); |
372 | + |
373 | + it('fires "_rpc_response" message after an RPC response', function(done) { |
374 | + // We don't want the real response, we just want to be sure the event is |
375 | + // fired. |
376 | + env.detach('_rpc_response'); |
377 | + env.on('_rpc_response', function(data) { |
378 | + done(); |
379 | + }); |
380 | + // Calling this sets up the callback. |
381 | + env._next(); |
382 | + env._txn_callbacks[env._counter].call(env, {}); |
383 | + // The only test assertion is that done (above) is called. |
384 | + }); |
385 | + |
386 | + it('fires "delta" when handling an RPC response', function(done) { |
387 | + env.detach('delta'); |
388 | + var callbackData = {Response: {Deltas: [['service', 'deploy', {}]]}}; |
389 | + env.on('delta', function(data) { |
390 | + console.log(data.result); |
391 | + done(); |
392 | + }); |
393 | + env._handleRpcResponse(callbackData); |
394 | + }); |
395 | + |
396 | + }); |
397 | + |
398 | +})(); |
399 | + |
400 | +(function() { |
401 | + |
402 | + describe('Go Juju environment service entity converter', function() { |
403 | + var environments, utils, Y, converter, entityInfoConverters; |
404 | + |
405 | + before(function(done) { |
406 | + Y = YUI(GlobalConfig).use(['juju-env', 'juju-tests-utils'], function(Y) { |
407 | + environments = Y.namespace('juju.environments'); |
408 | + utils = Y.namespace('juju-tests.utils'); |
409 | + converter = environments.entityInfoConverters.service; |
410 | + entityInfoConverters = environments.entityInfoConverters; |
411 | + done(); |
412 | + }); |
413 | + }); |
414 | + |
415 | + |
416 | + it('exists', function() { |
417 | + assert.isTrue('service' in entityInfoConverters); |
418 | + }); |
419 | + |
420 | + it('converts "Name" to "id"', function() { |
421 | + var converted = converter({Name: 'service name'}); |
422 | + assert.isTrue('id' in converted); |
423 | + assert.equal('service name', converted.id); |
424 | + }); |
425 | + |
426 | + it('converts "Exposed" to "exposed"', function() { |
427 | + var converted = converter({Exposed: true}); |
428 | + assert.isTrue('exposed' in converted); |
429 | + assert.isTrue(converted.exposed); |
430 | + }); |
431 | + |
432 | + }); |
433 | + |
434 | +})(); |
435 | + |
436 | +(function() { |
437 | + |
438 | + describe('Go Juju environment unit entity converter', function() { |
439 | + var environments, utils, Y, converter, entityInfoConverters; |
440 | + |
441 | + before(function(done) { |
442 | + Y = YUI(GlobalConfig).use(['juju-env', 'juju-tests-utils'], function(Y) { |
443 | + environments = Y.namespace('juju.environments'); |
444 | + utils = Y.namespace('juju-tests.utils'); |
445 | + converter = environments.entityInfoConverters.unit; |
446 | + entityInfoConverters = environments.entityInfoConverters; |
447 | + done(); |
448 | + }); |
449 | + }); |
450 | + |
451 | + |
452 | + it('exists', function() { |
453 | + assert.isTrue('unit' in entityInfoConverters); |
454 | + }); |
455 | + |
456 | + it('converts "Name" to "id"', function() { |
457 | + var converted = converter({Name: 'unit name'}); |
458 | + assert.isTrue('id' in converted); |
459 | + assert.equal('unit name', converted.id); |
460 | + }); |
461 | + |
462 | + it('converts "Service" to "service"', function() { |
463 | + var converted = converter({Service: 'a service'}); |
464 | + assert.isTrue('service' in converted); |
465 | + assert.equal('a service', converted.service); |
466 | + }); |
467 | + |
468 | + }); |
469 | + |
470 | +})(); |
471 | + |
472 | +(function() { |
473 | + |
474 | + describe('Go Juju environment relation entity converter', function() { |
475 | + var environments, utils, Y, converter, entityInfoConverters; |
476 | + |
477 | + before(function(done) { |
478 | + Y = YUI(GlobalConfig).use(['juju-env', 'juju-tests-utils'], function(Y) { |
479 | + environments = Y.namespace('juju.environments'); |
480 | + utils = Y.namespace('juju-tests.utils'); |
481 | + converter = environments.entityInfoConverters.relation; |
482 | + entityInfoConverters = environments.entityInfoConverters; |
483 | + done(); |
484 | + }); |
485 | + }); |
486 | + |
487 | + |
488 | + it('exists', function() { |
489 | + assert.isTrue('relation' in entityInfoConverters); |
490 | + }); |
491 | + |
492 | + it('converts "Name" to "id"', function() { |
493 | + var converted = converter({Key: 'relation name'}); |
494 | + assert.isTrue('id' in converted); |
495 | + assert.equal('relation name', converted.id); |
496 | + }); |
497 | + |
498 | + }); |
499 | + |
500 | +})(); |
501 | + |
502 | +(function() { |
503 | + |
504 | + describe('Go Juju environment machine entity converter', function() { |
505 | + var environments, utils, Y, converter, entityInfoConverters; |
506 | + |
507 | + before(function(done) { |
508 | + Y = YUI(GlobalConfig).use(['juju-env', 'juju-tests-utils'], function(Y) { |
509 | + environments = Y.namespace('juju.environments'); |
510 | + utils = Y.namespace('juju-tests.utils'); |
511 | + converter = environments.entityInfoConverters.machine; |
512 | + entityInfoConverters = environments.entityInfoConverters; |
513 | + done(); |
514 | + }); |
515 | + }); |
516 | + |
517 | + |
518 | + it('exists', function() { |
519 | + assert.isTrue('machine' in entityInfoConverters); |
520 | + }); |
521 | + |
522 | + it('converts "Id" to "id"', function() { |
523 | + var converted = converter({Id: 'machine ID'}); |
524 | + assert.isTrue('id' in converted); |
525 | + assert.equal('machine ID', converted.id); |
526 | + }); |
527 | + |
528 | + it('converts "InstanceId" to "instance_id"', function() { |
529 | + var converted = converter({InstanceId: 'instance ID'}); |
530 | + assert.isTrue('instance_id' in converted); |
531 | + assert.equal('instance ID', converted.instance_id); |
532 | + }); |
533 | + |
534 | }); |
535 | |
536 | })(); |
537 | |
538 | === modified file 'test/utils.js' |
539 | --- test/utils.js 2013-03-21 21:17:03 +0000 |
540 | +++ test/utils.js 2013-03-26 12:15:49 +0000 |
541 | @@ -10,7 +10,6 @@ |
542 | this.messages = []; |
543 | |
544 | this.close = function() { |
545 | - //console.log('close stub'); |
546 | this.messages = []; |
547 | }; |
548 | |
549 | @@ -24,16 +23,17 @@ |
550 | }; |
551 | |
552 | this.msg = function(m) { |
553 | - //console.log('serializing env msg', m); |
554 | this.onmessage({'data': Y.JSON.stringify(m)}); |
555 | }; |
556 | |
557 | - this.last_message = function(m) { |
558 | - return this.messages[this.messages.length - 1]; |
559 | + this.last_message = function(back) { |
560 | + if (!back) { |
561 | + back = 1; |
562 | + } |
563 | + return this.messages[this.messages.length - back]; |
564 | }; |
565 | |
566 | this.send = function(m) { |
567 | - //console.log('socket send', m); |
568 | this.messages.push(Y.JSON.parse(m)); |
569 | }; |
570 | |
571 | |
572 | === modified file 'undocumented' |
573 | --- undocumented 2013-03-12 11:16:32 +0000 |
574 | +++ undocumented 2013-03-26 12:15:49 +0000 |
575 | @@ -12,7 +12,6 @@ |
576 | app/store/env/python.js:94 "_dispatch_rpc_result" |
577 | app/store/env/python.js:195 "get_service" |
578 | app/store/env/python.js:86 "_dispatch_event" |
579 | -app/store/env/python.js:371 "get_endpoints" |
580 | app/store/env/python.js:191 "get_charm" |
581 | app/store/env/base.js:53 "destructor" |
582 | app/store/env/base.js:38 "initializer" |
LGTM thanks! 'land with changes' I would like to see the two tests
mentioned below switched to use done() and then just take a look at the
one which isn't async but possibly should be?
Thanks again!
https:/ /codereview. appspot. com/7783050/ diff/1/ app/store/ env/go. js
File app/store/env/go.js (right):
https:/ /codereview. appspot. com/7783050/ diff/1/ app/store/ env/go. js#newcode77 env/go. js:77: instance_id: entityInfo. InstanceId // XXX and
app/store/
more stuff
Can this be camelCased?
https:/ /codereview. appspot. com/7783050/ diff/1/ test/test_ env_go. js
File test/test_env_go.js (right):
https:/ /codereview. appspot. com/7783050/ diff/1/ test/test_ env_go. js#newcode58 env_go. js:58: assert. isTrue( loginFired) ;
test/test_
Last night I did some reading on the best approach to this and I think
that using the done() method is the best way. This way could potentially
have a race condition causing the test to fail.
see: http:// visionmedia. github. com/mocha/ #asynchronous- code
https:/ /codereview. appspot. com/7783050/ diff/1/ test/test_ env_go. js#newcode72 env_go. js:72: assert. isTrue( loginFired) ;
test/test_
see done() above
https:/ /codereview. appspot. com/7783050/ diff/1/ test/test_ env_go. js#newcode85 env_go. js:85: conn.msg( {RequestId: 1, Response: {}});
test/test_
conn.msg() is async above but not here?
https:/ /codereview. appspot. com/7783050/ diff/1/ test/utils. js
File test/utils.js (right):
https:/ /codereview. appspot. com/7783050/ diff/1/ test/utils. js#newcode30
test/utils.js:30: if (!back) {
just FYI - another commonly used convention is
back = back || 1;
https:/ /codereview. appspot. com/7783050/