Merge lp:~jcsackett/juju-gui/remove-charm-extension-in-browser-charm into lp:juju-gui/experimental
- remove-charm-extension-in-browser-charm
- Merge into trunk
Status: | Merged | ||||
---|---|---|---|---|---|
Merged at revision: | 933 | ||||
Proposed branch: | lp:~jcsackett/juju-gui/remove-charm-extension-in-browser-charm | ||||
Merge into: | lp:juju-gui/experimental | ||||
Diff against target: |
551 lines (+375/-91) 2 files modified
app/models/charm.js (+112/-5) test/test_model.js (+263/-86) |
||||
To merge this branch: | bzr merge lp:~jcsackett/juju-gui/remove-charm-extension-in-browser-charm | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Juju GUI Hackers | Pending | ||
Review via email: mp+179005@code.launchpad.net |
Commit message
Description of the change
Removes Charm extension from BrowserCharm
In order to be able to safely remove Charm, BrowserCharm cannot extend it.
-BrowserCharm now extends Model
-BrowserCharm now supports the initialization functions that Charm does (e.g.
setting attr from the provided ID)
-BrowserCharm now has the same `load` pipeline functions (e.g. `sync`)
-Tests have been updated or added to demonstrate new support
-Drive by test cleanup--there were many tests that checked the same exact
things; I've merged these to mitigate the damage from some of the test
repetition I've had to temporarily add.
j.c.sackett (jcsackett) wrote : | # |
Richard Harding (rharding) wrote : | # |
LGTM getting closer!
https:/
File app/models/charm.js (right):
https:/
app/models/
data.options) {
space after the !
Madison Scott-Clary (makyo) wrote : | # |
LGTM, thanks!
- 935. By j.c.sackett
-
Merged trunk.
- 936. By j.c.sackett
-
Change from review.
j.c.sackett (jcsackett) wrote : | # |
*** Submitted:
Removes Charm extension from BrowserCharm
In order to be able to safely remove Charm, BrowserCharm cannot extend
it.
-BrowserCharm now extends Model
-BrowserCharm now supports the initialization functions that Charm does
(e.g.
setting attr from the provided ID)
-BrowserCharm now has the same `load` pipeline functions (e.g. `sync`)
-Tests have been updated or added to demonstrate new support
-Drive by test cleanup--there were many tests that checked the same
exact
things; I've merged these to mitigate the damage from some of the test
repetition I've had to temporarily add.
R=rharding, matthew.scott
CC=
https:/
Preview Diff
1 | === modified file 'app/models/charm.js' |
2 | --- app/models/charm.js 2013-07-31 20:15:56 +0000 |
3 | +++ app/models/charm.js 2013-08-07 21:02:27 +0000 |
4 | @@ -216,7 +216,7 @@ |
5 | data.is_subordinate = data.subordinate || data.is_subordinate; |
6 | // Because the old and new charm models have different places for |
7 | // the options data, this handles the normalization. |
8 | - if (data.config && data.config.options && ! data.options) { |
9 | + if (data.config && data.config.options && !data.options) { |
10 | data.options = data.config.options; |
11 | delete data.config; |
12 | } |
13 | @@ -397,10 +397,10 @@ |
14 | * Model to represent the Charms from the Charmworld2 Api. |
15 | * |
16 | * @class BrowserCharm |
17 | - * @extends {Charm} |
18 | + * @extends {Y.Model} |
19 | * |
20 | */ |
21 | - models.BrowserCharm = Y.Base.create('browser-charm', Charm, [], { |
22 | + models.BrowserCharm = Y.Base.create('browser-charm', Y.Model, [], { |
23 | // Only care about at most, this number of related charms per interface. |
24 | maxRelatedCharms: 5, |
25 | |
26 | @@ -486,8 +486,94 @@ |
27 | } |
28 | if (cfg.id) { |
29 | this.set('storeId', cfg.id); |
30 | - this.set('id', this.get('scheme') + ':' + cfg.id); |
31 | - } |
32 | + } |
33 | + if (cfg.url) { |
34 | + this.set('id', cfg.url); |
35 | + } |
36 | + } |
37 | + var id = this.get('id'), |
38 | + parts = parseCharmId(id), |
39 | + self = this; |
40 | + if (!parts) { |
41 | + throw 'Developers must initialize charms with a well-formed id.'; |
42 | + } |
43 | + this.loaded = false; |
44 | + this.on('load', function() { this.loaded = true; }); |
45 | + Y.Object.each(parts, function(value, key) { |
46 | + this.set(key, value); |
47 | + }, this); |
48 | + }, |
49 | + |
50 | + sync: function(action, options, callback) { |
51 | + if (action !== 'read') { |
52 | + throw ( |
53 | + 'Only use the "read" action; "' + action + '" not supported.'); |
54 | + } |
55 | + if (Y.Lang.isValue(options.get_charm)) { |
56 | + // This is an env. |
57 | + options.get_charm(this.get('id'), function(response) { |
58 | + if (response.err) { |
59 | + callback(true, response); |
60 | + } else if (response.result) { |
61 | + callback(false, response.result); |
62 | + } else { |
63 | + // What's going on? This does not look like either of our |
64 | + // expected signatures. Declare a loading error. |
65 | + callback(true, response); |
66 | + } |
67 | + }); |
68 | + } else { |
69 | + throw 'You must supply a get_charm function.'; |
70 | + } |
71 | + }, |
72 | + |
73 | + parse: function(response) { |
74 | + var data = Charm.superclass.parse.apply(this, arguments), |
75 | + self = this; |
76 | + |
77 | + // TODO (gary): verify whether is_subordinate is ever passed by pyjuju |
78 | + // or juju core. If not, remove the "|| data.is_subordinate" and change |
79 | + // in the fakebackend and/or sandbox to send the expected thing there. |
80 | + data.is_subordinate = data.subordinate || data.is_subordinate; |
81 | + // Because the old and new charm models have different places for |
82 | + // the options data, this handles the normalization. |
83 | + if (data.config && data.config.options && !data.options) { |
84 | + data.options = data.config.options; |
85 | + delete data.config; |
86 | + } |
87 | + Y.each(data, function(value, key) { |
88 | + if (!Y.Lang.isValue(value) || |
89 | + !self.attrAdded(key) || |
90 | + Y.Lang.isValue(self.get(key))) { |
91 | + delete data[key]; |
92 | + } |
93 | + }); |
94 | + if (data.owner === 'charmers') { |
95 | + delete data.owner; |
96 | + } |
97 | + return data; |
98 | + }, |
99 | + |
100 | + compare: function(other, relevance, otherRelevance) { |
101 | + // Official charms sort before owned charms. |
102 | + // If !X.owner, that means it is owned by charmers. |
103 | + var owner = this.get('owner'), |
104 | + otherOwner = other.get('owner'); |
105 | + if (!owner && otherOwner) { |
106 | + return -1; |
107 | + } else if (owner && !otherOwner) { |
108 | + return 1; |
109 | + // Relevance is next most important. |
110 | + } else if (relevance && (relevance !== otherRelevance)) { |
111 | + // Higher relevance comes first. |
112 | + return otherRelevance - relevance; |
113 | + // Otherwise sort by package name, then by owner, then by revision. |
114 | + } else { |
115 | + return ( |
116 | + (this.get('package_name').localeCompare( |
117 | + other.get('package_name'))) || |
118 | + (owner ? owner.localeCompare(otherOwner) : 0) || |
119 | + (this.get('revision') - other.get('revision'))); |
120 | } |
121 | }, |
122 | |
123 | @@ -562,6 +648,27 @@ |
124 | changelog: { |
125 | value: {} |
126 | }, |
127 | + //XXX jcsackett Aug 7 2013 This attribute is only needed until we turn |
128 | + // on the service inspector. It's just used by the charm view you get when |
129 | + // inspecting a service, and should be ripped out (along with tests) when |
130 | + // we remove that view. |
131 | + charm_path: { |
132 | + /** |
133 | + * Generate the charm store path from the attributes of the charm. |
134 | + * |
135 | + * @method getter |
136 | + * |
137 | + */ |
138 | + getter: function() { |
139 | + var owner = this.get('owner'); |
140 | + return [ |
141 | + (owner ? '~' + owner : 'charms'), |
142 | + this.get('series'), |
143 | + (this.get('package_name') + '-' + this.get('revision')), |
144 | + 'json' |
145 | + ].join('/'); |
146 | + } |
147 | + }, |
148 | /** |
149 | * Object of data about the source for this charm including bugs link, |
150 | * log, revisions, etc. |
151 | |
152 | === modified file 'test/test_model.js' |
153 | --- test/test_model.js 2013-07-31 20:15:56 +0000 |
154 | +++ test/test_model.js 2013-08-07 21:02:27 +0000 |
155 | @@ -16,10 +16,9 @@ |
156 | with this program. If not, see <http://www.gnu.org/licenses/>. |
157 | */ |
158 | |
159 | - |
160 | 'use strict'; |
161 | |
162 | -describe('charm normalization', function() { |
163 | +describe('Charm and BrowserCharm initialization', function() { |
164 | var models; |
165 | |
166 | before(function(done) { |
167 | @@ -29,19 +28,101 @@ |
168 | }); |
169 | }); |
170 | |
171 | - it('must create derived attributes from official charm id', function() { |
172 | + it('must be able to create Charm', function() { |
173 | var charm = new models.Charm( |
174 | - {id: 'cs:precise/openstack-dashboard-0'}); |
175 | - charm.get('scheme').should.equal('cs'); |
176 | - var _ = expect(charm.get('owner')).to.not.exist; |
177 | - charm.get('full_name').should.equal('precise/openstack-dashboard'); |
178 | - charm.get('charm_path').should.equal( |
179 | - 'charms/precise/openstack-dashboard-0/json'); |
180 | + {id: 'cs:~alt-bac/precise/openstack-dashboard-0'}); |
181 | + charm.get('scheme').should.equal('cs'); |
182 | + charm.get('owner').should.equal('alt-bac'); |
183 | + charm.get('series').should.equal('precise'); |
184 | + charm.get('package_name').should.equal('openstack-dashboard'); |
185 | + charm.get('revision').should.equal(0); |
186 | + charm.get('full_name').should.equal( |
187 | + '~alt-bac/precise/openstack-dashboard'); |
188 | + charm.get('charm_path').should.equal( |
189 | + '~alt-bac/precise/openstack-dashboard-0/json'); |
190 | + }); |
191 | + |
192 | + it('must be able to create BrowserCharm', function() { |
193 | + var charm = new models.BrowserCharm( |
194 | + {id: 'cs:~alt-bac/precise/openstack-dashboard-0'}); |
195 | + charm.get('scheme').should.equal('cs'); |
196 | + charm.get('owner').should.equal('alt-bac'); |
197 | + charm.get('series').should.equal('precise'); |
198 | + charm.get('package_name').should.equal('openstack-dashboard'); |
199 | + charm.get('revision').should.equal(0); |
200 | + charm.get('full_name').should.equal( |
201 | + '~alt-bac/precise/openstack-dashboard'); |
202 | + charm.get('charm_path').should.equal( |
203 | + '~alt-bac/precise/openstack-dashboard-0/json'); |
204 | + }); |
205 | + |
206 | + it('must not set "owner" for promulgated charms', function() { |
207 | + var charm; |
208 | + charm = new models.Charm({id: 'cs:precise/openstack-dashboard-0'}); |
209 | + assert.isUndefined(charm.get('owner')); |
210 | + |
211 | + charm = new models.BrowserCharm({ |
212 | + id: 'cs:precise/openstack-dashboard-0' |
213 | + }); |
214 | + assert.isUndefined(charm.get('owner')); |
215 | + }); |
216 | + |
217 | + it('must be able to parse hyphenated owner names', function() { |
218 | + // Note that an earlier version of the parsing code did not handle |
219 | + // hyphens in user names, so this test intentionally includes one. |
220 | + var charm; |
221 | + charm = new models.Charm( |
222 | + {id: 'cs:~marco-ceppi/precise/wordpress-17'}); |
223 | + charm.get('full_name').should.equal('~marco-ceppi/precise/wordpress'); |
224 | + |
225 | + charm = new models.BrowserCharm( |
226 | + {id: 'cs:~marco-ceppi/precise/wordpress-17'}); |
227 | + charm.get('full_name').should.equal('~marco-ceppi/precise/wordpress'); |
228 | + }); |
229 | + |
230 | + it('must reject bad charm ids.', function() { |
231 | + var charm; |
232 | + try { |
233 | + charm = new models.Charm({id: 'foobar'}); |
234 | + assert.fail('Should have thrown an error'); |
235 | + } catch (e) { |
236 | + e.should.equal( |
237 | + 'Developers must initialize charms with a well-formed id.'); |
238 | + } |
239 | + |
240 | + try { |
241 | + charm = new models.BrowserCharm({id: 'foobar'}); |
242 | + assert.fail('Should have thrown an error'); |
243 | + } catch (e) { |
244 | + e.should.equal( |
245 | + 'Developers must initialize charms with a well-formed id.'); |
246 | + } |
247 | + }); |
248 | + |
249 | + |
250 | + it('must reject missing charm ids at initialization.', function() { |
251 | + var charm; |
252 | + try { |
253 | + charm = new models.Charm(); |
254 | + assert.fail('Should have thrown an error'); |
255 | + } catch (e) { |
256 | + e.should.equal( |
257 | + 'Developers must initialize charms with a well-formed id.'); |
258 | + } |
259 | + |
260 | + try { |
261 | + charm = new models.BrowserCharm(); |
262 | + assert.fail('Should have thrown an error'); |
263 | + } catch (e) { |
264 | + e.should.equal( |
265 | + 'Developers must initialize charms with a well-formed id.'); |
266 | + } |
267 | }); |
268 | |
269 | it('can load options from both "options" and "config"', function() { |
270 | - var options = {foo: 'bar'}; |
271 | - var charm = new models.Charm({ |
272 | + var options = {foo: 'bar'}, |
273 | + charm; |
274 | + charm = new models.Charm({ |
275 | id: 'cs:precise/openstack-dashboard-0', |
276 | options: options |
277 | }); |
278 | @@ -55,7 +136,7 @@ |
279 | assert.equal(charm.get('options'), options); |
280 | }); |
281 | |
282 | - it('must convert timestamps into time objects', function() { |
283 | + it('must convert timestamps into time objects on Charm', function() { |
284 | var time = 1349797266.032, |
285 | date = new Date(time), |
286 | charm = new models.Charm( |
287 | @@ -63,6 +144,13 @@ |
288 | charm.get('last_change').created.should.eql(date); |
289 | }); |
290 | |
291 | + it('must convert timestamps into time objects on BrowserCharm', function() { |
292 | + var time = 1349797266.032, |
293 | + date = new Date(time), |
294 | + charm = new models.BrowserCharm( |
295 | + { id: 'cs:precise/foo-9', last_change: {created: time / 1000} }); |
296 | + charm.get('last_change').created.should.eql(date); |
297 | + }); |
298 | }); |
299 | |
300 | describe('juju models', function() { |
301 | @@ -79,79 +167,6 @@ |
302 | window._gaq = []; |
303 | }); |
304 | |
305 | - it('must be able to create charm', function() { |
306 | - var charm = new models.Charm( |
307 | - {id: 'cs:~alt-bac/precise/openstack-dashboard-0'}); |
308 | - charm.get('scheme').should.equal('cs'); |
309 | - charm.get('owner').should.equal('alt-bac'); |
310 | - charm.get('series').should.equal('precise'); |
311 | - charm.get('package_name').should.equal('openstack-dashboard'); |
312 | - charm.get('revision').should.equal(0); |
313 | - charm.get('full_name').should.equal( |
314 | - '~alt-bac/precise/openstack-dashboard'); |
315 | - charm.get('charm_path').should.equal( |
316 | - '~alt-bac/precise/openstack-dashboard-0/json'); |
317 | - }); |
318 | - |
319 | - it('must be able to parse real-world charm names', function() { |
320 | - var charm = new models.Charm({id: 'cs:precise/openstack-dashboard-0'}); |
321 | - charm.get('full_name').should.equal('precise/openstack-dashboard'); |
322 | - charm.get('package_name').should.equal('openstack-dashboard'); |
323 | - charm.get('charm_path').should.equal( |
324 | - 'charms/precise/openstack-dashboard-0/json'); |
325 | - charm.get('scheme').should.equal('cs'); |
326 | - var _ = expect(charm.get('owner')).to.not.exist; |
327 | - charm.get('series').should.equal('precise'); |
328 | - charm.get('package_name').should.equal('openstack-dashboard'); |
329 | - charm.get('revision').should.equal(0); |
330 | - }); |
331 | - |
332 | - it('must be able to parse individually owned charms', function() { |
333 | - // Note that an earlier version of the parsing code did not handle |
334 | - // hyphens in user names, so this test intentionally includes one. |
335 | - var charm = new models.Charm( |
336 | - {id: 'cs:~marco-ceppi/precise/wordpress-17'}); |
337 | - charm.get('full_name').should.equal('~marco-ceppi/precise/wordpress'); |
338 | - charm.get('package_name').should.equal('wordpress'); |
339 | - charm.get('charm_path').should.equal( |
340 | - '~marco-ceppi/precise/wordpress-17/json'); |
341 | - charm.get('revision').should.equal(17); |
342 | - }); |
343 | - |
344 | - it('must reject bad charm ids.', function() { |
345 | - try { |
346 | - var charm = new models.Charm({id: 'foobar'}); |
347 | - assert.fail('Should have thrown an error'); |
348 | - } catch (e) { |
349 | - e.should.equal( |
350 | - 'Developers must initialize charms with a well-formed id.'); |
351 | - } |
352 | - }); |
353 | - |
354 | - it('must reject missing charm ids at initialization.', function() { |
355 | - try { |
356 | - var charm = new models.Charm(); |
357 | - assert.fail('Should have thrown an error'); |
358 | - } catch (e) { |
359 | - e.should.equal( |
360 | - 'Developers must initialize charms with a well-formed id.'); |
361 | - } |
362 | - }); |
363 | - |
364 | - it('must be able to create charm list', function() { |
365 | - var c1 = new models.Charm( |
366 | - { id: 'cs:precise/mysql-2', |
367 | - description: 'A DB'}), |
368 | - c2 = new models.Charm( |
369 | - { id: 'cs:precise/logger-3', |
370 | - description: 'Log sub'}), |
371 | - clist = new models.CharmList(); |
372 | - clist.add([c1, c2]); |
373 | - var names = clist.map(function(c) {return c.get('package_name');}); |
374 | - names[0].should.equal('mysql'); |
375 | - names[1].should.equal('logger'); |
376 | - }); |
377 | - |
378 | it('service unit list should be able to get units of a given service', |
379 | function() { |
380 | var sl = new models.ServiceList(); |
381 | @@ -491,7 +506,169 @@ |
382 | }); |
383 | }); |
384 | |
385 | -describe('juju charm load', function() { |
386 | +// XXX jcsackett August 7 2013 This is a complete duplication of the next test |
387 | +// case, but we need to test independently for both models while we're merging |
388 | +// them. The Charm load suite below can be removed once the work is done. |
389 | +describe('BrowserCharm load', function() { |
390 | + var Y, models, conn, env, app, container, fakeStore, data, juju; |
391 | + |
392 | + before(function(done) { |
393 | + Y = YUI(GlobalConfig).use(['juju-models', 'juju-gui', 'datasource-local', |
394 | + 'juju-tests-utils', 'json-stringify', |
395 | + 'juju-charm-store'], function(Y) { |
396 | + models = Y.namespace('juju.models'); |
397 | + juju = Y.namespace('juju'); |
398 | + done(); |
399 | + }); |
400 | + }); |
401 | + |
402 | + beforeEach(function() { |
403 | + conn = new (Y.namespace('juju-tests.utils')).SocketStub(); |
404 | + env = juju.newEnvironment({conn: conn}); |
405 | + env.connect(); |
406 | + conn.open(); |
407 | + container = Y.Node.create('<div id="test" class="container"></div>'); |
408 | + data = []; |
409 | + fakeStore = new Y.juju.Charmworld2({}); |
410 | + fakeStore.set('datasource', { |
411 | + sendRequest: function(params) { |
412 | + params.callback.success({ |
413 | + response: { |
414 | + results: [{ |
415 | + responseText: data |
416 | + }] |
417 | + } |
418 | + }); |
419 | + } |
420 | + }); |
421 | + }); |
422 | + |
423 | + afterEach(function() { |
424 | + container.destroy(); |
425 | + }); |
426 | + |
427 | + it('will throw an exception with non-read sync', function() { |
428 | + var charm = new models.BrowserCharm({id: 'local:precise/foo-4'}); |
429 | + try { |
430 | + charm.sync('create'); |
431 | + assert.fail('Should have thrown an error'); |
432 | + } catch (e) { |
433 | + e.should.equal('Only use the "read" action; "create" not supported.'); |
434 | + } |
435 | + try { |
436 | + charm.sync('update'); |
437 | + assert.fail('Should have thrown an error'); |
438 | + } catch (e) { |
439 | + e.should.equal('Only use the "read" action; "update" not supported.'); |
440 | + } |
441 | + try { |
442 | + charm.sync('delete'); |
443 | + assert.fail('Should have thrown an error'); |
444 | + } catch (e) { |
445 | + e.should.equal('Only use the "read" action; "delete" not supported.'); |
446 | + } |
447 | + }); |
448 | + |
449 | + it('throws an error if you do not pass get_charm', |
450 | + function() { |
451 | + var charm = new models.BrowserCharm({id: 'local:precise/foo-4'}); |
452 | + try { |
453 | + charm.sync('read', {}); |
454 | + assert.fail('Should have thrown an error'); |
455 | + } catch (e) { |
456 | + e.should.equal( |
457 | + 'You must supply a get_charm function.'); |
458 | + } |
459 | + try { |
460 | + charm.sync('read', {env: 42}); |
461 | + assert.fail('Should have thrown an error'); |
462 | + } catch (e) { |
463 | + e.should.equal( |
464 | + 'You must supply a get_charm function.'); |
465 | + } |
466 | + }); |
467 | + |
468 | + it('must send request to juju environment for local charms', function() { |
469 | + var charm = new models.BrowserCharm({id: 'local:precise/foo-4'}).load(env); |
470 | + assert(!charm.loaded); |
471 | + conn.last_message().op.should.equal('get_charm'); |
472 | + }); |
473 | + |
474 | + it('must handle success from local charm request', function(done) { |
475 | + var charm = new models.BrowserCharm({id: 'local:precise/foo-4'}).load( |
476 | + env, |
477 | + function(err, response) { |
478 | + assert(!err); |
479 | + charm.get('summary').should.equal('wowza'); |
480 | + assert(charm.loaded); |
481 | + done(); |
482 | + }); |
483 | + var response = conn.last_message(); |
484 | + response.result = { summary: 'wowza' }; |
485 | + env.dispatch_result(response); |
486 | + // The test in the callback above should run. |
487 | + }); |
488 | + |
489 | + it('parses the old charm model options location correctly', function(done) { |
490 | + var charm = new models.BrowserCharm({id: 'local:precise/foo-4'}).load( |
491 | + env, |
492 | + function(err, response) { |
493 | + assert(!err); |
494 | + // This checks to make sure the parse mechanism is working properly |
495 | + // for both the old ane new charm browser. |
496 | + assert.equal(charm.get('options').default_log['default'], 'global'); |
497 | + done(); |
498 | + }); |
499 | + var response = conn.last_message(); |
500 | + response.result = { |
501 | + config: { |
502 | + options: { |
503 | + default_log: { |
504 | + 'default': 'global', |
505 | + description: 'Default log', |
506 | + type: 'string' |
507 | + }}}}; |
508 | + env.dispatch_result(response); |
509 | + }); |
510 | + |
511 | + it('parses the new charm model options location correctly', function(done) { |
512 | + var charm = new models.BrowserCharm({id: 'local:precise/foo-4'}).load( |
513 | + env, |
514 | + function(err, response) { |
515 | + assert(!err); |
516 | + // This checks to make sure the parse mechanism is working properly |
517 | + // for both the old ane new charm browser. |
518 | + assert.equal(charm.get('options').default_log['default'], 'global'); |
519 | + done(); |
520 | + }); |
521 | + var response = conn.last_message(); |
522 | + response.result = { |
523 | + options: { |
524 | + default_log: { |
525 | + 'default': 'global', |
526 | + description: 'Default log', |
527 | + type: 'string' |
528 | + }}}; |
529 | + env.dispatch_result(response); |
530 | + }); |
531 | + |
532 | + it('must handle failure from local charm request', function(done) { |
533 | + var charm = new models.BrowserCharm({id: 'local:precise/foo-4'}).load( |
534 | + env, |
535 | + function(err, response) { |
536 | + assert(err); |
537 | + assert(response.err); |
538 | + assert(!charm.loaded); |
539 | + done(); |
540 | + }); |
541 | + var response = conn.last_message(); |
542 | + response.err = true; |
543 | + env.dispatch_result(response); |
544 | + // The test in the callback above should run. |
545 | + }); |
546 | +}); |
547 | + |
548 | +describe('Charm load', function() { |
549 | var Y, models, conn, env, app, container, fakeStore, data, juju; |
550 | |
551 | before(function(done) { |
Reviewers: mp+179005_ code.launchpad. net,
Message:
Please take a look.
Description:
Removes Charm extension from BrowserCharm
In order to be able to safely remove Charm, BrowserCharm cannot extend
it.
-BrowserCharm now extends Model
-BrowserCharm now supports the initialization functions that Charm does
(e.g.
setting attr from the provided ID)
-BrowserCharm now has the same `load` pipeline functions (e.g. `sync`)
-Tests have been updated or added to demonstrate new support
-Drive by test cleanup--there were many tests that checked the same
exact
things; I've merged these to mitigate the damage from some of the test
repetition I've had to temporarily add.
https:/ /code.launchpad .net/~jcsackett /juju-gui/ remove- charm-extension -in-browser- charm/+ merge/179005
(do not edit description out of merge proposal)
Please review this at https:/ /codereview. appspot. com/12608043/
Affected files:
A [revision details]
M app/models/charm.js
M test/test_model.js