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