NFVBENCH-40 Add pylint to tox
[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 import logging
18 import os
19 import sys
20
21 from attrdict import AttrDict
22 from nfvbench.config import config_loads
23 from nfvbench.credentials import Credentials
24 from nfvbench.fluentd import FluentLogHandler
25 import nfvbench.log
26 from nfvbench.network import Interface
27 from nfvbench.network import Network
28 from nfvbench.specs import ChainType
29 from nfvbench.specs import Encaps
30 import nfvbench.traffic_gen.traffic_utils as traffic_utils
31 import pytest
32
33 __location__ = os.path.realpath(os.path.join(os.getcwd(),
34                                              os.path.dirname(__file__)))
35
36
37 @pytest.fixture
38 def openstack_vxlan_spec():
39     return AttrDict(
40         {
41             'openstack': AttrDict({
42                 'vswitch': "VTS",
43                 'encaps': Encaps.VxLAN}),
44             'run_spec': AttrDict({
45                 'use_vpp': True
46             })
47         }
48     )
49
50
51 # =========================================================================
52 # PVP Chain tests
53 # =========================================================================
54
55 def test_chain_interface():
56     iface = Interface('testname', 'vpp', tx_packets=1234, rx_packets=4321)
57     assert iface.name == 'testname'
58     assert iface.device == 'vpp'
59     assert iface.get_packet_count('tx') == 1234
60     assert iface.get_packet_count('rx') == 4321
61     assert iface.get_packet_count('wrong_key') == 0
62
63
64 # pylint: disable=redefined-outer-name
65 @pytest.fixture(scope='session')
66 def iface1():
67     return Interface('iface1', 'trex', tx_packets=10000, rx_packets=1234)
68
69
70 @pytest.fixture(scope='session')
71 def iface2():
72     return Interface('iface2', 'n9k', tx_packets=1234, rx_packets=9901)
73
74
75 @pytest.fixture(scope='session')
76 def iface3():
77     return Interface('iface3', 'n9k', tx_packets=9900, rx_packets=1234)
78
79
80 @pytest.fixture(scope='session')
81 def iface4():
82     return Interface('iface4', 'vpp', tx_packets=1234, rx_packets=9801)
83
84
85 @pytest.fixture(scope='session')
86 def net1(iface1, iface2, iface3, iface4):
87     return Network([iface1, iface2, iface3, iface4], reverse=False)
88
89
90 @pytest.fixture(scope='session')
91 def net2(iface1, iface2, iface3):
92     return Network([iface1, iface2, iface3], reverse=True)
93
94
95 def test_chain_network(net1, net2, iface1, iface2, iface3, iface4):
96     assert [iface1, iface2, iface3, iface4] == net1.get_interfaces()
97     assert [iface3, iface2, iface1] == net2.get_interfaces()
98     net2.add_interface(iface4)
99     assert [iface4, iface3, iface2, iface1] == net2.get_interfaces()
100
101
102 # pylint: enable=redefined-outer-name
103
104 # pylint: disable=pointless-string-statement
105 """
106 def test_chain_analysis(net1, monkeypatch, openstack_vxlan_spec):
107     def mock_empty(self, *args, **kwargs):
108         pass
109
110     monkeypatch.setattr(ServiceChain, '_setup', mock_empty)
111
112     f = ServiceChain(AttrDict({'service_chain': 'DUMMY'}), [], {'tor': {}}, openstack_vxlan_spec,
113                      lambda x, y, z: None)
114     result = f.get_analysis([net1])
115     assert result[1]['packet_drop_count'] == 99
116     assert result[1]['packet_drop_percentage'] == 0.99
117     assert result[2]['packet_drop_count'] == 1
118     assert result[2]['packet_drop_percentage'] == 0.01
119     assert result[3]['packet_drop_count'] == 99
120     assert result[3]['packet_drop_percentage'] == 0.99
121
122     net1.reverse = True
123     result = f.get_analysis([net1])
124     assert result[1]['packet_drop_count'] == 0
125     assert result[1]['packet_drop_percentage'] == 0.0
126     assert result[2]['packet_drop_count'] == 0
127     assert result[2]['packet_drop_percentage'] == 0.0
128     assert result[3]['packet_drop_count'] == 0
129     assert result[3]['packet_drop_percentage'] == 0.0
130
131
132 @pytest.fixture
133 def pvp_chain(monkeypatch, openstack_vxlan_spec):
134     tor_vni1 = Interface('vni-4097', 'n9k', 50, 77)
135     vsw_vni1 = Interface('vxlan_tunnel0', 'vpp', 77, 48)
136     vsw_vif1 = Interface('VirtualEthernet0/0/2', 'vpp', 48, 77)
137     vsw_vif2 = Interface('VirtualEthernet0/0/3', 'vpp', 77, 47)
138     vsw_vni2 = Interface('vxlan_tunnel1', 'vpp', 43, 77)
139     tor_vni2 = Interface('vni-4098', 'n9k', 77, 40)
140
141     def mock_init(self, *args, **kwargs):
142         self.vni_ports = [4097, 4098]
143         self.specs = openstack_vxlan_spec
144         self.clients = {
145             'vpp': AttrDict({
146                 'set_interface_counters': lambda: None,
147             })
148         }
149         self.worker = AttrDict({
150             'run': lambda: None,
151         })
152
153     def mock_empty(self, *args, **kwargs):
154         pass
155
156     def mock_get_network(self, traffic_port, vni_id, reverse=False):
157         if vni_id == 0:
158             return Network([tor_vni1, vsw_vni1, vsw_vif1], reverse)
159         else:
160             return Network([tor_vni2, vsw_vni2, vsw_vif2], reverse)
161
162     def mock_get_data(self):
163         return {}
164
165     monkeypatch.setattr(PVPChain, '_get_network', mock_get_network)
166     monkeypatch.setattr(PVPChain, '_get_data', mock_get_data)
167     monkeypatch.setattr(PVPChain, '_setup', mock_empty)
168     monkeypatch.setattr(VxLANWorker, '_clear_interfaces', mock_empty)
169     monkeypatch.setattr(PVPChain, '_generate_traffic', mock_empty)
170     monkeypatch.setattr(PVPChain, '__init__', mock_init)
171     return PVPChain(None, None, {'vm': None, 'vpp': None, 'tor': None, 'traffic': None}, None)
172
173
174 def test_pvp_chain_run(pvp_chain):
175     result = pvp_chain.run()
176     expected_result = {
177         'raw_data': {},
178         'stats': None,
179         'packet_analysis': {
180             'direction-forward': [
181                 OrderedDict([
182                     ('interface', 'vni-4097'),
183                     ('device', 'n9k'),
184                     ('packet_count', 50)
185                 ]),
186                 OrderedDict([
187                     ('interface', 'vxlan_tunnel0'),
188                     ('device', 'vpp'),
189                     ('packet_count', 48),
190                     ('packet_drop_count', 2),
191                     ('packet_drop_percentage', 4.0)
192                 ]),
193                 OrderedDict([
194                     ('interface', 'VirtualEthernet0/0/2'),
195                     ('device', 'vpp'),
196                     ('packet_count', 48),
197                     ('packet_drop_count', 0),
198                     ('packet_drop_percentage', 0.0)
199                 ]),
200                 OrderedDict([
201                     ('interface', 'VirtualEthernet0/0/3'),
202                     ('device', 'vpp'),
203                     ('packet_count', 47),
204                     ('packet_drop_count', 1),
205                     ('packet_drop_percentage', 2.0)
206                 ]),
207                 OrderedDict([
208                     ('interface', 'vxlan_tunnel1'),
209                     ('device', 'vpp'),
210                     ('packet_count', 43),
211                     ('packet_drop_count', 4),
212                     ('packet_drop_percentage', 8.0)
213                 ]),
214                 OrderedDict([
215                     ('interface', 'vni-4098'),
216                     ('device', 'n9k'),
217                     ('packet_count', 40),
218                     ('packet_drop_count', 3),
219                     ('packet_drop_percentage', 6.0)
220                 ])
221             ],
222             'direction-reverse': [
223                 OrderedDict([
224                     ('interface', 'vni-4098'),
225                     ('device', 'n9k'),
226                     ('packet_count', 77)
227                 ]),
228                 OrderedDict([
229                     ('interface', 'vxlan_tunnel1'),
230                     ('device', 'vpp'),
231                     ('packet_count', 77),
232                     ('packet_drop_count', 0),
233                     ('packet_drop_percentage', 0.0)
234                 ]),
235                 OrderedDict([
236                     ('interface', 'VirtualEthernet0/0/3'),
237                     ('device', 'vpp'),
238                     ('packet_count', 77),
239                     ('packet_drop_count', 0),
240                     ('packet_drop_percentage', 0.0)
241                 ]),
242                 OrderedDict([
243                     ('interface', 'VirtualEthernet0/0/2'),
244                     ('device', 'vpp'),
245                     ('packet_count', 77),
246                     ('packet_drop_count', 0),
247                     ('packet_drop_percentage', 0.0)
248                 ]),
249                 OrderedDict([
250                     ('interface', 'vxlan_tunnel0'),
251                     ('device', 'vpp'),
252                     ('packet_count', 77),
253                     ('packet_drop_count', 0),
254                     ('packet_drop_percentage', 0.0)
255                 ]),
256                 OrderedDict([
257                     ('interface', 'vni-4097'),
258                     ('device', 'n9k'),
259                     ('packet_count', 77),
260                     ('packet_drop_count', 0),
261                     ('packet_drop_percentage', 0.0)
262                 ])
263             ]
264         }
265     }
266     assert result == expected_result
267 """
268
269 # =========================================================================
270 # PVVP Chain tests
271 # =========================================================================
272
273 """
274 @pytest.fixture
275 def pvvp_chain(monkeypatch, openstack_vxlan_spec):
276     tor_vni1 = Interface('vni-4097', 'n9k', 50, 77)
277     vsw_vni1 = Interface('vxlan_tunnel0', 'vpp', 77, 48)
278     vsw_vif1 = Interface('VirtualEthernet0/0/2', 'vpp', 48, 77)
279     vsw_vif3 = Interface('VirtualEthernet0/0/0', 'vpp', 77, 47)
280     vsw_vif4 = Interface('VirtualEthernet0/0/1', 'vpp', 45, 77)
281     vsw_vif2 = Interface('VirtualEthernet0/0/3', 'vpp', 77, 44)
282     vsw_vni2 = Interface('vxlan_tunnel1', 'vpp', 43, 77)
283     tor_vni2 = Interface('vni-4098', 'n9k', 77, 40)
284
285     def mock_init(self, *args, **kwargs):
286         self.vni_ports = [4099, 4100]
287         self.v2vnet = V2VNetwork()
288         self.specs = openstack_vxlan_spec
289         self.clients = {
290             'vpp': AttrDict({
291                 'get_v2v_network': lambda reverse=None: Network([vsw_vif3, vsw_vif4], reverse),
292                 'set_interface_counters': lambda pvvp=None: None,
293                 'set_v2v_counters': lambda: None,
294             })
295         }
296         self.worker = AttrDict({
297             'run': lambda: None,
298         })
299
300     def mock_empty(self, *args, **kwargs):
301         pass
302
303     def mock_get_network(self, traffic_port, vni_id, reverse=False):
304         if vni_id == 0:
305             return Network([tor_vni1, vsw_vni1, vsw_vif1], reverse)
306         else:
307             return Network([tor_vni2, vsw_vni2, vsw_vif2], reverse)
308
309     def mock_get_data(self):
310         return {}
311
312     monkeypatch.setattr(PVVPChain, '_get_network', mock_get_network)
313     monkeypatch.setattr(PVVPChain, '_get_data', mock_get_data)
314     monkeypatch.setattr(PVVPChain, '_setup', mock_empty)
315     monkeypatch.setattr(VxLANWorker, '_clear_interfaces', mock_empty)
316     monkeypatch.setattr(PVVPChain, '_generate_traffic', mock_empty)
317     monkeypatch.setattr(PVVPChain, '__init__', mock_init)
318
319     return PVVPChain(None, None, {'vm': None, 'vpp': None, 'tor': None, 'traffic': None}, None)
320
321
322 def test_pvvp_chain_run(pvvp_chain):
323     result = pvvp_chain.run()
324
325     expected_result = {
326         'raw_data': {},
327         'stats': None,
328         'packet_analysis':
329             {'direction-forward': [
330                 OrderedDict([
331                     ('interface', 'vni-4097'),
332                     ('device', 'n9k'),
333                     ('packet_count', 50)
334                 ]),
335                 OrderedDict([
336                     ('interface', 'vxlan_tunnel0'),
337                     ('device', 'vpp'),
338                     ('packet_count', 48),
339                     ('packet_drop_count', 2),
340                     ('packet_drop_percentage', 4.0)
341                 ]),
342                 OrderedDict([
343                     ('interface', 'VirtualEthernet0/0/2'),
344                     ('device', 'vpp'),
345                     ('packet_count', 48),
346                     ('packet_drop_count', 0),
347                     ('packet_drop_percentage', 0.0)
348                 ]),
349                 OrderedDict([
350                     ('interface', 'VirtualEthernet0/0/0'),
351                     ('device', 'vpp'),
352                     ('packet_count', 47),
353                     ('packet_drop_count', 1),
354                     ('packet_drop_percentage', 2.0)
355                 ]),
356                 OrderedDict([
357                     ('interface', 'VirtualEthernet0/0/1'),
358                     ('device', 'vpp'),
359                     ('packet_count', 45),
360                     ('packet_drop_count', 2),
361                     ('packet_drop_percentage', 4.0)
362                 ]),
363                 OrderedDict([
364                     ('interface', 'VirtualEthernet0/0/3'),
365                     ('device', 'vpp'),
366                     ('packet_count', 44),
367                     ('packet_drop_count', 1),
368                     ('packet_drop_percentage', 2.0)
369                 ]),
370                 OrderedDict([
371                     ('interface', 'vxlan_tunnel1'),
372                     ('device', 'vpp'),
373                     ('packet_count', 43),
374                     ('packet_drop_count', 1),
375                     ('packet_drop_percentage', 2.0)
376                 ]),
377                 OrderedDict([
378                     ('interface', 'vni-4098'),
379                     ('device', 'n9k'),
380                     ('packet_count', 40),
381                     ('packet_drop_count', 3),
382                     ('packet_drop_percentage', 6.0)
383                 ])
384             ],
385             'direction-reverse': [
386                 OrderedDict([
387                     ('interface', 'vni-4098'),
388                     ('device', 'n9k'),
389                     ('packet_count', 77)
390                 ]),
391                 OrderedDict([
392                     ('interface', 'vxlan_tunnel1'),
393                     ('device', 'vpp'),
394                     ('packet_count', 77),
395                     ('packet_drop_count', 0),
396                     ('packet_drop_percentage', 0.0)
397                 ]),
398                 OrderedDict([
399                     ('interface', 'VirtualEthernet0/0/3'),
400                     ('device', 'vpp'),
401                     ('packet_count', 77),
402                     ('packet_drop_count', 0),
403                     ('packet_drop_percentage', 0.0)
404                 ]),
405                 OrderedDict([
406                     ('interface', 'VirtualEthernet0/0/1'),
407                     ('device', 'vpp'),
408                     ('packet_count', 77),
409                     ('packet_drop_count', 0),
410                     ('packet_drop_percentage', 0.0)
411                 ]),
412                 OrderedDict([
413                     ('interface', 'VirtualEthernet0/0/0'),
414                     ('device', 'vpp'),
415                     ('packet_count', 77),
416                     ('packet_drop_count', 0),
417                     ('packet_drop_percentage', 0.0)
418                 ]),
419                 OrderedDict([
420                     ('interface', 'VirtualEthernet0/0/2'),
421                     ('device', 'vpp'),
422                     ('packet_count', 77),
423                     ('packet_drop_count', 0),
424                     ('packet_drop_percentage', 0.0)
425                 ]),
426                 OrderedDict([
427                     ('interface', 'vxlan_tunnel0'),
428                     ('device', 'vpp'),
429                     ('packet_count', 77),
430                     ('packet_drop_count', 0),
431                     ('packet_drop_percentage', 0.0)
432                 ]),
433                 OrderedDict([
434                     ('interface', 'vni-4097'),
435                     ('device', 'n9k'),
436                     ('packet_count', 77),
437                     ('packet_drop_count', 0),
438                     ('packet_drop_percentage', 0.0)
439                 ])
440             ]}
441     }
442     assert result == expected_result
443 """
444
445
446 # =========================================================================
447 # Traffic client tests
448 # =========================================================================
449
450 def test_parse_rate_str():
451     parse_rate_str = traffic_utils.parse_rate_str
452     try:
453         assert parse_rate_str('100%') == {'rate_percent': '100.0'}
454         assert parse_rate_str('37.5%') == {'rate_percent': '37.5'}
455         assert parse_rate_str('100%') == {'rate_percent': '100.0'}
456         assert parse_rate_str('60pps') == {'rate_pps': '60'}
457         assert parse_rate_str('60kpps') == {'rate_pps': '60000'}
458         assert parse_rate_str('6Mpps') == {'rate_pps': '6000000'}
459         assert parse_rate_str('6gpps') == {'rate_pps': '6000000000'}
460         assert parse_rate_str('80bps') == {'rate_bps': '80'}
461         assert parse_rate_str('80bps') == {'rate_bps': '80'}
462         assert parse_rate_str('80kbps') == {'rate_bps': '80000'}
463         assert parse_rate_str('80kBps') == {'rate_bps': '640000'}
464         assert parse_rate_str('80Mbps') == {'rate_bps': '80000000'}
465         assert parse_rate_str('80 MBps') == {'rate_bps': '640000000'}
466         assert parse_rate_str('80Gbps') == {'rate_bps': '80000000000'}
467     except Exception as exc:
468         assert False, exc.message
469
470     def should_raise_error(str):
471         try:
472             parse_rate_str(str)
473         except Exception:
474             return True
475         else:
476             assert False
477
478     assert should_raise_error('101')
479     assert should_raise_error('201%')
480     assert should_raise_error('10Kbps')
481     assert should_raise_error('0kbps')
482     assert should_raise_error('0pps')
483     assert should_raise_error('-1bps')
484
485
486 def test_rate_conversion():
487     assert traffic_utils.load_to_bps(50, 10000000000) == pytest.approx(5000000000.0)
488     assert traffic_utils.load_to_bps(37, 10000000000) == pytest.approx(3700000000.0)
489     assert traffic_utils.load_to_bps(100, 10000000000) == pytest.approx(10000000000.0)
490
491     assert traffic_utils.bps_to_load(5000000000.0, 10000000000) == pytest.approx(50.0)
492     assert traffic_utils.bps_to_load(3700000000.0, 10000000000) == pytest.approx(37.0)
493     assert traffic_utils.bps_to_load(10000000000.0, 10000000000) == pytest.approx(100.0)
494
495     assert traffic_utils.bps_to_pps(500000, 64) == pytest.approx(744.047619048)
496     assert traffic_utils.bps_to_pps(388888, 1518) == pytest.approx(31.6066319896)
497     assert traffic_utils.bps_to_pps(9298322222, 340.3) == pytest.approx(3225895.85831)
498
499     assert traffic_utils.pps_to_bps(744.047619048, 64) == pytest.approx(500000)
500     assert traffic_utils.pps_to_bps(31.6066319896, 1518) == pytest.approx(388888)
501     assert traffic_utils.pps_to_bps(3225895.85831, 340.3) == pytest.approx(9298322222)
502
503
504 """
505 @pytest.fixture
506 def traffic_client(monkeypatch):
507
508     def mock_init(self, *args, **kwargs):
509         self.run_config = {
510             'bidirectional': False,
511             'l2frame_size': '64',
512             'duration_sec': 30,
513             'rates': [{'rate_percent': '10'}, {'rate_pps': '1'}]
514         }
515
516         self.config = AttrDict({
517             'generator_config': {
518                 'intf_speed': 10000000000
519             },
520             'ndr_run': True,
521             'pdr_run': True,
522             'single_run': False,
523             'attempts': 1,
524             'measurement': {
525                 'NDR': 0.0,
526                 'PDR': 0.1,
527                 'load_epsilon': 0.1
528             }
529         })
530
531         self.runner = AttrDict({
532             'time_elapsed': lambda: 30,
533             'stop': lambda: None,
534             'client': AttrDict({'get_stats': lambda: None})
535         })
536
537         self.current_load = None
538         self.dummy_stats = {
539             50.0: 72.6433562831,
540             25.0: 45.6095059858,
541             12.5: 0.0,
542             18.75: 27.218642979,
543             15.625: 12.68585861,
544             14.0625: 2.47154392563,
545             13.28125: 0.000663797066801,
546             12.890625: 0.0,
547             13.0859375: 0.0,
548             13.18359375: 0.00359387347122,
549             13.671875: 0.307939922531,
550             13.4765625: 0.0207718516156,
551             13.57421875: 0.0661795060969
552         }
553
554     def mock_modify_load(self, load):
555         self.run_config['rates'][0] = {'rate_percent': str(load)}
556         self.current_load = load
557
558     def mock_run_traffic(self):
559         yield {
560             'overall': {
561                 'drop_rate_percent': self.dummy_stats[self.current_load],
562                 'rx': {
563                     'total_pkts': 1,
564                     'avg_delay_usec': 0.0,
565                     'max_delay_usec': 0.0,
566                     'min_delay_usec': 0.0
567                 }
568             }
569         }
570
571     monkeypatch.setattr(TrafficClient, '__init__', mock_init)
572     monkeypatch.setattr(TrafficClient, 'modify_load', mock_modify_load)
573     monkeypatch.setattr(TrafficClient, 'run_traffic', mock_run_traffic)
574
575     return TrafficClient()
576
577
578 def test_ndr_pdr_search(traffic_client):
579     expected_results = {
580         'pdr': {
581             'l2frame_size': '64',
582             'initial_rate_type': 'rate_percent',
583             'stats': {
584                 'overall': {
585                     'drop_rate_percent': 0.0661795060969,
586                     'min_delay_usec': 0.0,
587                     'avg_delay_usec': 0.0,
588                     'max_delay_usec': 0.0
589                 }
590             },
591             'load_percent_per_direction': 13.57421875,
592             'rate_percent': 13.57422547,
593             'rate_bps': 1357422547.0,
594             'rate_pps': 2019974.0282738095,
595             'duration_sec': 30
596         },
597         'ndr': {
598             'l2frame_size': '64',
599             'initial_rate_type': 'rate_percent',
600             'stats': {
601                 'overall': {
602                     'drop_rate_percent': 0.0,
603                     'min_delay_usec': 0.0,
604                     'avg_delay_usec': 0.0,
605                     'max_delay_usec': 0.0
606                 }
607             },
608             'load_percent_per_direction': 13.0859375,
609             'rate_percent': 13.08594422,
610             'rate_bps': 1308594422.0,
611             'rate_pps': 1947313.1279761905,
612             'duration_sec': 30
613         }
614     }
615
616     results = traffic_client.get_ndr_and_pdr()
617     assert len(results) == 2
618     for result in results.values():
619         result.pop('timestamp_sec')
620         result.pop('time_taken_sec')
621     assert results == expected_results
622 """
623
624
625 # pylint: enable=pointless-string-statement
626
627 # =========================================================================
628 # Other tests
629 # =========================================================================
630
631 def setup_module(module):
632     nfvbench.log.setup(mute_stdout=True)
633
634
635 def test_no_credentials():
636     cred = Credentials('/completely/wrong/path/openrc', None, False)
637     if cred.rc_auth_url:
638         # shouldn't get valid data unless user set environment variables
639         assert False
640     else:
641         assert True
642
643
644 # Because trex_stl_lib may not be installed when running unit test
645 # nfvbench.traffic_client will try to import STLError:
646 # from trex_stl_lib.api import STLError
647 # will raise ImportError: No module named trex_stl_lib.api
648 try:
649     import trex_stl_lib.api
650
651     assert trex_stl_lib.api
652 except ImportError:
653     # Make up a trex_stl_lib.api.STLError class
654     class STLError(Exception):
655         pass
656
657
658     from types import ModuleType
659
660     stl_lib_mod = ModuleType('trex_stl_lib')
661     sys.modules['trex_stl_lib'] = stl_lib_mod
662     api_mod = ModuleType('trex_stl_lib.api')
663     stl_lib_mod.api = api_mod
664     sys.modules['trex_stl_lib.api'] = api_mod
665     api_mod.STLError = STLError
666
667 # pylint: disable=wrong-import-position,ungrouped-imports
668 from nfvbench.traffic_client import Device
669 from nfvbench.traffic_client import IpBlock
670
671
672 # pylint: enable=wrong-import-position,ungrouped-imports
673
674 def test_ip_block():
675     ipb = IpBlock('10.0.0.0', '0.0.0.1', 256)
676     assert ipb.get_ip() == '10.0.0.0'
677     assert ipb.get_ip(255) == '10.0.0.255'
678     with pytest.raises(IndexError):
679         ipb.get_ip(256)
680     # verify with step larger than 1
681     ipb = IpBlock('10.0.0.0', '0.0.0.2', 256)
682     assert ipb.get_ip() == '10.0.0.0'
683     assert ipb.get_ip(1) == '10.0.0.2'
684     assert ipb.get_ip(128) == '10.0.1.0'
685     assert ipb.get_ip(255) == '10.0.1.254'
686     with pytest.raises(IndexError):
687         ipb.get_ip(256)
688
689
690 def check_config(configs, cc, fc, src_ip, dst_ip, step_ip):
691     '''Verify that the range configs for each chain have adjacent IP ranges
692     of the right size and without holes between chains
693     '''
694     step = Device.ip_to_int(step_ip)
695     cfc = 0
696     sip = Device.ip_to_int(src_ip)
697     dip = Device.ip_to_int(dst_ip)
698     for index in range(cc):
699         config = configs[index]
700         assert config['ip_src_count'] == config['ip_dst_count']
701         assert Device.ip_to_int(config['ip_src_addr']) == sip
702         assert Device.ip_to_int(config['ip_dst_addr']) == dip
703         count = config['ip_src_count']
704         cfc += count
705         sip += count * step
706         dip += count * step
707     assert cfc == fc
708
709
710 def create_device(fc, cc, ip, gip, tggip, step_ip):
711     return Device(0, 0, flow_count=fc, chain_count=cc, ip=ip, gateway_ip=gip, tg_gateway_ip=tggip,
712                   ip_addrs_step=step_ip,
713                   tg_gateway_ip_addrs_step=step_ip,
714                   gateway_ip_addrs_step=step_ip)
715
716
717 def check_device_flow_config(step_ip):
718     fc = 99999
719     cc = 10
720     ip0 = '10.0.0.0'
721     ip1 = '20.0.0.0'
722     tggip = '50.0.0.0'
723     gip = '60.0.0.0'
724     dev0 = create_device(fc, cc, ip0, gip, tggip, step_ip)
725     dev1 = create_device(fc, cc, ip1, gip, tggip, step_ip)
726     dev0.set_destination(dev1)
727     configs = dev0.get_stream_configs(ChainType.EXT)
728     check_config(configs, cc, fc, ip0, ip1, step_ip)
729
730
731 def test_device_flow_config():
732     check_device_flow_config('0.0.0.1')
733     check_device_flow_config('0.0.0.2')
734
735
736 def test_device_ip_range():
737     def ip_range_overlaps(ip0, ip1, flows):
738         tggip = '50.0.0.0'
739         gip = '60.0.0.0'
740         dev0 = create_device(flows, 10, ip0, gip, tggip, '0.0.0.1')
741         dev1 = create_device(flows, 10, ip1, gip, tggip, '0.0.0.1')
742         dev0.set_destination(dev1)
743         return dev0.ip_range_overlaps()
744
745     assert not ip_range_overlaps('10.0.0.0', '20.0.0.0', 10000)
746     assert ip_range_overlaps('10.0.0.0', '10.0.1.0', 10000)
747     assert ip_range_overlaps('10.0.0.0', '10.0.1.0', 257)
748     assert ip_range_overlaps('10.0.1.0', '10.0.0.0', 257)
749
750
751 def test_config():
752     refcfg = {1: 100, 2: {21: 100, 22: 200}, 3: None}
753     res1 = {1: 10, 2: {21: 100, 22: 200}, 3: None}
754     res2 = {1: 100, 2: {21: 1000, 22: 200}, 3: None}
755     res3 = {1: 100, 2: {21: 100, 22: 200}, 3: "abc"}
756     assert config_loads("{}", refcfg) == refcfg
757     assert config_loads("{1: 10}", refcfg) == res1
758     assert config_loads("{2: {21: 1000}}", refcfg) == res2
759     assert config_loads('{3: "abc"}', refcfg) == res3
760
761     # correctly fails
762     # pairs of input string and expected subset (None if identical)
763     fail_pairs = [
764         ["{4: 0}", None],
765         ["{2: {21: 100, 30: 50}}", "{2: {30: 50}}"],
766         ["{2: {0: 1, 1: 2}, 5: 5}", None],
767         ["{1: 'abc', 2: {21: 0}}", "{1: 'abc'}"],
768         ["{2: 100}", None]
769     ]
770     for fail_pair in fail_pairs:
771         with pytest.raises(Exception) as e_info:
772             config_loads(fail_pair[0], refcfg)
773         expected = fail_pair[1]
774         if expected is None:
775             expected = fail_pair[0]
776         assert expected in e_info.value.message
777
778     # whitelist keys
779     flavor = {'flavor': {'vcpus': 2, 'ram': 8192, 'disk': 0,
780                          'extra_specs': {'hw:cpu_policy': 'dedicated'}}}
781     new_flavor = {'flavor': {'vcpus': 2, 'ram': 8192, 'disk': 0,
782                              'extra_specs': {'hw:cpu_policy': 'dedicated', 'hw:numa_nodes': 2}}}
783     assert config_loads("{'flavor': {'extra_specs': {'hw:numa_nodes': 2}}}", flavor,
784                         whitelist_keys=['alpha', 'extra_specs']) == new_flavor
785
786
787 def test_fluentd():
788     logger = logging.getLogger('fluent-logger')
789     handler = FluentLogHandler('nfvbench', fluentd_port=7081)
790     logger.addHandler(handler)
791     logger.setLevel(logging.INFO)
792     logger.info('test')
793     logger.warning('test %d', 100)
794     try:
795         raise Exception("test")
796     except Exception:
797         logger.exception("got exception")