Merge "Dashboard for TC056"
[yardstick.git] / yardstick / tests / unit / benchmark / contexts / standalone / test_model.py
1 # Copyright (c) 2016-2017 Intel Corporation
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #      http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 import copy
16 import mock
17 import os
18 import unittest
19 import uuid
20
21 from xml.etree import ElementTree
22
23 from yardstick import ssh
24 from yardstick.benchmark.contexts.standalone import model
25 from yardstick.common import exceptions
26 from yardstick import constants
27 from yardstick.network_services import utils
28
29
30 XML_SAMPLE = """<?xml version="1.0"?>
31 <domain type="kvm">
32     <devices>
33     </devices>
34 </domain>
35 """
36
37 XML_SAMPLE_INTERFACE = """<?xml version="1.0"?>
38 <domain type="kvm">
39     <devices>
40         <interface>
41         </interface>
42     </devices>
43 </domain>
44 """
45
46
47 class ModelLibvirtTestCase(unittest.TestCase):
48
49     def setUp(self):
50         self.pci_address_str = '0001:04:03.2'
51         self.pci_address = utils.PciAddress(self.pci_address_str)
52         self.mac = '00:00:00:00:00:01'
53         self._mock_ssh = mock.Mock()
54         self.mock_ssh = self._mock_ssh.start()
55         self.addCleanup(self._cleanup)
56
57     def _cleanup(self):
58         self._mock_ssh.stop()
59
60     # TODO: Remove mocking of yardstick.ssh.SSH (here and elsewhere)
61     # In this case, we are mocking a param to be passed into other methods
62     # It can be a generic Mock() with return values set for the right methods
63     def test_check_if_vm_exists_and_delete(self):
64         with mock.patch("yardstick.ssh.SSH") as ssh:
65             ssh_mock = mock.Mock(autospec=ssh.SSH)
66             ssh_mock.execute = mock.Mock(return_value=(0, "a", ""))
67             ssh.return_value = ssh_mock
68         # NOTE(ralonsoh): this test doesn't cover function execution.
69         model.Libvirt.check_if_vm_exists_and_delete("vm_0", ssh_mock)
70
71     def test_virsh_create_vm(self):
72         self.mock_ssh.execute = mock.Mock(return_value=(0, 0, 0))
73         model.Libvirt.virsh_create_vm(self.mock_ssh, 'vm_0')
74         self.mock_ssh.execute.assert_called_once_with('virsh create vm_0')
75
76     def test_virsh_create_vm_error(self):
77         self.mock_ssh.execute = mock.Mock(return_value=(1, 0, 'error_create'))
78         with self.assertRaises(exceptions.LibvirtCreateError) as exc:
79             model.Libvirt.virsh_create_vm(self.mock_ssh, 'vm_0')
80         self.assertEqual('Error creating the virtual machine. Error: '
81                          'error_create.', str(exc.exception))
82         self.mock_ssh.execute.assert_called_once_with('virsh create vm_0')
83
84     def test_virsh_destroy_vm(self):
85         self.mock_ssh.execute = mock.Mock(return_value=(0, 0, 0))
86         model.Libvirt.virsh_destroy_vm('vm_0', self.mock_ssh)
87         self.mock_ssh.execute.assert_called_once_with('virsh destroy vm_0')
88
89     @mock.patch.object(model, 'LOG')
90     def test_virsh_destroy_vm_error(self, mock_logger):
91         self.mock_ssh.execute = mock.Mock(return_value=(1, 0, 'error_destroy'))
92         mock_logger.warning = mock.Mock()
93         model.Libvirt.virsh_destroy_vm('vm_0', self.mock_ssh)
94         mock_logger.warning.assert_called_once_with(
95             'Error destroying VM %s. Error: %s', 'vm_0', 'error_destroy')
96         self.mock_ssh.execute.assert_called_once_with('virsh destroy vm_0')
97
98     def test_add_interface_address(self):
99         xml = ElementTree.ElementTree(
100             element=ElementTree.fromstring(XML_SAMPLE_INTERFACE))
101         interface = xml.find('devices').find('interface')
102         result = model.Libvirt._add_interface_address(interface, self.pci_address)
103         self.assertEqual('pci', result.get('type'))
104         self.assertEqual('0x{}'.format(self.pci_address.domain),
105                          result.get('domain'))
106         self.assertEqual('0x{}'.format(self.pci_address.bus),
107                          result.get('bus'))
108         self.assertEqual('0x{}'.format(self.pci_address.slot),
109                          result.get('slot'))
110         self.assertEqual('0x{}'.format(self.pci_address.function),
111                          result.get('function'))
112
113     def test_add_ovs_interfaces(self):
114         xml_input = copy.deepcopy(XML_SAMPLE)
115         xml_output = model.Libvirt.add_ovs_interface(
116             '/usr/local', 0, self.pci_address_str, self.mac, xml_input)
117
118         root = ElementTree.fromstring(xml_output)
119         et_out = ElementTree.ElementTree(element=root)
120         interface = et_out.find('devices').find('interface')
121         self.assertEqual('vhostuser', interface.get('type'))
122         mac = interface.find('mac')
123         self.assertEqual(self.mac, mac.get('address'))
124         source = interface.find('source')
125         self.assertEqual('unix', source.get('type'))
126         self.assertEqual('/usr/local/var/run/openvswitch/dpdkvhostuser0',
127                          source.get('path'))
128         self.assertEqual('client', source.get('mode'))
129         _model = interface.find('model')
130         self.assertEqual('virtio', _model.get('type'))
131         driver = interface.find('driver')
132         self.assertEqual('4', driver.get('queues'))
133         host = driver.find('host')
134         self.assertEqual('off', host.get('mrg_rxbuf'))
135         self.assertIsNotNone(interface.find('address'))
136
137     def test_add_sriov_interfaces(self):
138         xml_input = copy.deepcopy(XML_SAMPLE)
139         vm_pci = '0001:05:04.2'
140         xml_output = model.Libvirt.add_sriov_interfaces(
141             vm_pci, self.pci_address_str, self.mac, xml_input)
142         root = ElementTree.fromstring(xml_output)
143         et_out = ElementTree.ElementTree(element=root)
144         interface = et_out.find('devices').find('interface')
145         self.assertEqual('yes', interface.get('managed'))
146         self.assertEqual('hostdev', interface.get('type'))
147         mac = interface.find('mac')
148         self.assertEqual(self.mac, mac.get('address'))
149         source = interface.find('source')
150         source_address = source.find('address')
151         self.assertIsNotNone(source.find('address'))
152
153         self.assertEqual('pci', source_address.get('type'))
154         self.assertEqual('0x' + self.pci_address_str.split(':')[0],
155                          source_address.get('domain'))
156         self.assertEqual('0x' + self.pci_address_str.split(':')[1],
157                          source_address.get('bus'))
158         self.assertEqual('0x' + self.pci_address_str.split(':')[2].split('.')[0],
159                          source_address.get('slot'))
160         self.assertEqual('0x' + self.pci_address_str.split(':')[2].split('.')[1],
161                          source_address.get('function'))
162
163         interface_address = interface.find('address')
164         self.assertEqual('pci', interface_address.get('type'))
165         self.assertEqual('0x' + vm_pci.split(':')[0],
166                          interface_address.get('domain'))
167         self.assertEqual('0x' + vm_pci.split(':')[1],
168                          interface_address.get('bus'))
169         self.assertEqual('0x' + vm_pci.split(':')[2].split('.')[0],
170                          interface_address.get('slot'))
171         self.assertEqual('0x' + vm_pci.split(':')[2].split('.')[1],
172                          interface_address.get('function'))
173
174     def test_create_snapshot_qemu(self):
175         result = "/var/lib/libvirt/images/0.qcow2"
176         with mock.patch("yardstick.ssh.SSH") as ssh:
177             ssh_mock = mock.Mock(autospec=ssh.SSH)
178             ssh_mock.execute = \
179                 mock.Mock(return_value=(0, "a", ""))
180             ssh.return_value = ssh_mock
181         image = model.Libvirt.create_snapshot_qemu(ssh_mock, "0", "ubuntu.img")
182         self.assertEqual(image, result)
183
184     @mock.patch.object(model.Libvirt, 'pin_vcpu_for_perf', return_value='4,5')
185     @mock.patch.object(model.Libvirt, 'create_snapshot_qemu',
186                        return_value='qemu_image')
187     def test_build_vm_xml(self, mock_create_snapshot_qemu,
188                           mock_pin_vcpu_for_perf):
189         extra_specs = {'hw:cpu_cores': '4',
190                        'hw:cpu_sockets': '3',
191                        'hw:cpu_threads': '2',
192                        'cputune': 'cool'}
193         flavor = {'ram': '1024',
194                   'extra_specs': extra_specs,
195                   'hw_socket': '1',
196                   'images': 'images'}
197         mac = model.StandaloneContextHelper.get_mac_address(0x00)
198         _uuid = uuid.uuid4()
199         connection = mock.Mock()
200         with mock.patch.object(model.StandaloneContextHelper,
201                                'get_mac_address', return_value=mac) as \
202                 mock_get_mac_address, \
203                 mock.patch.object(uuid, 'uuid4', return_value=_uuid):
204             xml_out, mac = model.Libvirt.build_vm_xml(
205                 connection, flavor, 'vm_name', 100)
206
207         xml_ref = model.VM_TEMPLATE.format(vm_name='vm_name',
208             random_uuid=_uuid, mac_addr=mac, memory='1024', vcpu='8', cpu='4',
209             numa_cpus='0-7', socket='3', threads='2',
210             vm_image='qemu_image', cpuset='4,5', cputune='cool')
211         self.assertEqual(xml_ref, xml_out)
212         mock_get_mac_address.assert_called_once_with(0x00)
213         mock_create_snapshot_qemu.assert_called_once_with(
214             connection, 100, 'images')
215         mock_pin_vcpu_for_perf.assert_called_once_with(connection, '1')
216
217     # TODO: Edit this test to test state instead of output
218     # update_interrupts_hugepages_perf does not return anything
219     def test_update_interrupts_hugepages_perf(self):
220         with mock.patch("yardstick.ssh.SSH") as ssh:
221             ssh_mock = mock.Mock(autospec=ssh.SSH)
222             ssh_mock.execute = \
223                 mock.Mock(return_value=(0, "a", ""))
224             ssh.return_value = ssh_mock
225         # NOTE(ralonsoh): 'update_interrupts_hugepages_perf' always return
226         # None, this check is trivial.
227         #status = Libvirt.update_interrupts_hugepages_perf(ssh_mock)
228         #self.assertIsNone(status)
229         model.Libvirt.update_interrupts_hugepages_perf(ssh_mock)
230
231     @mock.patch.object(model, 'CpuSysCores')
232     @mock.patch.object(model.Libvirt, 'update_interrupts_hugepages_perf')
233     def test_pin_vcpu_for_perf(self, *args):
234         # NOTE(ralonsoh): test mocked methods/variables.
235         with mock.patch("yardstick.ssh.SSH") as ssh:
236             ssh_mock = mock.Mock(autospec=ssh.SSH)
237             ssh_mock.execute = \
238                 mock.Mock(return_value=(0, "a", ""))
239             ssh.return_value = ssh_mock
240         status = model.Libvirt.pin_vcpu_for_perf(ssh_mock, 4)
241         self.assertIsNotNone(status)
242
243 class StandaloneContextHelperTestCase(unittest.TestCase):
244
245     NODE_SAMPLE = "nodes_sample.yaml"
246     NODE_SRIOV_SAMPLE = "nodes_sriov_sample.yaml"
247
248     NETWORKS = {
249         'mgmt': {'cidr': '152.16.100.10/24'},
250         'private_0': {
251             'phy_port': "0000:05:00.0",
252             'vpci': "0000:00:07.0",
253             'cidr': '152.16.100.10/24',
254             'gateway_ip': '152.16.100.20'},
255         'public_0': {
256             'phy_port': "0000:05:00.1",
257             'vpci': "0000:00:08.0",
258             'cidr': '152.16.40.10/24',
259             'gateway_ip': '152.16.100.20'}
260     }
261
262     def setUp(self):
263         self.helper = model.StandaloneContextHelper()
264
265     def test___init__(self):
266         self.assertIsNone(self.helper.file_path)
267
268     def test_install_req_libs(self):
269         with mock.patch("yardstick.ssh.SSH") as ssh:
270             ssh_mock = mock.Mock(autospec=ssh.SSH)
271             ssh_mock.execute = \
272                 mock.Mock(return_value=(1, "a", ""))
273             ssh.return_value = ssh_mock
274         # NOTE(ralonsoh): this test doesn't cover function execution. This test
275         # should also check mocked function calls.
276         model.StandaloneContextHelper.install_req_libs(ssh_mock)
277
278     def test_get_kernel_module(self):
279         with mock.patch("yardstick.ssh.SSH") as ssh:
280             ssh_mock = mock.Mock(autospec=ssh.SSH)
281             ssh_mock.execute = \
282                 mock.Mock(return_value=(1, "i40e", ""))
283             ssh.return_value = ssh_mock
284         # NOTE(ralonsoh): this test doesn't cover function execution. This test
285         # should also check mocked function calls.
286         model.StandaloneContextHelper.get_kernel_module(
287             ssh_mock, "05:00.0", None)
288
289     @mock.patch.object(model.StandaloneContextHelper, 'get_kernel_module')
290     def test_get_nic_details(self, mock_get_kernel_module):
291         with mock.patch("yardstick.ssh.SSH") as ssh:
292             ssh_mock = mock.Mock(autospec=ssh.SSH)
293             ssh_mock.execute = mock.Mock(return_value=(1, "i40e ixgbe", ""))
294             ssh.return_value = ssh_mock
295         mock_get_kernel_module.return_value = "i40e"
296         # NOTE(ralonsoh): this test doesn't cover function execution. This test
297         # should also check mocked function calls.
298         model.StandaloneContextHelper.get_nic_details(
299             ssh_mock, self.NETWORKS, 'dpdk-devbind.py')
300
301     def test_get_virtual_devices(self):
302         pattern = "PCI_SLOT_NAME=0000:05:00.0"
303         with mock.patch("yardstick.ssh.SSH") as ssh:
304             ssh_mock = mock.Mock(autospec=ssh.SSH)
305             ssh_mock.execute = \
306                 mock.Mock(return_value=(1, pattern, ""))
307             ssh.return_value = ssh_mock
308         # NOTE(ralonsoh): this test doesn't cover function execution. This test
309         # should also check mocked function calls.
310         model.StandaloneContextHelper.get_virtual_devices(
311             ssh_mock, '0000:00:05.0')
312
313     def _get_file_abspath(self, filename):
314         curr_path = os.path.dirname(os.path.abspath(__file__))
315         file_path = os.path.join(curr_path, filename)
316         return file_path
317
318     def test_read_config_file(self):
319         self.helper.file_path = self._get_file_abspath(self.NODE_SAMPLE)
320         status = self.helper.read_config_file()
321         self.assertIsNotNone(status)
322
323     def test_parse_pod_file(self):
324         self.helper.file_path = self._get_file_abspath("dummy")
325         self.assertRaises(IOError, self.helper.parse_pod_file,
326                           self.helper.file_path)
327
328         self.helper.file_path = self._get_file_abspath(self.NODE_SAMPLE)
329         self.assertRaises(TypeError, self.helper.parse_pod_file,
330                           self.helper.file_path)
331
332         self.helper.file_path = self._get_file_abspath(self.NODE_SRIOV_SAMPLE)
333         self.assertIsNotNone(self.helper.parse_pod_file(self.helper.file_path))
334
335     def test_get_mac_address(self):
336         status = model.StandaloneContextHelper.get_mac_address()
337         self.assertIsNotNone(status)
338
339     @mock.patch('yardstick.ssh.SSH')
340     def test_get_mgmt_ip(self, *args):
341         # NOTE(ralonsoh): test mocked methods/variables.
342         with mock.patch("yardstick.ssh.SSH") as ssh:
343             ssh_mock = mock.Mock(autospec=ssh.SSH)
344             ssh_mock.execute = mock.Mock(
345                 return_value=(1, "1.2.3.4 00:00:00:00:00:01", ""))
346             ssh.return_value = ssh_mock
347         # NOTE(ralonsoh): this test doesn't cover function execution. This test
348         # should also check mocked function calls.
349         status = model.StandaloneContextHelper.get_mgmt_ip(
350             ssh_mock, "00:00:00:00:00:01", "1.1.1.1/24", {})
351         self.assertIsNotNone(status)
352
353     @mock.patch('yardstick.ssh.SSH')
354     def test_get_mgmt_ip_no(self, *args):
355         # NOTE(ralonsoh): test mocked methods/variables.
356         with mock.patch("yardstick.ssh.SSH") as ssh:
357             ssh_mock = mock.Mock(autospec=ssh.SSH)
358             ssh_mock.execute = \
359                 mock.Mock(return_value=(1, "", ""))
360             ssh.return_value = ssh_mock
361         # NOTE(ralonsoh): this test doesn't cover function execution. This test
362         # should also check mocked function calls.
363         model.WAIT_FOR_BOOT = 0
364         status = model.StandaloneContextHelper.get_mgmt_ip(
365             ssh_mock, "99", "1.1.1.1/24", {})
366         self.assertIsNone(status)
367
368
369 class ServerTestCase(unittest.TestCase):
370
371     NETWORKS = {
372         'mgmt': {'cidr': '152.16.100.10/24'},
373         'private_0': {
374             'phy_port': "0000:05:00.0",
375             'vpci': "0000:00:07.0",
376             'driver': 'i40e',
377             'mac': '',
378             'cidr': '152.16.100.10/24',
379             'gateway_ip': '152.16.100.20'},
380         'public_0': {
381             'phy_port': "0000:05:00.1",
382             'vpci': "0000:00:08.0",
383             'driver': 'i40e',
384             'mac': '',
385             'cidr': '152.16.40.10/24',
386             'gateway_ip': '152.16.100.20'}
387     }
388
389     def setUp(self):
390         self.server = model.Server()
391
392     def test___init__(self):
393         self.assertIsNotNone(self.server)
394
395     def test_build_vnf_interfaces(self):
396         vnf = {
397             "network_ports": {
398                 'mgmt': {'cidr': '152.16.100.10/24'},
399                 'xe0': ['private_0'],
400                 'xe1': ['public_0'],
401             }
402         }
403         status = model.Server.build_vnf_interfaces(vnf, self.NETWORKS)
404         self.assertIsNotNone(status)
405
406     def test_generate_vnf_instance(self):
407         vnf = {
408             "network_ports": {
409                 'mgmt': {'cidr': '152.16.100.10/24'},
410                 'xe0': ['private_0'],
411                 'xe1': ['public_0'],
412             }
413         }
414         status = self.server.generate_vnf_instance(
415             {}, self.NETWORKS, '1.1.1.1/24', 'vm_0', vnf, '00:00:00:00:00:01')
416         self.assertIsNotNone(status)
417
418
419 class OvsDeployTestCase(unittest.TestCase):
420
421     OVS_DETAILS = {'version': {'ovs': 'ovs_version', 'dpdk': 'dpdk_version'}}
422
423     def setUp(self):
424         self._mock_ssh = mock.patch.object(ssh, 'SSH')
425         self.mock_ssh = self._mock_ssh .start()
426         self.ovs_deploy = model.OvsDeploy(self.mock_ssh,
427                                           '/tmp/dpdk-devbind.py',
428                                           self.OVS_DETAILS)
429         self._mock_path_isfile = mock.patch.object(os.path, 'isfile')
430         self._mock_path_join = mock.patch.object(os.path, 'join')
431         self.mock_path_isfile = self._mock_path_isfile.start()
432         self.mock_path_join = self._mock_path_join.start()
433
434         self.addCleanup(self._stop_mock)
435
436     def _stop_mock(self):
437         self._mock_ssh.stop()
438         self._mock_path_isfile.stop()
439         self._mock_path_join.stop()
440
441     @mock.patch.object(model.StandaloneContextHelper, 'install_req_libs')
442     def test_prerequisite(self, mock_install_req_libs):
443         pkgs = ["git", "build-essential", "pkg-config", "automake",
444                 "autotools-dev", "libltdl-dev", "cmake", "libnuma-dev",
445                 "libpcap-dev"]
446         self.ovs_deploy.prerequisite()
447         mock_install_req_libs.assert_called_once_with(
448             self.ovs_deploy.connection, pkgs)
449
450     def test_ovs_deploy_no_file(self):
451         self.mock_path_isfile.return_value = False
452         mock_file = mock.Mock()
453         self.mock_path_join.return_value = mock_file
454
455         self.ovs_deploy.ovs_deploy()
456         self.mock_path_isfile.assert_called_once_with(mock_file)
457         self.mock_path_join.assert_called_once_with(
458             constants.YARDSTICK_ROOT_PATH,
459             'yardstick/resources/scripts/install/',
460             self.ovs_deploy.OVS_DEPLOY_SCRIPT)
461
462     @mock.patch.object(os.environ, 'get', return_value='test_proxy')
463     def test_ovs_deploy(self, mock_env_get):
464         self.mock_path_isfile.return_value = True
465         mock_deploy_file = mock.Mock()
466         mock_remove_ovs_deploy = mock.Mock()
467         self.mock_path_join.side_effect = [mock_deploy_file,
468                                            mock_remove_ovs_deploy]
469         dpdk_version = self.OVS_DETAILS['version']['dpdk']
470         ovs_version = self.OVS_DETAILS['version']['ovs']
471
472         with mock.patch.object(self.ovs_deploy.connection, 'put') as \
473                 mock_put, \
474                 mock.patch.object(self.ovs_deploy.connection, 'execute') as \
475                 mock_execute, \
476                 mock.patch.object(self.ovs_deploy, 'prerequisite'):
477             mock_execute.return_value = (0, 0, 0)
478             self.ovs_deploy.ovs_deploy()
479
480             self.mock_path_isfile.assert_called_once_with(mock_deploy_file)
481             self.mock_path_join.assert_has_calls([
482                 mock.call(constants.YARDSTICK_ROOT_PATH,
483                           'yardstick/resources/scripts/install/',
484                           self.ovs_deploy.OVS_DEPLOY_SCRIPT),
485                 mock.call(self.ovs_deploy.bin_path,
486                           self.ovs_deploy.OVS_DEPLOY_SCRIPT)
487             ])
488             mock_put.assert_called_once_with(mock_deploy_file,
489                                              mock_remove_ovs_deploy)
490             cmd = ("sudo -E %(remote_ovs_deploy)s --ovs='%(ovs_version)s' "
491                    "--dpdk='%(dpdk_version)s' -p='%(proxy)s'" %
492                    {'remote_ovs_deploy': mock_remove_ovs_deploy,
493                     'ovs_version': ovs_version,
494                     'dpdk_version': dpdk_version,
495                     'proxy': 'test_proxy'})
496             mock_execute.assert_called_once_with(cmd)
497             mock_env_get.assert_called_once_with('http_proxy', '')