NFVBENCH-153 Add support for python3
[nfvbench.git] / test / test_chains.py
index e952eb8..3cf75cb 100644 (file)
 #
 """Test Chaining functions."""
 
-from mock_trex import no_op
-
 from mock import MagicMock
 from mock import patch
 import pytest
 
+from .mock_trex import no_op
+
 from nfvbench.chain_runner import ChainRunner
+from nfvbench.chaining import ChainException
 from nfvbench.chaining import ChainVnfPort
 from nfvbench.chaining import InstancePlacer
 from nfvbench.compute import Compute
@@ -37,8 +38,7 @@ from nfvbench.specs import Specs
 from nfvbench.summarizer import _annotate_chain_stats
 from nfvbench.traffic_client import TrafficClient
 from nfvbench.traffic_gen.traffic_base import Latency
-from nfvbench.traffic_gen.trex import TRex
-
+from nfvbench.traffic_gen.trex_gen import TRex
 
 # just to get rid of the unused function warning
 no_op()
@@ -49,17 +49,17 @@ def setup_module(module):
     nfvbench.log.setup(mute_stdout=False)
     nfvbench.log.set_level(debug=True)
 
-def _get_chain_config(sc=ChainType.PVP, scc=1, shared_net=True):
+def _get_chain_config(sc=ChainType.PVP, scc=1, shared_net=True, rate='1Mpps'):
     config, _ = load_default_config()
     config.vm_image_file = 'nfvbenchvm-0.0.qcow2'
     config.service_chain_count = scc
     config.service_chain = sc
     config.service_chain_shared_net = shared_net
-    config.rate = '1Mpps'
+    config.rate = rate
     config['traffic_generator']['generator_profile'] = [{'name': 'dummy',
                                                          'tool': 'dummy',
                                                          'ip': '127.0.0.1',
-                                                         'intf_speed': None,
+                                                         'intf_speed': '10Gbps',
                                                          'interfaces': [{'port': 0, 'pci': '0.0'},
                                                                         {'port': 1, 'pci': '0.0'}]}]
     config.ndr_run = False
@@ -69,6 +69,9 @@ def _get_chain_config(sc=ChainType.PVP, scc=1, shared_net=True):
     config.duration_sec = 2
     config.interval_sec = 1
     config.openrc_file = "dummy.rc"
+    config.no_flow_stats = False
+    config.no_latency_stats = False
+    config.no_latency_streams = False
     return config
 
 def test_chain_runner_ext_no_openstack():
@@ -78,11 +81,31 @@ def test_chain_runner_ext_no_openstack():
     config.vlans = [100, 200]
     config['traffic_generator']['mac_addrs_left'] = ['00:00:00:00:00:00']
     config['traffic_generator']['mac_addrs_right'] = ['00:00:00:00:01:00']
-    runner = ChainRunner(config, None, specs, BasicFactory())
-    runner.close()
+
+    for shared_net in [True, False]:
+        for no_arp in [False, True]:
+            for vlan_tag in [False, True]:
+                for scc in [1, 2]:
+                    config = _get_chain_config(ChainType.EXT, scc, shared_net)
+                    config.no_arp = no_arp
+                    if no_arp:
+                        # If EXT and no arp, the config must provide mac (1 pair per chain)
+                        config['traffic_generator']['mac_addrs_left'] = ['00:00:00:00:00:00'] * scc
+                        config['traffic_generator']['mac_addrs_right'] = ['00:00:00:00:01:00'] * scc
+                    config['vlan_tagging'] = vlan_tag
+                    if vlan_tag:
+                        # these are the 2 valid forms of vlan ranges
+                        if scc == 1:
+                            config.vlans = [100, 200]
+                        else:
+                            config.vlans = [[port * 100 + index for index in range(scc)]
+                                            for port in range(2)]
+                    runner = ChainRunner(config, None, specs, BasicFactory())
+                    runner.close()
+
 
 def _mock_find_image(self, image_name):
-    return True
+    return MagicMock()
 
 @patch.object(Compute, 'find_image', _mock_find_image)
 @patch('nfvbench.chaining.Client')
@@ -99,18 +122,87 @@ def _test_pvp_chain(config, cred, mock_glance, mock_neutron, mock_client):
     openstack_spec = OpenStackSpec()
     specs.set_openstack_spec(openstack_spec)
     cred = MagicMock(spec=nfvbench.credentials.Credentials)
+    cred.is_admin = True
     runner = ChainRunner(config, cred, specs, BasicFactory())
     runner.close()
 
 def test_pvp_chain_runner():
     """Test PVP chain runner."""
     cred = MagicMock(spec=nfvbench.credentials.Credentials)
+    cred.is_admin = True
     for shared_net in [True, False]:
         for sc in [ChainType.PVP]:
             for scc in [1, 2]:
                 config = _get_chain_config(sc, scc, shared_net)
                 _test_pvp_chain(config, cred)
 
+
+# Test not admin exception with empty value is raised
+@patch.object(Compute, 'find_image', _mock_find_image)
+@patch('nfvbench.chaining.Client')
+@patch('nfvbench.chaining.neutronclient')
+@patch('nfvbench.chaining.glanceclient')
+def _test_pvp_chain_no_admin_no_config_values(config, cred, mock_glance, mock_neutron, mock_client):
+    # instance = self.novaclient.servers.create(name=vmname,...)
+    # instance.status == 'ACTIVE'
+    mock_client.return_value.servers.create.return_value.status = 'ACTIVE'
+    netw = {'id': 0, 'provider:network_type': 'vlan', 'provider:segmentation_id': 1000}
+    mock_neutron.Client.return_value.create_network.return_value = {'network': netw}
+    mock_neutron.Client.return_value.list_networks.return_value = {'networks': None}
+    specs = Specs()
+    openstack_spec = OpenStackSpec()
+    specs.set_openstack_spec(openstack_spec)
+    runner = ChainRunner(config, cred, specs, BasicFactory())
+    runner.close()
+
+def test_pvp_chain_runner_no_admin_no_config_values():
+    """Test PVP/mock chain runner."""
+    cred = MagicMock(spec=nfvbench.credentials.Credentials)
+    cred.is_admin = False
+    for shared_net in [True, False]:
+        for sc in [ChainType.PVP]:
+            for scc in [1, 2]:
+                config = _get_chain_config(sc, scc, shared_net)
+                with pytest.raises(ChainException):
+                    _test_pvp_chain_no_admin_no_config_values(config, cred)
+
+# Test not admin with mandatory parameters values in config file
+@patch.object(Compute, 'find_image', _mock_find_image)
+@patch('nfvbench.chaining.Client')
+@patch('nfvbench.chaining.neutronclient')
+@patch('nfvbench.chaining.glanceclient')
+def _test_pvp_chain_no_admin_config_values(config, cred, mock_glance, mock_neutron, mock_client):
+    # instance = self.novaclient.servers.create(name=vmname,...)
+    # instance.status == 'ACTIVE'
+    mock_client.return_value.servers.create.return_value.status = 'ACTIVE'
+    netw = {'id': 0, 'provider:network_type': 'vlan', 'provider:segmentation_id': 1000}
+    mock_neutron.Client.return_value.create_network.return_value = {'network': netw}
+    mock_neutron.Client.return_value.list_networks.return_value = {'networks': None}
+    specs = Specs()
+    openstack_spec = OpenStackSpec()
+    specs.set_openstack_spec(openstack_spec)
+    runner = ChainRunner(config, cred, specs, BasicFactory())
+    runner.close()
+
+def test_pvp_chain_runner_no_admin_config_values():
+    """Test PVP chain runner."""
+    cred = MagicMock(spec=nfvbench.credentials.Credentials)
+    cred.is_admin = False
+    for shared_net in [True, False]:
+        for sc in [ChainType.PVP]:
+            for scc in [1, 2]:
+                config = _get_chain_config(sc, scc, shared_net)
+                config.availability_zone = "az"
+                config.hypervisor_hostname = "server"
+                # these are the 2 valid forms of vlan ranges
+                if scc == 1:
+                    config.vlans = [100, 200]
+                else:
+                    config.vlans = [[port * 100 + index for index in range(scc)]
+                                    for port in range(2)]
+                _test_pvp_chain_no_admin_config_values(config, cred)
+
+
 @patch.object(Compute, 'find_image', _mock_find_image)
 @patch('nfvbench.chaining.Client')
 @patch('nfvbench.chaining.neutronclient')
@@ -125,17 +217,26 @@ def _test_ext_chain(config, cred, mock_glance, mock_neutron, mock_client):
     openstack_spec = OpenStackSpec()
     specs.set_openstack_spec(openstack_spec)
     cred = MagicMock(spec=nfvbench.credentials.Credentials)
+    cred.is_admin = True
     runner = ChainRunner(config, cred, specs, BasicFactory())
     runner.close()
 
 def test_ext_chain_runner():
-    """Test openstack+EXT chain runner."""
+    """Test openstack+EXT chain runner.
+
+    Test 8 combinations of configs:
+    shared/not shared net x arp/no_arp x scc 1 or 2
+    """
     cred = MagicMock(spec=nfvbench.credentials.Credentials)
+    cred.is_admin = True
     for shared_net in [True, False]:
         for no_arp in [False, True]:
             for scc in [1, 2]:
                 config = _get_chain_config(ChainType.EXT, scc, shared_net)
                 config.no_arp = no_arp
+                # this time use a tuple of network names
+                config['external_networks']['left'] = ('ext-lnet00', 'ext-lnet01')
+                config['external_networks']['right'] = ('ext-rnet00', 'ext-rnet01')
                 if no_arp:
                     # If EXT and no arp, the config must provide mac addresses (1 pair per chain)
                     config['traffic_generator']['mac_addrs_left'] = ['00:00:00:00:00:00'] * scc
@@ -148,6 +249,9 @@ def _check_nfvbench_openstack(sc=ChainType.PVP, l2_loopback=False):
         if l2_loopback:
             config.l2_loopback = True
             config.vlans = [[100], [200]]
+        if sc == ChainType.EXT:
+            config['external_networks']['left'] = 'ext-lnet'
+            config['external_networks']['right'] = 'ext-rnet'
         factory = BasicFactory()
         config_plugin = factory.get_config_plugin_class()(config)
         config = config_plugin.get_config()
@@ -155,7 +259,7 @@ def _check_nfvbench_openstack(sc=ChainType.PVP, l2_loopback=False):
         nfvb = NFVBench(config, openstack_spec, config_plugin, factory)
         res = nfvb.run({}, 'pytest')
         if res['status'] != 'OK':
-            print res
+            print(res)
         assert res['status'] == 'OK'
 
 
@@ -169,6 +273,7 @@ def _mock_get_mac(dummy):
 @patch.object(Compute, 'find_image', _mock_find_image)
 @patch.object(TrafficClient, 'skip_sleep', lambda x: True)
 @patch.object(ChainVnfPort, 'get_mac', _mock_get_mac)
+@patch.object(TrafficClient, 'is_udp', lambda x, y: True)
 @patch('nfvbench.chaining.Client')
 @patch('nfvbench.chaining.neutronclient')
 @patch('nfvbench.chaining.glanceclient')
@@ -185,6 +290,7 @@ def test_nfvbench_run(mock_cred, mock_glance, mock_neutron, mock_client):
 
 @patch.object(Compute, 'find_image', _mock_find_image)
 @patch.object(TrafficClient, 'skip_sleep', lambda x: True)
+@patch.object(TrafficClient, 'is_udp', lambda x, y: True)
 @patch('nfvbench.chaining.Client')
 @patch('nfvbench.chaining.neutronclient')
 @patch('nfvbench.chaining.glanceclient')
@@ -200,6 +306,7 @@ def test_nfvbench_ext_arp(mock_cred, mock_glance, mock_neutron, mock_client):
 
 @patch.object(Compute, 'find_image', _mock_find_image)
 @patch.object(TrafficClient, 'skip_sleep', lambda x: True)
+@patch.object(TrafficClient, 'is_udp', lambda x, y: True)
 @patch('nfvbench.chaining.Client')
 @patch('nfvbench.chaining.neutronclient')
 @patch('nfvbench.chaining.glanceclient')
@@ -298,7 +405,7 @@ def test_placer_user_az():
 
 def test_placer_user_hyp():
     """Test placement when user provides a hypervisor."""
-    check_placer(None, 'comp1', 'comp1')
+    check_placer(None, 'comp1', ':comp1')
     check_placer('nova', 'comp1', 'nova:comp1', resolved=True)
     check_placer(None, 'nova:comp1', 'nova:comp1', resolved=True)
     # hyp overrides az
@@ -332,7 +439,11 @@ CHAIN_STATS = [{0: {'packets': [2000054, 1999996, 1999996]}},
                 'total': {'packets': [30000004, 30000004, 30000004, 30000004, 30000004, 30000004]}},
                {0: {'packets': [15000002, '', 14000002, 14000002, '', 13000002]},
                 1: {'packets': [15000002, '', 15000002, 15000002, '', 15000002]},
-                'total': {'packets': [30000004, 29000004, 29000004, 29000004, 29000004, 28000004]}}]
+                'total': {'packets': [30000004, 29000004, 29000004, 29000004, 29000004, 28000004]}},
+               # example with non-available rx count in last position
+               {0: {'packets': [2000054, 1999996, None]},
+                1: {'packets': [2000054, 2000054, None]},
+                'total': {'packets': [4000108, 4000050, 4000050]}}]
 XP_CHAIN_STATS = [{0: {'packets': [2000054, '-58 (-0.0029%)', 1999996]}},
                   {0: {'packets': [2000054, '-58 (-0.0029%)', 1999996]},
                    1: {'packets': [2000054, '=>', 2000054]},
@@ -347,7 +458,10 @@ XP_CHAIN_STATS = [{0: {'packets': [2000054, '-58 (-0.0029%)', 1999996]}},
                                    '-1,000,000 (-7.1429%)']},
                    1: {'packets': [15000002, '', '=>', '=>', '', 15000002]},
                    'total': {'packets': [30000004, '-1,000,000 (-3.3333%)', '=>', '=>', '=>',
-                                         '-1,000,000 (-3.4483%)']}}]
+                                         '-1,000,000 (-3.4483%)']}},
+                  {0: {'packets': [2000054, '-58 (-0.0029%)', 'n/a']},
+                   1: {'packets': [2000054, '=>', 'n/a']},
+                   'total': {'packets': [4000108, '-58 (-0.0014%)', 4000050]}}]
 
 
 def test_summarizer():
@@ -355,3 +469,28 @@ def test_summarizer():
     for stats, exp_stats in zip(CHAIN_STATS, XP_CHAIN_STATS):
         _annotate_chain_stats(stats)
         assert stats == exp_stats
+
+@patch.object(TrafficClient, 'skip_sleep', lambda x: True)
+@patch.object(TrafficClient, 'is_udp', lambda x, y: True)
+def test_fixed_rate_no_openstack():
+    """Test FIxed Rate run - no openstack."""
+    config = _get_chain_config(ChainType.EXT, 1, True, rate='100%')
+    specs = Specs()
+    config.vlans = [100, 200]
+    config['traffic_generator']['mac_addrs_left'] = ['00:00:00:00:00:00']
+    config['traffic_generator']['mac_addrs_right'] = ['00:00:00:00:01:00']
+    config.no_arp = True
+    config['vlan_tagging'] = True
+    config['traffic'] = {'profile': 'profile_64',
+                         'bidirectional': True}
+    config['traffic_profile'] = [{'name': 'profile_64', 'l2frame_size': ['64']}]
+
+    runner = ChainRunner(config, None, specs, BasicFactory())
+    tg = runner.traffic_client.gen
+
+    tg.set_response_curve(lr_dr=0, ndr=100, max_actual_tx=50, max_11_tx=50)
+    # tx packets should be 50% at requested 50% line rate or higher for 64B and no drops...
+    results = runner.run()
+    assert results
+    # pprint.pprint(results['EXT']['result']['result']['64'])
+    runner.close()