Merge lp:~hatch/juju-gui/auth-routes into lp:juju-gui/experimental
- auth-routes
- Merge into trunk
Status: | Merged |
---|---|
Merged at revision: | 662 |
Proposed branch: | lp:~hatch/juju-gui/auth-routes |
Merge into: | lp:juju-gui/experimental |
Diff against target: |
927 lines (+207/-176) 13 files modified
app/app.js (+37/-44) app/index.html (+1/-1) app/store/env/go.js (+1/-1) app/store/env/python.js (+1/-0) docs/unit-testing.rst (+20/-0) lib/views/stylesheet.less (+2/-1) test/index.html (+1/-0) test/test_app.js (+101/-111) test/test_app_hotkeys.js (+3/-2) test/test_browser_charm_details.js (+14/-14) test/test_endpoints.js (+3/-1) test/test_env_go.js (+20/-1) test/test_notifications.js (+3/-0) |
To merge this branch: | bzr merge lp:~hatch/juju-gui/auth-routes |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Juju GUI Hackers | Pending | ||
Review via email: mp+163732@code.launchpad.net |
Commit message
Description of the change
Converted login/logout to use routes
Login/Logout is now controlled via the routing system
this caused a number of issues with the order of
operations for the auth system so I would love
another QA using all three back ends please.
Jeff Pihach (hatch) wrote : | # |
- 656. By Jeff Pihach
-
fixing tests
- 657. By Jeff Pihach
-
refactored app tests
- 658. By Jeff Pihach
-
lint
- 659. By Jeff Pihach
-
fixed go auth test
- 660. By Jeff Pihach
-
merged trunk
Jeff Pihach (hatch) wrote : | # |
Please take a look.
Benjamin Saller (bcsaller) wrote : | # |
QA Issues
1) Improv + large.json
2) View a service
3) Logout
4) Get /login/:gui:/... url resulting in a blank page
Need to clear the namespace on login/logout navigation
- 661. By Jeff Pihach
-
fixed namespace logout issue
Jeff Pihach (hatch) wrote : | # |
Please take a look.
Benjamin Saller (bcsaller) wrote : | # |
LGTM
We may want a note in HACKING about having to disable navigate for
testing as this happens quite a few places and people are likely to hit
it again.
- 662. By Jeff Pihach
-
added docs to outline unit testing issues
Jeff Pihach (hatch) wrote : | # |
Please take a look.
Madison Scott-Clary (makyo) wrote : | # |
Code LGTM - no QA for now, but might get to it later.
https:/
File app/app.js (right):
https:/
app/app.js:825: this.showRootVi
What does this mean for the story of getting pasted a link by a
coworker, then having to log in and losing the link? As long as this is
acceptable, cool.
https:/
app/app.js:875: @param {function} next callable for the next route Rin
the chain.
Revert.
https:/
File test/test_app.js (right):
https:/
test/test_
Do we need this?
https:/
test/test_
successful login', function(done) {
Not a huge fan of the wording, since the 'it' is intended to be part of
the test name. However we haven't been sticking to this very well, so
I'll defer and create a card.
Jeff Pihach (hatch) wrote : | # |
Thanks for the reviews guys - I will await the QA from you Matt before I
merge just to be safe.
https:/
File app/app.js (right):
https:/
app/app.js:825: this.showRootVi
I was wondering the same - I have created a card to discuss Friday
https:/
app/app.js:875: @param {function} next callable for the next route Rin
the chain.
On 2013/05/14 23:24:54, matthew.scott wrote:
> Revert.
Done.
https:/
File test/test_app.js (right):
https:/
test/test_
Nope removed.
- 663. By Jeff Pihach
-
fixes from review
Jeff Pihach (hatch) wrote : | # |
Please take a look.
Jeff Pihach (hatch) wrote : | # |
*** Submitted:
Converted login/logout to use routes
Login/Logout is now controlled via the routing system
this caused a number of issues with the order of
operations for the auth system so I would love
another QA using all three back ends please.
R=bcsaller, matthew.scott
CC=
https:/
Preview Diff
1 | === modified file 'app/app.js' |
2 | --- app/app.js 2013-05-14 15:09:07 +0000 |
3 | +++ app/app.js 2013-05-15 00:00:36 +0000 |
4 | @@ -169,7 +169,7 @@ |
5 | }, |
6 | 'A-e': { |
7 | callback: function(evt) { |
8 | - this.fire('navigateTo', {url: '/:gui:/'}); |
9 | + this.fire('navigateTo', { url: '/:gui:/' }); |
10 | }, |
11 | help: 'Navigate to the Environment overview.' |
12 | }, |
13 | @@ -412,7 +412,6 @@ |
14 | if (credentials && credentials.areAvailable) { |
15 | this.env.login(); |
16 | } |
17 | - this.dispatch(); |
18 | } |
19 | }, this); |
20 | |
21 | @@ -456,6 +455,8 @@ |
22 | }, this); |
23 | } |
24 | |
25 | + Y.one('#logout-trigger').on('click', this.logout, this); |
26 | + |
27 | // Attach SubApplications |
28 | // The subapps should share the same db. |
29 | cfg.db = this.db; |
30 | @@ -563,8 +564,8 @@ |
31 | level: 'error' |
32 | }) |
33 | ); |
34 | - self.fire('navigateTo', {url: self.nsRouter.url( |
35 | - {gui: '/service/' + serviceId})}); |
36 | + self.navigate(self.nsRouter.url( |
37 | + {gui: '/service/' + serviceId})); |
38 | } |
39 | }, |
40 | // If there is no service available then there definitely is no unit |
41 | @@ -579,7 +580,7 @@ |
42 | level: 'error' |
43 | }) |
44 | ); |
45 | - self.fire('navigateTo', {url: self.nsRouter.url({gui: '/'})}); |
46 | + self.navigate(self.nsRouter.url({gui: '/'})); |
47 | }); |
48 | }, |
49 | |
50 | @@ -698,10 +699,10 @@ |
51 | /** |
52 | * Show the login screen. |
53 | * |
54 | - * @method show_login |
55 | + * @method showLogin |
56 | * @return {undefined} Nothing. |
57 | */ |
58 | - show_login: function() { |
59 | + showLogin: function() { |
60 | this.showView('login', { |
61 | env: this.env, |
62 | help_text: this.get('login_help') |
63 | @@ -721,11 +722,15 @@ |
64 | * @return {undefined} Nothing. |
65 | */ |
66 | logout: function(req) { |
67 | + // Clears out the topology local database on log out |
68 | + // because we clear out the environment database as well. |
69 | + // The order of these is important because we need to tell |
70 | + // the env to log out after it's navigated to make sure that |
71 | + // it always shows the login screen |
72 | + this.views.environment.instance.topo.update(); |
73 | + this.navigate('/login/', { overrideAllNamespaces: true }); |
74 | this.env.logout(); |
75 | - this.show_login(); |
76 | - // This flag will trigger a URL reset in check_user_credentials as the |
77 | - // routing finishes. |
78 | - this.loggingOut = true; |
79 | + return; |
80 | }, |
81 | |
82 | // Persistent Views |
83 | @@ -755,13 +760,13 @@ |
84 | /** |
85 | * Ensure that the current user has authenticated. |
86 | * |
87 | - * @method check_user_credentials |
88 | + * @method checkUserCredentials |
89 | * @param {Object} req The request. |
90 | * @param {Object} res ??? |
91 | * @param {Object} next The next route handler. |
92 | * |
93 | */ |
94 | - check_user_credentials: function(req, res, next) { |
95 | + checkUserCredentials: function(req, res, next) { |
96 | // If the Juju environment is not connected, exit without letting the |
97 | // route dispatch proceed. On env connection change, the app will |
98 | // re-dispatch and this route callback will be executed again. |
99 | @@ -775,26 +780,12 @@ |
100 | // form was never shown - this handles that edge case. |
101 | var noCredentials = !(credentials && credentials.areAvailable); |
102 | if (noCredentials) { |
103 | - // If there are no stored credentials, the user is prompted for some. |
104 | - this.show_login(); |
105 | - } |
106 | - if (!this.env.userIsAuthenticated) { |
107 | - // If there has not been a successful login attempt, do not let the |
108 | - // route dispatch proceed. |
109 | - if (noCredentials && this.loggingOut) { |
110 | - // Handle logging out. |
111 | - this.loggingOut = false; |
112 | - this.showRootView(); |
113 | + // If there are no stored credentials redirect to the login page |
114 | + if (req.path !== '/login/') { |
115 | + this.navigate('/login/'); |
116 | + return; |
117 | } |
118 | - // At this point, there can be credentials available, but there has not |
119 | - // been a successful login attempt. Assuming this can happen only |
120 | - // at the beginning of the auth process, and that the auth process |
121 | - // always starts right after the environment is connected, we can just |
122 | - // return here, because the connectedChange subscriber should take |
123 | - // care of performing a login attempt. |
124 | - return; |
125 | } |
126 | - // The route dispatch can proceed if the user is authenticated. |
127 | next(); |
128 | }, |
129 | |
130 | @@ -830,17 +821,11 @@ |
131 | */ |
132 | onLogin: function(evt) { |
133 | if (evt.data.result) { |
134 | - var mask = Y.one('#full-screen-mask'); |
135 | - if (mask) { |
136 | - mask.hide(); |
137 | - // Stop the animated loading spinner. |
138 | - if (spinner) { |
139 | - spinner.stop(); |
140 | - } |
141 | - } |
142 | - this.dispatch(); |
143 | + // Navigates to / overriding all namespaces |
144 | + this.showRootView(); |
145 | + return; |
146 | } else { |
147 | - this.show_login(); |
148 | + this.showLogin(); |
149 | } |
150 | }, |
151 | |
152 | @@ -928,6 +913,14 @@ |
153 | if (!this.renderEnvironment) { |
154 | next(); return; |
155 | } |
156 | + var mask = Y.one('#full-screen-mask'); |
157 | + if (mask) { |
158 | + mask.hide(); |
159 | + // Stop the animated loading spinner. |
160 | + if (spinner) { |
161 | + spinner.stop(); |
162 | + } |
163 | + } |
164 | var self = this, |
165 | view = this.getViewInfo('environment'), |
166 | options = { |
167 | @@ -1110,7 +1103,7 @@ |
168 | routes: { |
169 | value: [ |
170 | // Called on each request. |
171 | - { path: '*', callbacks: 'check_user_credentials'}, |
172 | + { path: '*', callbacks: 'checkUserCredentials'}, |
173 | { path: '*', callbacks: 'show_notifications_view'}, |
174 | { path: '*', callbacks: 'toggleStaticViews'}, |
175 | { path: '*', callbacks: 'show_environment'}, |
176 | @@ -1154,8 +1147,8 @@ |
177 | namespace: 'gui'}, |
178 | // Feature flags. |
179 | { path: '*', callbacks: 'featureFlags', namespace: 'flags' }, |
180 | - // Logout. |
181 | - { path: '/logout/', callbacks: 'logout'} |
182 | + // Authorization |
183 | + { path: '/login/', callbacks: 'showLogin' } |
184 | ] |
185 | } |
186 | } |
187 | |
188 | === modified file 'app/index.html' |
189 | --- app/index.html 2013-05-13 16:58:10 +0000 |
190 | +++ app/index.html 2013-05-15 00:00:36 +0000 |
191 | @@ -99,7 +99,7 @@ |
192 | </span> |
193 | <span class="nav-container"> |
194 | <span class="nav-section active-border"> |
195 | - <a href="/logout/" id="logout-trigger">Logout</a> |
196 | + <div id="logout-trigger">Logout</div> |
197 | </span> |
198 | </span> |
199 | <span class="nav-container" id="charm-search-trigger-container"> |
200 | |
201 | === modified file 'app/store/env/go.js' |
202 | --- app/store/env/go.js 2013-04-18 21:30:29 +0000 |
203 | +++ app/store/env/go.js 2013-05-15 00:00:36 +0000 |
204 | @@ -227,7 +227,7 @@ |
205 | /** |
206 | * React to the results of sending a login message to the server. |
207 | * |
208 | - * @method handleLoginEvent |
209 | + * @method handleLogin |
210 | * @param {Object} data The response returned by the server. |
211 | * @return {undefined} Nothing. |
212 | */ |
213 | |
214 | === modified file 'app/store/env/python.js' |
215 | --- app/store/env/python.js 2013-05-02 20:13:10 +0000 |
216 | +++ app/store/env/python.js 2013-05-15 00:00:36 +0000 |
217 | @@ -297,6 +297,7 @@ |
218 | login: function() { |
219 | // If the user is already authenticated there is nothing to do. |
220 | if (this.userIsAuthenticated) { |
221 | + this.fire('login', { data: { result: true }}); |
222 | return; |
223 | } |
224 | var credentials = this.getCredentials(); |
225 | |
226 | === added file 'docs/unit-testing.rst' |
227 | --- docs/unit-testing.rst 1970-01-01 00:00:00 +0000 |
228 | +++ docs/unit-testing.rst 2013-05-15 00:00:36 +0000 |
229 | @@ -0,0 +1,20 @@ |
230 | +========== |
231 | +Unit Tests |
232 | +========== |
233 | + |
234 | +The JUJU GUI project uses the `mocha.js`__ test framework for its unit tests. |
235 | +As the application complexity grows there are a number of 'gotchas' in the |
236 | +application which can result in huge headaches when trying to write or modify |
237 | +the unit tests. This document is the go-to resource to document these and should |
238 | +be read thoroughly before you modify or write additional tests. |
239 | + |
240 | +__ http://visionmedia.github.io/mocha/ |
241 | + |
242 | +noop app.navigate() when instantiating app |
243 | +------------------------------------------ |
244 | + |
245 | +Because the login system now automatically dispatches depending on the users |
246 | +credentials, saved or otherwise, navigate() needs to be noop'ed when |
247 | +instantiating app to stop it from navigating during tests:: |
248 | + |
249 | + app.navigate = function() {}; |
250 | |
251 | === modified file 'lib/views/stylesheet.less' |
252 | --- lib/views/stylesheet.less 2013-05-04 21:16:56 +0000 |
253 | +++ lib/views/stylesheet.less 2013-05-15 00:00:36 +0000 |
254 | @@ -149,6 +149,7 @@ |
255 | cursor: pointer; |
256 | } |
257 | #logout-trigger { |
258 | + cursor: pointer; |
259 | display: inline-block; |
260 | padding: 5px 0 8px 5px; |
261 | } |
262 | @@ -289,7 +290,7 @@ |
263 | padding: 1em; |
264 | .create-border-radius('black'); |
265 | .create-box-shadow(-2px 4px 4px 0 rgba(0, 0, 0, 0.5)); |
266 | - |
267 | + |
268 | background-color: black; |
269 | color: white; |
270 | |
271 | |
272 | === modified file 'test/index.html' |
273 | --- test/index.html 2013-05-10 23:25:01 +0000 |
274 | +++ test/index.html 2013-05-15 00:00:36 +0000 |
275 | @@ -109,6 +109,7 @@ |
276 | |
277 | <body> |
278 | <div id="shortcut-help" style="display: none"></div> |
279 | + <div id="logout-trigger" style="display: none"></div> |
280 | <div id="main" class="container"></div> |
281 | <div id="mocha"></div> |
282 | </body> |
283 | |
284 | === modified file 'test/test_app.js' |
285 | --- test/test_app.js 2013-05-06 00:49:09 +0000 |
286 | +++ test/test_app.js 2013-05-15 00:00:36 +0000 |
287 | @@ -38,7 +38,7 @@ |
288 | |
289 | before(function(done) { |
290 | Y = YUI(GlobalConfig).use( |
291 | - ['juju-gui', 'juju-tests-utils', 'juju-view-utils'], |
292 | + ['juju-gui', 'juju-tests-utils', 'juju-view-utils', 'juju-views'], |
293 | function(Y) { |
294 | utils = Y.namespace('juju-tests.utils'); |
295 | juju = Y.namespace('juju'); |
296 | @@ -56,70 +56,84 @@ |
297 | .append(Y.Node.create('<span/>') |
298 | .addClass('provider-type')) |
299 | .hide(); |
300 | - conn = new utils.SocketStub(); |
301 | - env = juju.newEnvironment({conn: conn}); |
302 | - env.connect(); |
303 | - app = new Y.juju.App({ |
304 | - container: container, |
305 | - viewContainer: container, |
306 | - env: env |
307 | + |
308 | + }); |
309 | + |
310 | + afterEach(function(done) { |
311 | + app.after('destroy', function() { |
312 | + container.remove(true); |
313 | + sessionStorage.setItem('credentials', null); |
314 | + done(); |
315 | }); |
316 | + |
317 | + app.destroy(); |
318 | + }); |
319 | + |
320 | + function constructAppInstance(config) { |
321 | + config = config || {}; |
322 | + if (config.env && config.env.connect) { |
323 | + config.env.connect(); |
324 | + } |
325 | + config.container = container; |
326 | + config.viewContainer = container; |
327 | + |
328 | + app = new Y.juju.App(config); |
329 | + app.navigate = function() {}; |
330 | app.showView(new Y.View()); |
331 | injectData(app); |
332 | - }); |
333 | - |
334 | - afterEach(function() { |
335 | - app.destroy(); |
336 | - container.remove(true); |
337 | - sessionStorage.setItem('credentials', null); |
338 | - }); |
339 | + return app; |
340 | + } |
341 | |
342 | it('should not have login credentials if missing from the configuration', |
343 | function() { |
344 | - app.render(); |
345 | + constructAppInstance({ |
346 | + env: juju.newEnvironment({ conn: new utils.SocketStub() }) |
347 | + }); |
348 | assert.equal(app.env.get('user'), undefined); |
349 | assert.equal(app.env.get('password'), undefined); |
350 | }); |
351 | |
352 | it('should propagate login credentials from the configuration', |
353 | - function() { |
354 | + function(done) { |
355 | var the_username = 'nehi'; |
356 | var the_password = 'moonpie'; |
357 | - // Replace the existing app. |
358 | - app.destroy(); |
359 | app = new Y.juju.App( |
360 | { container: container, |
361 | user: the_username, |
362 | password: the_password, |
363 | viewContainer: container, |
364 | conn: {close: function() {}}}); |
365 | - app.showView(new Y.View()); |
366 | - var credentials = app.env.getCredentials(); |
367 | - credentials.user.should.equal(the_username); |
368 | - credentials.password.should.equal(the_password); |
369 | + app.after('ready', function() { |
370 | + var credentials = app.env.getCredentials(); |
371 | + credentials.user.should.equal(the_username); |
372 | + credentials.password.should.equal(the_password); |
373 | + done(); |
374 | + }); |
375 | }); |
376 | |
377 | it('propagates the readOnly option from the configuration', function() { |
378 | - // Replace the existing app. |
379 | - app.destroy(); |
380 | app = new Y.juju.App({ |
381 | container: container, |
382 | readOnly: true, |
383 | viewContainer: container, |
384 | conn: {close: function() {}} |
385 | }); |
386 | - app.showView(new Y.View()); |
387 | assert.isTrue(app.env.get('readOnly')); |
388 | }); |
389 | |
390 | it('should produce a valid index', function() { |
391 | + constructAppInstance({ |
392 | + env: juju.newEnvironment({ conn: new utils.SocketStub() }) |
393 | + }); |
394 | var container = app.get('container'); |
395 | - app.render(); |
396 | container.getAttribute('id').should.equal('test-container'); |
397 | container.getAttribute('class').should.include('container'); |
398 | }); |
399 | |
400 | it('should be able to route objects to internal URLs', function() { |
401 | + constructAppInstance({ |
402 | + env: juju.newEnvironment({ conn: new utils.SocketStub() }) |
403 | + }); |
404 | // Take handles to database objects and ensure we can route to the view |
405 | // needed to show them. |
406 | var wordpress = app.db.services.getById('wordpress'), |
407 | @@ -145,13 +159,15 @@ |
408 | |
409 | it('should display the configured environment name', function() { |
410 | var environment_name = 'This is the environment name. Deal with it.'; |
411 | - app.destroy(); |
412 | - app = new Y.juju.App( |
413 | - { container: container, |
414 | - viewContainer: container, |
415 | - environment_name: environment_name, |
416 | - conn: {close: function() {}}}); |
417 | - app.showView(new Y.View()); |
418 | + constructAppInstance({ |
419 | + env: juju.newEnvironment({ |
420 | + conn: { |
421 | + send: function() {}, |
422 | + close: function() {} |
423 | + } |
424 | + }), |
425 | + environment_name: environment_name |
426 | + }); |
427 | assert.equal( |
428 | container.one('#environment-name').get('text'), |
429 | environment_name); |
430 | @@ -159,18 +175,23 @@ |
431 | |
432 | it('should show a generic environment name if none configured', |
433 | function() { |
434 | - app.destroy(); |
435 | - app = new Y.juju.App( |
436 | - { container: container, |
437 | - viewContainer: container, |
438 | - conn: {close: function() {}}}); |
439 | - app.showView(new Y.View()); |
440 | + constructAppInstance({ |
441 | + env: juju.newEnvironment({ |
442 | + conn: { |
443 | + send: function() {}, |
444 | + close: function() {} |
445 | + } |
446 | + }) |
447 | + }); |
448 | assert.equal( |
449 | container.one('#environment-name').get('text'), |
450 | 'Environment'); |
451 | }); |
452 | |
453 | it('should show the provider type, when available', function() { |
454 | + constructAppInstance({ |
455 | + env: juju.newEnvironment({ conn: new utils.SocketStub() }) |
456 | + }); |
457 | var providerType = 'excellent provider'; |
458 | // Since no provider type has been set yet, none is displayed. |
459 | assert.equal('', container.one('.provider-type').get('text')); |
460 | @@ -183,10 +204,13 @@ |
461 | }); |
462 | |
463 | it('hides the browser subapp on some urls', function() { |
464 | - var app = new Y.juju.App({ |
465 | - container: container, |
466 | - viewContainer: container, |
467 | - conn: {close: function() {}} |
468 | + constructAppInstance({ |
469 | + env: juju.newEnvironment({ |
470 | + conn: { |
471 | + send: function() {}, |
472 | + close: function() {} |
473 | + } |
474 | + }) |
475 | }); |
476 | |
477 | var checkUrls = [{ |
478 | @@ -215,7 +239,6 @@ |
479 | app.toggleStaticViews(req, undefined, next); |
480 | app.get('subApps').charmstore.hidden.should.eql(check.hidden); |
481 | }); |
482 | - app.destroy(); |
483 | }); |
484 | |
485 | }); |
486 | @@ -259,11 +282,17 @@ |
487 | }); |
488 | |
489 | // Create and return a new app. If connect is True, also connect the env. |
490 | - var makeApp = function(connect) { |
491 | - var app = new Y.juju.App({env: env, viewContainer: container}); |
492 | - var fakeView = new Y.View(); |
493 | - fakeView.name = FAKE_VIEW_NAME; |
494 | - app.showView(fakeView); |
495 | + var makeApp = function(connect, fakeview) { |
496 | + var app = new Y.juju.App({ |
497 | + env: env, |
498 | + viewContainer: container, |
499 | + consoleEnabled: true |
500 | + }); |
501 | + if (fakeview) { |
502 | + var fakeView = new Y.View(); |
503 | + fakeView.name = FAKE_VIEW_NAME; |
504 | + app.showView(fakeView); |
505 | + } |
506 | if (connect) { |
507 | env.connect(); |
508 | } |
509 | @@ -275,7 +304,6 @@ |
510 | var app = makeApp(false); // Create a disconnected app. |
511 | app.after('ready', function() { |
512 | assert.equal(0, conn.messages.length); |
513 | - assert.equal(FAKE_VIEW_NAME, app.get('activeView').name); |
514 | done(); |
515 | }); |
516 | }); |
517 | @@ -285,7 +313,6 @@ |
518 | app.after('ready', function() { |
519 | assert.equal(1, conn.messages.length); |
520 | assert.equal('login', conn.last_message().op); |
521 | - assert.equal(FAKE_VIEW_NAME, app.get('activeView').name); |
522 | done(); |
523 | }); |
524 | }); |
525 | @@ -293,9 +320,10 @@ |
526 | it('avoids trying to login without credentials', function(done) { |
527 | env.setCredentials(null); |
528 | var app = makeApp(true); // Create a connected app. |
529 | + app.navigate = function() { return; }; |
530 | app.after('ready', function() { |
531 | - assert.equal(0, conn.messages.length); |
532 | - assert.equal(LOGIN_VIEW_NAME, app.get('activeView').name); |
533 | + assert.equal(app.env.getCredentials(), null); |
534 | + assert.equal(conn.messages.length, 0); |
535 | done(); |
536 | }); |
537 | }); |
538 | @@ -312,40 +340,29 @@ |
539 | }); |
540 | }); |
541 | |
542 | - it('displays the env view if credentials are valid', function(done) { |
543 | - var app = makeApp(true); // Create a connected app. |
544 | - app.after('ready', function() { |
545 | - // Mimic a login successful response. |
546 | - conn.msg({op: 'login', result: true}); |
547 | - assert.equal(1, conn.messages.length); |
548 | - assert.equal('login', conn.last_message().op); |
549 | - assert.equal(ENV_VIEW_NAME, app.get('activeView').name); |
550 | + it('login method hanlder is called after successful login', function(done) { |
551 | + var oldOnLogin = Y.juju.App.onLogin; |
552 | + Y.juju.App.prototype.onLogin = function(e) { |
553 | + assert.equal(conn.messages.length, 1); |
554 | + assert.equal(conn.last_message().op, 'login'); |
555 | + assert.equal(e.data.result, true); |
556 | + Y.juju.App.onLogin = oldOnLogin; |
557 | done(); |
558 | - }); |
559 | + }; |
560 | + var app = new Y.juju.App({ env: env, viewContainer: container }); |
561 | + env.connect(); |
562 | + app.env.userIsAuthenticated = true; |
563 | + app.env.login(); |
564 | + app.destroy(true); |
565 | }); |
566 | |
567 | it('tries to log in on first connection', function(done) { |
568 | // This is the case when credential are stashed. |
569 | - var app = makeApp(false); // Create a disconnected app. |
570 | + var app = makeApp(true); // Create a disconnected app. |
571 | app.after('ready', function() { |
572 | - assert.equal(FAKE_VIEW_NAME, app.get('activeView').name); |
573 | env.connect(); |
574 | assert.equal(1, conn.messages.length); |
575 | assert.equal('login', conn.last_message().op); |
576 | - assert.equal(FAKE_VIEW_NAME, app.get('activeView').name); |
577 | - done(); |
578 | - }); |
579 | - }); |
580 | - |
581 | - it('displays the login view on first connection', function(done) { |
582 | - // This is the case when credential are not stashed. |
583 | - env.setCredentials(null); |
584 | - var app = makeApp(false); // Create a disconnected app. |
585 | - app.after('ready', function() { |
586 | - assert.equal(FAKE_VIEW_NAME, app.get('activeView').name); |
587 | - env.connect(); |
588 | - assert.equal(0, conn.messages.length); |
589 | - assert.equal(LOGIN_VIEW_NAME, app.get('activeView').name); |
590 | done(); |
591 | }); |
592 | }); |
593 | @@ -361,22 +378,6 @@ |
594 | Y.each(conn.messages, function(message) { |
595 | assert.equal('login', message.op); |
596 | }); |
597 | - assert.equal(FAKE_VIEW_NAME, app.get('activeView').name); |
598 | - done(); |
599 | - }); |
600 | - }); |
601 | - |
602 | - it('displays the login view on disconnections', function(done) { |
603 | - // This is the case when credential are not stashed. |
604 | - env.setCredentials(null); |
605 | - var app = makeApp(true); // Create a connected app. |
606 | - app.after('ready', function() { |
607 | - conn.msg({op: 'login', result: true}); |
608 | - assert.equal(ENV_VIEW_NAME, app.get('activeView').name); |
609 | - conn.transient_close(); |
610 | - conn.open(); |
611 | - assert.equal(0, conn.messages.length); |
612 | - assert.equal(LOGIN_VIEW_NAME, app.get('activeView').name); |
613 | done(); |
614 | }); |
615 | }); |
616 | @@ -388,20 +389,9 @@ |
617 | assert.equal(null, env.getCredentials()); |
618 | }); |
619 | |
620 | - it('displays the login view after logging out', function(done) { |
621 | - var app = makeApp(true); // Create a connected app. |
622 | - app.after('ready', function() { |
623 | - conn.msg({op: 'login', result: true}); |
624 | - assert.equal(ENV_VIEW_NAME, app.get('activeView').name); |
625 | - app.logout(); |
626 | - assert.equal(LOGIN_VIEW_NAME, app.get('activeView').name); |
627 | - done(); |
628 | - }); |
629 | - }); |
630 | }); |
631 | })(); |
632 | |
633 | - |
634 | (function() { |
635 | |
636 | describe('Application Connection State', function() { |
637 | @@ -418,7 +408,7 @@ |
638 | |
639 | it('should be able to handle env connection status changes', function() { |
640 | var juju = Y.namespace('juju'), |
641 | - conn = new(Y.namespace('juju-tests.utils')).SocketStub(), |
642 | + conn = new Y['juju-tests'].utils.SocketStub(), |
643 | env = juju.newEnvironment({ |
644 | conn: conn, |
645 | user: 'user', |
646 | @@ -460,18 +450,17 @@ |
647 | conn.open(); |
648 | // We need to fake the connection event. |
649 | reset_called.should.equal(true); |
650 | - dispatch_called.should.equal(true); |
651 | + //dispatch_called.should.equal(true); |
652 | login_called.should.equal(true); |
653 | |
654 | // Trigger a second time and verify. |
655 | conn.transient_close(); |
656 | reset_called = false; |
657 | - dispatch_called = false; |
658 | login_called = false; |
659 | conn.open(); |
660 | reset_called.should.equal(true); |
661 | - dispatch_called.should.equal(true); |
662 | - login_called.should.equal(true); |
663 | + //dispatch_called.should.equal(true); |
664 | + app.destroy(); |
665 | }); |
666 | |
667 | }); |
668 | @@ -621,3 +610,4 @@ |
669 | |
670 | }); |
671 | })(); |
672 | + |
673 | |
674 | === modified file 'test/test_app_hotkeys.js' |
675 | --- test/test_app_hotkeys.js 2013-05-06 16:18:15 +0000 |
676 | +++ test/test_app_hotkeys.js 2013-05-15 00:00:36 +0000 |
677 | @@ -59,7 +59,7 @@ |
678 | assert.equal(searchInput, Y.one(document.activeElement)); |
679 | }); |
680 | |
681 | - it('should listen for alt-E events', function() { |
682 | + it('should listen for alt-E events', function(done) { |
683 | var altEtriggered = false; |
684 | app.on('navigateTo', function(ev) { |
685 | if (ev && ev.url === '/:gui:/') { |
686 | @@ -67,12 +67,13 @@ |
687 | } |
688 | // Avoid URL change performed by additional listeners. |
689 | ev.stopImmediatePropagation(); |
690 | + assert.isTrue(altEtriggered); |
691 | + done(); |
692 | }); |
693 | windowNode.simulate('keydown', { |
694 | keyCode: 69, // "E" key. |
695 | altKey: true |
696 | }); |
697 | - assert.isTrue(altEtriggered); |
698 | }); |
699 | |
700 | }); |
701 | |
702 | === modified file 'test/test_browser_charm_details.js' |
703 | --- test/test_browser_charm_details.js 2013-05-13 18:43:47 +0000 |
704 | +++ test/test_browser_charm_details.js 2013-05-15 00:00:36 +0000 |
705 | @@ -286,7 +286,7 @@ |
706 | }); |
707 | |
708 | it('should display the config data in the config tab', function() { |
709 | - var view = new CharmView({ |
710 | + view = new CharmView({ |
711 | charm: new models.BrowserCharm({ |
712 | files: [], |
713 | id: 'precise/ceph-9', |
714 | @@ -310,7 +310,7 @@ |
715 | }); |
716 | |
717 | it('_buildQAData properly summerizes the scores', function() { |
718 | - var view = new CharmView({ |
719 | + view = new CharmView({ |
720 | charm: new models.BrowserCharm({ |
721 | files: [ |
722 | 'readme.md' |
723 | @@ -331,7 +331,7 @@ |
724 | }); |
725 | |
726 | it('qa content is loaded when the tab is clicked on', function(done) { |
727 | - var view = new CharmView({ |
728 | + view = new CharmView({ |
729 | charm: new models.BrowserCharm({ |
730 | files: [], |
731 | id: 'precise/ceph-9', |
732 | @@ -353,7 +353,7 @@ |
733 | }); |
734 | |
735 | it('does not blow up when the scores from the api is null', function() { |
736 | - var view = new CharmView({ |
737 | + view = new CharmView({ |
738 | charm: new models.BrowserCharm({ |
739 | files: [ |
740 | 'readme.md' |
741 | @@ -376,7 +376,7 @@ |
742 | Y.io('data/browsercharm.json', {sync: true}).responseText); |
743 | // We don't want any files so we don't have to mock/load them. |
744 | data.files = []; |
745 | - var view = new CharmView({ |
746 | + view = new CharmView({ |
747 | charm: new models.BrowserCharm(data), |
748 | container: Y.Node.create('<div class="charmview"/>') |
749 | }); |
750 | @@ -423,7 +423,7 @@ |
751 | } |
752 | } |
753 | }); |
754 | - var view = new CharmView({ |
755 | + view = new CharmView({ |
756 | charm: charm |
757 | }); |
758 | var interfaceIntro = view._getInterfaceIntroFlag( |
759 | @@ -444,7 +444,7 @@ |
760 | } |
761 | } |
762 | }); |
763 | - var view = new CharmView({ |
764 | + view = new CharmView({ |
765 | charm: charm |
766 | }); |
767 | var interfaceIntro = view._getInterfaceIntroFlag( |
768 | @@ -466,7 +466,7 @@ |
769 | } |
770 | } |
771 | }); |
772 | - var view = new CharmView({ |
773 | + view = new CharmView({ |
774 | charm: charm |
775 | }); |
776 | var interfaceIntro = view._getInterfaceIntroFlag( |
777 | @@ -487,7 +487,7 @@ |
778 | } |
779 | } |
780 | }); |
781 | - var view = new CharmView({ |
782 | + view = new CharmView({ |
783 | charm: charm |
784 | }); |
785 | var interfaceIntro = view._getInterfaceIntroFlag( |
786 | @@ -509,7 +509,7 @@ |
787 | } |
788 | } |
789 | }); |
790 | - var view = new CharmView({ |
791 | + view = new CharmView({ |
792 | charm: charm |
793 | }); |
794 | var interfaceIntro = view._getInterfaceIntroFlag( |
795 | @@ -532,7 +532,7 @@ |
796 | } |
797 | } |
798 | }); |
799 | - var view = new CharmView({ |
800 | + view = new CharmView({ |
801 | charm: charm |
802 | }); |
803 | var interfaceIntro = view._getInterfaceIntroFlag( |
804 | @@ -554,7 +554,7 @@ |
805 | } |
806 | } |
807 | }); |
808 | - var view = new CharmView({ |
809 | + view = new CharmView({ |
810 | charm: charm |
811 | }); |
812 | var interfaceIntro = view._getInterfaceIntroFlag( |
813 | @@ -577,7 +577,7 @@ |
814 | } |
815 | } |
816 | }); |
817 | - var view = new CharmView({ |
818 | + view = new CharmView({ |
819 | charm: charm |
820 | }); |
821 | var interfaceIntro = view._getInterfaceIntroFlag( |
822 | @@ -601,7 +601,7 @@ |
823 | } |
824 | } |
825 | }); |
826 | - var view = new CharmView({ |
827 | + view = new CharmView({ |
828 | charm: charm |
829 | }); |
830 | var interfaceIntro = view._getInterfaceIntroFlag( |
831 | |
832 | === modified file 'test/test_endpoints.js' |
833 | --- test/test_endpoints.js 2013-05-03 16:18:41 +0000 |
834 | +++ test/test_endpoints.js 2013-05-15 00:00:36 +0000 |
835 | @@ -20,7 +20,8 @@ |
836 | |
837 | |
838 | beforeEach(function(done) { |
839 | - Y = YUI(GlobalConfig).use(['juju-models', |
840 | + Y = YUI(GlobalConfig).use(['juju-views', |
841 | + 'juju-models', |
842 | 'juju-gui', |
843 | 'juju-tests-utils', |
844 | 'juju-controllers'], |
845 | @@ -32,6 +33,7 @@ |
846 | env = juju.newEnvironment({conn: conn}); |
847 | env.connect(); |
848 | app = new Y.juju.App({env: env}); |
849 | + app.navigate = function() { return true; }; |
850 | app.showView(new Y.View()); |
851 | db = app.db; |
852 | db.onDelta({data: {'op': 'delta', result: sample_env}}); |
853 | |
854 | === modified file 'test/test_env_go.js' |
855 | --- test/test_env_go.js 2013-04-19 16:09:42 +0000 |
856 | +++ test/test_env_go.js 2013-05-15 00:00:36 +0000 |
857 | @@ -63,7 +63,7 @@ |
858 | }); |
859 | |
860 | describe('Go Juju environment', function() { |
861 | - var conn, endpointA, endpointB, env, juju, msg, utils, Y; |
862 | + var conn, endpointA, endpointB, env, juju, msg, utils, Y, oldHandleLogin; |
863 | |
864 | before(function(done) { |
865 | Y = YUI(GlobalConfig).use(['juju-env', 'juju-tests-utils'], function(Y) { |
866 | @@ -85,7 +85,25 @@ |
867 | env.destroy(); |
868 | }); |
869 | |
870 | + var noopHandleLogin = function() { |
871 | + // In order to avoid rewriting all of these go tests we need to destroy |
872 | + // the env created in the beforeEach |
873 | + env.destroy(); |
874 | + oldHandleLogin = Y.juju.environments.GoEnvironment.handleLogin; |
875 | + Y.juju.environments.GoEnvironment.handleLogin = function() {}; |
876 | + conn = new utils.SocketStub(); |
877 | + env = juju.newEnvironment({ |
878 | + conn: conn, user: 'user', password: 'password' |
879 | + }, 'go'); |
880 | + env.connect(); |
881 | + }; |
882 | + |
883 | + var resetHandleLogin = function() { |
884 | + Y.juju.environments.GoEnvironment.handleLogin = oldHandleLogin; |
885 | + }; |
886 | + |
887 | it('sends the correct login message', function() { |
888 | + noopHandleLogin(); |
889 | env.login(); |
890 | var last_message = conn.last_message(); |
891 | var expected = { |
892 | @@ -95,6 +113,7 @@ |
893 | Params: {AuthTag: 'user', Password: 'password'} |
894 | }; |
895 | assert.deepEqual(expected, last_message); |
896 | + resetHandleLogin(); |
897 | }); |
898 | |
899 | it('resets the user and password if they are not valid', function() { |
900 | |
901 | === modified file 'test/test_notifications.js' |
902 | --- test/test_notifications.js 2013-04-08 18:23:28 +0000 |
903 | +++ test/test_notifications.js 2013-05-15 00:00:36 +0000 |
904 | @@ -205,6 +205,7 @@ |
905 | app: app, |
906 | env: env, |
907 | nsRouter: nsRouter}).render(); |
908 | + app.navigate = function() { return; }; |
909 | app.showView(new Y.View()); |
910 | // We use overview here for testing as it defaults |
911 | // to showing all notices. |
912 | @@ -244,6 +245,7 @@ |
913 | container: container, |
914 | viewContainer: container |
915 | }); |
916 | + app.navigate = function() { return; }; |
917 | app.showView(new Y.View()); |
918 | env.connect(); |
919 | var environment_delta = default_env; |
920 | @@ -288,6 +290,7 @@ |
921 | container: container, |
922 | viewContainer: container |
923 | }); |
924 | + app.navigate = function() { return; }; |
925 | app.showView(new Y.View()); |
926 | var environment_delta = { |
927 | 'result': [ |
Reviewers: mp+163732_ code.launchpad. net,
Message:
Please take a look.
Description:
Converted login/logout to use routes
Login/Logout is now controlled via the routing system
this caused a number of issues with the order of
operations for the auth system so I would love
another QA using all three back ends please.
https:/ /code.launchpad .net/~hatch/ juju-gui/ auth-routes/ +merge/ 163732
(do not edit description out of merge proposal)
Please review this at https:/ /codereview. appspot. com/9415043/
Affected files: env/python. js app_hotkeys. js endpoints. js notifications. js
A [revision details]
M app/app.js
M app/config-debug.js
M app/index.html
M app/store/env/go.js
M app/store/
M test/index.html
M test/test_app.js
M test/test_
M test/test_
M test/test_env_go.js
M test/test_