diff options
Diffstat (limited to 'tests/unit')
12 files changed, 3535 insertions, 6 deletions
diff --git a/tests/unit/benchmark/runner/test_base.py b/tests/unit/benchmark/runner/test_base.py index 0313ef843..956762c40 100644 --- a/tests/unit/benchmark/runner/test_base.py +++ b/tests/unit/benchmark/runner/test_base.py @@ -17,6 +17,7 @@ import time from mock import mock +from yardstick.benchmark.runners.base import Runner from yardstick.benchmark.runners.iteration import IterationRunner @@ -40,6 +41,12 @@ class RunnerTestCase(unittest.TestCase): actual_result = runner.get_output() self.assertEqual(idle_result, actual_result) + def test__run_benchmark(self): + runner = Runner(mock.Mock()) + + with self.assertRaises(NotImplementedError): + runner._run_benchmark(mock.Mock(), mock.Mock(), mock.Mock(), mock.Mock()) + def main(): unittest.main() diff --git a/tests/unit/benchmark/runner/test_search.py b/tests/unit/benchmark/runner/test_search.py new file mode 100644 index 000000000..9cfe6e154 --- /dev/null +++ b/tests/unit/benchmark/runner/test_search.py @@ -0,0 +1,263 @@ +# Copyright (c) 2017 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +from __future__ import absolute_import +import unittest +from contextlib import contextmanager + +import mock + +STL_MOCKS = { + 'stl': mock.MagicMock(), + 'stl.trex_stl_lib': mock.MagicMock(), + 'stl.trex_stl_lib.base64': mock.MagicMock(), + 'stl.trex_stl_lib.binascii': mock.MagicMock(), + 'stl.trex_stl_lib.collections': mock.MagicMock(), + 'stl.trex_stl_lib.copy': mock.MagicMock(), + 'stl.trex_stl_lib.datetime': mock.MagicMock(), + 'stl.trex_stl_lib.functools': mock.MagicMock(), + 'stl.trex_stl_lib.imp': mock.MagicMock(), + 'stl.trex_stl_lib.inspect': mock.MagicMock(), + 'stl.trex_stl_lib.json': mock.MagicMock(), + 'stl.trex_stl_lib.linecache': mock.MagicMock(), + 'stl.trex_stl_lib.math': mock.MagicMock(), + 'stl.trex_stl_lib.os': mock.MagicMock(), + 'stl.trex_stl_lib.platform': mock.MagicMock(), + 'stl.trex_stl_lib.pprint': mock.MagicMock(), + 'stl.trex_stl_lib.random': mock.MagicMock(), + 'stl.trex_stl_lib.re': mock.MagicMock(), + 'stl.trex_stl_lib.scapy': mock.MagicMock(), + 'stl.trex_stl_lib.socket': mock.MagicMock(), + 'stl.trex_stl_lib.string': mock.MagicMock(), + 'stl.trex_stl_lib.struct': mock.MagicMock(), + 'stl.trex_stl_lib.sys': mock.MagicMock(), + 'stl.trex_stl_lib.threading': mock.MagicMock(), + 'stl.trex_stl_lib.time': mock.MagicMock(), + 'stl.trex_stl_lib.traceback': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_async_client': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_client': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_exceptions': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_ext': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_jsonrpc_client': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_packet_builder_interface': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_packet_builder_scapy': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_port': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_stats': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_streams': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_types': mock.MagicMock(), + 'stl.trex_stl_lib.types': mock.MagicMock(), + 'stl.trex_stl_lib.utils': mock.MagicMock(), + 'stl.trex_stl_lib.utils.argparse': mock.MagicMock(), + 'stl.trex_stl_lib.utils.collections': mock.MagicMock(), + 'stl.trex_stl_lib.utils.common': mock.MagicMock(), + 'stl.trex_stl_lib.utils.json': mock.MagicMock(), + 'stl.trex_stl_lib.utils.os': mock.MagicMock(), + 'stl.trex_stl_lib.utils.parsing_opts': mock.MagicMock(), + 'stl.trex_stl_lib.utils.pwd': mock.MagicMock(), + 'stl.trex_stl_lib.utils.random': mock.MagicMock(), + 'stl.trex_stl_lib.utils.re': mock.MagicMock(), + 'stl.trex_stl_lib.utils.string': mock.MagicMock(), + 'stl.trex_stl_lib.utils.sys': mock.MagicMock(), + 'stl.trex_stl_lib.utils.text_opts': mock.MagicMock(), + 'stl.trex_stl_lib.utils.text_tables': mock.MagicMock(), + 'stl.trex_stl_lib.utils.texttable': mock.MagicMock(), + 'stl.trex_stl_lib.warnings': mock.MagicMock(), + 'stl.trex_stl_lib.yaml': mock.MagicMock(), + 'stl.trex_stl_lib.zlib': mock.MagicMock(), + 'stl.trex_stl_lib.zmq': mock.MagicMock(), +} + +STLClient = mock.MagicMock() +stl_patch = mock.patch.dict("sys.modules", STL_MOCKS) +stl_patch.start() + +if stl_patch: + from yardstick.benchmark.runners.search import SearchRunner + from yardstick.benchmark.runners.search import SearchRunnerHelper + + +class TestSearchRunnerHelper(unittest.TestCase): + + def test___call__(self): + cls = mock.MagicMock() + aborted = mock.MagicMock() + scenario_cfg = { + 'runner': {}, + } + + benchmark = cls() + method = getattr(benchmark, 'my_method') + helper = SearchRunnerHelper(cls, 'my_method', scenario_cfg, {}, aborted) + + with helper.get_benchmark_instance(): + helper() + + self.assertEqual(method.call_count, 1) + + def test___call___error(self): + cls = mock.MagicMock() + aborted = mock.MagicMock() + scenario_cfg = { + 'runner': {}, + } + + helper = SearchRunnerHelper(cls, 'my_method', scenario_cfg, {}, aborted) + + with self.assertRaises(RuntimeError): + helper() + + @mock.patch('yardstick.benchmark.runners.search.time') + def test_is_not_done(self, mock_time): + cls = mock.MagicMock() + aborted = mock.MagicMock() + scenario_cfg = { + 'runner': {}, + } + + mock_time.time.side_effect = range(1000) + + helper = SearchRunnerHelper(cls, 'my_method', scenario_cfg, {}, aborted) + + index = -1 + for index in helper.is_not_done(): + if index >= 10: + break + + self.assertGreaterEqual(index, 10) + + @mock.patch('yardstick.benchmark.runners.search.time') + def test_is_not_done_immediate_stop(self, mock_time): + cls = mock.MagicMock() + aborted = mock.MagicMock() + scenario_cfg = { + 'runner': { + 'run_step': '', + }, + } + + helper = SearchRunnerHelper(cls, 'my_method', scenario_cfg, {}, aborted) + + index = -1 + for index in helper.is_not_done(): + if index >= 10: + break + + self.assertEqual(index, -1) + +class TestSearchRunner(unittest.TestCase): + + def test__worker_run_once(self): + def update(*args): + args[-1].update(data) + + data = { + 'key1': { + 'inner1': 'value1', + 'done': 0, + }, + 'key2': { + 'done': None, + }, + } + + runner = SearchRunner({}) + runner.worker_helper = mock.MagicMock(side_effect=update) + + self.assertFalse(runner._worker_run_once('sequence 1')) + + def test__worker_run_once_done(self): + def update(*args): + args[-1].update(data) + + data = { + 'key1': { + 'inner1': 'value1', + 'done': 0, + }, + 'key2': { + 'done': None, + }, + 'key3': { + 'done': True, + }, + 'key4': [], + 'key5': 'value5', + } + + runner = SearchRunner({}) + runner.worker_helper = mock.MagicMock(side_effect=update) + + self.assertTrue(runner._worker_run_once('sequence 1')) + + def test__worker_run_once_assertion_error_assert(self): + runner = SearchRunner({}) + runner.sla_action = 'assert' + runner.worker_helper = mock.MagicMock(side_effect=AssertionError) + + with self.assertRaises(AssertionError): + runner._worker_run_once('sequence 1') + + def test__worker_run_once_assertion_error_monitor(self): + runner = SearchRunner({}) + runner.sla_action = 'monitor' + runner.worker_helper = mock.MagicMock(side_effect=AssertionError) + + self.assertFalse(runner._worker_run_once('sequence 1')) + + def test__worker_run_once_non_assertion_error_none(self): + runner = SearchRunner({}) + runner.worker_helper = mock.MagicMock(side_effect=RuntimeError) + + self.assertTrue(runner._worker_run_once('sequence 1')) + + def test__worker_run_once_non_assertion_error(self): + runner = SearchRunner({}) + runner.sla_action = 'monitor' + runner.worker_helper = mock.MagicMock(side_effect=RuntimeError) + + self.assertFalse(runner._worker_run_once('sequence 1')) + + def test__worker_run(self): + cls = mock.MagicMock() + scenario_cfg = { + 'runner': {'interval': 0, 'timeout': 1}, + } + + runner = SearchRunner({}) + runner._worker_run_once = mock.MagicMock(side_effect=[0, 0, 1]) + + runner._worker_run(cls, 'my_method', scenario_cfg, {}) + + def test__worker_run_immediate_stop(self): + cls = mock.MagicMock() + scenario_cfg = { + 'runner': { + 'run_step': '', + }, + } + + runner = SearchRunner({}) + runner._worker_run(cls, 'my_method', scenario_cfg, {}) + + @mock.patch('yardstick.benchmark.runners.search.multiprocessing') + def test__run_benchmark(self, mock_multi_process): + cls = mock.MagicMock() + scenario_cfg = { + 'runner': {}, + } + + runner = SearchRunner({}) + runner._run_benchmark(cls, 'my_method', scenario_cfg, {}) + self.assertEqual(mock_multi_process.Process.call_count, 1) diff --git a/tests/unit/common/test_utils.py b/tests/unit/common/test_utils.py index f25e6cc07..663226242 100644 --- a/tests/unit/common/test_utils.py +++ b/tests/unit/common/test_utils.py @@ -268,7 +268,7 @@ address sizes : 46 bits physical, 48 bits virtual power management: """ - socket_map = utils.parse_cpuinfo(cpuinfo) + socket_map = utils.SocketTopology.parse_cpuinfo(cpuinfo) assert sorted(socket_map.keys()) == [0] assert sorted(socket_map[0].keys()) == [2, 3, 4] @@ -356,7 +356,7 @@ address sizes : 39 bits physical, 48 bits virtual power management: """ - socket_map = utils.parse_cpuinfo(cpuinfo) + socket_map = utils.SocketTopology.parse_cpuinfo(cpuinfo) assert sorted(socket_map.keys()) == [0] assert sorted(socket_map[0].keys()) == [1, 2, 3] assert sorted(socket_map[0][1]) == [5] @@ -555,7 +555,7 @@ address sizes : 46 bits physical, 48 bits virtual power management: """ - socket_map = utils.parse_cpuinfo(cpuinfo) + socket_map = utils.SocketTopology.parse_cpuinfo(cpuinfo) assert sorted(socket_map.keys()) == [0, 1] assert sorted(socket_map[0].keys()) == [0, 1, 2] assert sorted(socket_map[1].keys()) == [26, 27, 28] @@ -758,7 +758,7 @@ address sizes : 46 bits physical, 48 bits virtual power management: """ - socket_map = utils.parse_cpuinfo(cpuinfo) + socket_map = utils.SocketTopology.parse_cpuinfo(cpuinfo) processors = socket_map.processors() assert processors == [1, 2, 43, 44, 85, 86, 87] cores = socket_map.cores() diff --git a/tests/unit/network_services/traffic_profile/test_prox_acl.py b/tests/unit/network_services/traffic_profile/test_prox_acl.py new file mode 100644 index 000000000..252c655da --- /dev/null +++ b/tests/unit/network_services/traffic_profile/test_prox_acl.py @@ -0,0 +1,124 @@ +# Copyright (c) 2017 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +from __future__ import absolute_import +import unittest + +import mock + +STL_MOCKS = { + 'stl': mock.MagicMock(), + 'stl.trex_stl_lib': mock.MagicMock(), + 'stl.trex_stl_lib.base64': mock.MagicMock(), + 'stl.trex_stl_lib.binascii': mock.MagicMock(), + 'stl.trex_stl_lib.collections': mock.MagicMock(), + 'stl.trex_stl_lib.copy': mock.MagicMock(), + 'stl.trex_stl_lib.datetime': mock.MagicMock(), + 'stl.trex_stl_lib.functools': mock.MagicMock(), + 'stl.trex_stl_lib.imp': mock.MagicMock(), + 'stl.trex_stl_lib.inspect': mock.MagicMock(), + 'stl.trex_stl_lib.json': mock.MagicMock(), + 'stl.trex_stl_lib.linecache': mock.MagicMock(), + 'stl.trex_stl_lib.math': mock.MagicMock(), + 'stl.trex_stl_lib.os': mock.MagicMock(), + 'stl.trex_stl_lib.platform': mock.MagicMock(), + 'stl.trex_stl_lib.pprint': mock.MagicMock(), + 'stl.trex_stl_lib.random': mock.MagicMock(), + 'stl.trex_stl_lib.re': mock.MagicMock(), + 'stl.trex_stl_lib.scapy': mock.MagicMock(), + 'stl.trex_stl_lib.socket': mock.MagicMock(), + 'stl.trex_stl_lib.string': mock.MagicMock(), + 'stl.trex_stl_lib.struct': mock.MagicMock(), + 'stl.trex_stl_lib.sys': mock.MagicMock(), + 'stl.trex_stl_lib.threading': mock.MagicMock(), + 'stl.trex_stl_lib.time': mock.MagicMock(), + 'stl.trex_stl_lib.traceback': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_async_client': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_client': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_exceptions': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_ext': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_jsonrpc_client': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_packet_builder_interface': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_packet_builder_scapy': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_port': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_stats': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_streams': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_types': mock.MagicMock(), + 'stl.trex_stl_lib.types': mock.MagicMock(), + 'stl.trex_stl_lib.utils': mock.MagicMock(), + 'stl.trex_stl_lib.utils.argparse': mock.MagicMock(), + 'stl.trex_stl_lib.utils.collections': mock.MagicMock(), + 'stl.trex_stl_lib.utils.common': mock.MagicMock(), + 'stl.trex_stl_lib.utils.json': mock.MagicMock(), + 'stl.trex_stl_lib.utils.os': mock.MagicMock(), + 'stl.trex_stl_lib.utils.parsing_opts': mock.MagicMock(), + 'stl.trex_stl_lib.utils.pwd': mock.MagicMock(), + 'stl.trex_stl_lib.utils.random': mock.MagicMock(), + 'stl.trex_stl_lib.utils.re': mock.MagicMock(), + 'stl.trex_stl_lib.utils.string': mock.MagicMock(), + 'stl.trex_stl_lib.utils.sys': mock.MagicMock(), + 'stl.trex_stl_lib.utils.text_opts': mock.MagicMock(), + 'stl.trex_stl_lib.utils.text_tables': mock.MagicMock(), + 'stl.trex_stl_lib.utils.texttable': mock.MagicMock(), + 'stl.trex_stl_lib.warnings': mock.MagicMock(), + 'stl.trex_stl_lib.yaml': mock.MagicMock(), + 'stl.trex_stl_lib.zlib': mock.MagicMock(), + 'stl.trex_stl_lib.zmq': mock.MagicMock(), +} + +STLClient = mock.MagicMock() +stl_patch = mock.patch.dict("sys.modules", STL_MOCKS) +stl_patch.start() + +if stl_patch: + from yardstick.network_services.traffic_profile.prox_ACL import ProxACLProfile + from yardstick.network_services.vnf_generic.vnf.prox_helpers import ProxTestDataTuple + + +class TestProxRampProfile(unittest.TestCase): + + def test_run_test_with_pkt_size(self): + tp_config = { + 'traffic_profile': { + 'upper_bound': 100.0, + }, + } + + success_tuple = ProxTestDataTuple(10.0, 1, 2, 3, 4, [5.1, 5.2, 5.3], 995, 1000, 123.4) + fail_tuple = ProxTestDataTuple(10.0, 1, 2, 3, 4, [5.6, 5.7, 5.8], 850, 1000, 123.4) + + traffic_gen = mock.MagicMock() + traffic_gen.resource_helper.run_test.side_effect = [ + success_tuple, + success_tuple, + success_tuple, + fail_tuple, + success_tuple, + fail_tuple, + fail_tuple, + fail_tuple, + ] + + fill_values = [1, 2, 3, 4, RuntimeError] + + profile = ProxACLProfile(tp_config) + profile.fill_samples = fill_samples = mock.MagicMock(side_effect=fill_values) + profile.queue = mock.MagicMock() + + with self.assertRaises(RuntimeError): + profile.run_test_with_pkt_size(traffic_gen, 128, 30) + + self.assertEqual(traffic_gen.resource_helper.run_test.call_count, 5) + self.assertEqual(fill_samples.call_count, 5) diff --git a/tests/unit/network_services/traffic_profile/test_prox_binsearch.py b/tests/unit/network_services/traffic_profile/test_prox_binsearch.py new file mode 100644 index 000000000..74e6121a7 --- /dev/null +++ b/tests/unit/network_services/traffic_profile/test_prox_binsearch.py @@ -0,0 +1,151 @@ +# Copyright (c) 2017 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +from __future__ import absolute_import +import unittest + +import mock + +STL_MOCKS = { + 'stl': mock.MagicMock(), + 'stl.trex_stl_lib': mock.MagicMock(), + 'stl.trex_stl_lib.base64': mock.MagicMock(), + 'stl.trex_stl_lib.binascii': mock.MagicMock(), + 'stl.trex_stl_lib.collections': mock.MagicMock(), + 'stl.trex_stl_lib.copy': mock.MagicMock(), + 'stl.trex_stl_lib.datetime': mock.MagicMock(), + 'stl.trex_stl_lib.functools': mock.MagicMock(), + 'stl.trex_stl_lib.imp': mock.MagicMock(), + 'stl.trex_stl_lib.inspect': mock.MagicMock(), + 'stl.trex_stl_lib.json': mock.MagicMock(), + 'stl.trex_stl_lib.linecache': mock.MagicMock(), + 'stl.trex_stl_lib.math': mock.MagicMock(), + 'stl.trex_stl_lib.os': mock.MagicMock(), + 'stl.trex_stl_lib.platform': mock.MagicMock(), + 'stl.trex_stl_lib.pprint': mock.MagicMock(), + 'stl.trex_stl_lib.random': mock.MagicMock(), + 'stl.trex_stl_lib.re': mock.MagicMock(), + 'stl.trex_stl_lib.scapy': mock.MagicMock(), + 'stl.trex_stl_lib.socket': mock.MagicMock(), + 'stl.trex_stl_lib.string': mock.MagicMock(), + 'stl.trex_stl_lib.struct': mock.MagicMock(), + 'stl.trex_stl_lib.sys': mock.MagicMock(), + 'stl.trex_stl_lib.threading': mock.MagicMock(), + 'stl.trex_stl_lib.time': mock.MagicMock(), + 'stl.trex_stl_lib.traceback': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_async_client': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_client': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_exceptions': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_ext': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_jsonrpc_client': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_packet_builder_interface': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_packet_builder_scapy': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_port': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_stats': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_streams': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_types': mock.MagicMock(), + 'stl.trex_stl_lib.types': mock.MagicMock(), + 'stl.trex_stl_lib.utils': mock.MagicMock(), + 'stl.trex_stl_lib.utils.argparse': mock.MagicMock(), + 'stl.trex_stl_lib.utils.collections': mock.MagicMock(), + 'stl.trex_stl_lib.utils.common': mock.MagicMock(), + 'stl.trex_stl_lib.utils.json': mock.MagicMock(), + 'stl.trex_stl_lib.utils.os': mock.MagicMock(), + 'stl.trex_stl_lib.utils.parsing_opts': mock.MagicMock(), + 'stl.trex_stl_lib.utils.pwd': mock.MagicMock(), + 'stl.trex_stl_lib.utils.random': mock.MagicMock(), + 'stl.trex_stl_lib.utils.re': mock.MagicMock(), + 'stl.trex_stl_lib.utils.string': mock.MagicMock(), + 'stl.trex_stl_lib.utils.sys': mock.MagicMock(), + 'stl.trex_stl_lib.utils.text_opts': mock.MagicMock(), + 'stl.trex_stl_lib.utils.text_tables': mock.MagicMock(), + 'stl.trex_stl_lib.utils.texttable': mock.MagicMock(), + 'stl.trex_stl_lib.warnings': mock.MagicMock(), + 'stl.trex_stl_lib.yaml': mock.MagicMock(), + 'stl.trex_stl_lib.zlib': mock.MagicMock(), + 'stl.trex_stl_lib.zmq': mock.MagicMock(), +} + +STLClient = mock.MagicMock() +stl_patch = mock.patch.dict("sys.modules", STL_MOCKS) +stl_patch.start() + +if stl_patch: + from yardstick.network_services.vnf_generic.vnf.prox_helpers import ProxTestDataTuple + from yardstick.network_services.traffic_profile.prox_binsearch import ProxBinSearchProfile + + +class TestProxBinSearchProfile(unittest.TestCase): + + def test_execute_1(self): + def target(*args, **kwargs): + runs.append(args[2]) + if args[2] < 0 or args[2] > 100: + raise RuntimeError(' '.join([str(args), str(runs)])) + if args[2] > 75.0: + return fail_tuple + return success_tuple + + tp_config = { + 'traffic_profile': { + 'packet_sizes': [200], + }, + } + + runs = [] + success_tuple = ProxTestDataTuple(10.0, 1, 2, 3, 4, [5.1, 5.2, 5.3], 995, 1000, 123.4) + fail_tuple = ProxTestDataTuple(10.0, 1, 2, 3, 4, [5.6, 5.7, 5.8], 850, 1000, 123.4) + + traffic_generator = mock.MagicMock() + traffic_generator.resource_helper.run_test = target + + profile = ProxBinSearchProfile(tp_config) + profile.init(mock.MagicMock()) + + profile.execute(traffic_generator) + self.assertEqual(round(profile.current_lower, 2), 74.69) + self.assertEqual(round(profile.current_upper, 2), 75.39) + self.assertEqual(len(runs), 8) + + def test_execute_2(self): + def target(*args, **kwargs): + runs.append(args[2]) + if args[2] < 0 or args[2] > 100: + raise RuntimeError(' '.join([str(args), str(runs)])) + if args[2] > 25.0: + return fail_tuple + return success_tuple + + tp_config = { + 'traffic_profile': { + 'packet_sizes': [200], + 'test_precision': 2.0, + }, + } + + runs = [] + success_tuple = ProxTestDataTuple(10.0, 1, 2, 3, 4, [5.1, 5.2, 5.3], 995, 1000, 123.4) + fail_tuple = ProxTestDataTuple(10.0, 1, 2, 3, 4, [5.6, 5.7, 5.8], 850, 1000, 123.4) + + traffic_generator = mock.MagicMock() + traffic_generator.resource_helper.run_test = target + + profile = ProxBinSearchProfile(tp_config) + profile.init(mock.MagicMock()) + + profile.execute(traffic_generator) + self.assertEqual(round(profile.current_lower, 2), 24.06) + self.assertEqual(round(profile.current_upper, 2), 25.47) + self.assertEqual(len(runs), 7) diff --git a/tests/unit/network_services/traffic_profile/test_prox_profile.py b/tests/unit/network_services/traffic_profile/test_prox_profile.py new file mode 100644 index 000000000..a2ad0333f --- /dev/null +++ b/tests/unit/network_services/traffic_profile/test_prox_profile.py @@ -0,0 +1,165 @@ +# Copyright (c) 2017 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +from __future__ import absolute_import +import unittest + +import mock + +STL_MOCKS = { + 'stl': mock.MagicMock(), + 'stl.trex_stl_lib': mock.MagicMock(), + 'stl.trex_stl_lib.base64': mock.MagicMock(), + 'stl.trex_stl_lib.binascii': mock.MagicMock(), + 'stl.trex_stl_lib.collections': mock.MagicMock(), + 'stl.trex_stl_lib.copy': mock.MagicMock(), + 'stl.trex_stl_lib.datetime': mock.MagicMock(), + 'stl.trex_stl_lib.functools': mock.MagicMock(), + 'stl.trex_stl_lib.imp': mock.MagicMock(), + 'stl.trex_stl_lib.inspect': mock.MagicMock(), + 'stl.trex_stl_lib.json': mock.MagicMock(), + 'stl.trex_stl_lib.linecache': mock.MagicMock(), + 'stl.trex_stl_lib.math': mock.MagicMock(), + 'stl.trex_stl_lib.os': mock.MagicMock(), + 'stl.trex_stl_lib.platform': mock.MagicMock(), + 'stl.trex_stl_lib.pprint': mock.MagicMock(), + 'stl.trex_stl_lib.random': mock.MagicMock(), + 'stl.trex_stl_lib.re': mock.MagicMock(), + 'stl.trex_stl_lib.scapy': mock.MagicMock(), + 'stl.trex_stl_lib.socket': mock.MagicMock(), + 'stl.trex_stl_lib.string': mock.MagicMock(), + 'stl.trex_stl_lib.struct': mock.MagicMock(), + 'stl.trex_stl_lib.sys': mock.MagicMock(), + 'stl.trex_stl_lib.threading': mock.MagicMock(), + 'stl.trex_stl_lib.time': mock.MagicMock(), + 'stl.trex_stl_lib.traceback': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_async_client': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_client': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_exceptions': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_ext': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_jsonrpc_client': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_packet_builder_interface': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_packet_builder_scapy': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_port': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_stats': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_streams': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_types': mock.MagicMock(), + 'stl.trex_stl_lib.types': mock.MagicMock(), + 'stl.trex_stl_lib.utils': mock.MagicMock(), + 'stl.trex_stl_lib.utils.argparse': mock.MagicMock(), + 'stl.trex_stl_lib.utils.collections': mock.MagicMock(), + 'stl.trex_stl_lib.utils.common': mock.MagicMock(), + 'stl.trex_stl_lib.utils.json': mock.MagicMock(), + 'stl.trex_stl_lib.utils.os': mock.MagicMock(), + 'stl.trex_stl_lib.utils.parsing_opts': mock.MagicMock(), + 'stl.trex_stl_lib.utils.pwd': mock.MagicMock(), + 'stl.trex_stl_lib.utils.random': mock.MagicMock(), + 'stl.trex_stl_lib.utils.re': mock.MagicMock(), + 'stl.trex_stl_lib.utils.string': mock.MagicMock(), + 'stl.trex_stl_lib.utils.sys': mock.MagicMock(), + 'stl.trex_stl_lib.utils.text_opts': mock.MagicMock(), + 'stl.trex_stl_lib.utils.text_tables': mock.MagicMock(), + 'stl.trex_stl_lib.utils.texttable': mock.MagicMock(), + 'stl.trex_stl_lib.warnings': mock.MagicMock(), + 'stl.trex_stl_lib.yaml': mock.MagicMock(), + 'stl.trex_stl_lib.zlib': mock.MagicMock(), + 'stl.trex_stl_lib.zmq': mock.MagicMock(), +} + +STLClient = mock.MagicMock() +stl_patch = mock.patch.dict("sys.modules", STL_MOCKS) +stl_patch.start() + +if stl_patch: + from yardstick.network_services.traffic_profile.prox_profile import ProxProfile + + +class TestProxProfile(unittest.TestCase): + + def test_fill_samples(self): + samples = {} + traffic_generator = mock.MagicMock() + traffic_generator.vpci_if_name_ascending = [ + ['id1', 'name1'], + ['id2', 'name2'], + ] + + traffic_generator.resource_helper.sut.port_stats.side_effect = [ + list(range(12)), + list(range(10, 22)), + ] + + expected = { + 'name1': { + 'in_packets': 6, + 'out_packets': 7, + }, + 'name2': { + 'in_packets': 16, + 'out_packets': 17, + }, + } + ProxProfile.fill_samples(samples, traffic_generator) + self.assertDictEqual(samples, expected) + + def test_init(self): + tp_config = { + 'traffic_profile': {}, + } + + profile = ProxProfile(tp_config) + profile.init(234) + self.assertEqual(profile.queue, 234) + + def test_execute(self): + packet_sizes = [ + 10, + 100, + 1000, + ] + tp_config = { + 'traffic_profile': { + 'packet_sizes': packet_sizes, + }, + } + + traffic_generator = mock.MagicMock() + profile = ProxProfile(tp_config) + + self.assertFalse(profile.done) + for _ in packet_sizes: + with self.assertRaises(NotImplementedError): + profile.execute(traffic_generator) + + self.assertIsNone(profile.execute(traffic_generator)) + + def test_bounds_iterator(self): + tp_config = { + 'traffic_profile': {}, + } + + profile = ProxProfile(tp_config) + value = 0.0 + for value in profile.bounds_iterator(): + pass + + self.assertEqual(value, 100.0) + + mock_logger = mock.MagicMock() + for _ in profile.bounds_iterator(mock_logger): + pass + + self.assertEqual(mock_logger.debug.call_count, 1) + self.assertEqual(mock_logger.info.call_count, 10) diff --git a/tests/unit/network_services/traffic_profile/test_prox_ramp.py b/tests/unit/network_services/traffic_profile/test_prox_ramp.py new file mode 100644 index 000000000..19e6ff8cb --- /dev/null +++ b/tests/unit/network_services/traffic_profile/test_prox_ramp.py @@ -0,0 +1,144 @@ +# Copyright (c) 2017 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +from __future__ import absolute_import +import unittest + +import mock + +STL_MOCKS = { + 'stl': mock.MagicMock(), + 'stl.trex_stl_lib': mock.MagicMock(), + 'stl.trex_stl_lib.base64': mock.MagicMock(), + 'stl.trex_stl_lib.binascii': mock.MagicMock(), + 'stl.trex_stl_lib.collections': mock.MagicMock(), + 'stl.trex_stl_lib.copy': mock.MagicMock(), + 'stl.trex_stl_lib.datetime': mock.MagicMock(), + 'stl.trex_stl_lib.functools': mock.MagicMock(), + 'stl.trex_stl_lib.imp': mock.MagicMock(), + 'stl.trex_stl_lib.inspect': mock.MagicMock(), + 'stl.trex_stl_lib.json': mock.MagicMock(), + 'stl.trex_stl_lib.linecache': mock.MagicMock(), + 'stl.trex_stl_lib.math': mock.MagicMock(), + 'stl.trex_stl_lib.os': mock.MagicMock(), + 'stl.trex_stl_lib.platform': mock.MagicMock(), + 'stl.trex_stl_lib.pprint': mock.MagicMock(), + 'stl.trex_stl_lib.random': mock.MagicMock(), + 'stl.trex_stl_lib.re': mock.MagicMock(), + 'stl.trex_stl_lib.scapy': mock.MagicMock(), + 'stl.trex_stl_lib.socket': mock.MagicMock(), + 'stl.trex_stl_lib.string': mock.MagicMock(), + 'stl.trex_stl_lib.struct': mock.MagicMock(), + 'stl.trex_stl_lib.sys': mock.MagicMock(), + 'stl.trex_stl_lib.threading': mock.MagicMock(), + 'stl.trex_stl_lib.time': mock.MagicMock(), + 'stl.trex_stl_lib.traceback': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_async_client': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_client': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_exceptions': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_ext': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_jsonrpc_client': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_packet_builder_interface': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_packet_builder_scapy': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_port': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_stats': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_streams': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_types': mock.MagicMock(), + 'stl.trex_stl_lib.types': mock.MagicMock(), + 'stl.trex_stl_lib.utils': mock.MagicMock(), + 'stl.trex_stl_lib.utils.argparse': mock.MagicMock(), + 'stl.trex_stl_lib.utils.collections': mock.MagicMock(), + 'stl.trex_stl_lib.utils.common': mock.MagicMock(), + 'stl.trex_stl_lib.utils.json': mock.MagicMock(), + 'stl.trex_stl_lib.utils.os': mock.MagicMock(), + 'stl.trex_stl_lib.utils.parsing_opts': mock.MagicMock(), + 'stl.trex_stl_lib.utils.pwd': mock.MagicMock(), + 'stl.trex_stl_lib.utils.random': mock.MagicMock(), + 'stl.trex_stl_lib.utils.re': mock.MagicMock(), + 'stl.trex_stl_lib.utils.string': mock.MagicMock(), + 'stl.trex_stl_lib.utils.sys': mock.MagicMock(), + 'stl.trex_stl_lib.utils.text_opts': mock.MagicMock(), + 'stl.trex_stl_lib.utils.text_tables': mock.MagicMock(), + 'stl.trex_stl_lib.utils.texttable': mock.MagicMock(), + 'stl.trex_stl_lib.warnings': mock.MagicMock(), + 'stl.trex_stl_lib.yaml': mock.MagicMock(), + 'stl.trex_stl_lib.zlib': mock.MagicMock(), + 'stl.trex_stl_lib.zmq': mock.MagicMock(), +} + +STLClient = mock.MagicMock() +stl_patch = mock.patch.dict("sys.modules", STL_MOCKS) +stl_patch.start() + +if stl_patch: + from yardstick.network_services.traffic_profile.prox_ramp import ProxRampProfile + from yardstick.network_services.vnf_generic.vnf.prox_helpers import ProxTestDataTuple + + +class TestProxRampProfile(unittest.TestCase): + + def test_run_test_with_pkt_size(self): + tp_config = { + 'traffic_profile': { + 'lower_bound': 10.0, + 'upper_bound': 100.0, + 'step_value': 10.0, + }, + } + + success_tuple = ProxTestDataTuple(10.0, 1, 2, 3, 4, [5.1, 5.2, 5.3], 995, 1000, 123.4) + + traffic_gen = mock.MagicMock() + traffic_gen.resource_helper.run_test.return_value = success_tuple + + profile = ProxRampProfile(tp_config) + profile.fill_samples = fill_samples = mock.MagicMock() + profile.queue = mock.MagicMock() + + profile.run_test_with_pkt_size(traffic_gen, 128, 30) + self.assertEqual(traffic_gen.resource_helper.run_test.call_count, 10) + self.assertEqual(fill_samples.call_count, 10) + + def test_run_test_with_pkt_size_with_fail(self): + tp_config = { + 'traffic_profile': { + 'lower_bound': 10.0, + 'upper_bound': 100.0, + 'step_value': 10.0, + }, + } + + success_tuple = ProxTestDataTuple(10.0, 1, 2, 3, 4, [5.1, 5.2, 5.3], 995, 1000, 123.4) + fail_tuple = ProxTestDataTuple(10.0, 1, 2, 3, 4, [5.6, 5.7, 5.8], 850, 1000, 123.4) + + traffic_gen = mock.MagicMock() + traffic_gen.resource_helper.run_test.side_effect = [ + success_tuple, + success_tuple, + success_tuple, + fail_tuple, + success_tuple, + fail_tuple, + fail_tuple, + fail_tuple, + ] + + profile = ProxRampProfile(tp_config) + profile.fill_samples = fill_samples = mock.MagicMock() + profile.queue = mock.MagicMock() + + profile.run_test_with_pkt_size(traffic_gen, 128, 30) + self.assertEqual(traffic_gen.resource_helper.run_test.call_count, 4) + self.assertEqual(fill_samples.call_count, 3) diff --git a/tests/unit/network_services/vnf_generic/vnf/test_base.py b/tests/unit/network_services/vnf_generic/vnf/test_base.py index e4f4450ce..8a5d836e0 100644 --- a/tests/unit/network_services/vnf_generic/vnf/test_base.py +++ b/tests/unit/network_services/vnf_generic/vnf/test_base.py @@ -59,8 +59,9 @@ def mock_ssh(ssh, spec=None, exec_result=_LOCAL_OBJECT, run_result=_LOCAL_OBJECT run_result = 0, "", "" ssh_mock = mock.Mock(autospec=spec) - ssh_mock.execute = mock.Mock(return_value=exec_result) - ssh_mock.run = mock.Mock(return_value=run_result) + ssh_mock._get_client.return_value = mock.Mock() + ssh_mock.execute.return_value = exec_result + ssh_mock.run.return_value = run_result ssh.from_node.return_value = ssh_mock diff --git a/tests/unit/network_services/vnf_generic/vnf/test_iniparser.py b/tests/unit/network_services/vnf_generic/vnf/test_iniparser.py new file mode 100644 index 000000000..53481ddd0 --- /dev/null +++ b/tests/unit/network_services/vnf_generic/vnf/test_iniparser.py @@ -0,0 +1,249 @@ +# Copyright (c) 2017 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +from __future__ import absolute_import +import unittest +from contextlib import contextmanager + +import mock + +STL_MOCKS = { + 'stl': mock.MagicMock(), + 'stl.trex_stl_lib': mock.MagicMock(), + 'stl.trex_stl_lib.base64': mock.MagicMock(), + 'stl.trex_stl_lib.binascii': mock.MagicMock(), + 'stl.trex_stl_lib.collections': mock.MagicMock(), + 'stl.trex_stl_lib.copy': mock.MagicMock(), + 'stl.trex_stl_lib.datetime': mock.MagicMock(), + 'stl.trex_stl_lib.functools': mock.MagicMock(), + 'stl.trex_stl_lib.imp': mock.MagicMock(), + 'stl.trex_stl_lib.inspect': mock.MagicMock(), + 'stl.trex_stl_lib.json': mock.MagicMock(), + 'stl.trex_stl_lib.linecache': mock.MagicMock(), + 'stl.trex_stl_lib.math': mock.MagicMock(), + 'stl.trex_stl_lib.os': mock.MagicMock(), + 'stl.trex_stl_lib.platform': mock.MagicMock(), + 'stl.trex_stl_lib.pprint': mock.MagicMock(), + 'stl.trex_stl_lib.random': mock.MagicMock(), + 'stl.trex_stl_lib.re': mock.MagicMock(), + 'stl.trex_stl_lib.scapy': mock.MagicMock(), + 'stl.trex_stl_lib.socket': mock.MagicMock(), + 'stl.trex_stl_lib.string': mock.MagicMock(), + 'stl.trex_stl_lib.struct': mock.MagicMock(), + 'stl.trex_stl_lib.sys': mock.MagicMock(), + 'stl.trex_stl_lib.threading': mock.MagicMock(), + 'stl.trex_stl_lib.time': mock.MagicMock(), + 'stl.trex_stl_lib.traceback': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_async_client': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_client': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_exceptions': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_ext': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_jsonrpc_client': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_packet_builder_interface': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_packet_builder_scapy': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_port': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_stats': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_streams': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_types': mock.MagicMock(), + 'stl.trex_stl_lib.types': mock.MagicMock(), + 'stl.trex_stl_lib.utils': mock.MagicMock(), + 'stl.trex_stl_lib.utils.argparse': mock.MagicMock(), + 'stl.trex_stl_lib.utils.collections': mock.MagicMock(), + 'stl.trex_stl_lib.utils.common': mock.MagicMock(), + 'stl.trex_stl_lib.utils.json': mock.MagicMock(), + 'stl.trex_stl_lib.utils.os': mock.MagicMock(), + 'stl.trex_stl_lib.utils.parsing_opts': mock.MagicMock(), + 'stl.trex_stl_lib.utils.pwd': mock.MagicMock(), + 'stl.trex_stl_lib.utils.random': mock.MagicMock(), + 'stl.trex_stl_lib.utils.re': mock.MagicMock(), + 'stl.trex_stl_lib.utils.string': mock.MagicMock(), + 'stl.trex_stl_lib.utils.sys': mock.MagicMock(), + 'stl.trex_stl_lib.utils.text_opts': mock.MagicMock(), + 'stl.trex_stl_lib.utils.text_tables': mock.MagicMock(), + 'stl.trex_stl_lib.utils.texttable': mock.MagicMock(), + 'stl.trex_stl_lib.warnings': mock.MagicMock(), + 'stl.trex_stl_lib.yaml': mock.MagicMock(), + 'stl.trex_stl_lib.zlib': mock.MagicMock(), + 'stl.trex_stl_lib.zmq': mock.MagicMock(), +} + +STLClient = mock.MagicMock() +stl_patch = mock.patch.dict("sys.modules", STL_MOCKS) +stl_patch.start() + +if stl_patch: + from yardstick.network_services.vnf_generic.vnf.iniparser import ParseError + from yardstick.network_services.vnf_generic.vnf.iniparser import BaseParser + from yardstick.network_services.vnf_generic.vnf.iniparser import ConfigParser + +PARSE_TEXT_1 = """\ + +[section1] +key1=value1 +list1: value2 + value3 + value4 +key2="double quote value" +key3='single quote value' ; comment here +key4= + +[section2] +# here is a comment line +list2: value5 +; another comment line +key5= +""" + +PARSE_TEXT_2 = """\ +[section1] +list1 = item1 + item2 + ended by eof""" + +PARSE_TEXT_BAD_1 = """\ +key1=value1 +""" + +PARSE_TEXT_BAD_2 = """\ +[section1 +""" + +PARSE_TEXT_BAD_3 = """\ +[] +""" + +PARSE_TEXT_BAD_4 = """\ +[section1] +no list or key +""" + +PARSE_TEXT_BAD_5 = """\ +[section1] + bad continuation +""" + +PARSE_TEXT_BAD_6 = """\ +[section1] +=value with no key +""" + + +class TestParseError(unittest.TestCase): + + def test___str__(self): + error = ParseError('a', 2, 'c') + self.assertEqual(str(error), "at line 2, a: 'c'") + + +class TestBaseParser(unittest.TestCase): + + @staticmethod + def make_open(text_blob): + @contextmanager + def internal_open(*args, **kwargs): + yield text_blob.split('\n') + + return internal_open + + @mock.patch('yardstick.network_services.vnf_generic.vnf.iniparser.open') + def test_parse_none(self, mock_open): + mock_open.side_effect = self.make_open('') + + parser = BaseParser() + + self.assertIsNone(parser.parse()) + + def test_not_implemented_methods(self): + parser = BaseParser() + + with self.assertRaises(NotImplementedError): + parser.assignment('key', 'value') + + with self.assertRaises(NotImplementedError): + parser.new_section('section') + + +class TestConfigParser(unittest.TestCase): + + @staticmethod + def make_open(text_blob): + @contextmanager + def internal_open(*args, **kwargs): + yield text_blob.split('\n') + + return internal_open + + @mock.patch('yardstick.network_services.vnf_generic.vnf.iniparser.open') + def test_parse(self, mock_open): + mock_open.side_effect = self.make_open(PARSE_TEXT_1) + + config_parser = ConfigParser('my_file', {}) + config_parser.parse() + + expected = { + 'section1': [ + ['key1', 'value1'], + ['list1', 'value2\nvalue3\nvalue4'], + ['key2', 'double quote value'], + ['key3', 'single quote value'], + ['key4', ''], + ], + 'section2': [ + ['list2', 'value5'], + ['key5', ''], + ], + } + + self.assertDictEqual(config_parser.sections, expected) + + @mock.patch('yardstick.network_services.vnf_generic.vnf.iniparser.open') + def test_parse_2(self, mock_open): + mock_open.side_effect = self.make_open(PARSE_TEXT_2) + + config_parser = ConfigParser('my_file', {}) + config_parser.parse() + + expected = { + 'section1': [ + ['list1', 'item1\nitem2\nended by eof'], + ], + } + + self.assertDictEqual(config_parser.sections, expected) + + @mock.patch('yardstick.network_services.vnf_generic.vnf.iniparser.open') + def test_parse_negative(self, mock_open): + bad_text_dict = { + 'no section': PARSE_TEXT_BAD_1, + 'incomplete section': PARSE_TEXT_BAD_2, + 'empty section name': PARSE_TEXT_BAD_3, + 'no list or key': PARSE_TEXT_BAD_4, + 'bad_continuation': PARSE_TEXT_BAD_5, + 'value with no key': PARSE_TEXT_BAD_6, + } + + for bad_reason, bad_text in bad_text_dict.items(): + mock_open.side_effect = self.make_open(bad_text) + + config_parser = ConfigParser('my_file', {}) + + try: + # TODO: replace with assertRaises, when the UT framework supports + # advanced messages when exceptions fail to occur + config_parser.parse() + except ParseError: + pass + else: + self.fail('\n'.join([bad_reason, bad_text, str(config_parser.sections)])) diff --git a/tests/unit/network_services/vnf_generic/vnf/test_prox_helpers.py b/tests/unit/network_services/vnf_generic/vnf/test_prox_helpers.py new file mode 100644 index 000000000..90ec3f374 --- /dev/null +++ b/tests/unit/network_services/vnf_generic/vnf/test_prox_helpers.py @@ -0,0 +1,1414 @@ +#!/usr/bin/env python + +# Copyright (c) 2016-2017 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +from __future__ import absolute_import + +import os +import socket +import unittest +from collections import OrderedDict +from itertools import repeat, chain +from contextlib import contextmanager + +import mock + + +STL_MOCKS = { + 'stl': mock.MagicMock(), + 'stl.trex_stl_lib': mock.MagicMock(), + 'stl.trex_stl_lib.base64': mock.MagicMock(), + 'stl.trex_stl_lib.binascii': mock.MagicMock(), + 'stl.trex_stl_lib.collections': mock.MagicMock(), + 'stl.trex_stl_lib.copy': mock.MagicMock(), + 'stl.trex_stl_lib.datetime': mock.MagicMock(), + 'stl.trex_stl_lib.functools': mock.MagicMock(), + 'stl.trex_stl_lib.imp': mock.MagicMock(), + 'stl.trex_stl_lib.inspect': mock.MagicMock(), + 'stl.trex_stl_lib.json': mock.MagicMock(), + 'stl.trex_stl_lib.linecache': mock.MagicMock(), + 'stl.trex_stl_lib.math': mock.MagicMock(), + 'stl.trex_stl_lib.os': mock.MagicMock(), + 'stl.trex_stl_lib.platform': mock.MagicMock(), + 'stl.trex_stl_lib.pprint': mock.MagicMock(), + 'stl.trex_stl_lib.random': mock.MagicMock(), + 'stl.trex_stl_lib.re': mock.MagicMock(), + 'stl.trex_stl_lib.scapy': mock.MagicMock(), + 'stl.trex_stl_lib.socket': mock.MagicMock(), + 'stl.trex_stl_lib.string': mock.MagicMock(), + 'stl.trex_stl_lib.struct': mock.MagicMock(), + 'stl.trex_stl_lib.sys': mock.MagicMock(), + 'stl.trex_stl_lib.threading': mock.MagicMock(), + 'stl.trex_stl_lib.time': mock.MagicMock(), + 'stl.trex_stl_lib.traceback': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_async_client': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_client': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_exceptions': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_ext': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_jsonrpc_client': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_packet_builder_interface': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_packet_builder_scapy': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_port': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_stats': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_streams': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_types': mock.MagicMock(), + 'stl.trex_stl_lib.types': mock.MagicMock(), + 'stl.trex_stl_lib.utils': mock.MagicMock(), + 'stl.trex_stl_lib.utils.argparse': mock.MagicMock(), + 'stl.trex_stl_lib.utils.collections': mock.MagicMock(), + 'stl.trex_stl_lib.utils.common': mock.MagicMock(), + 'stl.trex_stl_lib.utils.json': mock.MagicMock(), + 'stl.trex_stl_lib.utils.os': mock.MagicMock(), + 'stl.trex_stl_lib.utils.parsing_opts': mock.MagicMock(), + 'stl.trex_stl_lib.utils.pwd': mock.MagicMock(), + 'stl.trex_stl_lib.utils.random': mock.MagicMock(), + 'stl.trex_stl_lib.utils.re': mock.MagicMock(), + 'stl.trex_stl_lib.utils.string': mock.MagicMock(), + 'stl.trex_stl_lib.utils.sys': mock.MagicMock(), + 'stl.trex_stl_lib.utils.text_opts': mock.MagicMock(), + 'stl.trex_stl_lib.utils.text_tables': mock.MagicMock(), + 'stl.trex_stl_lib.utils.texttable': mock.MagicMock(), + 'stl.trex_stl_lib.warnings': mock.MagicMock(), + 'stl.trex_stl_lib.yaml': mock.MagicMock(), + 'stl.trex_stl_lib.zlib': mock.MagicMock(), + 'stl.trex_stl_lib.zmq': mock.MagicMock(), +} + +STLClient = mock.MagicMock() +stl_patch = mock.patch.dict("sys.modules", STL_MOCKS) +stl_patch.start() + +if stl_patch: + from yardstick.network_services.vnf_generic.vnf.sample_vnf import ScenarioHelper + from yardstick.network_services.vnf_generic.vnf.prox_helpers import ProxSocketHelper + from yardstick.network_services.vnf_generic.vnf.prox_helpers import PacketDump + from yardstick.network_services.vnf_generic.vnf.prox_helpers import CoreSocketTuple + from yardstick.network_services.vnf_generic.vnf.prox_helpers import ProxTestDataTuple + from yardstick.network_services.vnf_generic.vnf.prox_helpers import ProxDpdkVnfSetupEnvHelper + from yardstick.network_services.vnf_generic.vnf.prox_helpers import TotStatsTuple + from yardstick.network_services.vnf_generic.vnf.prox_helpers import ProxResourceHelper + + +class TestCoreTuple(unittest.TestCase): + + def test___init__(self): + core_tuple = CoreSocketTuple('core 5s6') + self.assertEqual(core_tuple.core_id, 5) + self.assertEqual(core_tuple.socket_id, 6) + self.assertFalse(core_tuple.is_hyperthread()) + + core_tuple = CoreSocketTuple('core 5s6h') + self.assertEqual(core_tuple.core_id, 5) + self.assertEqual(core_tuple.socket_id, 6) + self.assertTrue(core_tuple.is_hyperthread()) + + def test___init__negative(self): + bad_inputs = [ + '', + '5', + '5s', + '6h', + '5s6', + 'core', + 'core h', + 'core 5', + 'core 5s', + 'core 5 6', + 'core 5 6h', + 'core 5d6', + 'core 5d6h', + 1, + 2.3, + [], + {}, + object(), + ] + + for bad_input in bad_inputs: + with self.assertRaises(ValueError): + CoreSocketTuple(bad_input) + + def test_find_in_topology(self): + topology_in = { + 6: { + 5: { + 'key1': ['a', 'b'], + 'key2': ['c', 'd'], + }, + }, + } + + core_tuple = CoreSocketTuple('core 5s6') + + expected = 'a' + result = core_tuple.find_in_topology(topology_in) + self.assertEqual(result, expected) + + core_tuple = CoreSocketTuple('core 5s6h') + + expected = 'c' + result = core_tuple.find_in_topology(topology_in) + self.assertEqual(result, expected) + + def test_find_in_topology_negative(self): + core_tuple = CoreSocketTuple('core 6s5') + with self.assertRaises(ValueError): + # no socket key + core_tuple.find_in_topology({}) + + with self.assertRaises(ValueError): + # no core key + core_tuple.find_in_topology({5: {}}) + + with self.assertRaises(ValueError): + # no first value (as needed by non-hyperthread core) + core_tuple.find_in_topology({5: {6: {'key1': []}}}) + + core_tuple = CoreSocketTuple('core 6s5h') + with self.assertRaises(ValueError): + # no second value (as needed by hyperthread core) + core_tuple.find_in_topology({5: {6: {'key1': ['e']}}}) + + +class TestTotStatsTuple(unittest.TestCase): + + def test___new___negative(self): + with self.assertRaises(TypeError): + # no values + TotStatsTuple() + + with self.assertRaises(TypeError): + # one, non-integer value + TotStatsTuple('a') + + with self.assertRaises(TypeError): + # too many values + TotStatsTuple(3, 4, 5, 6, 7) + + +class TestProxTestDataTuple(unittest.TestCase): + + def test___init__(self): + prox_test_data = ProxTestDataTuple(1, 2, 3, 4, 5, 6, 7, 8, 9) + self.assertEqual(prox_test_data.tolerated, 1) + self.assertEqual(prox_test_data.tsc_hz, 2) + self.assertEqual(prox_test_data.delta_rx, 3) + self.assertEqual(prox_test_data.delta_tx, 4) + self.assertEqual(prox_test_data.delta_tsc, 5) + self.assertEqual(prox_test_data.latency, 6) + self.assertEqual(prox_test_data.rx_total, 7) + self.assertEqual(prox_test_data.tx_total, 8) + self.assertEqual(prox_test_data.pps, 9) + + def test_properties(self): + prox_test_data = ProxTestDataTuple(1, 2, 3, 4, 5, 6, 7, 8, 9) + self.assertEqual(prox_test_data.pkt_loss, 12.5) + self.assertEqual(prox_test_data.mpps, 1.6 / 1e6) + self.assertEqual(prox_test_data.can_be_lost, 0) + self.assertEqual(prox_test_data.drop_total, 1) + self.assertFalse(prox_test_data.success) + + prox_test_data = ProxTestDataTuple(10, 2, 3, 4, 5, 6, 997, 998, 9) + self.assertTrue(prox_test_data.success) + + def test_pkt_loss_zero_division(self): + prox_test_data = ProxTestDataTuple(1, 2, 3, 4, 5, 6, 7, 0, 9) + self.assertEqual(prox_test_data.pkt_loss, 100.0) + + def test_get_samples(self): + prox_test_data = ProxTestDataTuple(1, 2, 3, 4, 5, [6.1, 6.9, 6.4], 7, 8, 9) + + expected = { + "Throughput": 1.6 / 1e6, + "DropPackets": 12.5, + "CurrentDropPackets": 12.5, + "TxThroughput": 9 / 1e6, + "RxThroughput": 1.6 / 1e6, + "PktSize": 64, + "LatencyMin": 6.1, + "LatencyMax": 6.9, + "LatencyAvg": 6.4, + } + result = prox_test_data.get_samples(64) + self.assertDictEqual(result, expected) + + expected = { + "Throughput": 1.6 / 1e6, + "DropPackets": 0.123, + "CurrentDropPackets": 0.123, + "TxThroughput": 9 / 1e6, + "RxThroughput": 1.6 / 1e6, + "PktSize": 64, + "LatencyMin": 6.1, + "LatencyMax": 6.9, + "LatencyAvg": 6.4, + } + result = prox_test_data.get_samples(64, 0.123) + self.assertDictEqual(result, expected) + + @mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.LOG') + def test_log_data(self, mock_logger): + my_mock_logger = mock.MagicMock() + prox_test_data = ProxTestDataTuple(1, 2, 3, 4, 5, [6.1, 6.9, 6.4], 7, 8, 9) + prox_test_data.log_data() + self.assertEqual(my_mock_logger.debug.call_count, 0) + self.assertEqual(mock_logger.debug.call_count, 2) + + mock_logger.debug.reset_mock() + prox_test_data.log_data(my_mock_logger) + self.assertEqual(my_mock_logger.debug.call_count, 2) + self.assertEqual(mock_logger.debug.call_count, 0) + + +class TestPacketDump(unittest.TestCase): + + PAYLOAD = "payload" + + def test__init__(self): + PacketDump("port_id", len(self.PAYLOAD), self.PAYLOAD) + + def test___str__(self): + expected = '<PacketDump port: port_id payload: {}>'.format(self.PAYLOAD) + dump1 = PacketDump("port_id", len(self.PAYLOAD), self.PAYLOAD) + self.assertEqual(str(dump1), expected) + + def test_port_id(self): + p = PacketDump("port_id", len(self.PAYLOAD), self.PAYLOAD) + self.assertEqual(p.port_id, "port_id") + + def test_data_len(self): + p = PacketDump("port_id", len(self.PAYLOAD), self.PAYLOAD) + self.assertEqual(p.data_len, len(self.PAYLOAD)) + + def test_payload(self): + p = PacketDump("port_id", len(self.PAYLOAD), self.PAYLOAD) + self.assertEqual(p.payload(), self.PAYLOAD) + + self.assertEqual(p.payload(3), self.PAYLOAD[3:]) + + self.assertEqual(p.payload(end=3), self.PAYLOAD[:4]) + + self.assertEqual(p.payload(2, 4), self.PAYLOAD[2:5]) + + +PACKET_DUMP_1 = """\ +pktdump,3,11 +hello world +""" + +PACKET_DUMP_2 = """\ +pktdump,3,11 +hello world +pktdump,2,9 +brown fox jumped over +pktdump,4,8 +lazy +dog +""" + +PACKET_DUMP_NON_1 = """\ +not_a_dump,1,2 +other data +""" + +PACKET_DUMP_MIXED_1 = """\ +pktdump,3,11 +hello world +not_a_dump,1,2 +other data +""" + +PACKET_DUMP_BAD_1 = """\ +pktdump,one,12 +bad port id +""" + +PACKET_DUMP_BAD_2 = """\ +pktdump,3,twelve +bad data length +""" + +PACKET_DUMP_BAD_3 = """\ +pktdump,3 +no data length value +""" + + +@mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.time') +class TestProxSocketHelper(unittest.TestCase): + + @mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.socket') + def test___init__(self, mock_socket, mock_time): + expected = mock_socket.socket() + prox = ProxSocketHelper() + result = prox._sock + self.assertEqual(result, expected) + + def test_connect(self, mock_time): + mock_sock = mock.MagicMock() + prox = ProxSocketHelper(mock_sock) + prox.connect('10.20.30.40', 23456) + self.assertEqual(mock_sock.connect.call_count, 1) + + def test_get_sock(self, mock_time): + mock_sock = mock.MagicMock() + prox = ProxSocketHelper(mock_sock) + result = prox.get_socket() + self.assertIs(result, mock_sock) + + @mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.select') + def test_get_data(self, mock_select, mock_time): + mock_select.select.side_effect = [[1], [0]] + mock_socket = mock.MagicMock() + mock_recv = mock_socket.recv() + mock_recv.decode.return_value = "" + prox = ProxSocketHelper(mock_socket) + ret = prox.get_data() + self.assertEqual(ret, "") + self.assertEqual(len(prox._pkt_dumps), 0) + + mock_select.select.reset_mock() + mock_select.select.side_effect = chain([['a'], ['']], repeat([1], 3)) + mock_recv.decode.return_value = PACKET_DUMP_1 + ret = prox.get_data() + self.assertEqual(mock_select.select.call_count, 2) + self.assertEqual(ret, 'pktdump,3,11') + self.assertEqual(len(prox._pkt_dumps), 1) + + mock_select.select.reset_mock() + mock_select.select.side_effect = chain([[object()], [None]], repeat([1], 3)) + mock_recv.decode.return_value = PACKET_DUMP_2 + ret = prox.get_data() + self.assertEqual(mock_select.select.call_count, 2) + self.assertEqual(ret, 'jumped over') + self.assertEqual(len(prox._pkt_dumps), 3) + + def test__parse_socket_data_mixed_data(self, mock_time): + prox = ProxSocketHelper(mock.MagicMock()) + ret = prox._parse_socket_data(PACKET_DUMP_NON_1, False) + self.assertEqual(ret, 'not_a_dump,1,2') + self.assertEqual(len(prox._pkt_dumps), 0) + + ret = prox._parse_socket_data(PACKET_DUMP_MIXED_1, False) + self.assertEqual(ret, 'not_a_dump,1,2') + self.assertEqual(len(prox._pkt_dumps), 1) + + def test__parse_socket_data_bad_data(self, mock_time): + prox = ProxSocketHelper(mock.MagicMock()) + with self.assertRaises(ValueError): + prox._parse_socket_data(PACKET_DUMP_BAD_1, False) + + with self.assertRaises(ValueError): + prox._parse_socket_data(PACKET_DUMP_BAD_2, False) + + ret = prox._parse_socket_data(PACKET_DUMP_BAD_3, False) + self.assertEqual(ret, 'pktdump,3') + + def test__parse_socket_data_pkt_dump_only(self, mock_time): + prox = ProxSocketHelper(mock.MagicMock()) + ret = prox._parse_socket_data('', True) + self.assertFalse(ret) + + ret = prox._parse_socket_data(PACKET_DUMP_1, True) + self.assertTrue(ret) + + ret = prox._parse_socket_data(PACKET_DUMP_2, True) + self.assertTrue(ret) + + def test_put_command(self, mock_time): + mock_socket = mock.MagicMock() + prox = ProxSocketHelper(mock_socket) + prox.put_command("data") + mock_socket.sendall.assert_called_once() + + def test_get_packet_dump(self, mock_time): + mock_socket = mock.MagicMock() + prox = ProxSocketHelper(mock_socket) + prox._pkt_dumps = [] + self.assertIsNone(prox.get_packet_dump()) + + prox._pkt_dumps = [234] + self.assertEqual(prox.get_packet_dump(), 234) + self.assertEqual(prox._pkt_dumps, []) + + def test_stop_all_reset(self, mock_time): + mock_socket = mock.MagicMock() + prox = ProxSocketHelper(mock_socket) + prox.stop_all_reset() + mock_socket.sendall.assert_called() + + def test_stop_all(self, mock_time): + mock_socket = mock.MagicMock() + prox = ProxSocketHelper(mock_socket) + prox.stop_all() + mock_socket.sendall.assert_called() + + def test_stop(self, mock_time): + mock_socket = mock.MagicMock() + prox = ProxSocketHelper(mock_socket) + prox.stop([3, 4, 5], 16) + mock_socket.sendall.assert_called() + + def test_start_all(self, mock_time): + mock_socket = mock.MagicMock() + prox = ProxSocketHelper(mock_socket) + prox.start_all() + mock_socket.sendall.assert_called() + + def test_start(self, mock_time): + mock_socket = mock.MagicMock() + prox = ProxSocketHelper(mock_socket) + prox.start([3, 4, 5]) + mock_socket.sendall.assert_called() + + def test_reset_stats(self, mock_time): + mock_socket = mock.MagicMock() + prox = ProxSocketHelper(mock_socket) + prox.reset_stats() + mock_socket.sendall.assert_called() + + def test_set_pkt_size(self, mock_time): + mock_socket = mock.MagicMock() + prox = ProxSocketHelper(mock_socket) + prox.set_pkt_size([3, 4, 5], 1024) + self.assertEqual(mock_socket.sendall.call_count, 3) + + def test_set_value(self, mock_time): + mock_socket = mock.MagicMock() + prox = ProxSocketHelper(mock_socket) + prox.set_value([3, 4, 5], 10, 20, 30) + self.assertEqual(mock_socket.sendall.call_count, 3) + + def test_reset_values(self, mock_time): + mock_socket = mock.MagicMock() + prox = ProxSocketHelper(mock_socket) + prox.reset_values([3, 4, 5]) + self.assertEqual(mock_socket.sendall.call_count, 3) + + def test_set_speed(self, mock_time): + mock_socket = mock.MagicMock() + prox = ProxSocketHelper(mock_socket) + prox.set_speed([3, 4, 5], 1000) + self.assertEqual(mock_socket.sendall.call_count, 3) + + def test_slope_speed(self, mock_time): + core_data = [ + { + 'cores': [3, 4, 5], + 'speed': 1000, + }, + { + 'cores': [9, 10, 11], + 'speed': '500.5', + }, + ] + + mock_socket = mock.MagicMock() + prox = ProxSocketHelper(mock_socket) + prox.set_speed = set_speed = mock.MagicMock() + prox.slope_speed(core_data, 5) + self.assertEqual(set_speed.call_count, 20) + + set_speed.reset_mock() + prox.slope_speed(core_data, 5, 5) + self.assertEqual(set_speed.call_count, 10) + + def test_set_pps(self, mock_time): + mock_socket = mock.MagicMock() + prox = ProxSocketHelper(mock_socket) + prox.set_pps([3, 4, 5], 1000, 512) + self.assertEqual(mock_socket.sendall.call_count, 3) + + def test_lat_stats(self, mock_time): + latency_output = [ + '1, 2 , 3', # has white space + '4,5', # too short + '7,8,9,10.5,11', # too long with float, but float is in unused portion + 'twelve,13,14', # value as English word + '15,16.2,17', # float in used portion + ] + + mock_socket = mock.MagicMock() + prox = ProxSocketHelper(mock_socket) + prox.get_data = mock.MagicMock(side_effect=latency_output) + + expected = ( + { + 3: 1, + 5: 7, + }, + { + 3: 2, + 5: 8, + }, + { + 3: 3, + 5: 9, + }, + ) + result = prox.lat_stats([3, 4, 5, 6, 7], 16) + self.assertEqual(mock_socket.sendall.call_count, 5) + self.assertEqual(result, expected) + + def test_get_all_tot_stats(self, mock_time): + mock_socket = mock.MagicMock() + prox = ProxSocketHelper(mock_socket) + prox.get_data = mock.MagicMock(return_value='3,4,5,6') + expected = 3, 4, 5, 6 + result = prox.get_all_tot_stats() + self.assertEqual(result, expected) + + def test_hz(self, mock_time): + mock_socket = mock.MagicMock() + prox = ProxSocketHelper(mock_socket) + prox.get_data = mock.MagicMock(return_value='3,4,5,6') + expected = 6 + result = prox.hz() + self.assertEqual(result, expected) + + def test_rx_stats(self, mock_time): + core_stats = [ + '3,4,5,6', + '7,8,9,10,NaN', + '11,12,13,14,15', + ] + + mock_socket = mock.MagicMock() + prox = ProxSocketHelper(mock_socket) + prox.get_data = mock.MagicMock(side_effect=core_stats) + expected = 21, 24, 27, 14 + result = prox.rx_stats([3, 4, 5], 16) + self.assertEqual(result, expected) + + def test_core_stats(self, mock_time): + core_stats = [ + '3,4,5,6', + '7,8,9,10,NaN', + '11,12,13,14,15', + ] + + mock_socket = mock.MagicMock() + prox = ProxSocketHelper(mock_socket) + prox.get_data = mock.MagicMock(side_effect=core_stats) + expected = 21, 24, 27, 14 + result = prox.core_stats([3, 4, 5], 16) + self.assertEqual(result, expected) + + def test_port_stats(self, mock_time): + port_stats = [ + ','.join(str(n) for n in range(3, 15)), + ','.join(str(n) for n in range(8, 32, 2)), + ','.join(str(n) for n in range(5, 89, 7)), + ] + + mock_socket = mock.MagicMock() + prox = ProxSocketHelper(mock_socket) + prox.get_data = mock.MagicMock(side_effect=port_stats) + expected = [16, 26, 36, 46, 56, 66, 76, 86, 96, 106, 116, 126] + result = prox.port_stats([3, 4, 5]) + self.assertEqual(result, expected) + + def test_measure_tot_stats(self, mock_time): + start_tot = 3, 4, 5, 6 + end_tot = 7, 9, 11, 13 + delta_tot = 4, 5, 6, 7 + + get_data_output = [ + ','.join(str(n) for n in start_tot), + ','.join(str(n) for n in end_tot), + ] + + mock_socket = mock.MagicMock() + prox = ProxSocketHelper(mock_socket) + prox.get_data = mock.MagicMock(side_effect=get_data_output) + expected = { + 'start_tot': start_tot, + 'end_tot': end_tot, + 'delta': delta_tot, + } + with prox.measure_tot_stats() as result: + pass + self.assertEqual(result, expected) + + def test_tot_stats(self, mock_time): + mock_socket = mock.MagicMock() + prox = ProxSocketHelper(mock_socket) + prox.get_data = mock.MagicMock(return_value='3,4,5,6') + expected = 3, 4, 5 + result = prox.tot_stats() + self.assertEqual(result, expected) + + def test_tot_ierrors(self, mock_time): + mock_socket = mock.MagicMock() + prox = ProxSocketHelper(mock_socket) + prox.get_data = mock.MagicMock(return_value='3,4,5,6') + expected = 3, 3 + result = prox.tot_ierrors() + self.assertEqual(result, expected) + + def test_set_count(self, mock_time): + mock_socket = mock.MagicMock() + prox = ProxSocketHelper(mock_socket) + prox.set_count(432, [3, 4, 5]) + self.assertEqual(mock_socket.sendall.call_count, 3) + + def test_dump_rx(self, mock_time): + mock_socket = mock.MagicMock() + prox = ProxSocketHelper(mock_socket) + prox.dump_rx(3, 5, 8) + self.assertEqual(mock_socket.sendall.call_count, 1) + + def test_quit(self, mock_time): + mock_socket = mock.MagicMock() + prox = ProxSocketHelper(mock_socket) + prox.quit() + mock_socket.sendall.assert_called() + + def test_force_quit(self, mock_time): + mock_socket = mock.MagicMock() + prox = ProxSocketHelper(mock_socket) + prox.force_quit() + mock_socket.sendall.assert_called() + + +class TestProxDpdkVnfSetupEnvHelper(unittest.TestCase): + + def test_rebind_drivers(self): + def find_drivers(*args, **kwargs): + setup_helper.used_drivers = used_drivers + + used_drivers = { + 'a': (1, 'b'), + 'c': (2, 'd'), + } + + vnfd_helper = mock.MagicMock() + ssh_helper = mock.MagicMock() + scenario_helper = mock.MagicMock() + setup_helper = ProxDpdkVnfSetupEnvHelper(vnfd_helper, ssh_helper, scenario_helper) + setup_helper._find_used_drivers = mock_find = mock.MagicMock(side_effect=find_drivers) + + setup_helper.rebind_drivers() + self.assertEqual(mock_find.call_count, 1) + self.assertEqual(ssh_helper.execute.call_count, 2) + self.assertIn('--force', ssh_helper.execute.call_args[0][0]) + + mock_find.reset_mock() + ssh_helper.execute.reset_mock() + setup_helper.rebind_drivers(False) + self.assertEqual(mock_find.call_count, 0) + self.assertEqual(ssh_helper.execute.call_count, 2) + self.assertNotIn('--force', ssh_helper.execute.call_args[0][0]) + + +class TestProxResourceHelper(unittest.TestCase): + + def test__replace_quoted_with_value(self): + # empty string + input_str = '' + expected = '' + result = ProxResourceHelper._replace_quoted_with_value(input_str, 'cat') + self.assertEqual(result, expected) + + # no quoted substring + input_str = 'lion tiger bear' + expected = 'lion tiger bear' + result = ProxResourceHelper._replace_quoted_with_value(input_str, 'cat') + self.assertEqual(result, expected) + + # partially quoted substring + input_str = 'lion "tiger bear' + expected = 'lion "tiger bear' + result = ProxResourceHelper._replace_quoted_with_value(input_str, 'cat') + self.assertEqual(result, expected) + + # one quoted substring + input_str = 'lion "tiger" bear' + expected = 'lion "cat" bear' + result = ProxResourceHelper._replace_quoted_with_value(input_str, 'cat') + self.assertEqual(result, expected) + + # two quoted substrings + input_str = 'lion "tiger" bear "shark" whale' + expected = 'lion "cat" bear "shark" whale' + result = ProxResourceHelper._replace_quoted_with_value(input_str, 'cat') + self.assertEqual(result, expected) + + # two quoted substrings, both replaced + input_str = 'lion "tiger" bear "shark" whale' + expected = 'lion "cat" bear "cat" whale' + result = ProxResourceHelper._replace_quoted_with_value(input_str, 'cat', 2) + self.assertEqual(result, expected) + + def test__get_tx_port(self): + # no data + input_data = {'section1': []} + expected = -1 + result = ProxResourceHelper._get_tx_port('section1', input_data) + self.assertEqual(result, expected) + + # data for other section + input_data = { + 'section1': [], + 'section2': [ + ('rx port', '3'), + ('tx port', '4'), + ], + } + expected = -1 + result = ProxResourceHelper._get_tx_port('section1', input_data) + self.assertEqual(result, expected) + + # data for section + input_data['section1'] = section1 = [ + ('rx port', '4', 'more', 432), + ('tx port', '3'), + ] + expected = 3 + result = ProxResourceHelper._get_tx_port('section1', input_data) + self.assertEqual(result, expected) + + # more data for section, + section1.extend([ + ('rx port', '2'), + ('tx port', '1', 'and more', 234), + ]) + expected = 1 + result = ProxResourceHelper._get_tx_port('section1', input_data) + self.assertEqual(result, expected) + + def test_line_rate_to_pps(self): + expected = 0.25 * 1e8 + result = ProxResourceHelper.line_rate_to_pps(180, 4) + self.assertEqual(result, expected) + + def test_find_pci(self): + input_str_list = [ + 'no target here', + 'nor here', + 'and still not', + ] + result = ProxResourceHelper.find_pci('target', input_str_list) + self.assertFalse(result) + + input_str_list = [ + 'no target here', + 'nor here', + 'this is a target', + 'did we miss it', + ] + result = ProxResourceHelper.find_pci('target', input_str_list) + self.assertTrue(result) + + def test_write_prox_config(self): + input_data = {} + expected = '' + result = ProxResourceHelper.write_prox_config(input_data) + self.assertEqual(result, expected) + + input_data = { + 'section1': [], + } + expected = '[section1]' + result = ProxResourceHelper.write_prox_config(input_data) + self.assertEqual(result, expected) + + input_data = OrderedDict([ + ('section1', []), + ( + 'section2', [ + ('key1', 'value1'), + ('__name__', 'not this one'), + ('key2', None), + ('key3', 234), + ('key4', 'multi-line\nvalue'), + ] + ) + ]) + expected = os.linesep.join([ + '[section1]', + '[section2]', + 'key1=value1', + 'key2', + 'key3=234', + 'key4=multi-line\n\tvalue', + ]) + result = ProxResourceHelper.write_prox_config(input_data) + self.assertEqual(result, expected) + + def test_sut(self): + helper = ProxResourceHelper(mock.MagicMock()) + self.assertIsNone(helper.client) + result = helper.sut + self.assertIsNotNone(result) + self.assertIs(result, helper.client) + self.assertIs(result, helper.sut) + + @mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.SocketTopology') + def test_cpu_topology(self, mock_socket_topology): + mock_socket_topology.parse_cpuinfo.return_value = 432 + + setup_helper = mock.MagicMock() + setup_helper.ssh_helper.execute.return_value = 0, 'output', '' + + helper = ProxResourceHelper(setup_helper) + self.assertIsNone(helper._cpu_topology) + result = helper.cpu_topology + self.assertEqual(result, 432) + self.assertIs(result, helper._cpu_topology) + self.assertIs(result, helper.cpu_topology) + + def test_vpci_to_if_name_map(self): + setup_helper = mock.MagicMock() + setup_helper.vnfd_helper.interfaces = [] + + helper = ProxResourceHelper(setup_helper) + self.assertIsNone(helper._vpci_to_if_name_map) + result = helper.vpci_to_if_name_map + self.assertEqual(result, {}) + self.assertIs(result, helper._vpci_to_if_name_map) + self.assertIs(result, helper.vpci_to_if_name_map) + + setup_helper.vnfd_helper.interfaces = [ + { + 'name': 'vnf1', + 'virtual-interface': { + 'vpci': '0000:01.02.03', + }, + }, + { + 'name': 'vnf2', + 'virtual-interface': { + 'vpci': '0000:04.05.06', + }, + }, + ] + expected = { + '0000:01.02.03': 'vnf1', + '0000:04.05.06': 'vnf2', + } + helper = ProxResourceHelper(setup_helper) + self.assertIsNone(helper._vpci_to_if_name_map) + result = helper.vpci_to_if_name_map + self.assertDictEqual(result, expected) + self.assertIs(result, helper._vpci_to_if_name_map) + self.assertIs(result, helper.vpci_to_if_name_map) + + def test_test_cores(self): + setup_helper = mock.MagicMock() + helper = ProxResourceHelper(setup_helper) + helper.prox_config_dict = {} + helper._cpu_topology = [] + + expected = [] + result = helper.test_cores + self.assertEqual(result, expected) + + helper = ProxResourceHelper(setup_helper) + helper.prox_config_dict = OrderedDict([ + ('section1', []), + ('section2', [ + ('a', 'b'), + ('c', 'd'), + ]), + ('core 1s3', []), + ('core 2s5', [ + ('index', 8), + ('mode', ''), + ]), + ('core 3s1', [ + ('index', 5), + ('mode', 'gen'), + ]), + ('core 4s9h', [ + ('index', 7), + ('mode', 'gen'), + ]), + ]) + helper._cpu_topology = { + 1: { + 3: { + 'key1': (23, 32), + 'key2': (12, 21), + 'key3': (44, 33), + }, + }, + 9: { + 4: { + 'key1': (44, 32), + 'key2': (23, 21), + 'key3': (12, 33), + }, + }, + } + + self.assertIsNone(helper._test_cores) + expected = [12, 23] + result = helper.test_cores + self.assertEqual(result, expected) + self.assertIs(result, helper._test_cores) + self.assertIs(result, helper.test_cores) + + def test_latency_cores(self): + setup_helper = mock.MagicMock() + helper = ProxResourceHelper(setup_helper) + helper.prox_config_dict = {} + helper._cpu_topology = [] + + expected = [] + result = helper.latency_cores + self.assertEqual(result, expected) + + helper = ProxResourceHelper(setup_helper) + helper.prox_config_dict = OrderedDict([ + ('section1', []), + ('section2', [ + ('a', 'b'), + ('c', 'd'), + ]), + ('core 1s3', []), + ('core 2s5', [ + ('index', 8), + ('mode', ''), + ]), + ('core 3s1', [ + ('index', 5), + ('mode', 'lat'), + ]), + ('core 4s9h', [ + ('index', 7), + ('mode', 'lat'), + ]), + ]) + helper._cpu_topology = { + 1: { + 3: { + 'key1': (23, 32), + 'key2': (12, 21), + 'key3': (44, 33), + }, + }, + 9: { + 4: { + 'key1': (44, 32), + 'key2': (23, 21), + 'key3': (12, 33), + }, + }, + } + + self.assertIsNone(helper._latency_cores) + expected = [12, 23] + result = helper.latency_cores + self.assertEqual(result, expected) + self.assertIs(result, helper._latency_cores) + self.assertIs(result, helper.latency_cores) + + def test_start_collect(self): + setup_helper = mock.MagicMock() + helper = ProxResourceHelper(setup_helper) + self.assertIsNone(helper.start_collect()) + + def test_terminate(self): + setup_helper = mock.MagicMock() + helper = ProxResourceHelper(setup_helper) + self.assertIsNone(helper.terminate()) + + @mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.find_relative_file') + def test_get_process_args_no_additional_file(self, mock_find_path): + vnf1 = { + 'prox_args': 'c', + 'prox_path': 'd', + 'prox_config': 'e/f', + } + + mock_find_path.side_effect = ['1', '2'] + setup_helper = mock.MagicMock() + setup_helper.scenario_helper = ScenarioHelper('vnf1') + setup_helper.scenario_helper.scenario_cfg = { + 'task_path': 'a/b', + 'options': { + 'vnf1': vnf1, + }, + } + + helper = ProxResourceHelper(setup_helper) + helper.copy_to_target = mock.MagicMock(return_value='3') + helper.generate_prox_config_file = mock.MagicMock(return_value='4') + helper.upload_prox_config = mock.MagicMock(return_value='5') + + expected = 'c', 'd', '5' + result = helper.get_process_args() + self.assertEqual(result, expected) + self.assertFalse(helper.additional_file) + self.assertIsNone(helper.remote_prox_file_name) + + @mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.find_relative_file') + def test_get_process_args_additional_file(self, mock_find_path): + vnf1 = { + 'prox_args': 'c', + 'prox_path': 'd', + 'prox_config': 'e/f', + 'prox_files': 'g/h', + } + + mock_find_path.side_effect = ['1', '2'] + setup_helper = mock.MagicMock() + setup_helper.scenario_helper = ScenarioHelper('vnf1') + setup_helper.scenario_helper.scenario_cfg = { + 'task_path': 'a/b', + 'options': { + 'vnf1': vnf1, + }, + } + + helper = ProxResourceHelper(setup_helper) + helper.copy_to_target = mock.MagicMock(return_value='33') + helper.generate_prox_config_file = mock.MagicMock(return_value='44') + helper.upload_prox_config = mock.MagicMock(return_value='55') + + expected = 'c', 'd', '55' + result = helper.get_process_args() + self.assertEqual(result, expected) + self.assertTrue(helper.additional_file) + self.assertEqual(helper.remote_prox_file_name, '33') + + def test_up_post(self): + setup_helper = mock.MagicMock() + helper = ProxResourceHelper(setup_helper) + helper.client = expected = mock.MagicMock() + result = helper.up_post() + self.assertEqual(result, expected) + + def test_execute(self): + setup_helper = mock.MagicMock() + helper = ProxResourceHelper(setup_helper) + helper.client = mock.MagicMock() + + expected = helper.client.my_command() + result = helper.execute('my_command') + self.assertEqual(result, expected) + + helper.client = object() + + result = helper.execute('my_command') + self.assertIsNone(result) + + def test_copy_to_target(self): + setup_helper = mock.MagicMock() + helper = ProxResourceHelper(setup_helper) + expected = '/tmp/c' + result = helper.copy_to_target('a/b', 'c') + self.assertEqual(result, expected) + + def test_upload_prox_config(self): + setup_helper = mock.MagicMock() + helper = ProxResourceHelper(setup_helper) + helper.write_prox_config = mock.MagicMock(return_value='a long string') + expected = '/tmp/a' + result = helper.upload_prox_config('a', {}) + self.assertEqual(result, expected) + + @mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.time') + def test_run_test(self, mock_time): + @contextmanager + def measure(*args, **kwargs): + yield stats + + setup_helper = mock.MagicMock() + setup_helper.vnfd_helper.interfaces = [] + + stats = { + 'delta': TotStatsTuple(6, 7, 8, 9), + } + + client = mock.MagicMock() + client.hz.return_value = 2 + client.measure_tot_stats = measure + client.port_stats.return_value = tuple(range(12)) + + helper = ProxResourceHelper(setup_helper) + helper.client = client + helper.get_latency = mock.MagicMock(return_value=[3.3, 3.6, 3.8]) + + with self.assertRaises(AssertionError): + helper.run_test(980, 15, 45) + + setup_helper.vnfd_helper.interfaces = ['a', 'b', 'c', 'd'] + helper._test_cores = [3, 4] + + expected = ProxTestDataTuple(0.0, 2.0, 6, 7, 8, [3.3, 3.6, 3.8], 6, 7, 1.3e7) + result = helper.run_test(230, 60, 65) + self.assertEqual(result, expected) + + def test_generate_prox_lua_file(self): + setup_helper = mock.MagicMock() + setup_helper.vnfd_helper.interfaces = [] + + helper = ProxResourceHelper(setup_helper) + helper.LUA_PARAMETER_NAME = 'sut' + + expected = '' + result = helper.generate_prox_lua_file() + self.assertEqual(result, expected) + + setup_helper.vnfd_helper.interfaces = [ + { + 'local_ip': '10.20.30.40', + 'dst_ip': '10.11.12.13', + 'virtual-interface': { + 'dpdk_port_num': 3, + }, + }, + { + 'local_ip': '10.20.30.45', + 'dst_ip': '10.11.12.19', + 'virtual-interface': { + 'dpdk_port_num': 7, + }, + }, + ] + + expected = os.linesep.join([ + 'sut_hex_ip_port_3:"0a 14 1e 28"', + 'sut_ip_port_3:"10.20.30.40"', + 'gen_hex_ip_port_3:"0a 0b 0c 0d"', + 'gen_ip_port_3:"10.11.12.13"', + + 'sut_hex_ip_port_7:"0a 14 1e 2d"', + 'sut_ip_port_7:"10.20.30.45"', + 'gen_hex_ip_port_7:"0a 0b 0c 13"', + 'gen_ip_port_7:"10.11.12.19"', + ]) + result = helper.generate_prox_lua_file() + self.assertEqual(result, expected) + + def test_upload_prox_lua(self): + def identity(*args): + return args + + setup_helper = mock.MagicMock() + setup_helper.vnfd_helper.interfaces = [] + + helper = ProxResourceHelper(setup_helper) + helper.generate_prox_lua_file = mock.MagicMock(return_value=234) + helper.put_string_to_file = identity + + expected = '' + result = helper.upload_prox_lua('my_dir', {}) + self.assertEqual(result, expected) + + input_data = { + 'lua': { + 'key1': 'value1 ("inside") tail', + 'key2': 'value2', + 'key3 ("key_side") head': 'value3', + }, + } + + expected = 234, 'my_dir/key_side' + result = helper.upload_prox_lua('my_dir', input_data) + self.assertEqual(result, expected) + + def test_put_string_to_file(self): + setup_helper = mock.MagicMock() + setup_helper.vnfd_helper.interfaces = [] + + helper = ProxResourceHelper(setup_helper) + + expected = 'a/b' + result = helper.put_string_to_file('my long string', 'a/b') + self.assertEqual(result, expected) + + @mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.ConfigParser') + def test_generate_prox_config_file(self, mock_parser_type): + def init(*args): + args[-1].update(sections_data) + return mock.MagicMock() + + sections_data = {} + + mock_parser_type.side_effect = init + + setup_helper = mock.MagicMock() + setup_helper.vnfd_helper.interfaces = [] + + helper = ProxResourceHelper(setup_helper) + helper.additional_file = False + + expected = {} + result = helper.generate_prox_config_file('a/b') + self.assertEqual(result, expected) + + helper.additional_file = True + helper.remote_prox_file_name = 'remote' + setup_helper.vnfd_helper.interfaces = [ + { + 'virtual-interface': { + 'dpdk_port_num': 3, + 'dst_mac': '00:00:00:de:ad:88', + }, + }, + { + 'virtual-interface': { + 'dpdk_port_num': 5, + 'dst_mac': '00:00:00:de:ad:ff', + }, + }, + { + 'virtual-interface': { + 'dpdk_port_num': 7, + 'dst_mac': '00:00:00:de:ad:ff', + }, + }, + ] + sections_data = { + 'port 3': [ + ['ip', ''], + ['mac', 'foo'], + ['dst mac', ''], + ['tx port', '1'], + ], + 'port 5': [ + ['ip', ''], + ['dst mac', ''], + ['tx port', '0'], + ['single'], + ['???', 'dofile "here" 23'], + ], + } + + expected = { + 'port 3': [ + ['ip', ''], + ['mac', 'hardware'], + ['dst mac', '00:00:00:de:ad:ff'], + ['tx port', '1'], + ], + 'port 5': [ + ['ip', ''], + ['dst mac', '00:00:00:de:ad:88'], + ['tx port', '0'], + ['single'], + ['???', 'dofile "remote" 23'], + ], + } + result = helper.generate_prox_config_file('a/b') + self.assertDictEqual(result, expected) + + @mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.ConfigParser') + def test_generate_prox_config_file_negative(self, mock_parser_type): + def init(*args): + args[-1].update(sections_data) + return mock.MagicMock() + + sections_data = {} + + mock_parser_type.side_effect = init + + setup_helper = mock.MagicMock() + setup_helper.vnfd_helper.interfaces = [] + + helper = ProxResourceHelper(setup_helper) + helper.additional_file = False + helper.remote_prox_file_name = 'remote' + setup_helper.vnfd_helper.interfaces = [ + { + 'virtual-interface': { + 'dpdk_port_num': 3, + 'dst_mac': '00:00:00:de:ad:88', + }, + }, + { + 'virtual-interface': { + 'dpdk_port_num': 5, + 'dst_mac': '00:00:00:de:ad:ff', + }, + }, + { + 'virtual-interface': { + 'dpdk_port_num': 7, + 'dst_mac': '00:00:00:de:ad:ff', + }, + }, + ] + sections_data = { + 'port 3': [ + ['ip', ''], + ['mac', 'foo'], + ['dst mac', ''], + ], + 'port 5': [ + ['ip', ''], + ['dst mac', ''], + ['tx port', '0'], + ['???', 'dofile "here" 23'], + ], + } + + with self.assertRaises(Exception): + helper.generate_prox_config_file('a/b') + + def test_get_latency(self): + setup_helper = mock.MagicMock() + setup_helper.vnfd_helper.interfaces = [] + + helper = ProxResourceHelper(setup_helper) + helper._latency_cores = [] + + expected = [] + result = helper.get_latency() + self.assertEqual(result, expected) + + helper._latency_cores = [1, 2] + helper.client = mock.MagicMock() + + expected = helper.sut.lat_stats() + result = helper.get_latency() + self.assertIs(result, expected) + + def test__get_logical_if_name(self): + setup_helper = mock.MagicMock() + setup_helper.vnfd_helper.interfaces = [] + + helper = ProxResourceHelper(setup_helper) + helper._vpci_to_if_name_map = { + 'key1': 234, + 'key2': 432, + } + + expected = 234 + result = helper._get_logical_if_name('key1') + self.assertEqual(result, expected) + + @mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.time') + @mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.ProxSocketHelper') + def test__connect(self, mock_socket_helper_type, mock_time): + client = mock_socket_helper_type() + client.connect.side_effect = chain(repeat(socket.error, 5), [None]) + + setup_helper = mock.MagicMock() + setup_helper.vnfd_helper.interfaces = [] + + helper = ProxResourceHelper(setup_helper) + + result = helper._connect() + self.assertIs(result, client) + + client.connect.side_effect = chain(repeat(socket.error, 65), [None]) + + with self.assertRaises(Exception): + helper._connect() diff --git a/tests/unit/network_services/vnf_generic/vnf/test_prox_vnf.py b/tests/unit/network_services/vnf_generic/vnf/test_prox_vnf.py new file mode 100644 index 000000000..453100b90 --- /dev/null +++ b/tests/unit/network_services/vnf_generic/vnf/test_prox_vnf.py @@ -0,0 +1,524 @@ +#!/usr/bin/env python + +# Copyright (c) 2016-2017 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +from __future__ import absolute_import + +import os +import unittest + +import mock +from copy import deepcopy + +SSH_HELPER = 'yardstick.network_services.vnf_generic.vnf.sample_vnf.VnfSshHelper' + +STL_MOCKS = { + 'stl': mock.MagicMock(), + 'stl.trex_stl_lib': mock.MagicMock(), + 'stl.trex_stl_lib.base64': mock.MagicMock(), + 'stl.trex_stl_lib.binascii': mock.MagicMock(), + 'stl.trex_stl_lib.collections': mock.MagicMock(), + 'stl.trex_stl_lib.copy': mock.MagicMock(), + 'stl.trex_stl_lib.datetime': mock.MagicMock(), + 'stl.trex_stl_lib.functools': mock.MagicMock(), + 'stl.trex_stl_lib.imp': mock.MagicMock(), + 'stl.trex_stl_lib.inspect': mock.MagicMock(), + 'stl.trex_stl_lib.json': mock.MagicMock(), + 'stl.trex_stl_lib.linecache': mock.MagicMock(), + 'stl.trex_stl_lib.math': mock.MagicMock(), + 'stl.trex_stl_lib.os': mock.MagicMock(), + 'stl.trex_stl_lib.platform': mock.MagicMock(), + 'stl.trex_stl_lib.pprint': mock.MagicMock(), + 'stl.trex_stl_lib.random': mock.MagicMock(), + 'stl.trex_stl_lib.re': mock.MagicMock(), + 'stl.trex_stl_lib.scapy': mock.MagicMock(), + 'stl.trex_stl_lib.socket': mock.MagicMock(), + 'stl.trex_stl_lib.string': mock.MagicMock(), + 'stl.trex_stl_lib.struct': mock.MagicMock(), + 'stl.trex_stl_lib.sys': mock.MagicMock(), + 'stl.trex_stl_lib.threading': mock.MagicMock(), + 'stl.trex_stl_lib.time': mock.MagicMock(), + 'stl.trex_stl_lib.traceback': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_async_client': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_client': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_exceptions': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_ext': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_jsonrpc_client': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_packet_builder_interface': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_packet_builder_scapy': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_port': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_stats': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_streams': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_types': mock.MagicMock(), + 'stl.trex_stl_lib.types': mock.MagicMock(), + 'stl.trex_stl_lib.utils': mock.MagicMock(), + 'stl.trex_stl_lib.utils.argparse': mock.MagicMock(), + 'stl.trex_stl_lib.utils.collections': mock.MagicMock(), + 'stl.trex_stl_lib.utils.common': mock.MagicMock(), + 'stl.trex_stl_lib.utils.json': mock.MagicMock(), + 'stl.trex_stl_lib.utils.os': mock.MagicMock(), + 'stl.trex_stl_lib.utils.parsing_opts': mock.MagicMock(), + 'stl.trex_stl_lib.utils.pwd': mock.MagicMock(), + 'stl.trex_stl_lib.utils.random': mock.MagicMock(), + 'stl.trex_stl_lib.utils.re': mock.MagicMock(), + 'stl.trex_stl_lib.utils.string': mock.MagicMock(), + 'stl.trex_stl_lib.utils.sys': mock.MagicMock(), + 'stl.trex_stl_lib.utils.text_opts': mock.MagicMock(), + 'stl.trex_stl_lib.utils.text_tables': mock.MagicMock(), + 'stl.trex_stl_lib.utils.texttable': mock.MagicMock(), + 'stl.trex_stl_lib.warnings': mock.MagicMock(), + 'stl.trex_stl_lib.yaml': mock.MagicMock(), + 'stl.trex_stl_lib.zlib': mock.MagicMock(), + 'stl.trex_stl_lib.zmq': mock.MagicMock(), +} + +STLClient = mock.MagicMock() +stl_patch = mock.patch.dict("sys.modules", STL_MOCKS) +stl_patch.start() + +if stl_patch: + from yardstick.network_services.vnf_generic.vnf.prox_vnf import ProxApproxVnf + from tests.unit.network_services.vnf_generic.vnf.test_base import mock_ssh + + +NAME = "vnf__1" + + +@mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.time') +class TestProxApproxVnf(unittest.TestCase): + + VNFD0 = { + 'short-name': 'ProxVnf', + 'vdu': [ + { + 'routing_table': [ + { + 'network': '152.16.100.20', + 'netmask': '255.255.255.0', + 'gateway': '152.16.100.20', + 'if': 'xe0', + }, + { + 'network': '152.16.40.20', + 'netmask': '255.255.255.0', + 'gateway': '152.16.40.20', + 'if': 'xe1', + }, + ], + 'description': 'PROX approximation using DPDK', + 'name': 'proxvnf-baremetal', + 'nd_route_tbl': [ + { + 'network': '0064:ff9b:0:0:0:0:9810:6414', + 'netmask': '112', + 'gateway': '0064:ff9b:0:0:0:0:9810:6414', + 'if': 'xe0', + }, + { + 'network': '0064:ff9b:0:0:0:0:9810:2814', + 'netmask': '112', + 'gateway': '0064:ff9b:0:0:0:0:9810:2814', + 'if': 'xe1', + }, + ], + 'id': 'proxvnf-baremetal', + 'external-interface': [ + { + 'virtual-interface': { + 'dst_mac': '00:00:00:00:00:04', + 'vpci': '0000:05:00.0', + 'local_ip': '152.16.100.19', + 'type': 'PCI-PASSTHROUGH', + 'vld_id': '', + 'netmask': '255.255.255.0', + 'dpdk_port_num': '0', + 'bandwidth': '10 Gbps', + 'driver': "i40e", + 'dst_ip': '152.16.100.20', + 'local_iface_name': 'xe0', + 'local_mac': '00:00:00:00:00:02', + }, + 'vnfd-connection-point-ref': 'xe0', + 'name': 'xe0', + }, + { + 'virtual-interface': { + 'dst_mac': '00:00:00:00:00:03', + 'vpci': '0000:05:00.1', + 'local_ip': '152.16.40.19', + 'type': 'PCI-PASSTHROUGH', + 'vld_id': '', + 'driver': "i40e", + 'netmask': '255.255.255.0', + 'dpdk_port_num': '1', + 'bandwidth': '10 Gbps', + 'dst_ip': '152.16.40.20', + 'local_iface_name': 'xe1', + 'local_mac': '00:00:00:00:00:01', + }, + 'vnfd-connection-point-ref': 'xe1', + 'name': 'xe1', + }, + ], + }, + ], + 'description': 'PROX approximation using DPDK', + 'mgmt-interface': { + 'vdu-id': 'proxvnf-baremetal', + 'host': '1.2.1.1', + 'password': 'r00t', + 'user': 'root', + 'ip': '1.2.1.1', + }, + 'benchmark': { + 'kpi': [ + 'packets_in', + 'packets_fwd', + 'packets_dropped', + ], + }, + 'connection-point': [ + { + 'type': 'VPORT', + 'name': 'xe0', + }, + { + 'type': 'VPORT', + 'name': 'xe1', + }, + ], + 'id': 'ProxApproxVnf', + 'name': 'ProxVnf', + } + + VNFD = { + 'vnfd:vnfd-catalog': { + 'vnfd': [ + VNFD0, + ], + }, + } + + SCENARIO_CFG = { + 'task_path': "", + 'nodes': { + 'tg__1': 'trafficgen_1.yardstick', + 'vnf__1': 'vnf.yardstick'}, + 'runner': { + 'duration': 600, 'type': 'Duration'}, + 'topology': 'prox-tg-topology-2.yaml', + 'traffic_profile': '../../traffic_profiles/prox_binsearch.yaml', + 'type': 'NSPerf', + 'options': { + 'tg__1': {'prox_args': {'-e': '', + '-t': ''}, + 'prox_config': 'configs/l3-gen-2.cfg', + 'prox_path': + '/root/dppd-PROX-v035/build/prox'}, + 'vnf__1': { + 'prox_args': {'-t': ''}, + 'prox_config': 'configs/l3-swap-2.cfg', + 'prox_path': '/root/dppd-PROX-v035/build/prox'}}} + + CONTEXT_CFG = { + 'nodes': { + 'tg__2': { + 'member-vnf-index': '3', + 'role': 'TrafficGen', + 'name': 'trafficgen_2.yardstick', + 'vnfd-id-ref': 'tg__2', + 'ip': '1.2.1.1', + 'interfaces': { + 'xe0': { + 'local_iface_name': 'ens513f0', + 'vld_id': 'public', + 'netmask': '255.255.255.0', + 'local_ip': '152.16.40.20', + 'dst_mac': '00:00:00:00:00:01', + 'local_mac': '00:00:00:00:00:03', + 'dst_ip': '152.16.40.19', + 'driver': 'ixgbe', + 'vpci': '0000:02:00.0', + 'dpdk_port_num': 0, + }, + 'xe1': { + 'local_iface_name': 'ens513f1', + 'netmask': '255.255.255.0', + 'network': '202.16.100.0', + 'local_ip': '202.16.100.20', + 'local_mac': '00:1e:67:d0:60:5d', + 'driver': 'ixgbe', + 'vpci': '0000:02:00.1', + 'dpdk_port_num': 1, + }, + }, + 'password': 'r00t', + 'VNF model': 'l3fwd_vnf.yaml', + 'user': 'root', + }, + 'tg__1': { + 'member-vnf-index': '1', + 'role': 'TrafficGen', + 'name': 'trafficgen_1.yardstick', + 'vnfd-id-ref': 'tg__1', + 'ip': '1.2.1.1', + 'interfaces': { + 'xe0': { + 'local_iface_name': 'ens785f0', + 'vld_id': 'private', + 'netmask': '255.255.255.0', + 'local_ip': '152.16.100.20', + 'dst_mac': '00:00:00:00:00:02', + 'local_mac': '00:00:00:00:00:04', + 'dst_ip': '152.16.100.19', + 'driver': 'i40e', + 'vpci': '0000:05:00.0', + 'dpdk_port_num': 0, + }, + 'xe1': { + 'local_iface_name': 'ens785f1', + 'netmask': '255.255.255.0', + 'local_ip': '152.16.100.21', + 'local_mac': '00:00:00:00:00:01', + 'driver': 'i40e', + 'vpci': '0000:05:00.1', + 'dpdk_port_num': 1, + }, + }, + 'password': 'r00t', + 'VNF model': 'tg_rfc2544_tpl.yaml', + 'user': 'root', + }, + 'vnf__1': { + 'name': 'vnf.yardstick', + 'vnfd-id-ref': 'vnf__1', + 'ip': '1.2.1.1', + 'interfaces': { + 'xe0': { + 'local_iface_name': 'ens786f0', + 'vld_id': 'private', + 'netmask': '255.255.255.0', + 'local_ip': '152.16.100.19', + 'dst_mac': '00:00:00:00:00:04', + 'local_mac': '00:00:00:00:00:02', + 'dst_ip': '152.16.100.20', + 'driver': 'i40e', + 'vpci': '0000:05:00.0', + 'dpdk_port_num': 0, + }, + 'xe1': { + 'local_iface_name': 'ens786f1', + 'vld_id': 'public', + 'netmask': '255.255.255.0', + 'local_ip': '152.16.40.19', + 'dst_mac': '00:00:00:00:00:03', + 'local_mac': '00:00:00:00:00:01', + 'dst_ip': '152.16.40.20', + 'driver': 'i40e', + 'vpci': '0000:05:00.1', + 'dpdk_port_num': 1, + }, + }, + 'routing_table': [ + { + 'netmask': '255.255.255.0', + 'gateway': '152.16.100.20', + 'network': '152.16.100.20', + 'if': 'xe0', + }, + { + 'netmask': '255.255.255.0', + 'gateway': '152.16.40.20', + 'network': '152.16.40.20', + 'if': 'xe1', + }, + ], + 'member-vnf-index': '2', + 'host': '1.2.1.1', + 'role': 'vnf', + 'user': 'root', + 'nd_route_tbl': [ + { + 'netmask': '112', + 'gateway': '0064:ff9b:0:0:0:0:9810:6414', + 'network': '0064:ff9b:0:0:0:0:9810:6414', + 'if': 'xe0', + }, + { + 'netmask': '112', + 'gateway': '0064:ff9b:0:0:0:0:9810:2814', + 'network': '0064:ff9b:0:0:0:0:9810:2814', + 'if': 'xe1', + }, + ], + 'password': 'r00t', + 'VNF model': 'prox_vnf.yaml', + }, + }, + } + + @mock.patch(SSH_HELPER) + def test___init__(self, ssh, mock_time): + mock_ssh(ssh) + prox_approx_vnf = ProxApproxVnf(NAME, self.VNFD0) + self.assertIsNone(prox_approx_vnf._vnf_process) + + @mock.patch(SSH_HELPER) + def test_collect_kpi_no_client(self, ssh, mock_time): + mock_ssh(ssh) + + prox_approx_vnf = ProxApproxVnf(NAME, self.VNFD0) + prox_approx_vnf.resource_helper = None + expected = { + 'packets_in': 0, + 'packets_dropped': 0, + 'packets_fwd': 0, + 'collect_stats': {'core': {}}, + } + result = prox_approx_vnf.collect_kpi() + self.assertEqual(result, expected) + + @mock.patch(SSH_HELPER) + def test_collect_kpi(self, ssh, mock_time): + mock_ssh(ssh) + + resource_helper = mock.MagicMock() + resource_helper.execute.return_value = list(range(12)) + resource_helper.collect_kpi.return_value = {'core': {'result': 234}} + + prox_approx_vnf = ProxApproxVnf(NAME, self.VNFD0) + prox_approx_vnf.resource_helper = resource_helper + + expected = { + 'packets_in': 7, + 'packets_dropped': 1, + 'packets_fwd': 6, + 'collect_stats': {'core': {'result': 234}}, + } + result = prox_approx_vnf.collect_kpi() + self.assertEqual(result, expected) + + @mock.patch(SSH_HELPER) + def test_collect_kpi_error(self, ssh, mock_time): + mock_ssh(ssh) + + resource_helper = mock.MagicMock() + + prox_approx_vnf = ProxApproxVnf(NAME, deepcopy(self.VNFD0)) + prox_approx_vnf.resource_helper = resource_helper + prox_approx_vnf.vnfd_helper['vdu'][0]['external-interface'] = [] + + with self.assertRaises(RuntimeError): + prox_approx_vnf.collect_kpi() + + def _get_file_abspath(self, filename, mock_time): + curr_path = os.path.dirname(os.path.abspath(__file__)) + file_path = os.path.join(curr_path, filename) + return file_path + + @mock.patch(SSH_HELPER) + def test_run_prox(self, ssh, mock_time): + mock_ssh(ssh) + + prox_approx_vnf = ProxApproxVnf(NAME, self.VNFD0) + + filewrapper = mock.MagicMock() + config_path = self.SCENARIO_CFG['options']["vnf__1"]["prox_config"] + prox_path = self.SCENARIO_CFG['options']["vnf__1"]["prox_path"] + prox_args = self.SCENARIO_CFG['options']["vnf__1"]["prox_args"] + prox_approx_vnf.WAIT_TIME = 0 + prox_approx_vnf._run_prox(filewrapper, config_path, prox_path, prox_args) + + self.assertEqual(prox_approx_vnf.ssh_helper.run.call_args[0][0], + "sudo bash -c 'cd /root/dppd-PROX-v035/build; " + "/root/dppd-PROX-v035/build/prox -o cli -t -f configs/l3-swap-2.cfg '") + + @mock.patch('yardstick.network_services.vnf_generic.vnf.sample_vnf.CpuSysCores') + @mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.find_relative_file') + @mock.patch(SSH_HELPER) + def test_instantiate(self, ssh, mock_find, mock_cpu_sys_cores, mock_time): + mock_ssh(ssh) + + mock_cpu_sys_cores.get_core_socket.return_value = {'0': '01234'} + + prox_approx_vnf = ProxApproxVnf(NAME, self.VNFD0) + prox_approx_vnf.ssh_helper = mock.MagicMock( + **{"execute.return_value": (0, "", ""), "bin_path": ""}) + prox_approx_vnf.setup_helper._setup_resources = mock.MagicMock() + prox_approx_vnf.setup_helper._find_used_drivers = mock.MagicMock() + prox_approx_vnf.setup_helper.used_drivers = {} + prox_approx_vnf.setup_helper.bound_pci = [] + prox_approx_vnf._run_prox = mock.MagicMock(return_value=0) + prox_approx_vnf.resource_helper = mock.MagicMock() + prox_approx_vnf.resource_helper.get_process_args.return_value = { + '-e': '', + '-t': '', + }, 'configs/l3-gen-2.cfg', '/root/dppd-PROX-v035/build/prox' + + prox_approx_vnf.copy_to_target = mock.MagicMock() + prox_approx_vnf.upload_prox_config = mock.MagicMock() + prox_approx_vnf.generate_prox_config_file = mock.MagicMock() + prox_approx_vnf.q_out.put("PROX started") + prox_approx_vnf.WAIT_TIME = 0 + + # if process it still running exitcode will be None + expected = 0, None + result = prox_approx_vnf.instantiate(self.SCENARIO_CFG, self.CONTEXT_CFG) + self.assertIn(result, expected) + + @mock.patch(SSH_HELPER) + def test_wait_for_instantiate_panic(self, ssh, mock_time): + mock_ssh(ssh, exec_result=(1, "", "")) + prox_approx_vnf = ProxApproxVnf(NAME, self.VNFD0) + prox_approx_vnf._vnf_process = mock.MagicMock(**{"is_alive.return_value": True}) + prox_approx_vnf._run_prox = mock.Mock(return_value=0) + prox_approx_vnf.WAIT_TIME = 0 + prox_approx_vnf.q_out.put("PANIC") + with self.assertRaises(RuntimeError): + prox_approx_vnf.wait_for_instantiate() + + @mock.patch(SSH_HELPER) + def test_scale(self, ssh, mock_time): + mock_ssh(ssh) + prox_approx_vnf = ProxApproxVnf(NAME, self.VNFD0) + with self.assertRaises(NotImplementedError): + prox_approx_vnf.scale('') + + @mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.socket') + @mock.patch(SSH_HELPER) + def test_terminate(self, ssh, mock_socket, mock_time): + mock_ssh(ssh) + prox_approx_vnf = ProxApproxVnf(NAME, self.VNFD0) + prox_approx_vnf._vnf_process = mock.MagicMock() + prox_approx_vnf._vnf_process.terminate = mock.Mock() + prox_approx_vnf.ssh_helper = mock.MagicMock() + prox_approx_vnf.setup_helper = mock.Mock() + prox_approx_vnf.resource_helper = mock.MagicMock() + + self.assertIsNone(prox_approx_vnf.terminate()) + + @mock.patch(SSH_HELPER) + def test__vnf_up_post(self, ssh, mock_time): + mock_ssh(ssh) + prox_approx_vnf = ProxApproxVnf(NAME, self.VNFD0) + prox_approx_vnf.resource_helper = resource_helper = mock.Mock() + + prox_approx_vnf._vnf_up_post() + self.assertEqual(resource_helper.up_post.call_count, 1) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/unit/network_services/vnf_generic/vnf/test_tg_prox.py b/tests/unit/network_services/vnf_generic/vnf/test_tg_prox.py new file mode 100644 index 000000000..1a01b9e15 --- /dev/null +++ b/tests/unit/network_services/vnf_generic/vnf/test_tg_prox.py @@ -0,0 +1,487 @@ +# Copyright (c) 2017 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +from __future__ import absolute_import +import unittest +import mock + +from tests.unit.network_services.vnf_generic.vnf.test_base import mock_ssh + + +SSH_HELPER = 'yardstick.network_services.vnf_generic.vnf.sample_vnf.VnfSshHelper' +NAME = 'vnf__1' + + +STL_MOCKS = { + 'stl': mock.MagicMock(), + 'stl.trex_stl_lib': mock.MagicMock(), + 'stl.trex_stl_lib.base64': mock.MagicMock(), + 'stl.trex_stl_lib.binascii': mock.MagicMock(), + 'stl.trex_stl_lib.collections': mock.MagicMock(), + 'stl.trex_stl_lib.copy': mock.MagicMock(), + 'stl.trex_stl_lib.datetime': mock.MagicMock(), + 'stl.trex_stl_lib.functools': mock.MagicMock(), + 'stl.trex_stl_lib.imp': mock.MagicMock(), + 'stl.trex_stl_lib.inspect': mock.MagicMock(), + 'stl.trex_stl_lib.json': mock.MagicMock(), + 'stl.trex_stl_lib.linecache': mock.MagicMock(), + 'stl.trex_stl_lib.math': mock.MagicMock(), + 'stl.trex_stl_lib.os': mock.MagicMock(), + 'stl.trex_stl_lib.platform': mock.MagicMock(), + 'stl.trex_stl_lib.pprint': mock.MagicMock(), + 'stl.trex_stl_lib.random': mock.MagicMock(), + 'stl.trex_stl_lib.re': mock.MagicMock(), + 'stl.trex_stl_lib.scapy': mock.MagicMock(), + 'stl.trex_stl_lib.socket': mock.MagicMock(), + 'stl.trex_stl_lib.string': mock.MagicMock(), + 'stl.trex_stl_lib.struct': mock.MagicMock(), + 'stl.trex_stl_lib.sys': mock.MagicMock(), + 'stl.trex_stl_lib.threading': mock.MagicMock(), + 'stl.trex_stl_lib.time': mock.MagicMock(), + 'stl.trex_stl_lib.traceback': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_async_client': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_client': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_exceptions': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_ext': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_jsonrpc_client': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_packet_builder_interface': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_packet_builder_scapy': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_port': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_stats': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_streams': mock.MagicMock(), + 'stl.trex_stl_lib.trex_stl_types': mock.MagicMock(), + 'stl.trex_stl_lib.types': mock.MagicMock(), + 'stl.trex_stl_lib.utils': mock.MagicMock(), + 'stl.trex_stl_lib.utils.argparse': mock.MagicMock(), + 'stl.trex_stl_lib.utils.collections': mock.MagicMock(), + 'stl.trex_stl_lib.utils.common': mock.MagicMock(), + 'stl.trex_stl_lib.utils.json': mock.MagicMock(), + 'stl.trex_stl_lib.utils.os': mock.MagicMock(), + 'stl.trex_stl_lib.utils.parsing_opts': mock.MagicMock(), + 'stl.trex_stl_lib.utils.pwd': mock.MagicMock(), + 'stl.trex_stl_lib.utils.random': mock.MagicMock(), + 'stl.trex_stl_lib.utils.re': mock.MagicMock(), + 'stl.trex_stl_lib.utils.string': mock.MagicMock(), + 'stl.trex_stl_lib.utils.sys': mock.MagicMock(), + 'stl.trex_stl_lib.utils.text_opts': mock.MagicMock(), + 'stl.trex_stl_lib.utils.text_tables': mock.MagicMock(), + 'stl.trex_stl_lib.utils.texttable': mock.MagicMock(), + 'stl.trex_stl_lib.warnings': mock.MagicMock(), + 'stl.trex_stl_lib.yaml': mock.MagicMock(), + 'stl.trex_stl_lib.zlib': mock.MagicMock(), + 'stl.trex_stl_lib.zmq': mock.MagicMock(), +} + +STLClient = mock.MagicMock() +stl_patch = mock.patch.dict("sys.modules", STL_MOCKS) +stl_patch.start() + +if stl_patch: + from yardstick.network_services.vnf_generic.vnf.tg_prox import ProxTrafficGen + from yardstick.network_services.traffic_profile.base import TrafficProfile + + +@mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.time') +class TestProxTrafficGen(unittest.TestCase): + VNFD0 = { + 'short-name': 'ProxVnf', + 'vdu': [ + { + 'routing_table': [ + { + 'network': '152.16.100.20', + 'netmask': '255.255.255.0', + 'gateway': '152.16.100.20', + 'if': 'xe0', + }, + { + 'network': '152.16.40.20', + 'netmask': '255.255.255.0', + 'gateway': '152.16.40.20', + 'if': 'xe1', + }, + ], + 'description': 'PROX approximation using DPDK', + 'name': 'proxvnf-baremetal', + 'nd_route_tbl': [ + { + 'network': '0064:ff9b:0:0:0:0:9810:6414', + 'netmask': '112', + 'gateway': '0064:ff9b:0:0:0:0:9810:6414', + 'if': 'xe0', + }, + { + 'network': '0064:ff9b:0:0:0:0:9810:2814', + 'netmask': '112', + 'gateway': '0064:ff9b:0:0:0:0:9810:2814', + 'if': 'xe1', + }, + ], + 'id': 'proxvnf-baremetal', + 'external-interface': [ + { + 'virtual-interface': { + 'dst_mac': '00:00:00:00:00:04', + 'vpci': '0000:05:00.0', + 'local_ip': '152.16.100.19', + 'type': 'PCI-PASSTHROUGH', + 'vld_id': '', + 'netmask': '255.255.255.0', + 'dpdk_port_num': '0', + 'bandwidth': '10 Gbps', + 'driver': "i40e", + 'dst_ip': '152.16.100.20', + 'local_iface_name': 'xe0', + 'local_mac': '00:00:00:00:00:02', + }, + 'vnfd-connection-point-ref': 'xe0', + 'name': 'xe0', + }, + { + 'virtual-interface': { + 'dst_mac': '00:00:00:00:00:03', + 'vpci': '0000:05:00.1', + 'local_ip': '152.16.40.19', + 'type': 'PCI-PASSTHROUGH', + 'vld_id': '', + 'driver': "i40e", + 'netmask': '255.255.255.0', + 'dpdk_port_num': '1', + 'bandwidth': '10 Gbps', + 'dst_ip': '152.16.40.20', + 'local_iface_name': 'xe1', + 'local_mac': '00:00:00:00:00:01', + }, + 'vnfd-connection-point-ref': 'xe1', + 'name': 'xe1', + }, + ], + }, + ], + 'description': 'PROX approximation using DPDK', + 'mgmt-interface': { + 'vdu-id': 'proxvnf-baremetal', + 'host': '1.2.1.1', + 'password': 'r00t', + 'user': 'root', + 'ip': '1.2.1.1', + }, + 'benchmark': { + 'kpi': [ + 'packets_in', + 'packets_fwd', + 'packets_dropped', + ], + }, + 'connection-point': [ + { + 'type': 'VPORT', + 'name': 'xe0', + }, + { + 'type': 'VPORT', + 'name': 'xe1', + }, + ], + 'id': 'ProxApproxVnf', + 'name': 'ProxVnf', + } + + VNFD = { + 'vnfd:vnfd-catalog': { + 'vnfd': [ + VNFD0, + ], + }, + } + + SCENARIO_CFG = { + 'task_path': "", + 'nodes': { + 'tg__1': 'trafficgen_1.yardstick', + 'vnf__1': 'vnf.yardstick'}, + 'runner': { + 'duration': 600, 'type': 'Duration'}, + 'topology': 'prox-tg-topology-2.yaml', + 'traffic_profile': '../../traffic_profiles/prox_binsearch.yaml', + 'type': 'NSPerf', + 'options': { + 'tg__1': {'prox_args': {'-e': '', + '-t': ''}, + 'prox_config': 'configs/l3-gen-2.cfg', + 'prox_path': + '/root/dppd-PROX-v035/build/prox'}, + 'vnf__1': { + 'prox_args': {'-t': ''}, + 'prox_config': 'configs/l3-swap-2.cfg', + 'prox_path': '/root/dppd-PROX-v035/build/prox'}}} + + CONTEXT_CFG = { + 'nodes': { + 'tg__2': { + 'member-vnf-index': '3', + 'role': 'TrafficGen', + 'name': 'trafficgen_2.yardstick', + 'vnfd-id-ref': 'tg__2', + 'ip': '1.2.1.1', + 'interfaces': { + 'xe0': { + 'local_iface_name': 'ens513f0', + 'vld_id': 'public', + 'netmask': '255.255.255.0', + 'local_ip': '152.16.40.20', + 'dst_mac': '00:00:00:00:00:01', + 'local_mac': '00:00:00:00:00:03', + 'dst_ip': '152.16.40.19', + 'driver': 'ixgbe', + 'vpci': '0000:02:00.0', + 'dpdk_port_num': 0, + }, + 'xe1': { + 'local_iface_name': 'ens513f1', + 'netmask': '255.255.255.0', + 'network': '202.16.100.0', + 'local_ip': '202.16.100.20', + 'local_mac': '00:1e:67:d0:60:5d', + 'driver': 'ixgbe', + 'vpci': '0000:02:00.1', + 'dpdk_port_num': 1, + }, + }, + 'password': 'r00t', + 'VNF model': 'l3fwd_vnf.yaml', + 'user': 'root', + }, + 'tg__1': { + 'member-vnf-index': '1', + 'role': 'TrafficGen', + 'name': 'trafficgen_1.yardstick', + 'vnfd-id-ref': 'tg__1', + 'ip': '1.2.1.1', + 'interfaces': { + 'xe0': { + 'local_iface_name': 'ens785f0', + 'vld_id': 'private', + 'netmask': '255.255.255.0', + 'local_ip': '152.16.100.20', + 'dst_mac': '00:00:00:00:00:02', + 'local_mac': '00:00:00:00:00:04', + 'dst_ip': '152.16.100.19', + 'driver': 'i40e', + 'vpci': '0000:05:00.0', + 'dpdk_port_num': 0, + }, + 'xe1': { + 'local_iface_name': 'ens785f1', + 'netmask': '255.255.255.0', + 'local_ip': '152.16.100.21', + 'local_mac': '00:00:00:00:00:01', + 'driver': 'i40e', + 'vpci': '0000:05:00.1', + 'dpdk_port_num': 1, + }, + }, + 'password': 'r00t', + 'VNF model': 'tg_rfc2544_tpl.yaml', + 'user': 'root', + }, + 'vnf__1': { + 'name': 'vnf.yardstick', + 'vnfd-id-ref': 'vnf__1', + 'ip': '1.2.1.1', + 'interfaces': { + 'xe0': { + 'local_iface_name': 'ens786f0', + 'vld_id': 'private', + 'netmask': '255.255.255.0', + 'local_ip': '152.16.100.19', + 'dst_mac': '00:00:00:00:00:04', + 'local_mac': '00:00:00:00:00:02', + 'dst_ip': '152.16.100.20', + 'driver': 'i40e', + 'vpci': '0000:05:00.0', + 'dpdk_port_num': 0, + }, + 'xe1': { + 'local_iface_name': 'ens786f1', + 'vld_id': 'public', + 'netmask': '255.255.255.0', + 'local_ip': '152.16.40.19', + 'dst_mac': '00:00:00:00:00:03', + 'local_mac': '00:00:00:00:00:01', + 'dst_ip': '152.16.40.20', + 'driver': 'i40e', + 'vpci': '0000:05:00.1', + 'dpdk_port_num': 1, + }, + }, + 'routing_table': [ + { + 'netmask': '255.255.255.0', + 'gateway': '152.16.100.20', + 'network': '152.16.100.20', + 'if': 'xe0', + }, + { + 'netmask': '255.255.255.0', + 'gateway': '152.16.40.20', + 'network': '152.16.40.20', + 'if': 'xe1', + }, + ], + 'member-vnf-index': '2', + 'host': '1.2.1.1', + 'role': 'vnf', + 'user': 'root', + 'nd_route_tbl': [ + { + 'netmask': '112', + 'gateway': '0064:ff9b:0:0:0:0:9810:6414', + 'network': '0064:ff9b:0:0:0:0:9810:6414', + 'if': 'xe0', + }, + { + 'netmask': '112', + 'gateway': '0064:ff9b:0:0:0:0:9810:2814', + 'network': '0064:ff9b:0:0:0:0:9810:2814', + 'if': 'xe1', + }, + ], + 'password': 'r00t', + 'VNF model': 'prox_vnf.yaml', + }, + }, + } + + TRAFFIC_PROFILE = { + 'description': 'Binary search for max no-drop throughput over given packet sizes', + 'name': 'prox_binsearch', + 'schema': 'nsb:traffic_profile:0.1', + 'traffic_profile': { + 'duration': 5, + 'lower_bound': 0.0, + 'packet_sizes': [64, 65], + 'test_precision': 1.0, + 'tolerated_loss': 0.0, + 'traffic_type': 'ProxBinSearchProfile', + 'upper_bound': 100.0}} + + @mock.patch(SSH_HELPER) + def test___init__(self, ssh, mock_time): + mock_ssh(ssh) + prox_traffic_gen = ProxTrafficGen(NAME, self.VNFD0) + self.assertIsNone(prox_traffic_gen._tg_process) + self.assertIsNone(prox_traffic_gen._traffic_process) + + @mock.patch(SSH_HELPER) + def test_collect_kpi(self, ssh, mock_time): + mock_ssh(ssh) + + prox_traffic_gen = ProxTrafficGen(NAME, self.VNFD0) + prox_traffic_gen._queue = mock.MagicMock() + self.assertEqual({}, prox_traffic_gen.collect_kpi()) + + @mock.patch('yardstick.network_services.vnf_generic.vnf.sample_vnf.CpuSysCores') + @mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.find_relative_file') + @mock.patch(SSH_HELPER) + def test_instantiate(self, ssh, mock_find, mock_cpu_sys_cores, mock_time): + mock_ssh(ssh) + + mock_cpu_sys_cores.get_core_socket.return_value = {'0': '01234'} + + mock_traffic_profile = mock.Mock(autospec=TrafficProfile) + mock_traffic_profile.get_traffic_definition.return_value = "64" + mock_traffic_profile.params = self.TRAFFIC_PROFILE + + vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] + prox_traffic_gen = ProxTrafficGen(NAME, vnfd) + prox_traffic_gen.ssh_helper = mock.MagicMock( + **{"execute.return_value": (0, "", ""), "bin_path": ""}) + prox_traffic_gen.setup_helper._setup_resources = mock.MagicMock() + prox_traffic_gen.setup_hugepages = mock.MagicMock() + prox_traffic_gen.generate_prox_config_file = mock.MagicMock() + prox_traffic_gen.upload_prox_config = mock.MagicMock() + prox_traffic_gen.setup_helper._find_used_drivers = mock.MagicMock() + prox_traffic_gen.setup_helper.used_drivers = {} + prox_traffic_gen.setup_helper.bound_pci = [] + prox_traffic_gen._start_server = mock.Mock(return_value=0) + prox_traffic_gen._tg_process = mock.MagicMock() + prox_traffic_gen._tg_process.start = mock.Mock() + prox_traffic_gen._tg_process.exitcode = 0 + prox_traffic_gen._tg_process._is_alive = mock.Mock(return_value=1) + prox_traffic_gen.ssh_helper = mock.MagicMock() + prox_traffic_gen.resource_helper.ssh_helper = mock.MagicMock() + scenario_cfg = { + 'task_path': '', + 'options': {'tg__1': {'prox_args': {'-e': '', + '-t': ''}, + 'prox_config': 'configs/l3-gen-2.cfg', + 'prox_path': '/root/dppd-PROX-v035/build/prox'}, + 'vnf__1': {'prox_args': {'-t': ''}, + 'prox_config': 'configs/l3-swap-2.cfg', + 'prox_path': '/root/dppd-PROX-v035/build/prox'} + } + } + prox_traffic_gen.instantiate(scenario_cfg, {}) + + @mock.patch(SSH_HELPER) + def test__traffic_runner(self, ssh, mock_time): + mock_ssh(ssh) + + mock_traffic_profile = mock.Mock(autospec=TrafficProfile) + mock_traffic_profile.get_traffic_definition.return_value = "64" + mock_traffic_profile.execute.return_value = "64" + mock_traffic_profile.params = self.TRAFFIC_PROFILE + + vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] + sut = ProxTrafficGen(NAME, vnfd) + sut.prox_config_dict = {} + sut._get_socket = mock.MagicMock() + sut.ssh_helper = mock.Mock() + sut.ssh_helper.run = mock.Mock() + sut._vpci_ascending = ["0000:05:00.0", "0000:05:00.1"] + sut._connect_client = mock.Mock(autospec=STLClient) + sut._connect_client.get_stats = mock.Mock(return_value="0") + sut._traffic_runner(mock_traffic_profile) + + @mock.patch(SSH_HELPER) + def test_scale(self, ssh, mock_time): + mock_ssh(ssh, exec_result=(1, "", "")) + vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] + prox_traffic_gen = ProxTrafficGen(NAME, vnfd) + with self.assertRaises(NotImplementedError): + prox_traffic_gen.scale('') + + @mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.socket') + @mock.patch(SSH_HELPER) + def test_listen_traffic(self, ssh, mock_socket, mock_time): + mock_ssh(ssh) + vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] + prox_traffic_gen = ProxTrafficGen(NAME, vnfd) + self.assertIsNone(prox_traffic_gen.listen_traffic(mock.Mock())) + + @mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.socket') + @mock.patch(SSH_HELPER) + def test_terminate(self, ssh, mock_socket, mock_time): + mock_ssh(ssh) + vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] + prox_traffic_gen = ProxTrafficGen(NAME, vnfd) + prox_traffic_gen._terminated = mock.MagicMock() + prox_traffic_gen._traffic_process = mock.MagicMock() + prox_traffic_gen._traffic_process.terminate = mock.Mock() + prox_traffic_gen.ssh_helper = mock.MagicMock() + prox_traffic_gen.setup_helper = mock.MagicMock() + prox_traffic_gen.resource_helper = mock.MagicMock() + self.assertEqual(None, prox_traffic_gen.terminate()) |