Skip to content

Commit c22abf5

Browse files
committed
Add deployments unit tests
1 parent b5d4dc0 commit c22abf5

File tree

2 files changed

+329
-2
lines changed

2 files changed

+329
-2
lines changed

coriolisclient/cli/deployments.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ def get_parser(self, prog_name):
200200
return parser
201201

202202
def take_action(self, args):
203-
m = self.app.client_manager.coriolis.deployments
203+
d = self.app.client_manager.coriolis.deployments
204204
user_scripts = cli_utils.compose_user_scripts(
205205
args.global_scripts, args.instance_scripts)
206206
instance_osmorphing_minion_pool_mappings = None
@@ -209,7 +209,7 @@ def take_action(self, args):
209209
mp['instance_id']: mp['pool_id']
210210
for mp in args.instance_osmorphing_minion_pool_mappings}
211211

212-
deployment = m.create_from_transfer(
212+
deployment = d.create_from_transfer(
213213
args.transfer,
214214
args.clone_disks,
215215
args.force,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,327 @@
1+
# Copyright 2024 Cloudbase Solutions Srl
2+
# All Rights Reserved.
3+
import argparse
4+
import copy
5+
import os
6+
from unittest import mock
7+
8+
from coriolisclient.cli import deployments
9+
from coriolisclient.tests import test_base
10+
from coriolisclient.v1 import common
11+
from coriolisclient.v1 import deployments as v1_deployments
12+
13+
DEPLOYMENT_ID = "depl_id"
14+
DEPLOYMENT_DATA = {
15+
"storage_mappings": None,
16+
"id": DEPLOYMENT_ID,
17+
"last_execution_status": "COMPLETED",
18+
"created_at": None,
19+
"updated_at": None,
20+
"transfer_id": "transfer_1",
21+
"transfer_scenario_type": "replica",
22+
"reservation_id": "res1",
23+
"instances": ["instance1"],
24+
"notes": "",
25+
"origin_endpoint_id": "source1",
26+
"origin_minion_pool_id": None,
27+
"destination_endpoint_id": "dest1",
28+
"destination_minion_pool_id": None,
29+
"instance_osmorphing_minion_pool_mappings": None,
30+
"shutdown_instances": False,
31+
"destination_environment": {"opt1": "env1"},
32+
"source_environment": None,
33+
"network_map": {"net_source": "net_dest"},
34+
"user_scripts": None,
35+
"tasks": [],
36+
"transfer_result": None,
37+
}
38+
DEPLOYMENT_FORMATTED_DATA = [
39+
"depl_id", "COMPLETED", None, None, "transfer_1", "replica", "res1",
40+
"instance1", "", "source1", None, "dest1", None, '{}', False,
41+
'{\n "opt1": "env1"\n}', '{}', '{\n "net_source": "net_dest"\n}', "", "",
42+
None, '{}', "", '{}']
43+
44+
DEPLOYMENT_LIST_DATA = {
45+
"id": "1",
46+
"transfer_id": "2",
47+
"last_execution_status": "RUNNING",
48+
"instances": ["instance1", "instance2"],
49+
"notes": "test_notes",
50+
"created_at": "2024-11-28T15:18:25.000000",
51+
}
52+
DEPLOYMENT_LIST_FORMATTED_DATA = (
53+
"1", "2", "RUNNING", "instance1\ninstance2", "test_notes",
54+
"2024-11-28T15:18:25.000000")
55+
APP_MOCK = mock.MagicMock()
56+
57+
class DeploymentFormatterTestCase(test_base.CoriolisBaseTestCase):
58+
59+
def setUp(self):
60+
super(DeploymentFormatterTestCase, self).setUp()
61+
self.formatter = deployments.DeploymentFormatter()
62+
63+
def test__get_sorted_list(self):
64+
obj1 = mock.Mock(created_at="2024-10-24T18:51:32.000000")
65+
obj2 = mock.Mock(created_at="2024-11-18T15:18:25.000000")
66+
obj3 = mock.Mock(created_at="2024-11-28T15:18:25.000000")
67+
obj_list = [obj1, obj3, obj2]
68+
self.assertEqual(
69+
[obj1, obj2, obj3], self.formatter._get_sorted_list(obj_list))
70+
71+
def test__get_formatted_data(self):
72+
obj = mock.Mock(**DEPLOYMENT_LIST_DATA)
73+
self.assertEqual(
74+
DEPLOYMENT_LIST_FORMATTED_DATA,
75+
self.formatter._get_formatted_data(obj))
76+
77+
78+
class DeploymentDetailFormatterTestCase(test_base.CoriolisBaseTestCase):
79+
80+
def setUp(self):
81+
super(DeploymentDetailFormatterTestCase, self).setUp()
82+
self.formatter = deployments.DeploymentDetailFormatter(
83+
show_instances_data=True)
84+
self.progress_updates = [
85+
{"created_at": "2024-10-24T18:51:32.000000",
86+
"index": 0,
87+
"message": "message 0"},
88+
{"created_at": "2024-11-18T15:18:25.000000",
89+
"index": 2,
90+
"message": "message 2"},
91+
{"created_at": "2024-11-28T15:18:25.000000",
92+
"index": 1,
93+
"message": "message 1"},
94+
]
95+
self.formatted_progress_updates = (
96+
f"2024-10-24T18:51:32.000000 message 0{os.linesep}"
97+
f"2024-11-28T15:18:25.000000 message 1{os.linesep}"
98+
f"2024-11-18T15:18:25.000000 message 2")
99+
self.tasks_data = [
100+
{
101+
"id": "1",
102+
"task_type": "type1",
103+
"instance": "instance1",
104+
"status": "COMPLETED",
105+
"depends_on": ["task0"],
106+
"exception_details": None,
107+
"progress_updates": self.progress_updates,
108+
},
109+
{
110+
"id": "2",
111+
"task_type": "type2",
112+
"instance": "instance1",
113+
"status": "COMPLETED",
114+
"depends_on": ["task0"],
115+
"exception_details": None,
116+
"progress_updates": self.progress_updates,
117+
}
118+
]
119+
self.formatted_tasks = [
120+
f'id: 1{os.linesep}'
121+
f'task_type: type1{os.linesep}'
122+
f'instance: instance1{os.linesep}'
123+
f'status: COMPLETED{os.linesep}'
124+
f'depends_on: task0{os.linesep}'
125+
f'exception_details: {os.linesep}'
126+
f'progress_updates:{os.linesep}'
127+
f'{self.formatted_progress_updates}',
128+
129+
f'id: 2{os.linesep}'
130+
f'task_type: type2{os.linesep}'
131+
f'instance: instance1{os.linesep}'
132+
f'status: COMPLETED{os.linesep}'
133+
f'depends_on: task0{os.linesep}'
134+
f'exception_details: {os.linesep}'
135+
f'progress_updates:{os.linesep}'
136+
f'{self.formatted_progress_updates}'
137+
]
138+
self.manager_mock = mock.MagicMock()
139+
140+
def test_init_no_instances_data(self):
141+
formatter = deployments.DeploymentDetailFormatter(
142+
show_instances_data=False)
143+
self.assertNotIn('instances_data', formatter.columns)
144+
145+
def test__format_instances(self):
146+
obj = mock.Mock(instances=["instance2", "instance3", "instance1"])
147+
self.assertEqual(
148+
f"instance1{os.linesep}instance2{os.linesep}instance3",
149+
self.formatter._format_instances(obj))
150+
151+
def test__format_progress_updates(self):
152+
task_dict = {
153+
"progress_updates": self.progress_updates}
154+
self.assertEqual(
155+
self.formatted_progress_updates,
156+
self.formatter._format_progress_updates(task_dict))
157+
158+
def test__format_task(self):
159+
task_data = self.tasks_data[0]
160+
161+
task = common.Task(self.manager_mock, task_data)
162+
163+
self.assertEqual(
164+
self.formatted_tasks[0], self.formatter._format_task(task))
165+
166+
def test__format_tasks(self):
167+
obj = mock.Mock(
168+
tasks=[common.Task(self.manager_mock, task_data)
169+
for task_data in self.tasks_data])
170+
expected_result = (f'{self.formatted_tasks[0]}{os.linesep}{os.linesep}'
171+
f'{self.formatted_tasks[1]}')
172+
self.assertEqual(expected_result, self.formatter._format_tasks(obj))
173+
174+
def test__get_formatted_data(self):
175+
obj_data = {
176+
**DEPLOYMENT_DATA,
177+
"info": {"depl": "info"},
178+
}
179+
obj = mock.Mock(**obj_data)
180+
obj.to_dict.return_value = obj_data
181+
expected_result = copy.copy(DEPLOYMENT_FORMATTED_DATA)
182+
expected_result.append(obj_data['info'])
183+
184+
self.assertEqual(
185+
expected_result, self.formatter._get_formatted_data(obj))
186+
187+
188+
class CreateDeploymentTestCase(test_base.CoriolisBaseTestCase):
189+
190+
def setUp(self):
191+
super(CreateDeploymentTestCase, self).setUp()
192+
self.mock_app = APP_MOCK
193+
self.cli = deployments.CreateDeployment(self.mock_app, 'app_arg')
194+
195+
def test_get_parser(self):
196+
parser = self.cli.get_parser('coriolis')
197+
global_script = "linux=/linux/path"
198+
instance_script = "instance1=/instance1/path"
199+
args = parser.parse_args([
200+
'transfer_id', '--force', '--dont-clone-disks',
201+
'--skip-os-morphing', '--user-script-global', global_script,
202+
'--user-script-instance', instance_script])
203+
self.assertEqual(
204+
('transfer_id', True, False, True, [global_script],
205+
[instance_script]),
206+
(args.transfer, args.force, args.clone_disks,
207+
args.skip_os_morphing, args.global_scripts,
208+
args.instance_scripts))
209+
210+
def test_take_action(self):
211+
args = mock.Mock(global_scripts=None, instance_scripts=None)
212+
args.instance_osmorphing_minion_pool_mappings = [
213+
{"instance_id": "instance1", "pool_id": "pool1"}]
214+
mock_fun = (self.mock_app.client_manager.coriolis.deployments.
215+
create_from_transfer)
216+
mock_fun.return_value = (
217+
v1_deployments.Deployment(mock.MagicMock(), DEPLOYMENT_DATA))
218+
expected_pool_mappings = {"instance1": "pool1"}
219+
expected_user_scripts = {"global": {}, "instances": {}}
220+
expected_data = copy.copy(DEPLOYMENT_FORMATTED_DATA)
221+
222+
columns, data = self.cli.take_action(args)
223+
224+
self.assertEqual(
225+
deployments.DeploymentDetailFormatter().columns, columns)
226+
self.assertEqual(expected_data, data)
227+
mock_fun.assert_called_once_with(
228+
args.transfer, args.clone_disks, args.force, args.skip_os_morphing,
229+
user_scripts=expected_user_scripts,
230+
instance_osmorphing_minion_pool_mappings=expected_pool_mappings)
231+
232+
233+
class ShowDeploymentTestCase(test_base.CoriolisBaseTestCase):
234+
235+
def setUp(self):
236+
super(ShowDeploymentTestCase, self).setUp()
237+
self.mock_app = APP_MOCK
238+
self.cli = deployments.ShowDeployment(self.mock_app, 'app_args')
239+
240+
241+
def test_get_parser(self):
242+
parser = self.cli.get_parser('coriolis')
243+
args = parser.parse_args([DEPLOYMENT_ID, '--show-instances-data'])
244+
self.assertEqual(
245+
(DEPLOYMENT_ID, True),
246+
(args.id, args.show_instances_data))
247+
248+
def test_take_action(self):
249+
show_instances_data = False
250+
args = mock.Mock(
251+
id=DEPLOYMENT_ID, show_instances_data=show_instances_data)
252+
mock_fun = self.mock_app.client_manager.coriolis.deployments.get
253+
mock_fun.return_value = v1_deployments.Deployment(
254+
mock.MagicMock(), DEPLOYMENT_DATA)
255+
expected_data = DEPLOYMENT_FORMATTED_DATA
256+
257+
columns, data = self.cli.take_action(args)
258+
259+
self.assertEqual(
260+
deployments.DeploymentDetailFormatter(
261+
show_instances_data=show_instances_data).columns, columns)
262+
self.assertEqual(expected_data, data)
263+
mock_fun.assert_called_once_with(DEPLOYMENT_ID)
264+
265+
266+
class CancelDeploymentTestCase(test_base.CoriolisBaseTestCase):
267+
268+
def setUp(self):
269+
super(CancelDeploymentTestCase, self).setUp()
270+
self.mock_app = APP_MOCK
271+
self.cli = deployments.CancelDeployment(self.mock_app, 'app_args')
272+
273+
def test_get_parser(self):
274+
parser = self.cli.get_parser('coriolis')
275+
args = parser.parse_args([DEPLOYMENT_ID, '--force'])
276+
self.assertEqual((DEPLOYMENT_ID, True), (args.id, args.force))
277+
278+
def test_take_action(self):
279+
force = True
280+
args = mock.Mock(id=DEPLOYMENT_ID, force=force)
281+
mock_fun = self.mock_app.client_manager.coriolis.deployments.cancel
282+
283+
self.cli.take_action(args)
284+
285+
mock_fun.assert_called_once_with(DEPLOYMENT_ID, force)
286+
287+
288+
class DeleteDeploymentTestCase(test_base.CoriolisBaseTestCase):
289+
290+
def setUp(self):
291+
super(DeleteDeploymentTestCase, self).setUp()
292+
self.mock_app = APP_MOCK
293+
self.cli = deployments.DeleteDeployment(self.mock_app, 'app_args')
294+
295+
def test_get_parser(self):
296+
parser = self.cli.get_parser('coriolis')
297+
args = parser.parse_args([DEPLOYMENT_ID])
298+
self.assertEqual(DEPLOYMENT_ID, args.id)
299+
300+
def test_take_action(self):
301+
args = mock.Mock(id=DEPLOYMENT_ID)
302+
mock_fun = self.mock_app.client_manager.coriolis.deployments.delete
303+
304+
self.cli.take_action(args)
305+
mock_fun.assert_called_once_with(DEPLOYMENT_ID)
306+
307+
308+
class ListDeploymentTestCase(test_base.CoriolisBaseTestCase):
309+
310+
def setUp(self):
311+
super(ListDeploymentTestCase, self).setUp()
312+
self.mock_app = APP_MOCK
313+
self.cli = deployments.ListDeployment(self.mock_app, 'app_args')
314+
315+
def test_get_parser(self):
316+
parser = self.cli.get_parser('coriolis')
317+
self.assertIsInstance(parser, argparse.ArgumentParser)
318+
319+
def test_take_action(self):
320+
mock_fun = self.mock_app.client_manager.coriolis.deployments.list
321+
mock_fun.return_value = [
322+
v1_deployments.Deployment(mock.MagicMock(), DEPLOYMENT_LIST_DATA)]
323+
324+
columns, data = self.cli.take_action(mock.ANY)
325+
326+
self.assertEqual(deployments.DeploymentFormatter().columns, columns)
327+
self.assertEqual([DEPLOYMENT_LIST_FORMATTED_DATA], list(data))

0 commit comments

Comments
 (0)