Skip to content

Commit e197d84

Browse files
piterpunkdwoz
authored andcommitted
Add unit tests for modules.ssh and states.ssh_auth
1 parent efa62a6 commit e197d84

File tree

2 files changed

+461
-3
lines changed

2 files changed

+461
-3
lines changed

tests/pytests/unit/states/test_ssh_auth.py

Lines changed: 260 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,103 @@
55
import pytest
66

77
import salt.states.ssh_auth as ssh_auth
8-
from tests.support.mock import MagicMock, patch
8+
from tests.support.mock import MagicMock, call, patch
99

1010

1111
@pytest.fixture
1212
def configure_loader_modules():
13-
return {ssh_auth: {}}
13+
return {ssh_auth: {"__env__": "base"}}
14+
15+
16+
@pytest.fixture()
17+
def enc_types():
18+
# This list is from sshd manual page of openssh 8.7
19+
return [
20+
21+
"ecdsa-sha2-nistp256",
22+
"ecdsa-sha2-nistp384",
23+
"ecdsa-sha2-nistp521",
24+
25+
"ssh-ed25519",
26+
"ssh-dss",
27+
"ssh-rsa",
28+
]
29+
30+
31+
def test__present_test(enc_types):
32+
"""
33+
Test to verify if many encryption key types are accepted by ssh_auth._present_test
34+
"""
35+
user = "user"
36+
key = "1ABCDXXXXXXXXXXXXXXXXXXXXXXXXXXXX="
37+
comment = "[email protected]"
38+
name_list = []
39+
expected_calls = []
40+
for enc in enc_types:
41+
name_list.append(f"{enc} {key} {comment}")
42+
expected_calls.append(
43+
call(
44+
user,
45+
key,
46+
enc,
47+
comment,
48+
[],
49+
config=".ssh/authorized_keys",
50+
fingerprint_hash_type=None,
51+
)
52+
)
53+
54+
mock_check_key = MagicMock(return_value="update")
55+
56+
with patch.dict(ssh_auth.__salt__, {"ssh.check_key": mock_check_key}):
57+
with patch.dict(ssh_auth.__opts__, {"test": True}):
58+
for name in name_list:
59+
ret = None, f"Key {key} for user {user} is set to be updated"
60+
assert (
61+
ssh_auth._present_test(
62+
user, name, enc, comment, [], "", ".ssh/authorized_keys", None
63+
)
64+
== ret
65+
)
66+
mock_check_key.assert_has_calls(expected_calls)
67+
68+
69+
def test__absent_test(enc_types):
70+
"""
71+
Test to verify if many encryption key types are accepted by ssh_auth._absent_test
72+
"""
73+
user = "user"
74+
key = "1ABCDXXXXXXXXXXXXXXXXXXXXXXXXXXXX="
75+
comment = "[email protected]"
76+
name_list = []
77+
expected_calls = []
78+
for enc in enc_types:
79+
name_list.append(f"{enc} {key} {comment}")
80+
expected_calls.append(
81+
call(
82+
user,
83+
key,
84+
enc,
85+
comment,
86+
[],
87+
config=".ssh/authorized_keys",
88+
fingerprint_hash_type=None,
89+
)
90+
)
91+
92+
mock_check_key = MagicMock(return_value="update")
93+
94+
with patch.dict(ssh_auth.__salt__, {"ssh.check_key": mock_check_key}):
95+
with patch.dict(ssh_auth.__opts__, {"test": True}):
96+
for name in name_list:
97+
ret = None, f"Key {key} for user {user} is set for removal"
98+
assert (
99+
ssh_auth._absent_test(
100+
user, name, enc, comment, [], "", ".ssh/authorized_keys", None
101+
)
102+
== ret
103+
)
104+
mock_check_key.assert_has_calls(expected_calls)
14105

15106

16107
def test_present():
@@ -44,6 +135,101 @@ def test_present():
44135
assert ssh_auth.present(name, user, source) == ret
45136

46137

138+
def test_present_with_source():
139+
"""
140+
Test to check if ssh.set_auth_key_from_file is called with the correct parameters
141+
"""
142+
user = "user"
143+
source = "salt://fakefile"
144+
config = ".ssh/authorized_keys"
145+
146+
mock_cp_get_url = MagicMock(return_value=True)
147+
mock_auth_key_from_file = MagicMock(return_value="new")
148+
149+
with patch.dict(
150+
ssh_auth.__salt__,
151+
{
152+
"cp.get_url": mock_cp_get_url,
153+
"ssh.set_auth_key_from_file": mock_auth_key_from_file,
154+
},
155+
):
156+
with patch.dict(ssh_auth.__opts__, {"test": False}):
157+
name = "Call Without Options"
158+
ret = {
159+
"name": name,
160+
"changes": {name: "New"},
161+
"result": True,
162+
"comment": f"The authorized host key {name} for user {user} was added",
163+
}
164+
assert ssh_auth.present(name, user, source=source) == ret
165+
mock_auth_key_from_file.assert_called_with(
166+
"user",
167+
"salt://fakefile",
168+
config=".ssh/authorized_keys",
169+
saltenv="base",
170+
fingerprint_hash_type=None,
171+
options=None,
172+
)
173+
name = "Call With Options"
174+
ret = {
175+
"name": name,
176+
"changes": {name: "New"},
177+
"result": True,
178+
"comment": f"The authorized host key {name} for user {user} was added",
179+
}
180+
assert (
181+
ssh_auth.present(name, user, source=source, options=["no-pty"]) == ret
182+
)
183+
mock_auth_key_from_file.assert_called_with(
184+
"user",
185+
"salt://fakefile",
186+
config=".ssh/authorized_keys",
187+
saltenv="base",
188+
fingerprint_hash_type=None,
189+
options=["no-pty"],
190+
)
191+
192+
193+
def test_present_different_key_types_are_accepted(enc_types):
194+
"""
195+
Test to verify if many encryption key types are accepted by ssh_auth.present
196+
"""
197+
user = "user"
198+
key = "1ABCDXXXXXXXXXXXXXXXXXXXXXXXXXXXX="
199+
comment = "[email protected]"
200+
name_list = []
201+
expected_calls = []
202+
for enc in enc_types:
203+
name_list.append(f"{enc} {key} {comment}")
204+
expected_calls.append(
205+
call(
206+
user,
207+
key,
208+
enc,
209+
comment,
210+
[],
211+
"",
212+
".ssh/authorized_keys",
213+
None,
214+
)
215+
)
216+
217+
with patch.object(
218+
ssh_auth, "_present_test", return_value=[None, "Key is to be added"]
219+
) as mock__present_test:
220+
# it's tested with `test: True` because this already tests the fullkey regexp
221+
with patch.dict(ssh_auth.__opts__, {"test": True}):
222+
for name in name_list:
223+
ret = {
224+
"name": name,
225+
"changes": {},
226+
"result": None,
227+
"comment": "Key is to be added",
228+
}
229+
assert ssh_auth.present(name, user) == ret
230+
mock__present_test.assert_has_calls(expected_calls)
231+
232+
47233
def test_absent():
48234
"""
49235
Test to verifies that the specified SSH key is absent.
@@ -80,6 +266,78 @@ def test_absent():
80266
assert ssh_auth.absent(name, user, source) == ret
81267

82268

269+
def test_absent_with_source():
270+
"""
271+
Test to check if ssh.rm_auth_key_from_file is called with the correct parameters
272+
"""
273+
user = "user"
274+
source = "salt://fakefile"
275+
config = ".ssh/authorized_keys"
276+
277+
mock_cp_get_url = MagicMock(return_value=True)
278+
mock_auth_key_from_file = MagicMock(return_value="Key removed")
279+
280+
with patch.dict(
281+
ssh_auth.__salt__,
282+
{
283+
"cp.get_url": mock_cp_get_url,
284+
"ssh.rm_auth_key_from_file": mock_auth_key_from_file,
285+
},
286+
):
287+
with patch.dict(ssh_auth.__opts__, {"test": False}):
288+
name = "Call Absent With Source"
289+
ret = {
290+
"name": name,
291+
"changes": {name: "Removed"},
292+
"result": True,
293+
"comment": "Key removed",
294+
}
295+
assert ssh_auth.absent(name, user, source=source) == ret
296+
mock_auth_key_from_file.assert_called_with(
297+
"user",
298+
"salt://fakefile",
299+
".ssh/authorized_keys",
300+
saltenv="base",
301+
fingerprint_hash_type=None,
302+
)
303+
304+
305+
def test_absent_with_different_key_types_are_accepted(enc_types):
306+
"""
307+
Test to verify if many encription key types are accepted
308+
"""
309+
user = "user"
310+
key = "1ABCDXXXXXXXXXXXXXXXXXXXXXXXXXXXX="
311+
comment = "[email protected]"
312+
name_list = []
313+
expected_calls = []
314+
for enc in enc_types:
315+
name_list.append(f"{enc} {key} {comment}")
316+
expected_calls.append(
317+
call(
318+
user,
319+
key,
320+
config=".ssh/authorized_keys",
321+
fingerprint_hash_type=None,
322+
)
323+
)
324+
325+
mock_rm_test = MagicMock(return_value="Key removed")
326+
327+
with patch.dict(ssh_auth.__salt__, {"ssh.rm_auth_key": mock_rm_test}):
328+
# it's tested with `test: False` because the fullkey regexp is only in the actual execution
329+
with patch.dict(ssh_auth.__opts__, {"test": False}):
330+
for name in name_list:
331+
ret = {
332+
"name": name,
333+
"changes": {key: "Removed"},
334+
"result": True,
335+
"comment": "Key removed",
336+
}
337+
assert ssh_auth.absent(name, user) == ret
338+
mock_rm_test.assert_has_calls(expected_calls)
339+
340+
83341
def test_manage():
84342
"""
85343
Test to verifies that the specified SSH key is absent.

0 commit comments

Comments
 (0)