diff options
4 files changed, 373 insertions, 7 deletions
diff --git a/yardstick/network_services/libs/ixia_libs/ixnet/ixnet_api.py b/yardstick/network_services/libs/ixia_libs/ixnet/ixnet_api.py index 82f406d08..8274ff9ce 100644 --- a/yardstick/network_services/libs/ixia_libs/ixnet/ixnet_api.py +++ b/yardstick/network_services/libs/ixia_libs/ixnet/ixnet_api.py @@ -34,6 +34,13 @@ PROTO_UDP = 'udp' PROTO_TCP = 'tcp' PROTO_VLAN = 'vlan' +SINGLE_VALUE = "singleValue" + +S_VLAN = 0 +C_VLAN = 1 + +ETHER_TYPE_802_1ad = '0x88a8' + IP_VERSION_4_MASK = 24 IP_VERSION_6_MASK = 64 @@ -359,7 +366,6 @@ class IxNextgen(object): # pragma: no cover raise exceptions.IxNetworkFlowNotPresent(flow_group=fg_id) type = traffic_param.get('traffic_type', 'fixedDuration') - duration = traffic_param.get('duration', 30) rate = traffic_param['rate'] rate_unit = ( 'framesPerSecond' if traffic_param['rate_unit'] == @@ -368,10 +374,28 @@ class IxNextgen(object): # pragma: no cover traffic_param['outer_l2']['framesize']) srcmac = str(traffic_param.get('srcmac', '00:00:00:00:00:01')) dstmac = str(traffic_param.get('dstmac', '00:00:00:00:00:02')) - # NOTE(ralonsoh): add QinQ tagging when - # traffic_param['outer_l2']['QinQ'] exists. - # s_vlan = traffic_param['outer_l2']['QinQ']['S-VLAN'] - # c_vlan = traffic_param['outer_l2']['QinQ']['C-VLAN'] + + if traffic_param['outer_l2']['QinQ']: + s_vlan = traffic_param['outer_l2']['QinQ']['S-VLAN'] + c_vlan = traffic_param['outer_l2']['QinQ']['C-VLAN'] + + field_descriptor = self._get_field_in_stack_item( + self._get_stack_item(fg_id, PROTO_ETHERNET)[0], + 'etherType') + + self.ixnet.setMultiAttribute(field_descriptor, + '-auto', 'false', + '-singleValue', ETHER_TYPE_802_1ad, + '-fieldValue', ETHER_TYPE_802_1ad, + '-valueType', SINGLE_VALUE) + + self._append_procotol_to_stack( + PROTO_VLAN, config_element + '/stack:"ethernet-1"') + self._append_procotol_to_stack( + PROTO_VLAN, config_element + '/stack:"ethernet-1"') + + self._update_vlan_tag(fg_id, s_vlan, S_VLAN) + self._update_vlan_tag(fg_id, c_vlan, C_VLAN) self.ixnet.setMultiAttribute( config_element + '/transmissionControl', @@ -392,6 +416,27 @@ class IxNextgen(object): # pragma: no cover self._get_stack_item(fg_id, PROTO_ETHERNET)[0], 'sourceAddress', srcmac) + def _update_vlan_tag(self, fg_id, params, vlan=0): + field_to_param_map = { + 'vlanUserPriority': 'priority', + 'cfi': 'cfi', + 'vlanID': 'id' + } + for field, param in field_to_param_map.items(): + value = params.get(param) + if value: + field_descriptor = self._get_field_in_stack_item( + self._get_stack_item(fg_id, PROTO_VLAN)[vlan], + field) + + self.ixnet.setMultiAttribute(field_descriptor, + '-auto', 'false', + '-singleValue', value, + '-fieldValue', value, + '-valueType', SINGLE_VALUE) + + self.ixnet.commit() + def _update_ipv4_address(self, ip_descriptor, field, ip_address, seed, mask, count): """Set the IPv4 address in a config element stack IP field diff --git a/yardstick/network_services/traffic_profile/ixia_rfc2544.py b/yardstick/network_services/traffic_profile/ixia_rfc2544.py index 2086273e6..26dc1fe04 100644 --- a/yardstick/network_services/traffic_profile/ixia_rfc2544.py +++ b/yardstick/network_services/traffic_profile/ixia_rfc2544.py @@ -88,6 +88,7 @@ class IXIARFC2544Profile(trex_traffic_profile.TrexProfile): 'outer_l2': { 'framesize': value['outer_l2']['framesize'], 'framesPerSecond': True, + 'QinQ': value['outer_l2'].get('QinQ'), 'srcmac': mac['src_mac_{}'.format(port_index)], 'dstmac': mac['dst_mac_{}'.format(port_index)], }, diff --git a/yardstick/tests/unit/benchmark/runner/test_duration.py b/yardstick/tests/unit/benchmark/runner/test_duration.py index 21e3874b8..d4801ef2c 100644 --- a/yardstick/tests/unit/benchmark/runner/test_duration.py +++ b/yardstick/tests/unit/benchmark/runner/test_duration.py @@ -11,17 +11,50 @@ import mock import unittest import multiprocessing import os +import time from yardstick.benchmark.runners import duration +from yardstick.common import exceptions as y_exc class DurationRunnerTest(unittest.TestCase): + class MyMethod(object): + SLA_VALIDATION_ERROR_SIDE_EFFECT = 1 + BROAD_EXCEPTION_SIDE_EFFECT = 2 + + def __init__(self, side_effect=0): + self.count = 101 + self.side_effect = side_effect + + def __call__(self, data): + self.count += 1 + data['my_key'] = self.count + if self.side_effect == self.SLA_VALIDATION_ERROR_SIDE_EFFECT: + raise y_exc.SLAValidationError(case_name='My Case', + error_msg='my error message') + elif self.side_effect == self.BROAD_EXCEPTION_SIDE_EFFECT: + raise y_exc.YardstickException + return self.count + def setUp(self): self.scenario_cfg = { 'runner': {'interval': 0, "duration": 0}, 'type': 'some_type' } + self.benchmark = mock.Mock() + self.benchmark_cls = mock.Mock(return_value=self.benchmark) + + def _assert_defaults__worker_run_setup_and_teardown(self): + self.benchmark_cls.assert_called_once_with(self.scenario_cfg, {}) + self.benchmark.setup.assert_called_once() + self.benchmark.teardown.assert_called_once() + + def _assert_defaults__worker_run_one_iteration(self): + self.benchmark.pre_run_wait_time.assert_called_once_with(0) + self.benchmark.my_method.assert_called_once_with({}) + self.benchmark.post_run_wait_time.assert_called_once_with(0) + @mock.patch.object(os, 'getpid') @mock.patch.object(multiprocessing, 'Process') def test__run_benchmark_called_with(self, mock_multiprocessing_process, @@ -37,3 +70,246 @@ class DurationRunnerTest(unittest.TestCase): target=duration._worker_process, args=(runner.result_queue, benchmark_cls, 'my_method', self.scenario_cfg, {}, runner.aborted, runner.output_queue)) + + @mock.patch.object(os, 'getpid') + def test__worker_process_runner_id(self, mock_os_getpid): + mock_os_getpid.return_value = 101 + + duration._worker_process(mock.Mock(), self.benchmark_cls, 'my_method', + self.scenario_cfg, {}, + multiprocessing.Event(), mock.Mock()) + + self.assertEqual(self.scenario_cfg['runner']['runner_id'], 101) + + def test__worker_process_called_with_cfg(self): + duration._worker_process(mock.Mock(), self.benchmark_cls, 'my_method', + self.scenario_cfg, {}, + multiprocessing.Event(), mock.Mock()) + + self._assert_defaults__worker_run_setup_and_teardown() + self._assert_defaults__worker_run_one_iteration() + + def test__worker_process_called_with_cfg_loop(self): + self.scenario_cfg['runner']['duration'] = 0.01 + + duration._worker_process(mock.Mock(), self.benchmark_cls, 'my_method', + self.scenario_cfg, {}, + multiprocessing.Event(), mock.Mock()) + + self._assert_defaults__worker_run_setup_and_teardown() + self.assertGreater(self.benchmark.pre_run_wait_time.call_count, 2) + self.assertGreater(self.benchmark.my_method.call_count, 2) + self.assertGreater(self.benchmark.post_run_wait_time.call_count, 2) + + def test__worker_process_called_without_cfg(self): + scenario_cfg = {'runner': {}} + aborted = multiprocessing.Event() + aborted.set() + + duration._worker_process(mock.Mock(), self.benchmark_cls, 'my_method', + scenario_cfg, {}, aborted, mock.Mock()) + + self.benchmark_cls.assert_called_once_with(scenario_cfg, {}) + self.benchmark.setup.assert_called_once() + self.benchmark.pre_run_wait_time.assert_called_once_with(1) + self.benchmark.my_method.assert_called_once_with({}) + self.benchmark.post_run_wait_time.assert_called_once_with(1) + self.benchmark.teardown.assert_called_once() + + def test__worker_process_output_queue(self): + self.benchmark.my_method = mock.Mock(return_value='my_result') + + output_queue = multiprocessing.Queue() + duration._worker_process(mock.Mock(), self.benchmark_cls, 'my_method', + self.scenario_cfg, {}, + multiprocessing.Event(), output_queue) + time.sleep(0.1) + + self._assert_defaults__worker_run_setup_and_teardown() + self._assert_defaults__worker_run_one_iteration() + self.assertEquals(output_queue.get(), 'my_result') + + def test__worker_process_output_queue_multiple_iterations(self): + self.scenario_cfg['runner']['duration'] = 0.01 + self.benchmark.my_method = self.MyMethod() + + output_queue = multiprocessing.Queue() + duration._worker_process(mock.Mock(), self.benchmark_cls, 'my_method', + self.scenario_cfg, {}, + multiprocessing.Event(), output_queue) + time.sleep(0.1) + + self._assert_defaults__worker_run_setup_and_teardown() + self.assertGreater(self.benchmark.pre_run_wait_time.call_count, 2) + self.assertGreater(self.benchmark.my_method.count, 103) + self.assertGreater(self.benchmark.post_run_wait_time.call_count, 2) + + count = 101 + while not output_queue.empty(): + count += 1 + self.assertEquals(output_queue.get(), count) + + def test__worker_process_queue(self): + self.benchmark.my_method = self.MyMethod() + + queue = multiprocessing.Queue() + timestamp = time.time() + duration._worker_process(queue, self.benchmark_cls, 'my_method', + self.scenario_cfg, {}, + multiprocessing.Event(), mock.Mock()) + time.sleep(0.1) + + self._assert_defaults__worker_run_setup_and_teardown() + self.benchmark.pre_run_wait_time.assert_called_once_with(0) + self.benchmark.post_run_wait_time.assert_called_once_with(0) + + result = queue.get() + self.assertGreater(result['timestamp'], timestamp) + self.assertEqual(result['errors'], '') + self.assertEqual(result['data'], {'my_key': 102}) + self.assertEqual(result['sequence'], 1) + + def test__worker_process_queue_multiple_iterations(self): + self.scenario_cfg['runner']['duration'] = 0.5 + self.benchmark.my_method = self.MyMethod() + + queue = multiprocessing.Queue() + timestamp = time.time() + duration._worker_process(queue, self.benchmark_cls, 'my_method', + self.scenario_cfg, {}, + multiprocessing.Event(), mock.Mock()) + time.sleep(0.1) + + self._assert_defaults__worker_run_setup_and_teardown() + self.assertGreater(self.benchmark.pre_run_wait_time.call_count, 2) + self.assertGreater(self.benchmark.my_method.count, 103) + self.assertGreater(self.benchmark.post_run_wait_time.call_count, 2) + + count = 0 + while not queue.empty(): + count += 1 + result = queue.get() + self.assertGreater(result['timestamp'], timestamp) + self.assertEqual(result['errors'], '') + self.assertEqual(result['data'], {'my_key': count + 101}) + self.assertEqual(result['sequence'], count) + + def test__worker_process_except_sla_validation_error_no_sla_cfg(self): + self.benchmark.my_method = mock.Mock( + side_effect=y_exc.SLAValidationError) + + duration._worker_process(mock.Mock(), self.benchmark_cls, 'my_method', + self.scenario_cfg, {}, + multiprocessing.Event(), mock.Mock()) + + self._assert_defaults__worker_run_setup_and_teardown() + self._assert_defaults__worker_run_one_iteration() + + def test__worker_process_except_sla_validation_error_sla_cfg_monitor(self): + self.scenario_cfg['sla'] = {'action': 'monitor'} + self.benchmark.my_method = mock.Mock( + side_effect=y_exc.SLAValidationError) + + duration._worker_process(mock.Mock(), self.benchmark_cls, 'my_method', + self.scenario_cfg, {}, + multiprocessing.Event(), mock.Mock()) + + self._assert_defaults__worker_run_setup_and_teardown() + self._assert_defaults__worker_run_one_iteration() + + def test__worker_process_raise_sla_validation_error_sla_cfg_default(self): + self.scenario_cfg['sla'] = {} + self.benchmark.my_method = mock.Mock( + side_effect=y_exc.SLAValidationError) + + with self.assertRaises(y_exc.SLAValidationError): + duration._worker_process(mock.Mock(), self.benchmark_cls, + 'my_method', self.scenario_cfg, {}, + multiprocessing.Event(), mock.Mock()) + + self.benchmark_cls.assert_called_once_with(self.scenario_cfg, {}) + self.benchmark.setup.assert_called_once() + self.benchmark.pre_run_wait_time.assert_called_once_with(0) + self.benchmark.my_method.assert_called_once_with({}) + + def test__worker_process_raise_sla_validation_error_sla_cfg_assert(self): + self.scenario_cfg['sla'] = {'action': 'assert'} + self.benchmark.my_method = mock.Mock( + side_effect=y_exc.SLAValidationError) + + with self.assertRaises(y_exc.SLAValidationError): + duration._worker_process(mock.Mock(), self.benchmark_cls, + 'my_method', self.scenario_cfg, {}, + multiprocessing.Event(), mock.Mock()) + + self.benchmark_cls.assert_called_once_with(self.scenario_cfg, {}) + self.benchmark.setup.assert_called_once() + self.benchmark.pre_run_wait_time.assert_called_once_with(0) + self.benchmark.my_method.assert_called_once_with({}) + + def test__worker_process_queue_on_sla_validation_error_monitor(self): + self.scenario_cfg['sla'] = {'action': 'monitor'} + self.benchmark.my_method = self.MyMethod( + side_effect=self.MyMethod.SLA_VALIDATION_ERROR_SIDE_EFFECT) + + queue = multiprocessing.Queue() + timestamp = time.time() + duration._worker_process(queue, self.benchmark_cls, 'my_method', + self.scenario_cfg, {}, + multiprocessing.Event(), mock.Mock()) + time.sleep(0.1) + + self._assert_defaults__worker_run_setup_and_teardown() + self.benchmark.pre_run_wait_time.assert_called_once_with(0) + self.benchmark.post_run_wait_time.assert_called_once_with(0) + + result = queue.get() + self.assertGreater(result['timestamp'], timestamp) + self.assertEqual(result['errors'], ('My Case SLA validation failed. ' + 'Error: my error message',)) + self.assertEqual(result['data'], {'my_key': 102}) + self.assertEqual(result['sequence'], 1) + + def test__worker_process_broad_exception(self): + self.benchmark.my_method = mock.Mock( + side_effect=y_exc.YardstickException) + + duration._worker_process(mock.Mock(), self.benchmark_cls, 'my_method', + self.scenario_cfg, {}, + multiprocessing.Event(), mock.Mock()) + + self._assert_defaults__worker_run_setup_and_teardown() + self._assert_defaults__worker_run_one_iteration() + + def test__worker_process_queue_on_broad_exception(self): + self.benchmark.my_method = self.MyMethod( + side_effect=self.MyMethod.BROAD_EXCEPTION_SIDE_EFFECT) + + queue = multiprocessing.Queue() + timestamp = time.time() + duration._worker_process(queue, self.benchmark_cls, 'my_method', + self.scenario_cfg, {}, + multiprocessing.Event(), mock.Mock()) + time.sleep(0.1) + + self._assert_defaults__worker_run_setup_and_teardown() + self.benchmark.pre_run_wait_time.assert_called_once_with(0) + self.benchmark.post_run_wait_time.assert_called_once_with(0) + + result = queue.get() + self.assertGreater(result['timestamp'], timestamp) + self.assertNotEqual(result['errors'], '') + self.assertEqual(result['data'], {'my_key': 102}) + self.assertEqual(result['sequence'], 1) + + def test__worker_process_benchmark_teardown_on_broad_exception(self): + self.benchmark.teardown = mock.Mock( + side_effect=y_exc.YardstickException) + + with self.assertRaises(SystemExit) as raised: + duration._worker_process(mock.Mock(), self.benchmark_cls, + 'my_method', self.scenario_cfg, {}, + multiprocessing.Event(), mock.Mock()) + self.assertEqual(raised.exception.code, 1) + self._assert_defaults__worker_run_setup_and_teardown() + self._assert_defaults__worker_run_one_iteration() diff --git a/yardstick/tests/unit/network_services/libs/ixia_libs/test_ixnet_api.py b/yardstick/tests/unit/network_services/libs/ixia_libs/test_ixnet_api.py index 2416aee61..e078d70ad 100644 --- a/yardstick/tests/unit/network_services/libs/ixia_libs/test_ixnet_api.py +++ b/yardstick/tests/unit/network_services/libs/ixia_libs/test_ixnet_api.py @@ -16,6 +16,8 @@ import mock import IxNetwork import unittest +from copy import deepcopy + from yardstick.common import exceptions from yardstick.network_services.libs.ixia_libs.ixnet import ixnet_api @@ -31,7 +33,8 @@ TRAFFIC_PARAMETERS = { 'rate': 10000.5, 'rate_unit': 'fps', 'outer_l2': { - 'framesize': {'64B': '25', '256B': '75'} + 'framesize': {'64B': '25', '256B': '75'}, + 'QinQ': None }, 'outer_l3': { 'count': 512, @@ -61,7 +64,8 @@ TRAFFIC_PARAMETERS = { 'rate': 75.2, 'rate_unit': '%', 'outer_l2': { - 'framesize': {'128B': '35', '1024B': '65'} + 'framesize': {'128B': '35', '1024B': '65'}, + 'QinQ': None }, 'outer_l3': { 'count': 1024, @@ -339,6 +343,46 @@ class TestIxNextgen(unittest.TestCase): self.assertEqual(6, len(self.ixnet_gen.ixnet.setMultiAttribute.mock_calls)) self.assertEqual(4, len(mock_update_frame.mock_calls)) + self.ixnet_gen.ixnet.setMultiAttribute.assert_has_calls([ + mock.call('cfg_element/transmissionControl', + '-type', 'continuous', '-duration', 50) + ]) + + def test_update_frame_qinq(self): + with mock.patch.object(self.ixnet_gen, + '_get_config_element_by_flow_group_name', + return_value='cfg_element'), \ + mock.patch.object(self.ixnet_gen, '_update_frame_mac'),\ + mock.patch.object(self.ixnet_gen, '_get_stack_item', + return_value='item'), \ + mock.patch.object(self.ixnet_gen, '_get_field_in_stack_item', + return_value='field'): + + traffic_parameters = deepcopy(TRAFFIC_PARAMETERS) + traffic_parameters[UPLINK]['outer_l2']['QinQ'] = { + 'S-VLAN': {'id': 128, + 'priority': 1, + 'cfi': 0}, + 'C-VLAN': {'id': 512, + 'priority': 0, + 'cfi': 2} + } + + self.ixnet_gen.update_frame(traffic_parameters, 50) + + self.ixnet_gen.ixnet.setMultiAttribute.assert_has_calls([ + mock.call('field', '-auto', 'false', '-singleValue', '0x88a8', + '-fieldValue', '0x88a8', '-valueType', 'singleValue'), + mock.call('field', '-auto', 'false', '-singleValue', 1, + '-fieldValue', 1, '-valueType', 'singleValue'), + mock.call('field', '-auto', 'false', '-singleValue', 128, + '-fieldValue', 128, '-valueType', 'singleValue'), + mock.call('field', '-auto', 'false', '-singleValue', 512, + '-fieldValue', 512, '-valueType', 'singleValue'), + mock.call('field', '-auto', 'false', '-singleValue', 2, + '-fieldValue', 2, '-valueType', 'singleValue') + ], any_order=True) + def test_update_frame_flow_not_present(self): with mock.patch.object( self.ixnet_gen, '_get_config_element_by_flow_group_name', |