NFVBENCH-11 Cannot override extra_specs in flavor using -c
[nfvbench.git] / test / test_nfvbench.py
1 #!/usr/bin/env python
2 # Copyright 2016 Cisco Systems, Inc.  All rights reserved.
3 #
4 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
5 #    not use this file except in compliance with the License. You may obtain
6 #    a copy of the License at
7 #
8 #         http://www.apache.org/licenses/LICENSE-2.0
9 #
10 #    Unless required by applicable law or agreed to in writing, software
11 #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 #    License for the specific language governing permissions and limitations
14 #    under the License.
15 #
16
17 from attrdict import AttrDict
18 import logging
19 from nfvbench.config import config_loads
20 from nfvbench.connection import SSH
21 from nfvbench.credentials import Credentials
22 from nfvbench.fluentd import FluentLogHandler
23 import nfvbench.log
24 from nfvbench.network import Interface
25 from nfvbench.network import Network
26 from nfvbench.specs import Encaps
27 import nfvbench.traffic_gen.traffic_utils as traffic_utils
28 import os
29 import pytest
30
31 __location__ = os.path.realpath(os.path.join(os.getcwd(),
32                                              os.path.dirname(__file__)))
33
34
35 @pytest.fixture
36 def ssh(monkeypatch):
37     def mock_init(self, ssh_access, *args, **kwargs):
38         self.ssh_access = ssh_access
39         if ssh_access.private_key:
40             self.pkey = self._get_pkey(ssh_access.private_key)
41         else:
42             self.pkey = None
43         self._client = False
44         self.connect_timeout = 2
45         self.connect_retry_count = 1
46         self.connect_retry_wait_sec = 1
47         super(SSH, self).__init__()
48
49     monkeypatch.setattr(SSH, '__init__', mock_init)
50
51
52 @pytest.fixture
53 def openstack_vxlan_spec():
54     return AttrDict(
55         {
56             'openstack': AttrDict({
57                 'vswitch': "VTS",
58                 'encaps': Encaps.VxLAN}
59             ),
60             'run_spec': AttrDict({
61                 'use_vpp': True
62             })
63         }
64     )
65
66 # =========================================================================
67 # PVP Chain tests
68 # =========================================================================
69
70 def test_chain_interface():
71     iface = Interface('testname', 'vpp', tx_packets=1234, rx_packets=4321)
72     assert iface.name == 'testname'
73     assert iface.device == 'vpp'
74     assert iface.get_packet_count('tx') == 1234
75     assert iface.get_packet_count('rx') == 4321
76     assert iface.get_packet_count('wrong_key') == 0
77
78
79 @pytest.fixture(scope='session')
80 def iface1():
81     return Interface('iface1', 'trex', tx_packets=10000, rx_packets=1234)
82
83
84 @pytest.fixture(scope='session')
85 def iface2():
86     return Interface('iface2', 'n9k', tx_packets=1234, rx_packets=9901)
87
88
89 @pytest.fixture(scope='session')
90 def iface3():
91     return Interface('iface3', 'n9k', tx_packets=9900, rx_packets=1234)
92
93
94 @pytest.fixture(scope='session')
95 def iface4():
96     return Interface('iface4', 'vpp', tx_packets=1234, rx_packets=9801)
97
98
99 @pytest.fixture(scope='session')
100 def net1(iface1, iface2, iface3, iface4):
101     return Network([iface1, iface2, iface3, iface4], reverse=False)
102
103
104 @pytest.fixture(scope='session')
105 def net2(iface1, iface2, iface3):
106     return Network([iface1, iface2, iface3], reverse=True)
107
108
109 def test_chain_network(net1, net2, iface1, iface2, iface3, iface4):
110     assert [iface1, iface2, iface3, iface4] == net1.get_interfaces()
111     assert [iface3, iface2, iface1] == net2.get_interfaces()
112     net2.add_interface(iface4)
113     assert [iface4, iface3, iface2, iface1] == net2.get_interfaces()
114
115
116 """
117 def test_chain_analysis(net1, monkeypatch, openstack_vxlan_spec):
118     def mock_empty(self, *args, **kwargs):
119         pass
120
121     monkeypatch.setattr(ServiceChain, '_setup', mock_empty)
122
123     f = ServiceChain(AttrDict({'service_chain': 'DUMMY'}), [], {'tor': {}}, openstack_vxlan_spec,
124                      lambda x, y, z: None)
125     result = f.get_analysis([net1])
126     assert result[1]['packet_drop_count'] == 99
127     assert result[1]['packet_drop_percentage'] == 0.99
128     assert result[2]['packet_drop_count'] == 1
129     assert result[2]['packet_drop_percentage'] == 0.01
130     assert result[3]['packet_drop_count'] == 99
131     assert result[3]['packet_drop_percentage'] == 0.99
132
133     net1.reverse = True
134     result = f.get_analysis([net1])
135     assert result[1]['packet_drop_count'] == 0
136     assert result[1]['packet_drop_percentage'] == 0.0
137     assert result[2]['packet_drop_count'] == 0
138     assert result[2]['packet_drop_percentage'] == 0.0
139     assert result[3]['packet_drop_count'] == 0
140     assert result[3]['packet_drop_percentage'] == 0.0
141
142
143 @pytest.fixture
144 def pvp_chain(monkeypatch, openstack_vxlan_spec):
145     tor_vni1 = Interface('vni-4097', 'n9k', 50, 77)
146     vsw_vni1 = Interface('vxlan_tunnel0', 'vpp', 77, 48)
147     vsw_vif1 = Interface('VirtualEthernet0/0/2', 'vpp', 48, 77)
148     vsw_vif2 = Interface('VirtualEthernet0/0/3', 'vpp', 77, 47)
149     vsw_vni2 = Interface('vxlan_tunnel1', 'vpp', 43, 77)
150     tor_vni2 = Interface('vni-4098', 'n9k', 77, 40)
151
152     def mock_init(self, *args, **kwargs):
153         self.vni_ports = [4097, 4098]
154         self.specs = openstack_vxlan_spec
155         self.clients = {
156             'vpp': AttrDict({
157                 'set_interface_counters': lambda: None,
158             })
159         }
160         self.worker = AttrDict({
161             'run': lambda: None,
162         })
163
164     def mock_empty(self, *args, **kwargs):
165         pass
166
167     def mock_get_network(self, traffic_port, vni_id, reverse=False):
168         if vni_id == 0:
169             return Network([tor_vni1, vsw_vni1, vsw_vif1], reverse)
170         else:
171             return Network([tor_vni2, vsw_vni2, vsw_vif2], reverse)
172
173     def mock_get_data(self):
174         return {}
175
176     monkeypatch.setattr(PVPChain, '_get_network', mock_get_network)
177     monkeypatch.setattr(PVPChain, '_get_data', mock_get_data)
178     monkeypatch.setattr(PVPChain, '_setup', mock_empty)
179     monkeypatch.setattr(VxLANWorker, '_clear_interfaces', mock_empty)
180     monkeypatch.setattr(PVPChain, '_generate_traffic', mock_empty)
181     monkeypatch.setattr(PVPChain, '__init__', mock_init)
182     return PVPChain(None, None, {'vm': None, 'vpp': None, 'tor': None, 'traffic': None}, None)
183
184
185 def test_pvp_chain_run(pvp_chain):
186     result = pvp_chain.run()
187     expected_result = {
188         'raw_data': {},
189         'stats': None,
190         'packet_analysis': {
191             'direction-forward': [
192                 OrderedDict([
193                     ('interface', 'vni-4097'),
194                     ('device', 'n9k'),
195                     ('packet_count', 50)
196                 ]),
197                 OrderedDict([
198                     ('interface', 'vxlan_tunnel0'),
199                     ('device', 'vpp'),
200                     ('packet_count', 48),
201                     ('packet_drop_count', 2),
202                     ('packet_drop_percentage', 4.0)
203                 ]),
204                 OrderedDict([
205                     ('interface', 'VirtualEthernet0/0/2'),
206                     ('device', 'vpp'),
207                     ('packet_count', 48),
208                     ('packet_drop_count', 0),
209                     ('packet_drop_percentage', 0.0)
210                 ]),
211                 OrderedDict([
212                     ('interface', 'VirtualEthernet0/0/3'),
213                     ('device', 'vpp'),
214                     ('packet_count', 47),
215                     ('packet_drop_count', 1),
216                     ('packet_drop_percentage', 2.0)
217                 ]),
218                 OrderedDict([
219                     ('interface', 'vxlan_tunnel1'),
220                     ('device', 'vpp'),
221                     ('packet_count', 43),
222                     ('packet_drop_count', 4),
223                     ('packet_drop_percentage', 8.0)
224                 ]),
225                 OrderedDict([
226                     ('interface', 'vni-4098'),
227                     ('device', 'n9k'),
228                     ('packet_count', 40),
229                     ('packet_drop_count', 3),
230                     ('packet_drop_percentage', 6.0)
231                 ])
232             ],
233             'direction-reverse': [
234                 OrderedDict([
235                     ('interface', 'vni-4098'),
236                     ('device', 'n9k'),
237                     ('packet_count', 77)
238                 ]),
239                 OrderedDict([
240                     ('interface', 'vxlan_tunnel1'),
241                     ('device', 'vpp'),
242                     ('packet_count', 77),
243                     ('packet_drop_count', 0),
244                     ('packet_drop_percentage', 0.0)
245                 ]),
246                 OrderedDict([
247                     ('interface', 'VirtualEthernet0/0/3'),
248                     ('device', 'vpp'),
249                     ('packet_count', 77),
250                     ('packet_drop_count', 0),
251                     ('packet_drop_percentage', 0.0)
252                 ]),
253                 OrderedDict([
254                     ('interface', 'VirtualEthernet0/0/2'),
255                     ('device', 'vpp'),
256                     ('packet_count', 77),
257                     ('packet_drop_count', 0),
258                     ('packet_drop_percentage', 0.0)
259                 ]),
260                 OrderedDict([
261                     ('interface', 'vxlan_tunnel0'),
262                     ('device', 'vpp'),
263                     ('packet_count', 77),
264                     ('packet_drop_count', 0),
265                     ('packet_drop_percentage', 0.0)
266                 ]),
267                 OrderedDict([
268                     ('interface', 'vni-4097'),
269                     ('device', 'n9k'),
270                     ('packet_count', 77),
271                     ('packet_drop_count', 0),
272                     ('packet_drop_percentage', 0.0)
273                 ])
274             ]
275         }
276     }
277     assert result == expected_result
278 """
279
280
281 # =========================================================================
282 # PVVP Chain tests
283 # =========================================================================
284
285 """
286 @pytest.fixture
287 def pvvp_chain(monkeypatch, openstack_vxlan_spec):
288     tor_vni1 = Interface('vni-4097', 'n9k', 50, 77)
289     vsw_vni1 = Interface('vxlan_tunnel0', 'vpp', 77, 48)
290     vsw_vif1 = Interface('VirtualEthernet0/0/2', 'vpp', 48, 77)
291     vsw_vif3 = Interface('VirtualEthernet0/0/0', 'vpp', 77, 47)
292     vsw_vif4 = Interface('VirtualEthernet0/0/1', 'vpp', 45, 77)
293     vsw_vif2 = Interface('VirtualEthernet0/0/3', 'vpp', 77, 44)
294     vsw_vni2 = Interface('vxlan_tunnel1', 'vpp', 43, 77)
295     tor_vni2 = Interface('vni-4098', 'n9k', 77, 40)
296
297     def mock_init(self, *args, **kwargs):
298         self.vni_ports = [4099, 4100]
299         self.v2vnet = V2VNetwork()
300         self.specs = openstack_vxlan_spec
301         self.clients = {
302             'vpp': AttrDict({
303                 'get_v2v_network': lambda reverse=None: Network([vsw_vif3, vsw_vif4], reverse),
304                 'set_interface_counters': lambda pvvp=None: None,
305                 'set_v2v_counters': lambda: None,
306             })
307         }
308         self.worker = AttrDict({
309             'run': lambda: None,
310         })
311
312     def mock_empty(self, *args, **kwargs):
313         pass
314
315     def mock_get_network(self, traffic_port, vni_id, reverse=False):
316         if vni_id == 0:
317             return Network([tor_vni1, vsw_vni1, vsw_vif1], reverse)
318         else:
319             return Network([tor_vni2, vsw_vni2, vsw_vif2], reverse)
320
321     def mock_get_data(self):
322         return {}
323
324     monkeypatch.setattr(PVVPChain, '_get_network', mock_get_network)
325     monkeypatch.setattr(PVVPChain, '_get_data', mock_get_data)
326     monkeypatch.setattr(PVVPChain, '_setup', mock_empty)
327     monkeypatch.setattr(VxLANWorker, '_clear_interfaces', mock_empty)
328     monkeypatch.setattr(PVVPChain, '_generate_traffic', mock_empty)
329     monkeypatch.setattr(PVVPChain, '__init__', mock_init)
330
331     return PVVPChain(None, None, {'vm': None, 'vpp': None, 'tor': None, 'traffic': None}, None)
332
333
334 def test_pvvp_chain_run(pvvp_chain):
335     result = pvvp_chain.run()
336
337     expected_result = {
338         'raw_data': {},
339         'stats': None,
340         'packet_analysis':
341             {'direction-forward': [
342                 OrderedDict([
343                     ('interface', 'vni-4097'),
344                     ('device', 'n9k'),
345                     ('packet_count', 50)
346                 ]),
347                 OrderedDict([
348                     ('interface', 'vxlan_tunnel0'),
349                     ('device', 'vpp'),
350                     ('packet_count', 48),
351                     ('packet_drop_count', 2),
352                     ('packet_drop_percentage', 4.0)
353                 ]),
354                 OrderedDict([
355                     ('interface', 'VirtualEthernet0/0/2'),
356                     ('device', 'vpp'),
357                     ('packet_count', 48),
358                     ('packet_drop_count', 0),
359                     ('packet_drop_percentage', 0.0)
360                 ]),
361                 OrderedDict([
362                     ('interface', 'VirtualEthernet0/0/0'),
363                     ('device', 'vpp'),
364                     ('packet_count', 47),
365                     ('packet_drop_count', 1),
366                     ('packet_drop_percentage', 2.0)
367                 ]),
368                 OrderedDict([
369                     ('interface', 'VirtualEthernet0/0/1'),
370                     ('device', 'vpp'),
371                     ('packet_count', 45),
372                     ('packet_drop_count', 2),
373                     ('packet_drop_percentage', 4.0)
374                 ]),
375                 OrderedDict([
376                     ('interface', 'VirtualEthernet0/0/3'),
377                     ('device', 'vpp'),
378                     ('packet_count', 44),
379                     ('packet_drop_count', 1),
380                     ('packet_drop_percentage', 2.0)
381                 ]),
382                 OrderedDict([
383                     ('interface', 'vxlan_tunnel1'),
384                     ('device', 'vpp'),
385                     ('packet_count', 43),
386                     ('packet_drop_count', 1),
387                     ('packet_drop_percentage', 2.0)
388                 ]),
389                 OrderedDict([
390                     ('interface', 'vni-4098'),
391                     ('device', 'n9k'),
392                     ('packet_count', 40),
393                     ('packet_drop_count', 3),
394                     ('packet_drop_percentage', 6.0)
395                 ])
396             ],
397             'direction-reverse': [
398                 OrderedDict([
399                     ('interface', 'vni-4098'),
400                     ('device', 'n9k'),
401                     ('packet_count', 77)
402                 ]),
403                 OrderedDict([
404                     ('interface', 'vxlan_tunnel1'),
405                     ('device', 'vpp'),
406                     ('packet_count', 77),
407                     ('packet_drop_count', 0),
408                     ('packet_drop_percentage', 0.0)
409                 ]),
410                 OrderedDict([
411                     ('interface', 'VirtualEthernet0/0/3'),
412                     ('device', 'vpp'),
413                     ('packet_count', 77),
414                     ('packet_drop_count', 0),
415                     ('packet_drop_percentage', 0.0)
416                 ]),
417                 OrderedDict([
418                     ('interface', 'VirtualEthernet0/0/1'),
419                     ('device', 'vpp'),
420                     ('packet_count', 77),
421                     ('packet_drop_count', 0),
422                     ('packet_drop_percentage', 0.0)
423                 ]),
424                 OrderedDict([
425                     ('interface', 'VirtualEthernet0/0/0'),
426                     ('device', 'vpp'),
427                     ('packet_count', 77),
428                     ('packet_drop_count', 0),
429                     ('packet_drop_percentage', 0.0)
430                 ]),
431                 OrderedDict([
432                     ('interface', 'VirtualEthernet0/0/2'),
433                     ('device', 'vpp'),
434                     ('packet_count', 77),
435                     ('packet_drop_count', 0),
436                     ('packet_drop_percentage', 0.0)
437                 ]),
438                 OrderedDict([
439                     ('interface', 'vxlan_tunnel0'),
440                     ('device', 'vpp'),
441                     ('packet_count', 77),
442                     ('packet_drop_count', 0),
443                     ('packet_drop_percentage', 0.0)
444                 ]),
445                 OrderedDict([
446                     ('interface', 'vni-4097'),
447                     ('device', 'n9k'),
448                     ('packet_count', 77),
449                     ('packet_drop_count', 0),
450                     ('packet_drop_percentage', 0.0)
451                 ])
452             ]}
453     }
454     assert result == expected_result
455 """
456
457 # =========================================================================
458 # Traffic client tests
459 # =========================================================================
460
461 def test_parse_rate_str():
462     parse_rate_str = traffic_utils.parse_rate_str
463     try:
464         assert parse_rate_str('100%') == {'rate_percent': '100.0'}
465         assert parse_rate_str('37.5%') == {'rate_percent': '37.5'}
466         assert parse_rate_str('100%') == {'rate_percent': '100.0'}
467         assert parse_rate_str('60pps') == {'rate_pps': '60'}
468         assert parse_rate_str('60kpps') == {'rate_pps': '60000'}
469         assert parse_rate_str('6Mpps') == {'rate_pps': '6000000'}
470         assert parse_rate_str('6gpps') == {'rate_pps': '6000000000'}
471         assert parse_rate_str('80bps') == {'rate_bps': '80'}
472         assert parse_rate_str('80bps') == {'rate_bps': '80'}
473         assert parse_rate_str('80kbps') == {'rate_bps': '80000'}
474         assert parse_rate_str('80kBps') == {'rate_bps': '640000'}
475         assert parse_rate_str('80Mbps') == {'rate_bps': '80000000'}
476         assert parse_rate_str('80 MBps') == {'rate_bps': '640000000'}
477         assert parse_rate_str('80Gbps') == {'rate_bps': '80000000000'}
478     except Exception as exc:
479         assert False, exc.message
480
481     def should_raise_error(str):
482         try:
483             parse_rate_str(str)
484         except Exception:
485             return True
486         else:
487             assert False
488
489     assert should_raise_error('101')
490     assert should_raise_error('201%')
491     assert should_raise_error('10Kbps')
492     assert should_raise_error('0kbps')
493     assert should_raise_error('0pps')
494     assert should_raise_error('-1bps')
495
496 def test_rate_conversion():
497     assert traffic_utils.load_to_bps(50, 10000000000) == pytest.approx(5000000000.0)
498     assert traffic_utils.load_to_bps(37, 10000000000) == pytest.approx(3700000000.0)
499     assert traffic_utils.load_to_bps(100, 10000000000) == pytest.approx(10000000000.0)
500
501     assert traffic_utils.bps_to_load(5000000000.0, 10000000000) == pytest.approx(50.0)
502     assert traffic_utils.bps_to_load(3700000000.0, 10000000000) == pytest.approx(37.0)
503     assert traffic_utils.bps_to_load(10000000000.0, 10000000000) == pytest.approx(100.0)
504
505     assert traffic_utils.bps_to_pps(500000, 64) == pytest.approx(744.047619048)
506     assert traffic_utils.bps_to_pps(388888, 1518) == pytest.approx(31.6066319896)
507     assert traffic_utils.bps_to_pps(9298322222, 340.3) == pytest.approx(3225895.85831)
508
509     assert traffic_utils.pps_to_bps(744.047619048, 64) == pytest.approx(500000)
510     assert traffic_utils.pps_to_bps(31.6066319896, 1518) == pytest.approx(388888)
511     assert traffic_utils.pps_to_bps(3225895.85831, 340.3) == pytest.approx(9298322222)
512
513
514 """
515 @pytest.fixture
516 def traffic_client(monkeypatch):
517
518     def mock_init(self, *args, **kwargs):
519         self.run_config = {
520             'bidirectional': False,
521             'l2frame_size': '64',
522             'duration_sec': 30,
523             'rates': [{'rate_percent': '10'}, {'rate_pps': '1'}]
524         }
525
526         self.config = AttrDict({
527             'generator_config': {
528                 'intf_speed': 10000000000
529             },
530             'ndr_run': True,
531             'pdr_run': True,
532             'single_run': False,
533             'attempts': 1,
534             'measurement': {
535                 'NDR': 0.0,
536                 'PDR': 0.1,
537                 'load_epsilon': 0.1
538             }
539         })
540
541         self.runner = AttrDict({
542             'time_elapsed': lambda: 30,
543             'stop': lambda: None,
544             'client': AttrDict({'get_stats': lambda: None})
545         })
546
547         self.current_load = None
548         self.dummy_stats = {
549             50.0: 72.6433562831,
550             25.0: 45.6095059858,
551             12.5: 0.0,
552             18.75: 27.218642979,
553             15.625: 12.68585861,
554             14.0625: 2.47154392563,
555             13.28125: 0.000663797066801,
556             12.890625: 0.0,
557             13.0859375: 0.0,
558             13.18359375: 0.00359387347122,
559             13.671875: 0.307939922531,
560             13.4765625: 0.0207718516156,
561             13.57421875: 0.0661795060969
562         }
563
564     def mock_modify_load(self, load):
565         self.run_config['rates'][0] = {'rate_percent': str(load)}
566         self.current_load = load
567
568     def mock_run_traffic(self):
569         yield {
570             'overall': {
571                 'drop_rate_percent': self.dummy_stats[self.current_load],
572                 'rx': {
573                     'total_pkts': 1,
574                     'avg_delay_usec': 0.0,
575                     'max_delay_usec': 0.0,
576                     'min_delay_usec': 0.0
577                 }
578             }
579         }
580
581     monkeypatch.setattr(TrafficClient, '__init__', mock_init)
582     monkeypatch.setattr(TrafficClient, 'modify_load', mock_modify_load)
583     monkeypatch.setattr(TrafficClient, 'run_traffic', mock_run_traffic)
584
585     return TrafficClient()
586
587
588 def test_ndr_pdr_search(traffic_client):
589     expected_results = {
590         'pdr': {
591             'l2frame_size': '64',
592             'initial_rate_type': 'rate_percent',
593             'stats': {
594                 'overall': {
595                     'drop_rate_percent': 0.0661795060969,
596                     'min_delay_usec': 0.0,
597                     'avg_delay_usec': 0.0,
598                     'max_delay_usec': 0.0
599                 }
600             },
601             'load_percent_per_direction': 13.57421875,
602             'rate_percent': 13.57422547,
603             'rate_bps': 1357422547.0,
604             'rate_pps': 2019974.0282738095,
605             'duration_sec': 30
606         },
607         'ndr': {
608             'l2frame_size': '64',
609             'initial_rate_type': 'rate_percent',
610             'stats': {
611                 'overall': {
612                     'drop_rate_percent': 0.0,
613                     'min_delay_usec': 0.0,
614                     'avg_delay_usec': 0.0,
615                     'max_delay_usec': 0.0
616                 }
617             },
618             'load_percent_per_direction': 13.0859375,
619             'rate_percent': 13.08594422,
620             'rate_bps': 1308594422.0,
621             'rate_pps': 1947313.1279761905,
622             'duration_sec': 30
623         }
624     }
625
626     results = traffic_client.get_ndr_and_pdr()
627     assert len(results) == 2
628     for result in results.values():
629         result.pop('timestamp_sec')
630         result.pop('time_taken_sec')
631     assert results == expected_results
632 """
633
634 # =========================================================================
635 # Other tests
636 # =========================================================================
637
638 def setup_module(module):
639     nfvbench.log.setup(mute_stdout=True)
640
641 def test_no_credentials():
642     cred = Credentials('/completely/wrong/path/openrc', None, False)
643     if cred.rc_auth_url:
644         # shouldn't get valid data unless user set environment variables
645         assert False
646     else:
647         assert True
648
649 def test_config():
650     refcfg = {1: 100, 2: {21: 100, 22: 200}, 3: None}
651     res1 = {1: 10, 2: {21: 100, 22: 200}, 3: None}
652     res2 = {1: 100, 2: {21: 1000, 22: 200}, 3: None}
653     res3 = {1: 100, 2: {21: 100, 22: 200}, 3: "abc"}
654     assert(config_loads("{}", refcfg) == refcfg)
655     assert(config_loads("{1: 10}", refcfg) == res1)
656     assert(config_loads("{2: {21: 1000}}", refcfg) == res2)
657     assert(config_loads('{3: "abc"}', refcfg) == res3)
658
659     # correctly fails
660     # pairs of input string and expected subset (None if identical)
661     fail_pairs = [
662         ["{4: 0}", None],
663         ["{2: {21: 100, 30: 50}}", "{2: {30: 50}}"],
664         ["{2: {0: 1, 1: 2}, 5: 5}", None],
665         ["{1: 'abc', 2: {21: 0}}", "{1: 'abc'}"],
666         ["{2: 100}", None]
667     ]
668     for fail_pair in fail_pairs:
669         with pytest.raises(Exception) as e_info:
670             config_loads(fail_pair[0], refcfg)
671         expected = fail_pair[1]
672         if expected is None:
673             expected = fail_pair[0]
674         assert expected in e_info.value.message
675
676     # whitelist keys
677     flavor = {'flavor': {'vcpus': 2, 'ram': 8192, 'disk': 0,
678               'extra_specs': {'hw:cpu_policy': 'dedicated'}}}
679     new_flavor = {'flavor': {'vcpus': 2, 'ram': 8192, 'disk': 0,
680                   'extra_specs': {'hw:cpu_policy': 'dedicated', 'hw:numa_nodes': 2}}}
681     assert(config_loads("{'flavor': {'extra_specs': {'hw:numa_nodes': 2}}}", flavor,
682                         whitelist_keys=['alpha', 'extra_specs']) == new_flavor)
683
684 def test_fluentd():
685     logger = logging.getLogger('fluent-logger')
686     handler = FluentLogHandler('nfvbench', fluentd_port=7081)
687     logger.addHandler(handler)
688     logger.setLevel(logging.INFO)
689     logger.info('test')
690     logger.warning('test %d', 100)
691     try:
692         raise Exception("test")
693     except Exception:
694         logger.exception("got exception")