Skip to content

Commit 585fcb4

Browse files
authored
Add testing for the command line interface (#43)
1 parent 14fc913 commit 585fcb4

File tree

2 files changed

+167
-11
lines changed

2 files changed

+167
-11
lines changed

tests/conftest.py

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
from collections.abc import AsyncGenerator, Generator
44
from typing import Any
5+
from unittest.mock import MagicMock, patch
56

67
import aiohttp
78
from aioresponses import aioresponses
@@ -41,14 +42,14 @@
4142

4243
@pytest.fixture(name="session")
4344
async def aiohttp_client_session() -> AsyncGenerator[aiohttp.ClientSession, Any]:
44-
"""Create a client session."""
45+
"""Create a client session."""
4546
async with aiohttp.ClientSession() as session:
4647
yield session
4748

4849

4950
@pytest.fixture(name="pyload")
50-
async def mocked_pyloadapi_client(session: aiohttp.ClientSession) -> PyLoadAPI:
51-
"""Create Bring instance."""
51+
async def pyloadapi_client(session: aiohttp.ClientSession) -> PyLoadAPI:
52+
"""Create pyLoad instance."""
5253
pyload = PyLoadAPI(
5354
session,
5455
TEST_API_URL,
@@ -65,12 +66,12 @@ def aioclient_mock() -> Generator[aioresponses, Any, None]:
6566
yield m
6667

6768

68-
def parametrize_exception(
69-
exception: Exception,
70-
expected: Any,
71-
mocked_aiohttp: aioresponses,
72-
) -> Any:
73-
"""Parametrize exceptions."""
74-
mocked_aiohttp.post(r".*", exception=exception)
69+
@pytest.fixture
70+
def mock_pyloadapi() -> Generator[MagicMock, None, None]:
71+
"""Mock pyloadapi."""
7572

76-
return pytest.raises(expected)
73+
with patch("pyloadapi.cli.PyLoadAPI", autospec=True) as mock_client:
74+
client = mock_client.return_value
75+
client.get_status.return_value = TEST_STATUS_RESPONSE
76+
client.free_space.return_value = 107374182400
77+
yield client

tests/test_cli.py

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
"""Tests for pyloadapi CLI."""
2+
3+
from pathlib import Path
4+
from unittest.mock import MagicMock, patch
5+
6+
from click.testing import CliRunner
7+
import pytest
8+
9+
from pyloadapi import CannotConnect, InvalidAuth, ParserError
10+
from pyloadapi.cli import cli
11+
12+
from .conftest import TEST_API_URL, TEST_PASSWORD, TEST_USERNAME
13+
14+
15+
@pytest.mark.usefixtures("mock_pyloadapi")
16+
def test_status() -> None:
17+
"""Test status."""
18+
runner = CliRunner()
19+
with runner.isolated_filesystem():
20+
result = runner.invoke(
21+
cli,
22+
args=f"--username {TEST_USERNAME} --password {TEST_PASSWORD} --api-url {TEST_API_URL} status",
23+
)
24+
assert result.exit_code == 0
25+
assert result.output == (
26+
"Status:\n"
27+
" - Active Downloads: 10\n"
28+
" - Items in Queue: 5\n"
29+
" - Finished Downloads: 15\n"
30+
" - Download Speed: 80.0 Mbit/s\n"
31+
" - Free space: 100.0 GiB\n"
32+
" - Reconnect: Disabled\n"
33+
" - Queue : Running\n\n"
34+
)
35+
36+
37+
@pytest.mark.usefixtures("mock_pyloadapi")
38+
def test_missing_credentials(tmp_path: Path) -> None:
39+
"""Test status."""
40+
p = tmp_path / ".pyload_config.json"
41+
with patch("pyloadapi.cli.CONFIG_FILE_PATH", p) as mock_path:
42+
assert p == mock_path
43+
runner = CliRunner()
44+
45+
result = runner.invoke(
46+
cli,
47+
args="status",
48+
)
49+
assert result.exit_code == 1
50+
assert (
51+
result.output
52+
== "Error: URL, username, and password must be provided either via command line or config file.\n"
53+
)
54+
55+
56+
@pytest.mark.parametrize(
57+
("command", "msg"),
58+
(
59+
("queue", "Resumed download queue.\n"),
60+
("stop-all", "Aborted all running downloads.\n"),
61+
("retry", "Retrying failed downloads.\n"),
62+
("delete-finished", "Deleted finished files and packages.\n"),
63+
("restart", "Restarting pyLoad...\n"),
64+
("toggle-reconnect", "Disabled auto-reconnect\n"),
65+
),
66+
)
67+
@pytest.mark.usefixtures("mock_pyloadapi")
68+
def test_all_commands(
69+
msg: str,
70+
command: str,
71+
) -> None:
72+
"""Test status."""
73+
runner = CliRunner()
74+
with runner.isolated_filesystem():
75+
result = runner.invoke(
76+
cli,
77+
args=f"--username {TEST_USERNAME} --password {TEST_PASSWORD} --api-url {TEST_API_URL} {command}",
78+
)
79+
assert result.exit_code == 0
80+
assert result.output == msg
81+
82+
83+
@pytest.mark.parametrize(
84+
("command", "pause", "msg"),
85+
[
86+
("queue -p", True, "Paused download queue.\n"),
87+
("queue --pause", True, "Paused download queue.\n"),
88+
("queue -r", False, "Resumed download queue.\n"),
89+
("queue --resume", False, "Resumed download queue.\n"),
90+
],
91+
)
92+
def test_queue_with_options(
93+
mock_pyloadapi: MagicMock, msg: str, command: str, pause: bool
94+
) -> None:
95+
"""Test status."""
96+
runner = CliRunner()
97+
with runner.isolated_filesystem():
98+
mock_pyloadapi.get_status.return_value = {"pause": pause}
99+
result = runner.invoke(
100+
cli,
101+
args=f"--username {TEST_USERNAME} --password {TEST_PASSWORD} --api-url {TEST_API_URL} {command}",
102+
)
103+
assert result.exit_code == 0
104+
assert result.output == msg
105+
106+
107+
@pytest.mark.parametrize(
108+
("exception", "msg"),
109+
[
110+
(CannotConnect, "Error: Unable to connect to pyLoad\n"),
111+
(InvalidAuth, "Error: Authentication failed, verify username and password\n"),
112+
(ParserError, "Error: Unable to parse response from pyLoad\n"),
113+
],
114+
)
115+
@pytest.mark.parametrize(
116+
("command"),
117+
(
118+
"status",
119+
"queue",
120+
"queue -p",
121+
"queue -r",
122+
"stop-all",
123+
"retry",
124+
"delete-finished",
125+
"restart",
126+
"toggle-reconnect",
127+
),
128+
)
129+
def test_exceptions(
130+
mock_pyloadapi: MagicMock,
131+
exception: Exception,
132+
msg: str,
133+
command: str,
134+
) -> None:
135+
"""Test status."""
136+
137+
runner = CliRunner()
138+
with runner.isolated_filesystem():
139+
mock_pyloadapi.get_status.side_effect = exception
140+
mock_pyloadapi.unpause.side_effect = exception
141+
mock_pyloadapi.pause.side_effect = exception
142+
mock_pyloadapi.toggle_pause.side_effect = exception
143+
mock_pyloadapi.stop_all_downloads.side_effect = exception
144+
mock_pyloadapi.restart_failed.side_effect = exception
145+
mock_pyloadapi.toggle_reconnect.side_effect = exception
146+
mock_pyloadapi.delete_finished.side_effect = exception
147+
mock_pyloadapi.restart.side_effect = exception
148+
mock_pyloadapi.free_space.side_effect = exception
149+
150+
result = runner.invoke(
151+
cli,
152+
args=f"--username {TEST_USERNAME} --password {TEST_PASSWORD} --api-url {TEST_API_URL} {command}",
153+
)
154+
assert result.exit_code == 1
155+
assert result.output == msg

0 commit comments

Comments
 (0)