def test_task_will_invoke_provided_class(): def foo(): pass fake = Fake() fake.expects("__init__").with_args(foo) fudge.clear_calls() fudge.clear_expectations() foo = decorators.task(foo, task_class=fake) fudge.verify()
def test_should_set_env_command_to_string_arg(self): """ should set env.command to any string arg, if given """ name = "foo" def command(): self.assert_(env.command, name) task = Fake(callable=True, expect_call=True).calls(command) with patched_context(fabric.state, 'commands', {name: task}): execute(name)
def test_silent_empty_page_error(table): request = build_request("/") paginator = (Fake("Paginator") .has_attr(num_pages=987) .expects("page").with_args(987)) table = (table .has_attr(paginator=paginator) .expects("paginate").with_args(page=123) .raises(EmptyPage)) RequestConfig(request, paginate={"page": 123, "silent": True}).configure(table)
def test_put_use_sudo(self): """ put(use_sudo=True) works by uploading a the `local_path` to a temporary path and then moving it to a `remote_path` """ fake_run = Fake('_run_command', callable=True, expect_call=True).with_matching_args( fudge_arg.startswith('mv "'), True, True, None, ) fake_put = Fake('put', callable=True, expect_call=True) local_path = self.mkfile('foobar.txt', "baz") with hide('everything'): with patched_context('fabric.operations', '_run_command', fake_run): with patched_context(SFTPClient, 'put', fake_put): retval = put(local_path, "/", use_sudo=True) # check that the downloaded file has the same name as the one requested assert retval[0].endswith('foobar.txt')
def test_silent_page_not_an_integer_error(self): table = self.table() request = build_request('/') paginator = (Fake('Paginator').expects('page').with_args(1)) table = (table.has_attr( paginator=paginator).expects('paginate').with_args( page='abc').raises(PageNotAnInteger)) RequestConfig(request, paginate={ 'page': 'abc', 'silent': True }).configure(table)
def test_should_preserve_previous_settings(self): """ should not overwrite env.user, etc after it finishes """ outer = dict(user='******', host='localhost', port='123') inner = dict(user='******', host='fabfile.org', port='555') def command(): dict_contains(superset=fabric.state.env, subset=inner) with settings(**outer): task = Fake(callable=True, expect_call=True).calls(command) execute(task, host=from_dict(inner)) dict_contains(superset=fabric.state.env, subset=outer)
def test_should_set_env_command_to_name_attr(self): """ should set env.command to TaskSubclass.name if possible """ name = "foo" def command(): self.assertEqual(env.command, name) task = (Fake(callable=True, expect_call=True).has_attr(name=name).calls(command)) execute(task)
def test_should_honor_hosts_kwarg(self): """ should use hosts kwarg to set run list """ # Make two full copies of a host list hostlist = ['a', 'b', 'c'] hosts = hostlist[:] # Side-effect which asserts the value of env.host_string when it runs def host_string(): eq_(env.host_string, hostlist.pop(0)) task = Fake(callable=True, expect_call=True).calls(host_string) execute(task, hosts=hosts)
def test_get_use_sudo_temp_dir(self): """ get(use_sudo=True, temp_dir="/tmp") works by copying to /tmp/..., downloading it and then removing it at the end """ fake_run = Fake('_run_command', callable=True, expect_call=True).with_matching_args( fudge_arg.startswith( 'cp -p "/etc/apache2/apache2.conf" "/tmp/'), True, True, None, ).next_call().with_matching_args( fudge_arg.startswith('chown username "/tmp/'), True, True, None, ).next_call().with_matching_args( fudge_arg.startswith('chmod 400 "/tmp/'), True, True, None, ).next_call().with_matching_args( fudge_arg.startswith('rm -f "/tmp/'), True, True, None, ) fake_get = Fake('get', callable=True, expect_call=True).with_args( fudge_arg.startswith('/tmp/'), fudge_arg.any_value()) with hide('everything'): with patched_context('fabric.operations', '_run_command', fake_run): with patched_context(SFTPClient, 'get', fake_get): retval = get('/etc/apache2/apache2.conf', self.path(), use_sudo=True, temp_dir="/tmp") # check that the downloaded file has the same name as the one requested assert retval[0].endswith('apache2.conf')
def test_arg_diffs_are_not_shortened(self): fake = Fake("widget").provides("set_bits").with_args( "12345678910111213141516171819202122232425262728293031") try: # this should not be shortened but the above arg spec should: fake.set_bits( "99999999999999999999999999999999999999999999999999999999") except AssertionError, exc: eq_( str(exc), "fake:widget.set_bits('123456789101112131415161718192021222324252627...') " "was called unexpectedly with args " "('99999999999999999999999999999999999999999999999999999999')")
def fake_function(*args, **kwargs): """ Returns a ``fudge.Fake`` exhibiting function-like attributes. Passes in all args/kwargs to the ``fudge.Fake`` constructor. However, if ``callable`` or ``expect_call`` kwargs are not given, ``callable`` will be set to True by default. """ # Must define __name__ to be compatible with function wrapping mechanisms # like @wraps(). if 'callable' not in kwargs and 'expect_call' not in kwargs: kwargs['callable'] = True return Fake(*args, **kwargs).has_attr(__name__='fake')
def test_task_passes_args_to_the_task_class(): random_vars = ("some text", random.randint(100, 200)) def foo(): pass fake = Fake() fake.expects("__init__").with_args(foo, *random_vars) fudge.clear_calls() fudge.clear_expectations() foo = decorators.task(foo, task_class=fake, *random_vars) fudge.verify()
def test_silent_empty_page_error(self): table = self.table() request = build_request('/') paginator = (Fake('Paginator').has_attr( num_pages=987).expects('page').with_args(987)) table = (table.has_attr( paginator=paginator).expects('paginate').with_args( page=123).raises(EmptyPage)) RequestConfig(request, paginate={ 'page': 123, 'silent': True }).configure(table)
def test_env_host_set_when_host_prompt_used(self): """ Ensure env.host is set during host prompting """ copied_host_string = str(env.host_string) fake = Fake('raw_input', callable=True).returns(copied_host_string) env.host_string = None env.host = None with settings(hide('everything'), patched_input(fake)): run("ls /") # Ensure it did set host_string back to old value eq_(env.host_string, copied_host_string) # Ensure env.host is correct eq_(env.host, normalize(copied_host_string)[1])
def test_incremental_order_assertion_ok(self): # need to drop down a level to bypass expected calls: fake = Fake() call_order = ExpectedCallOrder(fake) exp = ExpectedCall(fake, "one", call_order=call_order) call_order.add_expected_call(exp) exp() # call this exp = ExpectedCall(fake, "two", call_order=call_order) call_order.add_expected_call(exp) # two() not called but assertion is not finalized: call_order.assert_order_met(finalize=False)
def test_get_use_sudo_temp_dir(self): """ get(use_sudo=True, temp_dir="/tmp") works by copying to a /tmp/sha1_hash, downloading it and then removing it at the end """ # the sha1 hash is the unique filename of the file being downloaded. sha1(<filename>) fake_run = Fake( '_run_command', callable=True, expect_call=True ).with_matching_args( 'cp -p "/etc/apache2/apache2.conf" "/tmp/229a29e5693876645e39de0cb0532e43ad73311a"', True, True, None, ).next_call().with_matching_args( 'chmod 404 "/tmp/229a29e5693876645e39de0cb0532e43ad73311a"', True, True, None, ).next_call().with_matching_args( 'rm -f "/tmp/229a29e5693876645e39de0cb0532e43ad73311a"', True, True, None, ) fake_get = Fake('get', callable=True, expect_call=True).with_args( '/tmp/229a29e5693876645e39de0cb0532e43ad73311a', fudge_arg.any_value()) with hide('everything'): with patched_context('fabric.operations', '_run_command', fake_run): with patched_context(SFTPClient, 'get', fake_get): retval = get('/etc/apache2/apache2.conf', self.path(), use_sudo=True, temp_dir="/tmp") # check that the downloaded file has the same name as the one requested assert retval[0].endswith('apache2.conf')
def test_fastprint_calls_puts(): """ fastprint() is just an alias to puts() """ text = "Some output" fake_puts = Fake('puts', expect_call=True).with_args(text=text, show_prefix=False, end="", flush=True) with patched_context(utils, 'puts', fake_puts): try: fastprint(text) verify() finally: clear_expectations()
def test_method_call(self): """ Tests calling a method of the original object through the Proxy. """ expected = 6 args = 1, 4, 5 kwargs = {"a": 2, "b": 3} self.foo.func = Fake("func").expects_call().returns( expected).with_args(*args, **kwargs) result = self.proxy.func(*args, **kwargs) self.assertEqual( result, expected, "Call to a function through Proxy returned an unexpected result")
def test_only_one_call(self): # need to drop down a level to bypass expected calls: r = Registry() fake = Fake() call_order = ExpectedCallOrder(fake) r.remember_expected_call_order(call_order) exp = ExpectedCall(fake, "one", call_order=call_order) call_order.add_expected_call(exp) exp() # call this exp = ExpectedCall(fake, "two", call_order=call_order) call_order.add_expected_call(exp) r.verify()
def test_put_use_sudo(self): """ put(use_sudo=True) works by uploading a the `local_path` to a temporary path and then moving it to a `remote_path` """ # the sha1 hash is the unique filename of the file being downloaded. sha1(<filename>) fake_run = Fake( '_run_command', callable=True, expect_call=True).with_matching_args( 'mv "7c91837ec0b3570264a325df6b7ef949ee22bc56" "/foobar.txt"', True, True, None, ) fake_put = Fake('put', callable=True, expect_call=True).with_args( fudge_arg.any_value(), '7c91837ec0b3570264a325df6b7ef949ee22bc56') local_path = self.mkfile('foobar.txt', "baz") with hide('everything'): with patched_context('fabric.operations', '_run_command', fake_run): with patched_context(SFTPClient, 'put', fake_put): retval = put(local_path, "/", use_sudo=True) # check that the downloaded file has the same name as the one requested assert retval[0].endswith('foobar.txt')
def test_should_set_all_hosts(self): """ should set env.all_hosts to its derived host list """ hosts = ['a', 'b'] roledefs = {'r1': ['c', 'd']} roles = ['r1'] exclude_hosts = ['a'] def command(): eq_(set(env.all_hosts), set(['b', 'c', 'd'])) task = Fake(callable=True, expect_call=True).calls(command) with settings(hide('everything'), roledefs=roledefs): execute( task, hosts=hosts, roles=roles, exclude_hosts=exclude_hosts )
def check_connection_calls(host_strings, num_calls): # Clear Fudge call stack # Patch connect() with Fake obj set to expect num_calls calls patched_connect = patch_object('fabric.network', 'connect', Fake('connect', expect_call=True).times_called(num_calls) ) try: # Make new cache object cache = HostConnectionCache() # Connect to all connection strings for host_string in host_strings: # Obtain connection from cache, potentially calling connect() cache[host_string] finally: # Restore connect() patched_connect.restore()
def test_connection_cache_deletion(self): """ HostConnectionCache should delete correctly w/ non-full keys """ hcc = HostConnectionCache() fake = Fake('connect', callable=True) with patched_context('fabric.network', 'connect', fake): for host_string in ('hostname', 'user@hostname', 'user@hostname:222'): # Prime hcc[host_string] # Test ok_(host_string in hcc) # Delete del hcc[host_string] # Test ok_(host_string not in hcc)
def password_response(password, times_called=None, silent=True): """ Context manager which patches ``getpass.getpass`` to return ``password``. ``password`` may be a single string or an iterable of strings: * If single string, given password is returned every time ``getpass`` is called. * If iterable, iterated over for each call to ``getpass``, after which ``getpass`` will error. If ``times_called`` is given, it is used to add a ``Fake.times_called`` clause to the mock object, e.g. ``.times_called(1)``. Specifying ``times_called`` alongside an iterable ``password`` list is unsupported (see Fudge docs on ``Fake.next_call``). If ``silent`` is True, no prompt will be printed to ``sys.stderr``. """ fake = Fake('getpass', callable=True) # Assume stringtype or iterable, turn into mutable iterable if isinstance(password, six.string_types): passwords = [password] else: passwords = list(password) # Optional echoing of prompt to mimic real behavior of getpass # NOTE: also echo a newline if the prompt isn't a "passthrough" from the # server (as it means the server won't be sending its own newline for us). echo = lambda x, y: y.write(x + ("\n" if x != " " else "")) # Always return first (only?) password right away fake = fake.returns(passwords.pop(0)) if not silent: fake = fake.calls(echo) # If we had >1, return those afterwards for pw in passwords: fake = fake.next_call().returns(pw) if not silent: fake = fake.calls(echo) # Passthrough times_called if times_called: fake = fake.times_called(times_called) return patched_context(getpass, 'getpass', fake)
class MyTask(Task): name = "mytask" run = Fake(callable=True, expect_call=True)
class MyTask(Task): run = Fake(callable=True, expect_call=True)
def test_calls_task_function_objects(self): """ should execute the passed-in function object """ execute(Fake(callable=True, expect_call=True))
def test_error_calls_given_func_if_func_not_None(self): """ error(func=callable) => calls callable() """ error('foo', func=Fake(callable=True, expect_call=True))
class TestErrorHandling(FabricTest): dummy_string = 'test1234!' @with_patched_object(utils, 'warn', Fake('warn', callable=True, expect_call=True)) def test_error_warns_if_warn_only_True_and_func_None(self): """ warn_only=True, error(func=None) => calls warn() """ with settings(warn_only=True): error('foo') @with_patched_object(utils, 'abort', Fake('abort', callable=True, expect_call=True)) def test_error_aborts_if_warn_only_False_and_func_None(self): """ warn_only=False, error(func=None) => calls abort() """ with settings(warn_only=False): error('foo') def test_error_calls_given_func_if_func_not_None(self): """ error(func=callable) => calls callable() """ error('foo', func=Fake(callable=True, expect_call=True)) @mock_streams('stdout') @with_patched_object( utils, 'abort', Fake('abort', callable=True, expect_call=True).calls(lambda x: sys.stdout.write(x + "\n"))) def test_error_includes_stdout_if_given_and_hidden(self): """ error() correctly prints stdout if it was previously hidden """ # Mostly to catch regression bug(s) stdout = "this is my stdout" with hide('stdout'): error("error message", func=utils.abort, stdout=stdout) assert_contains(stdout, sys.stdout.getvalue()) @mock_streams('stdout') @with_patched_object( utils, 'abort', Fake('abort', callable=True, expect_call=True).calls(lambda x: sys.stdout.write(x + "\n"))) @with_patched_object(output, 'exceptions', True) @with_patched_object(utils, 'format_exc', Fake('format_exc', callable=True, expect_call=True).returns(dummy_string)) def test_includes_traceback_if_exceptions_logging_is_on(self): """ error() includes traceback in message if exceptions logging is on """ error("error message", func=utils.abort, stdout=error) assert_contains(self.dummy_string, sys.stdout.getvalue()) @mock_streams('stdout') @with_patched_object( utils, 'abort', Fake('abort', callable=True, expect_call=True).calls(lambda x: sys.stdout.write(x + "\n"))) @with_patched_object(output, 'debug', True) @with_patched_object(utils, 'format_exc', Fake('format_exc', callable=True, expect_call=True).returns(dummy_string)) def test_includes_traceback_if_debug_logging_is_on(self): """ error() includes traceback in message if debug logging is on (backwardis compatibility) """ error("error message", func=utils.abort, stdout=error) assert_contains(self.dummy_string, sys.stdout.getvalue()) @mock_streams('stdout') @with_patched_object( utils, 'abort', Fake('abort', callable=True, expect_call=True).calls(lambda x: sys.stdout.write(x + "\n"))) @with_patched_object(output, 'exceptions', True) @with_patched_object(utils, 'format_exc', Fake('format_exc', callable=True, expect_call=True).returns(None)) def test_doesnt_print_None_when_no_traceback_present(self): """ error() doesn't include None in message if there is no traceback """ error("error message", func=utils.abort, stdout=error) assert_not_contains('None', sys.stdout.getvalue()) @mock_streams('stderr') @with_patched_object( utils, 'abort', Fake('abort', callable=True, expect_call=True).calls(lambda x: sys.stderr.write(x + "\n"))) def test_error_includes_stderr_if_given_and_hidden(self): """ error() correctly prints stderr if it was previously hidden """ # Mostly to catch regression bug(s) stderr = "this is my stderr" with hide('stderr'): error("error message", func=utils.abort, stderr=stderr) assert_contains(stderr, sys.stderr.getvalue()) @mock_streams('stderr') def test_warnings_print_magenta_if_colorize_on(self): with settings(colorize_errors=True): error("oh god", func=utils.warn, stderr="oops") # can't use assert_contains as ANSI codes contain regex specialchars eq_(magenta("\nWarning: oh god\n\n"), sys.stderr.getvalue()) @mock_streams('stderr') @raises(SystemExit) def test_errors_print_red_if_colorize_on(self): with settings(colorize_errors=True): error("oh god", func=utils.abort, stderr="oops") # can't use assert_contains as ANSI codes contain regex specialchars eq_(red("\Error: oh god\n\n"), sys.stderr.getvalue())
class TestErrorHandling(FabricTest): @with_patched_object(utils, 'warn', Fake('warn', callable=True, expect_call=True)) def test_error_warns_if_warn_only_True_and_func_None(self): """ warn_only=True, error(func=None) => calls warn() """ with settings(warn_only=True): error('foo') @with_patched_object(utils, 'abort', Fake('abort', callable=True, expect_call=True)) def test_error_aborts_if_warn_only_False_and_func_None(self): """ warn_only=False, error(func=None) => calls abort() """ with settings(warn_only=False): error('foo') def test_error_calls_given_func_if_func_not_None(self): """ error(func=callable) => calls callable() """ error('foo', func=Fake(callable=True, expect_call=True)) @mock_streams('stdout') @with_patched_object(utils, 'abort', Fake('abort', callable=True, expect_call=True).calls(lambda x: sys.stdout.write(x + "\n"))) def test_error_includes_stdout_if_given_and_hidden(self): """ error() correctly prints stdout if it was previously hidden """ # Mostly to catch regression bug(s) stdout = "this is my stdout" with hide('stdout'): error("error message", func=utils.abort, stdout=stdout) assert_contains(stdout, sys.stdout.getvalue()) @mock_streams('stderr') @with_patched_object(utils, 'abort', Fake('abort', callable=True, expect_call=True).calls(lambda x: sys.stderr.write(x + "\n"))) def test_error_includes_stderr_if_given_and_hidden(self): """ error() correctly prints stderr if it was previously hidden """ # Mostly to catch regression bug(s) stderr = "this is my stderr" with hide('stderr'): error("error message", func=utils.abort, stderr=stderr) assert_contains(stderr, sys.stderr.getvalue()) @mock_streams('stderr') def test_warnings_print_magenta_if_colorize_on(self): with settings(colorize_errors=True): error("oh god", func=utils.warn, stderr="oops") # can't use assert_contains as ANSI codes contain regex specialchars eq_(magenta("\nWarning: oh god\n\n"), sys.stderr.getvalue()) @mock_streams('stderr') @raises(SystemExit) def test_errors_print_red_if_colorize_on(self): with settings(colorize_errors=True): error("oh god", func=utils.abort, stderr="oops") # can't use assert_contains as ANSI codes contain regex specialchars eq_(red("\Error: oh god\n\n"), sys.stderr.getvalue())