Merge "Fix report generation"
[yardstick.git] / yardstick / tests / unit / benchmark / contexts / test_model.py
1 ##############################################################################
2 # Copyright (c) 2015 Ericsson AB and others.
3 #
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 ##############################################################################
9
10 # Unittest for yardstick.benchmark.contexts.model
11
12 from __future__ import absolute_import
13 import unittest
14 import mock
15
16 from yardstick.benchmark.contexts import model
17
18
19 class ObjectTestCase(unittest.TestCase):
20
21     def setUp(self):
22         self.mock_context = mock.Mock()
23
24     def test_construct(self):
25
26         test_object = model.Object('foo', self.mock_context)
27
28         self.assertEqual(test_object.name, 'foo')
29         self.assertEqual(test_object._context, self.mock_context)
30         self.assertIsNone(test_object.stack_name)
31         self.assertIsNone(test_object.stack_id)
32
33     def test_dn(self):
34
35         self.mock_context.name = 'bar'
36         test_object = model.Object('foo', self.mock_context)
37
38         self.assertEqual('foo.bar', test_object.dn)
39
40
41 class PlacementGroupTestCase(unittest.TestCase):
42
43     def setUp(self):
44         self.mock_context = mock.Mock()
45         self.mock_context.name = 'bar'
46
47     def tearDown(self):
48         model.PlacementGroup.map = {}
49
50     def test_sucessful_construct(self):
51
52         test_pg = model.PlacementGroup('foo', self.mock_context, 'affinity')
53
54         self.assertEqual(test_pg.name, 'foo')
55         self.assertEqual(test_pg.members, set())
56         self.assertEqual(test_pg.stack_name, 'bar-foo')
57         self.assertEqual(test_pg.policy, 'affinity')
58
59         test_map = {'foo': test_pg}
60         self.assertEqual(model.PlacementGroup.map, test_map)
61
62     def test_wrong_policy_in_construct(self):
63
64         self.assertRaises(ValueError, model.PlacementGroup, 'foo',
65                           self.mock_context, 'baz')
66
67     def test_add_member(self):
68
69         test_pg = model.PlacementGroup('foo', self.mock_context, 'affinity')
70         test_pg.add_member('foo')
71
72         self.assertEqual(test_pg.members, set(['foo']))
73
74     def test_get_name_successful(self):
75
76         model.PlacementGroup.map = {'foo': True}
77         self.assertTrue(model.PlacementGroup.get('foo'))
78
79     def test_get_name_unsuccessful(self):
80
81         self.assertIsNone(model.PlacementGroup.get('foo'))
82
83
84 class RouterTestCase(unittest.TestCase):
85
86     def test_construct(self):
87
88         mock_context = mock.Mock()
89         mock_context.name = 'baz'
90         test_router = model.Router('foo', 'bar', mock_context, 'qux')
91
92         self.assertEqual(test_router.stack_name, 'baz-bar-foo')
93         self.assertEqual(test_router.stack_if_name, 'baz-bar-foo-if0')
94         self.assertEqual(test_router.external_gateway_info, 'qux')
95
96
97 class NetworkTestCase(unittest.TestCase):
98
99     def setUp(self):
100         self.mock_context = mock.Mock()
101         self.mock_context.name = 'bar'
102
103     def tearDown(self):
104         model.Network.list = []
105
106     def test_construct_no_external_network(self):
107
108         attrs = {'cidr': '10.0.0.0/24'}
109         test_network = model.Network('foo', self.mock_context, attrs)
110
111         self.assertEqual(test_network.stack_name, 'bar-foo')
112         self.assertEqual(test_network.subnet_stack_name, 'bar-foo-subnet')
113         self.assertEqual(test_network.subnet_cidr, attrs['cidr'])
114         self.assertIsNone(test_network.router)
115         self.assertIn(test_network, model.Network.list)
116
117     def test_construct_has_external_network(self):
118
119         attrs = {'external_network': 'ext_net'}
120         test_network = model.Network('foo', self.mock_context, attrs)
121         exp_router = model.Router('router', 'foo', self.mock_context,
122                                   'ext_net')
123
124         self.assertEqual(test_network.router.stack_name, exp_router.stack_name)
125         self.assertEqual(test_network.router.stack_if_name,
126                          exp_router.stack_if_name)
127         self.assertEqual(test_network.router.external_gateway_info,
128                          exp_router.external_gateway_info)
129
130     def test_has_route_to(self):
131
132         attrs = {'external_network': 'ext_net'}
133         test_network = model.Network('foo', self.mock_context, attrs)
134
135         self.assertTrue(test_network.has_route_to('ext_net'))
136
137     def test_has_no_route_to(self):
138
139         attrs = {}
140         test_network = model.Network('foo', self.mock_context, attrs)
141
142         self.assertFalse(test_network.has_route_to('ext_net'))
143
144     @mock.patch('yardstick.benchmark.contexts.model.Network.has_route_to')
145     def test_find_by_route_to(self, mock_has_route_to):
146
147         mock_network = mock.Mock()
148         model.Network.list = [mock_network]
149         mock_has_route_to.return_value = True
150
151         self.assertIs(mock_network, model.Network.find_by_route_to('foo'))
152
153     def test_find_external_network(self):
154
155         mock_network = mock.Mock()
156         mock_network.router = mock.Mock() #pylint ignore assignment-from-none
157         mock_network.router.external_gateway_info = 'ext_net'
158         model.Network.list = [mock_network]
159
160         self.assertEqual(model.Network.find_external_network(), 'ext_net')
161
162     def test_construct_gateway_ip_is_null(self):
163
164         attrs = {'gateway_ip': 'null'}
165         test_network = model.Network('foo', self.mock_context, attrs)
166         self.assertEqual(test_network.gateway_ip, 'null')
167
168     def test_construct_gateway_ip_is_none(self):
169
170         attrs = {'gateway_ip': None}
171         test_network = model.Network('foo', self.mock_context, attrs)
172         self.assertEqual(test_network.gateway_ip, 'null')
173
174     def test_construct_gateway_ip_is_absent(self):
175
176         attrs = {}
177         test_network = model.Network('foo', self.mock_context, attrs)
178         self.assertIsNone(test_network.gateway_ip)
179
180
181 class ServerTestCase(unittest.TestCase):
182
183     def setUp(self):
184         self.mock_context = mock.Mock()
185         self.mock_context.name = 'bar'
186         self.mock_context.keypair_name = 'some-keys'
187         self.mock_context.secgroup_name = 'some-secgroup'
188         self.mock_context.user = "some-user"
189         netattrs = {'cidr': '10.0.0.0/24', 'provider': None, 'external_network': 'ext_net'}
190         self.mock_context.networks = [model.Network("some-network", self.mock_context, netattrs)]
191
192     def test_construct_defaults(self):
193
194         attrs = None
195         test_server = model.Server('foo', self.mock_context, attrs)
196
197         self.assertEqual(test_server.stack_name, 'foo.bar')
198         self.assertEqual(test_server.keypair_name, 'some-keys')
199         self.assertEqual(test_server.secgroup_name, 'some-secgroup')
200         self.assertEqual(test_server.placement_groups, [])
201         self.assertIsNone(test_server.server_group)
202         self.assertEqual(test_server.instances, 1)
203         self.assertIsNone(test_server.floating_ip)
204         self.assertIsNone(test_server._image)
205         self.assertIsNone(test_server._flavor)
206         self.assertIn(test_server, model.Server.list)
207
208     @mock.patch('yardstick.benchmark.contexts.model.PlacementGroup')
209     def test_construct_get_wrong_placement_group(self, mock_pg):
210
211         attrs = {'placement': 'baz'}
212         mock_pg.get.return_value = None
213
214         self.assertRaises(ValueError, model.Server, 'foo',
215                           self.mock_context, attrs)
216
217     @mock.patch('yardstick.benchmark.contexts.model.PlacementGroup')
218     def test_construct_get_wrong_server_group(self, mock_sg):
219
220         attrs = {'server_group': 'baz'}
221         mock_sg.get.return_value = None
222
223         self.assertRaises(ValueError, model.Server, 'foo',
224                           self.mock_context, attrs)
225
226     @mock.patch('yardstick.benchmark.contexts.heat.HeatTemplate')
227     def test__add_instance(self, mock_template):
228         attrs = {'image': 'some-image', 'flavor': 'some-flavor', 'floating_ip': '192.168.1.10',
229                  'floating_ip_assoc': 'some-vm',
230                  'availability_zone': 'zone'}
231         test_server = model.Server('foo', self.mock_context, attrs)
232
233         self.mock_context.flavors = ['flavor1', 'flavor2', 'some-flavor']
234
235         mock_network = mock.Mock()
236         mock_network.name = 'some-network'
237         mock_network.stack_name = 'some-network-stack'
238         mock_network.allowed_address_pairs = ["1", "2"]
239         mock_network.vnic_type = 'normal'
240         mock_network.subnet_stack_name = 'some-network-stack-subnet'
241         mock_network.provider = 'sriov'
242         mock_network.external_network = 'ext_net'
243         mock_network.router = model.Router('some-router', 'some-network', self.mock_context,
244                                            'ext_net')
245
246         test_server._add_instance(mock_template, 'some-server',
247                                   [mock_network], 'hints')
248
249         mock_template.add_port.assert_called_with(
250             'some-server-some-network-port',
251             mock_network.stack_name,
252             mock_network.subnet_stack_name,
253             mock_network.vnic_type,
254             sec_group_id=self.mock_context.secgroup_name,
255             provider=mock_network.provider,
256             allowed_address_pairs=mock_network.allowed_address_pairs)
257
258         mock_template.add_floating_ip.assert_called_with(
259             'some-server-fip',
260             mock_network.external_network,
261             'some-server-some-network-port',
262             'bar-some-network-some-router-if0',
263             'some-secgroup'
264         )
265
266         mock_template.add_floating_ip_association.assert_called_with(
267             'some-server-fip-assoc',
268             'some-server-fip',
269             'some-server-some-network-port'
270         )
271
272         mock_template.add_server.assert_called_with(
273             'some-server', 'some-image',
274             flavor='some-flavor',
275             flavors=['flavor1', 'flavor2', 'some-flavor'],
276             ports=['some-server-some-network-port'],
277             user=self.mock_context.user,
278             key_name=self.mock_context.keypair_name,
279             user_data='',
280             scheduler_hints='hints',
281             availability_zone='zone')
282
283     def test_override_ip(self):
284         network_ports = {
285             'mgmt': ['mgmt'],
286             'uplink_0': [
287                 {'xe0': {'local_ip': '10.44.0.20', 'netmask': '255.255.255.0'}},
288             ],
289             'downlink_0': [
290                 {'xe1': {'local_ip': '10.44.0.30', 'netmask': '255.255.255.0'}},
291             ],
292         }
293         attrs = {
294             'image': 'some-image', 'flavor': 'some-flavor',
295         }
296         test_server = model.Server('foo', self.mock_context, attrs)
297         test_server.interfaces = {
298             "xe0": {
299                 "local_ip": "1.2.3.4",
300                 "netmask": "255.255.255.0",
301             },
302             "xe1": {
303                 "local_ip": "1.2.3.5",
304                 "netmask": "255.255.255.0"
305             }
306         }
307         test_server.network_ports = network_ports
308
309         test_server.override_ip("uplink_0", {"port": "xe0"})
310         self.assertEqual(test_server.interfaces["xe0"], network_ports["uplink_0"][0]["xe0"])
311
312     def test_override_ip_multiple(self):
313         network_ports = {
314             'mgmt': ['mgmt'],
315             'uplink_0': [
316                 {'xe0': {'local_ip': '10.44.0.20', 'netmask': '255.255.255.0'}},
317                 {'xe0': {'local_ip': '10.44.0.21', 'netmask': '255.255.255.0'}},
318             ],
319             'downlink_0': [
320                 {'xe1': {'local_ip': '10.44.0.30', 'netmask': '255.255.255.0'}},
321             ],
322         }
323         attrs = {
324             'image': 'some-image', 'flavor': 'some-flavor',
325         }
326         test_server = model.Server('foo', self.mock_context, attrs)
327         test_server.interfaces = {
328             "xe0": {
329                 "local_ip": "1.2.3.4",
330                 "netmask": "255.255.255.0",
331             },
332             "xe1": {
333                 "local_ip": "1.2.3.5",
334                 "netmask": "255.255.255.0"
335             }
336         }
337         test_server.network_ports = network_ports
338         test_server.override_ip("uplink_0", {"port": "xe0"})
339         self.assertEqual(test_server.interfaces["xe0"], network_ports["uplink_0"][0]["xe0"])
340
341     def test_override_ip_mixed(self):
342         network_ports = {
343             'mgmt': ['mgmt'],
344             'uplink_0': [
345                 'xe0',
346                 {'xe0': {'local_ip': '10.44.0.21', 'netmask': '255.255.255.0'}},
347             ],
348             'downlink_0': [
349                 {'xe1': {'local_ip': '10.44.0.30', 'netmask': '255.255.255.0'}},
350             ],
351         }
352         attrs = {
353             'image': 'some-image', 'flavor': 'some-flavor',
354         }
355         test_server = model.Server('foo', self.mock_context, attrs)
356         test_server.interfaces = {
357             "xe0": {
358                 "local_ip": "1.2.3.4",
359                 "netmask": "255.255.255.0",
360             },
361             "xe1": {
362                 "local_ip": "1.2.3.5",
363                 "netmask": "255.255.255.0"
364             }
365         }
366         test_server.network_ports = network_ports
367         test_server.override_ip("uplink_0", {"port": "xe0"})
368         self.assertEqual(test_server.interfaces["xe0"], network_ports["uplink_0"][1]["xe0"])
369
370     @mock.patch('yardstick.benchmark.contexts.heat.HeatTemplate')
371     def test__add_instance_with_ip_override_invalid_syntax(self, mock_template):
372         network_ports = {
373             'mgmt': ['mgmt'],
374             'uplink_0': 'xe0',
375             'downlink_0': [
376                 {'xe1': {'local_ip': '10.44.0.30', 'netmask': '255.255.255.0'}},
377             ],
378         }
379         attrs = {
380             'image': 'some-image', 'flavor': 'some-flavor',
381         }
382         test_server = model.Server('foo', self.mock_context, attrs)
383         test_server.network_ports = network_ports
384         context = type("Context", (object,), {})
385         # can't use Mock because Mock.name is reserved
386         context.name = "context"
387         networks = [model.Network(n, context, {}) for n in network_ports]
388
389         with self.assertRaises(SyntaxError):
390             test_server._add_instance(mock_template, 'some-server',
391                                       networks, 'hints')
392
393     @mock.patch('yardstick.benchmark.contexts.heat.HeatTemplate')
394     def test__add_instance_with_ip_override(self, mock_template):
395         network_ports = {
396             'mgmt': ['mgmt'],
397             'uplink_0': [
398                 {'xe0': {'local_ip': '10.44.0.20', 'netmask': '255.255.255.0'}},
399             ],
400             'downlink_0': [
401                 {'xe1': {'local_ip': '10.44.0.30', 'netmask': '255.255.255.0'}},
402             ],
403         }
404         attrs = {
405             'image': 'some-image', 'flavor': 'some-flavor',
406         }
407         test_server = model.Server('foo', self.mock_context, attrs)
408         test_server.network_ports = network_ports
409         context = type("Context", (object,), {})
410         # can't use Mock because Mock.name is reserved
411         context.name = "context"
412         networks = [model.Network(n, context, {}) for n in network_ports]
413
414         test_server._add_instance(mock_template, 'some-server',
415                                   networks, 'hints')
416         self.assertEqual(test_server.ports, {
417             'downlink_0': [{'port': 'xe1', 'stack_name': 'some-server-xe1-port'}],
418             'mgmt': [{'port': 'mgmt', 'stack_name': 'some-server-mgmt-port'}],
419             'uplink_0': [{'port': 'xe0', 'stack_name': 'some-server-xe0-port'}]
420         })
421
422     @mock.patch('yardstick.benchmark.contexts.heat.HeatTemplate')
423     def test__add_instance_with_multiple_ip_override(self, mock_template):
424         network_ports = {
425             'mgmt': ['mgmt'],
426             'uplink_0': [
427                 {'xe0': {'local_ip': '10.44.0.20', 'netmask': '255.255.255.0'}},
428                 {'xe0': {'local_ip': '10.44.0.21', 'netmask': '255.255.255.0'}},
429             ],
430             'downlink_0': [
431                 {'xe1': {'local_ip': '10.44.0.30', 'netmask': '255.255.255.0'}},
432             ],
433         }
434         attrs = {
435             'image': 'some-image', 'flavor': 'some-flavor',
436         }
437         test_server = model.Server('foo', self.mock_context, attrs)
438         test_server.network_ports = network_ports
439         context = type("Context", (object,), {})
440         # can't use Mock because Mock.name is reserved
441         context.name = "context"
442         networks = [model.Network(n, context, {}) for n in network_ports]
443
444         test_server._add_instance(mock_template, 'some-server',
445                                   networks, 'hints')
446         self.assertEqual(test_server.ports, {
447             'downlink_0': [{'port': 'xe1', 'stack_name': 'some-server-xe1-port'}],
448             'mgmt': [{'port': 'mgmt', 'stack_name': 'some-server-mgmt-port'}],
449             'uplink_0': [{'port': 'xe0', 'stack_name': 'some-server-xe0-port'},
450                          # this is not an error, we can produce this, it is left to Heat
451                          # to detect duplicate ports and error
452                          {'port': 'xe0', 'stack_name': 'some-server-xe0-port'}]
453         })
454
455     @mock.patch('yardstick.benchmark.contexts.heat.HeatTemplate')
456     def test__add_instance_with_user_data(self, mock_template):
457         user_data = "USER_DATA"
458         attrs = {
459             'image': 'some-image', 'flavor': 'some-flavor',
460             'user_data': user_data,
461         }
462         test_server = model.Server('foo', self.mock_context, attrs)
463
464         test_server._add_instance(mock_template, 'some-server',
465                                   [], 'hints')
466
467         mock_template.add_server.assert_called_with(
468             'some-server', 'some-image',
469             flavor='some-flavor',
470             flavors=self.mock_context.flavors,
471             ports=[],
472             user=self.mock_context.user,
473             key_name=self.mock_context.keypair_name,
474             user_data=user_data,
475             scheduler_hints='hints',
476             availability_zone=None)
477
478     @mock.patch('yardstick.benchmark.contexts.heat.HeatTemplate')
479     def test__add_instance_with_availablity_zone(self, mock_template):
480         attrs = {
481             'image': 'some-image', 'flavor': 'some-flavor',
482             'availability_zone': 'zone',
483         }
484         test_server = model.Server('foo', self.mock_context, attrs)
485
486         test_server._add_instance(mock_template, 'some-server',
487                                   [], 'hints')
488
489         mock_template.add_server.assert_called_with(
490             'some-server', 'some-image',
491             flavor='some-flavor',
492             flavors=self.mock_context.flavors,
493             ports=[],
494             user=self.mock_context.user,
495             key_name=self.mock_context.keypair_name,
496             user_data='',
497             scheduler_hints='hints',
498             availability_zone='zone')
499
500     @mock.patch('yardstick.benchmark.contexts.heat.HeatTemplate')
501     def test__add_instance_plus_flavor(self, mock_template):
502
503         user_data = ''
504         attrs = {
505             'image': 'some-image', 'flavor': 'flavor1',
506             'flavors': ['flavor2'], 'user_data': user_data
507         }
508         test_server = model.Server('ServerFlavor-2', self.mock_context, attrs)
509
510         self.mock_context.flavors = ['flavor2']
511         mock_network = mock.Mock()
512         mock_network.allowed_address_pairs = ["1", "2"]
513         mock_network.vnic_type = 'normal'
514         mock_network.configure_mock(name='some-network', stack_name='some-network-stack',
515                                     subnet_stack_name='some-network-stack-subnet',
516                                     provider='some-provider')
517
518         test_server._add_instance(mock_template, 'ServerFlavor-2',
519                                   [mock_network], 'hints')
520
521         mock_template.add_port.assert_called_with(
522             'ServerFlavor-2-some-network-port',
523             mock_network.stack_name,
524             mock_network.subnet_stack_name,
525             mock_network.vnic_type,
526             provider=mock_network.provider,
527             sec_group_id=self.mock_context.secgroup_name,
528             allowed_address_pairs=mock_network.allowed_address_pairs)
529
530         mock_template.add_server.assert_called_with(
531             'ServerFlavor-2', 'some-image',
532             flavor='flavor1',
533             flavors=['flavor2'],
534             ports=['ServerFlavor-2-some-network-port'],
535             user=self.mock_context.user,
536             key_name=self.mock_context.keypair_name,
537             user_data=user_data,
538             scheduler_hints='hints',
539             availability_zone=None)
540
541     @mock.patch('yardstick.benchmark.contexts.heat.HeatTemplate')
542     def test__add_instance_misc(self, mock_template):
543
544         user_data = ''
545         attrs = {
546             'image': 'some-image', 'flavor': 'flavor1',
547             'flavors': ['flavor2'], 'user_data': user_data
548         }
549         test_server = model.Server('ServerFlavor-3', self.mock_context, attrs)
550
551         self.mock_context.flavors = ['flavor2']
552         self.mock_context.flavor = {'vcpus': 4}
553         mock_network = mock.Mock()
554         mock_network.name = 'some-network'
555         mock_network.stack_name = 'some-network-stack'
556         mock_network.subnet_stack_name = 'some-network-stack-subnet'
557
558         test_server._add_instance(mock_template, 'ServerFlavor-3',
559                                   [mock_network], 'hints')
560
561         mock_template.add_port(
562             'ServerFlavor-3-some-network-port',
563             mock_network.stack_name,
564             mock_network.subnet_stack_name,
565             sec_group_id=self.mock_context.secgroup_name)
566
567         mock_template.add_flavor(
568             vcpus=4,
569             ram=2048,
570             disk=1)
571
572         mock_template.add_flavor(
573             vcpus=4,
574             ram=2048,
575             disk=1,
576             extra_specs={'cat': 1, 'dog': 2, 'dragon': 1000})
577
578         mock_template.add_server.assert_called_with(
579             'ServerFlavor-3', 'some-image',
580             flavor='flavor1',
581             flavors=['flavor2'],
582             ports=['ServerFlavor-3-some-network-port'],
583             user=self.mock_context.user,
584             key_name=self.mock_context.keypair_name,
585             user_data=user_data,
586             scheduler_hints='hints',
587             availability_zone=None)