Skip to content

Commit 993c863

Browse files
authored
Merge pull request #1757 from dbcli/RW/add-special-utils-tests
Add unit tests for `mycli/packages/special/utils.py`
2 parents 991334a + cc3a260 commit 993c863

2 files changed

Lines changed: 187 additions & 18 deletions

File tree

test/pytests/test_dbspecial.py

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
from mycli.packages.completion_engine import suggest_type
66
from mycli.packages.special.dbcommands import list_tables
7-
from mycli.packages.special.utils import format_uptime
87
from test.pytests.test_completion_engine import sorted_dicts
98

109

@@ -83,20 +82,3 @@ def test_describe_table():
8382
def test_list_or_show_create_tables():
8483
suggestions = suggest_type("\\dt+", "\\dt+ ")
8584
assert sorted_dicts(suggestions) == sorted_dicts([{"type": "table", "schema": []}, {"type": "view", "schema": []}, {"type": "schema"}])
86-
87-
88-
def test_format_uptime():
89-
seconds = 59
90-
assert "59 sec" == format_uptime(seconds)
91-
92-
seconds = 120
93-
assert "2 min 0 sec" == format_uptime(seconds)
94-
95-
seconds = 54890
96-
assert "15 hours 14 min 50 sec" == format_uptime(seconds)
97-
98-
seconds = 598244
99-
assert "6 days 22 hours 10 min 44 sec" == format_uptime(seconds)
100-
101-
seconds = 522600
102-
assert "6 days 1 hour 10 min 0 sec" == format_uptime(seconds)

test/pytests/test_special_utils.py

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
# type: ignore
2+
3+
import os
4+
import pathlib
5+
import tempfile
6+
from unittest.mock import MagicMock
7+
8+
import pymysql
9+
import pytest
10+
11+
import mycli.packages.special.utils
12+
from mycli.packages.special.utils import (
13+
CACHED_SSL_VERSION,
14+
format_uptime,
15+
get_ssl_version,
16+
get_uptime,
17+
get_warning_count,
18+
handle_cd_command,
19+
)
20+
from test.utils import TEMPFILE_PREFIX
21+
22+
23+
@pytest.fixture(autouse=True)
24+
def clear_ssl_cache() -> None:
25+
CACHED_SSL_VERSION.clear()
26+
27+
28+
def test_handle_cd_command_rejects_non_cd_command() -> None:
29+
handled, message = handle_cd_command(['pwd'])
30+
31+
assert handled is False
32+
assert message == 'Not a cd command.'
33+
34+
35+
def test_handle_cd_command_requires_exactly_one_directory() -> None:
36+
handled, message = handle_cd_command(['cd'])
37+
38+
assert handled is False
39+
assert message == 'Exactly one directory name must be provided.'
40+
41+
42+
def test_handle_cd_command_changes_directory_and_echoes_cwd(monkeypatch) -> None:
43+
echoed = []
44+
45+
monkeypatch.setattr(mycli.packages.special.utils.click, 'echo', lambda message, err=False: echoed.append((message, err)))
46+
monkeypatch.chdir(os.getcwd())
47+
48+
# resolve() is needed for mac /private/var arrangement
49+
with tempfile.TemporaryDirectory(prefix=TEMPFILE_PREFIX) as tempdir:
50+
tempdir_resolved = str(pathlib.Path(tempdir).resolve())
51+
handled, message = handle_cd_command(['cd', tempdir_resolved])
52+
assert str(pathlib.Path(os.getcwd()).resolve()) == tempdir_resolved
53+
assert handled is True
54+
assert message is None
55+
assert echoed == [(tempdir_resolved, True)]
56+
57+
58+
def test_handle_cd_command_returns_oserror_message(monkeypatch) -> None:
59+
def raise_oserror(directory: str) -> None:
60+
raise OSError(2, 'No such file or directory')
61+
62+
monkeypatch.setattr(mycli.packages.special.utils.os, 'chdir', raise_oserror)
63+
64+
handled, message = handle_cd_command(['cd', '/missing'])
65+
66+
assert handled is False
67+
assert message == 'No such file or directory'
68+
69+
70+
def test_format_uptime():
71+
seconds = 59
72+
assert '59 sec' == format_uptime(seconds)
73+
74+
seconds = 120
75+
assert '2 min 0 sec' == format_uptime(seconds)
76+
77+
seconds = 54890
78+
assert '15 hours 14 min 50 sec' == format_uptime(seconds)
79+
80+
seconds = 598244
81+
assert '6 days 22 hours 10 min 44 sec' == format_uptime(seconds)
82+
83+
seconds = 522600
84+
assert '6 days 1 hour 10 min 0 sec' == format_uptime(seconds)
85+
86+
87+
def test_format_uptime_uses_singular_units() -> None:
88+
assert format_uptime('90061') == '1 day 1 hour 1 min 1 sec'
89+
90+
91+
def test_get_uptime_returns_value_from_status_row() -> None:
92+
cur = MagicMock()
93+
cur.fetchone.return_value = ('Uptime', '15')
94+
95+
uptime = get_uptime(cur)
96+
97+
cur.execute.assert_called_once_with('SHOW STATUS LIKE "Uptime"')
98+
assert uptime == 15
99+
100+
101+
def test_get_uptime_defaults_to_zero_for_missing_value() -> None:
102+
cur = MagicMock()
103+
cur.fetchone.return_value = ('Uptime', None)
104+
105+
assert get_uptime(cur) == 0
106+
107+
108+
def test_get_uptime_ignores_operational_error() -> None:
109+
cur = MagicMock()
110+
cur.execute.side_effect = pymysql.err.OperationalError()
111+
112+
assert get_uptime(cur) == 0
113+
114+
115+
def test_get_warning_count_returns_value_from_count_row() -> None:
116+
cur = MagicMock()
117+
cur.fetchone.return_value = ('7',)
118+
119+
warning_count = get_warning_count(cur)
120+
121+
cur.execute.assert_called_once_with('SHOW COUNT(*) WARNINGS')
122+
assert warning_count == 7
123+
124+
125+
def test_get_warning_count_defaults_to_zero_for_missing_value() -> None:
126+
cur = MagicMock()
127+
cur.fetchone.return_value = (None,)
128+
129+
assert get_warning_count(cur) == 0
130+
131+
132+
def test_get_warning_count_ignores_operational_error() -> None:
133+
cur = MagicMock()
134+
cur.execute.side_effect = pymysql.err.OperationalError()
135+
136+
assert get_warning_count(cur) == 0
137+
138+
139+
def test_get_ssl_version_fetches_and_caches_value() -> None:
140+
cur = MagicMock()
141+
cur.connection = MagicMock()
142+
cur.connection.thread_id.return_value = 42
143+
cur.fetchone.return_value = ('Ssl_version', 'TLSv1.3')
144+
145+
first = get_ssl_version(cur)
146+
second = get_ssl_version(cur)
147+
148+
cur.execute.assert_called_once_with('SHOW STATUS LIKE "Ssl_version"')
149+
assert first == 'TLSv1.3'
150+
assert second == 'TLSv1.3'
151+
152+
153+
def test_get_ssl_version_caches_missing_row_as_none() -> None:
154+
cur = MagicMock()
155+
cur.connection = MagicMock()
156+
cur.connection.thread_id.return_value = 42
157+
cur.fetchone.return_value = None
158+
159+
first = get_ssl_version(cur)
160+
second = get_ssl_version(cur)
161+
162+
cur.execute.assert_called_once_with('SHOW STATUS LIKE "Ssl_version"')
163+
assert first is None
164+
assert second is None
165+
166+
167+
def test_get_ssl_version_returns_none_for_empty_value_and_caches_it() -> None:
168+
cur = MagicMock()
169+
cur.connection = MagicMock()
170+
cur.connection.thread_id.return_value = 42
171+
cur.fetchone.return_value = ('Ssl_version', '')
172+
173+
first = get_ssl_version(cur)
174+
second = get_ssl_version(cur)
175+
176+
cur.execute.assert_called_once_with('SHOW STATUS LIKE "Ssl_version"')
177+
assert first is None
178+
assert second is None
179+
180+
181+
def test_get_ssl_version_ignores_operational_error() -> None:
182+
cur = MagicMock()
183+
cur.connection = MagicMock()
184+
cur.connection.thread_id.return_value = 42
185+
cur.execute.side_effect = pymysql.err.OperationalError()
186+
187+
assert get_ssl_version(cur) is None

0 commit comments

Comments
 (0)