Skip to content

Commit 550a2e2

Browse files
Merge pull request #94 from baloise/test-deploy-command
test(deploy): add tests for deploy command
2 parents 9b4dff2 + 708b065 commit 550a2e2

3 files changed

Lines changed: 324 additions & 2 deletions

File tree

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ lint:
99
pylint gitopscli
1010

1111
test:
12-
python3 -m pytest -v -s
12+
python3 -m pytest -vv -s
1313

1414
image:
1515
docker build -t gitopscli:latest .

gitopscli/commands/deploy.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ def __create_pr(git, branch, file, updated_values, auto_merge):
105105
```
106106
"""
107107
pull_request = git.create_pull_request(branch, "master", title, description)
108-
logging.info("Pull request created: %s", {git.get_pull_request_url(pull_request)})
108+
logging.info("Pull request created: %s", git.get_pull_request_url(pull_request))
109109

110110
if auto_merge:
111111
git.merge_pull_request(pull_request)

tests/commands/test_deploy.py

Lines changed: 322 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,322 @@
1+
import unittest
2+
from uuid import UUID
3+
from unittest.mock import patch, MagicMock, Mock, call
4+
import pytest
5+
from gitopscli.gitops_exception import GitOpsException
6+
from gitopscli.commands.deploy import deploy_command
7+
8+
9+
class DeployCommandTest(unittest.TestCase):
10+
def setUp(self):
11+
def add_patch(target):
12+
patcher = patch(target)
13+
self.addCleanup(patcher.stop)
14+
return patcher.start()
15+
16+
# Monkey patch all external functions the command is using:
17+
self.os_path_isfile_mock = add_patch("gitopscli.commands.deploy.os.path.isfile")
18+
self.update_yaml_file_mock = add_patch("gitopscli.commands.deploy.update_yaml_file")
19+
self.create_tmp_dir_mock = add_patch("gitopscli.commands.deploy.create_tmp_dir")
20+
self.delete_tmp_dir_mock = add_patch("gitopscli.commands.deploy.delete_tmp_dir")
21+
self.logging_mock = add_patch("gitopscli.commands.deploy.logging")
22+
self.uuid_mock = add_patch("gitopscli.commands.deploy.uuid")
23+
self.create_git_mock = add_patch("gitopscli.commands.deploy.create_git")
24+
self.git_util_mock = MagicMock()
25+
26+
# Attach all mocks to a single mock manager
27+
self.mock_manager = Mock()
28+
self.mock_manager.attach_mock(self.create_tmp_dir_mock, "create_tmp_dir")
29+
self.mock_manager.attach_mock(self.create_git_mock, "create_git")
30+
self.mock_manager.attach_mock(self.git_util_mock, "git_util")
31+
self.mock_manager.attach_mock(self.delete_tmp_dir_mock, "delete_tmp_dir")
32+
self.mock_manager.attach_mock(self.update_yaml_file_mock, "update_yaml_file")
33+
self.mock_manager.attach_mock(self.os_path_isfile_mock, "os.path.isfile")
34+
self.mock_manager.attach_mock(self.logging_mock, "logging")
35+
36+
# Define some common default return values
37+
self.create_git_mock.return_value = self.git_util_mock
38+
self.create_tmp_dir_mock.return_value = "/tmp/created-tmp-dir"
39+
self.git_util_mock.get_full_file_path.side_effect = lambda x: f"/tmp/created-tmp-dir/{x}"
40+
self.git_util_mock.create_pull_request.return_value = "<dummy-pr-object>"
41+
self.git_util_mock.get_pull_request_url.side_effect = lambda x: f"<url of {x}>"
42+
self.os_path_isfile_mock.return_value = True
43+
self.update_yaml_file_mock.return_value = True
44+
self.uuid_mock.uuid4.return_value = UUID("b973b5bb-64a6-4735-a840-3113d531b41c")
45+
46+
def test_happy_flow(self):
47+
deploy_command(
48+
command="deploy",
49+
file="test/file.yml",
50+
values={"a.b.c": "foo", "a.b.d": "bar"},
51+
username="USERNAME",
52+
password="PASSWORD",
53+
git_user="GIT_USER",
54+
git_email="GIT_EMAIL",
55+
create_pr=False,
56+
auto_merge=False,
57+
single_commit=False,
58+
organisation="ORGA",
59+
repository_name="REPO",
60+
git_provider="github",
61+
git_provider_url=None,
62+
)
63+
64+
assert self.mock_manager.mock_calls == [
65+
call.create_tmp_dir(),
66+
call.create_git(
67+
"USERNAME", "PASSWORD", "GIT_USER", "GIT_EMAIL", "ORGA", "REPO", "github", None, "/tmp/created-tmp-dir"
68+
),
69+
call.git_util.checkout("master"),
70+
call.logging.info("Master checkout successful"),
71+
call.git_util.get_full_file_path("test/file.yml"),
72+
call.os.path.isfile("/tmp/created-tmp-dir/test/file.yml"),
73+
call.update_yaml_file("/tmp/created-tmp-dir/test/file.yml", "a.b.c", "foo"),
74+
call.logging.info("Updated yaml property %s to %s", "a.b.c", "foo"),
75+
call.git_util.commit("changed 'a.b.c' to 'foo' in test/file.yml"),
76+
call.update_yaml_file("/tmp/created-tmp-dir/test/file.yml", "a.b.d", "bar"),
77+
call.logging.info("Updated yaml property %s to %s", "a.b.d", "bar"),
78+
call.git_util.commit("changed 'a.b.d' to 'bar' in test/file.yml"),
79+
call.git_util.push("master"),
80+
call.logging.info("Pushed branch %s", "master"),
81+
call.delete_tmp_dir("/tmp/created-tmp-dir"),
82+
]
83+
84+
def test_create_pr_happy_flow(self):
85+
deploy_command(
86+
command="deploy",
87+
file="test/file.yml",
88+
values={"a.b.c": "foo", "a.b.d": "bar"},
89+
username="USERNAME",
90+
password="PASSWORD",
91+
git_user="GIT_USER",
92+
git_email="GIT_EMAIL",
93+
create_pr=True,
94+
auto_merge=False,
95+
single_commit=False,
96+
organisation="ORGA",
97+
repository_name="REPO",
98+
git_provider="github",
99+
git_provider_url=None,
100+
)
101+
102+
assert self.mock_manager.mock_calls == [
103+
call.create_tmp_dir(),
104+
call.create_git(
105+
"USERNAME", "PASSWORD", "GIT_USER", "GIT_EMAIL", "ORGA", "REPO", "github", None, "/tmp/created-tmp-dir"
106+
),
107+
call.git_util.checkout("master"),
108+
call.logging.info("Master checkout successful"),
109+
call.git_util.new_branch("gitopscli-deploy-b973b5bb"),
110+
call.logging.info("Created branch %s", "gitopscli-deploy-b973b5bb"),
111+
call.git_util.get_full_file_path("test/file.yml"),
112+
call.os.path.isfile("/tmp/created-tmp-dir/test/file.yml"),
113+
call.update_yaml_file("/tmp/created-tmp-dir/test/file.yml", "a.b.c", "foo"),
114+
call.logging.info("Updated yaml property %s to %s", "a.b.c", "foo"),
115+
call.git_util.commit("changed 'a.b.c' to 'foo' in test/file.yml"),
116+
call.update_yaml_file("/tmp/created-tmp-dir/test/file.yml", "a.b.d", "bar"),
117+
call.logging.info("Updated yaml property %s to %s", "a.b.d", "bar"),
118+
call.git_util.commit("changed 'a.b.d' to 'bar' in test/file.yml"),
119+
call.git_util.push("gitopscli-deploy-b973b5bb"),
120+
call.logging.info("Pushed branch %s", "gitopscli-deploy-b973b5bb"),
121+
call.delete_tmp_dir("/tmp/created-tmp-dir"),
122+
call.git_util.create_pull_request(
123+
"gitopscli-deploy-b973b5bb",
124+
"master",
125+
"Updated values in test/file.yml",
126+
"Updated 2 values in `test/file.yml`:\n```yaml\na.b.c: foo\na.b.d: bar\n```\n",
127+
),
128+
call.git_util.get_pull_request_url("<dummy-pr-object>"),
129+
call.logging.info("Pull request created: %s", "<url of <dummy-pr-object>>"),
130+
]
131+
132+
def test_create_pr_and_merge_happy_flow(self):
133+
deploy_command(
134+
command="deploy",
135+
file="test/file.yml",
136+
values={"a.b.c": "foo", "a.b.d": "bar"},
137+
username="USERNAME",
138+
password="PASSWORD",
139+
git_user="GIT_USER",
140+
git_email="GIT_EMAIL",
141+
create_pr=True,
142+
auto_merge=True,
143+
single_commit=False,
144+
organisation="ORGA",
145+
repository_name="REPO",
146+
git_provider="github",
147+
git_provider_url=None,
148+
)
149+
150+
assert self.mock_manager.mock_calls == [
151+
call.create_tmp_dir(),
152+
call.create_git(
153+
"USERNAME", "PASSWORD", "GIT_USER", "GIT_EMAIL", "ORGA", "REPO", "github", None, "/tmp/created-tmp-dir"
154+
),
155+
call.git_util.checkout("master"),
156+
call.logging.info("Master checkout successful"),
157+
call.git_util.new_branch("gitopscli-deploy-b973b5bb"),
158+
call.logging.info("Created branch %s", "gitopscli-deploy-b973b5bb"),
159+
call.git_util.get_full_file_path("test/file.yml"),
160+
call.os.path.isfile("/tmp/created-tmp-dir/test/file.yml"),
161+
call.update_yaml_file("/tmp/created-tmp-dir/test/file.yml", "a.b.c", "foo"),
162+
call.logging.info("Updated yaml property %s to %s", "a.b.c", "foo"),
163+
call.git_util.commit("changed 'a.b.c' to 'foo' in test/file.yml"),
164+
call.update_yaml_file("/tmp/created-tmp-dir/test/file.yml", "a.b.d", "bar"),
165+
call.logging.info("Updated yaml property %s to %s", "a.b.d", "bar"),
166+
call.git_util.commit("changed 'a.b.d' to 'bar' in test/file.yml"),
167+
call.git_util.push("gitopscli-deploy-b973b5bb"),
168+
call.logging.info("Pushed branch %s", "gitopscli-deploy-b973b5bb"),
169+
call.delete_tmp_dir("/tmp/created-tmp-dir"),
170+
call.git_util.create_pull_request(
171+
"gitopscli-deploy-b973b5bb",
172+
"master",
173+
"Updated values in test/file.yml",
174+
"Updated 2 values in `test/file.yml`:\n```yaml\na.b.c: foo\na.b.d: bar\n```\n",
175+
),
176+
call.git_util.get_pull_request_url("<dummy-pr-object>"),
177+
call.logging.info("Pull request created: %s", "<url of <dummy-pr-object>>"),
178+
call.git_util.merge_pull_request("<dummy-pr-object>"),
179+
call.logging.info("Pull request merged"),
180+
call.git_util.delete_branch("gitopscli-deploy-b973b5bb"),
181+
call.logging.info("Branch '%s' deleted", "gitopscli-deploy-b973b5bb"),
182+
]
183+
184+
def test_single_commit_happy_flow(self):
185+
deploy_command(
186+
command="deploy",
187+
file="test/file.yml",
188+
values={"a.b.c": "foo", "a.b.d": "bar"},
189+
username="USERNAME",
190+
password="PASSWORD",
191+
git_user="GIT_USER",
192+
git_email="GIT_EMAIL",
193+
create_pr=False,
194+
auto_merge=False,
195+
single_commit=True,
196+
organisation="ORGA",
197+
repository_name="REPO",
198+
git_provider="github",
199+
git_provider_url=None,
200+
)
201+
202+
assert self.mock_manager.mock_calls == [
203+
call.create_tmp_dir(),
204+
call.create_git(
205+
"USERNAME", "PASSWORD", "GIT_USER", "GIT_EMAIL", "ORGA", "REPO", "github", None, "/tmp/created-tmp-dir"
206+
),
207+
call.git_util.checkout("master"),
208+
call.logging.info("Master checkout successful"),
209+
call.git_util.get_full_file_path("test/file.yml"),
210+
call.os.path.isfile("/tmp/created-tmp-dir/test/file.yml"),
211+
call.update_yaml_file("/tmp/created-tmp-dir/test/file.yml", "a.b.c", "foo"),
212+
call.logging.info("Updated yaml property %s to %s", "a.b.c", "foo"),
213+
call.update_yaml_file("/tmp/created-tmp-dir/test/file.yml", "a.b.d", "bar"),
214+
call.logging.info("Updated yaml property %s to %s", "a.b.d", "bar"),
215+
call.git_util.commit("updated 2 values in test/file.yml\n\na.b.c: foo\na.b.d: bar"),
216+
call.git_util.push("master"),
217+
call.logging.info("Pushed branch %s", "master"),
218+
call.delete_tmp_dir("/tmp/created-tmp-dir"),
219+
]
220+
221+
def test_checkout_error(self):
222+
checkout_exception = GitOpsException("dummy checkout error")
223+
self.git_util_mock.checkout.side_effect = checkout_exception
224+
225+
with pytest.raises(GitOpsException) as ex:
226+
deploy_command(
227+
command="deploy",
228+
file="test/file.yml",
229+
values={"a.b.c": "foo", "a.b.d": "bar"},
230+
username="USERNAME",
231+
password="PASSWORD",
232+
git_user="GIT_USER",
233+
git_email="GIT_EMAIL",
234+
create_pr=False,
235+
auto_merge=False,
236+
single_commit=False,
237+
organisation="ORGA",
238+
repository_name="REPO",
239+
git_provider="github",
240+
git_provider_url=None,
241+
)
242+
self.assertEqual(ex.value, checkout_exception)
243+
244+
assert self.mock_manager.mock_calls == [
245+
call.create_tmp_dir(),
246+
call.create_git(
247+
"USERNAME", "PASSWORD", "GIT_USER", "GIT_EMAIL", "ORGA", "REPO", "github", None, "/tmp/created-tmp-dir"
248+
),
249+
call.git_util.checkout("master"),
250+
call.delete_tmp_dir("/tmp/created-tmp-dir"),
251+
]
252+
253+
def test_file_not_found(self):
254+
self.os_path_isfile_mock.return_value = False
255+
256+
with pytest.raises(GitOpsException) as ex:
257+
deploy_command(
258+
command="deploy",
259+
file="test/file.yml",
260+
values={"a.b.c": "foo", "a.b.d": "bar"},
261+
username="USERNAME",
262+
password="PASSWORD",
263+
git_user="GIT_USER",
264+
git_email="GIT_EMAIL",
265+
create_pr=False,
266+
auto_merge=False,
267+
single_commit=False,
268+
organisation="ORGA",
269+
repository_name="REPO",
270+
git_provider="github",
271+
git_provider_url=None,
272+
)
273+
self.assertEqual(str(ex.value), "No such file: test/file.yml")
274+
275+
assert self.mock_manager.mock_calls == [
276+
call.create_tmp_dir(),
277+
call.create_git(
278+
"USERNAME", "PASSWORD", "GIT_USER", "GIT_EMAIL", "ORGA", "REPO", "github", None, "/tmp/created-tmp-dir"
279+
),
280+
call.git_util.checkout("master"),
281+
call.logging.info("Master checkout successful"),
282+
call.git_util.get_full_file_path("test/file.yml"),
283+
call.os.path.isfile("/tmp/created-tmp-dir/test/file.yml"),
284+
call.delete_tmp_dir("/tmp/created-tmp-dir"),
285+
]
286+
287+
def test_nothing_to_update(self):
288+
self.update_yaml_file_mock.return_value = False
289+
290+
deploy_command(
291+
command="deploy",
292+
file="test/file.yml",
293+
values={"a.b.c": "foo", "a.b.d": "bar"},
294+
username="USERNAME",
295+
password="PASSWORD",
296+
git_user="GIT_USER",
297+
git_email="GIT_EMAIL",
298+
create_pr=False,
299+
auto_merge=False,
300+
single_commit=False,
301+
organisation="ORGA",
302+
repository_name="REPO",
303+
git_provider="github",
304+
git_provider_url=None,
305+
)
306+
307+
assert self.mock_manager.mock_calls == [
308+
call.create_tmp_dir(),
309+
call.create_git(
310+
"USERNAME", "PASSWORD", "GIT_USER", "GIT_EMAIL", "ORGA", "REPO", "github", None, "/tmp/created-tmp-dir"
311+
),
312+
call.git_util.checkout("master"),
313+
call.logging.info("Master checkout successful"),
314+
call.git_util.get_full_file_path("test/file.yml"),
315+
call.os.path.isfile("/tmp/created-tmp-dir/test/file.yml"),
316+
call.update_yaml_file("/tmp/created-tmp-dir/test/file.yml", "a.b.c", "foo"),
317+
call.logging.info("Yaml property %s already up-to-date", "a.b.c"),
318+
call.update_yaml_file("/tmp/created-tmp-dir/test/file.yml", "a.b.d", "bar"),
319+
call.logging.info("Yaml property %s already up-to-date", "a.b.d"),
320+
call.logging.info("All values already up-to-date. I'm done here"),
321+
call.delete_tmp_dir("/tmp/created-tmp-dir"),
322+
]

0 commit comments

Comments
 (0)