Skip to content

Commit 89205fb

Browse files
committed
rewrite unit tests for the improved run_occ
Signed-off-by: Marc Crébassa <[email protected]>
1 parent a872607 commit 89205fb

File tree

1 file changed

+144
-109
lines changed

1 file changed

+144
-109
lines changed

tests/unit/module_utils/test_nc_tools.py

Lines changed: 144 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from ansible_collections.nextcloud.admin.plugins.module_utils.nc_tools import (
22
convert_string,
3+
execute_occ_command,
34
run_occ,
45
)
56
import ansible_collections.nextcloud.admin.plugins.module_utils.exceptions as occ_exceptions
@@ -50,6 +51,82 @@ def test_backslash_behaviour(self):
5051
)
5152

5253

54+
class TestExecuteOccCommand(unittest.TestCase):
55+
def setUp(self):
56+
self.mock_conn = MagicMock()
57+
self.module = MagicMock()
58+
self.mock_stat = patch("os.stat").start()
59+
self.mock_getuid = patch("os.getuid").start()
60+
self.mock_getgid = patch("os.getgid").start()
61+
self.mock_setuid = patch("os.setuid").start()
62+
self.mock_setgid = patch("os.setgid").start()
63+
self.mock_stat.return_value.st_uid = 1234
64+
self.mock_stat.return_value.st_gid = 1234
65+
self.mock_getuid.return_value = 1234
66+
self.mock_getgid.return_value = 1234
67+
self.addCleanup(patch.stopall)
68+
self.module.run_command.return_value = (0, "output", "")
69+
70+
def test_execute_occ_command_success(self):
71+
execute_occ_command(
72+
self.mock_conn, self.module, "/path/to/php", ["/path/to/occ", "command"]
73+
)
74+
75+
self.mock_conn.send.assert_called_once_with(
76+
{"rc": 0, "stdout": "output", "stderr": ""}
77+
)
78+
79+
def test_change_uid_execute_occ_command_success(self):
80+
self.mock_getuid.return_value = 0
81+
self.mock_getgid.return_value = 0
82+
83+
execute_occ_command(
84+
self.mock_conn, self.module, "/path/to/php", ["/path/to/occ", "command"]
85+
)
86+
87+
self.mock_conn.send.assert_called_once_with(
88+
{"rc": 0, "stdout": "output", "stderr": ""}
89+
)
90+
self.mock_setuid.assert_called_with(1234)
91+
self.mock_setgid.assert_called_with(1234)
92+
93+
def test_occ_command_FileNotFoundError(self):
94+
self.mock_stat.side_effect = FileNotFoundError
95+
96+
execute_occ_command(
97+
self.mock_conn, self.module, "/path/to/php", ["/path/to/occ", "command"]
98+
)
99+
100+
self.mock_conn.send.assert_called_once_with(
101+
{"exception": "OccFileNotFoundException"}
102+
)
103+
104+
def test_occ_command_PermissionError(self):
105+
self.mock_getuid.return_value = 0
106+
self.mock_getgid.return_value = 0
107+
self.mock_setuid.side_effect = PermissionError
108+
109+
execute_occ_command(
110+
self.mock_conn, self.module, "/path/to/php", ["/path/to/occ", "command"]
111+
)
112+
113+
self.mock_conn.send.assert_called_once_with(
114+
{
115+
"exception": "OccAuthenticationException",
116+
"msg": "Insufficient permissions to switch to user id 1234.",
117+
}
118+
)
119+
120+
def test_occ_command_AnyError(self):
121+
self.mock_getuid.side_effect = Exception("TKIAL")
122+
123+
execute_occ_command(
124+
self.mock_conn, self.module, "/path/to/php", ["/path/to/occ", "command"]
125+
)
126+
127+
self.mock_conn.send.assert_called_once_with({"exception": "TKIAL"})
128+
129+
53130
class TestRunOcc(unittest.TestCase):
54131

55132
def setUp(self):
@@ -60,16 +137,29 @@ def setUp(self):
60137
"php_runtime": "/usr/bin/php",
61138
}
62139

63-
@patch("os.stat")
64-
@patch("os.getuid")
65-
@patch("os.setgid")
66-
@patch("os.setuid")
67-
def test_run_occ_success(self, mock_setuid, mock_setgid, mock_getuid, mock_stat):
68-
# Setup mocks
69-
mock_stat.return_value.st_uid = 1000
70-
mock_stat.return_value.st_gid = 1000
71-
mock_getuid.return_value = 1001
72-
self.module.run_command.return_value = (0, "Success", "")
140+
self.mock_process = patch(
141+
"ansible_collections.nextcloud.admin.plugins.module_utils.nc_tools.Process"
142+
).start()
143+
self.mock_instance = self.mock_process.return_value
144+
self.mock_instance.start.return_value = None
145+
self.mock_instance.join.return_value = None
146+
147+
self.mock_pipe_parent, self.mock_pipe_child = MagicMock(), MagicMock()
148+
patcher_pipe = patch(
149+
"ansible_collections.nextcloud.admin.plugins.module_utils.nc_tools.Pipe",
150+
return_value=(self.mock_pipe_parent, self.mock_pipe_child),
151+
)
152+
patcher_pipe.start()
153+
154+
self.mock_pipe_parent.recv.return_value = {
155+
"rc": 0,
156+
"stdout": "Success",
157+
"stderr": "",
158+
}
159+
160+
self.addCleanup(patch.stopall)
161+
162+
def test_run_occ_success(self):
73163

74164
# Call the function
75165
returnCode, stdOut, stdErr, maintenanceMode = run_occ(self.module, "status")
@@ -79,21 +169,14 @@ def test_run_occ_success(self, mock_setuid, mock_setgid, mock_getuid, mock_stat)
79169
self.assertEqual(stdOut, "Success")
80170
self.assertEqual(stdErr, "")
81171
self.assertFalse(maintenanceMode)
82-
mock_setgid.assert_called_once_with(1000)
83-
mock_setuid.assert_called_once_with(1000)
84172

85-
@patch("os.stat")
86-
@patch("os.getuid")
87-
def test_run_occ_maintenance_mode(self, mock_getuid, mock_stat):
173+
def test_run_occ_maintenance_mode(self):
88174
# Setup mocks
89-
mock_stat.return_value.st_uid = 1000
90-
mock_stat.return_value.st_gid = 1000
91-
mock_getuid.return_value = 1000
92-
self.module.run_command.return_value = (
93-
0,
94-
"",
95-
"Nextcloud is in maintenance mode, no apps are loaded.",
96-
)
175+
self.mock_pipe_parent.recv.return_value = {
176+
"rc": 0,
177+
"stdout": "",
178+
"stderr": "Nextcloud is in maintenance mode, no apps are loaded.",
179+
}
97180

98181
# Call the function
99182
returnCode, stdOut, stdErr, maintenanceMode = run_occ(self.module, "status")
@@ -107,117 +190,69 @@ def test_run_occ_maintenance_mode(self, mock_getuid, mock_stat):
107190
self.assertIn("maintenance mode", stdErr)
108191
self.assertTrue(maintenanceMode)
109192

110-
@patch("os.stat")
111-
@patch("os.getuid", return_value=1000)
112-
def test_file_not_found_exception(self, mock_getuid, mock_stat):
193+
def test_file_not_found_exception(self):
113194
# Simulate FileNotFoundError when accessing the occ file
114-
mock_stat.side_effect = FileNotFoundError
195+
self.mock_pipe_parent.recv.return_value = {
196+
"exception": "OccFileNotFoundException",
197+
"msg": "",
198+
}
115199

116200
with self.assertRaises(occ_exceptions.OccFileNotFoundException):
117201
run_occ(self.module, "status")
118202

119-
@patch("os.stat")
120-
@patch("os.setuid")
121-
@patch("os.setgid")
122-
@patch("os.getuid", return_value=1000)
123-
def test_authentication_exception(
124-
self, mock_getuid, mock_setgid, mock_setuid, mock_stat
125-
):
203+
def test_authentication_exception(self):
126204
# Simulate PermissionError when trying to change user
127-
mock_stat.return_value.st_uid = 2000
128-
mock_stat.return_value.st_gid = 2000
129-
mock_setuid.side_effect = PermissionError
205+
self.mock_pipe_parent.recv.return_value = {
206+
"exception": "OccAuthenticationException",
207+
"msg": "",
208+
}
130209

131210
with self.assertRaises(occ_exceptions.OccAuthenticationException):
132211
run_occ(self.module, "status")
133212

134-
@patch("os.stat")
135-
@patch("os.setuid")
136-
@patch("os.setgid")
137-
@patch("os.getuid", return_value=1000)
138-
def test_no_commands_defined_exception(
139-
self, mock_getuid, mock_setgid, mock_setuid, mock_stat
140-
):
141-
# Mock successful stat call and simulate command execution error
142-
mock_stat.return_value.st_uid = 1000
143-
mock_stat.return_value.st_gid = 1000
144-
self.module.run_command.return_value = (1, "", "Command 'foo' is not defined.")
213+
def test_no_commands_defined_exception(self):
214+
# simulate command execution error
215+
self.mock_pipe_parent.recv.return_value = {
216+
"rc": 1,
217+
"stdout": "",
218+
"stderr": "Command 'foo' is not defined.",
219+
}
145220

146221
with self.assertRaises(occ_exceptions.OccNoCommandsDefined):
147222
run_occ(self.module, "foo")
148223

149-
@patch("os.stat")
150-
@patch("os.setuid")
151-
@patch("os.setgid")
152-
@patch("os.getuid", return_value=1000)
153-
def test_not_enough_arguments_exception(
154-
self, mock_getuid, mock_setgid, mock_setuid, mock_stat
155-
):
156-
# Mock successful stat call and simulate command execution error
157-
mock_stat.return_value.st_uid = 1000
158-
mock_stat.return_value.st_gid = 1000
159-
self.module.run_command.return_value = (
160-
1,
161-
"",
162-
'Not enough arguments (missing: "bar").',
163-
)
164-
224+
def test_not_enough_arguments_exception(self):
225+
# simulate command execution error
226+
self.mock_pipe_parent.recv.return_value = {
227+
"rc": 1,
228+
"stdout": "",
229+
"stderr": 'Not enough arguments (missing: "bar").',
230+
}
165231
with self.assertRaises(occ_exceptions.OccNotEnoughArguments):
166232
run_occ(self.module, "foo")
167233

168-
@patch("os.stat")
169-
@patch("os.setuid")
170-
@patch("os.setgid")
171-
@patch("os.getuid", return_value=1000)
172-
def test_option_not_defined_exception(
173-
self, mock_getuid, mock_setgid, mock_setuid, mock_stat
174-
):
175-
# Mock successful stat call and simulate command execution error
176-
mock_stat.return_value.st_uid = 1000
177-
mock_stat.return_value.st_gid = 1000
178-
self.module.run_command.return_value = (
179-
1,
180-
"",
181-
"The option '--baz' does not exist.",
182-
)
234+
def test_option_not_defined_exception(self):
235+
self.mock_pipe_parent.recv.return_value = {
236+
"rc": 1,
237+
"stdout": "",
238+
"stderr": "The option '--baz' does not exist.",
239+
}
183240

184241
with self.assertRaises(occ_exceptions.OccOptionNotDefined):
185242
run_occ(self.module, "foo --baz")
186243

187-
@patch("os.stat")
188-
@patch("os.setuid")
189-
@patch("os.setgid")
190-
@patch("os.getuid", return_value=1000)
191-
def test_option_requires_value_exception(
192-
self, mock_getuid, mock_setgid, mock_setuid, mock_stat
193-
):
194-
# Mock successful stat call and simulate command execution error
195-
mock_stat.return_value.st_uid = 1000
196-
mock_stat.return_value.st_gid = 1000
197-
self.module.run_command.return_value = (
198-
1,
199-
"",
200-
"The option '--baz' requires a value.",
201-
)
244+
def test_option_requires_value_exception(self):
245+
self.mock_pipe_parent.recv.return_value = {
246+
"rc": 1,
247+
"stdout": "",
248+
"stderr": "The option '--baz' requires a value.",
249+
}
202250

203251
with self.assertRaises(occ_exceptions.OccOptionRequiresValue):
204252
run_occ(self.module, "foo --baz")
205253

206-
@patch("os.stat")
207-
@patch("os.setuid")
208-
@patch("os.setgid")
209-
@patch("os.getuid", return_value=1000)
210-
def test_empty_msg_exception(
211-
self, mock_getuid, mock_setgid, mock_setuid, mock_stat
212-
):
213-
# Mock successful stat call and simulate command execution error
214-
mock_stat.return_value.st_uid = 1000
215-
mock_stat.return_value.st_gid = 1000
216-
self.module.run_command.return_value = (
217-
1,
218-
"",
219-
"",
220-
)
254+
def test_empty_msg_exception(self):
255+
self.mock_pipe_parent.recv.return_value = {"rc": 1, "stdout": "", "stderr": ""}
221256

222257
with self.assertRaises(occ_exceptions.OccExceptions):
223258
run_occ(self.module, "foo --baz")

0 commit comments

Comments
 (0)