3 ##############################################################################
4 # Copyright (c) 2015 Ericsson AB and others.
6 # All rights reserved. This program and the accompanying materials
7 # are made available under the terms of the Apache License, Version 2.0
8 # which accompanies this distribution, and is available at
9 # http://www.apache.org/licenses/LICENSE-2.0
10 ##############################################################################
12 from collections import OrderedDict
13 from itertools import count
21 from yardstick.benchmark.contexts import base
22 from yardstick.benchmark.contexts import heat
23 from yardstick.benchmark.contexts import model
24 from yardstick.common import exceptions as y_exc
25 from yardstick.orchestrator import heat as orch_heat
26 from yardstick import ssh
29 LOG = logging.getLogger(__name__)
32 class HeatContextTestCase(unittest.TestCase):
34 def __init__(self, *args, **kwargs):
35 super(HeatContextTestCase, self).__init__(*args, **kwargs)
36 self.name_iter = ('vnf{:03}'.format(x) for x in count(0, step=3))
39 self.test_context = heat.HeatContext()
40 self.addCleanup(self._remove_contexts)
41 self.mock_context = mock.Mock(spec=heat.HeatContext())
43 def _remove_contexts(self):
44 if self.test_context in self.test_context.list:
45 self.test_context._delete_context()
47 def test___init__(self):
48 self.assertIsNone(self.test_context._name)
49 self.assertIsNone(self.test_context._task_id)
50 self.assertFalse(self.test_context._flags.no_setup)
51 self.assertFalse(self.test_context._flags.no_teardown)
52 self.assertIsNone(self.test_context.stack)
53 self.assertEqual(self.test_context.networks, OrderedDict())
54 self.assertEqual(self.test_context.servers, [])
55 self.assertEqual(self.test_context.placement_groups, [])
56 self.assertEqual(self.test_context.server_groups, [])
57 self.assertIsNone(self.test_context.keypair_name)
58 self.assertIsNone(self.test_context.secgroup_name)
59 self.assertEqual(self.test_context._server_map, {})
60 self.assertIsNone(self.test_context._image)
61 self.assertIsNone(self.test_context._flavor)
62 self.assertIsNone(self.test_context._user)
63 self.assertIsNone(self.test_context.template_file)
64 self.assertIsNone(self.test_context.heat_parameters)
65 self.assertIsNone(self.test_context.key_filename)
67 @mock.patch.object(ssh.SSH, 'gen_keys')
68 @mock.patch('yardstick.benchmark.contexts.heat.PlacementGroup')
69 @mock.patch('yardstick.benchmark.contexts.heat.ServerGroup')
70 @mock.patch('yardstick.benchmark.contexts.heat.Network')
71 @mock.patch('yardstick.benchmark.contexts.heat.Server')
72 def test_init(self, mock_server, mock_network, mock_sg, mock_pg, mock_ssh_gen_keys):
74 pgs = {'pgrp1': {'policy': 'availability'}}
75 sgs = {'servergroup1': {'policy': 'affinity'}}
76 networks = {'bar': {'cidr': '10.0.1.0/24'}}
77 servers = {'baz': {'floating_ip': True, 'placement': 'pgrp1'}}
78 attrs = {'name': 'foo',
79 'task_id': '1234567890',
80 'placement_groups': pgs,
85 self.test_context.init(attrs)
87 self.assertFalse(self.test_context._flags.no_setup)
88 self.assertFalse(self.test_context._flags.no_teardown)
89 self.assertEqual(self.test_context._name, "foo")
90 self.assertEqual(self.test_context._task_id, '1234567890')
91 self.assertEqual(self.test_context.name, "foo-12345678")
92 self.assertEqual(self.test_context.keypair_name, "foo-12345678-key")
93 self.assertEqual(self.test_context.secgroup_name, "foo-12345678-secgroup")
95 mock_pg.assert_called_with('pgrp1', self.test_context,
96 pgs['pgrp1']['policy'])
97 mock_sg.assert_called_with('servergroup1', self.test_context,
98 sgs['servergroup1']['policy'])
99 self.assertEqual(len(self.test_context.placement_groups), 1)
100 self.assertEqual(len(self.test_context.server_groups), 1)
102 mock_network.assert_called_with(
103 'bar', self.test_context, networks['bar'])
104 self.assertEqual(len(self.test_context.networks), 1)
106 mock_server.assert_called_with('baz', self.test_context,
108 self.assertEqual(len(self.test_context.servers), 1)
110 mock_ssh_gen_keys.assert_called()
112 def test_init_no_name_or_task_id(self):
114 self.assertRaises(KeyError, self.test_context.init, attrs)
117 self.test_context._name = 'foo'
118 self.test_context._task_id = '1234567890'
119 self.test_context._name_task_id = '{}-{}'.format(
120 self.test_context._name, self.test_context._task_id[:8])
121 self.assertEqual(self.test_context.name, 'foo-12345678')
122 self.assertEqual(self.test_context.assigned_name, 'foo')
124 def test_name_flags(self):
125 self.test_context._flags = base.Flags(
126 **{"no_setup": True, "no_teardown": True})
127 self.test_context._name = 'foo'
128 self.test_context._task_id = '1234567890'
130 self.assertEqual(self.test_context.name, 'foo')
131 self.assertEqual(self.test_context.assigned_name, 'foo')
133 @mock.patch('yardstick.ssh.SSH.gen_keys')
134 def test_init_no_setup_no_teardown(self, *args):
136 attrs = {'name': 'foo',
137 'task_id': '1234567890',
138 'placement_groups': {},
148 self.test_context.init(attrs)
149 self.assertTrue(self.test_context._flags.no_setup)
150 self.assertTrue(self.test_context._flags.no_teardown)
152 @mock.patch('yardstick.benchmark.contexts.heat.HeatTemplate')
153 def test__add_resources_to_template_no_servers(self, mock_template):
154 self.test_context._name = 'ctx'
155 self.test_context._task_id = '1234567890'
156 self.test_context._name_task_id = '{}-{}'.format(
157 self.test_context._name, self.test_context._task_id[:8])
158 self.test_context.keypair_name = "ctx-key"
159 self.test_context.secgroup_name = "ctx-secgroup"
160 self.test_context.key_uuid = "2f2e4997-0a8e-4eb7-9fa4-f3f8fbbc393b"
161 netattrs = {'cidr': '10.0.0.0/24', 'provider': None,
162 'external_network': 'ext_net'}
164 self.test_context.networks = OrderedDict(
165 {"mynet": model.Network("mynet", self.test_context,
168 self.test_context._add_resources_to_template(mock_template)
169 mock_template.add_keypair.assert_called_with(
172 mock_template.add_security_group.assert_called_with("ctx-secgroup")
173 mock_template.add_network.assert_called_with(
174 "ctx-12345678-mynet", 'physnet1', None, None, None, None)
175 mock_template.add_router.assert_called_with(
176 "ctx-12345678-mynet-router",
177 netattrs["external_network"],
178 "ctx-12345678-mynet-subnet")
179 mock_template.add_router_interface.assert_called_with(
180 "ctx-12345678-mynet-router-if0",
181 "ctx-12345678-mynet-router",
182 "ctx-12345678-mynet-subnet")
184 @mock.patch('yardstick.benchmark.contexts.heat.HeatTemplate')
185 def test_attrs_get(self, *args):
186 image, flavor, user = expected_tuple = 'foo1', 'foo2', 'foo3'
187 self.assertNotEqual(self.test_context.image, image)
188 self.assertNotEqual(self.test_context.flavor, flavor)
189 self.assertNotEqual(self.test_context.user, user)
190 self.test_context._image = image
191 self.test_context._flavor = flavor
192 self.test_context._user = user
193 attr_tuple = self.test_context.image, self.test_context.flavor, self.test_context.user
194 self.assertEqual(attr_tuple, expected_tuple)
196 @mock.patch('yardstick.benchmark.contexts.heat.HeatTemplate')
197 def test_attrs_set_negative(self, *args):
198 with self.assertRaises(AttributeError):
199 self.test_context.image = 'foo'
201 with self.assertRaises(AttributeError):
202 self.test_context.flavor = 'foo'
204 with self.assertRaises(AttributeError):
205 self.test_context.user = 'foo'
207 def test__create_new_stack(self):
208 template = mock.Mock()
209 self.test_context._create_new_stack(template)
210 template.create.assert_called_once()
212 def test__create_new_stack_stack_create_failed(self):
213 template = mock.Mock()
214 template.create.side_effect = y_exc.HeatTemplateError
216 self.assertRaises(y_exc.HeatTemplateError,
217 self.test_context._create_new_stack,
220 def test__create_new_stack_keyboard_interrupt(self):
221 template = mock.Mock()
222 template.create.side_effect = KeyboardInterrupt
223 self.assertRaises(y_exc.StackCreationInterrupt,
224 self.test_context._create_new_stack,
227 @mock.patch.object(orch_heat.HeatTemplate, 'add_keypair')
228 @mock.patch.object(heat.HeatContext, '_create_new_stack')
229 def test_deploy_stack_creation_failed(self, mock_create, *args):
230 self.test_context._name = 'foo'
231 self.test_context._task_id = '1234567890'
232 self.test_context._name_task_id = 'foo-12345678'
233 mock_create.side_effect = y_exc.HeatTemplateError
234 self.assertRaises(y_exc.HeatTemplateError,
235 self.test_context.deploy)
237 @mock.patch('yardstick.benchmark.contexts.heat.HeatTemplate')
238 def test_deploy(self, mock_template):
239 self.test_context._name = 'foo'
240 self.test_context._task_id = '1234567890'
241 self.test_context._name_task_id = '{}-{}'.format(
242 self.test_context._name, self.test_context._task_id[:8])
243 self.test_context.template_file = '/bar/baz/some-heat-file'
244 self.test_context.heat_parameters = {'image': 'cirros'}
245 self.test_context.get_neutron_info = mock.MagicMock()
246 self.test_context.deploy()
248 mock_template.assert_called_with('foo-12345678',
249 '/bar/baz/some-heat-file',
251 self.assertIsNotNone(self.test_context.stack)
253 # TODO: patch objects
254 @mock.patch.object(heat, 'HeatTemplate')
255 @mock.patch.object(heat.HeatContext, '_retrieve_existing_stack')
256 @mock.patch.object(heat.HeatContext, '_create_new_stack')
257 def test_deploy_no_setup(self, mock_create_new_stack, mock_retrieve_existing_stack, *args):
258 self.test_context._name = 'foo'
259 self.test_context._task_id = '1234567890'
260 # Might be able to get rid of these
261 self.test_context.template_file = '/bar/baz/some-heat-file'
262 self.test_context.heat_parameters = {'image': 'cirros'}
263 self.test_context.get_neutron_info = mock.MagicMock()
264 self.test_context._flags.no_setup = True
265 self.test_context.deploy()
267 # check that heat client is called...
268 mock_create_new_stack.assert_not_called()
269 mock_retrieve_existing_stack.assert_called_with(self.test_context.name)
270 self.assertIsNotNone(self.test_context.stack)
272 @mock.patch.object(shade, 'openstack_cloud')
273 @mock.patch.object(heat.HeatTemplate, 'add_keypair')
274 @mock.patch.object(heat.HeatContext, '_create_new_stack')
275 @mock.patch.object(heat.HeatStack, 'get')
276 def test_deploy_try_retrieve_context_does_not_exist(self,
278 mock_create_new_stack,
280 self.test_context._name = 'demo'
281 self.test_context._task_id = '1234567890'
282 self.test_context._flags.no_setup = True
283 self.test_context.get_neutron_info = mock.MagicMock()
285 # TODo: Check is this the right value to return, should it be None instead?
286 mock_get_stack.return_value = []
288 self.test_context.deploy()
290 mock_get_stack.assert_called()
291 mock_create_new_stack.assert_called()
293 def test_check_for_context(self):
295 # check that the context exists
297 def test_add_server_port(self):
298 network1 = mock.MagicMock()
299 network2 = mock.MagicMock()
300 self.test_context._name = 'foo'
301 self.test_context._task_id = '1234567890'
302 self.test_context._name_task_id = '{}-{}'.format(
303 self.test_context._name, self.test_context._task_id[:8])
304 self.test_context.stack = mock.MagicMock()
305 self.test_context.networks = {
309 self.test_context.stack.outputs = {
310 u'b': u'10.20.30.45',
312 u'foo-12345678-a-subnet-cidr': u'10.20.0.0/15',
313 u'foo-12345678-a-subnet-gateway_ip': u'10.20.30.1',
314 u'b-mac_address': u'00:01',
315 u'b-device_id': u'dev21',
316 u'b-network_id': u'net789',
317 u'd': u'40.30.20.15',
319 u'foo-12345678-c-subnet-cidr': u'40.30.0.0/18',
320 u'foo-12345678-c-subnet-gateway_ip': u'40.30.20.254',
321 u'd-mac_address': u'00:10',
322 u'd-device_id': u'dev43',
323 u'd-network_id': u'net987',
324 u'e': u'40.30.20.15',
326 u'e-mac_address': u'00:10',
327 u'e-device_id': u'dev43',
328 u'e-network_id': u'net987',
330 server = mock.MagicMock()
331 server.ports = OrderedDict([
332 ('a', [{'stack_name': 'b', 'port': 'port_a'}]),
333 ('c', [{'stack_name': 'd', 'port': 'port_c'},
334 {'stack_name': 'e', 'port': 'port_f'}]),
338 "private_ip": '10.20.30.45',
340 "subnet_cidr": '10.20.0.0/15',
341 "network": '10.20.0.0',
342 "netmask": '255.254.0.0',
344 "gateway_ip": '10.20.30.1',
345 "mac_address": '00:01',
346 "device_id": 'dev21',
347 "network_id": 'net789',
349 "local_mac": '00:01',
350 "local_ip": '10.20.30.45',
352 self.test_context.add_server_port(server)
353 self.assertEqual(server.private_ip, '10.20.30.45')
354 self.assertEqual(len(server.interfaces), 3)
355 self.assertDictEqual(server.interfaces['port_a'], expected)
357 @mock.patch('yardstick.benchmark.contexts.heat.os')
358 @mock.patch('yardstick.benchmark.contexts.heat.HeatTemplate')
359 def test_undeploy(self, mock_template, *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 self.assertTrue(mock_template.delete.called)
370 @mock.patch('yardstick.benchmark.contexts.heat.HeatTemplate')
371 def test_undeploy_no_teardown(self, mock_template):
372 self.test_context.stack = mock_template
373 self.test_context._name = 'foo'
374 self.test_context._task_id = '1234567890'
375 self.test_context._flags.no_teardown = True
376 self.test_context.undeploy()
378 mock_template.delete.assert_not_called()
380 @mock.patch('yardstick.benchmark.contexts.heat.HeatTemplate')
381 @mock.patch('yardstick.benchmark.contexts.heat.os')
382 def test_undeploy_key_filename(self, mock_os, mock_template):
383 self.test_context.stack = mock_template
384 self.test_context._name = 'foo'
385 self.test_context._task_id = '1234567890'
386 self.test_context._name_task_id = '{}-{}'.format(
387 self.test_context._name, self.test_context._task_id)
388 mock_os.path.exists.return_value = True
389 self.test_context.key_filename = 'foo/bar/foobar'
390 self.assertIsNone(self.test_context.undeploy())
392 @mock.patch("yardstick.benchmark.contexts.heat.pkg_resources")
393 def test__get_server_found_dict(self, *args):
395 Use HeatContext._get_server to get a server that matches
396 based on a dictionary input.
398 foo2_server = mock.Mock()
399 foo2_server.key_filename = None
400 foo2_server.private_ip = '10.0.0.2'
401 foo2_server.public_ip = '127.0.0.2'
402 foo2_server.context.user = 'oof'
404 baz3_server = mock.Mock()
405 baz3_server.key_filename = None
406 baz3_server.private_ip = '10.0.0.3'
407 baz3_server.public_ip = '127.0.0.3'
408 baz3_server.context.user = 'zab'
410 self.test_context._name = 'bar'
411 self.test_context._task_id = '1234567890'
412 self.test_context._name_task_id = '{}-{}'.format(
413 self.test_context._name, self.test_context._task_id[:8])
414 self.test_context._user = 'bot'
415 self.test_context.stack = mock.Mock()
416 self.test_context.stack.outputs = {
417 'private_ip': '10.0.0.1',
418 'public_ip': '127.0.0.1',
420 self.test_context._server_map = {
426 'name': 'foo.bar-12345678',
427 'private_ip_attr': 'private_ip',
428 'public_ip_attr': 'public_ip',
430 self.test_context.key_uuid = 'foo-42'
431 result = self.test_context._get_server(attr_name)
432 self.assertEqual(result['user'], 'bot')
433 self.assertEqual(result['ip'], '127.0.0.1')
434 self.assertEqual(result['private_ip'], '10.0.0.1')
436 @mock.patch("yardstick.benchmark.contexts.heat.pkg_resources")
437 def test__get_server_found_dict_no_attrs(self, *args):
439 Use HeatContext._get_server to get a server that matches
440 based on a dictionary input.
442 foo2_server = mock.Mock()
443 foo2_server.private_ip = '10.0.0.2'
444 foo2_server.public_ip = '127.0.0.2'
445 foo2_server.context.user = 'oof'
447 baz3_server = mock.Mock()
448 baz3_server.private_ip = '10.0.0.3'
449 baz3_server.public_ip = '127.0.0.3'
450 baz3_server.context.user = 'zab'
452 self.test_context._name = 'bar'
453 self.test_context._task_id = '1234567890'
454 self.test_context._name_task_id = '{}-{}'.format(
455 self.test_context._name, self.test_context._task_id[:8])
456 self.test_context._user = 'bot'
457 self.test_context.stack = mock.Mock()
458 self.test_context.stack.outputs = {
459 'private_ip': '10.0.0.1',
460 'public_ip': '127.0.0.1',
462 self.test_context._server_map = {
468 'name': 'foo.bar-12345678',
471 self.test_context.key_uuid = 'foo-42'
472 result = self.test_context._get_server(attr_name)
473 self.assertEqual(result['user'], 'bot')
474 # no private ip attr mapping in the map results in None value in the result
475 self.assertIsNone(result['private_ip'])
476 # no public ip attr mapping in the map results in no value in the result
477 self.assertNotIn('ip', result)
479 @mock.patch("yardstick.benchmark.contexts.heat.pkg_resources")
480 def test__get_server_found_not_dict(self, *args):
482 Use HeatContext._get_server to get a server that matches
483 based on a non-dictionary input
485 foo2_server = mock.Mock()
486 foo2_server.private_ip = '10.0.0.2'
487 foo2_server.public_ip = '127.0.0.2'
488 foo2_server.context.user = 'oof'
490 baz3_server = mock.Mock()
491 baz3_server.private_ip = '10.0.0.3'
492 baz3_server.public_ip = None
493 baz3_server.context.user = 'zab'
495 self.test_context._name = 'bar1'
496 self.test_context._task_id = '1234567890'
497 self.test_context._name_task_id = 'bar1-12345678'
498 self.test_context.stack = mock.Mock()
499 self.test_context.stack.outputs = {
500 'private_ip': '10.0.0.1',
501 'public_ip': '127.0.0.1',
503 self.test_context.generate_routing_table = mock.MagicMock(return_value=[])
505 self.test_context._server_map = {
511 result = self.test_context._get_server(attr_name)
512 self.assertEqual(result['user'], 'zab')
513 self.assertEqual(result['private_ip'], '10.0.0.3')
514 # no public_ip on the server results in no value in the result
515 self.assertNotIn('public_ip', result)
517 @mock.patch("yardstick.benchmark.contexts.heat.pkg_resources")
518 def test__get_server_none_found_not_dict(self, *args):
520 Use HeatContext._get_server to not get a server due to
521 None value associated with the match to a non-dictionary
524 foo2_server = mock.Mock()
525 foo2_server.private_ip = '10.0.0.2'
526 foo2_server.public_ip = '127.0.0.2'
527 foo2_server.context.user = 'oof'
529 baz3_server = mock.Mock()
530 baz3_server.private_ip = '10.0.0.3'
531 baz3_server.public_ip = None
532 baz3_server.context.user = 'zab'
534 self.test_context._name = 'bar1'
535 self.test_context.stack = mock.Mock()
536 self.test_context.stack.outputs = {
537 'private_ip': '10.0.0.1',
538 'public_ip': '127.0.0.1',
540 self.test_context._server_map = {
546 self.test_context.key_uuid = 'foo-42'
548 result = self.test_context._get_server(attr_name)
549 self.assertIsNone(result)
551 @mock.patch("yardstick.benchmark.contexts.heat.pkg_resources")
552 def test__get_server_not_found_dict(self, *args):
554 Use HeatContext._get_server to not get a server for lack
555 of a match to a dictionary input
557 foo2_server = mock.Mock()
558 foo2_server.private_ip = '10.0.0.2'
559 foo2_server.public_ip = '127.0.0.2'
560 foo2_server.context.user = 'oof'
562 baz3_server = mock.Mock()
563 baz3_server.private_ip = '10.0.0.3'
564 baz3_server.public_ip = None
565 baz3_server.context.user = 'zab'
567 self.test_context._name = 'bar1'
568 self.test_context._task_id = '1235467890'
569 self.test_context._name_task_id = '{}-{}'.format(
570 self.test_context._name, self.test_context._task_id[:8])
571 self.test_context.stack = mock.Mock()
572 self.test_context.stack.outputs = {
573 'private_ip': '10.0.0.1',
574 'public_ip': '127.0.0.1',
576 self.test_context._server_map = {
581 self.test_context.key_uuid = 'foo-42'
584 'private_ip_attr': 'private_ip',
585 'public_ip_attr': 'public_ip',
587 result = self.test_context._get_server(attr_name)
588 self.assertIsNone(result)
590 @mock.patch("yardstick.benchmark.contexts.heat.pkg_resources")
591 def test__get_server_not_found_not_dict(self, *args):
593 Use HeatContext._get_server to not get a server for lack
594 of a match to a non-dictionary input
596 foo2_server = mock.Mock()
597 foo2_server.private_ip = '10.0.0.2'
598 foo2_server.public_ip = '127.0.0.2'
599 foo2_server.context.user = 'oof'
601 baz3_server = mock.Mock()
602 baz3_server.private_ip = '10.0.0.3'
603 baz3_server.public_ip = None
604 baz3_server.context.user = 'zab'
606 self.mock_context._name = 'bar1'
607 self.test_context.stack = mock.Mock()
608 self.mock_context.stack.outputs = {
609 'private_ip': '10.0.0.1',
610 'public_ip': '127.0.0.1',
612 self.mock_context._server_map = {
617 self.test_context.key_uuid = 'foo-42'
618 attr_name = 'foo.wow4'
619 result = self.test_context._get_server(attr_name)
620 self.assertIsNone(result)
622 # TODO: Split this into more granular tests
623 def test__get_network(self):
624 network1 = mock.MagicMock()
625 network1.name = 'net_1'
626 network1.vld_id = 'vld111'
627 network1.segmentation_id = 'seg54'
628 network1.network_type = 'type_a'
629 network1.physical_network = 'phys'
631 network2 = mock.MagicMock()
632 network2.name = 'net_2'
633 network2.segmentation_id = 'seg45'
634 network2.network_type = 'type_b'
635 network2.physical_network = 'virt'
637 self.test_context.networks = {
643 self.assertIsNone(self.test_context._get_network(attr_name))
646 self.assertIsNone(self.test_context._get_network(attr_name))
648 attr_name = {'network_type': 'nosuch'}
649 self.assertIsNone(self.test_context._get_network(attr_name))
652 self.assertIsNone(self.test_context._get_network(attr_name))
654 attr_name = {'segmentation_id': 'seg45'}
657 "segmentation_id": 'seg45',
658 "network_type": 'type_b',
659 "physical_network": 'virt',
661 result = self.test_context._get_network(attr_name)
662 self.assertDictEqual(result, expected)
667 "segmentation_id": 'seg54',
668 "network_type": 'type_a',
669 "physical_network": 'phys',
671 result = self.test_context._get_network(attr_name)
672 self.assertDictEqual(result, expected)