Skip to content

Commit

Permalink
Test asking again for API key
Browse files Browse the repository at this point in the history
Make it so that the `mock_input` context manager can indicate the
expectation of an unanswered prompt by using `None` instead of an
answer.

When this happens, the expected `StopIteration` that indicates that
a prompt was asked for which no answer was given is not raised as an
error.

Delete several duplicates of `mock_input` and move it to a single
`utils.py` file.
  • Loading branch information
unflxw committed Mar 7, 2024
1 parent eb69dde commit 1b55359
Show file tree
Hide file tree
Showing 6 changed files with 43 additions and 32 deletions.
4 changes: 2 additions & 2 deletions src/appsignal/cli/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def _push_api_key(self) -> str:
key = input("Please enter your Push API key: ")
return key

def _valid_push_api_key(self) -> str | NoReturn:
def _valid_push_api_key(self) -> str:
while True:
key = self._push_api_key()
config = Config(Options(push_api_key=key))
Expand Down Expand Up @@ -101,7 +101,7 @@ def _environment(self) -> str:
)
return environment

def _client_from_config_file(self) -> Client | None | NoReturn:
def _client_from_config_file(self) -> Client | None:
try:
return _client_from_config_file()
except Exception as error:
Expand Down
Empty file added tests/cli/__init__.py
Empty file.
10 changes: 1 addition & 9 deletions tests/cli/test_demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,11 @@

import os
import shutil
from contextlib import contextmanager

from appsignal.cli.base import main
from appsignal.cli.install import INSTALL_FILE_TEMPLATE


@contextmanager
def mock_input(mocker, *pairs: tuple[str, str]):
prompt_calls = [mocker.call(prompt) for (prompt, _) in pairs]
answers = [answer for (_, answer) in pairs]
mock = mocker.patch("builtins.input", side_effect=answers)
yield
assert prompt_calls == mock.mock_calls
from .utils import mock_input


def test_demo_with_valid_config(mocker, capfd):
Expand Down
10 changes: 1 addition & 9 deletions tests/cli/test_diagnose.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,11 @@

import os
import shutil
from contextlib import contextmanager

from appsignal.cli.base import main
from appsignal.cli.install import INSTALL_FILE_TEMPLATE


@contextmanager
def mock_input(mocker, *pairs: tuple[str, str]):
prompt_calls = [mocker.call(prompt) for (prompt, _) in pairs]
answers = [answer for (_, answer) in pairs]
mock = mocker.patch("builtins.input", side_effect=answers)
yield
assert prompt_calls == mock.mock_calls
from .utils import mock_input


def test_diagnose_with_valid_config(mocker, capfd):
Expand Down
32 changes: 20 additions & 12 deletions tests/cli/test_install.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@

import os
import shutil
from contextlib import contextmanager
from unittest.mock import MagicMock

from appsignal.cli.base import main
from appsignal.cli.install import INSTALL_FILE_TEMPLATE

from .utils import mock_input


EXPECTED_FILE_CONTENTS = """from appsignal import Appsignal
Expand All @@ -22,15 +23,6 @@
"""


@contextmanager
def mock_input(mocker, *pairs: tuple[str, str]):
prompt_calls = [mocker.call(prompt) for (prompt, _) in pairs]
answers = [answer for (_, answer) in pairs]
mock = mocker.patch("builtins.input", side_effect=answers)
yield
assert prompt_calls == mock.mock_calls


def mock_file_operations(mocker, file_exists: bool = False):
mocker.patch("os.path.exists", return_value=file_exists)
mocker.patch("appsignal.cli.install.open")
Expand All @@ -47,6 +39,17 @@ def assert_wrote_file_contents(mocker):
)


def assert_did_not_write_file_contents(mocker):
from appsignal.cli import install

builtins_open: MagicMock = install.open # type: ignore[attr-defined]
assert mocker.call("__appsignal__.py", "w") not in builtins_open.mock_calls
assert (
mocker.call().__enter__().write(EXPECTED_FILE_CONTENTS)
not in builtins_open.mock_calls
)


def assert_wrote_real_file_contents(test_dir, name, push_api_key):
with open(os.path.join(test_dir, "__appsignal__.py")) as f:
file_contents = INSTALL_FILE_TEMPLATE.format(
Expand Down Expand Up @@ -159,11 +162,16 @@ def test_install_command_when_file_exists_no_overwrite(mocker):
assert install.open.mock_calls == [] # type: ignore[attr-defined]


def test_install_comand_when_api_key_is_not_valid(mocker):
def test_install_command_when_invalid_api_key_ask_again(mocker):
mock_file_operations(mocker)
mock_validate_push_api_key_request(mocker, status_code=401)

with mock_input(
mocker,
("Please enter the name of your application: ", "My app name"),
("Please enter your Push API key: ", "My push API key"),
("Please enter your Push API key: ", None),
):
assert main(["install", "--push-api-key=bad-push-api-key"]) == 1
main(["install"])

assert_did_not_write_file_contents(mocker)
19 changes: 19 additions & 0 deletions tests/cli/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from __future__ import annotations

from contextlib import contextmanager


@contextmanager
def mock_input(mocker, *pairs: tuple[str, str | None]):
expected_unanswered = pairs[-1][1] is None

prompt_calls = [mocker.call(prompt) for (prompt, _) in pairs]
answers = [answer for (_, answer) in pairs if answer is not None]
mock = mocker.patch("builtins.input", side_effect=answers)
try:
yield
except StopIteration as e:
if not expected_unanswered:
raise e
finally:
assert prompt_calls == mock.mock_calls

0 comments on commit 1b55359

Please sign in to comment.