Merge lp:~hatch/juju-gui/bundle-fail-gracefully into lp:juju-gui/experimental

Proposed by Jeff Pihach
Status: Merged
Merged at revision: 1132
Proposed branch: lp:~hatch/juju-gui/bundle-fail-gracefully
Merge into: lp:juju-gui/experimental
Diff against target: 222 lines (+125/-23)
2 files modified
app/subapps/browser/views/bundle.js (+48/-8)
test/test_bundle_details_view.js (+77/-15)
To merge this branch: bzr merge lp:~hatch/juju-gui/bundle-fail-gracefully
Reviewer Review Type Date Requested Status
Juju GUI Hackers Pending
Review via email: mp+190769@code.launchpad.net

Description of the change

Bundle topology rendering fails gracefully

If the bundle does not provide proper xy position annotations
on any of the services in its deployer file we do not render
the bundle topology and instead remove the bundle topology
tab, selecting the Charms tab to show the charms the
bundle contains.

Because we don't have any bundles with proper positions right
now I added the flag `strictBundle` to enable this feature.

https://codereview.appspot.com/14502061/

To post a comment you must log in.
Revision history for this message
Jeff Pihach (hatch) wrote :

Reviewers: mp+190769_code.launchpad.net,

Message:
Please take a look.

Description:
Bundle topology rendering fails gracefully

If the bundle does not provide proper xy position annotations
on any of the services in its deployer file we do not render
the bundle topology and instead issue a warning.

Because we don't have any bundles with proper positions right
now I added the flag strictBundle to enable this feature.

https://code.launchpad.net/~hatch/juju-gui/bundle-fail-gracefully/+merge/190769

(do not edit description out of merge proposal)

Please review this at https://codereview.appspot.com/14502061/

Affected files (+119, -23 lines):
   A [revision details]
   M app/subapps/browser/views/bundle.js
   M test/test_bundle_details_view.js

Revision history for this message
Gary Poster (gary) wrote :

Small test change requested, and otherwise code is LGTM. doing qa now.

https://codereview.appspot.com/14502061/diff/1/test/test_bundle_details_view.js
File test/test_bundle_details_view.js (right):

https://codereview.appspot.com/14502061/diff/1/test/test_bundle_details_view.js#newcode188
test/test_bundle_details_view.js:188: 'gui-y': ''
I wonder if we should not allow this either. shrug.

https://codereview.appspot.com/14502061/diff/1/test/test_bundle_details_view.js#newcode208
test/test_bundle_details_view.js:208: view._positionAnnotationsIncluded
= function() {
But this way you are not testing whether _postionAnnotationsIncluded
actually ever can approve something! :-) Can we just adjust the data
instead?

https://codereview.appspot.com/14502061/

1135. By Jeff Pihach

If a bundle topology data is invalid we now don't show the tab at all and instead default to the charms tab

Revision history for this message
Jeff Pihach (hatch) wrote :
Revision history for this message
Jeff Pihach (hatch) wrote :

*** Submitted:

Bundle topology rendering fails gracefully

If the bundle does not provide proper xy position annotations
on any of the services in its deployer file we do not render
the bundle topology and instead remove the bundle topology
tab, selecting the Charms tab to show the charms the
bundle contains.

Because we don't have any bundles with proper positions right
now I added the flag `strictBundle` to enable this feature.

R=gary.poster
CC=
https://codereview.appspot.com/14502061

https://codereview.appspot.com/14502061/

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'app/subapps/browser/views/bundle.js'
2--- app/subapps/browser/views/bundle.js 2013-10-11 17:51:10 +0000
3+++ app/subapps/browser/views/bundle.js 2013-10-11 22:52:00 +0000
4@@ -150,27 +150,67 @@
5 return !/\.svg$/.test(fileName);
6 });
7 var content = this.template(attrs);
8-
9 var node = this.get('container').setHTML(content);
10 var renderTo = this.get('renderTo');
11 var options = {size: [480, 360]};
12 this.hideIndicator(renderTo);
13- this.environment = new views.BundleTopology(Y.mix({
14- db: this.fakebackend.db,
15- container: node.one('#bws-bundle'), // Id because of Y.TabView
16- store: this.get('store')
17- }, options));
18-
19- this.environment.render();
20+
21+ var showTopo = true;
22+ // remove the flag in the test(test_bundle_details_view.js)
23+ // when this flag is no longer needed.
24+ if (window.flags && window.flags.strictBundle) {
25+ showTopo = this._positionAnnotationsIncluded(attrs.data.services);
26+ }
27+ if (showTopo) {
28+ this.environment = new views.BundleTopology(Y.mix({
29+ db: this.fakebackend.db,
30+ container: node.one('#bws-bundle'), // Id because of Y.TabView
31+ store: this.get('store')
32+ }, options));
33+ this.environment.render();
34+ } else {
35+ // Remove the bundle tab so it doesn't get PE'd when
36+ // we instantiate the tabview.
37+ node.one('#bws-bundle').remove();
38+ node.one('a[href=#bws-bundle]').get('parentNode').remove();
39+ }
40+
41 renderTo.setHTML(node);
42
43 this._setupTabview();
44+ if (!showTopo) {
45+ // Select the charms tab as the landing tab if
46+ // we aren't showing the bundle topology.
47+ this.tabview.selectChild(2);
48+ }
49 this._dispatchTabEvents(this.tabview);
50
51 this.set('rendered', true);
52 },
53
54 /**
55+ Determines if all of the services in the bundle
56+ have position annotations.
57+
58+ @method _positionAnnotationsIncluded
59+ @param {Object} services An object of all of the services in the bundle.
60+ @return {Boolean} Weather all services have position annotations or not.
61+ */
62+ _positionAnnotationsIncluded: function(services) {
63+ // Some returns true if it's stopped early, this inverts before returning.
64+ return !Object.keys(services).some(function(key) {
65+ var annotations = services[key].annotations;
66+ // If there is no annotations for the position coords
67+ // return true stopping the 'some' loop.
68+ if (!annotations ||
69+ !annotations['gui-x'] ||
70+ !annotations['gui-y']) {
71+ return true;
72+ }
73+ });
74+ },
75+
76+ /**
77 Renders the loading indicator into the DOM and then calls
78 the _prepareData method to fetch/parse the bundle data for
79 the real view rendering.
80
81=== modified file 'test/test_bundle_details_view.js'
82--- test/test_bundle_details_view.js 2013-10-11 20:13:50 +0000
83+++ test/test_bundle_details_view.js 2013-10-11 22:52:00 +0000
84@@ -60,6 +60,9 @@
85 entityId: data.id,
86 renderTo: container
87 });
88+ view._setupLocalFakebackend = function() {
89+ this.fakebackend = utils.makeFakeBackend();
90+ };
91 });
92
93 afterEach(function() {
94@@ -89,9 +92,6 @@
95 });
96
97 it('displays the bundle data in a tabview', function(done) {
98- view._setupLocalFakebackend = function() {
99- this.fakebackend = utils.makeFakeBackend();
100- };
101 view.after('renderedChange', function(e) {
102 assert.isNotNull(container.one('.yui3-tabview'));
103 done();
104@@ -112,9 +112,6 @@
105 done();
106 }
107 });
108- view._setupLocalFakebackend = function() {
109- this.fakebackend = utils.makeFakeBackend();
110- };
111 view.after('renderedChange', function(e) {
112 container.one('a.readme').simulate('click');
113 });
114@@ -134,9 +131,6 @@
115 done();
116 }
117 });
118- view._setupLocalFakebackend = function() {
119- this.fakebackend = utils.makeFakeBackend();
120- };
121 view.after('renderedChange', function(e) {
122 container.one('a.code').simulate('click');
123 var codeNode = container.one('#bws-code');
124@@ -148,9 +142,6 @@
125 });
126
127 it('renders the proper charm icons into the header', function(done) {
128- view._setupLocalFakebackend = function() {
129- this.fakebackend = utils.makeFakeBackend();
130- };
131 view.after('renderedChange', function(e) {
132 assert.equal(
133 container.one('.header .details .charms').all('img').size(),
134@@ -161,9 +152,6 @@
135 });
136
137 it('deploys a bundle when \'add\' button is clicked', function(done) {
138- view._setupLocalFakebackend = function() {
139- this.fakebackend = utils.makeFakeBackend();
140- };
141 // app.js sets this to its deploy bundle method so
142 // as long as it's called it's successful.
143 view.set('deployBundle', function(data) {
144@@ -176,4 +164,78 @@
145 view.render();
146 });
147
148+ it('fails gracefully if services don\'t provide xy annotations',
149+ function(done) {
150+ window.flags = { strictBundle: true };
151+ view._parseData = function() {
152+ return new Y.Promise(function(resolve) { resolve(); });
153+ };
154+ view.set('entity', {
155+ getAttrs: function() {
156+ return {
157+ charm_metadata: {},
158+ files: [],
159+ data: {
160+ services: {
161+ foo: {
162+ annotations: {
163+ 'gui-x': '',
164+ 'gui-y': ''
165+ }
166+ },
167+ bar: {}
168+ }
169+ }
170+ };
171+ }});
172+ view.after('renderedChange', function(e) {
173+ assert.isNull(container.one('#bws-bundle'));
174+ assert.isNull(container.one('a[href=#bws-bundle]'));
175+ // Check that the charms tab is the landing tab
176+ assert.equal(view.tabview.get('selection').get('index'), 2);
177+ window.flags = {};
178+ done();
179+ });
180+ view.render();
181+ });
182+
183+ it('renders the bundle topology into the view', function(done) {
184+ window.flags = { strictBundle: true };
185+ view._parseData = function() {
186+ return new Y.Promise(function(resolve) { resolve(); });
187+ };
188+ view.set('entity', {
189+ getAttrs: function() {
190+ return {
191+ charm_metadata: {},
192+ files: [],
193+ data: {
194+ services: {
195+ foo: {
196+ annotations: {
197+ 'gui-x': '1',
198+ 'gui-y': '2'
199+ }
200+ },
201+ bar: {
202+ annotations: {
203+ 'gui-x': '3',
204+ 'gui-y': '4'
205+ }
206+ }
207+ }
208+ }
209+ };
210+ }});
211+ view.after('renderedChange', function(e) {
212+ assert.isNotNull(container.one('.topology-canvas'));
213+ // Check that the bundle topology tab is the landing tab.
214+ assert.equal(view.tabview.get('selection').get('index'), 0);
215+ window.flags = {};
216+ done();
217+ });
218+ view.render();
219+ });
220+
221+
222 });

Subscribers

People subscribed via source and target branches