1 # Copyright (c) 2016-2017 Intel Corporation
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
7 # http://www.apache.org/licenses/LICENSE-2.0
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.
21 from xml.etree import ElementTree
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
30 XML_SAMPLE = """<?xml version="1.0"?>
37 XML_SAMPLE_INTERFACE = """<?xml version="1.0"?>
47 class ModelLibvirtTestCase(unittest.TestCase):
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)
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)
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')
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')
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')
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')
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),
108 self.assertEqual('0x{}'.format(self.pci_address.slot),
110 self.assertEqual('0x{}'.format(self.pci_address.function),
111 result.get('function'))
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)
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',
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'))
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'))
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'))
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'))
174 def test_create_snapshot_qemu(self):
175 self.mock_ssh.execute = mock.Mock(return_value=(0, 0, 0))
177 vm_image = '/var/lib/libvirt/images/%s.qcow2' % index
178 base_image = '/tmp/base_image'
180 model.Libvirt.create_snapshot_qemu(self.mock_ssh, index, base_image)
181 self.mock_ssh.execute.assert_has_calls([
182 mock.call('rm -- "%s"' % vm_image),
183 mock.call('test -r %s' % base_image),
184 mock.call('qemu-img create -f qcow2 -o backing_file=%s %s' %
185 (base_image, vm_image))
188 @mock.patch.object(os.path, 'basename', return_value='base_image')
189 @mock.patch.object(os.path, 'normpath')
190 @mock.patch.object(os, 'access', return_value=True)
191 def test_create_snapshot_qemu_no_image_remote(self,
192 mock_os_access, mock_normpath, mock_basename):
193 self.mock_ssh.execute = mock.Mock(
194 side_effect=[(0, 0, 0), (1, 0, 0), (0, 0, 0), (0, 0, 0)])
196 vm_image = '/var/lib/libvirt/images/%s.qcow2' % index
197 base_image = '/tmp/base_image'
198 mock_normpath.return_value = base_image
200 model.Libvirt.create_snapshot_qemu(self.mock_ssh, index, base_image)
201 self.mock_ssh.execute.assert_has_calls([
202 mock.call('rm -- "%s"' % vm_image),
203 mock.call('test -r %s' % base_image),
204 mock.call('mv -- "/tmp/%s" "%s"' % ('base_image', base_image)),
205 mock.call('qemu-img create -f qcow2 -o backing_file=%s %s' %
206 (base_image, vm_image))
208 mock_os_access.assert_called_once_with(base_image, os.R_OK)
209 mock_normpath.assert_called_once_with(base_image)
210 mock_basename.assert_has_calls([mock.call(base_image)])
211 self.mock_ssh.put_file.assert_called_once_with(base_image,
214 @mock.patch.object(os, 'access', return_value=False)
215 def test_create_snapshot_qemu_no_image_local(self, mock_os_access):
216 self.mock_ssh.execute = mock.Mock(side_effect=[(0, 0, 0), (1, 0, 0)])
217 base_image = '/tmp/base_image'
219 with self.assertRaises(exceptions.LibvirtQemuImageBaseImageNotPresent):
220 model.Libvirt.create_snapshot_qemu(self.mock_ssh, 3, base_image)
221 mock_os_access.assert_called_once_with(base_image, os.R_OK)
223 def test_create_snapshot_qemu_error_qemuimg_command(self):
224 self.mock_ssh.execute = mock.Mock(
225 side_effect=[(0, 0, 0), (0, 0, 0), (1, 0, 0)])
227 vm_image = '/var/lib/libvirt/images/%s.qcow2' % index
228 base_image = '/tmp/base_image'
230 with self.assertRaises(exceptions.LibvirtQemuImageCreateError):
231 model.Libvirt.create_snapshot_qemu(self.mock_ssh, index,
233 self.mock_ssh.execute.assert_has_calls([
234 mock.call('rm -- "%s"' % vm_image),
235 mock.call('test -r %s' % base_image),
236 mock.call('qemu-img create -f qcow2 -o backing_file=%s %s' %
237 (base_image, vm_image))
240 @mock.patch.object(model.Libvirt, 'pin_vcpu_for_perf', return_value='4,5')
241 @mock.patch.object(model.Libvirt, 'create_snapshot_qemu',
242 return_value='qemu_image')
243 def test_build_vm_xml(self, mock_create_snapshot_qemu,
244 mock_pin_vcpu_for_perf):
245 extra_specs = {'hw:cpu_cores': '4',
246 'hw:cpu_sockets': '3',
247 'hw:cpu_threads': '2',
249 flavor = {'ram': '1024',
250 'extra_specs': extra_specs,
253 mac = model.StandaloneContextHelper.get_mac_address(0x00)
255 connection = mock.Mock()
256 with mock.patch.object(model.StandaloneContextHelper,
257 'get_mac_address', return_value=mac) as \
258 mock_get_mac_address, \
259 mock.patch.object(uuid, 'uuid4', return_value=_uuid):
260 xml_out, mac = model.Libvirt.build_vm_xml(
261 connection, flavor, 'vm_name', 100)
263 xml_ref = model.VM_TEMPLATE.format(vm_name='vm_name',
264 random_uuid=_uuid, mac_addr=mac, memory='1024', vcpu='8', cpu='4',
265 numa_cpus='0-7', socket='3', threads='2',
266 vm_image='qemu_image', cpuset='4,5', cputune='cool')
267 self.assertEqual(xml_ref, xml_out)
268 mock_get_mac_address.assert_called_once_with(0x00)
269 mock_create_snapshot_qemu.assert_called_once_with(
270 connection, 100, 'images')
271 mock_pin_vcpu_for_perf.assert_called_once_with(connection, '1')
273 # TODO: Edit this test to test state instead of output
274 # update_interrupts_hugepages_perf does not return anything
275 def test_update_interrupts_hugepages_perf(self):
276 with mock.patch("yardstick.ssh.SSH") as ssh:
277 ssh_mock = mock.Mock(autospec=ssh.SSH)
279 mock.Mock(return_value=(0, "a", ""))
280 ssh.return_value = ssh_mock
281 # NOTE(ralonsoh): 'update_interrupts_hugepages_perf' always return
282 # None, this check is trivial.
283 #status = Libvirt.update_interrupts_hugepages_perf(ssh_mock)
284 #self.assertIsNone(status)
285 model.Libvirt.update_interrupts_hugepages_perf(ssh_mock)
287 @mock.patch.object(model, 'CpuSysCores')
288 @mock.patch.object(model.Libvirt, 'update_interrupts_hugepages_perf')
289 def test_pin_vcpu_for_perf(self, *args):
290 # NOTE(ralonsoh): test mocked methods/variables.
291 with mock.patch("yardstick.ssh.SSH") as ssh:
292 ssh_mock = mock.Mock(autospec=ssh.SSH)
294 mock.Mock(return_value=(0, "a", ""))
295 ssh.return_value = ssh_mock
296 status = model.Libvirt.pin_vcpu_for_perf(ssh_mock, 4)
297 self.assertIsNotNone(status)
299 class StandaloneContextHelperTestCase(unittest.TestCase):
301 NODE_SAMPLE = "nodes_sample.yaml"
302 NODE_SRIOV_SAMPLE = "nodes_sriov_sample.yaml"
305 'mgmt': {'cidr': '152.16.100.10/24'},
307 'phy_port': "0000:05:00.0",
308 'vpci': "0000:00:07.0",
309 'cidr': '152.16.100.10/24',
310 'gateway_ip': '152.16.100.20'},
312 'phy_port': "0000:05:00.1",
313 'vpci': "0000:00:08.0",
314 'cidr': '152.16.40.10/24',
315 'gateway_ip': '152.16.100.20'}
319 self.helper = model.StandaloneContextHelper()
321 def test___init__(self):
322 self.assertIsNone(self.helper.file_path)
324 def test_install_req_libs(self):
325 with mock.patch("yardstick.ssh.SSH") as ssh:
326 ssh_mock = mock.Mock(autospec=ssh.SSH)
328 mock.Mock(return_value=(1, "a", ""))
329 ssh.return_value = ssh_mock
330 # NOTE(ralonsoh): this test doesn't cover function execution. This test
331 # should also check mocked function calls.
332 model.StandaloneContextHelper.install_req_libs(ssh_mock)
334 def test_get_kernel_module(self):
335 with mock.patch("yardstick.ssh.SSH") as ssh:
336 ssh_mock = mock.Mock(autospec=ssh.SSH)
338 mock.Mock(return_value=(1, "i40e", ""))
339 ssh.return_value = ssh_mock
340 # NOTE(ralonsoh): this test doesn't cover function execution. This test
341 # should also check mocked function calls.
342 model.StandaloneContextHelper.get_kernel_module(
343 ssh_mock, "05:00.0", None)
345 @mock.patch.object(model.StandaloneContextHelper, 'get_kernel_module')
346 def test_get_nic_details(self, mock_get_kernel_module):
347 with mock.patch("yardstick.ssh.SSH") as ssh:
348 ssh_mock = mock.Mock(autospec=ssh.SSH)
349 ssh_mock.execute = mock.Mock(return_value=(1, "i40e ixgbe", ""))
350 ssh.return_value = ssh_mock
351 mock_get_kernel_module.return_value = "i40e"
352 # NOTE(ralonsoh): this test doesn't cover function execution. This test
353 # should also check mocked function calls.
354 model.StandaloneContextHelper.get_nic_details(
355 ssh_mock, self.NETWORKS, 'dpdk-devbind.py')
357 def test_get_virtual_devices(self):
358 pattern = "PCI_SLOT_NAME=0000:05:00.0"
359 with mock.patch("yardstick.ssh.SSH") as ssh:
360 ssh_mock = mock.Mock(autospec=ssh.SSH)
362 mock.Mock(return_value=(1, pattern, ""))
363 ssh.return_value = ssh_mock
364 # NOTE(ralonsoh): this test doesn't cover function execution. This test
365 # should also check mocked function calls.
366 model.StandaloneContextHelper.get_virtual_devices(
367 ssh_mock, '0000:00:05.0')
369 def _get_file_abspath(self, filename):
370 curr_path = os.path.dirname(os.path.abspath(__file__))
371 file_path = os.path.join(curr_path, filename)
374 def test_parse_pod_file(self):
375 self.helper.file_path = self._get_file_abspath("dummy")
376 self.assertRaises(IOError, self.helper.parse_pod_file,
377 self.helper.file_path)
379 self.helper.file_path = self._get_file_abspath(self.NODE_SAMPLE)
380 self.assertRaises(TypeError, self.helper.parse_pod_file,
381 self.helper.file_path)
383 self.helper.file_path = self._get_file_abspath(self.NODE_SRIOV_SAMPLE)
384 self.assertIsNotNone(self.helper.parse_pod_file(self.helper.file_path))
386 def test_get_mac_address(self):
387 status = model.StandaloneContextHelper.get_mac_address()
388 self.assertIsNotNone(status)
390 @mock.patch('yardstick.ssh.SSH')
391 def test_get_mgmt_ip(self, *args):
392 # NOTE(ralonsoh): test mocked methods/variables.
393 with mock.patch("yardstick.ssh.SSH") as ssh:
394 ssh_mock = mock.Mock(autospec=ssh.SSH)
395 ssh_mock.execute = mock.Mock(
396 return_value=(1, "1.2.3.4 00:00:00:00:00:01", ""))
397 ssh.return_value = ssh_mock
398 # NOTE(ralonsoh): this test doesn't cover function execution. This test
399 # should also check mocked function calls.
400 status = model.StandaloneContextHelper.get_mgmt_ip(
401 ssh_mock, "00:00:00:00:00:01", "1.1.1.1/24", {})
402 self.assertIsNotNone(status)
404 @mock.patch('yardstick.ssh.SSH')
405 def test_get_mgmt_ip_no(self, *args):
406 # NOTE(ralonsoh): test mocked methods/variables.
407 with mock.patch("yardstick.ssh.SSH") as ssh:
408 ssh_mock = mock.Mock(autospec=ssh.SSH)
410 mock.Mock(return_value=(1, "", ""))
411 ssh.return_value = ssh_mock
412 # NOTE(ralonsoh): this test doesn't cover function execution. This test
413 # should also check mocked function calls.
414 model.WAIT_FOR_BOOT = 0
415 status = model.StandaloneContextHelper.get_mgmt_ip(
416 ssh_mock, "99", "1.1.1.1/24", {})
417 self.assertIsNone(status)
420 class ServerTestCase(unittest.TestCase):
423 'mgmt': {'cidr': '152.16.100.10/24'},
425 'phy_port': "0000:05:00.0",
426 'vpci': "0000:00:07.0",
429 'cidr': '152.16.100.10/24',
430 'gateway_ip': '152.16.100.20'},
432 'phy_port': "0000:05:00.1",
433 'vpci': "0000:00:08.0",
436 'cidr': '152.16.40.10/24',
437 'gateway_ip': '152.16.100.20'}
441 self.server = model.Server()
443 def test___init__(self):
444 self.assertIsNotNone(self.server)
446 def test_build_vnf_interfaces(self):
449 'mgmt': {'cidr': '152.16.100.10/24'},
450 'xe0': ['private_0'],
454 status = model.Server.build_vnf_interfaces(vnf, self.NETWORKS)
455 self.assertIsNotNone(status)
457 def test_generate_vnf_instance(self):
460 'mgmt': {'cidr': '152.16.100.10/24'},
461 'xe0': ['private_0'],
465 status = self.server.generate_vnf_instance(
466 {}, self.NETWORKS, '1.1.1.1/24', 'vm_0', vnf, '00:00:00:00:00:01')
467 self.assertIsNotNone(status)
470 class OvsDeployTestCase(unittest.TestCase):
472 OVS_DETAILS = {'version': {'ovs': 'ovs_version', 'dpdk': 'dpdk_version'}}
475 self._mock_ssh = mock.patch.object(ssh, 'SSH')
476 self.mock_ssh = self._mock_ssh.start()
477 self.ovs_deploy = model.OvsDeploy(self.mock_ssh,
478 '/tmp/dpdk-devbind.py',
480 self._mock_path_isfile = mock.patch.object(os.path, 'isfile')
481 self._mock_path_join = mock.patch.object(os.path, 'join')
482 self.mock_path_isfile = self._mock_path_isfile.start()
483 self.mock_path_join = self._mock_path_join.start()
485 self.addCleanup(self._stop_mock)
487 def _stop_mock(self):
488 self._mock_ssh.stop()
489 self._mock_path_isfile.stop()
490 self._mock_path_join.stop()
492 @mock.patch.object(model.StandaloneContextHelper, 'install_req_libs')
493 def test_prerequisite(self, mock_install_req_libs):
494 pkgs = ["git", "build-essential", "pkg-config", "automake",
495 "autotools-dev", "libltdl-dev", "cmake", "libnuma-dev",
497 self.ovs_deploy.prerequisite()
498 mock_install_req_libs.assert_called_once_with(
499 self.ovs_deploy.connection, pkgs)
501 def test_ovs_deploy_no_file(self):
502 self.mock_path_isfile.return_value = False
503 mock_file = mock.Mock()
504 self.mock_path_join.return_value = mock_file
506 self.ovs_deploy.ovs_deploy()
507 self.mock_path_isfile.assert_called_once_with(mock_file)
508 self.mock_path_join.assert_called_once_with(
509 constants.YARDSTICK_ROOT_PATH,
510 'yardstick/resources/scripts/install/',
511 self.ovs_deploy.OVS_DEPLOY_SCRIPT)
513 @mock.patch.object(os.environ, 'get', return_value='test_proxy')
514 def test_ovs_deploy(self, mock_env_get):
515 self.mock_path_isfile.return_value = True
516 mock_deploy_file = mock.Mock()
517 mock_remove_ovs_deploy = mock.Mock()
518 self.mock_path_join.side_effect = [mock_deploy_file,
519 mock_remove_ovs_deploy]
520 dpdk_version = self.OVS_DETAILS['version']['dpdk']
521 ovs_version = self.OVS_DETAILS['version']['ovs']
523 with mock.patch.object(self.ovs_deploy.connection, 'put') as \
525 mock.patch.object(self.ovs_deploy.connection, 'execute') as \
527 mock.patch.object(self.ovs_deploy, 'prerequisite'):
528 mock_execute.return_value = (0, 0, 0)
529 self.ovs_deploy.ovs_deploy()
531 self.mock_path_isfile.assert_called_once_with(mock_deploy_file)
532 self.mock_path_join.assert_has_calls([
533 mock.call(constants.YARDSTICK_ROOT_PATH,
534 'yardstick/resources/scripts/install/',
535 self.ovs_deploy.OVS_DEPLOY_SCRIPT),
536 mock.call(self.ovs_deploy.bin_path,
537 self.ovs_deploy.OVS_DEPLOY_SCRIPT)
539 mock_put.assert_called_once_with(mock_deploy_file,
540 mock_remove_ovs_deploy)
541 cmd = ("sudo -E %(remote_ovs_deploy)s --ovs='%(ovs_version)s' "
542 "--dpdk='%(dpdk_version)s' -p='%(proxy)s'" %
543 {'remote_ovs_deploy': mock_remove_ovs_deploy,
544 'ovs_version': ovs_version,
545 'dpdk_version': dpdk_version,
546 'proxy': 'test_proxy'})
547 mock_execute.assert_called_once_with(cmd)
548 mock_env_get.assert_has_calls([mock.call('http_proxy', '')])