Merge lp:~frankban/juju-quickstart/views-params into lp:juju-quickstart
- views-params
- Merge into trunk
Status: | Merged |
---|---|
Merged at revision: | 111 |
Proposed branch: | lp:~frankban/juju-quickstart/views-params |
Merge into: | lp:juju-quickstart |
Diff against target: |
975 lines (+301/-172) 6 files modified
quickstart/cli/params.py (+51/-0) quickstart/cli/views.py (+70/-74) quickstart/manage.py (+11/-4) quickstart/tests/cli/test_params.py (+87/-0) quickstart/tests/cli/test_views.py (+71/-90) quickstart/tests/test_manage.py (+11/-4) |
To merge this branch: | bzr merge lp:~frankban/juju-quickstart/views-params |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Juju GUI Hackers | Pending | ||
Review via email: mp+245753@code.launchpad.net |
Commit message
Description of the change
Refactor view parameters.
Implement a Params object used to store
common view parameters. This way it will
be easier to add parameters in the future
(e.g. one callable to remove stale jenv files).
New code include the params module and a fix
to the code handling the listing of jenv files
in the index view: now the header message is
only displayed if jenv files actually exist.
The rest of the diff is mechanical: i.e. replacing
the single view arguments with the params named
tuple.
Tests: `make check`.
QA:
Use the quickstart interactive session and
check everything works ok.
Francesco Banconi (frankban) wrote : | # |
Brad Crittenden (bac) wrote : | # |
LGTM. No QA yet.
https:/
File quickstart/
https:/
quickstart/
user has the ability to select
Maybe 'assumed' would be clearer than 'supposed'?
https:/
File quickstart/
https:/
quickstart/
params)
Such a nice set of tests! Thanks for the clarity.
Martin Hilton (martin-hilton) wrote : | # |
Brad Crittenden (bac) wrote : | # |
QA-OK. I simply ran quickstart and launched a local provider.
Everything came up as expected.
- 114. By Francesco Banconi
-
Improve view comment.
Francesco Banconi (frankban) wrote : | # |
*** Submitted:
Refactor view parameters.
Implement a Params object used to store
common view parameters. This way it will
be easier to add parameters in the future
(e.g. one callable to remove stale jenv files).
New code include the params module and a fix
to the code handling the listing of jenv files
in the index view: now the header message is
only displayed if jenv files actually exist.
The rest of the diff is mechanical: i.e. replacing
the single view arguments with the params named
tuple.
Tests: `make check`.
QA:
Use the quickstart interactive session and
check everything works ok.
R=bac, martin.hilton
CC=
https:/
https:/
File quickstart/
https:/
quickstart/
user has the ability to select
On 2015/01/07 15:58:26, bac wrote:
> Maybe 'assumed' would be clearer than 'supposed'?
Done.
Francesco Banconi (frankban) wrote : | # |
Thanks for the reviews!
Preview Diff
1 | === added file 'quickstart/cli/params.py' | |||
2 | --- quickstart/cli/params.py 1970-01-01 00:00:00 +0000 | |||
3 | +++ quickstart/cli/params.py 2015-01-07 16:46:42 +0000 | |||
4 | @@ -0,0 +1,51 @@ | |||
5 | 1 | # This file is part of the Juju Quickstart Plugin, which lets users set up a | ||
6 | 2 | # Juju environment in very few steps (https://launchpad.net/juju-quickstart). | ||
7 | 3 | # Copyright (C) 2015 Canonical Ltd. | ||
8 | 4 | # | ||
9 | 5 | # This program is free software: you can redistribute it and/or modify it under | ||
10 | 6 | # the terms of the GNU Affero General Public License version 3, as published by | ||
11 | 7 | # the Free Software Foundation. | ||
12 | 8 | # | ||
13 | 9 | # This program is distributed in the hope that it will be useful, but WITHOUT | ||
14 | 10 | # ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, | ||
15 | 11 | # SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | 12 | # Affero General Public License for more details. | ||
17 | 13 | # | ||
18 | 14 | # You should have received a copy of the GNU Affero General Public License | ||
19 | 15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
20 | 16 | |||
21 | 17 | """Juju Quickstart view parameters implementation. | ||
22 | 18 | |||
23 | 19 | This module contains an implementation of a composite parameter object to be | ||
24 | 20 | used in views. | ||
25 | 21 | |||
26 | 22 | The Params named tuple is intended to both help grouping view parameters | ||
27 | 23 | together and avoid undesired mutations, by allowing explicit copies of the | ||
28 | 24 | whole parameters object (see the Params.copy instance method). | ||
29 | 25 | """ | ||
30 | 26 | |||
31 | 27 | from __future__ import unicode_literals | ||
32 | 28 | |||
33 | 29 | from collections import namedtuple | ||
34 | 30 | import copy | ||
35 | 31 | |||
36 | 32 | |||
37 | 33 | _PARAMS = ('env_type_db', 'env_db', 'jenv_db', 'save_callable') | ||
38 | 34 | |||
39 | 35 | |||
40 | 36 | class Params(namedtuple('Params', _PARAMS)): | ||
41 | 37 | """View parameters as a named tuple.""" | ||
42 | 38 | |||
43 | 39 | # Define empty slots to keep memory requirements low by preventing the | ||
44 | 40 | # creation of instance dictionaries. | ||
45 | 41 | # See https://docs.python.org/2/library/collections.html | ||
46 | 42 | __slots__ = () | ||
47 | 43 | |||
48 | 44 | def copy(self): | ||
49 | 45 | """Return a deep copy of the stored parameters.""" | ||
50 | 46 | return self.__class__( | ||
51 | 47 | env_type_db=self.env_type_db, | ||
52 | 48 | env_db=copy.deepcopy(self.env_db), | ||
53 | 49 | jenv_db=copy.deepcopy(self.jenv_db), | ||
54 | 50 | save_callable=self.save_callable, | ||
55 | 51 | ) | ||
56 | 0 | 52 | ||
57 | === modified file 'quickstart/cli/views.py' | |||
58 | --- quickstart/cli/views.py 2014-12-17 11:34:06 +0000 | |||
59 | +++ quickstart/cli/views.py 2015-01-07 16:46:42 +0000 | |||
60 | @@ -155,36 +155,33 @@ | |||
61 | 155 | raise ui.AppExit((env_db, env_data)) | 155 | raise ui.AppExit((env_db, env_data)) |
62 | 156 | 156 | ||
63 | 157 | 157 | ||
65 | 158 | def env_index(app, env_type_db, env_db, jenv_db, save_callable): | 158 | def env_index(app, params): |
66 | 159 | """Show the Juju environments list. | 159 | """Show the Juju environments list. |
67 | 160 | 160 | ||
68 | 161 | The env_detail view is displayed when the user clicks on an environment. | 161 | The env_detail view is displayed when the user clicks on an environment. |
69 | 162 | From here it is also possible to switch to the edit view in order to create | 162 | From here it is also possible to switch to the edit view in order to create |
70 | 163 | a new environment. | 163 | a new environment. |
71 | 164 | 164 | ||
73 | 165 | Receives: | 165 | Receives a params namedtuple-like object including the following fields: |
74 | 166 | - env_type_db: the environments meta information; | 166 | - env_type_db: the environments meta information; |
75 | 167 | - env_db: the environments database; | 167 | - env_db: the environments database; |
76 | 168 | - jenv_db: the jenv files database; | 168 | - jenv_db: the jenv files database; |
77 | 169 | - save_callable: a function called to save a new environment database. | 169 | - save_callable: a function called to save a new environment database. |
78 | 170 | See quickstart.cli.params.Params. | ||
79 | 170 | """ | 171 | """ |
80 | 171 | # XXX frankban 16/12/2014: this function is too long, subdivide it. | 172 | # XXX frankban 16/12/2014: this function is too long, subdivide it. |
83 | 172 | env_db = copy.deepcopy(env_db) | 173 | params = params.copy() |
82 | 173 | jenv_db = copy.deepcopy(jenv_db) | ||
84 | 174 | # All the environment views return a tuple (new_env_db, env_data). | 174 | # All the environment views return a tuple (new_env_db, env_data). |
85 | 175 | # Set the env_data to None in the case the user quits the application | 175 | # Set the env_data to None in the case the user quits the application |
86 | 176 | # without selecting an environment to use. | 176 | # without selecting an environment to use. |
94 | 177 | app.set_return_value_on_exit((env_db, None)) | 177 | app.set_return_value_on_exit((params.env_db, None)) |
95 | 178 | detail_view = functools.partial( | 178 | detail_view = functools.partial(env_detail, app, params) |
96 | 179 | env_detail, app, env_type_db, env_db, jenv_db, save_callable) | 179 | jenv_view = functools.partial(jenv_detail, app, params) |
97 | 180 | jenv_view = functools.partial( | 180 | edit_view = functools.partial(env_edit, app, params) |
91 | 181 | jenv_detail, app, env_type_db, env_db, jenv_db, save_callable) | ||
92 | 182 | edit_view = functools.partial( | ||
93 | 183 | env_edit, app, env_type_db, env_db, jenv_db, save_callable) | ||
98 | 184 | # Alphabetically sort the existing environments. | 181 | # Alphabetically sort the existing environments. |
99 | 185 | environments = sorted([ | 182 | environments = sorted([ |
102 | 186 | envs.get_env_data(env_db, env_name) | 183 | envs.get_env_data(params.env_db, env_name) |
103 | 187 | for env_name in env_db['environments'] | 184 | for env_name in params.env_db['environments'] |
104 | 188 | ], key=operator.itemgetter('name')) | 185 | ], key=operator.itemgetter('name')) |
105 | 189 | 186 | ||
106 | 190 | def create_and_start_local_env(): | 187 | def create_and_start_local_env(): |
107 | @@ -193,8 +190,8 @@ | |||
108 | 193 | # database. For this reason, the new environment is set as default. | 190 | # database. For this reason, the new environment is set as default. |
109 | 194 | # Exit the interactive session selecting the newly created environment. | 191 | # Exit the interactive session selecting the newly created environment. |
110 | 195 | env_data = envs.create_local_env_data( | 192 | env_data = envs.create_local_env_data( |
113 | 196 | env_type_db, 'local', is_default=True) | 193 | params.env_type_db, 'local', is_default=True) |
114 | 197 | _save_and_exit(env_db, env_data, save_callable) | 194 | _save_and_exit(params.env_db, env_data, params.save_callable) |
115 | 198 | 195 | ||
116 | 199 | def create_and_start_maas_env(name, server, api_key): | 196 | def create_and_start_maas_env(name, server, api_key): |
117 | 200 | # Automatically create and use a MAAS environment. | 197 | # Automatically create and use a MAAS environment. |
118 | @@ -202,8 +199,8 @@ | |||
119 | 202 | # database. For this reason, the new environment is set as default. | 199 | # database. For this reason, the new environment is set as default. |
120 | 203 | # Exit the interactive session selecting the newly created environment. | 200 | # Exit the interactive session selecting the newly created environment. |
121 | 204 | env_data = envs.create_maas_env_data( | 201 | env_data = envs.create_maas_env_data( |
124 | 205 | env_type_db, name, server, api_key, is_default=True) | 202 | params.env_type_db, name, server, api_key, is_default=True) |
125 | 206 | _save_and_exit(env_db, env_data, save_callable) | 203 | _save_and_exit(params.env_db, env_data, params.save_callable) |
126 | 207 | 204 | ||
127 | 208 | platform = platform_support.get_platform() | 205 | platform = platform_support.get_platform() |
128 | 209 | supports_local = platform_support.supports_local(platform) | 206 | supports_local = platform_support.supports_local(platform) |
129 | @@ -279,7 +276,7 @@ | |||
130 | 279 | focus_position = None | 276 | focus_position = None |
131 | 280 | active_found = default_found = errors_found = False | 277 | active_found = default_found = errors_found = False |
132 | 281 | existing_widgets_num = len(widgets) | 278 | existing_widgets_num = len(widgets) |
134 | 282 | remaining_jenv_db = copy.deepcopy(jenv_db) | 279 | remaining_jenv_db = copy.deepcopy(params.jenv_db) |
135 | 283 | for position, env_data in enumerate(environments): | 280 | for position, env_data in enumerate(environments): |
136 | 284 | bullet = '\N{BULLET}' | 281 | bullet = '\N{BULLET}' |
137 | 285 | # Is this environment the default one? | 282 | # Is this environment the default one? |
138 | @@ -294,7 +291,7 @@ | |||
139 | 294 | bullet = ('active', bullet) | 291 | bullet = ('active', bullet) |
140 | 295 | else: | 292 | else: |
141 | 296 | # Check if this environment is valid. | 293 | # Check if this environment is valid. |
143 | 297 | env_metadata = envs.get_env_metadata(env_type_db, env_data) | 294 | env_metadata = envs.get_env_metadata(params.env_type_db, env_data) |
144 | 298 | errors = envs.validate(env_metadata, env_data) | 295 | errors = envs.validate(env_metadata, env_data) |
145 | 299 | if errors: | 296 | if errors: |
146 | 300 | errors_found = True | 297 | errors_found = True |
147 | @@ -306,25 +303,28 @@ | |||
148 | 306 | 303 | ||
149 | 307 | # Alphabetically sort the remaining environments not included in the | 304 | # Alphabetically sort the remaining environments not included in the |
150 | 308 | # environments.yaml file. | 305 | # environments.yaml file. |
152 | 309 | environments = sorted([ | 306 | environments = list(sorted([ |
153 | 310 | envs.get_env_data(remaining_jenv_db, env_name) | 307 | envs.get_env_data(remaining_jenv_db, env_name) |
154 | 311 | for env_name in remaining_jenv_db['environments'] | 308 | for env_name in remaining_jenv_db['environments'] |
156 | 312 | ], key=operator.itemgetter('name')) | 309 | ], key=operator.itemgetter('name'))) |
157 | 313 | 310 | ||
172 | 314 | # List the remaining active environments. Those environments are not | 311 | if environments: |
173 | 315 | # included in the environments.yaml file: they are probably imported and | 312 | # List the remaining active environments. Those environments are not |
174 | 316 | # supposed to be working/active. The user has the ability to select them. | 313 | # included in the environments.yaml file: they are probably imported |
175 | 317 | widgets.extend([ | 314 | # and assumed to be working/active. The user has the ability to select |
176 | 318 | urwid.Divider(), | 315 | # them. |
177 | 319 | urwid.Text(('highlight', 'Other active environments')), | 316 | widgets.extend([ |
178 | 320 | urwid.Text('(imported/not included in your environments.yaml file):'), | 317 | urwid.Divider(), |
179 | 321 | urwid.Divider(), | 318 | urwid.Text(('highlight', 'Other active environments')), |
180 | 322 | ]) | 319 | urwid.Text( |
181 | 323 | bullet = ('active', '\N{BULLET}') | 320 | '(imported/not included in your environments.yaml file):'), |
182 | 324 | for env_data in environments: | 321 | urwid.Divider(), |
183 | 325 | env_short_description = jenv.get_env_short_description(env_data) | 322 | ]) |
184 | 326 | text = [bullet, ' {}'.format(env_short_description)] | 323 | bullet = ('active', '\N{BULLET}') |
185 | 327 | widgets.append(ui.MenuButton(text, ui.thunk(jenv_view, env_data))) | 324 | for env_data in environments: |
186 | 325 | env_short_description = jenv.get_env_short_description(env_data) | ||
187 | 326 | text = [bullet, ' {}'.format(env_short_description)] | ||
188 | 327 | widgets.append(ui.MenuButton(text, ui.thunk(jenv_view, env_data))) | ||
189 | 328 | 328 | ||
190 | 329 | # Set up the "create a new environment" section. | 329 | # Set up the "create a new environment" section. |
191 | 330 | widgets.extend([ | 330 | widgets.extend([ |
192 | @@ -342,7 +342,7 @@ | |||
193 | 342 | if not supports_local: | 342 | if not supports_local: |
194 | 343 | filter_function = lambda env_type, _: env_type != 'local' | 343 | filter_function = lambda env_type, _: env_type != 'local' |
195 | 344 | supported_env_types = envs.get_supported_env_types( | 344 | supported_env_types = envs.get_supported_env_types( |
197 | 345 | env_type_db, filter_function=filter_function) | 345 | params.env_type_db, filter_function=filter_function) |
198 | 346 | # Add the buttons used to create new environments. | 346 | # Add the buttons used to create new environments. |
199 | 347 | widgets.extend([ | 347 | widgets.extend([ |
200 | 348 | ui.MenuButton( | 348 | ui.MenuButton( |
201 | @@ -369,42 +369,40 @@ | |||
202 | 369 | app.set_contents(contents) | 369 | app.set_contents(contents) |
203 | 370 | 370 | ||
204 | 371 | 371 | ||
206 | 372 | def env_detail(app, env_type_db, env_db, jenv_db, save_callable, env_data): | 372 | def env_detail(app, params, env_data): |
207 | 373 | """Show details on a Juju environment. | 373 | """Show details on a Juju environment. |
208 | 374 | 374 | ||
209 | 375 | From this view it is possible to start the environment, set it as default, | 375 | From this view it is possible to start the environment, set it as default, |
210 | 376 | edit/remove the environment. | 376 | edit/remove the environment. |
211 | 377 | 377 | ||
213 | 378 | Receives: | 378 | Receives a params namedtuple-like object including the following fields: |
214 | 379 | - env_type_db: the environments meta information; | 379 | - env_type_db: the environments meta information; |
215 | 380 | - env_db: the environments database; | 380 | - env_db: the environments database; |
216 | 381 | - jenv_db: the jenv files database; | 381 | - jenv_db: the jenv files database; |
219 | 382 | - save_callable: a function called to save a new environment database; | 382 | - save_callable: a function called to save a new environment database. |
220 | 383 | - env_data: the environment data. | 383 | See quickstart.cli.params.Params. |
221 | 384 | Also receives the current environment data env_data. | ||
222 | 384 | """ | 385 | """ |
225 | 385 | env_db = copy.deepcopy(env_db) | 386 | params = params.copy() |
224 | 386 | jenv_db = copy.deepcopy(jenv_db) | ||
226 | 387 | # All the environment views return a tuple (new_env_db, env_data). | 387 | # All the environment views return a tuple (new_env_db, env_data). |
227 | 388 | # Set the env_data to None in the case the user quits the application | 388 | # Set the env_data to None in the case the user quits the application |
228 | 389 | # without selecting an environment to use. | 389 | # without selecting an environment to use. |
234 | 390 | app.set_return_value_on_exit((env_db, None)) | 390 | app.set_return_value_on_exit((params.env_db, None)) |
235 | 391 | index_view = functools.partial( | 391 | index_view = functools.partial(env_index, app, params) |
236 | 392 | env_index, app, env_type_db, env_db, jenv_db, save_callable) | 392 | edit_view = functools.partial(env_edit, app, params, env_data) |
232 | 393 | edit_view = functools.partial( | ||
233 | 394 | env_edit, app, env_type_db, env_db, jenv_db, save_callable, env_data) | ||
237 | 395 | 393 | ||
238 | 396 | def use(env_data): | 394 | def use(env_data): |
239 | 397 | # Quit the interactive session returning the (possibly modified) | 395 | # Quit the interactive session returning the (possibly modified) |
240 | 398 | # environment database and the environment data corresponding to the | 396 | # environment database and the environment data corresponding to the |
241 | 399 | # selected environment. | 397 | # selected environment. |
243 | 400 | raise ui.AppExit((env_db, env_data)) | 398 | raise ui.AppExit((params.env_db, env_data)) |
244 | 401 | 399 | ||
245 | 402 | def set_default(env_data): | 400 | def set_default(env_data): |
246 | 403 | # Set this environment as the default one, save the env_db and return | 401 | # Set this environment as the default one, save the env_db and return |
247 | 404 | # to the index view. | 402 | # to the index view. |
248 | 405 | env_name = env_data['name'] | 403 | env_name = env_data['name'] |
251 | 406 | env_db['default'] = env_name | 404 | params.env_db['default'] = env_name |
252 | 407 | save_callable(env_db) | 405 | params.save_callable(params.env_db) |
253 | 408 | app.set_message('{} successfully set as default'.format(env_name)) | 406 | app.set_message('{} successfully set as default'.format(env_name)) |
254 | 409 | index_view() | 407 | index_view() |
255 | 410 | 408 | ||
256 | @@ -412,8 +410,8 @@ | |||
257 | 412 | # The environment deletion is confirmed: remove the environment from | 410 | # The environment deletion is confirmed: remove the environment from |
258 | 413 | # the database, save the new env_db and return to the index view. | 411 | # the database, save the new env_db and return to the index view. |
259 | 414 | env_name = env_data['name'] | 412 | env_name = env_data['name'] |
262 | 415 | envs.remove_env(env_db, env_name) | 413 | envs.remove_env(params.env_db, env_name) |
263 | 416 | save_callable(env_db) | 414 | params.save_callable(params.env_db) |
264 | 417 | app.set_message('{} successfully removed'.format(env_name)) | 415 | app.set_message('{} successfully removed'.format(env_name)) |
265 | 418 | index_view() | 416 | index_view() |
266 | 419 | 417 | ||
267 | @@ -427,7 +425,7 @@ | |||
268 | 427 | ], | 425 | ], |
269 | 428 | ) | 426 | ) |
270 | 429 | 427 | ||
272 | 430 | env_metadata = envs.get_env_metadata(env_type_db, env_data) | 428 | env_metadata = envs.get_env_metadata(params.env_type_db, env_data) |
273 | 431 | app.set_title(envs.get_env_short_description(env_data)) | 429 | app.set_title(envs.get_env_short_description(env_data)) |
274 | 432 | # Validate the environment. | 430 | # Validate the environment. |
275 | 433 | errors = envs.validate(env_metadata, env_data) | 431 | errors = envs.validate(env_metadata, env_data) |
276 | @@ -464,34 +462,33 @@ | |||
277 | 464 | app.set_contents(listbox) | 462 | app.set_contents(listbox) |
278 | 465 | 463 | ||
279 | 466 | 464 | ||
281 | 467 | def jenv_detail(app, env_type_db, env_db, jenv_db, save_callable, env_data): | 465 | def jenv_detail(app, params, env_data): |
282 | 468 | """Show details on a Juju imported environment. | 466 | """Show details on a Juju imported environment. |
283 | 469 | 467 | ||
284 | 470 | The environment is not included in the environments.yaml file, but just | 468 | The environment is not included in the environments.yaml file, but just |
285 | 471 | found in the jenv database. | 469 | found in the jenv database. |
286 | 472 | From this view it is possible to start the environment. | 470 | From this view it is possible to start the environment. |
287 | 473 | 471 | ||
289 | 474 | Receives: | 472 | Receives a params namedtuple-like object including the following fields: |
290 | 475 | - env_type_db: the environments meta information; | 473 | - env_type_db: the environments meta information; |
291 | 476 | - env_db: the environments database; | 474 | - env_db: the environments database; |
292 | 477 | - jenv_db: the jenv files database; | 475 | - jenv_db: the jenv files database; |
293 | 478 | - save_callable: a function called to save a new environment database; | 476 | - save_callable: a function called to save a new environment database; |
295 | 479 | - env_data: the environment data. | 477 | See quickstart.cli.params.Params. |
296 | 478 | Also receives the current environment data env_data. | ||
297 | 480 | """ | 479 | """ |
300 | 481 | env_db = copy.deepcopy(env_db) | 480 | params = params.copy() |
299 | 482 | jenv_db = copy.deepcopy(jenv_db) | ||
301 | 483 | # All the environment views return a tuple (new_env_db, env_data). | 481 | # All the environment views return a tuple (new_env_db, env_data). |
302 | 484 | # Set the env_data to None in the case the user quits the application | 482 | # Set the env_data to None in the case the user quits the application |
303 | 485 | # without selecting an environment to use. | 483 | # without selecting an environment to use. |
307 | 486 | app.set_return_value_on_exit((env_db, None)) | 484 | app.set_return_value_on_exit((params.env_db, None)) |
308 | 487 | index_view = functools.partial( | 485 | index_view = functools.partial(env_index, app, params) |
306 | 488 | env_index, app, env_type_db, env_db, jenv_db, save_callable) | ||
309 | 489 | 486 | ||
310 | 490 | def use(env_data): | 487 | def use(env_data): |
311 | 491 | # Quit the interactive session returning the (possibly modified) | 488 | # Quit the interactive session returning the (possibly modified) |
312 | 492 | # environment database and the environment data corresponding to the | 489 | # environment database and the environment data corresponding to the |
313 | 493 | # selected environment. | 490 | # selected environment. |
315 | 494 | raise ui.AppExit((env_db, env_data)) | 491 | raise ui.AppExit((params.env_db, env_data)) |
316 | 495 | 492 | ||
317 | 496 | app.set_title(jenv.get_env_short_description(env_data)) | 493 | app.set_title(jenv.get_env_short_description(env_data)) |
318 | 497 | widgets = [] | 494 | widgets = [] |
319 | @@ -519,36 +516,34 @@ | |||
320 | 519 | app.set_status([' \N{RIGHTWARDS ARROW OVER LEFTWARDS ARROW} navigate ']) | 516 | app.set_status([' \N{RIGHTWARDS ARROW OVER LEFTWARDS ARROW} navigate ']) |
321 | 520 | 517 | ||
322 | 521 | 518 | ||
324 | 522 | def env_edit(app, env_type_db, env_db, jenv_db, save_callable, env_data): | 519 | def env_edit(app, params, env_data): |
325 | 523 | """Create or modify a Juju environment. | 520 | """Create or modify a Juju environment. |
326 | 524 | 521 | ||
327 | 525 | This view displays an edit form allowing for environment | 522 | This view displays an edit form allowing for environment |
328 | 526 | creation/modification. Saving the form redirects to the environment detail | 523 | creation/modification. Saving the form redirects to the environment detail |
329 | 527 | view if the values are valid. | 524 | view if the values are valid. |
330 | 528 | 525 | ||
332 | 529 | Receives: | 526 | Receives a params namedtuple-like object including the following fields: |
333 | 530 | - env_type_db: the environments meta information; | 527 | - env_type_db: the environments meta information; |
334 | 531 | - env_db: the environments database; | 528 | - env_db: the environments database; |
335 | 532 | - jenv_db: the jenv files database; | 529 | - jenv_db: the jenv files database; |
336 | 533 | - save_callable: a function called to save a new environment database; | 530 | - save_callable: a function called to save a new environment database; |
338 | 534 | - env_data: the environment data. | 531 | See quickstart.cli.params.Params. |
339 | 532 | Also receives the current environment data env_data. | ||
340 | 535 | 533 | ||
341 | 536 | The last value (env_data) indicates whether this view is used to create a | 534 | The last value (env_data) indicates whether this view is used to create a |
342 | 537 | new environment or to change an existing one. In the former case, env_data | 535 | new environment or to change an existing one. In the former case, env_data |
343 | 538 | does not include the "name" key. If instead the environment already exists, | 536 | does not include the "name" key. If instead the environment already exists, |
344 | 539 | env_data includes the "name" key and all the other environment info. | 537 | env_data includes the "name" key and all the other environment info. |
345 | 540 | """ | 538 | """ |
348 | 541 | env_db = copy.deepcopy(env_db) | 539 | params = params.copy() |
347 | 542 | jenv_db = copy.deepcopy(jenv_db) | ||
349 | 543 | # All the environment views return a tuple (new_env_db, env_data). | 540 | # All the environment views return a tuple (new_env_db, env_data). |
350 | 544 | # Set the env_data to None in the case the user quits the application | 541 | # Set the env_data to None in the case the user quits the application |
351 | 545 | # without selecting an environment to use. | 542 | # without selecting an environment to use. |
358 | 546 | app.set_return_value_on_exit((env_db, None)) | 543 | app.set_return_value_on_exit((params.env_db, None)) |
359 | 547 | env_metadata = envs.get_env_metadata(env_type_db, env_data) | 544 | env_metadata = envs.get_env_metadata(params.env_type_db, env_data) |
360 | 548 | index_view = functools.partial( | 545 | index_view = functools.partial(env_index, app, params) |
361 | 549 | env_index, app, env_type_db, env_db, jenv_db, save_callable) | 546 | detail_view = functools.partial(env_detail, app, params) |
356 | 550 | detail_view = functools.partial( | ||
357 | 551 | env_detail, app, env_type_db, env_db, jenv_db, save_callable) | ||
362 | 552 | if 'name' in env_data: | 547 | if 'name' in env_data: |
363 | 553 | exists = True | 548 | exists = True |
364 | 554 | title = 'Edit the {} environment' | 549 | title = 'Edit the {} environment' |
365 | @@ -580,6 +575,7 @@ | |||
366 | 580 | errors = envs.validate(env_metadata, new_env_data) | 575 | errors = envs.validate(env_metadata, new_env_data) |
367 | 581 | new_name = new_env_data['name'] | 576 | new_name = new_env_data['name'] |
368 | 582 | initial_name = env_data.get('name') | 577 | initial_name = env_data.get('name') |
369 | 578 | env_db = params.env_db | ||
370 | 583 | if (new_name != initial_name) and new_name in env_db['environments']: | 579 | if (new_name != initial_name) and new_name in env_db['environments']: |
371 | 584 | errors['name'] = 'an environment with this name already exists' | 580 | errors['name'] = 'an environment with this name already exists' |
372 | 585 | # If errors are found, re-render the form passing the errors. This way | 581 | # If errors are found, re-render the form passing the errors. This way |
373 | @@ -594,7 +590,7 @@ | |||
374 | 594 | if not env_db['environments']: | 590 | if not env_db['environments']: |
375 | 595 | env_data['is-default'] = True | 591 | env_data['is-default'] = True |
376 | 596 | envs.set_env_data(env_db, initial_name, env_data) | 592 | envs.set_env_data(env_db, initial_name, env_data) |
378 | 597 | save_callable(env_db) | 593 | params.save_callable(env_db) |
379 | 598 | verb = 'modified' if exists else 'created' | 594 | verb = 'modified' if exists else 'created' |
380 | 599 | app.set_message('{} successfully {}'.format(new_name, verb)) | 595 | app.set_message('{} successfully {}'.format(new_name, verb)) |
381 | 600 | return detail_view(env_data) | 596 | return detail_view(env_data) |
382 | 601 | 597 | ||
383 | === modified file 'quickstart/manage.py' | |||
384 | --- quickstart/manage.py 2014-12-16 16:52:49 +0000 | |||
385 | +++ quickstart/manage.py 2015-01-07 16:46:42 +0000 | |||
386 | @@ -38,7 +38,10 @@ | |||
387 | 38 | settings, | 38 | settings, |
388 | 39 | utils, | 39 | utils, |
389 | 40 | ) | 40 | ) |
391 | 41 | from quickstart.cli import views | 41 | from quickstart.cli import ( |
392 | 42 | params, | ||
393 | 43 | views, | ||
394 | 44 | ) | ||
395 | 42 | from quickstart.models import ( | 45 | from quickstart.models import ( |
396 | 43 | charms, | 46 | charms, |
397 | 44 | envs, | 47 | envs, |
398 | @@ -210,9 +213,13 @@ | |||
399 | 210 | Exit the application if the user exits the interactive session without | 213 | Exit the application if the user exits the interactive session without |
400 | 211 | selecting an environment to start. | 214 | selecting an environment to start. |
401 | 212 | """ | 215 | """ |
405 | 213 | save_callable = _create_save_callable(parser, env_file) | 216 | parameters = params.Params( |
406 | 214 | new_env_db, env_data = views.show( | 217 | env_type_db=env_type_db, |
407 | 215 | views.env_index, env_type_db, env_db, jenv_db, save_callable) | 218 | env_db=env_db, |
408 | 219 | jenv_db=jenv_db, | ||
409 | 220 | save_callable=_create_save_callable(parser, env_file), | ||
410 | 221 | ) | ||
411 | 222 | new_env_db, env_data = views.show(views.env_index, parameters) | ||
412 | 216 | if new_env_db != env_db: | 223 | if new_env_db != env_db: |
413 | 217 | print('changes to the environments file have been saved') | 224 | print('changes to the environments file have been saved') |
414 | 218 | if env_data is None: | 225 | if env_data is None: |
415 | 219 | 226 | ||
416 | === added file 'quickstart/tests/cli/test_params.py' | |||
417 | --- quickstart/tests/cli/test_params.py 1970-01-01 00:00:00 +0000 | |||
418 | +++ quickstart/tests/cli/test_params.py 2015-01-07 16:46:42 +0000 | |||
419 | @@ -0,0 +1,87 @@ | |||
420 | 1 | # This file is part of the Juju Quickstart Plugin, which lets users set up a | ||
421 | 2 | # Juju environment in very few steps (https://launchpad.net/juju-quickstart). | ||
422 | 3 | # Copyright (C) 2015 Canonical Ltd. | ||
423 | 4 | # | ||
424 | 5 | # This program is free software: you can redistribute it and/or modify it under | ||
425 | 6 | # the terms of the GNU Affero General Public License version 3, as published by | ||
426 | 7 | # the Free Software Foundation. | ||
427 | 8 | # | ||
428 | 9 | # This program is distributed in the hope that it will be useful, but WITHOUT | ||
429 | 10 | # ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, | ||
430 | 11 | # SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
431 | 12 | # Affero General Public License for more details. | ||
432 | 13 | # | ||
433 | 14 | # You should have received a copy of the GNU Affero General Public License | ||
434 | 15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
435 | 16 | |||
436 | 17 | """Tests for the Juju Quickstart CLI parameters implementation.""" | ||
437 | 18 | |||
438 | 19 | from __future__ import unicode_literals | ||
439 | 20 | |||
440 | 21 | import unittest | ||
441 | 22 | |||
442 | 23 | from quickstart.cli import params | ||
443 | 24 | from quickstart.models import envs | ||
444 | 25 | from quickstart.tests import helpers | ||
445 | 26 | |||
446 | 27 | |||
447 | 28 | class TestParams(unittest.TestCase): | ||
448 | 29 | |||
449 | 30 | def setUp(self): | ||
450 | 31 | # Store parameters. | ||
451 | 32 | self.env_type_db = envs.get_env_type_db() | ||
452 | 33 | self.env_db = helpers.make_env_db() | ||
453 | 34 | self.jenv_db = helpers.make_jenv_db() | ||
454 | 35 | self.save_callable = lambda env_db: None | ||
455 | 36 | # Set up a params object used in tests. | ||
456 | 37 | self.params = params.Params( | ||
457 | 38 | env_type_db=self.env_type_db, | ||
458 | 39 | env_db=self.env_db, | ||
459 | 40 | jenv_db=self.jenv_db, | ||
460 | 41 | save_callable=self.save_callable, | ||
461 | 42 | ) | ||
462 | 43 | |||
463 | 44 | def test_tuple(self): | ||
464 | 45 | # The params object can be used as a tuple. | ||
465 | 46 | env_type_db, env_db, jenv_db, save_callable = self.params | ||
466 | 47 | self.assertIs(self.env_type_db, env_type_db) | ||
467 | 48 | self.assertIs(self.env_db, env_db) | ||
468 | 49 | self.assertIs(self.jenv_db, jenv_db) | ||
469 | 50 | self.assertIs(self.save_callable, save_callable) | ||
470 | 51 | |||
471 | 52 | def test_attributes(self): | ||
472 | 53 | # Parameters can be accessed as attributes. | ||
473 | 54 | self.assertIs(self.env_type_db, self.params.env_type_db) | ||
474 | 55 | self.assertIs(self.env_db, self.params.env_db) | ||
475 | 56 | self.assertIs(self.jenv_db, self.params.jenv_db) | ||
476 | 57 | self.assertIs(self.save_callable, self.params.save_callable) | ||
477 | 58 | |||
478 | 59 | def test_immutable(self): | ||
479 | 60 | # It is not possible to replace a stored parameter. | ||
480 | 61 | with self.assertRaises(AttributeError): | ||
481 | 62 | self.params.env_db = {} | ||
482 | 63 | |||
483 | 64 | def test_copy(self): | ||
484 | 65 | # Params can be copied. | ||
485 | 66 | params = self.params.copy() | ||
486 | 67 | # The original object is not mutated by the copy. | ||
487 | 68 | self.assertIs(self.env_type_db, self.params.env_type_db) | ||
488 | 69 | self.assertIs(self.env_db, self.params.env_db) | ||
489 | 70 | self.assertIs(self.jenv_db, self.params.jenv_db) | ||
490 | 71 | self.assertIs(self.save_callable, self.params.save_callable) | ||
491 | 72 | # The new params object stores the same data. | ||
492 | 73 | self.assertEqual(self.params, params) | ||
493 | 74 | # But they do not refer to the same object. | ||
494 | 75 | self.assertIsNot(self.params, params) | ||
495 | 76 | |||
496 | 77 | def test_copy_mutations(self): | ||
497 | 78 | # Internal mutable objects can be still mutated. | ||
498 | 79 | params = self.params.copy() | ||
499 | 80 | # Mutate the copy. | ||
500 | 81 | params.env_db['environments']['lxc'] = {} | ||
501 | 82 | # The mutation took effect. | ||
502 | 83 | self.assertNotEqual(self.env_db, params.env_db) | ||
503 | 84 | # The original object is still preserved. | ||
504 | 85 | self.assertIs(self.env_db, self.params.env_db) | ||
505 | 86 | # The two now store different data. | ||
506 | 87 | self.assertNotEqual(self.params, params) | ||
507 | 0 | 88 | ||
508 | === modified file 'quickstart/tests/cli/test_views.py' | |||
509 | --- quickstart/tests/cli/test_views.py 2014-12-17 11:47:43 +0000 | |||
510 | +++ quickstart/tests/cli/test_views.py 2015-01-07 16:46:42 +0000 | |||
511 | @@ -31,6 +31,7 @@ | |||
512 | 31 | from quickstart.cli import ( | 31 | from quickstart.cli import ( |
513 | 32 | base, | 32 | base, |
514 | 33 | forms, | 33 | forms, |
515 | 34 | params, | ||
516 | 34 | ui, | 35 | ui, |
517 | 35 | views, | 36 | views, |
518 | 36 | ) | 37 | ) |
519 | @@ -166,6 +167,15 @@ | |||
520 | 166 | """ | 167 | """ |
521 | 167 | return lambda arg: isinstance(arg, cls) | 168 | return lambda arg: isinstance(arg, cls) |
522 | 168 | 169 | ||
523 | 170 | def make_params(self, env_db, jenv_db): | ||
524 | 171 | """Create and return view parameters using the given env databases.""" | ||
525 | 172 | return params.Params( | ||
526 | 173 | env_type_db=self.env_type_db, | ||
527 | 174 | env_db=env_db, | ||
528 | 175 | jenv_db=jenv_db, | ||
529 | 176 | save_callable=self.save_callable, | ||
530 | 177 | ) | ||
531 | 178 | |||
532 | 169 | 179 | ||
533 | 170 | class TestEnvIndex(EnvViewTestsMixin, unittest.TestCase): | 180 | class TestEnvIndex(EnvViewTestsMixin, unittest.TestCase): |
534 | 171 | 181 | ||
535 | @@ -175,6 +185,7 @@ | |||
536 | 175 | create_maas_caption = ( | 185 | create_maas_caption = ( |
537 | 176 | '\N{BULLET} automatically create and bootstrap the {} MAAS ' | 186 | '\N{BULLET} automatically create and bootstrap the {} MAAS ' |
538 | 177 | 'environment'.format(MAAS_NAME)) | 187 | 'environment'.format(MAAS_NAME)) |
539 | 188 | active_environments_message = 'Other active environments' | ||
540 | 178 | 189 | ||
541 | 179 | def test_view_default_return_value_on_exit(self): | 190 | def test_view_default_return_value_on_exit(self): |
542 | 180 | # The view configures the app so that the return value on user exit is | 191 | # The view configures the app so that the return value on user exit is |
543 | @@ -182,8 +193,7 @@ | |||
544 | 182 | # meaning no environment has been selected. | 193 | # meaning no environment has been selected. |
545 | 183 | env_db = helpers.make_env_db() | 194 | env_db = helpers.make_env_db() |
546 | 184 | jenv_db = helpers.make_jenv_db() | 195 | jenv_db = helpers.make_jenv_db() |
549 | 185 | views.env_index( | 196 | views.env_index(self.app, self.make_params(env_db, jenv_db)) |
548 | 186 | self.app, self.env_type_db, env_db, jenv_db, self.save_callable) | ||
550 | 187 | new_env_db, env_data = self.get_on_exit_return_value(self.loop) | 197 | new_env_db, env_data = self.get_on_exit_return_value(self.loop) |
551 | 188 | self.assertEqual(env_db, new_env_db) | 198 | self.assertEqual(env_db, new_env_db) |
552 | 189 | self.assertIsNot(env_db, new_env_db) | 199 | self.assertIsNot(env_db, new_env_db) |
553 | @@ -193,8 +203,7 @@ | |||
554 | 193 | # The application title is correctly set up. | 203 | # The application title is correctly set up. |
555 | 194 | env_db = helpers.make_env_db() | 204 | env_db = helpers.make_env_db() |
556 | 195 | jenv_db = helpers.make_jenv_db() | 205 | jenv_db = helpers.make_jenv_db() |
559 | 196 | views.env_index( | 206 | views.env_index(self.app, self.make_params(env_db, jenv_db)) |
558 | 197 | self.app, self.env_type_db, env_db, jenv_db, self.save_callable) | ||
560 | 198 | self.assertEqual( | 207 | self.assertEqual( |
561 | 199 | 'Select an existing Juju environment or create a new one', | 208 | 'Select an existing Juju environment or create a new one', |
562 | 200 | self.app.get_title()) | 209 | self.app.get_title()) |
563 | @@ -203,8 +212,7 @@ | |||
564 | 203 | # The application title changes if the env_db has no environments. | 212 | # The application title changes if the env_db has no environments. |
565 | 204 | env_db = {'environments': {}} | 213 | env_db = {'environments': {}} |
566 | 205 | jenv_db = helpers.make_jenv_db() | 214 | jenv_db = helpers.make_jenv_db() |
569 | 206 | views.env_index( | 215 | views.env_index(self.app, self.make_params(env_db, jenv_db)) |
568 | 207 | self.app, self.env_type_db, env_db, jenv_db, self.save_callable) | ||
570 | 208 | self.assertEqual( | 216 | self.assertEqual( |
571 | 209 | 'No Juju environments already set up: please create one', | 217 | 'No Juju environments already set up: please create one', |
572 | 210 | self.app.get_title()) | 218 | self.app.get_title()) |
573 | @@ -215,9 +223,7 @@ | |||
574 | 215 | env_db = helpers.make_env_db() | 223 | env_db = helpers.make_env_db() |
575 | 216 | jenv_db = {'environments': {}} | 224 | jenv_db = {'environments': {}} |
576 | 217 | with local_envs_supported(True): | 225 | with local_envs_supported(True): |
580 | 218 | views.env_index( | 226 | views.env_index(self.app, self.make_params(env_db, jenv_db)) |
578 | 219 | self.app, self.env_type_db, env_db, jenv_db, | ||
579 | 220 | self.save_callable) | ||
581 | 221 | buttons = self.get_widgets_in_contents( | 227 | buttons = self.get_widgets_in_contents( |
582 | 222 | filter_function=self.is_a(ui.MenuButton)) | 228 | filter_function=self.is_a(ui.MenuButton)) |
583 | 223 | # A button is created for each existing environment (see details) and | 229 | # A button is created for each existing environment (see details) and |
584 | @@ -232,9 +238,7 @@ | |||
585 | 232 | env_db = {'environments': {}} | 238 | env_db = {'environments': {}} |
586 | 233 | jenv_db = helpers.make_jenv_db() | 239 | jenv_db = helpers.make_jenv_db() |
587 | 234 | with local_envs_supported(True): | 240 | with local_envs_supported(True): |
591 | 235 | views.env_index( | 241 | views.env_index(self.app, self.make_params(env_db, jenv_db)) |
589 | 236 | self.app, self.env_type_db, env_db, jenv_db, | ||
590 | 237 | self.save_callable) | ||
592 | 238 | buttons = self.get_widgets_in_contents( | 242 | buttons = self.get_widgets_in_contents( |
593 | 239 | filter_function=self.is_a(ui.MenuButton)) | 243 | filter_function=self.is_a(ui.MenuButton)) |
594 | 240 | # A button is created for each existing environment (see details) and | 244 | # A button is created for each existing environment (see details) and |
595 | @@ -249,6 +253,20 @@ | |||
596 | 249 | 1 | 253 | 1 |
597 | 250 | ) | 254 | ) |
598 | 251 | self.assertEqual(expected_buttons_number, len(buttons)) | 255 | self.assertEqual(expected_buttons_number, len(buttons)) |
599 | 256 | # A text widget is displayed as header for the imported environments. | ||
600 | 257 | widgets = self.get_widgets_in_contents( | ||
601 | 258 | filter_function=self.is_a(urwid.Text)) | ||
602 | 259 | self.assertEqual(self.active_environments_message, widgets[2].text) | ||
603 | 260 | |||
604 | 261 | def test_view_contents_without_imported_envs(self): | ||
605 | 262 | # If there are no active imported environments the corresponding | ||
606 | 263 | # header text is not displayed. | ||
607 | 264 | env_db = jenv_db = {'environments': {}} | ||
608 | 265 | views.env_index(self.app, self.make_params(env_db, jenv_db)) | ||
609 | 266 | widgets = self.get_widgets_in_contents( | ||
610 | 267 | filter_function=self.is_a(urwid.Text)) | ||
611 | 268 | texts = [widget.text for widget in widgets] | ||
612 | 269 | self.assertNotIn(self.active_environments_message, texts) | ||
613 | 252 | 270 | ||
614 | 253 | def test_new_local_environment_disabled(self): | 271 | def test_new_local_environment_disabled(self): |
615 | 254 | # The option to create a new local environment is not present if they | 272 | # The option to create a new local environment is not present if they |
616 | @@ -256,9 +274,7 @@ | |||
617 | 256 | env_db = helpers.make_env_db() | 274 | env_db = helpers.make_env_db() |
618 | 257 | jenv_db = helpers.make_jenv_db() | 275 | jenv_db = helpers.make_jenv_db() |
619 | 258 | with local_envs_supported(False): | 276 | with local_envs_supported(False): |
623 | 259 | views.env_index( | 277 | views.env_index(self.app, self.make_params(env_db, jenv_db)) |
621 | 260 | self.app, self.env_type_db, env_db, jenv_db, | ||
622 | 261 | self.save_callable) | ||
624 | 262 | buttons = self.get_widgets_in_contents( | 278 | buttons = self.get_widgets_in_contents( |
625 | 263 | filter_function=self.is_a(ui.MenuButton)) | 279 | filter_function=self.is_a(ui.MenuButton)) |
626 | 264 | captions = map(cli_helpers.get_button_caption, buttons) | 280 | captions = map(cli_helpers.get_button_caption, buttons) |
627 | @@ -273,8 +289,8 @@ | |||
628 | 273 | # The environment detail view is called when clicking an environment. | 289 | # The environment detail view is called when clicking an environment. |
629 | 274 | env_db = helpers.make_env_db() | 290 | env_db = helpers.make_env_db() |
630 | 275 | jenv_db = {'environments': {}} | 291 | jenv_db = {'environments': {}} |
633 | 276 | views.env_index( | 292 | params = self.make_params(env_db, jenv_db) |
634 | 277 | self.app, self.env_type_db, env_db, jenv_db, self.save_callable) | 293 | views.env_index(self.app, params) |
635 | 278 | buttons = self.get_widgets_in_contents( | 294 | buttons = self.get_widgets_in_contents( |
636 | 279 | filter_function=self.is_a(ui.MenuButton)) | 295 | filter_function=self.is_a(ui.MenuButton)) |
637 | 280 | # The environments are listed in alphabetical order. | 296 | # The environments are listed in alphabetical order. |
638 | @@ -288,9 +304,7 @@ | |||
639 | 288 | # When the button is clicked, the detail view is called passing the | 304 | # When the button is clicked, the detail view is called passing the |
640 | 289 | # corresponding environment data. | 305 | # corresponding environment data. |
641 | 290 | cli_helpers.emit(button) | 306 | cli_helpers.emit(button) |
645 | 291 | mock_env_detail.assert_called_once_with( | 307 | mock_env_detail.assert_called_once_with(self.app, params, env_data) |
643 | 292 | self.app, self.env_type_db, env_db, jenv_db, | ||
644 | 293 | self.save_callable, env_data) | ||
646 | 294 | # Reset the mock so that it does not include any calls on the next | 308 | # Reset the mock so that it does not include any calls on the next |
647 | 295 | # loop cycle. | 309 | # loop cycle. |
648 | 296 | mock_env_detail.reset_mock() | 310 | mock_env_detail.reset_mock() |
649 | @@ -300,10 +314,9 @@ | |||
650 | 300 | # The jenv detail view is called when clicking an imported environment. | 314 | # The jenv detail view is called when clicking an imported environment. |
651 | 301 | env_db = {'environments': {}} | 315 | env_db = {'environments': {}} |
652 | 302 | jenv_db = helpers.make_jenv_db() | 316 | jenv_db = helpers.make_jenv_db() |
653 | 317 | params = self.make_params(env_db, jenv_db) | ||
654 | 303 | with local_envs_supported(False): | 318 | with local_envs_supported(False): |
658 | 304 | views.env_index( | 319 | views.env_index(self.app, params) |
656 | 305 | self.app, self.env_type_db, env_db, jenv_db, | ||
657 | 306 | self.save_callable) | ||
659 | 307 | buttons = self.get_widgets_in_contents( | 320 | buttons = self.get_widgets_in_contents( |
660 | 308 | filter_function=self.is_a(ui.MenuButton)) | 321 | filter_function=self.is_a(ui.MenuButton)) |
661 | 309 | # The environments are listed in alphabetical order. | 322 | # The environments are listed in alphabetical order. |
662 | @@ -318,8 +331,7 @@ | |||
663 | 318 | # passing the corresponding environment data. | 331 | # passing the corresponding environment data. |
664 | 319 | cli_helpers.emit(button) | 332 | cli_helpers.emit(button) |
665 | 320 | mock_jenv_detail.assert_called_once_with( | 333 | mock_jenv_detail.assert_called_once_with( |
668 | 321 | self.app, self.env_type_db, env_db, jenv_db, | 334 | self.app, params, env_data) |
667 | 322 | self.save_callable, env_data) | ||
669 | 323 | # Reset the mock so that it does not include any calls on the next | 335 | # Reset the mock so that it does not include any calls on the next |
670 | 324 | # loop cycle. | 336 | # loop cycle. |
671 | 325 | mock_jenv_detail.reset_mock() | 337 | mock_jenv_detail.reset_mock() |
672 | @@ -330,10 +342,9 @@ | |||
673 | 330 | # environment. | 342 | # environment. |
674 | 331 | env_db = helpers.make_env_db() | 343 | env_db = helpers.make_env_db() |
675 | 332 | jenv_db = {'environments': {}} | 344 | jenv_db = {'environments': {}} |
676 | 345 | params = self.make_params(env_db, jenv_db) | ||
677 | 333 | with local_envs_supported(True): | 346 | with local_envs_supported(True): |
681 | 334 | views.env_index( | 347 | views.env_index(self.app, params) |
679 | 335 | self.app, self.env_type_db, env_db, jenv_db, | ||
680 | 336 | self.save_callable) | ||
682 | 337 | buttons = self.get_widgets_in_contents( | 348 | buttons = self.get_widgets_in_contents( |
683 | 338 | filter_function=self.is_a(ui.MenuButton)) | 349 | filter_function=self.is_a(ui.MenuButton)) |
684 | 339 | env_types = envs.get_supported_env_types(self.env_type_db) | 350 | env_types = envs.get_supported_env_types(self.env_type_db) |
685 | @@ -347,8 +358,7 @@ | |||
686 | 347 | # corresponding environment data. | 358 | # corresponding environment data. |
687 | 348 | cli_helpers.emit(button) | 359 | cli_helpers.emit(button) |
688 | 349 | mock_env_edit.assert_called_once_with( | 360 | mock_env_edit.assert_called_once_with( |
691 | 350 | self.app, self.env_type_db, env_db, jenv_db, | 361 | self.app, params, { |
690 | 351 | self.save_callable, { | ||
692 | 352 | 'type': env_type, | 362 | 'type': env_type, |
693 | 353 | 'default-series': settings.JUJU_GUI_SUPPORTED_SERIES[-1], | 363 | 'default-series': settings.JUJU_GUI_SUPPORTED_SERIES[-1], |
694 | 354 | }) | 364 | }) |
695 | @@ -365,9 +375,7 @@ | |||
696 | 365 | jenv_db = helpers.make_jenv_db() | 375 | jenv_db = helpers.make_jenv_db() |
697 | 366 | with maas_env_detected(False): | 376 | with maas_env_detected(False): |
698 | 367 | with local_envs_supported(True): | 377 | with local_envs_supported(True): |
702 | 368 | views.env_index( | 378 | views.env_index(self.app, self.make_params(env_db, jenv_db)) |
700 | 369 | self.app, self.env_type_db, env_db, jenv_db, | ||
701 | 370 | self.save_callable) | ||
703 | 371 | buttons = self.get_widgets_in_contents( | 379 | buttons = self.get_widgets_in_contents( |
704 | 372 | filter_function=self.is_a(ui.MenuButton)) | 380 | filter_function=self.is_a(ui.MenuButton)) |
705 | 373 | # The "create and bootstrap" button is the first one in the contents. | 381 | # The "create and bootstrap" button is the first one in the contents. |
706 | @@ -390,9 +398,7 @@ | |||
707 | 390 | env_db = envs.create_empty_env_db() | 398 | env_db = envs.create_empty_env_db() |
708 | 391 | jenv_db = helpers.make_jenv_db() | 399 | jenv_db = helpers.make_jenv_db() |
709 | 392 | with local_envs_supported(False): | 400 | with local_envs_supported(False): |
713 | 393 | views.env_index( | 401 | views.env_index(self.app, self.make_params(env_db, jenv_db)) |
711 | 394 | self.app, self.env_type_db, env_db, jenv_db, | ||
712 | 395 | self.save_callable) | ||
714 | 396 | buttons = self.get_widgets_in_contents( | 402 | buttons = self.get_widgets_in_contents( |
715 | 397 | filter_function=self.is_a(ui.MenuButton)) | 403 | filter_function=self.is_a(ui.MenuButton)) |
716 | 398 | # No "create and bootstrap local" buttons are present. | 404 | # No "create and bootstrap local" buttons are present. |
717 | @@ -408,9 +414,7 @@ | |||
718 | 408 | env_db = envs.create_empty_env_db() | 414 | env_db = envs.create_empty_env_db() |
719 | 409 | jenv_db = helpers.make_jenv_db() | 415 | jenv_db = helpers.make_jenv_db() |
720 | 410 | with maas_env_detected(True): | 416 | with maas_env_detected(True): |
724 | 411 | views.env_index( | 417 | views.env_index(self.app, self.make_params(env_db, jenv_db)) |
722 | 412 | self.app, self.env_type_db, env_db, jenv_db, | ||
723 | 413 | self.save_callable) | ||
725 | 414 | buttons = self.get_widgets_in_contents( | 418 | buttons = self.get_widgets_in_contents( |
726 | 415 | filter_function=self.is_a(ui.MenuButton)) | 419 | filter_function=self.is_a(ui.MenuButton)) |
727 | 416 | # The "create and bootstrap" button is the first one in the contents. | 420 | # The "create and bootstrap" button is the first one in the contents. |
728 | @@ -433,9 +437,7 @@ | |||
729 | 433 | env_db = envs.create_empty_env_db() | 437 | env_db = envs.create_empty_env_db() |
730 | 434 | jenv_db = helpers.make_jenv_db() | 438 | jenv_db = helpers.make_jenv_db() |
731 | 435 | with maas_env_detected(False): | 439 | with maas_env_detected(False): |
735 | 436 | views.env_index( | 440 | views.env_index(self.app, self.make_params(env_db, jenv_db)) |
733 | 437 | self.app, self.env_type_db, env_db, jenv_db, | ||
734 | 438 | self.save_callable) | ||
736 | 439 | buttons = self.get_widgets_in_contents( | 441 | buttons = self.get_widgets_in_contents( |
737 | 440 | filter_function=self.is_a(ui.MenuButton)) | 442 | filter_function=self.is_a(ui.MenuButton)) |
738 | 441 | # No "create and bootstrap MAAS" buttons are present. | 443 | # No "create and bootstrap MAAS" buttons are present. |
739 | @@ -446,8 +448,7 @@ | |||
740 | 446 | # The default environment is already selected in the list. | 448 | # The default environment is already selected in the list. |
741 | 447 | env_db = helpers.make_env_db(default='lxc') | 449 | env_db = helpers.make_env_db(default='lxc') |
742 | 448 | jenv_db = helpers.make_jenv_db() | 450 | jenv_db = helpers.make_jenv_db() |
745 | 449 | views.env_index( | 451 | views.env_index(self.app, self.make_params(env_db, jenv_db)) |
744 | 450 | self.app, self.env_type_db, env_db, jenv_db, self.save_callable) | ||
746 | 451 | env_data = envs.get_env_data(env_db, 'lxc') | 452 | env_data = envs.get_env_data(env_db, 'lxc') |
747 | 452 | env_description = envs.get_env_short_description(env_data) | 453 | env_description = envs.get_env_short_description(env_data) |
748 | 453 | contents = self.app.get_contents() | 454 | contents = self.app.get_contents() |
749 | @@ -460,8 +461,7 @@ | |||
750 | 460 | # The status message explains how errors are displayed. | 461 | # The status message explains how errors are displayed. |
751 | 461 | env_db = helpers.make_env_db() | 462 | env_db = helpers.make_env_db() |
752 | 462 | jenv_db = {'environments': {}} | 463 | jenv_db = {'environments': {}} |
755 | 463 | views.env_index( | 464 | views.env_index(self.app, self.make_params(env_db, jenv_db)) |
754 | 464 | self.app, self.env_type_db, env_db, jenv_db, self.save_callable) | ||
756 | 465 | status = self.app.get_status() | 465 | status = self.app.get_status() |
757 | 466 | self.assertEqual(self.base_status + ' \N{BULLET} has errors ', status) | 466 | self.assertEqual(self.base_status + ' \N{BULLET} has errors ', status) |
758 | 467 | 467 | ||
759 | @@ -469,8 +469,7 @@ | |||
760 | 469 | # The status message explains how default environment is represented. | 469 | # The status message explains how default environment is represented. |
761 | 470 | env_db = helpers.make_env_db(default='lxc', exclude_invalid=True) | 470 | env_db = helpers.make_env_db(default='lxc', exclude_invalid=True) |
762 | 471 | jenv_db = {'environments': {}} | 471 | jenv_db = {'environments': {}} |
765 | 472 | views.env_index( | 472 | views.env_index(self.app, self.make_params(env_db, jenv_db)) |
764 | 473 | self.app, self.env_type_db, env_db, jenv_db, self.save_callable) | ||
766 | 474 | status = self.app.get_status() | 473 | status = self.app.get_status() |
767 | 475 | self.assertEqual(self.base_status + ' \N{CHECK MARK} default ', status) | 474 | self.assertEqual(self.base_status + ' \N{CHECK MARK} default ', status) |
768 | 476 | 475 | ||
769 | @@ -478,8 +477,7 @@ | |||
770 | 478 | # The status message explains how active environments are displayed. | 477 | # The status message explains how active environments are displayed. |
771 | 479 | env_db = helpers.make_env_db(exclude_invalid=True) | 478 | env_db = helpers.make_env_db(exclude_invalid=True) |
772 | 480 | jenv_db = helpers.make_jenv_db() | 479 | jenv_db = helpers.make_jenv_db() |
775 | 481 | views.env_index( | 480 | views.env_index(self.app, self.make_params(env_db, jenv_db)) |
774 | 482 | self.app, self.env_type_db, env_db, jenv_db, self.save_callable) | ||
776 | 483 | status = self.app.get_status() | 481 | status = self.app.get_status() |
777 | 484 | self.assertEqual(self.base_status + ' \N{BULLET} active ', status) | 482 | self.assertEqual(self.base_status + ' \N{BULLET} active ', status) |
778 | 485 | 483 | ||
779 | @@ -487,8 +485,7 @@ | |||
780 | 487 | # The status message includes default, active and errors explanations. | 485 | # The status message includes default, active and errors explanations. |
781 | 488 | env_db = helpers.make_env_db(default='lxc') | 486 | env_db = helpers.make_env_db(default='lxc') |
782 | 489 | jenv_db = helpers.make_jenv_db() | 487 | jenv_db = helpers.make_jenv_db() |
785 | 490 | views.env_index( | 488 | views.env_index(self.app, self.make_params(env_db, jenv_db)) |
784 | 491 | self.app, self.env_type_db, env_db, jenv_db, self.save_callable) | ||
786 | 492 | status = self.app.get_status() | 489 | status = self.app.get_status() |
787 | 493 | self.assertEqual( | 490 | self.assertEqual( |
788 | 494 | self.base_status + | 491 | self.base_status + |
789 | @@ -501,8 +498,7 @@ | |||
790 | 501 | # The status only includes navigation info if there are no errors. | 498 | # The status only includes navigation info if there are no errors. |
791 | 502 | env_db = helpers.make_env_db(exclude_invalid=True) | 499 | env_db = helpers.make_env_db(exclude_invalid=True) |
792 | 503 | jenv_db = {'environments': {}} | 500 | jenv_db = {'environments': {}} |
795 | 504 | views.env_index( | 501 | views.env_index(self.app, self.make_params(env_db, jenv_db)) |
794 | 505 | self.app, self.env_type_db, env_db, jenv_db, self.save_callable) | ||
796 | 506 | status = self.app.get_status() | 502 | status = self.app.get_status() |
797 | 507 | self.assertEqual(self.base_status, status) | 503 | self.assertEqual(self.base_status, status) |
798 | 508 | 504 | ||
799 | @@ -516,9 +512,8 @@ | |||
800 | 516 | def call_view(self, env_name='lxc'): | 512 | def call_view(self, env_name='lxc'): |
801 | 517 | """Call the view passing the env_data corresponding to env_name.""" | 513 | """Call the view passing the env_data corresponding to env_name.""" |
802 | 518 | self.env_data = envs.get_env_data(self.env_db, env_name) | 514 | self.env_data = envs.get_env_data(self.env_db, env_name) |
806 | 519 | return views.env_detail( | 515 | self.params = self.make_params(self.env_db, self.jenv_db) |
807 | 520 | self.app, self.env_type_db, self.env_db, self.jenv_db, | 516 | return views.env_detail(self.app, self.params, self.env_data) |
805 | 521 | self.save_callable, self.env_data) | ||
808 | 522 | 517 | ||
809 | 523 | def test_view_default_return_value_on_exit(self): | 518 | def test_view_default_return_value_on_exit(self): |
810 | 524 | # The view configures the app so that the return value on user exit is | 519 | # The view configures the app so that the return value on user exit is |
811 | @@ -584,9 +579,7 @@ | |||
812 | 584 | # The "back" button is the first one. | 579 | # The "back" button is the first one. |
813 | 585 | back_button = self.get_control_buttons()[0] | 580 | back_button = self.get_control_buttons()[0] |
814 | 586 | cli_helpers.emit(back_button) | 581 | cli_helpers.emit(back_button) |
818 | 587 | mock_env_index.assert_called_once_with( | 582 | mock_env_index.assert_called_once_with(self.app, self.params) |
816 | 588 | self.app, self.env_type_db, self.env_db, self.jenv_db, | ||
817 | 589 | self.save_callable) | ||
819 | 590 | 583 | ||
820 | 591 | def test_use_button(self): | 584 | def test_use_button(self): |
821 | 592 | # The application exits if the "use" button is clicked. | 585 | # The application exits if the "use" button is clicked. |
822 | @@ -608,14 +601,13 @@ | |||
823 | 608 | # The "set default" button is the third one. | 601 | # The "set default" button is the third one. |
824 | 609 | set_default_button = self.get_control_buttons()[2] | 602 | set_default_button = self.get_control_buttons()[2] |
825 | 610 | cli_helpers.emit(set_default_button) | 603 | cli_helpers.emit(set_default_button) |
828 | 611 | # The index view has been called passing the modified env_db as third | 604 | # The index view has been called passing the modified env_db in params. |
827 | 612 | # argument. | ||
829 | 613 | self.assertTrue(mock_env_index.called) | 605 | self.assertTrue(mock_env_index.called) |
831 | 614 | new_env_db = mock_env_index.call_args[0][2] | 606 | params = mock_env_index.call_args[0][1] |
832 | 615 | # The new env_db has a new default. | 607 | # The new env_db has a new default. |
834 | 616 | self.assertEqual(new_env_db['default'], 'ec2-west') | 608 | self.assertEqual(params.env_db['default'], 'ec2-west') |
835 | 617 | # The new env_db has been saved. | 609 | # The new env_db has been saved. |
837 | 618 | self.save_callable.assert_called_once_with(new_env_db) | 610 | self.save_callable.assert_called_once_with(params.env_db) |
838 | 619 | 611 | ||
839 | 620 | @mock.patch('quickstart.cli.views.env_edit') | 612 | @mock.patch('quickstart.cli.views.env_edit') |
840 | 621 | def test_edit_button(self, mock_env_edit): | 613 | def test_edit_button(self, mock_env_edit): |
841 | @@ -625,8 +617,7 @@ | |||
842 | 625 | edit_button = self.get_control_buttons()[3] | 617 | edit_button = self.get_control_buttons()[3] |
843 | 626 | cli_helpers.emit(edit_button) | 618 | cli_helpers.emit(edit_button) |
844 | 627 | mock_env_edit.assert_called_once_with( | 619 | mock_env_edit.assert_called_once_with( |
847 | 628 | self.app, self.env_type_db, self.env_db, self.jenv_db, | 620 | self.app, self.params, self.env_data) |
846 | 629 | self.save_callable, self.env_data) | ||
848 | 630 | 621 | ||
849 | 631 | def test_remove_button(self): | 622 | def test_remove_button(self): |
850 | 632 | # A confirmation dialog is displayed if the "remove" button is clicked. | 623 | # A confirmation dialog is displayed if the "remove" button is clicked. |
851 | @@ -677,14 +668,13 @@ | |||
852 | 677 | # The "confirm" button is the second one in the dialog. | 668 | # The "confirm" button is the second one in the dialog. |
853 | 678 | confirm_button = buttons[1] | 669 | confirm_button = buttons[1] |
854 | 679 | cli_helpers.emit(confirm_button) | 670 | cli_helpers.emit(confirm_button) |
857 | 680 | # The index view has been called passing the modified env_db as third | 671 | # The index view has been called passing the modified env_db in params. |
856 | 681 | # argument. | ||
858 | 682 | self.assertTrue(mock_env_index.called) | 672 | self.assertTrue(mock_env_index.called) |
860 | 683 | new_env_db = mock_env_index.call_args[0][2] | 673 | params = mock_env_index.call_args[0][1] |
861 | 684 | # The new env_db no longer includes the "ec2-west" environment. | 674 | # The new env_db no longer includes the "ec2-west" environment. |
863 | 685 | self.assertNotIn('ec2-west', new_env_db['environments']) | 675 | self.assertNotIn('ec2-west', params.env_db['environments']) |
864 | 686 | # The new env_db has been saved. | 676 | # The new env_db has been saved. |
866 | 687 | self.save_callable.assert_called_once_with(new_env_db) | 677 | self.save_callable.assert_called_once_with(params.env_db) |
867 | 688 | 678 | ||
868 | 689 | def test_status_with_errors(self): | 679 | def test_status_with_errors(self): |
869 | 690 | # The status message explains how field errors are displayed. | 680 | # The status message explains how field errors are displayed. |
870 | @@ -709,9 +699,8 @@ | |||
871 | 709 | def call_view(self, env_name='lxc'): | 699 | def call_view(self, env_name='lxc'): |
872 | 710 | """Call the view passing the env_data corresponding to env_name.""" | 700 | """Call the view passing the env_data corresponding to env_name.""" |
873 | 711 | self.env_data = envs.get_env_data(self.jenv_db, env_name) | 701 | self.env_data = envs.get_env_data(self.jenv_db, env_name) |
877 | 712 | return views.jenv_detail( | 702 | self.params = self.make_params(self.env_db, self.jenv_db) |
878 | 713 | self.app, self.env_type_db, self.env_db, self.jenv_db, | 703 | return views.jenv_detail(self.app, self.params, self.env_data) |
876 | 714 | self.save_callable, self.env_data) | ||
879 | 715 | 704 | ||
880 | 716 | def test_view_default_return_value_on_exit(self): | 705 | def test_view_default_return_value_on_exit(self): |
881 | 717 | # The view configures the app so that the return value on user exit is | 706 | # The view configures the app so that the return value on user exit is |
882 | @@ -756,9 +745,7 @@ | |||
883 | 756 | # The "back" button is the first one. | 745 | # The "back" button is the first one. |
884 | 757 | back_button = self.get_control_buttons()[0] | 746 | back_button = self.get_control_buttons()[0] |
885 | 758 | cli_helpers.emit(back_button) | 747 | cli_helpers.emit(back_button) |
889 | 759 | mock_env_index.assert_called_once_with( | 748 | mock_env_index.assert_called_once_with(self.app, self.params) |
887 | 760 | self.app, self.env_type_db, self.env_db, self.jenv_db, | ||
888 | 761 | self.save_callable) | ||
890 | 762 | 749 | ||
891 | 763 | def test_use_button(self): | 750 | def test_use_button(self): |
892 | 764 | # The application exits if the "use" button is clicked. | 751 | # The application exits if the "use" button is clicked. |
893 | @@ -788,9 +775,8 @@ | |||
894 | 788 | self.env_data = envs.get_env_data(self.env_db, env_name) | 775 | self.env_data = envs.get_env_data(self.env_db, env_name) |
895 | 789 | else: | 776 | else: |
896 | 790 | self.env_data = {'type': env_type} | 777 | self.env_data = {'type': env_type} |
900 | 791 | return views.env_edit( | 778 | self.params = self.make_params(self.env_db, self.jenv_db) |
901 | 792 | self.app, self.env_type_db, self.env_db, self.jenv_db, | 779 | return views.env_edit(self.app, self.params, self.env_data) |
899 | 793 | self.save_callable, self.env_data) | ||
902 | 794 | 780 | ||
903 | 795 | def get_form_contents(self): | 781 | def get_form_contents(self): |
904 | 796 | """Return the form contents included in the app page. | 782 | """Return the form contents included in the app page. |
905 | @@ -925,8 +911,7 @@ | |||
906 | 925 | 'ec2-west successfully modified', self.app.get_message()) | 911 | 'ec2-west successfully modified', self.app.get_message()) |
907 | 926 | # The application displays the environment detail view. | 912 | # The application displays the environment detail view. |
908 | 927 | mock_env_detail.assert_called_once_with( | 913 | mock_env_detail.assert_called_once_with( |
911 | 928 | self.app, self.env_type_db, self.env_db, self.jenv_db, | 914 | self.app, self.params, new_env_data) |
910 | 929 | self.save_callable, new_env_data) | ||
912 | 930 | 915 | ||
913 | 931 | @mock.patch('quickstart.cli.views.env_detail') | 916 | @mock.patch('quickstart.cli.views.env_detail') |
914 | 932 | def test_save_empty_db(self, mock_env_detail): | 917 | def test_save_empty_db(self, mock_env_detail): |
915 | @@ -945,8 +930,7 @@ | |||
916 | 945 | expected_new_env_data.update({'type': 'local', 'is-default': True}) | 930 | expected_new_env_data.update({'type': 'local', 'is-default': True}) |
917 | 946 | envs.set_env_data(self.env_db, None, expected_new_env_data) | 931 | envs.set_env_data(self.env_db, None, expected_new_env_data) |
918 | 947 | mock_env_detail.assert_called_once_with( | 932 | mock_env_detail.assert_called_once_with( |
921 | 948 | self.app, self.env_type_db, self.env_db, self.jenv_db, | 933 | self.app, self.params, expected_new_env_data) |
920 | 949 | self.save_callable, expected_new_env_data) | ||
922 | 950 | 934 | ||
923 | 951 | def test_save_invalid_form_data(self): | 935 | def test_save_invalid_form_data(self): |
924 | 952 | # Errors are displayed if the user tries to save invalid data. | 936 | # Errors are displayed if the user tries to save invalid data. |
925 | @@ -990,9 +974,7 @@ | |||
926 | 990 | # The "cancel" button is the second one. | 974 | # The "cancel" button is the second one. |
927 | 991 | cancel_button = self.get_control_buttons()[1] | 975 | cancel_button = self.get_control_buttons()[1] |
928 | 992 | cli_helpers.emit(cancel_button) | 976 | cli_helpers.emit(cancel_button) |
932 | 993 | mock_env_index.assert_called_once_with( | 977 | mock_env_index.assert_called_once_with(self.app, self.params) |
930 | 994 | self.app, self.env_type_db, self.env_db, self.jenv_db, | ||
931 | 995 | self.save_callable) | ||
933 | 996 | 978 | ||
934 | 997 | @mock.patch('quickstart.cli.views.env_detail') | 979 | @mock.patch('quickstart.cli.views.env_detail') |
935 | 998 | def test_modification_view_cancel_button(self, mock_env_detail): | 980 | def test_modification_view_cancel_button(self, mock_env_detail): |
936 | @@ -1003,5 +985,4 @@ | |||
937 | 1003 | cancel_button = self.get_control_buttons()[1] | 985 | cancel_button = self.get_control_buttons()[1] |
938 | 1004 | cli_helpers.emit(cancel_button) | 986 | cli_helpers.emit(cancel_button) |
939 | 1005 | mock_env_detail.assert_called_once_with( | 987 | mock_env_detail.assert_called_once_with( |
942 | 1006 | self.app, self.env_type_db, self.env_db, self.jenv_db, | 988 | self.app, self.params, self.env_data) |
941 | 1007 | self.save_callable, self.env_data) | ||
943 | 1008 | 989 | ||
944 | === modified file 'quickstart/tests/test_manage.py' | |||
945 | --- quickstart/tests/test_manage.py 2014-12-16 16:52:49 +0000 | |||
946 | +++ quickstart/tests/test_manage.py 2015-01-07 16:46:42 +0000 | |||
947 | @@ -35,7 +35,10 @@ | |||
948 | 35 | manage, | 35 | manage, |
949 | 36 | settings, | 36 | settings, |
950 | 37 | ) | 37 | ) |
952 | 38 | from quickstart.cli import views | 38 | from quickstart.cli import ( |
953 | 39 | params, | ||
954 | 40 | views, | ||
955 | 41 | ) | ||
956 | 39 | from quickstart.models import ( | 42 | from quickstart.models import ( |
957 | 40 | envs, | 43 | envs, |
958 | 41 | jenv, | 44 | jenv, |
959 | @@ -391,9 +394,13 @@ | |||
960 | 391 | with mock.patch('quickstart.manage.views.show', mock_show): | 394 | with mock.patch('quickstart.manage.views.show', mock_show): |
961 | 392 | yield | 395 | yield |
962 | 393 | mock_save_callable.assert_called_once_with(self.parser, self.env_file) | 396 | mock_save_callable.assert_called_once_with(self.parser, self.env_file) |
966 | 394 | mock_show.assert_called_once_with( | 397 | expected_params = params.Params( |
967 | 395 | views.env_index, self.env_type_db, env_db, jenv_db, | 398 | env_type_db=self.env_type_db, |
968 | 396 | mock_save_callable()) | 399 | env_db=env_db, |
969 | 400 | jenv_db=jenv_db, | ||
970 | 401 | save_callable=mock_save_callable(), | ||
971 | 402 | ) | ||
972 | 403 | mock_show.assert_called_once_with(views.env_index, expected_params) | ||
973 | 397 | 404 | ||
974 | 398 | def test_resulting_env_data(self): | 405 | def test_resulting_env_data(self): |
975 | 399 | # The interactive session can be used to select an environment, in | 406 | # The interactive session can be used to select an environment, in |
Reviewers: mp+245753_ code.launchpad. net,
Message:
Please take a look.
Description:
Refactor view parameters.
Implement a Params object used to store
common view parameters. This way it will
be easier to add parameters in the future
(e.g. one callable to remove stale jenv files).
New code include the params module and a fix
to the code handling the listing of jenv files
in the index view: now the header message is
only displayed if jenv files actually exist.
The rest of the diff is mechanical: i.e. replacing
the single view arguments with the params named
tuple.
Tests: `make check`.
QA:
Use the quickstart interactive session and
check everything works ok.
https:/ /code.launchpad .net/~frankban/ juju-quickstart /views- params/ +merge/ 245753
(do not edit description out of merge proposal)
Please review this at https:/ /codereview. appspot. com/194030043/
Affected files (+303, -172 lines): cli/params. py cli/views. py manage. py tests/cli/ test_params. py tests/cli/ test_views. py tests/test_ manage. py
A [revision details]
A quickstart/
M quickstart/
M quickstart/
A quickstart/
M quickstart/
M quickstart/