From 7a242eeb8e12c18366bff5eb27500b0de2a213c8 Mon Sep 17 00:00:00 2001 From: Junchao-Mellanox <57339448+Junchao-Mellanox@users.noreply.github.com> Date: Sat, 20 Jan 2024 01:15:28 +0800 Subject: [PATCH] [202311] Support reading/writing module EEPROM data by page and offset (#3008) (#3073) * Support reading/writing module EEPROM data by page and offset (#3008) * Support reading/writing module EEPROM data by page and offset --- doc/Command-Reference.md | 7 +- sfputil/main.py | 193 +++++++++++++++++++++++++--- tests/sfputil_test.py | 267 ++++++++++++++++++++++++++++++++++++++- 3 files changed, 441 insertions(+), 26 deletions(-) diff --git a/doc/Command-Reference.md b/doc/Command-Reference.md index 30f317be80..3e64103a4e 100644 --- a/doc/Command-Reference.md +++ b/doc/Command-Reference.md @@ -12942,7 +12942,8 @@ Clear MACsec counters which is to reset all MACsec counters to ZERO. Go Back To [Beginning of the document](#) or [Beginning of this section](#macsec-commands) # SFP Utilities Commands - This sub-section explains the list of commands available for SFP utilities feature. + +This sub-section explains the list of commands available for SFP utilities feature. ## SFP Utilities show commands @@ -13048,7 +13049,7 @@ EEPROM hexdump for port Ethernet8 000000f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| ``` -# SFP Utilities read command +## SFP Utilities read command - Read SFP EEPROM data @@ -13080,7 +13081,7 @@ admin@sonic:~$ sfputil read-eeprom --port Ethernet0 --page 0 --offset 100 --size 4a44 ``` -# SFP Utilities write command +## SFP Utilities write command - Write SFP EEPROM data diff --git a/sfputil/main.py b/sfputil/main.py index 013c8d7c6f..0e59fbe898 100644 --- a/sfputil/main.py +++ b/sfputil/main.py @@ -908,27 +908,6 @@ def eeprom_dump_general(physical_port, page, flat_offset, size, page_offset, no_ return 0, ''.join('{:02x}'.format(x) for x in page_dump) -def eeprom_dump_general(physical_port, page, flat_offset, size, page_offset, no_format=False): - """ - Dump module EEPROM for given pages in hex format. - Args: - logical_port_name: logical port name - pages: a list of pages to be dumped. The list always include a default page list and the target_page input by - user - target_page: user input page number, optional. target_page is only for display purpose - Returns: - tuple(0, dump string) if success else tuple(error_code, error_message) - """ - sfp = platform_chassis.get_sfp(physical_port) - page_dump = sfp.read_eeprom(flat_offset, size) - if page_dump is None: - return ERROR_NOT_IMPLEMENTED, f'Error: Failed to read EEPROM for page {page:x}h, flat_offset {flat_offset}, page_offset {page_offset}, size {size}!' - if not no_format: - return 0, hexdump(EEPROM_DUMP_INDENT, page_dump, page_offset, start_newline=False) - else: - return 0, ''.join('{:02x}'.format(x) for x in page_dump) - - def convert_byte_to_valid_ascii_char(byte): if byte < 32 or 126 < byte: return '.' @@ -1712,5 +1691,177 @@ def target(port_name, target): click.echo("Target Mode set failed!") sys.exit(EXIT_FAIL) + +# 'read-eeprom' subcommand +@cli.command() +@click.option('-p', '--port', metavar='', help="Logical port name", required=True) +@click.option('-n', '--page', metavar='', type=click.IntRange(0, MAX_EEPROM_PAGE), help="EEPROM page number", required=True) +@click.option('-o', '--offset', metavar='', type=click.IntRange(0, MAX_EEPROM_OFFSET), help="EEPROM offset within the page", required=True) +@click.option('-s', '--size', metavar='', type=click.IntRange(1, MAX_EEPROM_OFFSET + 1), help="Size of byte to be read", required=True) +@click.option('--no-format', is_flag=True, help="Display non formatted data") +@click.option('--wire-addr', help="Wire address of sff8472") +def read_eeprom(port, page, offset, size, no_format, wire_addr): + """Read SFP EEPROM data + """ + try: + if platform_sfputil.is_logical_port(port) == 0: + click.echo("Error: invalid port {}".format(port)) + print_all_valid_port_values() + sys.exit(ERROR_INVALID_PORT) + + if is_port_type_rj45(port): + click.echo("This functionality is not applicable for RJ45 port {}.".format(port)) + sys.exit(EXIT_FAIL) + + physical_port = logical_port_to_physical_port_index(port) + sfp = platform_chassis.get_sfp(physical_port) + if not sfp.get_presence(): + click.echo("{}: SFP EEPROM not detected\n".format(port)) + sys.exit(EXIT_FAIL) + + from sonic_platform_base.sonic_xcvr.api.public import sff8472 + api = sfp.get_xcvr_api() + if api is None: + click.echo('Error: SFP EEPROM not detected!') + if not isinstance(api, sff8472.Sff8472Api): + overall_offset = get_overall_offset_general(api, page, offset, size) + else: + overall_offset = get_overall_offset_sff8472(api, page, offset, size, wire_addr) + return_code, output = eeprom_dump_general(physical_port, page, overall_offset, size, offset, no_format) + if return_code != 0: + click.echo("Error: Failed to read EEPROM!") + sys.exit(return_code) + click.echo(output) + except NotImplementedError: + click.echo("This functionality is currently not implemented for this platform") + sys.exit(ERROR_NOT_IMPLEMENTED) + except ValueError as e: + click.echo(f"Error: {e}") + sys.exit(EXIT_FAIL) + + +# 'write-eeprom' subcommand +@cli.command() +@click.option('-p', '--port', metavar='', help="Logical port name", required=True) +@click.option('-n', '--page', metavar='', type=click.IntRange(0, MAX_EEPROM_PAGE), help="EEPROM page number", required=True) +@click.option('-o', '--offset', metavar='', type=click.IntRange(0, MAX_EEPROM_OFFSET), help="EEPROM offset within the page", required=True) +@click.option('-d', '--data', metavar='', help="Hex string EEPROM data", required=True) +@click.option('--wire-addr', help="Wire address of sff8472") +@click.option('--verify', is_flag=True, help="Verify the data by reading back") +def write_eeprom(port, page, offset, data, wire_addr, verify): + """Write SFP EEPROM data""" + try: + if platform_sfputil.is_logical_port(port) == 0: + click.echo("Error: invalid port {}".format(port)) + print_all_valid_port_values() + sys.exit(ERROR_INVALID_PORT) + + if is_port_type_rj45(port): + click.echo("This functionality is not applicable for RJ45 port {}.".format(port)) + sys.exit(EXIT_FAIL) + + physical_port = logical_port_to_physical_port_index(port) + sfp = platform_chassis.get_sfp(physical_port) + if not sfp.get_presence(): + click.echo("{}: SFP EEPROM not detected\n".format(port)) + sys.exit(EXIT_FAIL) + + try: + bytes = bytearray.fromhex(data) + except ValueError: + click.echo("Error: Data must be a hex string of even length!") + sys.exit(EXIT_FAIL) + + from sonic_platform_base.sonic_xcvr.api.public import sff8472 + api = sfp.get_xcvr_api() + if api is None: + click.echo('Error: SFP EEPROM not detected!') + sys.exit(EXIT_FAIL) + + if not isinstance(api, sff8472.Sff8472Api): + overall_offset = get_overall_offset_general(api, page, offset, len(bytes)) + else: + overall_offset = get_overall_offset_sff8472(api, page, offset, len(bytes), wire_addr) + success = sfp.write_eeprom(overall_offset, len(bytes), bytes) + if not success: + click.echo("Error: Failed to write EEPROM!") + sys.exit(ERROR_NOT_IMPLEMENTED) + if verify: + read_data = sfp.read_eeprom(overall_offset, len(bytes)) + if read_data != bytes: + click.echo(f"Error: Write data failed! Write: {''.join('{:02x}'.format(x) for x in bytes)}, read: {''.join('{:02x}'.format(x) for x in read_data)}") + sys.exit(EXIT_FAIL) + except NotImplementedError: + click.echo("This functionality is currently not implemented for this platform") + sys.exit(ERROR_NOT_IMPLEMENTED) + except ValueError as e: + click.echo("Error: {}".format(e)) + sys.exit(EXIT_FAIL) + + +def get_overall_offset_general(api, page, offset, size): + """ + Validate input parameter page, offset, size and translate them to overall offset + Args: + api: cable API object + page: module EEPROM page number. + offset: module EEPROM page offset. + size: number bytes of the data to be read/write + + Returns: + The overall offset + """ + if api.is_flat_memory(): + if page != 0: + raise ValueError(f'Invalid page number {page}, only page 0 is supported') + + if page != 0: + if offset < MIN_OFFSET_FOR_NON_PAGE0: + raise ValueError(f'Invalid offset {offset} for page {page}, valid range: [128, 255]') + + if size + offset - 1 > MAX_EEPROM_OFFSET: + raise ValueError(f'Invalid size {size}, valid range: [1, {255 - offset + 1}]') + + return page * PAGE_SIZE + offset + + +def get_overall_offset_sff8472(api, page, offset, size, wire_addr): + """ + Validate input parameter page, offset, size, wire_addr and translate them to overall offset + Args: + api: cable API object + page: module EEPROM page number. + offset: module EEPROM page offset. + size: number bytes of the data to be read/write + wire_addr: case-insensitive wire address string. Only valid for sff8472, a0h or a2h. + + Returns: + The overall offset + """ + if not wire_addr: + raise ValueError("Invalid wire address for sff8472, must a0h or a2h") + + is_active_cable = not api.is_copper() + valid_wire_address = ('a0h', 'a2h') if is_active_cable else ('a0h',) + wire_addr = wire_addr.lower() + if wire_addr not in valid_wire_address: + raise ValueError(f"Invalid wire address {wire_addr} for sff8472, must be {' or '.join(valid_wire_address)}") + + if wire_addr == 'a0h': + if page != 0: + raise ValueError(f'Invalid page number {page} for wire address {wire_addr}, only page 0 is supported') + max_offset = MAX_OFFSET_FOR_A0H_UPPER_PAGE if is_active_cable else MAX_OFFSET_FOR_A0H_LOWER_PAGE + if offset > max_offset: + raise ValueError(f'Invalid offset {offset} for wire address {wire_addr}, valid range: [0, {max_offset}]') + if size + offset - 1 > max_offset: + raise ValueError( + f'Invalid size {size} for wire address {wire_addr}, valid range: [1, {max_offset - offset + 1}]') + return offset + else: + if size + offset - 1 > MAX_OFFSET_FOR_A2H: + raise ValueError(f'Invalid size {size} for wire address {wire_addr}, valid range: [1, {255 - offset + 1}]') + return page * PAGE_SIZE + offset + PAGE_SIZE_FOR_A0H + + if __name__ == '__main__': cli() diff --git a/tests/sfputil_test.py b/tests/sfputil_test.py index 2b74423ad9..63814f31c5 100644 --- a/tests/sfputil_test.py +++ b/tests/sfputil_test.py @@ -1117,6 +1117,271 @@ def test_update_firmware_info_to_state_db(self, mock_chassis): sfputil.update_firmware_info_to_state_db("Ethernet0") + @patch('sfputil.main.is_port_type_rj45', MagicMock(return_value=False)) + @patch('sfputil.main.logical_port_to_physical_port_index', MagicMock(return_value=1)) + @patch('sfputil.main.platform_sfputil', MagicMock(is_logical_port=MagicMock(return_value=1))) + @patch('sfputil.main.platform_chassis') + def test_read_eeprom(self, mock_chassis): + mock_sfp = MagicMock() + mock_chassis.get_sfp = MagicMock(return_value=mock_sfp) + + mock_sfp.get_presence = MagicMock(return_value=False) + runner = CliRunner() + result = runner.invoke(sfputil.cli.commands['read-eeprom'], + ['-p', "Ethernet0", '-n', '0', '-o', '0', '-s', '1']) + assert result.exit_code == EXIT_FAIL + + mock_sfp.get_presence.return_value = True + mock_sfp.read_eeprom = MagicMock(return_value=None) + result = runner.invoke(sfputil.cli.commands['read-eeprom'], + ['-p', "Ethernet0", '-n', '0', '-o', '0', '-s', '1']) + assert result.exit_code == ERROR_NOT_IMPLEMENTED + + mock_sfp.read_eeprom.return_value = bytearray([0x00, 0x01]) + result = runner.invoke(sfputil.cli.commands['read-eeprom'], + ['-p', "Ethernet0", '-n', '0', '-o', '0', '-s', '2', '--no-format']) + assert result.exit_code == 0 + assert result.output == '0001\n' + + result = runner.invoke(sfputil.cli.commands['read-eeprom'], + ['-p', "Ethernet0", '-n', '0', '-o', '5', '-s', '2']) + assert result.exit_code == 0 + expected_output = """ 00000005 00 01 |..| +""" + print(result.output) + assert result.output == expected_output + + mock_sfp.read_eeprom.side_effect = NotImplementedError + result = runner.invoke(sfputil.cli.commands['read-eeprom'], + ['-p', "Ethernet0", '-n', '0', '-o', '5', '-s', '2']) + assert result.exit_code == ERROR_NOT_IMPLEMENTED + + mock_sfp.read_eeprom.side_effect = ValueError + result = runner.invoke(sfputil.cli.commands['read-eeprom'], + ['-p', "Ethernet0", '-n', '0', '-o', '5', '-s', '2']) + assert result.exit_code == EXIT_FAIL + + @patch('sfputil.main.is_port_type_rj45', MagicMock(return_value=False)) + @patch('sfputil.main.logical_port_to_physical_port_index', MagicMock(return_value=1)) + @patch('sfputil.main.platform_sfputil', MagicMock(is_logical_port=MagicMock(return_value=1))) + @patch('sfputil.main.platform_chassis') + def test_write_eeprom(self, mock_chassis): + mock_sfp = MagicMock() + mock_chassis.get_sfp = MagicMock(return_value=mock_sfp) + + mock_sfp.get_presence = MagicMock(return_value=False) + runner = CliRunner() + result = runner.invoke(sfputil.cli.commands['write-eeprom'], + ['-p', "Ethernet0", '-n', '0', '-o', '0', '-d', '01']) + assert result.exit_code == EXIT_FAIL + + # invalid hex string, hex string must have even length + mock_sfp.get_presence.return_value = True + result = runner.invoke(sfputil.cli.commands['write-eeprom'], + ['-p', "Ethernet0", '-n', '0', '-o', '0', '-d', '1']) + assert result.exit_code == EXIT_FAIL + + # invalid hex string + result = runner.invoke(sfputil.cli.commands['write-eeprom'], + ['-p', "Ethernet0", '-n', '0', '-o', '0', '-d', '+0']) + assert result.exit_code == EXIT_FAIL + + # write failed + mock_sfp.write_eeprom = MagicMock(return_value=False) + result = runner.invoke(sfputil.cli.commands['write-eeprom'], + ['-p', "Ethernet0", '-n', '0', '-o', '0', '-d', '10']) + print(result.output) + assert result.exit_code == ERROR_NOT_IMPLEMENTED + + # write success + mock_sfp.write_eeprom.return_value = True + result = runner.invoke(sfputil.cli.commands['write-eeprom'], + ['-p', "Ethernet0", '-n', '0', '-o', '0', '-d', '10']) + assert result.exit_code == 0 + + # write verify success + mock_sfp.read_eeprom = MagicMock(return_value=bytearray([16])) + result = runner.invoke(sfputil.cli.commands['write-eeprom'], + ['-p', "Ethernet0", '-n', '0', '-o', '0', '-d', '10', '--verify']) + assert result.exit_code == 0 + + # write verify failed + mock_sfp.read_eeprom = MagicMock(return_value=bytearray([10])) + result = runner.invoke(sfputil.cli.commands['write-eeprom'], + ['-p', "Ethernet0", '-n', '0', '-o', '0', '-d', '11', '--verify']) + assert result.exit_code != 0 + + # Not implemented + mock_sfp.write_eeprom.side_effect = NotImplementedError + result = runner.invoke(sfputil.cli.commands['write-eeprom'], + ['-p', "Ethernet0", '-n', '0', '-o', '0', '-d', '10']) + assert result.exit_code == ERROR_NOT_IMPLEMENTED + + # Value error + mock_sfp.write_eeprom.side_effect = ValueError + result = runner.invoke(sfputil.cli.commands['write-eeprom'], + ['-p', "Ethernet0", '-n', '0', '-o', '0', '-d', '10']) + assert result.exit_code == EXIT_FAIL + + @patch('sfputil.main.platform_sfputil', MagicMock(is_logical_port=MagicMock(return_value=0))) + def test_read_eeprom_invalid_port(self): + runner = CliRunner() + result = runner.invoke(sfputil.cli.commands['read-eeprom'], + ['-p', "Ethernet0", '-n', '0', '-o', '0', '-s', '1']) + assert result.exit_code == ERROR_INVALID_PORT + + @patch('sfputil.main.platform_sfputil', MagicMock(is_logical_port=MagicMock(return_value=0))) + def test_write_eeprom_invalid_port(self): + runner = CliRunner() + result = runner.invoke(sfputil.cli.commands['write-eeprom'], + ['-p', "Ethernet0", '-n', '0', '-o', '0', '-d', '00']) + assert result.exit_code == ERROR_INVALID_PORT + + @patch('sfputil.main.is_port_type_rj45', MagicMock(return_value=True)) + @patch('sfputil.main.platform_sfputil', MagicMock(is_logical_port=MagicMock(return_value=1))) + def test_read_eeprom_rj45(self): + runner = CliRunner() + result = runner.invoke(sfputil.cli.commands['read-eeprom'], + ['-p', "Ethernet0", '-n', '0', '-o', '0', '-s', '1']) + assert result.exit_code == EXIT_FAIL + + @patch('sfputil.main.is_port_type_rj45', MagicMock(return_value=True)) + @patch('sfputil.main.platform_sfputil', MagicMock(is_logical_port=MagicMock(return_value=1))) + def test_write_eeprom_rj45(self): + runner = CliRunner() + result = runner.invoke(sfputil.cli.commands['write-eeprom'], + ['-p', "Ethernet0", '-n', '0', '-o', '0', '-d', '00']) + assert result.exit_code == EXIT_FAIL + + @patch('sfputil.main.is_port_type_rj45', MagicMock(return_value=False)) + @patch('sfputil.main.logical_port_to_physical_port_index', MagicMock(return_value=1)) + @patch('sfputil.main.platform_sfputil', MagicMock(is_logical_port=MagicMock(return_value=1))) + @patch('sfputil.main.platform_chassis') + def test_get_overall_offset_general(self, mock_chassis): + api = MagicMock() + api.is_flat_memory = MagicMock(return_value=False) + mock_sfp = MagicMock() + mock_chassis.get_sfp = MagicMock(return_value=mock_sfp) + + mock_sfp.get_presence = MagicMock(return_value=True) + mock_sfp.get_xcvr_api = MagicMock(return_value=api) + + runner = CliRunner() + result = runner.invoke(sfputil.cli.commands['write-eeprom'], + ['-p', "Ethernet0", '-n', '-1', '-o', '0', '-d', '01']) + assert result.exit_code != 0 + + result = runner.invoke(sfputil.cli.commands['write-eeprom'], + ['-p', "Ethernet0", '-n', '256', '-o', '0', '-d', '01']) + assert result.exit_code != 0 + + result = runner.invoke(sfputil.cli.commands['write-eeprom'], + ['-p', "Ethernet0", '-n', '0', '-o', '-1', '-d', '01']) + assert result.exit_code != 0 + + result = runner.invoke(sfputil.cli.commands['write-eeprom'], + ['-p', "Ethernet0", '-n', '0', '-o', '256', '-d', '01']) + assert result.exit_code != 0 + + result = runner.invoke(sfputil.cli.commands['write-eeprom'], + ['-p', "Ethernet0", '-n', '1', '-o', '127', '-d', '01']) + assert result.exit_code != 0 + + result = runner.invoke(sfputil.cli.commands['write-eeprom'], + ['-p', "Ethernet0", '-n', '1', '-o', '256', '-d', '01']) + assert result.exit_code != 0 + + result = runner.invoke(sfputil.cli.commands['read-eeprom'], + ['-p', "Ethernet0", '-n', '0', '-o', '0', '-s', '0']) + assert result.exit_code != 0 + + result = runner.invoke(sfputil.cli.commands['read-eeprom'], + ['-p', "Ethernet0", '-n', '0', '-o', '0', '-s', '257']) + assert result.exit_code != 0 + + result = runner.invoke(sfputil.cli.commands['write-eeprom'], + ['-p', "Ethernet0", '-n', '0', '-o', '1', '-d', '01']) + assert result.exit_code == 0 + + @patch('sfputil.main.isinstance', MagicMock(return_value=True)) + @patch('sfputil.main.is_port_type_rj45', MagicMock(return_value=False)) + @patch('sfputil.main.logical_port_to_physical_port_index', MagicMock(return_value=1)) + @patch('sfputil.main.platform_sfputil', MagicMock(is_logical_port=MagicMock(return_value=1))) + @patch('sfputil.main.platform_chassis') + def test_get_overall_offset_sff8472(self, mock_chassis): + api = MagicMock() + api.is_copper = MagicMock(return_value=False) + mock_sfp = MagicMock() + mock_chassis.get_sfp = MagicMock(return_value=mock_sfp) + + mock_sfp.get_presence = MagicMock(return_value=True) + mock_sfp.get_xcvr_api = MagicMock(return_value=api) + + runner = CliRunner() + result = runner.invoke(sfputil.cli.commands['read-eeprom'], + ['-p', "Ethernet0", '-n', '0', '-o', '0', '-s', '1']) + assert result.exit_code != 0 + print(result.output) + + result = runner.invoke(sfputil.cli.commands['read-eeprom'], + ['-p', "Ethernet0", '--wire-addr', 'invalid', '-n', '0', '-o', '0', '-s', '1']) + assert result.exit_code != 0 + print(result.output) + + result = runner.invoke(sfputil.cli.commands['read-eeprom'], + ['-p', "Ethernet0", '--wire-addr', 'a0h', '-n', '1', '-o', '0', '-s', '1']) + assert result.exit_code != 0 + print(result.output) + + result = runner.invoke(sfputil.cli.commands['read-eeprom'], + ['-p', "Ethernet0", '--wire-addr', 'A0h', '-n', '0', '-o', '-1', '-s', '1']) + assert result.exit_code != 0 + print(result.output) + + result = runner.invoke(sfputil.cli.commands['read-eeprom'], + ['-p', "Ethernet0", '--wire-addr', 'A0h', '-n', '0', '-o', '256', '-s', '1']) + assert result.exit_code != 0 + print(result.output) + + result = runner.invoke(sfputil.cli.commands['read-eeprom'], + ['-p', "Ethernet0", '--wire-addr', 'A0h', '-n', '0', '-o', '0', '-s', '0']) + assert result.exit_code != 0 + print(result.output) + + result = runner.invoke(sfputil.cli.commands['read-eeprom'], + ['-p', "Ethernet0", '--wire-addr', 'A0h', '-n', '0', '-o', '0', '-s', '257']) + assert result.exit_code != 0 + print(result.output) + + assert sfputil.get_overall_offset_sff8472(api, 0, 2, 2, wire_addr='A0h') == 2 + + result = runner.invoke(sfputil.cli.commands['read-eeprom'], + ['-p', "Ethernet0", '--wire-addr', 'a2h', '-n', '-1', '-o', '0', '-s', '1']) + assert result.exit_code != 0 + print(result.output) + + result = runner.invoke(sfputil.cli.commands['read-eeprom'], + ['-p', "Ethernet0", '--wire-addr', 'a2h', '-n', '256', '-o', '0', '-s', '1']) + assert result.exit_code != 0 + print(result.output) + + result = runner.invoke(sfputil.cli.commands['read-eeprom'], + ['-p', "Ethernet0", '--wire-addr', 'a2h', '-n', '0', '-o', '-1', '-s', '1']) + assert result.exit_code != 0 + print(result.output) + + result = runner.invoke(sfputil.cli.commands['read-eeprom'], + ['-p', "Ethernet0", '--wire-addr', 'a2h', '-n', '0', '-o', '0', '-s', '0']) + assert result.exit_code != 0 + print(result.output) + + result = runner.invoke(sfputil.cli.commands['read-eeprom'], + ['-p', "Ethernet0", '--wire-addr', 'a2h', '-n', '0', '-o', '0', '-s', '257']) + assert result.exit_code != 0 + print(result.output) + + assert sfputil.get_overall_offset_sff8472(api, 0, 2, 2, wire_addr='A2h') == 258 + @patch('sfputil.main.platform_chassis') @patch('sfputil.main.logical_port_to_physical_port_index', MagicMock(return_value=1)) def test_target_firmware(self, mock_chassis): @@ -1147,5 +1412,3 @@ def test_target_firmware(self, mock_chassis): result = runner.invoke(sfputil.cli.commands['firmware'].commands['target'], ["Ethernet0", "1"]) assert result.output == 'Target Mode set failed!\n' assert result.exit_code == EXIT_FAIL - -