From 1ee04fb4b07e801e4c6a4bde87e618b385a64c3c Mon Sep 17 00:00:00 2001 From: Sangita Maity Date: Wed, 24 Mar 2021 10:06:58 -0700 Subject: [PATCH] Modified the tests to use mock functionality of get_child_port function under portconfig utility (#1464) Modified the tests to use mock functionality of get_child_port function under portconfig utility. This will remove the dependency of port config utility in the sonic-buildimage and make the test case more robust specific to the DPB cli utility. Signed-off-by: Sangita Maity --- tests/config_dpb_test.py | 272 +++++++++++++++++++++++++++++++++++---- 1 file changed, 246 insertions(+), 26 deletions(-) diff --git a/tests/config_dpb_test.py b/tests/config_dpb_test.py index e8f3149682..e347538bcf 100644 --- a/tests/config_dpb_test.py +++ b/tests/config_dpb_test.py @@ -1,5 +1,6 @@ import json import os +import re from imp import load_source from unittest import mock @@ -16,12 +17,12 @@ os.path.join(os.path.dirname(__file__), '..', 'config', 'config_mgmt.py')) import config_mgmt -breakout_cfg_file_json = { +# Sample platform.json for Test +BRKOUT_CFG_FILE_JSON = { "interfaces": { "Ethernet0": { "index": "1,1,1,1", "lanes": "65,66,67,68", - "alias_at_lanes": "Eth1/1, Eth1/2, Eth1/3, Eth1/4", "breakout_modes": { "1x100G[40G]": ["Eth1"], "2x50G": ["Eth1/1", "Eth1/3"], @@ -31,7 +32,6 @@ "Ethernet4": { "index": "2,2,2,2", "lanes": "69,70,71,72", - "alias_at_lanes": "Eth2/1, Eth2/2, Eth2/3, Eth2/4", "breakout_modes": { "1x100G[40G]": ["Eth2"], "2x50G": ["Eth2/1", "Eth2/3"], @@ -42,7 +42,6 @@ "Ethernet8": { "index": "3,3,3,3", "lanes": "73,74,75,76", - "alias_at_lanes": "Eth3/1, Eth3/2, Eth3/3, Eth3/4", "breakout_modes": { "1x100G[40G]": ["Eth3"], "2x50G": ["Eth3/1", "Eth3/3"], @@ -53,7 +52,6 @@ "Ethernet12": { "index": "4,4,4,4", "lanes": "77,78,79,80", - "alias_at_lanes": "Eth4/1, Eth4/2, Eth4/3, Eth4/4", "breakout_modes": { "1x100G[40G]": ["Eth4"], "2x50G": ["Eth4/1", "Eth4/3"], @@ -63,6 +61,17 @@ } } +# Default Parameter +PREFIX = "Ethernet" +SPEED_LANE_MAP = { + "4x25G[10G]": [1,1,1,1], + "2x50G": [2,2], + "1x100G[40G]": [4], + "1x50G(2)+2x25G(2)": [2,1,1], + "2x25G(2)+1x50G(2)": [1,1,2] +} +LANE_SPEED = 25000 + @pytest.fixture(scope='module') def breakout_cfg_file(): ''' @@ -71,7 +80,7 @@ def breakout_cfg_file(): file = '/tmp/breakout_cfg_file.json' print("File is:{}",file) with open(file, 'w') as f: - json.dump(breakout_cfg_file_json, f, indent=4) + json.dump(BRKOUT_CFG_FILE_JSON, f, indent=4) yield file os.system("rm /tmp/breakout_cfg_file.json") @@ -163,6 +172,95 @@ def config_mgmt_dpb(cfgdb): cmdpb._verifyAsicDB = mock.MagicMock(return_value=True) return cmdpb +def _generate_args(portIdx, laneIdx, mode): + ''' + Generate port to deleted, added and {lanes, speed} setting based on + current and new mode. + + Parameters: + portIdx (int): Port Index. + laneIdx (int): Lane Index. + mode (str): can be current breakout mode or target breakout mode of Port. + + Example -> + For generate_args(0, 65, '4x25G', '2x25G(2)+1x50G(2)'): + Return: + childPorts, pJson (tuple)[list, dict] + Example -> + childPorts: ['Ethernet0', 'Ethernet1', 'Ethernet2', 'Ethernet3'] + pJson: { + 'PORT': { + 'Ethernet0': {'speed': '25000', 'lanes': '65'}, + 'Ethernet1': {'speed': '25000', 'lanes': '66'}, + 'Ethernet2': {'speed': '50000', 'lanes': '67,68'} + } + } + ''' + + # Generate child Ports + l = list(SPEED_LANE_MAP[mode]) + l.insert(0, 0) + id = portIdx + childPorts = list() + + for i in l[:-1]: + id = id + i + portName = portName = "{}{}".format(PREFIX, id) + childPorts.append(portName) + + # Generate port Json for child ports + l = SPEED_LANE_MAP[mode] + pJson = {"PORT": {}} + li = laneIdx + pi = 0 + + for i in l: + speed = int(LANE_SPEED)*int(i) + lanes = [str(int(li)+int(j)) for j in range(i)]; lanes = ','.join(lanes) + pJson['PORT'][childPorts[pi]] = {"speed": str(speed), "lanes": str(lanes)} + li = int(li)+int(i); pi = pi + 1 + + return childPorts, pJson + +def get_child_ports_mock(interface, mode): + ''' + get_child_ports function. portconfig class instance with mocked functions. + + Parameters: + interface (str): Interface Name. + mode (str): can be current breakout mode or target breakout mode of Port. + + Return: + childPorts, pJson (tuple)[list, dict] + Example-> Input sample: interface = 'Ethernet0' + mode = "2x25G(2)+1x50G(2)" + + childPorts: ['Ethernet0', 'Ethernet1', 'Ethernet2'] + pJson: { + 'PORT': { + 'Ethernet0': {'speed': '25000', 'lanes': '65'}, + 'Ethernet1': {'speed': '25000', 'lanes': '66'}, + 'Ethernet2': {'speed': '50000', 'lanes': '67,68'} + } + } + ''' + + interface_portmap = dict() + if interface in BRKOUT_CFG_FILE_JSON["interfaces"].keys(): + fv = BRKOUT_CFG_FILE_JSON["interfaces"][interface] + portIdx_reg = re.search("{}(\d+)".format(PREFIX), interface) + if portIdx_reg is not None: + portIdx = int(portIdx_reg.group(1)) + laneIdx = fv["lanes"].split(",")[0] + interface_portmap[interface] = { "portIdx": portIdx, "laneIdx": laneIdx } + + _, pJson = _generate_args(portIdx, laneIdx, mode) + return pJson['PORT'] + else: + return {} + else: + return {} + class TestConfigDPB(object): @classmethod def setup_class(cls): @@ -229,6 +327,11 @@ def test_config_breakout_extra_table_warning(self, breakout_cfg_file, sonic_db): write_config_db(db.cfgdb, unknown) print(db.cfgdb.get_table('UNKNOWN_TABLE')) + # Input Data + interface = 'Ethernet0' + curMode = '4x25G[10G]' + newMode = '2x50G' + # Mock functions except breakout_warnUser_extraTables mock_funcs[0] = config.device_info.get_path_to_port_config_file mock_funcs[1] = config.load_ConfigMgmt @@ -236,12 +339,15 @@ def test_config_breakout_extra_table_warning(self, breakout_cfg_file, sonic_db): mock.MagicMock(return_value = breakout_cfg_file) config.load_ConfigMgmt = \ mock.MagicMock(return_value = config_mgmt_dpb(db.cfgdb)) + config.get_child_ports = mock.MagicMock( + side_effect = [get_child_ports_mock(interface, curMode), get_child_ports_mock(interface, newMode)]) runner = CliRunner() obj = {'config_db':db.cfgdb} result = runner.invoke(config.config.commands["interface"].\ - commands["breakout"], ['Ethernet0', '2x50G', '-v', '-y'], obj=obj) + commands["breakout"], ['{}'.format(interface), '{}'.format(newMode), '-v', '-y'], obj=obj) + print(result.exit_code, result.output) assert result.exit_code == 0 assert 'Below Config can not be verified' in result.output @@ -249,7 +355,7 @@ def test_config_breakout_extra_table_warning(self, breakout_cfg_file, sonic_db): assert 'Do you wish to Continue?' in result.output brk_cfg_table = db.cfgdb.get_table('BREAKOUT_CFG') - assert brk_cfg_table["Ethernet0"]["brkout_mode"] == '4x25G[10G]' + assert brk_cfg_table["Ethernet0"]["brkout_mode"] == '{}'.format(curMode) # remove unknown table in config unknown = { @@ -275,8 +381,19 @@ def test_config_breakout_verbose(self, sonic_db): runner = CliRunner() obj = {'config_db':db.cfgdb} + # Input Data + interface = 'Ethernet0' + curMode = '4x25G[10G]' + newMode = '2x50G' + + print("Mocked Child ports data-> {}".format([get_child_ports_mock(interface, curMode), get_child_ports_mock(interface, newMode)])) + + config.get_child_ports = mock.MagicMock( + side_effect = [get_child_ports_mock(interface, curMode), get_child_ports_mock(interface, newMode)]) + result = runner.invoke(config.config.commands["interface"].\ - commands["breakout"], ['Ethernet0', '2x50G', '-v', '-y'], obj=obj) + commands["breakout"], ['{}'.format(interface), '{}'.format(newMode), '-v', '-y'], obj=obj) + print(result.exit_code, result.output) assert result.exit_code == 0 assert 'Dependecies Exist.' in result.output @@ -300,17 +417,29 @@ def test_config_breakout_negative_cases(self, sonic_db): runner = CliRunner() obj = {'config_db':db.cfgdb} + # Input Data + interface = 'Ethern' + curMode = '4x25G[10G]' + newMode = '2x50G' + + # Wrong interface name result = runner.invoke(config.config.commands["interface"].\ - commands["breakout"], ['Ethern', '2x50G', '-v', '-y'], obj=obj) + commands["breakout"], ['{}'.format(interface), '{}'.format(newMode), '-v', '-y'], obj=obj) + print(result.exit_code, result.output) assert result.exit_code == 1 - #TODO: Uncomment it after Dev Fix, right now it is python bt - #assert "Ethern is not present" in result.output + assert "Ethern interface is NOT present" in result.output + + # Input Data + interface = 'Ethernet0' + curMode = '4x25G[10G]' + newMode = '1x50G' # Wrong mode result = runner.invoke(config.config.commands["interface"].\ commands["breakout"], ['Ethernet0', '1x50G', '-v', '-y'], obj=obj) + print(result.exit_code, result.output) assert result.exit_code == 1 assert "Target mode 1x50G is not available for the port Ethernet0" in result.output @@ -318,9 +447,15 @@ def test_config_breakout_negative_cases(self, sonic_db): brk_cfg_table = db.cfgdb.get_table('BREAKOUT_CFG') assert brk_cfg_table["Ethernet0"]["brkout_mode"] == '4x25G[10G]' + # Input Data + interface = 'Ethernet0' + curMode = '4x25G[10G]' + newMode = '2x50G' + # Wrong option result = runner.invoke(config.config.commands["interface"].\ commands["breakout"], ['Ethernet0', '2x50G', '-v', '-p' '-y'], obj=obj) + print(result.exit_code, result.output) assert result.exit_code == 2 assert "no such option: -p" in result.output @@ -362,22 +497,44 @@ def test_config_breakout_various_modes(self, sonic_db): # Ethernet8: start from 4x25G-->2x50G with -f -l def config_dpb_port8_4x25G_2x50G_f_l(): + # Input Data + interface = 'Ethernet8' + curMode = '4x25G[10G]' + newMode = '2x50G' + + print("Mocked Child ports data-> {}".format([get_child_ports_mock(interface, curMode), get_child_ports_mock(interface, newMode)])) + + config.get_child_ports = mock.MagicMock( + side_effect = [get_child_ports_mock(interface, curMode), get_child_ports_mock(interface, newMode)]) + result = runner.invoke(config.config.commands["interface"].\ - commands["breakout"], ['Ethernet8', '2x50G', '-v', '-f',\ + commands["breakout"], ['{}'.format(interface), '{}'.format(newMode), '-v', '-f',\ '-l', '-y'], obj=obj) + print(result.exit_code, result.output) assert result.exit_code == 0 assert 'Breakout process got successfully completed.' in result.output brk_cfg_table = db.cfgdb.get_table('BREAKOUT_CFG') - assert brk_cfg_table["Ethernet8"]["brkout_mode"] == '2x50G' + assert brk_cfg_table["Ethernet8"]["brkout_mode"] == '{}'.format(newMode) return # Ethernet8: move from 2x50G-->1x100G without force, list deps def config_dpb_port8_2x50G_1x100G(): + # Input Data + interface = 'Ethernet8' + curMode = '2x50G' + newMode = '1x100G[40G]' + + print("Mocked Child ports data-> {}".format([get_child_ports_mock(interface, curMode), get_child_ports_mock(interface, newMode)])) + + config.get_child_ports = mock.MagicMock( + side_effect = [get_child_ports_mock(interface, curMode), get_child_ports_mock(interface, newMode)]) + result = runner.invoke(config.config.commands["interface"].\ - commands["breakout"], ['Ethernet8', '1x100G[40G]', '-v','-y'], obj=obj) + commands["breakout"], ['{}'.format(interface), '{}'.format(newMode), '-v','-y'], obj=obj) + print(result.exit_code, result.output) assert result.exit_code == 0 assert 'Dependecies Exist.' in result.output @@ -385,76 +542,133 @@ def config_dpb_port8_2x50G_1x100G(): assert 'NO-NSW-PACL-V4' in result.output brk_cfg_table = db.cfgdb.get_table('BREAKOUT_CFG') - assert brk_cfg_table["Ethernet8"]["brkout_mode"] == '2x50G' + assert brk_cfg_table["Ethernet8"]["brkout_mode"] == '{}'.format(curMode) return # Ethernet8: move from 2x50G-->1x100G with force, where deps exists def config_dpb_port8_2x50G_1x100G_f(): + # Input Data + interface = 'Ethernet8' + curMode = '2x50G' + newMode = '1x100G[40G]' + + print("Mocked Child ports data-> {}".format([get_child_ports_mock(interface, curMode), get_child_ports_mock(interface, newMode)])) + + config.get_child_ports = mock.MagicMock( + side_effect = [get_child_ports_mock(interface, curMode), get_child_ports_mock(interface, newMode)]) + result = runner.invoke(config.config.commands["interface"].\ - commands["breakout"], ['Ethernet8', '1x100G[40G]', '-v', '-f',\ + commands["breakout"], ['{}'.format(interface), '{}'.format(newMode), '-v', '-f',\ '-y'], obj=obj) + print(result.exit_code, result.output) assert result.exit_code == 0 assert 'Breakout process got successfully completed.' in result.output brk_cfg_table = db.cfgdb.get_table('BREAKOUT_CFG') - assert brk_cfg_table["Ethernet8"]["brkout_mode"] == '1x100G[40G]' + assert brk_cfg_table["Ethernet8"]["brkout_mode"] == '{}'.format(newMode) return # Ethernet8: move from 1x100G-->4x25G without force, no deps def config_dpb_port8_1x100G_4x25G(): + + # Input Data + interface = 'Ethernet8' + curMode = '1x100G[40G]' + newMode = '4x25G[10G]' + + print("Mocked Child ports data-> {}".format([get_child_ports_mock(interface, curMode), get_child_ports_mock(interface, newMode)])) + + config.get_child_ports = mock.MagicMock( + side_effect = [get_child_ports_mock(interface, curMode), get_child_ports_mock(interface, newMode)]) + + result = runner.invoke(config.config.commands["interface"].\ - commands["breakout"], ['Ethernet8', '4x25G[10G]', '-v',\ + commands["breakout"], ['{}'.format(interface), '{}'.format(newMode), '-v',\ '-y'], obj=obj) + print(result.exit_code, result.output) assert result.exit_code == 0 assert 'Breakout process got successfully completed.' in result.output brk_cfg_table = db.cfgdb.get_table('BREAKOUT_CFG') - assert brk_cfg_table["Ethernet8"]["brkout_mode"] == '4x25G[10G]' + assert brk_cfg_table["Ethernet8"]["brkout_mode"] == '{}'.format(newMode) return # Ethernet8: move from 4x25G-->1x100G with force, no deps def config_dpb_port8_4x25G_1x100G_f(): + # Input Data + interface = 'Ethernet8' + curMode = '4x25G[10G]' + newMode = '1x100G[40G]' + + print("Mocked Child ports data-> {}".format([get_child_ports_mock(interface, curMode), get_child_ports_mock(interface, newMode)])) + + config.get_child_ports = mock.MagicMock( + side_effect = [get_child_ports_mock(interface, curMode), get_child_ports_mock(interface, newMode)]) + result = runner.invoke(config.config.commands["interface"].\ - commands["breakout"], ['Ethernet8', '1x100G[40G]', '-v', '-f',\ + commands["breakout"], ['{}'.format(interface), '{}'.format(newMode), '-v', '-f',\ '-y'], obj=obj) + print(result.exit_code, result.output) assert result.exit_code == 0 assert 'Breakout process got successfully completed.' in result.output brk_cfg_table = db.cfgdb.get_table('BREAKOUT_CFG') - assert brk_cfg_table["Ethernet8"]["brkout_mode"] == '1x100G[40G]' + assert brk_cfg_table["Ethernet8"]["brkout_mode"] == '{}'.format(newMode) return # Ethernet8: move from 1x100G-->1x50G(2)+2x25G(2) with -f -l, def config_dpb_port8_1x100G_1x50G_2x25G_f_l(): + # Input Data + interface = 'Ethernet8' + curMode = '1x100G[40G]' + newMode = '1x50G(2)+2x25G(2)' + + print("Mocked Child ports data-> {}".format([get_child_ports_mock(interface, curMode), get_child_ports_mock(interface, newMode)])) + + config.get_child_ports = mock.MagicMock( + side_effect = [get_child_ports_mock(interface, curMode), get_child_ports_mock(interface, newMode)]) + result = runner.invoke(config.config.commands["interface"].\ - commands["breakout"], ['Ethernet8', '1x50G(2)+2x25G(2)', '-v',\ + commands["breakout"], ['{}'.format(interface), '{}'.format(newMode), '-v',\ '-f', '-l', '-y'], obj=obj) + print(result.exit_code, result.output) assert result.exit_code == 0 assert 'Breakout process got successfully completed.' in result.output brk_cfg_table = db.cfgdb.get_table('BREAKOUT_CFG') - assert brk_cfg_table["Ethernet8"]["brkout_mode"] == '1x50G(2)+2x25G(2)' + assert brk_cfg_table["Ethernet8"]["brkout_mode"] == '{}'.format(newMode) return # Ethernet4: breakout from 4x25G to 2x50G with -f -l def config_dpb_port4_4x25G_2x50G_f_l(): + # Input Data + interface = 'Ethernet4' + curMode = '4x25G[10G]' + newMode = '2x50G' + + print("Mocked Child ports data-> {}".format([get_child_ports_mock(interface, curMode), get_child_ports_mock(interface, newMode)])) + + config.get_child_ports = mock.MagicMock( + side_effect = [get_child_ports_mock(interface, curMode), get_child_ports_mock(interface, newMode)]) + result = runner.invoke(config.config.commands["interface"].\ - commands["breakout"], ['Ethernet4', '2x50G', '-v',\ + commands["breakout"], ['{}'.format(interface), '{}'.format(newMode), '-v',\ '-f', '-l', '-y'], obj=obj) + print(result.exit_code, result.output) assert result.exit_code == 0 assert 'Breakout process got successfully completed.' in result.output brk_cfg_table = db.cfgdb.get_table('BREAKOUT_CFG') - assert brk_cfg_table["Ethernet4"]["brkout_mode"] == '2x50G' + assert brk_cfg_table["Ethernet4"]["brkout_mode"] == '{}'.format(newMode) assert brk_cfg_table["Ethernet8"]["brkout_mode"] == '1x50G(2)+2x25G(2)' return ''' @@ -463,16 +677,22 @@ def config_dpb_port4_4x25G_2x50G_f_l(): # Ethernet8: start from 4x25G-->2x50G with -f -l config_dpb_port8_4x25G_2x50G_f_l() + # Ethernet8: move from 2x50G-->1x100G without force, list deps config_dpb_port8_2x50G_1x100G() + # Ethernet8: move from 2x50G-->1x100G with force, where deps exists config_dpb_port8_2x50G_1x100G_f() + # Ethernet8: move from 1x100G-->4x25G without force, no deps config_dpb_port8_1x100G_4x25G() + # Ethernet8: move from 4x25G-->1x100G with force, no deps config_dpb_port8_4x25G_1x100G_f() + # Ethernet8: move from 1x100G-->1x50G(2)+2x25G(2) with -f -l, config_dpb_port8_1x100G_1x50G_2x25G_f_l() + # Ethernet4: breakout from 4x25G to 2x50G with -f -l config_dpb_port4_4x25G_2x50G_f_l()