Browse files

Global state is bad no matter what

This is in prep for some memoization in invoke.Program,
without these changes that change means only the first
ever test of hits the memoized block...
  • Loading branch information...
bitprophet committed Nov 8, 2018
1 parent b16a928 commit 401aa9fd8a6d93dad3a38dc9f7622df193f790fb
Showing with 40 additions and 29 deletions.
  1. +11 −6 fabric/
  2. +2 −2 tests/
  3. +27 −21 tests/
@@ -138,9 +138,14 @@ def update_config(self):
program = Fab(
# Mostly a concession to testing.
def make_program():
return Fab(
program = make_program()
@@ -8,7 +8,7 @@
from pytest_relaxed import trap
from fabric import Connection as Connection_, Config as Config_
from fabric.main import program as fab_program
from fabric.main import make_program
from paramiko import SSHConfig
@@ -26,7 +26,7 @@ def eq_(got, expected):
def expect(invocation, out, program=None, test="equals"):
if program is None:
program = fab_program
program = make_program()"fab {}".format(invocation), exit=False)
output = sys.stdout.getvalue()
if test == "equals":
@@ -11,7 +11,7 @@
from pytest_relaxed import raises
from fabric.config import Config
from fabric.main import program
from fabric.main import make_program
from fabric.exceptions import NothingToDo
from _util import expect, Session, support, config_file, trap
@@ -49,12 +49,12 @@ def exposes_hosts_flag_in_help(self):
def executes_remainder_as_anonymous_task(self, remote):
remote.expect(host="myhost", cmd="whoami")"fab -H myhost -- whoami", exit=False)
make_program().run("fab -H myhost -- whoami", exit=False)
def uses_FABRIC_env_prefix(self, environ):
environ["FABRIC_RUN_ECHO"] = "1"
with cd(support):"fab expect-from-env")
make_program().run("fab expect-from-env")
def basic_pre_and_post_tasks_still_work(self):
with cd(support):
@@ -95,7 +95,7 @@ def loads_fabric_config_files_not_invoke_ones(self):
with cd(os.path.join(support, "{}_conf".format(type_))):
# This task, in each subdir, expects data present in a
# fabric.<ext> nearby to show up in the config."fab expect-conf-value")
make_program().run("fab expect-conf-value")
class runtime_ssh_config_path:
def _run(
@@ -108,7 +108,7 @@ def _run(
# Relies on asserts within the task, which will bubble up as
# it's executed in-process
cmd = "fab -c runtime_fabfile {} {} -H runtime {}", file_, tasks))
make_program().run(cmd.format(flag, file_, tasks))
def capital_F_flag_specifies_runtime_ssh_config_file(self):
@@ -142,24 +142,24 @@ def single_string_is_single_host_and_single_exec(self, remote):
# dumb bug where one appends to, instead of replacing, the task
# list during parameterization/expansion XD
with cd(support):"fab -H myhost basic-run")
make_program().run("fab -H myhost basic-run")
def comma_separated_string_is_multiple_hosts(self, remote):
Session("host1", cmd="nope"), Session("host2", cmd="nope")
with cd(support):"fab -H host1,host2 basic-run")
make_program().run("fab -H host1,host2 basic-run")
def multiple_hosts_works_with_remainder_too(self, remote):
Session("host1", cmd="whoami"), Session("host2", cmd="whoami")
)"fab -H host1,host2 -- whoami")
make_program().run("fab -H host1,host2 -- whoami")
def host_string_shorthand_is_passed_through(self, remote):
remote.expect(host="host1", port=1234, user="someuser")"fab -H someuser@host1:1234 -- whoami")
make_program().run("fab -H someuser@host1:1234 -- whoami")
# NOTE: no mocking because no actual run() under test, only
# parameterization
@@ -171,12 +171,16 @@ def host_string_shorthand_is_passed_through(self, remote):
def config_mutation_not_preserved(self):
with cd(support):"fab -H host1,host2 expect-mutation-to-fail")
"fab -H host1,host2 expect-mutation-to-fail"
def pre_post_tasks_are_not_parameterized_across_hosts(self):
with cd(support):"fab -H hostA,hostB,hostC second --show-host")
"fab -H hostA,hostB,hostC second --show-host"
output = sys.stdout.getvalue()
# Expect pre once, 3x main, post once, as opposed to e.g. both
# pre and main task
@@ -192,17 +196,17 @@ def pre_post_tasks_are_not_parameterized_across_hosts(self):
class no_hosts_flag:
def calls_task_once_with_invoke_context(self):
with cd(support):"fab expect-vanilla-Context")
make_program().run("fab expect-vanilla-Context")
def generates_exception_if_combined_with_remainder(self):"fab -- nope")
make_program().run("fab -- nope")
def invokelike_multitask_invocation_preserves_config_mutation(self):
# Mostly a guard against Executor subclass tweaks breaking Invoke
# behavior added in pyinvoke/invoke#309
with cd(support):"fab mutate expect-mutation")
make_program().run("fab mutate expect-mutation")
class runtime_identity_file:
def dash_i_supplies_default_connect_kwarg_key_filename(self):
@@ -211,15 +215,17 @@ def dash_i_supplies_default_connect_kwarg_key_filename(self):
# relying on other tests to prove connect_kwargs makes its way into
# that context.
with cd(support):"fab -i identity.key expect-identity")
make_program().run("fab -i identity.key expect-identity")
def double_dash_identity_also_works(self):
with cd(support):"fab --identity identity.key expect-identity")
"fab --identity identity.key expect-identity"
def may_be_given_multiple_times(self):
with cd(support):
"fab -i identity.key -i identity2.key expect-identities"
@@ -230,7 +236,7 @@ def _expect_prompt(self, getpass, flag, key, value, prompt):
with cd(support):
# Expect that the given key was found in the context.
cmd = "fab -c prompting {} expect-connect-kwarg --key {} --val {}" # noqa, key, value))
make_program().run(cmd.format(flag, key, value))
# Then we also expect that getpass was called w/ expected prompt
@@ -257,11 +263,11 @@ def key_filename_can_be_set_via_non_override_config_levels(self):
# test fixtures, which has a fabric.yml w/ a
# connect_kwargs.key_filename value of [private.key, other.key].
with cd(os.path.join(support, "yml_conf")):"fab expect-conf-key-filename")
make_program().run("fab expect-conf-key-filename")
def cli_identity_still_overrides_when_non_empty(self):
with cd(os.path.join(support, "yml_conf")):"fab -i cli.key expect-cli-key-filename")
make_program().run("fab -i cli.key expect-cli-key-filename")
class completion:
# NOTE: most completion tests are in Invoke too; this is just an
@@ -272,7 +278,7 @@ def complete_flag_does_not_trigger_remainder_only_behavior(self):
# collections because it thinks it's in remainder-only,
# work-without-a-collection mode.
with cd(support):"fab --complete -- fab", exit=False)
make_program().run("fab --complete -- fab", exit=False)
# Cherry-picked sanity checks looking for tasks from fixture
# fabfile
output = sys.stdout.getvalue()

0 comments on commit 401aa9f

Please sign in to comment.