diff options
Diffstat (limited to 'scripts')
6 files changed, 316 insertions, 130 deletions
diff --git a/scripts/automation/regression/functional_tests/filters_test.py b/scripts/automation/regression/functional_tests/filters_test.py new file mode 100644 index 00000000..abb92999 --- /dev/null +++ b/scripts/automation/regression/functional_tests/filters_test.py @@ -0,0 +1,107 @@ +#!/router/bin/python + +import functional_general_test +#HACK FIX ME START +import sys +import os + +CURRENT_PATH = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.abspath(os.path.join(CURRENT_PATH, '../../trex_control_plane/common'))) +#HACK FIX ME END +import filters +from nose.tools import assert_equal +from nose.tools import assert_not_equal +from nose.tools import assert_raises +from nose.tools import assert_true, assert_false +from nose.tools import raises + + +class ToggleFilter_Test(functional_general_test.CGeneralFunctional_Test): + + def setUp(self): + self.list_db = [1, 2, 3, 4, 5] + self.set_db = {1, 2, 3, 4, 5} + self.tuple_db = (1, 2, 3, 4, 5) + self.dict_db = {str(x): x**2 + for x in range(5)} + + def test_init_with_dict(self): + toggle_filter = filters.ToggleFilter(self.dict_db) + assert_equal(toggle_filter._toggle_db, set(self.dict_db.keys())) + assert_equal(toggle_filter.filter_items(), self.dict_db) + + + def test_init_with_list(self): + toggle_filter = filters.ToggleFilter(self.list_db) + assert_equal(toggle_filter._toggle_db, set(self.list_db)) + assert_equal(toggle_filter.filter_items(), self.list_db) + + def test_init_with_set(self): + toggle_filter = filters.ToggleFilter(self.set_db) + assert_equal(toggle_filter._toggle_db, self.set_db) + assert_equal(toggle_filter.filter_items(), self.set_db) + + def test_init_with_tuple(self): + toggle_filter = filters.ToggleFilter(self.tuple_db) + assert_equal(toggle_filter._toggle_db, set(self.tuple_db)) + assert_equal(toggle_filter.filter_items(), self.tuple_db) + + @raises(TypeError) + def test_init_with_non_iterable(self): + toggle_filter = filters.ToggleFilter(15) + + def test_dict_toggeling(self): + toggle_filter = filters.ToggleFilter(self.dict_db) + assert_false(toggle_filter.toggle_item("3")) + assert_equal(toggle_filter._toggle_db, {'0', '1', '2', '4'}) + assert_true(toggle_filter.toggle_item("3")) + assert_equal(toggle_filter._toggle_db, {'0', '1', '2', '3', '4'}) + assert_false(toggle_filter.toggle_item("2")) + assert_false(toggle_filter.toggle_item("4")) + self.dict_db.update({'5': 25, '6': 36}) + assert_true(toggle_filter.toggle_item("6")) + + assert_equal(toggle_filter.filter_items(), {'0': 0, '1': 1, '3': 9, '6': 36}) + + del self.dict_db['1'] + assert_equal(toggle_filter.filter_items(), {'0': 0, '3': 9, '6': 36}) + + def test_dict_toggeling_negative(self): + toggle_filter = filters.ToggleFilter(self.dict_db) + assert_raises(KeyError, toggle_filter.toggle_item, "100") + + def test_list_toggeling(self): + toggle_filter = filters.ToggleFilter(self.list_db) + assert_false(toggle_filter.toggle_item(3)) + assert_equal(toggle_filter._toggle_db, {1, 2, 4, 5}) + assert_true(toggle_filter.toggle_item(3)) + assert_equal(toggle_filter._toggle_db, {1, 2, 3, 4, 5}) + assert_false(toggle_filter.toggle_item(2)) + assert_false(toggle_filter.toggle_item(4)) + self.list_db.extend([6 ,7]) + assert_true(toggle_filter.toggle_item(6)) + + assert_equal(toggle_filter.filter_items(), [1, 3 , 5, 6]) + + self.list_db.remove(1) + assert_equal(toggle_filter.filter_items(), [3, 5, 6]) + + def test_list_toggling_negative(self): + toggle_filter = filters.ToggleFilter(self.list_db) + assert_raises(KeyError, toggle_filter.toggle_item, 10) + + def test_toggle_multiple_items(self): + toggle_filter = filters.ToggleFilter(self.list_db) + assert_false(toggle_filter.toggle_items(1, 3, 5)) + assert_equal(toggle_filter._toggle_db, {2, 4}) + assert_true(toggle_filter.toggle_items(1, 5)) + assert_equal(toggle_filter._toggle_db, {1, 2, 4, 5}) + + def test_dont_show_after_init(self): + toggle_filter = filters.ToggleFilter(self.list_db, show_by_default = False) + assert_equal(toggle_filter._toggle_db, set()) + assert_equal(toggle_filter.filter_items(), []) + + + def tearDown(self): + pass diff --git a/scripts/automation/trex_control_plane/stl/console/trex_console.py b/scripts/automation/trex_control_plane/stl/console/trex_console.py index a126bf35..f8161dcb 100755 --- a/scripts/automation/trex_control_plane/stl/console/trex_console.py +++ b/scripts/automation/trex_control_plane/stl/console/trex_console.py @@ -577,7 +577,7 @@ class TRexConsole(TRexGeneralCmd): info = self.stateless_client.get_connection_info() exe = './trex-console --top -t -q -s {0} -p {1} --async_port {2}'.format(info['server'], info['sync_port'], info['async_port']) - cmd = ['/usr/bin/xterm', '-geometry', '111x48', '-sl', '0', '-title', 'trex_tui', '-e', exe] + cmd = ['/usr/bin/xterm', '-geometry', '111x49', '-sl', '0', '-title', 'trex_tui', '-e', exe] # detach child self.terminal = subprocess.Popen(cmd, preexec_fn = os.setpgrp) diff --git a/scripts/automation/trex_control_plane/stl/console/trex_tui.py b/scripts/automation/trex_control_plane/stl/console/trex_tui.py index cbaae392..231eff93 100644 --- a/scripts/automation/trex_control_plane/stl/console/trex_tui.py +++ b/scripts/automation/trex_control_plane/stl/console/trex_tui.py @@ -13,6 +13,7 @@ else: from trex_stl_lib.utils.text_opts import * from trex_stl_lib.utils import text_tables from trex_stl_lib import trex_stl_stats +from trex_stl_lib.utils.filters import ToggleFilter # for STL exceptions from trex_stl_lib.api import * @@ -62,34 +63,38 @@ class TrexTUIDashBoard(TrexTUIPanel): def __init__ (self, mng): super(TrexTUIDashBoard, self).__init__(mng, "dashboard") + self.ports = self.stateless_client.get_all_ports() + self.key_actions = OrderedDict() self.key_actions['c'] = {'action': self.action_clear, 'legend': 'clear', 'show': True} - self.key_actions['p'] = {'action': self.action_pause, 'legend': 'pause', 'show': True} - self.key_actions['r'] = {'action': self.action_resume, 'legend': 'resume', 'show': True} + self.key_actions['p'] = {'action': self.action_pause, 'legend': 'pause', 'show': True, 'color': 'red'} + self.key_actions['r'] = {'action': self.action_resume, 'legend': 'resume', 'show': True, 'color': 'blue'} self.key_actions['+'] = {'action': self.action_raise, 'legend': 'up 5%', 'show': True} self.key_actions['-'] = {'action': self.action_lower, 'legend': 'low 5%', 'show': True} self.key_actions['o'] = {'action': self.action_show_owned, 'legend': 'owned ports', 'show': True} self.key_actions['a'] = {'action': self.action_show_all, 'legend': 'all ports', 'show': True} + # register all the ports to the toggle action + for port_id in self.ports: + self.key_actions[str(port_id)] = {'action': self.action_toggle_port(port_id), 'legend': 'port {0}'.format(port_id), 'show': False} + + + self.toggle_filter = ToggleFilter(self.ports) + if self.stateless_client.get_acquired_ports(): - self.ports_filter = self.FILTER_ACQUIRED + self.action_show_owned() else: - self.ports_filter = self.FILTER_ALL - + self.action_show_all() - def get_ports (self): - if self.ports_filter == self.FILTER_ACQUIRED: - return self.stateless_client.get_acquired_ports() - elif self.ports_filter == self.FILTER_ALL: - return self.stateless_client.get_all_ports() + def get_showed_ports (self): + return self.toggle_filter.filter_items() - assert(0) def show (self): - stats = self.stateless_client._get_formatted_stats(self.get_ports()) + stats = self.stateless_client._get_formatted_stats(self.get_showed_ports()) # print stats to screen for stat_type, stat_data in stats.items(): text_tables.print_table_with_header(stat_data.text_table, stat_type) @@ -101,17 +106,21 @@ class TrexTUIDashBoard(TrexTUIPanel): allowed['c'] = self.key_actions['c'] allowed['o'] = self.key_actions['o'] allowed['a'] = self.key_actions['a'] + for i in self.ports: + allowed[str(i)] = self.key_actions[str(i)] + - if self.ports_filter == self.FILTER_ALL and self.stateless_client.get_acquired_ports() != self.stateless_client.get_all_ports(): + # if not all ports are acquired - no operations + if not (set(self.get_showed_ports()) <= set(self.stateless_client.get_acquired_ports())): return allowed - if len(self.stateless_client.get_transmitting_ports()) > 0: + # if any/some ports are transmitting - support those actions + if set(self.get_showed_ports()) & set(self.stateless_client.get_transmitting_ports()): allowed['p'] = self.key_actions['p'] allowed['+'] = self.key_actions['+'] allowed['-'] = self.key_actions['-'] - - if len(self.stateless_client.get_paused_ports()) > 0: + if set(self.get_showed_ports()) & set(self.stateless_client.get_paused_ports()): allowed['r'] = self.key_actions['r'] return allowed @@ -120,7 +129,7 @@ class TrexTUIDashBoard(TrexTUIPanel): ######### actions def action_pause (self): try: - rc = self.stateless_client.pause(ports = self.mng.ports) + rc = self.stateless_client.pause(ports = self.get_showed_ports()) except STLError: pass @@ -130,7 +139,7 @@ class TrexTUIDashBoard(TrexTUIPanel): def action_resume (self): try: - self.stateless_client.resume(ports = self.mng.ports) + self.stateless_client.resume(ports = self.get_showed_ports()) except STLError: pass @@ -139,7 +148,7 @@ class TrexTUIDashBoard(TrexTUIPanel): def action_raise (self): try: - self.stateless_client.update(mult = "5%+", ports = self.mng.ports) + self.stateless_client.update(mult = "5%+", ports = self.get_showed_ports()) except STLError: pass @@ -148,7 +157,7 @@ class TrexTUIDashBoard(TrexTUIPanel): def action_lower (self): try: - self.stateless_client.update(mult = "5%-", ports = self.mng.ports) + self.stateless_client.update(mult = "5%-", ports = self.get_showed_ports()) except STLError: pass @@ -156,116 +165,26 @@ class TrexTUIDashBoard(TrexTUIPanel): def action_show_owned (self): - self.ports_filter = self.FILTER_ACQUIRED + self.toggle_filter.reset() + self.toggle_filter.toggle_items(*self.stateless_client.get_acquired_ports()) return "" def action_show_all (self): - self.ports_filter = self.FILTER_ALL + self.toggle_filter.reset() + self.toggle_filter.toggle_items(*self.stateless_client.get_all_ports()) return "" def action_clear (self): - self.stateless_client.clear_stats(self.mng.ports) + self.stateless_client.clear_stats(self.toggle_filter.filter_items()) return "cleared all stats" -# port panel -class TrexTUIPort(TrexTUIPanel): - def __init__ (self, mng, port_id): - super(TrexTUIPort, self).__init__(mng, "port {0}".format(port_id)) - - self.port_id = port_id - self.port = self.mng.stateless_client.get_port(port_id) - - self.key_actions = OrderedDict() - - self.key_actions['c'] = {'action': self.action_clear, 'legend': 'clear', 'show': True} - self.key_actions['p'] = {'action': self.action_pause, 'legend': 'pause', 'show': True} - self.key_actions['r'] = {'action': self.action_resume, 'legend': 'resume', 'show': True} - self.key_actions['+'] = {'action': self.action_raise, 'legend': 'up 5%', 'show': True} - self.key_actions['-'] = {'action': self.action_lower, 'legend': 'low 5%', 'show': True} - self.key_actions['t'] = {'action': self.action_toggle_graph, 'legend': 'toggle graph', 'show': True} - - - def show (self): - if self.mng.tui.is_graph is False: - stats = self.stateless_client._get_formatted_stats([self.port_id]) - # print stats to screen - for stat_type, stat_data in stats.items(): - text_tables.print_table_with_header(stat_data.text_table, stat_type) - else: - stats = self.stateless_client._get_formatted_stats([self.port_id], stats_mask = trex_stl_stats.GRAPH_PORT_COMPACT) - for stat_type, stat_data in stats.items(): - text_tables.print_table_with_header(stat_data.text_table, stat_type) - - def get_key_actions (self): - - allowed = OrderedDict() - - allowed['c'] = self.key_actions['c'] - allowed['t'] = self.key_actions['t'] - - if self.port_id not in self.stateless_client.get_acquired_ports(): - return allowed - - if self.port.state == self.port.STATE_TX: - allowed['p'] = self.key_actions['p'] - allowed['+'] = self.key_actions['+'] - allowed['-'] = self.key_actions['-'] - - elif self.port.state == self.port.STATE_PAUSE: - allowed['r'] = self.key_actions['r'] - - - return allowed - - def action_toggle_graph(self): - try: - self.mng.tui.is_graph = not self.mng.tui.is_graph - except Exception: - pass - - return "" - - def action_pause (self): - try: - self.stateless_client.pause(ports = [self.port_id]) - except STLError: - pass - - return "" - - def action_resume (self): - try: - self.stateless_client.resume(ports = [self.port_id]) - except STLError: - pass - - return "" - - - def action_raise (self): - mult = {'type': 'percentage', 'value': 5, 'op': 'add'} - - try: - self.stateless_client.update(mult = mult, ports = [self.port_id]) - except STLError: - pass - - return "" - - def action_lower (self): - mult = {'type': 'percentage', 'value': 5, 'op': 'sub'} - - try: - self.stateless_client.update(mult = mult, ports = [self.port_id]) - except STLError: - pass - - return "" + def action_toggle_port(self, port_id): + def action_toggle_port_x(): + self.toggle_filter.toggle_item(port_id) + return "" - def action_clear (self): - self.stateless_client.clear_stats([self.port_id]) - return "port {0}: cleared stats".format(self.port_id) + return action_toggle_port_x @@ -333,10 +252,6 @@ class TrexTUIPanelManager(): self.key_actions['g'] = {'action': self.action_show_dash, 'legend': 'dashboard', 'show': True} self.key_actions['s'] = {'action': self.action_show_sstats, 'legend': 'streams stats', 'show': True} - for port_id in self.ports: - self.key_actions[str(port_id)] = {'action': self.action_show_port(port_id), 'legend': 'port {0}'.format(port_id), 'show': False} - self.panels['port {0}'.format(port_id)] = TrexTUIPort(self, port_id) - # start with dashboard self.main_panel = self.panels['dashboard'] @@ -349,23 +264,30 @@ class TrexTUIPanelManager(): self.dis_bar = SimpleBar('status: ', ['X', ' ']) self.show_log = False + def generate_legend (self): + self.legend = "\n{:<12}".format("browse:") for k, v in self.key_actions.items(): if v['show']: x = "'{0}' - {1}, ".format(k, v['legend']) - self.legend += "{:}".format(x) - - self.legend += "'0-{0}' - port display".format(len(self.ports) - 1) + if v.get('color'): + self.legend += "{:}".format(format_text(x, v.get('color'))) + else: + self.legend += "{:}".format(x) self.legend += "\n{:<12}".format(self.main_panel.get_name() + ":") for k, v in self.main_panel.get_key_actions().items(): if v['show']: x = "'{0}' - {1}, ".format(k, v['legend']) - self.legend += "{:}".format(x) + + if v.get('color'): + self.legend += "{:}".format(format_text(x, v.get('color'))) + else: + self.legend += "{:}".format(x) def print_connection_status (self): @@ -433,6 +355,7 @@ class TrexTUIPanelManager(): return action_show_port_x + def action_show_sstats (self): self.main_panel = self.panels['sstats'] self.init(self.show_log) diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_port.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_port.py index 16e55d73..5cf94bda 100644 --- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_port.py +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_port.py @@ -76,6 +76,9 @@ class Port(object): def get_speed_bps (self): return (self.info['speed'] * 1000 * 1000 * 1000) + def get_formatted_speed (self): + return "{0} Gbps".format(self.info['speed']) + # take the port def acquire(self, force = False): params = {"port_id": self.port_id, diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py index 4057c50d..42bef360 100644 --- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py @@ -251,6 +251,7 @@ class CTRexInfoGenerator(object): return_stats_data = {} per_field_stats = OrderedDict([("owner", []), ("state", []), + ("speed", []), ("--", []), ("Tx bps L2", []), ("Tx bps L1", []), @@ -767,9 +768,17 @@ class CPortStats(CTRexStats): else: state = format_text(state, 'bold') + # mark owned ports by color + if self._port_obj: + owner = self._port_obj.get_owner() + if self._port_obj.is_acquired(): + owner = format_text(owner, 'green') + else: + owner = '' - return {"owner": self._port_obj.get_owner() if self._port_obj else "", + return {"owner": owner, "state": "{0}".format(state), + "speed": self._port_obj.get_formatted_speed() if self._port_obj else '', "--": " ", "---": " ", diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/filters.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/filters.py new file mode 100644 index 00000000..714f7807 --- /dev/null +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/filters.py @@ -0,0 +1,144 @@ + +def shallow_copy(x): + return type(x)(x) + + +class ToggleFilter(object): + """ + This class provides a "sticky" filter, that works by "toggling" items of the original database on and off. + """ + def __init__(self, db_ref, show_by_default=True): + """ + Instantiate a ToggleFilter object + + :parameters: + db_ref : iterable + an iterable object (i.e. list, set etc) that would serve as the reference db of the instance. + Changes in that object will affect the output of ToggleFilter instance. + + show_by_default: bool + decide if by default all the items are "on", i.e. these items will be presented if no other + toggling occurred. + + default value : **True** + + """ + self._data = db_ref + self._toggle_db = set() + self._filter_method = filter + self.__set_initial_state(show_by_default) + + def reset (self): + """ + Toggles off all the items + """ + self._toggle_db = set() + + + def toggle_item(self, item_key): + """ + Toggle a single item in/out. + + :parameters: + item_key : + an item the by its value the filter can decide to toggle or not. + Example: int, str and so on. + + :return: + + **True** if item toggled **into** the filtered items + + **False** if item toggled **out from** the filtered items + + :raises: + + KeyError, in case if item key is not part of the toggled list and not part of the referenced db. + + """ + if item_key in self._toggle_db: + self._toggle_db.remove(item_key) + return False + elif item_key in self._data: + self._toggle_db.add(item_key) + return True + else: + raise KeyError("Provided item key isn't a key of the referenced data structure.") + + def toggle_items(self, *args): + """ + Toggle multiple items in/out with a single call. Each item will be ha. + + :parameters: + args : iterable + an iterable object containing all item keys to be toggled in/out + + :return: + + **True** if all toggled items were toggled **into** the filtered items + + **False** if at least one of the items was toggled **out from** the filtered items + + :raises: + + KeyError, in case if ont of the item keys was not part of the toggled list and not part of the referenced db. + + """ + # in python 3, 'map' returns an iterator, so wrapping with 'list' call creates same effect for both python 2 and 3 + return all(list(map(self.toggle_item, args))) + + def filter_items(self): + """ + Filters the pointed database by showing only the items mapped at toggle_db set. + + :returns: + Filtered data of the original object. + + """ + return self._filter_method(self.__toggle_filter, self._data) + + # private methods + + def __set_initial_state(self, show_by_default): + try: + _ = (x for x in self._data) + if isinstance(self._data, dict): + self._filter_method = ToggleFilter.dict_filter + if show_by_default: + self._toggle_db = set(self._data.keys()) + return + elif isinstance(self._data, list): + self._filter_method = ToggleFilter.list_filter + elif isinstance(self._data, set): + self._filter_method = ToggleFilter.set_filter + elif isinstance(self._data, tuple): + self._filter_method = ToggleFilter.tuple_filter + if show_by_default: + self._toggle_db = set(shallow_copy(self._data)) # assuming all relevant data with unique identifier + return + except TypeError: + raise TypeError("provided data object is not iterable") + + def __toggle_filter(self, x): + return (x in self._toggle_db) + + # static utility methods + + @staticmethod + def dict_filter(function, iterable): + assert isinstance(iterable, dict) + return {k: v + for k,v in iterable.items() + if function(k)} + + @staticmethod + def list_filter(function, iterable): + # in python 3, filter returns an iterator, so wrapping with list creates same effect for both python 2 and 3 + return list(filter(function, iterable)) + + @staticmethod + def set_filter(function, iterable): + return {x + for x in iterable + if function(x)} + + @staticmethod + def tuple_filter(function, iterable): + return tuple(filter(function, iterable)) + + +if __name__ == "__main__": + pass |