NFVBENCH-158 Allow multiple UDP ports in traffic generation
[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 from mock import patch
17 import pytest
18
19 from .mock_trex import no_op
20
21 import json
22 import logging
23 import sys
24 from attrdict import AttrDict
25 from nfvbench.config import config_loads
26 from nfvbench.credentials import Credentials
27 from nfvbench.fluentd import FluentLogHandler
28 import nfvbench.log
29 import nfvbench.nfvbench
30 from nfvbench.traffic_client import Device
31 from nfvbench.traffic_client import GeneratorConfig
32 from nfvbench.traffic_client import IpBlock
33 from nfvbench.traffic_client import TrafficClient
34 import nfvbench.traffic_gen.traffic_utils as traffic_utils
35
36
37 # just to get rid of the unused function warning
38 no_op()
39
40 def setup_module(module):
41     """Enable log."""
42     nfvbench.log.setup(mute_stdout=True)
43
44 # =========================================================================
45 # Traffic client tests
46 # =========================================================================
47
48 def test_parse_rate_str():
49     parse_rate_str = traffic_utils.parse_rate_str
50     try:
51         assert parse_rate_str('100%') == {'rate_percent': '100.0'}
52         assert parse_rate_str('37.5%') == {'rate_percent': '37.5'}
53         assert parse_rate_str('100%') == {'rate_percent': '100.0'}
54         assert parse_rate_str('60pps') == {'rate_pps': '60'}
55         assert parse_rate_str('60kpps') == {'rate_pps': '60000'}
56         assert parse_rate_str('6Mpps') == {'rate_pps': '6000000'}
57         assert parse_rate_str('6gpps') == {'rate_pps': '6000000000'}
58         assert parse_rate_str('80bps') == {'rate_bps': '80'}
59         assert parse_rate_str('80bps') == {'rate_bps': '80'}
60         assert parse_rate_str('80kbps') == {'rate_bps': '80000'}
61         assert parse_rate_str('80kBps') == {'rate_bps': '640000'}
62         assert parse_rate_str('80Mbps') == {'rate_bps': '80000000'}
63         assert parse_rate_str('80 MBps') == {'rate_bps': '640000000'}
64         assert parse_rate_str('80Gbps') == {'rate_bps': '80000000000'}
65     except Exception as exc:
66         assert False, exc.message
67
68     def should_raise_error(str):
69         try:
70             parse_rate_str(str)
71         except Exception:
72             return True
73         else:
74             return False
75         return False
76
77     assert should_raise_error('101')
78     assert should_raise_error('201%')
79     assert should_raise_error('10Kbps')
80     assert should_raise_error('0kbps')
81     assert should_raise_error('0pps')
82     assert should_raise_error('-1bps')
83
84
85 def test_rate_conversion():
86     assert traffic_utils.load_to_bps(50, 10000000000) == pytest.approx(5000000000.0)
87     assert traffic_utils.load_to_bps(37, 10000000000) == pytest.approx(3700000000.0)
88     assert traffic_utils.load_to_bps(100, 10000000000) == pytest.approx(10000000000.0)
89
90     assert traffic_utils.bps_to_load(5000000000.0, 10000000000) == pytest.approx(50.0)
91     assert traffic_utils.bps_to_load(3700000000.0, 10000000000) == pytest.approx(37.0)
92     assert traffic_utils.bps_to_load(10000000000.0, 10000000000) == pytest.approx(100.0)
93
94     assert traffic_utils.bps_to_pps(500000, 64) == pytest.approx(744.047619048)
95     assert traffic_utils.bps_to_pps(388888, 1518) == pytest.approx(31.6066319896)
96     assert traffic_utils.bps_to_pps(9298322222, 340.3) == pytest.approx(3225895.85831)
97
98     assert traffic_utils.pps_to_bps(744.047619048, 64) == pytest.approx(500000)
99     assert traffic_utils.pps_to_bps(31.6066319896, 1518) == pytest.approx(388888)
100     assert traffic_utils.pps_to_bps(3225895.85831, 340.3) == pytest.approx(9298322222)
101
102
103 # pps at 10Gbps line rate for 64 byte frames
104 LR_64B_PPS = 14880952
105 LR_1518B_PPS = 812743
106
107 def assert_equivalence(reference, value, allowance_pct=1):
108     """Assert if a value is equivalent to a reference value with given margin.
109
110     :param float reference: reference value to compare to
111     :param float value: value to compare to reference
112     :param float allowance_pct: max allowed percentage of margin
113         0 : requires exact match
114         1 : must be equal within 1% of the reference value
115         ...
116         100: always true
117     """
118     if reference == 0:
119         assert value == 0
120     else:
121         assert abs(value - reference) * 100 / reference <= allowance_pct
122
123 def test_load_from_rate():
124     assert traffic_utils.get_load_from_rate('100%') == 100
125     assert_equivalence(100, traffic_utils.get_load_from_rate(str(LR_64B_PPS) + 'pps'))
126     assert_equivalence(50, traffic_utils.get_load_from_rate(str(LR_64B_PPS / 2) + 'pps'))
127     assert_equivalence(100, traffic_utils.get_load_from_rate('10Gbps'))
128     assert_equivalence(50, traffic_utils.get_load_from_rate('5000Mbps'))
129     assert_equivalence(1, traffic_utils.get_load_from_rate('100Mbps'))
130     assert_equivalence(100, traffic_utils.get_load_from_rate(str(LR_1518B_PPS) + 'pps',
131                                                              avg_frame_size=1518))
132     assert_equivalence(100, traffic_utils.get_load_from_rate(str(LR_1518B_PPS * 2) + 'pps',
133                                                              avg_frame_size=1518,
134                                                              line_rate='20Gbps'))
135
136 # =========================================================================
137 # Other tests
138 # =========================================================================
139
140 def test_no_credentials():
141     cred = Credentials('/completely/wrong/path/openrc', None, False)
142     if cred.rc_auth_url:
143         # shouldn't get valid data unless user set environment variables
144         assert False
145     else:
146         assert True
147
148 def test_ip_block():
149     ipb = IpBlock('10.0.0.0', '0.0.0.1', 256)
150     assert ipb.get_ip() == '10.0.0.0'
151     assert ipb.get_ip(255) == '10.0.0.255'
152     with pytest.raises(IndexError):
153         ipb.get_ip(256)
154     ipb = IpBlock('10.0.0.0', '0.0.0.1', 1)
155     assert ipb.get_ip() == '10.0.0.0'
156     with pytest.raises(IndexError):
157         ipb.get_ip(1)
158
159     ipb = IpBlock('10.0.0.0', '0.0.0.2', 256)
160     assert ipb.get_ip() == '10.0.0.0'
161     assert ipb.get_ip(1) == '10.0.0.2'
162     assert ipb.get_ip(127) == '10.0.0.254'
163     assert ipb.get_ip(128) == '10.0.1.0'
164     with pytest.raises(IndexError):
165         ipb.get_ip(256)
166
167     # verify with step larger than 1
168     ipb = IpBlock('10.0.0.0', '0.0.0.2', 256)
169     assert ipb.get_ip() == '10.0.0.0'
170     assert ipb.get_ip(1) == '10.0.0.2'
171     assert ipb.get_ip(128) == '10.0.1.0'
172     assert ipb.get_ip(255) == '10.0.1.254'
173     with pytest.raises(IndexError):
174         ipb.get_ip(256)
175
176     ipb = IpBlock('10.0.0.0', '0.0.0.2', 128)
177     assert ipb.get_ip() == '10.0.0.0'
178     assert ipb.get_ip(1) == '10.0.0.2'
179     assert ipb.get_ip(127) == '10.0.0.254'
180     with pytest.raises(IndexError):
181         ipb.get_ip(128)
182
183     ipb = IpBlock('10.0.0.0', '0.0.0.4', 64)
184     assert ipb.get_ip() == '10.0.0.0'
185     assert ipb.get_ip(1) == '10.0.0.4'
186     assert ipb.get_ip(63) == '10.0.0.252'
187     with pytest.raises(IndexError):
188         ipb.get_ip(64)
189
190     ipb = IpBlock('10.0.0.0', '0.0.0.10', 1)
191     assert ipb.get_ip() == '10.0.0.0'
192     with pytest.raises(IndexError):
193         ipb.get_ip(1)
194
195
196 def test_lcm():
197     assert Device.lcm(10, 2) == 10
198     assert Device.lcm(1, 256) == 256
199     assert Device.lcm(10, 256) == 1280
200     assert Device.lcm(Device.lcm(10, 2), Device.lcm(1, 256))
201     with pytest.raises(TypeError):
202         Device.lcm(0, 0)
203
204
205 def test_check_ipsize():
206     assert Device.check_ipsize(256, 1) == 256
207     assert Device.check_ipsize(256, 3) == 86
208     assert Device.check_ipsize(256, 4) == 64
209     assert Device.check_ipsize(16, 10) == 2
210     assert Device.check_ipsize(1, 10) == 1
211     with pytest.raises(ZeroDivisionError):
212         Device.check_ipsize(256, 0)
213
214
215 def test_reserve_ip_range():
216     ipb = IpBlock('10.0.0.0', '0.0.0.1', 256)
217     src_ip_first, src_ip_last = ipb.reserve_ip_range(256, False)
218     assert src_ip_first == "10.0.0.0"
219     assert src_ip_last == "10.0.0.255"
220     ipb = IpBlock('20.0.0.0', '0.0.0.1', 2)
221     src_ip_first, src_ip_last = ipb.reserve_ip_range(2, False)
222     assert src_ip_first == "20.0.0.0"
223     assert src_ip_last == "20.0.0.1"
224     ipb = IpBlock('30.0.0.0', '0.0.0.1', 2)
225     src_ip_first, src_ip_last = ipb.reserve_ip_range(256, True)
226     assert src_ip_first == "30.0.0.0"
227     assert src_ip_last == "30.0.0.1"
228     ipb = IpBlock('40.0.0.0', '0.0.0.1', 2)
229     with pytest.raises(IndexError):
230         ipb.reserve_ip_range(256, False)
231
232
233 def check_stream_configs(gen_config):
234     """Verify that the range for each chain have adjacent IP ranges without holes between chains."""
235     config = gen_config.config
236     tgc = config['traffic_generator']
237     step = Device.ip_to_int(tgc['ip_addrs_step'])
238     cfc = 0
239     sip = Device.ip_to_int(tgc['ip_addrs'][0].split('/')[0])
240     dip = Device.ip_to_int(tgc['ip_addrs'][1].split('/')[0])
241     stream_configs = gen_config.devices[0].get_stream_configs()
242     for index in range(config['service_chain_count']):
243         stream_cfg = stream_configs[index]
244         assert stream_cfg['ip_src_count'] == stream_cfg['ip_dst_count']
245         assert Device.ip_to_int(stream_cfg['ip_src_addr']) == sip
246         assert Device.ip_to_int(stream_cfg['ip_dst_addr']) == dip
247         count = stream_cfg['ip_src_count']
248         cfc += count
249         sip += count * step
250         dip += count * step
251     assert cfc == int(config['flow_count'] / 2)
252
253 def _check_device_flow_config(step_ip):
254     config = _get_dummy_tg_config('PVP', '1Mpps', scc=10, fc=99999, step_ip=step_ip)
255     gen_config = GeneratorConfig(config)
256     check_stream_configs(gen_config)
257
258 def test_device_flow_config():
259     _check_device_flow_config('0.0.0.1')
260     _check_device_flow_config('0.0.0.2')
261
262
263 def check_udp_stream_configs(gen_config, expected):
264     """Verify that the range for each chain have adjacent UDP ports without holes between chains."""
265     config = gen_config.config
266     stream_configs = gen_config.devices[0].get_stream_configs()
267     for index in range(config['service_chain_count']):
268         stream_cfg = stream_configs[index]
269         assert stream_cfg['ip_src_addr'] == expected['ip_src_addr']
270         assert stream_cfg['ip_src_addr_max'] == expected['ip_src_addr_max']
271         assert stream_cfg['ip_dst_addr'] == expected['ip_dst_addr']
272         assert stream_cfg['ip_dst_addr_max'] == expected['ip_dst_addr_max']
273         assert stream_cfg['udp_src_port'] == expected['udp_src_port']
274         assert stream_cfg['udp_src_port_max'] == expected['udp_src_port_max']
275         assert stream_cfg['udp_src_count'] == expected['udp_src_count']
276         assert stream_cfg['udp_dst_port'] == expected['udp_dst_port']
277         assert stream_cfg['udp_dst_port_max'] == expected['udp_dst_port_max']
278         assert stream_cfg['udp_dst_count'] == expected['udp_dst_count']
279
280
281 def _check_device_udp_flow_config(param, expected):
282     config = _get_dummy_tg_config('PVP', '1Mpps',
283                                   ip_src_static=param['ip_src_static'],
284                                   fc=param['flow_count'],
285                                   ip0=param['ip_src_addr'],
286                                   ip1=param['ip_dst_addr'],
287                                   src_udp=param['udp_src_port'],
288                                   dst_udp=param['udp_dst_port'])
289     gen_config = GeneratorConfig(config)
290     check_udp_stream_configs(gen_config, expected)
291
292
293 def test_device_udp_flow_config():
294     param = {'ip_src_static': True,
295              'ip_src_addr': '110.0.0.0/32',
296              'ip_dst_addr': '120.0.0.0/32',
297              'udp_src_port': 53,
298              'udp_dst_port': 53,
299              'flow_count': 2}
300     expected = {'ip_src_addr': '110.0.0.0',
301                 'ip_src_addr_max': '110.0.0.0',
302                 'ip_dst_addr': '120.0.0.0',
303                 'ip_dst_addr_max': '120.0.0.0',
304                 'udp_src_port': 53,
305                 'udp_src_port_max': 53,
306                 'udp_src_count': 1,
307                 'udp_dst_port': 53,
308                 'udp_dst_port_max': 53,
309                 'udp_dst_count': 1}
310     _check_device_udp_flow_config(param, expected)
311     # Overwrite the udp_src_port value to define a large range of ports
312     # instead of a single port, in order to check if the imposed
313     # flow count is respected. Notice that udp range >> flow count.
314     param['udp_src_port'] = [53, 1024]
315     param['flow_count'] = 10
316     expected['udp_src_port_max'] = 57
317     expected['udp_src_count'] = 5
318     _check_device_udp_flow_config(param, expected)
319     # Re affect the default udp_src_port values and
320     # overwrite the ip_dst_addr value to define a large range of addresses
321     # instead of a single one, in order to check if the imposed
322     # flow count is respected. Notice that the netmask allows a very larger
323     # range of possible addresses than the flow count value.
324     param['udp_src_port'] = 53
325     expected['udp_src_port_max'] = 53
326     expected['udp_src_count'] = 1
327     param['ip_src_static'] = False
328     param['ip_dst_addr'] = '120.0.0.0/24'
329     expected['ip_dst_addr'] = '120.0.0.0'
330     expected['ip_dst_addr_max'] = '120.0.0.4'
331     _check_device_udp_flow_config(param, expected)
332
333
334 def test_config():
335     refcfg = {1: 100, 2: {21: 100, 22: 200}, 3: None}
336     res1 = {1: 10, 2: {21: 100, 22: 200}, 3: None}
337     res2 = {1: 100, 2: {21: 1000, 22: 200}, 3: None}
338     res3 = {1: 100, 2: {21: 100, 22: 200}, 3: "abc"}
339     assert config_loads("{}", refcfg) == refcfg
340     assert config_loads("{1: 10}", refcfg) == res1
341     assert config_loads("{2: {21: 1000}}", refcfg) == res2
342     assert config_loads('{3: "abc"}', refcfg) == res3
343
344     # correctly fails
345     # pairs of input string and expected subset (None if identical)
346     fail_pairs = [
347         ["{4: 0}", None],
348         ["{2: {21: 100, 30: 50}}", "{2: {30: 50}}"],
349         ["{2: {0: 1, 1: 2}, 5: 5}", None],
350         ["{1: 'abc', 2: {21: 0}}", "{1: 'abc'}"],
351         ["{2: 100}", None]
352     ]
353     for fail_pair in fail_pairs:
354         with pytest.raises(Exception) as e_info:
355             config_loads(fail_pair[0], refcfg)
356         expected = fail_pair[1]
357         if expected is None:
358             expected = fail_pair[0]
359         assert expected in str(e_info)
360
361     # whitelist keys
362     flavor = {'flavor': {'vcpus': 2, 'ram': 8192, 'disk': 0,
363                          'extra_specs': {'hw:cpu_policy': 'dedicated'}}}
364     new_flavor = {'flavor': {'vcpus': 2, 'ram': 8192, 'disk': 0,
365                              'extra_specs': {'hw:cpu_policy': 'dedicated', 'hw:numa_nodes': 2}}}
366     assert config_loads("{'flavor': {'extra_specs': {'hw:numa_nodes': 2}}}", flavor,
367                         whitelist_keys=['alpha', 'extra_specs']) == new_flavor
368
369
370 def test_fluentd():
371     logger = logging.getLogger('fluent-logger')
372
373     class FluentdConfig(dict):
374         def __getattr__(self, attr):
375             return self.get(attr)
376
377     fluentd_configs = [
378         FluentdConfig({
379             'logging_tag': 'nfvbench',
380             'result_tag': 'resultnfvbench',
381             'ip': '127.0.0.1',
382             'port': 7081
383         }),
384         FluentdConfig({
385             'logging_tag': 'nfvbench',
386             'result_tag': 'resultnfvbench',
387             'ip': '127.0.0.1',
388             'port': 24224
389         }),
390         FluentdConfig({
391             'logging_tag': None,
392             'result_tag': 'resultnfvbench',
393             'ip': '127.0.0.1',
394             'port': 7082
395         }),
396         FluentdConfig({
397             'logging_tag': 'nfvbench',
398             'result_tag': None,
399             'ip': '127.0.0.1',
400             'port': 7083
401         })
402     ]
403
404     handler = FluentLogHandler(fluentd_configs=fluentd_configs)
405     logger.addHandler(handler)
406     logger.setLevel(logging.INFO)
407     logger.info('test')
408     logger.warning('test %d', 100)
409
410     try:
411         raise Exception("test")
412     except Exception:
413         logger.exception("got exception")
414
415 def assert_ndr_pdr(stats, ndr, ndr_dr, pdr, pdr_dr):
416     assert stats['ndr']['rate_percent'] == ndr
417     assert stats['ndr']['stats']['overall']['drop_percentage'] == ndr_dr
418     assert_equivalence(pdr, stats['pdr']['rate_percent'])
419     assert_equivalence(pdr_dr, stats['pdr']['stats']['overall']['drop_percentage'])
420
421 def _get_dummy_tg_config(chain_type, rate, scc=1, fc=10, step_ip='0.0.0.1',
422                          ip0='10.0.0.0/8', ip1='20.0.0.0/8',
423                          step_udp=1, src_udp=None, dst_udp=None, ip_src_static=True):
424     return AttrDict({
425         'traffic_generator': {'host_name': 'nfvbench_tg',
426                               'default_profile': 'dummy',
427                               'generator_profile': [{'name': 'dummy',
428                                                      'tool': 'dummy',
429                                                      'ip': '127.0.0.1',
430                                                      'intf_speed': '10Gbps',
431                                                      'interfaces': [{'port': 0, 'pci': '0.0'},
432                                                                     {'port': 1, 'pci': '0.0'}]}],
433                               'ip_addrs_step': step_ip,
434                               'ip_addrs': [ip0, ip1],
435                               'ip_src_static': ip_src_static,
436                               'tg_gateway_ip_addrs': ['1.1.0.100', '2.2.0.100'],
437                               'tg_gateway_ip_addrs_step': step_ip,
438                               'gateway_ip_addrs': ['1.1.0.2', '2.2.0.2'],
439                               'gateway_ip_addrs_step': step_ip,
440                               'mac_addrs_left': None,
441                               'mac_addrs_right': None,
442                               'udp_src_port': src_udp,
443                               'udp_dst_port': dst_udp,
444                               'udp_port_step': step_udp},
445         'traffic': {'profile': 'profile_64',
446                     'bidirectional': True},
447         'traffic_profile': [{'name': 'profile_64', 'l2frame_size': ['64']}],
448         'generator_profile': None,
449         'service_chain': chain_type,
450         'service_chain_count': scc,
451         'flow_count': fc,
452         'vlan_tagging': True,
453         'no_arp': False,
454         'duration_sec': 1,
455         'interval_sec': 1,
456         'pause_sec': 1,
457         'rate': rate,
458         'check_traffic_time_sec': 200,
459         'generic_poll_sec': 2,
460         'measurement': {'NDR': 0.001, 'PDR': 0.1, 'load_epsilon': 0.1},
461         'l2_loopback': False,
462         'cores': None,
463         'mbuf_factor': None,
464         'disable_hdrh': None,
465         'mbuf_64': None,
466         'service_mode': False,
467         'no_flow_stats': False,
468         'no_latency_stats': False,
469         'no_latency_streams': False
470
471     })
472
473 def _get_traffic_client():
474     config = _get_dummy_tg_config('PVP', 'ndr_pdr')
475     config['vxlan'] = False
476     config['mpls'] = False
477     config['ndr_run'] = True
478     config['pdr_run'] = True
479     config['generator_profile'] = 'dummy'
480     config['single_run'] = False
481     traffic_client = TrafficClient(config)
482     traffic_client.start_traffic_generator()
483     traffic_client.set_traffic('64', True)
484     return traffic_client
485
486 @patch.object(TrafficClient, 'skip_sleep', lambda x: True)
487 def test_ndr_at_lr():
488     """Test NDR at line rate."""
489     traffic_client = _get_traffic_client()
490     tg = traffic_client.gen
491     # this is a perfect sut with no loss at LR
492     tg.set_response_curve(lr_dr=0, ndr=100, max_actual_tx=100, max_11_tx=100)
493     # tx packets should be line rate for 64B and no drops...
494     assert tg.get_tx_pps_dropped_pps(100) == (LR_64B_PPS, 0)
495     # NDR and PDR should be at 100%
496     # traffic_client.ensure_end_to_end()
497     results = traffic_client.get_ndr_and_pdr()
498     assert_ndr_pdr(results, 200.0, 0.0, 200.0, 0.0)
499
500 @patch.object(TrafficClient, 'skip_sleep', lambda x: True)
501 def test_ndr_at_50():
502     """Test NDR at 50% line rate.
503
504     This is a sut with an NDR of 50% and linear drop rate after NDR up to 20% drops at LR
505     (meaning that if you send 100% TX, you will only receive 80% RX)
506     the tg requested TX/actual TX ratio is up to 50%, after 50%
507     is linear up 80% actuak TX when requesting 100%
508     """
509     traffic_client = _get_traffic_client()
510     tg = traffic_client.gen
511
512     tg.set_response_curve(lr_dr=20, ndr=50, max_actual_tx=80, max_11_tx=50)
513     # tx packets should be half line rate for 64B and no drops...
514     assert tg.get_tx_pps_dropped_pps(50) == (LR_64B_PPS / 2, 0)
515     # at 100% TX requested, actual TX is 80% where the drop rate is 3/5 of 20% of the actual TX
516     assert tg.get_tx_pps_dropped_pps(100) == (int(LR_64B_PPS * 0.8),
517                                               int(LR_64B_PPS * 0.8 * 0.6 * 0.2))
518     results = traffic_client.get_ndr_and_pdr()
519     assert_ndr_pdr(results, 100.0, 0.0, 100.781, 0.09374)
520
521 @patch.object(TrafficClient, 'skip_sleep', lambda x: True)
522 def test_ndr_pdr_low_cpu():
523     """Test NDR and PDR with too low cpu.
524
525     This test is for the case where the TG is underpowered and cannot send fast enough for the NDR
526     true NDR=40%, actual TX at 50% = 30%, actual measured DR is 0%
527     The ndr/pdr should bail out with a warning and a best effort measured NDR of 30%
528     """
529     traffic_client = _get_traffic_client()
530     tg = traffic_client.gen
531     tg.set_response_curve(lr_dr=50, ndr=40, max_actual_tx=60, max_11_tx=0)
532     # tx packets should be 30% at requested half line rate for 64B and no drops...
533     assert tg.get_tx_pps_dropped_pps(50) == (int(LR_64B_PPS * 0.3), 0)
534     results = traffic_client.get_ndr_and_pdr()
535     assert results
536     # import pprint
537     # pp = pprint.PrettyPrinter(indent=4)
538     # pp.pprint(results)
539
540 @patch.object(TrafficClient, 'skip_sleep', lambda x: True)
541 def test_no_openstack():
542     """Test nfvbench using main."""
543     config = _get_dummy_tg_config('EXT', '1000pps')
544     config.openrc_file = None
545     config.vlans = [[100], [200]]
546     config['traffic_generator']['mac_addrs_left'] = ['00:00:00:00:00:00']
547     config['traffic_generator']['mac_addrs_right'] = ['00:00:00:00:01:00']
548     del config['generator_profile']
549     old_argv = sys.argv
550     sys.argv = [old_argv[0], '-c', json.dumps(config)]
551     nfvbench.nfvbench.main()
552     sys.argv = old_argv