Merge lp:~ack/landscape-client/refactor-prompt-functions into lp:~landscape/landscape-client/trunk

Proposed by Alberto Donato
Status: Merged
Approved by: Alberto Donato
Approved revision: 943
Merged at revision: 938
Proposed branch: lp:~ack/landscape-client/refactor-prompt-functions
Merge into: lp:~landscape/landscape-client/trunk
Diff against target: 807 lines (+190/-168)
2 files modified
landscape/configuration.py (+52/-47)
landscape/tests/test_configuration.py (+138/-121)
To merge this branch: bzr merge lp:~ack/landscape-client/refactor-prompt-functions
Reviewer Review Type Date Requested Status
Bogdana Vereha (community) Approve
Free Ekanayaka (community) Approve
🤖 Landscape Builder test results Approve
Review via email: mp+318905@code.launchpad.net

Commit message

Purely refactoring branch, it moves prompt_yes_no and show_help functions out of the script class, and reuse prompt_yes_no instead of duplicated code.

Description of the change

Purely refactoring branch, it moves prompt_yes_no and show_help functions out of the script class, and reuse prompt_yes_no instead of duplicated code.

Diff is big because of mock changes in tests.

Testing instructions:

run unittests

To post a comment you must log in.
Revision history for this message
🤖 Landscape Builder (landscape-builder) :
review: Abstain (executing tests)
Revision history for this message
🤖 Landscape Builder (landscape-builder) wrote :

Command: TRIAL_ARGS=-j4 make check
Result: Success
Revno: 943
Branch: lp:~ack/landscape-client/refactor-prompt-functions
Jenkins: https://ci.lscape.net/job/latch-test-precise/870/

review: Approve (test results)
Revision history for this message
Free Ekanayaka (free.ekanayaka) wrote :

+1

review: Approve
Revision history for this message
Bogdana Vereha (bogdana) wrote :

+1

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'landscape/configuration.py'
--- landscape/configuration.py 2017-02-24 09:38:26 +0000
+++ landscape/configuration.py 2017-03-03 12:43:19 +0000
@@ -22,10 +22,13 @@
22from landscape.lib.twisted_util import gather_results22from landscape.lib.twisted_util import gather_results
23from landscape.lib.fetch import fetch, FetchError23from landscape.lib.fetch import fetch, FetchError
24from landscape.lib.bootstrap import BootstrapList, BootstrapDirectory24from landscape.lib.bootstrap import BootstrapList, BootstrapDirectory
25from landscape.lib.persist import Persist
25from landscape.reactor import LandscapeReactor26from landscape.reactor import LandscapeReactor
26from landscape.broker.registration import RegistrationError27from landscape.broker.registration import RegistrationError
27from landscape.broker.config import BrokerConfiguration28from landscape.broker.config import BrokerConfiguration
28from landscape.broker.amp import RemoteBrokerConnector29from landscape.broker.amp import RemoteBrokerConnector
30from landscape.broker.registration import Identity
31from landscape.broker.service import BrokerService
2932
3033
31class ConfigurationError(Exception):34class ConfigurationError(Exception):
@@ -47,6 +50,27 @@
47 stream.flush()50 stream.flush()
4851
4952
53def show_help(text):
54 """Display help text."""
55 lines = text.strip().splitlines()
56 print_text("\n" + "".join([line.strip() + "\n" for line in lines]))
57
58
59def prompt_yes_no(message, default=True):
60 """Prompt for a yes/no question and return the answer as bool."""
61 default_msg = "[Y/n]" if default else "[y/N]"
62 while True:
63 value = raw_input("{} {}: ".format(message, default_msg)).lower()
64 if value:
65 if value.startswith("n"):
66 return False
67 if value.startswith("y"):
68 return True
69 show_help("Invalid input.")
70 else:
71 return default
72
73
50def get_invalid_users(users):74def get_invalid_users(users):
51 """75 """
52 Process a string with a list of comma separated usernames, this returns76 Process a string with a list of comma separated usernames, this returns
@@ -183,10 +207,6 @@
183 def __init__(self, config):207 def __init__(self, config):
184 self.config = config208 self.config = config
185209
186 def show_help(self, text):
187 lines = text.strip().splitlines()
188 print_text("\n" + "".join([line.strip() + "\n" for line in lines]))
189
190 def prompt_get_input(self, msg, required):210 def prompt_get_input(self, msg, required):
191 """Prompt the user on the terminal for a value211 """Prompt the user on the terminal for a value
192212
@@ -199,7 +219,7 @@
199 return value219 return value
200 elif not required:220 elif not required:
201 break221 break
202 self.show_help("This option is required to configure Landscape.")222 show_help("This option is required to configure Landscape.")
203223
204 def prompt(self, option, msg, required=False):224 def prompt(self, option, msg, required=False):
205 """Prompt the user on the terminal for a value.225 """Prompt the user on the terminal for a value.
@@ -239,37 +259,20 @@
239 value2 = getpass.getpass("Please confirm: ")259 value2 = getpass.getpass("Please confirm: ")
240 if value:260 if value:
241 if value != value2:261 if value != value2:
242 self.show_help("Keys must match.")262 show_help("Keys must match.")
243 else:263 else:
244 setattr(self.config, option, value)264 setattr(self.config, option, value)
245 break265 break
246 elif default or not required:266 elif default or not required:
247 break267 break
248 else:268 else:
249 self.show_help("This option is required to configure "269 show_help("This option is required to configure Landscape.")
250 "Landscape.")
251
252 def prompt_yes_no(self, message, default=True):
253 if default:
254 default_msg = " [Y/n]"
255 else:
256 default_msg = " [y/N]"
257 while True:
258 value = raw_input(message + default_msg).lower()
259 if value:
260 if value.startswith("n"):
261 return False
262 if value.startswith("y"):
263 return True
264 self.show_help("Invalid input.")
265 else:
266 return default
267270
268 def query_computer_title(self):271 def query_computer_title(self):
269 if "computer_title" in self.config.get_command_line_options():272 if "computer_title" in self.config.get_command_line_options():
270 return273 return
271274
272 self.show_help(275 show_help(
273 """276 """
274 The computer title you provide will be used to represent this277 The computer title you provide will be used to represent this
275 computer in the Landscape user interface. It's important to use278 computer in the Landscape user interface. It's important to use
@@ -283,7 +286,7 @@
283 if "account_name" in self.config.get_command_line_options():286 if "account_name" in self.config.get_command_line_options():
284 return287 return
285288
286 self.show_help(289 show_help(
287 """290 """
288 You must now specify the name of the Landscape account you291 You must now specify the name of the Landscape account you
289 want to register this computer with. Your account name is shown292 want to register this computer with. Your account name is shown
@@ -297,7 +300,7 @@
297 if "registration_key" in command_line_options:300 if "registration_key" in command_line_options:
298 return301 return
299302
300 self.show_help(303 show_help(
301 """304 """
302 A registration key may be associated with your Landscape305 A registration key may be associated with your Landscape
303 account to prevent unauthorized registration attempts. This306 account to prevent unauthorized registration attempts. This
@@ -316,7 +319,7 @@
316 if "http_proxy" in options and "https_proxy" in options:319 if "http_proxy" in options and "https_proxy" in options:
317 return320 return
318321
319 self.show_help(322 show_help(
320 """323 """
321 The Landscape client communicates with the server over HTTP and324 The Landscape client communicates with the server over HTTP and
322 HTTPS. If your network requires you to use a proxy to access HTTP325 HTTPS. If your network requires you to use a proxy to access HTTP
@@ -337,7 +340,7 @@
337 raise ConfigurationError("Unknown system users: %s" %340 raise ConfigurationError("Unknown system users: %s" %
338 ", ".join(invalid_users))341 ", ".join(invalid_users))
339 return342 return
340 self.show_help(343 show_help(
341 """344 """
342 Landscape has a feature which enables administrators to run345 Landscape has a feature which enables administrators to run
343 arbitrary scripts on machines under their control. By default this346 arbitrary scripts on machines under their control. By default this
@@ -351,10 +354,10 @@
351 if included_plugins == [""]:354 if included_plugins == [""]:
352 included_plugins = []355 included_plugins = []
353 default = "ScriptExecution" in included_plugins356 default = "ScriptExecution" in included_plugins
354 if self.prompt_yes_no(msg, default=default):357 if prompt_yes_no(msg, default=default):
355 if "ScriptExecution" not in included_plugins:358 if "ScriptExecution" not in included_plugins:
356 included_plugins.append("ScriptExecution")359 included_plugins.append("ScriptExecution")
357 self.show_help(360 show_help(
358 """361 """
359 By default, scripts are restricted to the 'landscape' and362 By default, scripts are restricted to the 'landscape' and
360 'nobody' users. Please enter a comma-delimited list of users363 'nobody' users. Please enter a comma-delimited list of users
@@ -368,8 +371,8 @@
368 if not invalid_users:371 if not invalid_users:
369 break372 break
370 else:373 else:
371 self.show_help("Unknown system users: %s" %374 show_help("Unknown system users: {}".format(
372 ",".join(invalid_users))375 ",".join(invalid_users)))
373 self.config.script_users = None376 self.config.script_users = None
374 else:377 else:
375 if "ScriptExecution" in included_plugins:378 if "ScriptExecution" in included_plugins:
@@ -382,8 +385,9 @@
382 if "access_group" in options:385 if "access_group" in options:
383 return # an access group is already provided, don't ask for one386 return # an access group is already provided, don't ask for one
384387
385 self.show_help("You may provide an access group for this computer "388 show_help(
386 "e.g. webservers.")389 "You may provide an access group for this computer "
390 "e.g. webservers.")
387 self.prompt("access_group", "Access group", False)391 self.prompt("access_group", "Access group", False)
388392
389 def _get_invalid_tags(self, tagnames):393 def _get_invalid_tags(self, tagnames):
@@ -407,19 +411,19 @@
407 ", ".join(invalid_tags))411 ", ".join(invalid_tags))
408 return412 return
409413
410 self.show_help("You may provide tags for this computer e.g. "414 show_help(
411 "server,precise.")415 "You may provide tags for this computer e.g. server,precise.")
412 while True:416 while True:
413 self.prompt("tags", "Tags", False)417 self.prompt("tags", "Tags", False)
414 if self._get_invalid_tags(self.config.tags):418 if self._get_invalid_tags(self.config.tags):
415 self.show_help("Tag names may only contain alphanumeric "419 show_help(
416 "characters.")420 "Tag names may only contain alphanumeric characters.")
417 self.config.tags = None # Reset for the next prompt421 self.config.tags = None # Reset for the next prompt
418 else:422 else:
419 break423 break
420424
421 def show_header(self):425 def show_header(self):
422 self.show_help(426 show_help(
423 """427 """
424 This script will interactively set up the Landscape client. It will428 This script will interactively set up the Landscape client. It will
425 ask you a few questions about this computer and your Landscape429 ask you a few questions about this computer and your Landscape
@@ -526,10 +530,11 @@
526 if config.silent:530 if config.silent:
527 setup_init_script_and_start_client()531 setup_init_script_and_start_client()
528 elif not sysvconfig.is_configured_to_run():532 elif not sysvconfig.is_configured_to_run():
529 answer = raw_input("\nThe Landscape client must be started "533 answer = prompt_yes_no(
530 "on boot to operate correctly.\n\n"534 "\nThe Landscape client must be started "
531 "Start Landscape client on boot? (Y/n): ")535 "on boot to operate correctly.\n\n"
532 if not answer.upper().startswith("N"):536 "Start Landscape client on boot?")
537 if answer:
533 setup_init_script_and_start_client()538 setup_init_script_and_start_client()
534 else:539 else:
535 sys.exit("Aborting Landscape configuration")540 sys.exit("Aborting Landscape configuration")
@@ -774,9 +779,9 @@
774 report_registration_outcome(result, print=print)779 report_registration_outcome(result, print=print)
775 sys.exit(determine_exit_code(result))780 sys.exit(determine_exit_code(result))
776 else:781 else:
777 answer = raw_input("\nRequest a new registration for "782 answer = prompt_yes_no(
778 "this computer now? (Y/n): ")783 "\nRequest a new registration for this computer now?")
779 if not answer.upper().startswith("N"):784 if answer:
780 result = register(config, reactor)785 result = register(config, reactor)
781 report_registration_outcome(result, print=print)786 report_registration_outcome(result, print=print)
782 sys.exit(determine_exit_code(result))787 sys.exit(determine_exit_code(result))
783788
=== modified file 'landscape/tests/test_configuration.py'
--- landscape/tests/test_configuration.py 2017-02-24 10:09:22 +0000
+++ landscape/tests/test_configuration.py 2017-03-03 12:43:19 +0000
@@ -15,7 +15,7 @@
15from landscape.configuration import (15from landscape.configuration import (
16 print_text, LandscapeSetupScript, LandscapeSetupConfiguration,16 print_text, LandscapeSetupScript, LandscapeSetupConfiguration,
17 register, setup, main, setup_init_script_and_start_client,17 register, setup, main, setup_init_script_and_start_client,
18 ConfigurationError,18 ConfigurationError, prompt_yes_no, show_help,
19 ImportOptionError, store_public_key_data,19 ImportOptionError, store_public_key_data,
20 bootstrap_tree, got_connection, success, failure, exchange_failure,20 bootstrap_tree, got_connection, success, failure, exchange_failure,
21 handle_registration_errors, done, got_error, report_registration_outcome,21 handle_registration_errors, done, got_error, report_registration_outcome,
@@ -217,6 +217,50 @@
217 self.assertEqual("Hi!END", stdout.getvalue())217 self.assertEqual("Hi!END", stdout.getvalue())
218218
219219
220class PromptYesNoTest(unittest.TestCase):
221
222 def test_prompt_yes_no(self):
223 """
224 prompt_yes_no prompts a question and returns a boolean with the answer.
225 """
226 comparisons = [("Y", True),
227 ("y", True),
228 ("yEs", True),
229 ("YES", True),
230 ("n", False),
231 ("N", False),
232 ("No", False),
233 ("no", False),
234 ("", True)]
235
236 for input_string, result in comparisons:
237 with mock.patch("__builtin__.raw_input",
238 return_value=input_string) as mock_raw_input:
239 prompt_yes_no("Foo")
240 mock_raw_input.assert_called_once_with("Foo [Y/n]: ")
241
242 @mock.patch("__builtin__.raw_input", return_value="")
243 def test_prompt_yes_no_default(self, mock_raw_input):
244 self.assertFalse(prompt_yes_no("Foo", default=False))
245 mock_raw_input.assert_called_once_with("Foo [y/N]: ")
246
247 @mock.patch("__builtin__.raw_input", side_effect=("x", "n"))
248 @mock.patch("landscape.configuration.show_help")
249 def test_prompt_yes_no_invalid(self, mock_show_help, mock_raw_input):
250 self.assertFalse(prompt_yes_no("Foo"))
251 mock_show_help.assert_called_once_with("Invalid input.")
252 calls = [mock.call("Foo [Y/n]: "), mock.call("Foo [Y/n]: ")]
253 mock_raw_input.assert_has_calls(calls)
254
255
256class ShowHelpTest(unittest.TestCase):
257
258 @mock.patch("landscape.configuration.print_text")
259 def test_show_help(self, mock_print_text):
260 show_help("\n\n \n Hello \n \n world! \n \n\n")
261 mock_print_text.assert_called_once_with("\nHello\n\nworld!\n")
262
263
220class LandscapeSetupScriptTest(LandscapeTest):264class LandscapeSetupScriptTest(LandscapeTest):
221265
222 def setUp(self):266 def setUp(self):
@@ -228,11 +272,6 @@
228 self.config = MyLandscapeSetupConfiguration()272 self.config = MyLandscapeSetupConfiguration()
229 self.script = LandscapeSetupScript(self.config)273 self.script = LandscapeSetupScript(self.config)
230274
231 @mock.patch("landscape.configuration.print_text")
232 def test_show_help(self, mock_print_text):
233 self.script.show_help("\n\n \n Hello \n \n world! \n \n\n")
234 mock_print_text.assert_called_once_with("\nHello\n\nworld!\n")
235
236 @mock.patch("__builtin__.raw_input", return_value="Desktop")275 @mock.patch("__builtin__.raw_input", return_value="Desktop")
237 def test_prompt_simple(self, mock_raw_input):276 def test_prompt_simple(self, mock_raw_input):
238 self.script.prompt("computer_title", "Message")277 self.script.prompt("computer_title", "Message")
@@ -248,10 +287,10 @@
248 self.assertEqual(self.config.computer_title, "default")287 self.assertEqual(self.config.computer_title, "default")
249288
250 @mock.patch("__builtin__.raw_input", side_effect=("", "Desktop"))289 @mock.patch("__builtin__.raw_input", side_effect=("", "Desktop"))
251 def test_prompt_with_required(self, mock_raw_input):290 @mock.patch("landscape.configuration.show_help")
252 self.script.show_help = mock.Mock()291 def test_prompt_with_required(self, mock_show_help, mock_raw_input):
253 self.script.prompt("computer_title", "Message", True)292 self.script.prompt("computer_title", "Message", True)
254 self.script.show_help.assert_called_once_with(293 mock_show_help.assert_called_once_with(
255 "This option is required to configure Landscape.")294 "This option is required to configure Landscape.")
256295
257 calls = [mock.call("Message: "), mock.call("Message: ")]296 calls = [mock.call("Message: "), mock.call("Message: ")]
@@ -286,71 +325,41 @@
286 mock_getpass.assert_has_calls(calls)325 mock_getpass.assert_has_calls(calls)
287 self.assertEqual(self.config.registration_key, "password")326 self.assertEqual(self.config.registration_key, "password")
288327
328 @mock.patch("landscape.configuration.show_help")
289 @mock.patch("landscape.configuration.getpass.getpass",329 @mock.patch("landscape.configuration.getpass.getpass",
290 side_effect=("password", "", "password", "password"))330 side_effect=("password", "", "password", "password"))
291 def test_password_prompt_simple_non_matching(self, mock_getpass):331 def test_password_prompt_simple_non_matching(self, mock_getpass,
292 self.script.show_help = mock.Mock()332 mock_show_help):
293
294 self.script.password_prompt("registration_key", "Password")333 self.script.password_prompt("registration_key", "Password")
295334
296 calls = [mock.call("Password: "), mock.call("Please confirm: "),335 calls = [mock.call("Password: "), mock.call("Please confirm: "),
297 mock.call("Password: "), mock.call("Please confirm: ")]336 mock.call("Password: "), mock.call("Please confirm: ")]
298 mock_getpass.assert_has_calls(calls)337 mock_getpass.assert_has_calls(calls)
299 self.script.show_help.assert_called_once_with("Keys must match.")338 mock_show_help.assert_called_once_with("Keys must match.")
300 self.assertEqual(self.config.registration_key, "password")339 self.assertEqual(self.config.registration_key, "password")
301340
341 @mock.patch("landscape.configuration.show_help")
302 @mock.patch("landscape.configuration.getpass.getpass",342 @mock.patch("landscape.configuration.getpass.getpass",
303 side_effect=("", "password", "password"))343 side_effect=("", "password", "password"))
304 def test_password_prompt_simple_matching_required(self, mock_getpass):344 def test_password_prompt_simple_matching_required(self, mock_getpass,
305 self.script.show_help = mock.Mock()345 mock_show_help):
306
307 self.script.password_prompt("registration_key", "Password", True)346 self.script.password_prompt("registration_key", "Password", True)
308347
309 calls = [mock.call("Password: "), mock.call("Password: "),348 calls = [mock.call("Password: "), mock.call("Password: "),
310 mock.call("Please confirm: ")]349 mock.call("Please confirm: ")]
311 mock_getpass.assert_has_calls(calls)350 mock_getpass.assert_has_calls(calls)
312 self.script.show_help.assert_called_once_with(351 mock_show_help.assert_called_once_with(
313 "This option is required to configure Landscape.")352 "This option is required to configure Landscape.")
314 self.assertEqual(self.config.registration_key, "password")353 self.assertEqual(self.config.registration_key, "password")
315354
316 def test_prompt_yes_no(self):355 @mock.patch("landscape.configuration.show_help")
317 comparisons = [("Y", True),356 def test_query_computer_title(self, mock_show_help):
318 ("y", True),
319 ("yEs", True),
320 ("YES", True),
321 ("n", False),
322 ("N", False),
323 ("No", False),
324 ("no", False),
325 ("", True)]
326
327 for input_string, result in comparisons:
328 with mock.patch("__builtin__.raw_input",
329 return_value=input_string) as mock_raw_input:
330 self.script.prompt_yes_no("Foo")
331 mock_raw_input.assert_called_once_with("Foo [Y/n]")
332
333 @mock.patch("__builtin__.raw_input", return_value="")
334 def test_prompt_yes_no_default(self, mock_raw_input):
335 self.assertFalse(self.script.prompt_yes_no("Foo", default=False))
336 mock_raw_input.assert_called_once_with("Foo [y/N]")
337
338 @mock.patch("__builtin__.raw_input", side_effect=("x", "n"))
339 def test_prompt_yes_no_invalid(self, mock_raw_input):
340 self.script.show_help = mock.Mock()
341 self.assertFalse(self.script.prompt_yes_no("Foo"))
342 self.script.show_help.assert_called_once_with("Invalid input.")
343 calls = [mock.call("Foo [Y/n]"), mock.call("Foo [Y/n]")]
344 mock_raw_input.assert_has_calls(calls)
345
346 def test_query_computer_title(self):
347 help_snippet = "The computer title you"357 help_snippet = "The computer title you"
348 self.script.show_help = mock.Mock()
349 self.script.prompt = mock.Mock()358 self.script.prompt = mock.Mock()
350 self.script.query_computer_title()359 self.script.query_computer_title()
351 self.script.prompt.assert_called_once_with(360 self.script.prompt.assert_called_once_with(
352 "computer_title", "This computer's title", True)361 "computer_title", "This computer's title", True)
353 [call] = self.script.show_help.mock_calls362 [call] = mock_show_help.mock_calls
354 self.assertTrue(call.strip().startswith(help_snippet))363 self.assertTrue(call.strip().startswith(help_snippet))
355364
356 @mock.patch("__builtin__.raw_input")365 @mock.patch("__builtin__.raw_input")
@@ -360,14 +369,14 @@
360 self.script.query_computer_title()369 self.script.query_computer_title()
361 mock_raw_input.assert_not_called()370 mock_raw_input.assert_not_called()
362371
363 def test_query_account_name(self):372 @mock.patch("landscape.configuration.show_help")
373 def test_query_account_name(self, mock_show_help):
364 help_snippet = "You must now specify the name of the Landscape account"374 help_snippet = "You must now specify the name of the Landscape account"
365 self.script.show_help = mock.Mock()
366 self.script.prompt = mock.Mock()375 self.script.prompt = mock.Mock()
367 self.script.query_account_name()376 self.script.query_account_name()
368 self.script.prompt.assert_called_once_with(377 self.script.prompt.assert_called_once_with(
369 "account_name", "Account name", True)378 "account_name", "Account name", True)
370 [call] = self.script.show_help.mock_calls379 [call] = mock_show_help.mock_calls
371 self.assertTrue(call.strip().startswith(help_snippet))380 self.assertTrue(call.strip().startswith(help_snippet))
372381
373 self.script.query_account_name()382 self.script.query_account_name()
@@ -378,14 +387,14 @@
378 self.script.query_account_name()387 self.script.query_account_name()
379 mock_raw_input.assert_not_called()388 mock_raw_input.assert_not_called()
380389
381 def test_query_registration_key(self):390 @mock.patch("landscape.configuration.show_help")
391 def test_query_registration_key(self, mock_show_help):
382 help_snippet = "A registration key may be"392 help_snippet = "A registration key may be"
383 self.script.show_help = mock.Mock()
384 self.script.password_prompt = mock.Mock()393 self.script.password_prompt = mock.Mock()
385 self.script.query_registration_key()394 self.script.query_registration_key()
386 self.script.password_prompt.assert_called_once_with(395 self.script.password_prompt.assert_called_once_with(
387 "registration_key", "Account registration key")396 "registration_key", "Account registration key")
388 [call] = self.script.show_help.mock_calls397 [call] = mock_show_help.mock_calls
389 self.assertTrue(call.strip().startswith(help_snippet))398 self.assertTrue(call.strip().startswith(help_snippet))
390399
391 @mock.patch("landscape.configuration.getpass.getpass")400 @mock.patch("landscape.configuration.getpass.getpass")
@@ -395,16 +404,16 @@
395 self.script.query_registration_key()404 self.script.query_registration_key()
396 mock_getpass.assert_not_called()405 mock_getpass.assert_not_called()
397406
398 def test_query_proxies(self):407 @mock.patch("landscape.configuration.show_help")
408 def test_query_proxies(self, mock_show_help):
399 help_snippet = "The Landscape client communicates"409 help_snippet = "The Landscape client communicates"
400 self.script.show_help = mock.Mock()
401 self.script.prompt = mock.Mock()410 self.script.prompt = mock.Mock()
402411
403 self.script.query_proxies()412 self.script.query_proxies()
404 calls = [mock.call("http_proxy", "HTTP proxy URL"),413 calls = [mock.call("http_proxy", "HTTP proxy URL"),
405 mock.call("https_proxy", "HTTPS proxy URL")]414 mock.call("https_proxy", "HTTPS proxy URL")]
406 self.script.prompt.assert_has_calls(calls)415 self.script.prompt.assert_has_calls(calls)
407 [call] = self.script.show_help.mock_calls416 [call] = mock_show_help.mock_calls
408 self.assertTrue(call.strip().startswith(help_snippet))417 self.assertTrue(call.strip().startswith(help_snippet))
409418
410 @mock.patch("__builtin__.raw_input")419 @mock.patch("__builtin__.raw_input")
@@ -414,53 +423,53 @@
414 self.script.query_proxies()423 self.script.query_proxies()
415 mock_raw_input.assert_not_called()424 mock_raw_input.assert_not_called()
416425
417 def test_query_http_proxy_defined_on_command_line(self):426 @mock.patch("landscape.configuration.show_help")
427 def test_query_http_proxy_defined_on_command_line(self, mock_show_help):
418 help_snippet = "The Landscape client communicates"428 help_snippet = "The Landscape client communicates"
419 self.script.show_help = mock.Mock()
420 self.script.prompt = mock.Mock()429 self.script.prompt = mock.Mock()
421430
422 self.config.load_command_line(["--http-proxy", "localhost:8080"])431 self.config.load_command_line(["--http-proxy", "localhost:8080"])
423 self.script.query_proxies()432 self.script.query_proxies()
424 [call] = self.script.show_help.mock_calls433 [call] = mock_show_help.mock_calls
425 self.assertTrue(call.strip().startswith(help_snippet))434 self.assertTrue(call.strip().startswith(help_snippet))
426435
427 def test_query_https_proxy_defined_on_command_line(self):436 @mock.patch("landscape.configuration.show_help")
437 def test_query_https_proxy_defined_on_command_line(self, mock_show_help):
428 help_snippet = "The Landscape client communicates"438 help_snippet = "The Landscape client communicates"
429 self.script.show_help = mock.Mock()
430 self.script.prompt = mock.Mock()439 self.script.prompt = mock.Mock()
431 self.config.load_command_line(["--https-proxy", "localhost:8443"])440 self.config.load_command_line(["--https-proxy", "localhost:8443"])
432 self.script.query_proxies()441 self.script.query_proxies()
433 self.script.prompt.assert_called_once_with(442 self.script.prompt.assert_called_once_with(
434 "http_proxy", "HTTP proxy URL")443 "http_proxy", "HTTP proxy URL")
435 [call] = self.script.show_help.mock_calls444 [call] = mock_show_help.mock_calls
436 self.assertTrue(call.strip().startswith(help_snippet))445 self.assertTrue(call.strip().startswith(help_snippet))
437446
438 def test_query_script_plugin_no(self):447 @mock.patch("landscape.configuration.show_help")
448 @mock.patch("landscape.configuration.prompt_yes_no", return_value=False)
449 def test_query_script_plugin_no(self, mock_prompt_yes_no, mock_show_help):
439 help_snippet = "Landscape has a feature which enables administrators"450 help_snippet = "Landscape has a feature which enables administrators"
440 self.script.show_help = mock.Mock()
441 self.script.prompt_yes_no = mock.Mock(return_value=False)
442451
443 self.script.query_script_plugin()452 self.script.query_script_plugin()
444 self.assertEqual(self.config.include_manager_plugins, "")453 self.assertEqual(self.config.include_manager_plugins, "")
445 self.script.prompt_yes_no.assert_called_once_with(454 mock_prompt_yes_no.assert_called_once_with(
446 "Enable script execution?", default=False)455 "Enable script execution?", default=False)
447 [call] = self.script.show_help.mock_calls456 [call] = mock_show_help.mock_calls
448 self.assertTrue(call.strip().startswith(help_snippet))457 self.assertTrue(call.strip().startswith(help_snippet))
449458
450 def test_query_script_plugin_yes(self):459 @mock.patch("landscape.configuration.show_help")
460 @mock.patch("landscape.configuration.prompt_yes_no", return_value=True)
461 def test_query_script_plugin_yes(self, mock_prompt_yes_no, mock_show_help):
451 """462 """
452 If the user *does* want script execution, then the script asks which463 If the user *does* want script execution, then the script asks which
453 users to enable it for.464 users to enable it for.
454 """465 """
455 help_snippet = "Landscape has a feature which enables administrators"466 help_snippet = "Landscape has a feature which enables administrators"
456 self.script.show_help = mock.Mock()
457 self.script.prompt_yes_no = mock.Mock(return_value=True)
458 self.script.prompt = mock.Mock()467 self.script.prompt = mock.Mock()
459468
460 self.script.query_script_plugin()469 self.script.query_script_plugin()
461 self.script.prompt_yes_no.assert_called_once_with(470 mock_prompt_yes_no.assert_called_once_with(
462 "Enable script execution?", default=False)471 "Enable script execution?", default=False)
463 first_call, second_call = self.script.show_help.mock_calls472 first_call, second_call = mock_show_help.mock_calls
464 self.assertTrue(first_call.strip().startswith(help_snippet))473 self.assertTrue(first_call.strip().startswith(help_snippet))
465 self.assertTrue(second_call.strip().startswith(474 self.assertTrue(second_call.strip().startswith(
466 "By default, scripts are restricted"))475 "By default, scripts are restricted"))
@@ -470,56 +479,58 @@
470 self.assertEqual(self.config.include_manager_plugins,479 self.assertEqual(self.config.include_manager_plugins,
471 "ScriptExecution")480 "ScriptExecution")
472481
473 def test_disable_script_plugin(self):482 @mock.patch("landscape.configuration.show_help")
483 @mock.patch("landscape.configuration.prompt_yes_no", return_value=False)
484 def test_disable_script_plugin(self, mock_prompt_yes_no, mock_show_help):
474 """485 """
475 Answering NO to enabling the script plugin while it's already enabled486 Answering NO to enabling the script plugin while it's already enabled
476 will disable it.487 will disable it.
477 """488 """
478 self.config.include_manager_plugins = "ScriptExecution"489 self.config.include_manager_plugins = "ScriptExecution"
479 help_snippet = "Landscape has a feature which enables administrators"490 help_snippet = "Landscape has a feature which enables administrators"
480 self.script.show_help = mock.Mock()
481 self.script.prompt_yes_no = mock.Mock(return_value=False)
482491
483 self.script.query_script_plugin()492 self.script.query_script_plugin()
484 self.script.prompt_yes_no.assert_called_once_with(493 mock_prompt_yes_no.assert_called_once_with(
485 "Enable script execution?", default=True)494 "Enable script execution?", default=True)
486 self.assertEqual(self.config.include_manager_plugins, "")495 self.assertEqual(self.config.include_manager_plugins, "")
487 [call] = self.script.show_help.mock_calls496 [call] = mock_show_help.mock_calls
488 self.assertTrue(call.strip().startswith(help_snippet))497 self.assertTrue(call.strip().startswith(help_snippet))
489498
490 def test_disabling_script_plugin_leaves_existing_inclusions(self):499 @mock.patch("landscape.configuration.show_help")
500 @mock.patch("landscape.configuration.prompt_yes_no", return_value=False)
501 def test_disabling_script_plugin_leaves_existing_inclusions(
502 self, mock_prompt_yes_no, mock_show_help):
491 """503 """
492 Disabling the script execution plugin doesn't remove other included504 Disabling the script execution plugin doesn't remove other included
493 plugins.505 plugins.
494 """506 """
495 self.config.include_manager_plugins = "FooPlugin, ScriptExecution"507 self.config.include_manager_plugins = "FooPlugin, ScriptExecution"
496 self.script.show_help = mock.Mock()
497 self.script.prompt_yes_no = mock.Mock(return_value=False)
498508
499 self.script.query_script_plugin()509 self.script.query_script_plugin()
500 self.script.prompt_yes_no.assert_called_once_with(510 mock_prompt_yes_no.assert_called_once_with(
501 "Enable script execution?", default=True)511 "Enable script execution?", default=True)
502 self.assertEqual(self.config.include_manager_plugins, "FooPlugin")512 self.assertEqual(self.config.include_manager_plugins, "FooPlugin")
503 self.script.show_help.assert_called_once_with(mock.ANY)513 mock_show_help.assert_called_once_with(mock.ANY)
504514
505 def test_enabling_script_plugin_leaves_existing_inclusions(self):515 @mock.patch("landscape.configuration.show_help")
516 @mock.patch("landscape.configuration.prompt_yes_no", return_value=True)
517 def test_enabling_script_plugin_leaves_existing_inclusions(
518 self, mock_prompt_yes_no, mock_show_help):
506 """519 """
507 Enabling the script execution plugin doesn't remove other included520 Enabling the script execution plugin doesn't remove other included
508 plugins.521 plugins.
509 """522 """
510 self.config.include_manager_plugins = "FooPlugin"523 self.config.include_manager_plugins = "FooPlugin"
511524
512 self.script.show_help = mock.Mock()
513 self.script.prompt_yes_no = mock.Mock(return_value=True)
514 self.script.prompt = mock.Mock()525 self.script.prompt = mock.Mock()
515526
516 self.script.query_script_plugin()527 self.script.query_script_plugin()
517 self.script.prompt_yes_no.assert_called_once_with(528 mock_prompt_yes_no.assert_called_once_with(
518 "Enable script execution?", default=False)529 "Enable script execution?", default=False)
519530
520 self.script.prompt.assert_called_once_with(531 self.script.prompt.assert_called_once_with(
521 "script_users", "Script users")532 "script_users", "Script users")
522 self.assertEqual(2, self.script.show_help.call_count)533 self.assertEqual(2, mock_show_help.call_count)
523 self.assertEqual(self.config.include_manager_plugins,534 self.assertEqual(self.config.include_manager_plugins,
524 "FooPlugin, ScriptExecution")535 "FooPlugin, ScriptExecution")
525536
@@ -534,9 +545,10 @@
534 "ScriptExecution")545 "ScriptExecution")
535 self.assertEqual(self.config.script_users, "root, nobody")546 self.assertEqual(self.config.script_users, "root, nobody")
536547
537 def test_query_script_manager_plugins_defined_on_command_line(self):548 @mock.patch("landscape.configuration.show_help")
538 self.script.show_help = mock.Mock()549 @mock.patch("landscape.configuration.prompt_yes_no", return_value=True)
539 self.script.prompt_yes_no = mock.Mock(return_value=True)550 def test_query_script_manager_plugins_defined_on_command_line(
551 self, mock_prompt_yes_no, mock_show_help):
540 self.script.prompt = mock.Mock()552 self.script.prompt = mock.Mock()
541553
542 self.config.load_command_line(554 self.config.load_command_line(
@@ -544,17 +556,19 @@
544 self.script.query_script_plugin()556 self.script.query_script_plugin()
545 self.script.prompt.assert_called_once_with(557 self.script.prompt.assert_called_once_with(
546 "script_users", "Script users")558 "script_users", "Script users")
547 self.assertEqual(2, self.script.show_help.call_count)559 self.assertEqual(2, mock_show_help.call_count)
548 self.assertEqual(self.config.include_manager_plugins,560 self.assertEqual(self.config.include_manager_plugins,
549 "FooPlugin, ScriptExecution")561 "FooPlugin, ScriptExecution")
550562
563 @mock.patch("landscape.configuration.show_help")
564 @mock.patch("landscape.configuration.prompt_yes_no", return_value=True)
551 @mock.patch("landscape.configuration.pwd.getpwnam", return_value=None)565 @mock.patch("landscape.configuration.pwd.getpwnam", return_value=None)
552 def test_query_script_users_defined_on_command_line(self, mock_getpwnam):566 def test_query_script_users_defined_on_command_line(self, mock_getpwnam,
567 mock_prompt_yes_no,
568 mock_show_help):
553 """569 """
554 Confirm with the user for users specified for the ScriptPlugin.570 Confirm with the user for users specified for the ScriptPlugin.
555 """571 """
556 self.script.show_help = mock.Mock()
557 self.script.prompt_yes_no = mock.Mock(return_value=True)
558 self.script.prompt_get_input = mock.Mock(return_value=None)572 self.script.prompt_get_input = mock.Mock(return_value=None)
559573
560 self.config.include_manager_plugins = "FooPlugin"574 self.config.include_manager_plugins = "FooPlugin"
@@ -564,11 +578,11 @@
564 self.script.query_script_plugin()578 self.script.query_script_plugin()
565579
566 mock_getpwnam.assert_called_with("landscape")580 mock_getpwnam.assert_called_with("landscape")
567 self.script.prompt_yes_no.assert_called_once_with(581 mock_prompt_yes_no.assert_called_once_with(
568 "Enable script execution?", default=False)582 "Enable script execution?", default=False)
569 self.script.prompt_get_input.assert_called_once_with(583 self.script.prompt_get_input.assert_called_once_with(
570 "Script users [root, nobody, landscape]: ", False)584 "Script users [root, nobody, landscape]: ", False)
571 self.assertEqual(2, self.script.show_help.call_count)585 self.assertEqual(2, mock_show_help.call_count)
572 self.assertEqual(self.config.script_users,586 self.assertEqual(self.config.script_users,
573 "root, nobody, landscape")587 "root, nobody, landscape")
574588
@@ -617,53 +631,56 @@
617 "--include-manager-plugins", "ScriptPlugin"])631 "--include-manager-plugins", "ScriptPlugin"])
618 self.assertRaises(ConfigurationError, self.script.query_script_plugin)632 self.assertRaises(ConfigurationError, self.script.query_script_plugin)
619633
620 def test_invalid_user_entered_by_user(self):634 @mock.patch("landscape.configuration.show_help")
635 @mock.patch("landscape.configuration.prompt_yes_no", return_value=True)
636 def test_invalid_user_entered_by_user(self, mock_prompt_yes_no,
637 mock_show_help):
621 """638 """
622 If an invalid user is entered on the command line the user should be639 If an invalid user is entered on the command line the user should be
623 informed and prompted again.640 informed and prompted again.
624 """641 """
625 help_snippet = "Landscape has a feature which enables administrators"642 help_snippet = "Landscape has a feature which enables administrators"
626 self.script.show_help = mock.Mock()
627 self.script.prompt_yes_no = mock.Mock(return_value=True)
628 self.script.prompt_get_input = mock.Mock(643 self.script.prompt_get_input = mock.Mock(
629 side_effect=(u"nonexistent", u"root"))644 side_effect=(u"nonexistent", u"root"))
630645
631 self.script.query_script_plugin()646 self.script.query_script_plugin()
632 self.assertEqual(self.config.script_users, "root")647 self.assertEqual(self.config.script_users, "root")
633 first_call, second_call, third_call = self.script.show_help.mock_calls648 first_call, second_call, third_call = mock_show_help.mock_calls
634 self.assertTrue(first_call.strip().startswith(help_snippet))649 self.assertTrue(first_call.strip().startswith(help_snippet))
635 self.assertTrue(second_call.strip().startswith(650 self.assertTrue(second_call.strip().startswith(
636 "By default, scripts are restricted"))651 "By default, scripts are restricted"))
637 self.assertTrue(third_call.strip().startswith(652 self.assertTrue(third_call.strip().startswith(
638 "Unknown system users: nonexistsent"))653 "Unknown system users: nonexistsent"))
639654
640 def test_tags_not_defined_on_command_line(self):655 @mock.patch("landscape.configuration.show_help")
656 def test_tags_not_defined_on_command_line(self, mock_show_help):
641 """657 """
642 If tags are not provided, the user should be prompted for them.658 If tags are not provided, the user should be prompted for them.
643 """659 """
644 help_snippet = ("You may provide tags for this computer e.g. "660 help_snippet = ("You may provide tags for this computer e.g. "
645 "server,precise.")661 "server,precise.")
646 self.script.show_help = mock.Mock()
647 self.script.prompt = mock.Mock()662 self.script.prompt = mock.Mock()
648663
649 self.script.query_tags()664 self.script.query_tags()
650 self.script.prompt.assert_called_once_with(665 self.script.prompt.assert_called_once_with(
651 "tags", "Tags", False)666 "tags", "Tags", False)
652 [call] = self.script.show_help.mock_calls667 [call] = mock_show_help.mock_calls
653 self.assertTrue(call.strip().startswith(help_snippet))668 self.assertTrue(call.strip().startswith(help_snippet))
654669
655 def test_invalid_tags_entered_by_user(self):670 @mock.patch("landscape.configuration.show_help")
671 @mock.patch("landscape.configuration.prompt_yes_no")
672 def test_invalid_tags_entered_by_user(self, mock_prompt_yes_no,
673 mock_show_help):
656 """674 """
657 If tags are not provided, the user should be prompted for them, and675 If tags are not provided, the user should be prompted for them, and
658 they should be valid tags, if not the user should be prompted for them676 they should be valid tags, if not the user should be prompted for them
659 again.677 again.
660 """678 """
661 self.script.show_help = mock.Mock()
662 self.script.prompt_get_input = mock.Mock(679 self.script.prompt_get_input = mock.Mock(
663 side_effect=(u"<script>alert();</script>", u"london"))680 side_effect=(u"<script>alert();</script>", u"london"))
664681
665 self.script.query_tags()682 self.script.query_tags()
666 first_call, second_call = self.script.show_help.mock_calls683 first_call, second_call = mock_show_help.mock_calls
667 self.assertTrue(684 self.assertTrue(
668 first_call.strip().startswith("You may provide tags for this "685 first_call.strip().startswith("You may provide tags for this "
669 "computer e.g. server,precise."))686 "computer e.g. server,precise."))
@@ -693,16 +710,16 @@
693 self.assertRaises(ConfigurationError, self.script.query_tags)710 self.assertRaises(ConfigurationError, self.script.query_tags)
694 mock_raw_input.assert_not_called()711 mock_raw_input.assert_not_called()
695712
696 def test_access_group_not_defined_on_command_line(self):713 @mock.patch("landscape.configuration.show_help")
714 def test_access_group_not_defined_on_command_line(self, mock_show_help):
697 """715 """
698 If an access group is not provided, the user should be prompted for it.716 If an access group is not provided, the user should be prompted for it.
699 """717 """
700 help_snippet = ("You may provide an access group for this computer "718 help_snippet = ("You may provide an access group for this computer "
701 "e.g. webservers.")719 "e.g. webservers.")
702 self.script.show_help = mock.Mock()
703 self.script.prompt = mock.Mock()720 self.script.prompt = mock.Mock()
704 self.script.query_access_group()721 self.script.query_access_group()
705 [call] = self.script.show_help.mock_calls722 [call] = mock_show_help.mock_calls
706 self.assertTrue(call.strip().startswith(help_snippet))723 self.assertTrue(call.strip().startswith(help_snippet))
707724
708 @mock.patch("__builtin__.raw_input")725 @mock.patch("__builtin__.raw_input")
@@ -716,11 +733,11 @@
716 self.assertEqual(self.config.access_group, u"webservers")733 self.assertEqual(self.config.access_group, u"webservers")
717 mock_raw_input.assert_not_called()734 mock_raw_input.assert_not_called()
718735
719 def test_show_header(self):736 @mock.patch("landscape.configuration.show_help")
737 def test_show_header(self, mock_show_help):
720 help_snippet = "This script will"738 help_snippet = "This script will"
721 self.script.show_help = mock.Mock()
722 self.script.show_header()739 self.script.show_header()
723 [call] = self.script.show_help.mock_calls740 [call] = mock_show_help.mock_calls
724 self.assertTrue(call.strip().startswith(help_snippet))741 self.assertTrue(call.strip().startswith(help_snippet))
725742
726 def test_run(self):743 def test_run(self):
@@ -1095,7 +1112,7 @@
1095 main(["-c", self.make_working_config()], print=noop_print)1112 main(["-c", self.make_working_config()], print=noop_print)
1096 mock_register.assert_not_called()1113 mock_register.assert_not_called()
1097 mock_raw_input.assert_called_once_with(1114 mock_raw_input.assert_called_once_with(
1098 "\nRequest a new registration for this computer now? (Y/n): ")1115 "\nRequest a new registration for this computer now? [Y/n]: ")
10991116
1100 @mock.patch("landscape.configuration.register", return_value="success")1117 @mock.patch("landscape.configuration.register", return_value="success")
1101 @mock.patch("landscape.configuration.setup")1118 @mock.patch("landscape.configuration.setup")
@@ -1136,7 +1153,7 @@
1136 mock_setup.assert_called_once_with(mock.ANY)1153 mock_setup.assert_called_once_with(mock.ANY)
1137 mock_register.assert_called_once_with(mock.ANY, mock.ANY)1154 mock_register.assert_called_once_with(mock.ANY, mock.ANY)
1138 mock_raw_input.assert_called_once_with(1155 mock_raw_input.assert_called_once_with(
1139 "\nRequest a new registration for this computer now? (Y/n): ")1156 "\nRequest a new registration for this computer now? [Y/n]: ")
1140 self.assertEqual(1157 self.assertEqual(
1141 [("Please wait...", sys.stdout),1158 [("Please wait...", sys.stdout),
1142 ("System successfully registered.", sys.stdout)],1159 ("System successfully registered.", sys.stdout)],
@@ -1161,7 +1178,7 @@
1161 mock_setup.assert_called_once_with(mock.ANY)1178 mock_setup.assert_called_once_with(mock.ANY)
1162 mock_register.assert_called_once_with(mock.ANY, mock.ANY)1179 mock_register.assert_called_once_with(mock.ANY, mock.ANY)
1163 mock_raw_input.assert_called_once_with(1180 mock_raw_input.assert_called_once_with(
1164 "\nRequest a new registration for this computer now? (Y/n): ")1181 "\nRequest a new registration for this computer now? [Y/n]: ")
11651182
1166 # Note that the error is output via sys.stderr.1183 # Note that the error is output via sys.stderr.
1167 self.assertEqual(1184 self.assertEqual(
@@ -1249,9 +1266,9 @@
1249 mock_raw_input.assert_any_call(1266 mock_raw_input.assert_any_call(
1250 "\nThe Landscape client must be started "1267 "\nThe Landscape client must be started "
1251 "on boot to operate correctly.\n\n"1268 "on boot to operate correctly.\n\n"
1252 "Start Landscape client on boot? (Y/n): ")1269 "Start Landscape client on boot? [Y/n]: ")
1253 mock_raw_input.assert_called_with(1270 mock_raw_input.assert_called_with(
1254 "\nRequest a new registration for this computer now? (Y/n): ")1271 "\nRequest a new registration for this computer now? [Y/n]: ")
12551272
1256 @mock.patch("landscape.configuration.print_text")1273 @mock.patch("landscape.configuration.print_text")
1257 @mock.patch("landscape.configuration.SysVConfig")1274 @mock.patch("landscape.configuration.SysVConfig")
@@ -1307,7 +1324,7 @@
1307 mock_setup.assert_called_once_with(mock.ANY)1324 mock_setup.assert_called_once_with(mock.ANY)
1308 mock_register.assert_called_once_with(mock.ANY, mock.ANY)1325 mock_register.assert_called_once_with(mock.ANY, mock.ANY)
1309 mock_raw_input.assert_called_once_with(1326 mock_raw_input.assert_called_once_with(
1310 "\nRequest a new registration for this computer now? (Y/n): ")1327 "\nRequest a new registration for this computer now? [Y/n]: ")
13111328
1312 @mock.patch("landscape.configuration.SysVConfig")1329 @mock.patch("landscape.configuration.SysVConfig")
1313 def test_setup_init_script_and_start_client(1330 def test_setup_init_script_and_start_client(

Subscribers

People subscribed via source and target branches

to all changes: