Merge "Add ability to reuse existing OpenStack set-up"
[yardstick.git] / yardstick / tests / unit / benchmark / core / test_task.py
1 ##############################################################################
2 # Copyright (c) 2015 Huawei Technologies Co.,Ltd and others.
3 #
4 # All rights reserved. This program and the accompanying materials
5 # are made available under the terms of the Apache License, Version 2.0
6 # which accompanies this distribution, and is available at
7 # http://www.apache.org/licenses/LICENSE-2.0
8 ##############################################################################
9
10 import copy
11 import os
12
13 import mock
14 import unittest
15
16 from yardstick.benchmark.contexts import dummy
17 from yardstick.benchmark.core import task
18 from yardstick.common import constants as consts
19 from yardstick.common import exceptions
20
21
22 class TaskTestCase(unittest.TestCase):
23
24     @mock.patch.object(task, 'Context')
25     def test_parse_nodes_with_context_same_context(self, mock_context):
26         scenario_cfg = {
27             "nodes": {
28                 "host": "node1.LF",
29                 "target": "node2.LF"
30             }
31         }
32         server_info = {
33             "ip": "10.20.0.3",
34             "user": "root",
35             "key_filename": "/root/.ssh/id_rsa"
36         }
37         mock_context.get_server.return_value = server_info
38
39         context_cfg = task.parse_nodes_with_context(scenario_cfg)
40
41         self.assertEqual(context_cfg["host"], server_info)
42         self.assertEqual(context_cfg["target"], server_info)
43
44     def test_set_dispatchers(self):
45         t = task.Task()
46         output_config = {"DEFAULT": {"dispatcher": "file, http"}}
47         t._set_dispatchers(output_config)
48         self.assertEqual(output_config, output_config)
49
50     @mock.patch.object(task, 'DispatcherBase')
51     def test__do_output(self, mock_dispatcher):
52         t = task.Task()
53         output_config = {"DEFAULT": {"dispatcher": "file, http"}}
54
55         dispatcher1 = mock.MagicMock()
56         dispatcher1.__dispatcher_type__ = 'file'
57
58         dispatcher2 = mock.MagicMock()
59         dispatcher2.__dispatcher_type__ = 'http'
60
61         mock_dispatcher.get = mock.MagicMock(return_value=[dispatcher1,
62                                                            dispatcher2])
63         self.assertEqual(None, t._do_output(output_config, {}))
64
65     @mock.patch.object(task, 'Context')
66     def test_parse_networks_from_nodes(self, mock_context):
67         nodes = {
68             'node1': {
69                 'interfaces': {
70                     'mgmt': {
71                         'network_name': 'mgmt',
72                     },
73                     'xe0': {
74                         'network_name': 'uplink_0',
75                     },
76                     'xe1': {
77                         'network_name': 'downlink_0',
78                     },
79                 },
80             },
81             'node2': {
82                 'interfaces': {
83                     'mgmt': {
84                         'network_name': 'mgmt',
85                     },
86                     'uplink_0': {
87                         'network_name': 'uplink_0',
88                     },
89                     'downlink_0': {
90                         'network_name': 'downlink_0',
91                     },
92                 },
93             },
94         }
95
96         mock_context.get_network.side_effect = iter([
97             None,
98             {
99                 'name': 'mgmt',
100                 'network_type': 'flat',
101             },
102             {},
103             {
104                 'name': 'uplink_0',
105                 'subnet_cidr': '10.20.0.0/16',
106             },
107             {
108                 'name': 'downlink_0',
109                 'segmentation_id': '1001',
110             },
111             {
112                 'name': 'uplink_1',
113             },
114         ])
115
116         # one for each interface
117         expected_get_network_calls = 6
118         expected = {
119             'mgmt': {'name': 'mgmt', 'network_type': 'flat'},
120             'uplink_0': {'name': 'uplink_0', 'subnet_cidr': '10.20.0.0/16'},
121             'uplink_1': {'name': 'uplink_1'},
122             'downlink_0': {'name': 'downlink_0', 'segmentation_id': '1001'},
123         }
124
125         networks = task.get_networks_from_nodes(nodes)
126         self.assertEqual(mock_context.get_network.call_count, expected_get_network_calls)
127         self.assertDictEqual(networks, expected)
128
129     @mock.patch.object(task, 'Context')
130     @mock.patch.object(task, 'base_runner')
131     def test_run(self, mock_base_runner, *args):
132         scenario = {
133             'host': 'athena.demo',
134             'target': 'ares.demo',
135             'runner': {
136                 'duration': 60,
137                 'interval': 1,
138                 'type': 'Duration'
139             },
140             'type': 'Ping'
141         }
142
143         t = task.Task()
144         runner = mock.Mock()
145         runner.join.return_value = 0
146         runner.get_output.return_value = {}
147         runner.get_result.return_value = []
148         mock_base_runner.Runner.get.return_value = runner
149         t._run([scenario], False, "yardstick.out")
150         self.assertTrue(runner.run.called)
151
152     @mock.patch.object(os, 'environ')
153     def test_check_precondition(self, mock_os_environ):
154         cfg = {
155             'precondition': {
156                 'installer_type': 'compass',
157                 'deploy_scenarios': 'os-nosdn',
158                 'pod_name': 'huawei-pod1'
159             }
160         }
161
162         t = task.TaskParser('/opt')
163         mock_os_environ.get.side_effect = ['compass',
164                                            'os-nosdn',
165                                            'huawei-pod1']
166         result = t._check_precondition(cfg)
167         self.assertTrue(result)
168
169     def test_parse_suite_no_constraint_no_args(self):
170         SAMPLE_SCENARIO_PATH = "no_constraint_no_args_scenario_sample.yaml"
171         t = task.TaskParser(self._get_file_abspath(SAMPLE_SCENARIO_PATH))
172         with mock.patch.object(os, 'environ',
173                         new={'NODE_NAME': 'huawei-pod1', 'INSTALLER_TYPE': 'compass'}):
174             task_files, task_args, task_args_fnames = t.parse_suite()
175
176         self.assertEqual(task_files[0], self.change_to_abspath(
177                          'tests/opnfv/test_cases/opnfv_yardstick_tc037.yaml'))
178         self.assertEqual(task_files[1], self.change_to_abspath(
179                          'tests/opnfv/test_cases/opnfv_yardstick_tc043.yaml'))
180
181         self.assertIsNone(task_args[0])
182         self.assertIsNone(task_args[1])
183         self.assertIsNone(task_args_fnames[0])
184         self.assertIsNone(task_args_fnames[1])
185
186     def test_parse_suite_no_constraint_with_args(self):
187         SAMPLE_SCENARIO_PATH = "no_constraint_with_args_scenario_sample.yaml"
188         t = task.TaskParser(self._get_file_abspath(SAMPLE_SCENARIO_PATH))
189         with mock.patch.object(os, 'environ',
190                         new={'NODE_NAME': 'huawei-pod1', 'INSTALLER_TYPE': 'compass'}):
191             task_files, task_args, task_args_fnames = t.parse_suite()
192
193         self.assertEqual(task_files[0], self.change_to_abspath(
194                          'tests/opnfv/test_cases/opnfv_yardstick_tc037.yaml'))
195         self.assertEqual(task_files[1], self.change_to_abspath(
196                          'tests/opnfv/test_cases/opnfv_yardstick_tc043.yaml'))
197         self.assertIsNone(task_args[0])
198         self.assertEqual(task_args[1],
199                          '{"host": "node1.LF","target": "node2.LF"}')
200         self.assertIsNone(task_args_fnames[0])
201         self.assertIsNone(task_args_fnames[1])
202
203     def test_parse_suite_with_constraint_no_args(self):
204         SAMPLE_SCENARIO_PATH = "with_constraint_no_args_scenario_sample.yaml"
205         t = task.TaskParser(self._get_file_abspath(SAMPLE_SCENARIO_PATH))
206         with mock.patch.object(os, 'environ',
207                         new={'NODE_NAME': 'huawei-pod1', 'INSTALLER_TYPE': 'compass'}):
208             task_files, task_args, task_args_fnames = t.parse_suite()
209         self.assertEqual(task_files[0], self.change_to_abspath(
210                          'tests/opnfv/test_cases/opnfv_yardstick_tc037.yaml'))
211         self.assertEqual(task_files[1], self.change_to_abspath(
212                          'tests/opnfv/test_cases/opnfv_yardstick_tc043.yaml'))
213         self.assertIsNone(task_args[0])
214         self.assertIsNone(task_args[1])
215         self.assertIsNone(task_args_fnames[0])
216         self.assertIsNone(task_args_fnames[1])
217
218     def test_parse_suite_with_constraint_with_args(self):
219         SAMPLE_SCENARIO_PATH = "with_constraint_with_args_scenario_sample.yaml"
220         t = task.TaskParser(self._get_file_abspath(SAMPLE_SCENARIO_PATH))
221         with mock.patch('os.environ',
222                         new={'NODE_NAME': 'huawei-pod1', 'INSTALLER_TYPE': 'compass'}):
223             task_files, task_args, task_args_fnames = t.parse_suite()
224
225         self.assertEqual(task_files[0], self.change_to_abspath(
226                          'tests/opnfv/test_cases/opnfv_yardstick_tc037.yaml'))
227         self.assertEqual(task_files[1], self.change_to_abspath(
228                          'tests/opnfv/test_cases/opnfv_yardstick_tc043.yaml'))
229         self.assertIsNone(task_args[0])
230         self.assertEqual(task_args[1],
231                          '{"host": "node1.LF","target": "node2.LF"}')
232         self.assertIsNone(task_args_fnames[0])
233         self.assertIsNone(task_args_fnames[1])
234
235     def test_parse_options(self):
236         options = {
237             'openstack': {
238                 'EXTERNAL_NETWORK': '$network'
239             },
240             'nodes': ['node1', '$node'],
241             'host': '$host'
242         }
243
244         t = task.Task()
245         t.outputs = {
246             'network': 'ext-net',
247             'node': 'node2',
248             'host': 'server.yardstick'
249         }
250
251         expected_result = {
252             'openstack': {
253                 'EXTERNAL_NETWORK': 'ext-net'
254             },
255             'nodes': ['node1', 'node2'],
256             'host': 'server.yardstick'
257         }
258
259         actual_result = t._parse_options(options)
260         self.assertEqual(expected_result, actual_result)
261
262     def test_parse_options_no_teardown(self):
263         options = {
264             'openstack': {
265                 'EXTERNAL_NETWORK': '$network'
266             },
267             'nodes': ['node1', '$node'],
268             'host': '$host',
269             'contexts' : {'name': "my-context",
270                           'no_teardown': True}
271         }
272
273         t = task.Task()
274         t.outputs = {
275             'network': 'ext-net',
276             'node': 'node2',
277             'host': 'server.yardstick'
278         }
279
280         expected_result = {
281             'openstack': {
282                 'EXTERNAL_NETWORK': 'ext-net'
283             },
284             'nodes': ['node1', 'node2'],
285             'host': 'server.yardstick',
286             'contexts': {'name': 'my-context',
287                          'no_teardown': True,
288                         }
289         }
290
291         actual_result = t._parse_options(options)
292         self.assertEqual(expected_result, actual_result)
293
294     @mock.patch('six.moves.builtins.open', side_effect=mock.mock_open())
295     @mock.patch.object(task, 'utils')
296     @mock.patch('logging.root')
297     def test_set_log(self, mock_logging_root, *args):
298         task_obj = task.Task()
299         task_obj.task_id = 'task_id'
300         task_obj._set_log()
301         mock_logging_root.addHandler.assert_called()
302
303     def _get_file_abspath(self, filename):
304         curr_path = os.path.dirname(os.path.abspath(__file__))
305         file_path = os.path.join(curr_path, filename)
306         return file_path
307
308     def change_to_abspath(self, filepath):
309         return os.path.join(consts.YARDSTICK_ROOT_PATH, filepath)
310
311
312 class TaskParserTestCase(unittest.TestCase):
313
314     def setUp(self):
315         self.parser = task.TaskParser('fake/path')
316         self.scenario = {
317             'host': 'athena.demo',
318             'target': 'kratos.demo',
319             'targets': [
320                 'ares.demo', 'mars.demo'
321                 ],
322             'options': {
323                 'server_name': {
324                     'host': 'jupiter.demo',
325                     'target': 'saturn.demo',
326                     },
327                 },
328             'nodes': {
329                 'tg__0': 'tg_0.demo',
330                 'vnf__0': 'vnf_0.demo',
331                 }
332             }
333
334     def test__change_node_names(self):
335
336         ctx_attrs = {
337             'name': 'demo',
338             'task_id': '1234567890',
339             'servers': [
340                 'athena', 'kratos',
341                 'ares', 'mars',
342                 'jupiter', 'saturn',
343                 'tg_0', 'vnf_0'
344                 ]
345             }
346
347         my_context = dummy.DummyContext()
348         my_context.init(ctx_attrs)
349
350         expected_scenario = {
351             'host': 'athena.demo-12345678',
352             'target': 'kratos.demo-12345678',
353             'targets': [
354                 'ares.demo-12345678', 'mars.demo-12345678'
355                 ],
356             'options': {
357                 'server_name': {
358                     'host': 'jupiter.demo-12345678',
359                     'target': 'saturn.demo-12345678',
360                     },
361                 },
362             'nodes': {
363                 'tg__0': 'tg_0.demo-12345678',
364                 'vnf__0': 'vnf_0.demo-12345678',
365                 }
366             }
367
368         scenario = copy.deepcopy(self.scenario)
369
370         self.parser._change_node_names(scenario, [my_context])
371         self.assertEqual(scenario, expected_scenario)
372
373     def test__change_node_names_context_not_found(self):
374         scenario = copy.deepcopy(self.scenario)
375         self.assertRaises(exceptions.ScenarioConfigContextNameNotFound,
376                           self.parser._change_node_names,
377                           scenario, [])
378
379     def test__change_node_names_context_name_unchanged(self):
380         ctx_attrs = {
381             'name': 'demo',
382             'task_id': '1234567890',
383             'flags': {
384                 'no_setup': True,
385                 'no_teardown': True
386                 }
387             }
388
389         my_context = dummy.DummyContext()
390         my_context.init(ctx_attrs)
391
392         scenario = copy.deepcopy(self.scenario)
393         expected_scenario = copy.deepcopy(self.scenario)
394
395         self.parser._change_node_names(scenario, [my_context])
396         self.assertEqual(scenario, expected_scenario)