From 7324971e2368ddc2341b8c33fa104632fe84f768 Mon Sep 17 00:00:00 2001 From: azawlocki Date: Wed, 14 Apr 2021 08:14:01 +0200 Subject: [PATCH 1/5] Fix issues with monitored logger --- goth/runner/log.py | 8 ++++---- goth/runner/probe/__init__.py | 10 +++++++--- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/goth/runner/log.py b/goth/runner/log.py index 2613e35f..7327decc 100644 --- a/goth/runner/log.py +++ b/goth/runner/log.py @@ -185,10 +185,10 @@ def monitored_logger(name: str, monitor: EventMonitor[str]) -> Iterator[logging. from the logger. """ - logger_ = logging.getLogger(name) + logger_to_monitor = logging.getLogger(name) filter = MonitoringFilter(monitor, "cyan") - logger_.filters.insert(0, filter) + logger_to_monitor.filters.insert(0, filter) try: - yield logger_ + yield logger_to_monitor finally: - logger.removeFilter(filter) + logger_to_monitor.removeFilter(filter) diff --git a/goth/runner/probe/__init__.py b/goth/runner/probe/__init__.py index 5d1c658e..94ae5d95 100644 --- a/goth/runner/probe/__init__.py +++ b/goth/runner/probe/__init__.py @@ -34,7 +34,7 @@ YagnaContainerConfig, PAYMENT_MOUNT_PATH, ) -from goth.runner.exceptions import KeyAlreadyExistsError +from goth.runner.exceptions import KeyAlreadyExistsError, TemporalAssertionError from goth.runner.log import LogConfig, monitored_logger from goth.runner.log_monitor import PatternMatchingEventMonitor from goth.runner.probe.agent import AgentComponent, ProviderAgentComponent @@ -313,6 +313,7 @@ async def run_command_on_host( with monitored_logger( f"goth.{self.name}.command_output", cmd_monitor ) as cmd_logger: + cmd_task = asyncio.create_task( process.run_command( command.split(), @@ -324,6 +325,9 @@ async def run_command_on_host( ) yield cmd_task, cmd_monitor + await cmd_task + logger.debug("Command task has finished") + except Exception as e: logger.warning(f"Cancelling command on error: {e!r}") if cmd_task and not cmd_task.done(): @@ -332,8 +336,8 @@ async def run_command_on_host( finally: await cmd_monitor.stop() - logger.debug("Waiting for the command to finish") - await asyncio.gather(cmd_task, return_exceptions=True) + for assertion in cmd_monitor.failed: + raise TemporalAssertionError(assertion.name) @contextlib.contextmanager From ee6e14d7ae6f251fc7653e38373fd8c98c9c679b Mon Sep 17 00:00:00 2001 From: azawlocki Date: Wed, 14 Apr 2021 08:15:18 +0200 Subject: [PATCH 2/5] Change the default way of handling TestFailure exceptions in Runner --- goth/runner/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/goth/runner/__init__.py b/goth/runner/__init__.py index 74d5ce41..8d71cea0 100644 --- a/goth/runner/__init__.py +++ b/goth/runner/__init__.py @@ -253,7 +253,7 @@ async def __call__( if self._test_failure_callback: self._test_failure_callback(err) else: - logger.info("Runner stopped due to test failure") + raise async def _enter(self) -> None: self._exit_stack.enter_context(configure_logging_for_test(self.log_dir)) From 41024d07f6499f2535d437b8a1a5437407b84b47 Mon Sep 17 00:00:00 2001 From: azawlocki Date: Wed, 14 Apr 2021 08:21:44 +0200 Subject: [PATCH 3/5] Stop monitor after stopping buffering task, not before, in LogMonitor --- goth/runner/log_monitor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/goth/runner/log_monitor.py b/goth/runner/log_monitor.py index 1d2309ff..b741b9ca 100644 --- a/goth/runner/log_monitor.py +++ b/goth/runner/log_monitor.py @@ -178,9 +178,9 @@ def start(self, in_stream: Iterator[bytes]): async def stop(self) -> None: """Stop the monitor.""" - await super().stop() if self._buffer_task: self._buffer_task.stop(StopThreadException) + await super().stop() def update_stream(self, in_stream: Iterator[bytes]): """Update the stream when restarting a container.""" From 38d4baf4e01230b41dc659aea495c4604210b443 Mon Sep 17 00:00:00 2001 From: azawlocki Date: Wed, 14 Apr 2021 08:29:05 +0200 Subject: [PATCH 4/5] Add unit test for Probe.run_command_on_host --- .../runner/probe/test_run_command_on_host.py | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 test/goth/runner/probe/test_run_command_on_host.py diff --git a/test/goth/runner/probe/test_run_command_on_host.py b/test/goth/runner/probe/test_run_command_on_host.py new file mode 100644 index 00000000..8208db42 --- /dev/null +++ b/test/goth/runner/probe/test_run_command_on_host.py @@ -0,0 +1,63 @@ +"""Tests for the method Probe.run_command_on_host.""" +import os +import pytest +from unittest.mock import MagicMock + +from goth.address import YAGNA_BUS_URL, YAGNA_REST_URL +import goth.runner.container.yagna +from goth.runner.probe import RequestorProbe + + +@pytest.mark.asyncio +async def test_run_command_on_host(monkeypatch): + """Test if the method `run_command_on_host` works as expected.""" + + runner = MagicMock() + docker_client = MagicMock() + container_config = MagicMock() + log_config = MagicMock() + + monkeypatch.setattr(goth.runner.probe, "YagnaContainer", MagicMock(spec="ports")) + monkeypatch.setattr(goth.runner.probe, "Cli", MagicMock(spec="yagna")) + monkeypatch.setattr( + goth.runner.probe, "get_container_address", lambda *_args: "1.2.3.4" + ) + monkeypatch.setattr(RequestorProbe, "app_key", "0xcafebabe") + + probe = RequestorProbe( + runner=runner, + client=docker_client, + config=container_config, + log_config=log_config, + ) + + async def func(lines): + # The monitor should guarantee that we don't skip any events + assert len(lines.past_events) == 0, lines.past_events + env = {} + async for line in lines: + tokens = line.split("=", 1) + if len(tokens) == 2: + env[tokens[0]] = tokens[1] + return env + + async with probe.run_command_on_host( + "/usr/bin/env", + env=os.environ, + ) as (_task, monitor): + assertion = monitor.add_assertion(func) + + result = await assertion.wait_for_result(timeout=1) + + assert result["YAGNA_APPKEY"] == probe.app_key + assert result["YAGNA_API_URL"] == YAGNA_REST_URL.substitute(host=None) + assert result["GSB_URL"] == YAGNA_BUS_URL.substitute(host=None) + + # Let's make sure that another command can be run without problems + # (see https://github.com/golemfactory/goth/issues/484). + async with probe.run_command_on_host("/bin/echo eChO", env=os.environ) as ( + _task, + monitor, + ): + + monitor.wait_for_pattern(".*eChO", timeout=10) From a81f8648db8322d5239ace303ef744bdd21110a9 Mon Sep 17 00:00:00 2001 From: azawlocki Date: Wed, 14 Apr 2021 12:07:00 +0200 Subject: [PATCH 5/5] Bump `goth` version in `pyproject.toml` --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 9a4b73c1..a6f3e4d7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ exclude= '/(\.eggs|\.git|\.hg|\.mypy_cache|\.nox|\.tox|\.venv|venv|\.svn|_build| [tool.poetry] name = "goth" -version = "0.2.0" +version = "0.2.1" description = "Golem Test Harness - integration testing framework" authors = ["Golem Factory "] license = "GPL-3.0"