Пример #1
0
 def can_be_pickled(self):
     c = Context()
     c.foo = {"bar": {"biz": ["baz", "buzz"]}}
     c2 = pickle.loads(pickle.dumps(c))
     assert c == c2
     assert c is not c2
     assert c.foo.bar.biz is not c2.foo.bar.biz
Пример #2
0
 def echo_hides_extra_sudo_flags(self):
     skip()  # see TODO in sudo() re: clean output display
     config = Config(overrides={"runner": _Dummy})
     Context(config=config).sudo("nope", echo=True)
     output = sys.stdout.getvalue()
     sys.__stderr__.write(repr(output) + "\n")
     assert "-S" not in output
     assert Context().sudo.prompt not in output
     assert "sudo nope" in output
Пример #3
0
        def prefixes_should_apply_to_sudo(self, Local):
            runner = Local.return_value
            c = Context()
            with c.prefix("cd foo"):
                c.sudo("whoami")

            cmd = "sudo -S -p '[sudo] password: ' cd foo && whoami"
            assert runner.run.called, "sudo() never called runner.run()!"
            assert runner.run.call_args[0][0] == cmd
Пример #4
0
        def prefixes_should_apply_to_run(self, Local):
            runner = Local.return_value
            c = Context()
            with c.prefix("cd foo"):
                c.run("whoami")

            cmd = "cd foo && whoami"
            assert runner.run.called, "run() never called runner.run()!"
            assert runner.run.call_args[0][0] == cmd
Пример #5
0
 def kwarg_only_adds_to_kwarg(self, Local):
     runner = Local.return_value
     context = Context()
     watcher = self.watcher_klass()
     context.sudo("whoami", watchers=[watcher])
     # When sudo() called w/ user-specified watchers, we add ours to
     # that list
     watchers = runner.run.call_args[1]["watchers"]
     # Will raise ValueError if not in the list
     watchers.remove(watcher)
     # Only remaining item in list should be our sudo responder
     assert len(watchers) == 1
     assert isinstance(watchers[0], FailingResponder)
     assert watchers[0].pattern == self.escaped_prompt
Пример #6
0
def sites(c):
    """
    Build both doc sites w/ maxed nitpicking.
    """
    # TODO: This is super lolzy but we haven't actually tackled nontrivial
    # in-Python task calling yet, so we do this to get a copy of 'our' context,
    # which has been updated with the per-collection config data of the
    # docs/www subcollections.
    docs_c = Context(config=c.config.clone())
    www_c = Context(config=c.config.clone())
    docs_c.update(**docs.configuration())
    www_c.update(**www.configuration())
    # Must build both normally first to ensure good intersphinx inventory files
    # exist =/ circular dependencies ahoy! Do it quietly to avoid pulluting
    # output; only super-serious errors will bubble up.
    # TODO: wants a 'temporarily tweak context settings' contextmanager
    # TODO: also a f*****g spinner cuz this confuses me every time I run it
    # when the docs aren't already prebuilt
    docs_c["run"].hide = True
    www_c["run"].hide = True
    docs["build"](docs_c)
    www["build"](www_c)
    docs_c["run"].hide = False
    www_c["run"].hide = False
    # Run the actual builds, with nitpick=True (nitpicks + tracebacks)
    docs["build"](docs_c, nitpick=True)
    www["build"](www_c, nitpick=True)
Пример #7
0
 def prefixes_command_with_sudo(self, Local):
     runner = Local.return_value
     Context().sudo("whoami")
     # NOTE: implicitly tests default sudo.prompt conf value
     cmd = "sudo -S -p '[sudo] password: ' whoami"
     assert runner.run.called, "sudo() never called runner.run()!"
     assert runner.run.call_args[0][0] == cmd
Пример #8
0
 def tracks_times_called(self):
     context = Context()
     assert self.task.called is False
     self.task(context)
     assert self.task.called is True
     assert self.task.times_called == 1
     self.task(context)
     assert self.task.times_called == 2
Пример #9
0
 def base_case(self):
     # NOTE: Assumes a user whose password is 'mypass' has been created
     # & added to passworded (not passwordless) sudo configuration; and
     # that this user is the one running the test suite. Only for
     # running on Travis, basically.
     if not os.environ.get("TRAVIS", False):
         skip()
     config = Config({"sudo": {"password": "******"}})
     result = Context(config=config).sudo("whoami", hide=True)
     assert result.stdout.strip() == "root"
Пример #10
0
 def passes_through_other_run_kwargs(self, Local):
     runner = Local.return_value
     Context().sudo(
         "whoami", echo=True, warn=False, hide=True, encoding="ascii"
     )
     assert runner.run.called, "sudo() never called runner.run()!"
     kwargs = runner.run.call_args[1]
     assert kwargs["echo"] is True
     assert kwargs["warn"] is False
     assert kwargs["hide"] is True
     assert kwargs["encoding"] == "ascii"
Пример #11
0
        def _expect_responses(self, expected, config=None, kwargs=None):
            """
            Execute mocked sudo(), expecting watchers= kwarg in its run().

            * expected: list of 2-tuples of FailingResponder prompt/response
            * config: Config object, if an overridden one is needed
            * kwargs: sudo() kwargs, if needed
            """
            if kwargs is None:
                kwargs = {}
            Local = Mock()
            runner = Local.return_value
            context = Context(config=config) if config else Context()
            context.config.runners.local = Local
            context.sudo("whoami", **kwargs)
            # Tease out the interesting bits - pattern/response - ignoring the
            # sentinel, etc for now.
            prompt_responses = [
                (watcher.pattern, watcher.response)
                for watcher in runner.run.call_args[1]["watchers"]
            ]
            assert prompt_responses == expected
Пример #12
0
        def nesting_should_retain_order(self, Local):
            runner = Local.return_value
            c = Context()
            with c.prefix("cd foo"):
                with c.prefix("cd bar"):
                    c.run("whoami")
                    cmd = "cd foo && cd bar && whoami"
                    assert (
                        runner.run.called
                    ), "run() never called runner.run()!"  # noqa
                    assert runner.run.call_args[0][0] == cmd

                c.run("whoami")
                cmd = "cd foo && whoami"
                assert runner.run.called, "run() never called runner.run()!"
                assert runner.run.call_args[0][0] == cmd

            # also test that prefixes do not persist
            c.run("whoami")
            cmd = "whoami"
            assert runner.run.called, "run() never called runner.run()!"
            assert runner.run.call_args[0][0] == cmd
Пример #13
0
        def should_occur_before_prefixes(self, Local):
            runner = Local.return_value
            c = Context()
            with c.prefix("source venv"):
                with c.cd("foo"):
                    c.run("whoami")

            cmd = "cd foo && source venv && whoami"
            assert runner.run.called, "run() never called runner.run()!"
            assert runner.run.call_args[0][0] == cmd
Пример #14
0
 def config_only(self, Local):
     runner = Local.return_value
     # Set a config-driven list of watchers
     watcher = self.watcher_klass()
     overrides = {"run": {"watchers": [watcher]}}
     config = Config(overrides=overrides)
     Context(config=config).sudo("whoami")
     # Expect that sudo() extracted that config value & put it into
     # the kwarg level. (See comment in sudo() about why...)
     watchers = runner.run.call_args[1]["watchers"]
     # Will raise ValueError if not in the list
     watchers.remove(watcher)
     # Only remaining item in list should be our sudo responder
     assert len(watchers) == 1
     assert isinstance(watchers[0], FailingResponder)
     assert watchers[0].pattern == self.escaped_prompt
Пример #15
0
def watch_docs(c):
    """
    Watch both doc trees & rebuild them if files change.

    This includes e.g. rebuilding the API docs if the source code changes;
    rebuilding the WWW docs if the README changes; etc.

    Reuses the configuration values ``packaging.package`` or ``tests.package``
    (the former winning over the latter if both defined) when determining which
    source directory to scan for API doc updates.
    """
    # TODO: break back down into generic single-site version, then create split
    # tasks as with docs/www above. Probably wants raft#63.

    # NOTE: 'www'/'docs' refer to the module level sub-collections. meh.

    # Readme & WWW triggers WWW
    www_c = Context(config=c.config.clone())
    www_c.update(**www.configuration())
    www_handler = make_handler(
        ctx=www_c,
        task_=www["build"],
        regexes=[r"\./README.rst", r"\./sites/www"],
        ignore_regexes=[r".*/\..*\.swp", r"\./sites/www/_build"],
    )

    # Code and docs trigger API
    docs_c = Context(config=c.config.clone())
    docs_c.update(**docs.configuration())
    regexes = [r"\./sites/docs"]
    package = c.get("packaging", {}).get("package", None)
    if package is None:
        package = c.get("tests", {}).get("package", None)
    if package:
        regexes.append(r"\./{}/".format(package))
    api_handler = make_handler(
        ctx=docs_c,
        task_=docs["build"],
        regexes=regexes,
        ignore_regexes=[r".*/\..*\.swp", r"\./sites/docs/_build"],
    )

    observe(www_handler, api_handler)
Пример #16
0
        def should_use_finally_to_revert_changes_on_exceptions(self, Local):
            class Oops(Exception):
                pass

            runner = Local.return_value
            c = Context()
            try:
                with c.prefix("cd foo"):
                    c.run("whoami")
                    assert runner.run.call_args[0][0] == "cd foo && whoami"
                    raise Oops
            except Oops:
                pass
            c.run("ls")
            # When bug present, this would be "cd foo && ls"
            assert runner.run.call_args[0][0] == "ls"
Пример #17
0
        def _hang_on_full_pipe(self, pty):
            class Whoops(Exception):
                pass

            runner = Local(Context())
            # Force runner IO thread-body method to raise an exception to mimic
            # real world encoding explosions/etc. When bug is present, this
            # will make the test hang until forcibly terminated.
            runner.handle_stdout = Mock(side_effect=Whoops, __name__="sigh")
            # NOTE: both Darwin (10.10) and Linux (Travis' docker image) have
            # this file. It's plenty large enough to fill most pipe buffers,
            # which is the triggering behavior.
            try:
                runner.run("cat /usr/share/dict/words", pty=pty)
            except ThreadException as e:
                assert len(e.exceptions) == 1
                assert e.exceptions[0].type is Whoops
            else:
                assert False, "Did not receive expected ThreadException!"
Пример #18
0
 def raises_auth_failure_when_failure_detected(self):
     with patch("raft.context.FailingResponder") as klass:
         unacceptable = Mock(side_effect=ResponseNotAccepted)
         klass.return_value.submit = unacceptable
         excepted = False
         try:
             config = Config(overrides={"sudo": {"password": "******"}})
             Context(config=config).sudo("meh", hide=True)
         except AuthFailure as e:
             # Basic sanity checks; most of this is really tested in
             # Runner tests.
             assert e.result.exited is None
             expected = "The password submitted to prompt '[sudo] password: '******'t use except/else as that masks other real exceptions,
         # such as incorrectly unhandled ThreadErrors
         if not excepted:
             assert False, "Did not raise AuthFailure!"
Пример #19
0
 def config_use_does_not_modify_config(self, Local):
     runner = Local.return_value
     watcher = self.watcher_klass()
     overrides = {"run": {"watchers": [watcher]}}
     config = Config(overrides=overrides)
     Context(config=config).sudo("whoami")
     # Here, 'watchers' is _the same object_ as was passed into
     # run(watchers=...).
     watchers = runner.run.call_args[1]["watchers"]
     # We want to make sure that what's in the config we just
     # generated, is untouched by the manipulation done inside
     # sudo().
     # First, that they aren't the same obj
     err = "Found sudo() reusing config watchers list directly!"
     assert watchers is not config.run.watchers, err
     # And that the list is as it was before (i.e. it is not both
     # our watcher and the sudo()-added one)
     err = "Our config watchers list was modified!"
     assert config.run.watchers == [watcher], err
Пример #20
0
 def both_kwarg_and_config(self, Local):
     runner = Local.return_value
     # Set a config-driven list of watchers
     conf_watcher = self.watcher_klass()
     overrides = {"run": {"watchers": [conf_watcher]}}
     config = Config(overrides=overrides)
     # AND supply a DIFFERENT kwarg-driven list of watchers
     kwarg_watcher = self.watcher_klass()
     Context(config=config).sudo("whoami", watchers=[kwarg_watcher])
     # Expect that the kwarg watcher and our internal one were the
     # final result.
     watchers = runner.run.call_args[1]["watchers"]
     # Will raise ValueError if not in the list. .remove() uses
     # identity testing, so two instances of self.watcher_klass will
     # be different values here.
     watchers.remove(kwarg_watcher)
     # Only remaining item in list should be our sudo responder
     assert len(watchers) == 1
     assert conf_watcher not in watchers  # Extra sanity
     assert isinstance(watchers[0], FailingResponder)
     assert watchers[0].pattern == self.escaped_prompt
Пример #21
0
 def takes_optional_config_arg(self):
     # Meh-tastic doesn't-barf tests. MEH.
     Context()
     Context(config={"foo": "bar"})
Пример #22
0
 def dunder_call_wraps_body_call(self):
     context = Context()
     assert self.task(context) == 5
Пример #23
0
 def setup(self):
     config = Config(defaults={"foo": "bar", "biz": {"baz": "boz"}})
     self.c = Context(config=config)
Пример #24
0
    class configuration_proxy:
        "Dict-like proxy for self.config"

        def setup(self):
            config = Config(defaults={"foo": "bar", "biz": {"baz": "boz"}})
            self.c = Context(config=config)

        def direct_access_allowed(self):
            assert self.c.config.__class__ == Config
            assert self.c.config["foo"] == "bar"
            assert self.c.config.foo == "bar"

        def config_attr_may_be_overwritten_at_runtime(self):
            new_config = Config(defaults={"foo": "notbar"})
            self.c.config = new_config
            assert self.c.foo == "notbar"

        def getitem(self):
            "___getitem__"
            assert self.c["foo"] == "bar"
            assert self.c["biz"]["baz"] == "boz"

        def getattr(self):
            "__getattr__"
            assert self.c.foo == "bar"
            assert self.c.biz.baz == "boz"

        def get(self):
            assert self.c.get("foo") == "bar"
            assert self.c.get("nope", "wut") == "wut"
            assert self.c.biz.get("nope", "hrm") == "hrm"

        def pop(self):
            assert self.c.pop("foo") == "bar"
            assert self.c.pop("foo", "notbar") == "notbar"
            assert self.c.biz.pop("baz") == "boz"

        def popitem(self):
            assert self.c.biz.popitem() == ("baz", "boz")
            del self.c["biz"]
            assert self.c.popitem() == ("foo", "bar")
            assert self.c.config == {}

        def del_(self):
            "del"
            del self.c["foo"]
            del self.c["biz"]["baz"]
            assert self.c.biz == {}
            del self.c["biz"]
            assert self.c.config == {}

        def clear(self):
            self.c.biz.clear()
            assert self.c.biz == {}
            self.c.clear()
            assert self.c.config == {}

        def setdefault(self):
            assert self.c.setdefault("foo") == "bar"
            assert self.c.biz.setdefault("baz") == "boz"
            assert self.c.setdefault("notfoo", "notbar") == "notbar"
            assert self.c.notfoo == "notbar"
            assert self.c.biz.setdefault("otherbaz", "otherboz") == "otherboz"
            assert self.c.biz.otherbaz == "otherboz"

        def update(self):
            self.c.update({"newkey": "newval"})
            assert self.c["newkey"] == "newval"
            assert self.c.foo == "bar"
            self.c.biz.update(otherbaz="otherboz")
            assert self.c.biz.otherbaz == "otherboz"
Пример #25
0
 def honors_runner_config_setting(self):
     runner_class = Mock()
     config = Config({"runners": {"local": runner_class}})
     c = Context(config)
     c.run("foo")
     assert runner_class.mock_calls == [call(c), call().run("foo")]
Пример #26
0
 def honors_config_for_prompt_value(self, Local):
     runner = Local.return_value
     config = Config(overrides={"sudo": {"prompt": "FEED ME: "}})
     Context(config=config).sudo("whoami")
     cmd = "sudo -S -p 'FEED ME: ' whoami"
     assert runner.run.call_args[0][0] == cmd
Пример #27
0
 def returns_run_result(self, Local):
     runner = Local.return_value
     expected = runner.run.return_value
     result = Context().sudo("whoami")
     err = "sudo() did not return run()'s return value!"
     assert result is expected, err
Пример #28
0
 def user_kwarg_wins_over_config(self, Local):
     runner = Local.return_value
     config = Config(overrides={"sudo": {"user": "******"}})
     Context(config=config).sudo("whoami", user="******")
     cmd = "sudo -S -p '[sudo] password: ' -H -u calrissian whoami"
     assert runner.run.call_args[0][0] == cmd
Пример #29
0
 def defaults_to_Local(self, Local):
     c = Context()
     c.run("foo")
     assert Local.mock_calls == [call(c), call().run("foo")]
Пример #30
0
 def _expect_attr(self, attr):
     c = Context()
     assert hasattr(c, attr) and callable(getattr(c, attr))