Merge "Add a document describing vIPSEC testcase"
[yardstick.git] / yardstick / tests / unit / benchmark / contexts / test_node.py
1 ##############################################################################
2 # Copyright (c) 2015-2017 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 os
11 import errno
12
13 import mock
14 import unittest
15
16 from yardstick.benchmark.contexts import base
17 from yardstick.benchmark.contexts import node
18 from yardstick.common import constants as consts
19 from yardstick.common import exceptions
20 from yardstick.common import yaml_loader
21
22
23 class NodeContextTestCase(unittest.TestCase):
24
25     PREFIX = 'yardstick.benchmark.contexts.node'
26
27     NODES_SAMPLE = "nodes_sample.yaml"
28     NODES_DUPLICATE_SAMPLE = "nodes_duplicate_sample.yaml"
29
30     def setUp(self):
31         self.test_context = node.NodeContext()
32         self.addCleanup(self._remove_contexts)
33         self.os_path_join = os.path.join
34         self.attrs = {
35             'name': 'foo',
36             'task_id': '1234567890',
37             'file': self._get_file_abspath(self.NODES_SAMPLE)
38         }
39
40     @staticmethod
41     def _remove_contexts():
42         for context in base.Context.list:
43             context._delete_context()
44         base.Context.list = []
45
46     def _get_file_abspath(self, filename):
47         curr_path = os.path.dirname(os.path.abspath(__file__))
48         file_path = self.os_path_join(curr_path, filename)
49         return file_path
50
51     def test___init__(self):
52         self.assertIsNone(self.test_context._name)
53         self.assertIsNone(self.test_context.file_path)
54         self.assertEqual(self.test_context.nodes, [])
55         self.assertEqual(self.test_context.controllers, [])
56         self.assertEqual(self.test_context.computes, [])
57         self.assertEqual(self.test_context.baremetals, [])
58         self.assertEqual(self.test_context.env, {})
59         self.assertEqual(self.test_context.attrs, {})
60
61     @mock.patch.object(yaml_loader, 'read_yaml_file')
62     @mock.patch('{}.os.path.join'.format(PREFIX))
63     def test_init_negative(self, mock_path_join, read_mock):
64         special_path = '/foo/bar/error_file'
65         error_path = self._get_file_abspath("error_file")
66
67         def path_join(*args):
68             if args == (consts.YARDSTICK_ROOT_PATH, error_path):
69                 return special_path
70             return self.os_path_join(*args)
71
72         # we can't count mock_path_join calls because
73         # it can catch join calls for .pyc files.
74         mock_path_join.side_effect = path_join
75         read_calls = 0
76
77         with self.assertRaises(KeyError):
78             self.test_context.init({})
79
80         self.assertEqual(read_mock.call_count, read_calls)
81
82         attrs = {
83             'name': 'foo',
84             'task_id': '1234567890',
85             'file': error_path,
86         }
87         read_mock.side_effect = IOError(errno.EBUSY, 'busy')
88         with self.assertRaises(IOError) as raised:
89             self.test_context.init(attrs)
90
91         read_calls += 1
92         self.assertEqual(read_mock.call_count, read_calls)
93         self.assertIn(attrs['file'], self.test_context.file_path)
94         self.assertEqual(raised.exception.errno, errno.EBUSY)
95         self.assertEqual(str(raised.exception), str(read_mock.side_effect))
96
97         read_mock.side_effect = IOError(errno.ENOENT, 'not found')
98         with self.assertRaises(IOError) as raised:
99             self.test_context.init(attrs)
100
101         read_calls += 2
102         self.assertEqual(read_mock.call_count, read_calls)
103         self.assertEqual(self.test_context.file_path, special_path)
104         self.assertEqual(raised.exception.errno, errno.ENOENT)
105         self.assertEqual(str(raised.exception), str(read_mock.side_effect))
106
107     def test__dispatch_script(self):
108         self.test_context.init(self.attrs)
109
110         self.test_context.env = {'bash': [{'script': 'dummy'}]}
111         self.test_context._execute_script = mock.Mock()
112         self.assertEqual(self.test_context._dispatch_script('bash'), None)
113
114     def test__dispatch_ansible(self):
115         self.test_context.init(self.attrs)
116
117         self.test_context.env = {'ansible': [{'script': 'dummy'}]}
118         self.test_context._do_ansible_job = mock.Mock()
119         self.assertEqual(self.test_context._dispatch_ansible('ansible'), None)
120         self.test_context.env = {}
121         self.assertEqual(self.test_context._dispatch_ansible('ansible'), None)
122
123     @mock.patch("{}.AnsibleCommon".format(PREFIX))
124     def test__do_ansible_job(self, *args):
125         self.assertIsNone(self.test_context._do_ansible_job('dummy'))
126
127     def test_init(self):
128         self.test_context.init(self.attrs)
129
130         self.assertEqual(self.test_context.name, "foo-12345678")
131         self.assertEqual(len(self.test_context.nodes), 4)
132         self.assertEqual(len(self.test_context.controllers), 2)
133         self.assertEqual(len(self.test_context.computes), 1)
134         self.assertEqual(self.test_context.computes[0]["name"], "node3")
135         self.assertEqual(len(self.test_context.baremetals), 1)
136         self.assertEqual(self.test_context.baremetals[0]["name"], "node4")
137
138     def test__get_server_with_dict_attr_name(self):
139         self.test_context.init(self.attrs)
140         result = self.test_context._get_server({'name': 'node1.foo-12345678'})
141
142         self.assertIsNone(result, None)
143
144     def test__get_server_not_found(self):
145         self.test_context.init(self.attrs)
146
147         self.assertIsNone(self.test_context._get_server('bar.foo-12345678'))
148
149     def test__get_server_mismatch(self):
150         self.test_context.init(self.attrs)
151
152         self.assertIsNone(self.test_context._get_server('bar.foo1'))
153
154     def test__get_server_duplicate(self):
155         self.attrs['file'] = self._get_file_abspath(
156             self.NODES_DUPLICATE_SAMPLE)
157         self.test_context.init(self.attrs)
158
159         with self.assertRaises(ValueError):
160             self.test_context._get_server('node1.foo-12345678')
161
162     def test__get_server_found(self):
163         self.test_context.init(self.attrs)
164
165         result = self.test_context._get_server('node1.foo-12345678')
166
167         self.assertEqual(result['ip'], '10.229.47.137')
168         self.assertEqual(result['name'], 'node1.foo-12345678')
169         self.assertEqual(result['user'], 'root')
170         self.assertEqual(result['key_filename'], '/root/.yardstick_key')
171
172     def test__get_physical_nodes(self):
173         self.test_context.init(self.attrs)
174         nodes = self.test_context._get_physical_nodes()
175         self.assertEqual(nodes, self.test_context.nodes)
176
177     def test__get_physical_node_for_server(self):
178         self.test_context.init(self.attrs)
179
180         # When server is not from this context
181         result = self.test_context._get_physical_node_for_server('node1.another-context')
182         self.assertIsNone(result)
183
184         # When node_name is not from this context
185         result = self.test_context._get_physical_node_for_server('fake.foo-12345678')
186         self.assertIsNone(result)
187
188         result = self.test_context._get_physical_node_for_server('node1.foo-12345678')
189         self.assertEqual(result, 'node1.foo')
190
191     def test_update_collectd_options_for_node(self):
192         self.test_context.init(self.attrs)
193         options = {'collectd': {'interval': 5}}
194
195         with self.assertRaises(exceptions.ContextUpdateCollectdForNodeError):
196             self.test_context.update_collectd_options_for_node(options, 'fake.foo-12345678')
197
198         self.test_context.update_collectd_options_for_node(options, 'node1.foo-12345678')
199
200         node_collectd_options = [node for node in self.test_context.nodes
201                                  if node['name'] == 'node1'][0]['collectd']
202
203         self.assertEqual(node_collectd_options, options)
204
205     @mock.patch('{}.NodeContext._dispatch_script'.format(PREFIX))
206     def test_deploy(self, dispatch_script_mock):
207         obj = node.NodeContext()
208         self.addCleanup(obj._delete_context)
209         obj.env = {
210             'type': 'script'
211         }
212         obj.deploy()
213         dispatch_script_mock.assert_called_once()
214
215     @mock.patch('{}.NodeContext._dispatch_ansible'.format(PREFIX))
216     def test_deploy_anisible(self, dispatch_ansible_mock):
217         obj = node.NodeContext()
218         self.addCleanup(obj._delete_context)
219         obj.env = {
220             'type': 'ansible'
221         }
222         obj.deploy()
223         dispatch_ansible_mock.assert_called_once()
224
225     @mock.patch('{}.NodeContext._dispatch_script'.format(PREFIX))
226     def test_undeploy(self, dispatch_script_mock):
227         obj = node.NodeContext()
228         obj.env = {
229             'type': 'script'
230         }
231         obj.undeploy()
232         dispatch_script_mock.assert_called_once()
233
234     @mock.patch('{}.NodeContext._dispatch_ansible'.format(PREFIX))
235     def test_undeploy_anisble(self, dispatch_ansible_mock):
236         obj = node.NodeContext()
237         obj.env = {
238             'type': 'ansible'
239         }
240         obj.undeploy()
241         dispatch_ansible_mock.assert_called_once()
242
243     @mock.patch('{}.ssh.SSH._put_file_shell'.format(PREFIX))
244     @mock.patch('{}.ssh.SSH.execute'.format(PREFIX))
245     def test_execute_remote_script(self, execute_mock, put_file_mock):
246         obj = node.NodeContext()
247         self.addCleanup(obj._delete_context)
248         obj.env = {'prefix': 'yardstick.benchmark.scenarios.compute'}
249         node_name_args = 'node5'
250         obj.nodes = [{
251             'name': node_name_args,
252             'user': 'ubuntu',
253             'ip': '10.10.10.10',
254             'pwd': 'ubuntu',
255         }]
256
257         info = {'script': 'computecapacity.bash'}
258         execute_mock.return_value = (0, '', '')
259         obj._execute_remote_script('node5', info)
260
261         put_file_mock.assert_called_once()
262         execute_mock.assert_called()
263
264     @mock.patch('{}.NodeContext._execute_local_script'.format(PREFIX))
265     def test_execute_script_local(self, local_execute_mock):
266         node_name = 'local'
267         info = {}
268         obj = node.NodeContext()
269         self.addCleanup(obj._delete_context)
270         obj._execute_script(node_name, info)
271         local_execute_mock.assert_called_once()
272
273     @mock.patch('{}.NodeContext._execute_remote_script'.format(PREFIX))
274     def test_execute_script_remote(self, remote_execute_mock):
275         node_name = 'node5'
276         info = {}
277         obj = node.NodeContext()
278         self.addCleanup(obj._delete_context)
279         obj._execute_script(node_name, info)
280         remote_execute_mock.assert_called_once()
281
282     def test_get_script(self):
283         script_args = 'hello.bash'
284         info_args = {
285             'script': script_args
286         }
287         obj = node.NodeContext()
288         self.addCleanup(obj._delete_context)
289         script, options = obj._get_script(info_args)
290         self.assertEqual(script_args, script)
291         self.assertEqual('', options)
292
293     def test_node_info(self):
294         node_name_args = 'node5'
295         obj = node.NodeContext()
296         self.addCleanup(obj._delete_context)
297         obj.nodes = [{'name': node_name_args, 'check': node_name_args}]
298         node_info = obj._get_node_info(node_name_args)
299         self.assertEqual(node_info.get('check'), node_name_args)
300
301     @mock.patch('{}.ssh.SSH.wait'.format(PREFIX))
302     def test_get_client(self, wait_mock):
303         node_name_args = 'node5'
304         obj = node.NodeContext()
305         self.addCleanup(obj._delete_context)
306         obj.nodes = [{
307             'name': node_name_args,
308             'user': 'ubuntu',
309             'ip': '10.10.10.10',
310             'pwd': 'ubuntu',
311         }]
312         obj._get_client(node_name_args)
313         wait_mock.assert_called_once()
314
315     def test_get_server(self):
316         self.test_context.init(self.attrs)
317         self.test_context._name = 'foo'
318         self.test_context._task_id = '1234567890'
319         self.test_context._name_task_id = '{}-{}'.format(
320             self.test_context._name, self.test_context._task_id[:8])
321         self.assertEqual('foo-12345678', self.test_context.name)
322         self.assertIsNotNone(self.test_context._task_id)
323
324         result = self.test_context.get_server('node1.foo-12345678')
325
326         self.assertEqual(result['ip'], '10.229.47.137')
327         self.assertEqual(result['name'], 'node1.foo-12345678')
328         self.assertEqual(result['user'], 'root')
329         self.assertEqual(result['key_filename'], '/root/.yardstick_key')
330
331     def test_get_server_server_not_in_context(self):
332         self.test_context.init(self.attrs)
333
334         with self.assertRaises(ValueError):
335             self.test_context.get_server('my2.foo-12345678')
336
337     def test_get_context_from_server(self):
338         self.test_context._name = 'vnf1'
339         self.test_context._task_id = '1234567890'
340         self.test_context._name_task_id = '{}-{}'.format(
341             self.test_context._name, self.test_context._task_id[:8])
342         self.test_context.nodes = [{'name': 'my', 'value': 100}]
343         self.test_context.attrs = {'attr1': 200}
344
345         self.assertIs(
346             self.test_context.get_context_from_server('my.vnf1-12345678'),
347             self.test_context)
348
349     # TODO: Split this into more granular tests
350     def test__get_network(self):
351         network1 = {
352             'name': 'net_1',
353             'vld_id': 'vld111',
354             'segmentation_id': 'seg54',
355             'network_type': 'type_a',
356             'physical_network': 'phys',
357         }
358         network2 = {
359             'name': 'net_2',
360             'vld_id': 'vld999',
361         }
362         self.test_context.networks = {
363             'a': network1,
364             'b': network2,
365         }
366
367         attr_name = {}
368         self.assertIsNone(self.test_context._get_network(attr_name))
369
370         attr_name = {'vld_id': 'vld777'}
371         self.assertIsNone(self.test_context._get_network(attr_name))
372
373         self.assertIsNone(self.test_context._get_network(None))
374
375         attr_name = 'vld777'
376         self.assertIsNone(self.test_context._get_network(attr_name))
377
378         attr_name = {'vld_id': 'vld999'}
379         expected = {
380             "name": 'net_2',
381             "vld_id": 'vld999',
382             "segmentation_id": None,
383             "network_type": None,
384             "physical_network": None,
385         }
386         result = self.test_context._get_network(attr_name)
387         self.assertDictEqual(result, expected)
388
389         attr_name = 'a'
390         expected = network1
391         result = self.test_context._get_network(attr_name)
392         self.assertDictEqual(result, expected)