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 result = "/var/lib/libvirt/images/0.qcow2"
176 with mock.patch("yardstick.ssh.SSH") as ssh:
177 ssh_mock = mock.Mock(autospec=ssh.SSH)
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)
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',
193 flavor = {'ram': '1024',
194 'extra_specs': extra_specs,
197 mac = model.StandaloneContextHelper.get_mac_address(0x00)
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)
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')
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)
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)
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)
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)
243 class StandaloneContextHelperTestCase(unittest.TestCase):
245 NODE_SAMPLE = "nodes_sample.yaml"
246 NODE_SRIOV_SAMPLE = "nodes_sriov_sample.yaml"
249 'mgmt': {'cidr': '152.16.100.10/24'},
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'},
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'}
263 self.helper = model.StandaloneContextHelper()
265 def test___init__(self):
266 self.assertIsNone(self.helper.file_path)
268 def test_install_req_libs(self):
269 with mock.patch("yardstick.ssh.SSH") as ssh:
270 ssh_mock = mock.Mock(autospec=ssh.SSH)
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)
278 def test_get_kernel_module(self):
279 with mock.patch("yardstick.ssh.SSH") as ssh:
280 ssh_mock = mock.Mock(autospec=ssh.SSH)
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)
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')
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)
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')
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)
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)
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)
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)
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))
335 def test_get_mac_address(self):
336 status = model.StandaloneContextHelper.get_mac_address()
337 self.assertIsNotNone(status)
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)
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)
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)
369 class ServerTestCase(unittest.TestCase):
372 'mgmt': {'cidr': '152.16.100.10/24'},
374 'phy_port': "0000:05:00.0",
375 'vpci': "0000:00:07.0",
378 'cidr': '152.16.100.10/24',
379 'gateway_ip': '152.16.100.20'},
381 'phy_port': "0000:05:00.1",
382 'vpci': "0000:00:08.0",
385 'cidr': '152.16.40.10/24',
386 'gateway_ip': '152.16.100.20'}
390 self.server = model.Server()
392 def test___init__(self):
393 self.assertIsNotNone(self.server)
395 def test_build_vnf_interfaces(self):
398 'mgmt': {'cidr': '152.16.100.10/24'},
399 'xe0': ['private_0'],
403 status = model.Server.build_vnf_interfaces(vnf, self.NETWORKS)
404 self.assertIsNotNone(status)
406 def test_generate_vnf_instance(self):
409 'mgmt': {'cidr': '152.16.100.10/24'},
410 'xe0': ['private_0'],
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)
419 class OvsDeployTestCase(unittest.TestCase):
421 OVS_DETAILS = {'version': {'ovs': 'ovs_version', 'dpdk': 'dpdk_version'}}
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',
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()
434 self.addCleanup(self._stop_mock)
436 def _stop_mock(self):
437 self._mock_ssh.stop()
438 self._mock_path_isfile.stop()
439 self._mock_path_join.stop()
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",
446 self.ovs_deploy.prerequisite()
447 mock_install_req_libs.assert_called_once_with(
448 self.ovs_deploy.connection, pkgs)
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
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)
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']
472 with mock.patch.object(self.ovs_deploy.connection, 'put') as \
474 mock.patch.object(self.ovs_deploy.connection, 'execute') as \
476 mock.patch.object(self.ovs_deploy, 'prerequisite'):
477 mock_execute.return_value = (0, 0, 0)
478 self.ovs_deploy.ovs_deploy()
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)
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', '')