Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[IO-1332][internal] E2E Test harness #632

Merged
merged 5 commits into from
Jul 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file added e2e_tests/__init__.py
Empty file.
5 changes: 5 additions & 0 deletions e2e_tests/e2e_test.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# End to end tests module

This module is setup in `pytest.ini` to _not run_. If you want to run the E2E tests,
you will need to run `pytest e2e_tests` rather than `pytest`.

42 changes: 42 additions & 0 deletions e2e_tests/helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from subprocess import run
from typing import Optional, Tuple

from darwin.exceptions import DarwinException


def run_cli_command(command: str, working_directory: Optional[str] = None) -> Tuple[int, str, str]:
"""
Run a CLI command and return the return code, stdout, and stderr.

Parameters
----------
command : str
The command to run.
working_directory : str, optional
The working directory to run the command in.

Returns
-------
Tuple[int, str, str]
The return code, stdout, and stderr.
"""

# Do ot allow directory traversal
if ".." in command or (working_directory and ".." in working_directory):
raise DarwinException("Cannot pass directory traversal to 'run_cli_command'.")

if working_directory:
result = run(
command,
cwd=working_directory,
capture_output=True,
shell=True,
)
else:
result = run(
command,
capture_output=True,
shell=True,
)

return result.returncode, result.stdout.decode("utf-8"), result.stderr.decode("utf-8")
9 changes: 9 additions & 0 deletions e2e_tests/test_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import pytest


def test_example_test_does_nothing() -> None:
assert True


if __name__ == "__main__":
pytest.main()
2 changes: 2 additions & 0 deletions pytest.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[pytest]
addopts = --ignore=e2e_tests
Empty file.
58 changes: 58 additions & 0 deletions tests/e2e_test_internals/test_run_cli_command.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
from collections import namedtuple
from unittest import mock

import pytest

from darwin.exceptions import DarwinException
from e2e_tests.helpers import run_cli_command


def test_does_not_allow_directory_traversal() -> None:
with pytest.raises(DarwinException) as excinfo:
run_cli_command("darwin --help; ls ..")

assert excinfo.value == "Cannot pass directory traversal to 'run_cli_command'."

with pytest.raises(DarwinException) as excinfo:
run_cli_command("darwin --help", working_directory="/usr/bin/../")
assert excinfo.value == "Cannot pass directory traversal to 'run_cli_command'."


@mock.patch("e2e_tests.helpers.run")
def test_passes_working_directory_to_run_cli_command(mock_subprocess_run: mock.Mock) -> None:
mock_subprocess_run.reset_mock()
run_cli_command("darwin --help", "/usr/bin")

mock_subprocess_run.assert_called_once()
assert mock_subprocess_run.call_args[0][0] == "darwin --help"
assert mock_subprocess_run.call_args[1]["cwd"] == "/usr/bin"


@mock.patch("e2e_tests.helpers.run")
def test_passes_back_returncode_stdout_and_stderr(mock_subprocess_run: mock.Mock) -> None:
CompletedProcess = namedtuple("CompletedProcess", ["returncode", "stdout", "stderr"])
mocked_output = CompletedProcess(returncode=137, stdout=b"stdout", stderr=b"stderr")

mock_subprocess_run.return_value = mocked_output

return_code, std_out, std_err = run_cli_command("darwin --help", "/usr/bin")

mock_subprocess_run.assert_called_once()

assert return_code == 137
assert std_out == "stdout"
assert std_err == "stderr"


@mock.patch("e2e_tests.helpers.run")
def test_does_not_pass_working_directory_to_run_cli_command(mock_subprocess_run: mock.Mock) -> None:
mock_subprocess_run.reset_mock()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this shouldn't be necessary, patch resets automatically after exiting a decorator

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's true, originally, I was wrapping several tests in a with mock.patch but removed it because it's very messy. I'll correct in the next ticket because it's in the same area

run_cli_command("darwin --help")

mock_subprocess_run.assert_called_once()
assert mock_subprocess_run.call_args[0][0] == "darwin --help"
assert "cwd" not in mock_subprocess_run.call_args[1]


if __name__ == "__main__":
pytest.main()
Loading