1 ##############################################################################
2 # Copyright (c) 2015 Ericsson AB and others.
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 ##############################################################################
10 from collections import OrderedDict
11 from itertools import count
19 from yardstick.benchmark.contexts import base
20 from yardstick.benchmark.contexts import heat
21 from yardstick.benchmark.contexts import model
22 from yardstick.common import exceptions as y_exc
23 from yardstick.orchestrator import heat as orch_heat
24 from yardstick import ssh
27 LOG = logging.getLogger(__name__)
30 class HeatContextTestCase(unittest.TestCase):
32 def __init__(self, *args, **kwargs):
33 super(HeatContextTestCase, self).__init__(*args, **kwargs)
34 self.name_iter = ('vnf{:03}'.format(x) for x in count(0, step=3))
37 self.test_context = heat.HeatContext()
38 self.addCleanup(self._remove_contexts)
39 self.mock_context = mock.Mock(spec=heat.HeatContext())
41 def _remove_contexts(self):
42 if self.test_context in self.test_context.list:
43 self.test_context._delete_context()
45 def test___init__(self):
46 self.assertIsNone(self.test_context._name)
47 self.assertIsNone(self.test_context._task_id)
48 self.assertFalse(self.test_context._flags.no_setup)
49 self.assertFalse(self.test_context._flags.no_teardown)
50 self.assertIsNone(self.test_context.stack)
51 self.assertEqual(self.test_context.networks, OrderedDict())
52 self.assertEqual(self.test_context.servers, [])
53 self.assertEqual(self.test_context.placement_groups, [])
54 self.assertEqual(self.test_context.server_groups, [])
55 self.assertIsNone(self.test_context.keypair_name)
56 self.assertIsNone(self.test_context.secgroup_name)
57 self.assertEqual(self.test_context._server_map, {})
58 self.assertIsNone(self.test_context._image)
59 self.assertIsNone(self.test_context._flavor)
60 self.assertIsNone(self.test_context._user)
61 self.assertIsNone(self.test_context.template_file)
62 self.assertIsNone(self.test_context.heat_parameters)
63 self.assertIsNone(self.test_context.key_filename)
65 @mock.patch.object(ssh.SSH, 'gen_keys')
66 @mock.patch('yardstick.benchmark.contexts.heat.PlacementGroup')
67 @mock.patch('yardstick.benchmark.contexts.heat.ServerGroup')
68 @mock.patch('yardstick.benchmark.contexts.heat.Network')
69 @mock.patch('yardstick.benchmark.contexts.heat.Server')
70 def test_init(self, mock_server, mock_network, mock_sg, mock_pg, mock_ssh_gen_keys):
72 pgs = {'pgrp1': {'policy': 'availability'}}
73 sgs = {'servergroup1': {'policy': 'affinity'}}
74 networks = {'bar': {'cidr': '10.0.1.0/24'}}
75 servers = {'baz': {'floating_ip': True, 'placement': 'pgrp1'}}
76 attrs = {'name': 'foo',
77 'task_id': '1234567890',
78 'placement_groups': pgs,
83 self.test_context.init(attrs)
85 self.assertFalse(self.test_context._flags.no_setup)
86 self.assertFalse(self.test_context._flags.no_teardown)
87 self.assertEqual(self.test_context._name, "foo")
88 self.assertEqual(self.test_context._task_id, '1234567890')
89 self.assertEqual(self.test_context.name, "foo-12345678")
90 self.assertEqual(self.test_context.keypair_name, "foo-12345678-key")
91 self.assertEqual(self.test_context.secgroup_name, "foo-12345678-secgroup")
93 mock_pg.assert_called_with('pgrp1', self.test_context,
94 pgs['pgrp1']['policy'])
95 mock_sg.assert_called_with('servergroup1', self.test_context,
96 sgs['servergroup1']['policy'])
97 self.assertEqual(len(self.test_context.placement_groups), 1)
98 self.assertEqual(len(self.test_context.server_groups), 1)
100 mock_network.assert_called_with(
101 'bar', self.test_context, networks['bar'])
102 self.assertEqual(len(self.test_context.networks), 1)
104 mock_server.assert_called_with('baz', self.test_context,
106 self.assertEqual(len(self.test_context.servers), 1)
108 mock_ssh_gen_keys.assert_called()
110 def test_init_no_name_or_task_id(self):
112 self.assertRaises(KeyError, self.test_context.init, attrs)
115 self.test_context._name = 'foo'
116 self.test_context._task_id = '1234567890'
117 self.test_context._name_task_id = '{}-{}'.format(
118 self.test_context._name, self.test_context._task_id[:8])
119 self.assertEqual(self.test_context.name, 'foo-12345678')
120 self.assertEqual(self.test_context.assigned_name, 'foo')
122 def test_name_flags(self):
123 self.test_context._flags = base.Flags(
124 **{"no_setup": True, "no_teardown": True})
125 self.test_context._name = 'foo'
126 self.test_context._task_id = '1234567890'
128 self.assertEqual(self.test_context.name, 'foo')
129 self.assertEqual(self.test_context.assigned_name, 'foo')
131 @mock.patch('yardstick.ssh.SSH.gen_keys')
132 def test_init_no_setup_no_teardown(self, *args):
134 attrs = {'name': 'foo',
135 'task_id': '1234567890',
136 'placement_groups': {},
146 self.test_context.init(attrs)
147 self.assertTrue(self.test_context._flags.no_setup)
148 self.assertTrue(self.test_context._flags.no_teardown)
150 @mock.patch('yardstick.benchmark.contexts.heat.HeatTemplate')
151 def test__add_resources_to_template_no_servers(self, mock_template):
152 self.test_context._name = 'ctx'
153 self.test_context._task_id = '1234567890'
154 self.test_context._name_task_id = '{}-{}'.format(
155 self.test_context._name, self.test_context._task_id[:8])
156 self.test_context.keypair_name = "ctx-key"
157 self.test_context.secgroup_name = "ctx-secgroup"
158 self.test_context.key_uuid = "2f2e4997-0a8e-4eb7-9fa4-f3f8fbbc393b"
159 netattrs = {'cidr': '10.0.0.0/24', 'provider': None,
160 'external_network': 'ext_net'}
162 self.test_context.networks = OrderedDict(
163 {"mynet": model.Network("mynet", self.test_context,
166 self.test_context._add_resources_to_template(mock_template)
167 mock_template.add_keypair.assert_called_with(
170 mock_template.add_security_group.assert_called_with("ctx-secgroup")
171 mock_template.add_network.assert_called_with(
172 "ctx-12345678-mynet", 'physnet1', None, None, None, None)
173 mock_template.add_router.assert_called_with(
174 "ctx-12345678-mynet-router",
175 netattrs["external_network"],
176 "ctx-12345678-mynet-subnet")
177 mock_template.add_router_interface.assert_called_with(
178 "ctx-12345678-mynet-router-if0",
179 "ctx-12345678-mynet-router",
180 "ctx-12345678-mynet-subnet")
182 @mock.patch('yardstick.benchmark.contexts.heat.HeatTemplate')
183 def test_attrs_get(self, *args):
184 image, flavor, user = expected_tuple = 'foo1', 'foo2', 'foo3'
185 self.assertNotEqual(self.test_context.image, image)
186 self.assertNotEqual(self.test_context.flavor, flavor)
187 self.assertNotEqual(self.test_context.user, user)
188 self.test_context._image = image
189 self.test_context._flavor = flavor
190 self.test_context._user = user
191 attr_tuple = self.test_context.image, self.test_context.flavor, self.test_context.user
192 self.assertEqual(attr_tuple, expected_tuple)
194 @mock.patch('yardstick.benchmark.contexts.heat.HeatTemplate')
195 def test_attrs_set_negative(self, *args):
196 with self.assertRaises(AttributeError):
197 self.test_context.image = 'foo'
199 with self.assertRaises(AttributeError):
200 self.test_context.flavor = 'foo'
202 with self.assertRaises(AttributeError):
203 self.test_context.user = 'foo'
205 def test__create_new_stack(self):
206 template = mock.Mock()
207 self.test_context._create_new_stack(template)
208 template.create.assert_called_once()
210 def test__create_new_stack_stack_create_failed(self):
211 template = mock.Mock()
212 template.create.side_effect = y_exc.HeatTemplateError
214 self.assertRaises(y_exc.HeatTemplateError,
215 self.test_context._create_new_stack,
218 def test__create_new_stack_keyboard_interrupt(self):
219 template = mock.Mock()
220 template.create.side_effect = KeyboardInterrupt
221 self.assertRaises(y_exc.StackCreationInterrupt,
222 self.test_context._create_new_stack,
225 @mock.patch.object(orch_heat.HeatTemplate, 'add_keypair')
226 @mock.patch.object(heat.HeatContext, '_create_new_stack')
227 def test_deploy_stack_creation_failed(self, mock_create, *args):
228 self.test_context._name = 'foo'
229 self.test_context._task_id = '1234567890'
230 self.test_context._name_task_id = 'foo-12345678'
231 mock_create.side_effect = y_exc.HeatTemplateError
232 self.assertRaises(y_exc.HeatTemplateError,
233 self.test_context.deploy)
235 @mock.patch('yardstick.benchmark.contexts.heat.HeatTemplate')
236 def test_deploy(self, mock_template):
237 self.test_context._name = 'foo'
238 self.test_context._task_id = '1234567890'
239 self.test_context._name_task_id = '{}-{}'.format(
240 self.test_context._name, self.test_context._task_id[:8])
241 self.test_context.template_file = '/bar/baz/some-heat-file'
242 self.test_context.heat_parameters = {'image': 'cirros'}
243 self.test_context.get_neutron_info = mock.MagicMock()
244 self.test_context.deploy()
246 mock_template.assert_called_with('foo-12345678',
247 '/bar/baz/some-heat-file',
249 self.assertIsNotNone(self.test_context.stack)
251 # TODO: patch objects
252 @mock.patch.object(heat, 'HeatTemplate')
253 @mock.patch.object(heat.HeatContext, '_retrieve_existing_stack')
254 @mock.patch.object(heat.HeatContext, '_create_new_stack')
255 def test_deploy_no_setup(self, mock_create_new_stack, mock_retrieve_existing_stack, *args):
256 self.test_context._name = 'foo'
257 self.test_context._task_id = '1234567890'
258 # Might be able to get rid of these
259 self.test_context.template_file = '/bar/baz/some-heat-file'
260 self.test_context.heat_parameters = {'image': 'cirros'}
261 self.test_context.get_neutron_info = mock.MagicMock()
262 self.test_context._flags.no_setup = True
263 self.test_context.deploy()
265 # check that heat client is called...
266 mock_create_new_stack.assert_not_called()
267 mock_retrieve_existing_stack.assert_called_with(self.test_context.name)
268 self.assertIsNotNone(self.test_context.stack)
270 @mock.patch.object(shade, 'openstack_cloud')
271 @mock.patch.object(heat.HeatTemplate, 'add_keypair')
272 @mock.patch.object(heat.HeatContext, '_create_new_stack')
273 @mock.patch.object(heat.HeatStack, 'get')
274 def test_deploy_try_retrieve_context_does_not_exist(self,
276 mock_create_new_stack,
278 self.test_context._name = 'demo'
279 self.test_context._task_id = '1234567890'
280 self.test_context._flags.no_setup = True
281 self.test_context.get_neutron_info = mock.MagicMock()
283 # TODo: Check is this the right value to return, should it be None instead?
284 mock_get_stack.return_value = []
286 self.test_context.deploy()
288 mock_get_stack.assert_called()
289 mock_create_new_stack.assert_called()
291 def test_check_for_context(self):
293 # check that the context exists
295 def test_add_server_port(self):
296 network1 = mock.MagicMock()
297 network2 = mock.MagicMock()
298 self.test_context._name = 'foo'
299 self.test_context._task_id = '1234567890'
300 self.test_context._name_task_id = '{}-{}'.format(
301 self.test_context._name, self.test_context._task_id[:8])
302 self.test_context.stack = mock.MagicMock()
303 self.test_context.networks = {
307 self.test_context.stack.outputs = {
308 u'b': u'10.20.30.45',
310 u'foo-12345678-a-subnet-cidr': u'10.20.0.0/15',
311 u'foo-12345678-a-subnet-gateway_ip': u'10.20.30.1',
312 u'b-mac_address': u'00:01',
313 u'b-device_id': u'dev21',
314 u'b-network_id': u'net789',
315 u'd': u'40.30.20.15',
317 u'foo-12345678-c-subnet-cidr': u'40.30.0.0/18',
318 u'foo-12345678-c-subnet-gateway_ip': u'40.30.20.254',
319 u'd-mac_address': u'00:10',
320 u'd-device_id': u'dev43',
321 u'd-network_id': u'net987',
322 u'e': u'40.30.20.15',
324 u'e-mac_address': u'00:10',
325 u'e-device_id': u'dev43',
326 u'e-network_id': u'net987',
328 server = mock.MagicMock()
329 server.private_ip = None
330 server.ports = OrderedDict([
331 ('a', [{'stack_name': 'b', 'port': 'port_a'}]),
332 ('c', [{'stack_name': 'd', 'port': 'port_c'},
333 {'stack_name': 'e', 'port': 'port_f'}]),
337 "private_ip": '10.20.30.45',
339 "subnet_cidr": '10.20.0.0/15',
340 "network": '10.20.0.0',
341 "netmask": '255.254.0.0',
343 "gateway_ip": '10.20.30.1',
344 "mac_address": '00:01',
345 "device_id": 'dev21',
346 "network_id": 'net789',
348 "local_mac": '00:01',
349 "local_ip": '10.20.30.45',
351 self.test_context.add_server_port(server)
352 self.assertEqual(server.private_ip, '10.20.30.45')
353 self.assertEqual(len(server.interfaces), 3)
354 self.assertDictEqual(server.interfaces['port_a'], expected)
356 @mock.patch('yardstick.benchmark.contexts.heat.os')
357 @mock.patch.object(heat.HeatContext, '_delete_key_file')
358 @mock.patch('yardstick.benchmark.contexts.heat.HeatTemplate')
359 def test_undeploy(self, mock_template, mock_delete_key, *args):
360 self.test_context.stack = mock_template
361 self.test_context._name = 'foo'
362 self.test_context._task_id = '1234567890'
363 self.test_context._name_task_id = '{}-{}'.format(
364 self.test_context._name, self.test_context._task_id[:8])
365 # mock_os.path.exists.return_value = True
366 self.test_context.key_filename = 'foo/bar/foobar'
367 self.test_context.undeploy()
368 mock_delete_key.assert_called()
369 self.assertTrue(mock_template.delete.called)
371 @mock.patch('yardstick.benchmark.contexts.heat.HeatTemplate')
372 def test_undeploy_no_teardown(self, mock_template):
373 self.test_context.stack = mock_template
374 self.test_context._name = 'foo'
375 self.test_context._task_id = '1234567890'
376 self.test_context._flags.no_teardown = True
377 self.test_context.undeploy()
379 mock_template.delete.assert_not_called()
381 @mock.patch('yardstick.benchmark.contexts.heat.HeatTemplate')
382 @mock.patch('yardstick.benchmark.contexts.heat.os')
383 def test_undeploy_key_filename(self, mock_os, mock_template):
384 self.test_context.stack = mock_template
385 self.test_context._name = 'foo'
386 self.test_context._task_id = '1234567890'
387 self.test_context._name_task_id = '{}-{}'.format(
388 self.test_context._name, self.test_context._task_id)
389 mock_os.path.exists.return_value = True
390 self.test_context.key_filename = 'foo/bar/foobar'
391 self.assertIsNone(self.test_context.undeploy())
393 @mock.patch("yardstick.benchmark.contexts.heat.pkg_resources")
394 def test__get_server_found_dict(self, *args):
396 Use HeatContext._get_server to get a server that matches
397 based on a dictionary input.
399 foo2_server = mock.Mock()
400 foo2_server.key_filename = None
401 foo2_server.private_ip = '10.0.0.2'
402 foo2_server.public_ip = '127.0.0.2'
403 foo2_server.context.user = 'oof'
405 baz3_server = mock.Mock()
406 baz3_server.key_filename = None
407 baz3_server.private_ip = '10.0.0.3'
408 baz3_server.public_ip = '127.0.0.3'
409 baz3_server.context.user = 'zab'
411 self.test_context._name = 'bar'
412 self.test_context._task_id = '1234567890'
413 self.test_context._name_task_id = '{}-{}'.format(
414 self.test_context._name, self.test_context._task_id[:8])
415 self.test_context._user = 'bot'
416 self.test_context.stack = mock.Mock()
417 self.test_context.stack.outputs = {
418 'private_ip': '10.0.0.1',
419 'public_ip': '127.0.0.1',
421 self.test_context._server_map = {
427 'name': 'foo.bar-12345678',
428 'private_ip_attr': 'private_ip',
429 'public_ip_attr': 'public_ip',
431 self.test_context.key_uuid = 'foo-42'
432 result = self.test_context._get_server(attr_name)
433 self.assertEqual(result['user'], 'bot')
434 self.assertEqual(result['ip'], '127.0.0.1')
435 self.assertEqual(result['private_ip'], '10.0.0.1')
437 @mock.patch("yardstick.benchmark.contexts.heat.pkg_resources")
438 def test__get_server_found_dict_no_attrs(self, *args):
440 Use HeatContext._get_server to get a server that matches
441 based on a dictionary input.
443 foo2_server = mock.Mock()
444 foo2_server.private_ip = '10.0.0.2'
445 foo2_server.public_ip = '127.0.0.2'
446 foo2_server.context.user = 'oof'
448 baz3_server = mock.Mock()
449 baz3_server.private_ip = '10.0.0.3'
450 baz3_server.public_ip = '127.0.0.3'
451 baz3_server.context.user = 'zab'
453 self.test_context._name = 'bar'
454 self.test_context._task_id = '1234567890'
455 self.test_context._name_task_id = '{}-{}'.format(
456 self.test_context._name, self.test_context._task_id[:8])
457 self.test_context._user = 'bot'
458 self.test_context.stack = mock.Mock()
459 self.test_context.stack.outputs = {
460 'private_ip': '10.0.0.1',
461 'public_ip': '127.0.0.1',
463 self.test_context._server_map = {
469 'name': 'foo.bar-12345678',
472 self.test_context.key_uuid = 'foo-42'
473 result = self.test_context._get_server(attr_name)
474 self.assertEqual(result['user'], 'bot')
475 # no private ip attr mapping in the map results in None value in the result
476 self.assertIsNone(result['private_ip'])
477 # no public ip attr mapping in the map results in no value in the result
478 self.assertNotIn('ip', result)
480 @mock.patch("yardstick.benchmark.contexts.heat.pkg_resources")
481 def test__get_server_found_not_dict(self, *args):
483 Use HeatContext._get_server to get a server that matches
484 based on a non-dictionary input
486 foo2_server = mock.Mock()
487 foo2_server.private_ip = '10.0.0.2'
488 foo2_server.public_ip = '127.0.0.2'
489 foo2_server.context.user = 'oof'
491 baz3_server = mock.Mock()
492 baz3_server.private_ip = '10.0.0.3'
493 baz3_server.public_ip = None
494 baz3_server.context.user = 'zab'
496 self.test_context._name = 'bar1'
497 self.test_context._task_id = '1234567890'
498 self.test_context._name_task_id = 'bar1-12345678'
499 self.test_context.stack = mock.Mock()
500 self.test_context.stack.outputs = {
501 'private_ip': '10.0.0.1',
502 'public_ip': '127.0.0.1',
504 self.test_context.generate_routing_table = mock.MagicMock(return_value=[])
506 self.test_context._server_map = {
512 result = self.test_context._get_server(attr_name)
513 self.assertEqual(result['user'], 'zab')
514 self.assertEqual(result['private_ip'], '10.0.0.3')
515 # no public_ip on the server results in no value in the result
516 self.assertNotIn('public_ip', result)
518 @mock.patch("yardstick.benchmark.contexts.heat.pkg_resources")
519 def test__get_server_none_found_not_dict(self, *args):
521 Use HeatContext._get_server to not get a server due to
522 None value associated with the match to a non-dictionary
525 foo2_server = mock.Mock()
526 foo2_server.private_ip = '10.0.0.2'
527 foo2_server.public_ip = '127.0.0.2'
528 foo2_server.context.user = 'oof'
530 baz3_server = mock.Mock()
531 baz3_server.private_ip = '10.0.0.3'
532 baz3_server.public_ip = None
533 baz3_server.context.user = 'zab'
535 self.test_context._name = 'bar1'
536 self.test_context.stack = mock.Mock()
537 self.test_context.stack.outputs = {
538 'private_ip': '10.0.0.1',
539 'public_ip': '127.0.0.1',
541 self.test_context._server_map = {
547 self.test_context.key_uuid = 'foo-42'
549 result = self.test_context._get_server(attr_name)
550 self.assertIsNone(result)
552 @mock.patch("yardstick.benchmark.contexts.heat.pkg_resources")
553 def test__get_server_not_found_dict(self, *args):
555 Use HeatContext._get_server to not get a server for lack
556 of a match to a dictionary input
558 foo2_server = mock.Mock()
559 foo2_server.private_ip = '10.0.0.2'
560 foo2_server.public_ip = '127.0.0.2'
561 foo2_server.context.user = 'oof'
563 baz3_server = mock.Mock()
564 baz3_server.private_ip = '10.0.0.3'
565 baz3_server.public_ip = None
566 baz3_server.context.user = 'zab'
568 self.test_context._name = 'bar1'
569 self.test_context._task_id = '1235467890'
570 self.test_context._name_task_id = '{}-{}'.format(
571 self.test_context._name, self.test_context._task_id[:8])
572 self.test_context.stack = mock.Mock()
573 self.test_context.stack.outputs = {
574 'private_ip': '10.0.0.1',
575 'public_ip': '127.0.0.1',
577 self.test_context._server_map = {
582 self.test_context.key_uuid = 'foo-42'
585 'private_ip_attr': 'private_ip',
586 'public_ip_attr': 'public_ip',
588 result = self.test_context._get_server(attr_name)
589 self.assertIsNone(result)
591 @mock.patch("yardstick.benchmark.contexts.heat.pkg_resources")
592 def test__get_server_not_found_not_dict(self, *args):
594 Use HeatContext._get_server to not get a server for lack
595 of a match to a non-dictionary input
597 foo2_server = mock.Mock()
598 foo2_server.private_ip = '10.0.0.2'
599 foo2_server.public_ip = '127.0.0.2'
600 foo2_server.context.user = 'oof'
602 baz3_server = mock.Mock()
603 baz3_server.private_ip = '10.0.0.3'
604 baz3_server.public_ip = None
605 baz3_server.context.user = 'zab'
607 self.mock_context._name = 'bar1'
608 self.test_context.stack = mock.Mock()
609 self.mock_context.stack.outputs = {
610 'private_ip': '10.0.0.1',
611 'public_ip': '127.0.0.1',
613 self.mock_context._server_map = {
618 self.test_context.key_uuid = 'foo-42'
619 attr_name = 'foo.wow4'
620 result = self.test_context._get_server(attr_name)
621 self.assertIsNone(result)
623 # TODO: Split this into more granular tests
624 def test__get_network(self):
625 network1 = mock.MagicMock()
626 network1.name = 'net_1'
627 network1.vld_id = 'vld111'
628 network1.segmentation_id = 'seg54'
629 network1.network_type = 'type_a'
630 network1.physical_network = 'phys'
632 network2 = mock.MagicMock()
633 network2.name = 'net_2'
634 network2.segmentation_id = 'seg45'
635 network2.network_type = 'type_b'
636 network2.physical_network = 'virt'
638 self.test_context.networks = {
644 self.assertIsNone(self.test_context._get_network(attr_name))
647 self.assertIsNone(self.test_context._get_network(attr_name))
649 attr_name = {'network_type': 'nosuch'}
650 self.assertIsNone(self.test_context._get_network(attr_name))
653 self.assertIsNone(self.test_context._get_network(attr_name))
655 attr_name = {'segmentation_id': 'seg45'}
658 "segmentation_id": 'seg45',
659 "network_type": 'type_b',
660 "physical_network": 'virt',
662 result = self.test_context._get_network(attr_name)
663 self.assertDictEqual(result, expected)
668 "segmentation_id": 'seg54',
669 "network_type": 'type_a',
670 "physical_network": 'phys',
672 result = self.test_context._get_network(attr_name)
673 self.assertDictEqual(result, expected)