def test_show_platform_syseeprom(localhost, ansible_adhoc, testbed):
    """
    @summary: Check output of 'show platform syseeprom'
    """
    hostname = testbed['dut']
    ans_host = AnsibleHost(ansible_adhoc, hostname)

    logging.info("Check output of '%s'" % CMD_PLATFORM_SYSEEPROM)
    platform_info = parse_platform_summary(
        ans_host.command(CMD_PLATFORM_SUMMARY)["stdout_lines"])
    show_output = ans_host.command(CMD_PLATFORM_SYSEEPROM)
    assert show_output[
        "rc"] == 0, "Run command '%s' failed" % CMD_PLATFORM_SYSEEPROM
    if platform_info["asic"] in ["mellanox"]:
        expected_fields = [
            "Product Name", "Part Number", "Serial Number", "Base MAC Address",
            "Manufacture Date", "Device Version", "MAC Addresses",
            "Manufacturer", "Vendor Extension", "ONIE Version", "CRC-32"
        ]
        utility_cmd = "sudo python -c \"import imp; \
            m = imp.load_source('eeprom', '/usr/share/sonic/device/%s/plugins/eeprom.py'); \
            t = m.board('board', '', '', ''); e = t.read_eeprom(); t.decode_eeprom(e)\"" % platform_info[
            "platform"]
        utility_cmd_output = ans_host.command(utility_cmd)

        for field in expected_fields:
            assert show_output["stdout"].find(
                field) >= 0, "Expected field %s is not found" % field
            assert utility_cmd_output["stdout"].find(
                field) >= 0, "Expected field %s is not found" % field

        for line in utility_cmd_output["stdout_lines"]:
            assert line in show_output["stdout"], \
                "Line %s is not found in output of '%s'" % (line, CMD_PLATFORM_SYSEEPROM)
Example #2
0
def ptfadapter(ansible_adhoc, testbed):
    """return ptf test adapter object.
    The fixture is module scope, because usually there is not need to
    restart PTF nn agent and reinitialize data plane thread on every
    test class or test function/method. Session scope should also be Ok,
    however if something goes really wrong in one test module it is safer
    to restart PTF before proceeding running other test modules
    """

    ptfhost = AnsibleHost(ansible_adhoc, testbed['ptf'])
    # get the eth interfaces from PTF and initialize ifaces_map
    res = ptfhost.command('cat /proc/net/dev')
    ifaces = get_ifaces(res['stdout'])
    ifaces_map = {
        int(ifname.replace(ETH_PFX, '')): ifname
        for ifname in ifaces
    }

    # generate supervisor configuration for ptf_nn_agent
    ptfhost.host.options['variable_manager'].extra_vars = {
        'device_num': DEFAULT_DEVICE_NUM,
        'ptf_nn_port': DEFAULT_PTF_NN_PORT,
        'ifaces_map': ifaces_map,
    }
    ptfhost.template(src='ptfadapter/templates/ptf_nn_agent.conf.ptf.j2',
                     dest='/etc/supervisor/conf.d/ptf_nn_agent.conf')

    # reread configuration and update supervisor
    ptfhost.command('supervisorctl reread')
    ptfhost.command('supervisorctl update')

    with PtfTestAdapter(testbed['ptf_ip'], DEFAULT_PTF_NN_PORT, 0,
                        len(ifaces_map)) as adapter:
        yield adapter
Example #3
0
def fdb_cleanup(ansible_adhoc, testbed):
    """ cleanup FDB before and after test run """
    duthost = AnsibleHost(ansible_adhoc, testbed['dut'])
    try:
        duthost.command('sonic-clear fdb all')
        yield
    finally:
        # in any case clear fdb after test
        duthost.command('sonic-clear fdb all')
def run_test(ansible_adhoc,
             testbed,
             conn_graph_facts,
             leaf_fanouts,
             is_pfc=True,
             pause_time=65535):
    """
    @Summary: Run test for Ethernet flow control (FC) or priority-based flow control (PFC)
    @param ansible_adhoc: Fixture provided by the pytest-ansible package. Source of the various device objects. It is
    mandatory argument for the class constructors.
    @param testbed: Testbed information
    @param conn_graph_facts: Testbed topology connectivity information
    @param leaf_fanouts: Leaf fanout switches
    @param is_pfc: If this test is for PFC?
    @param pause_time: Pause time quanta (0-65535) in the frame. 0 means unpause.
    """
    setup_testbed(ansible_adhoc, testbed, leaf_fanouts)
    conn_facts = conn_graph_facts['device_conn']

    dut_hostname = testbed['dut']
    dut_ans = AnsibleHost(ansible_adhoc, dut_hostname)
    int_status = dut_ans.show_interface(
        command="status")['ansible_facts']['int_status']
    """ We only test active physical interfaces """
    active_phy_intfs = [intf for intf in int_status if \
        intf.startswith('Ethernet') and \
        int_status[intf]['admin_state'] == 'up' and \
        int_status[intf]['oper_state'] == 'up']
    """ Generate PFC or FC packets for active physical interfaces """
    for intf in active_phy_intfs:
        peer_device = conn_facts[intf]['peerdevice']
        peer_port = conn_facts[intf]['peerport']
        peer_port_name = eos_to_linux_intf(peer_port)

        peerdev_ans = AnsibleHost(ansible_adhoc, peer_device)
        if is_pfc:
            for priority in range(PRIO_COUNT):
                cmd = "sudo python %s -i %s -p %d -t %d -n %d" % (
                    PFC_GEN_FILE_DEST, peer_port_name, 2**
                    priority, pause_time, PKT_COUNT)
                peerdev_ans.command(cmd)
        else:
            cmd = "sudo python %s -i %s -g -t %d -n %d" % (
                PFC_GEN_FILE_DEST, peer_port_name, pause_time, PKT_COUNT)
            peerdev_ans.command(cmd)
    """ SONiC takes some time to update counters in database """
    time.sleep(5)
    """ Check results """
    counter_facts = dut_ans.sonic_pfc_counters(method="get")['ansible_facts']

    for intf in active_phy_intfs:
        if is_pfc:
            assert counter_facts[intf]['Rx'] == [str(PKT_COUNT)] * PRIO_COUNT
        else:
            assert counter_facts[intf]['Rx'] == ['0'] * PRIO_COUNT
def test_reload_configuration(localhost, ansible_adhoc, testbed):
    """
    @summary: This test case is to reload the configuration and check platform status
    """
    hostname = testbed['dut']
    ans_host = AnsibleHost(ansible_adhoc, hostname)
    ans_host.command("show platform summary")
    lab_conn_graph_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), \
        "../../ansible/files/lab_connection_graph.xml")
    conn_graph_facts = localhost.conn_graph_facts(host=hostname, filename=lab_conn_graph_file).\
        contacted['localhost']['ansible_facts']
    interfaces = conn_graph_facts["device_conn"]
    asic_type = ans_host.shell(
        "show platform summary | awk '/ASIC: / {print$2}'")["stdout"].strip()

    logging.info("Reload configuration")
    ans_host.command("sudo config reload -y")

    logging.info("Wait until all critical services are fully started")
    check_critical_services(ans_host)

    logging.info("Wait some time for all the transceivers to be detected")
    assert wait_until(300, 20, all_transceivers_detected, ans_host, interfaces), \
        "Not all transceivers are detected in 300 seconds"

    logging.info("Check interface status")
    time.sleep(60)
    check_interface_status(ans_host, interfaces)

    logging.info("Check transceiver status")
    check_transceiver_basic(ans_host, interfaces)

    if asic_type in ["mellanox"]:

        current_file_dir = os.path.dirname(os.path.realpath(__file__))
        sub_folder_dir = os.path.join(current_file_dir, "mellanox")
        if sub_folder_dir not in sys.path:
            sys.path.append(sub_folder_dir)
        from check_hw_mgmt_service import check_hw_management_service
        from check_sysfs import check_sysfs

        logging.info("Check the hw-management service")
        check_hw_management_service(ans_host)

        logging.info("Check sysfs")
        check_sysfs(ans_host)
Example #6
0
def test_fdb(ansible_adhoc, testbed, ptfadapter):
    """
    1. verify fdb forwarding in T0 topology.
    2. verify show mac command on DUT for learned mac.
    """

    if testbed['topo'] not in ['t0', 't0-64', 't0-116']:
        pytest.skip('unsupported testbed type')

    duthost = AnsibleHost(ansible_adhoc, testbed['dut'])
    ptfhost = AnsibleHost(ansible_adhoc, testbed['ptf'])

    host_facts = duthost.setup()['ansible_facts']
    mg_facts = duthost.minigraph_facts(host=duthost.hostname)['ansible_facts']

    # remove existing IPs from PTF host
    ptfhost.script('scripts/remove_ip.sh')
    # set unique MACs to PTF interfaces
    ptfhost.script('scripts/change_mac.sh')
    # reinitialize data plane due to above changes on PTF interfaces
    ptfadapter.reinit()

    router_mac = host_facts['ansible_Ethernet0']['macaddress']
    vlan_member_count = sum(
        [len(v['members']) for k, v in mg_facts['minigraph_vlans'].items()])

    vlan_table = {}
    for vlan in mg_facts['minigraph_vlan_interfaces']:
        vlan_table[vlan['subnet']] = []
        for ifname in mg_facts['minigraph_vlans'][vlan['attachto']]['members']:
            vlan_table[vlan['subnet']].append(
                mg_facts['minigraph_port_indices'][ifname])

    fdb = setup_fdb(ptfadapter, vlan_table, router_mac)

    for vlan in vlan_table:
        for src, dst in itertools.combinations(vlan_table[vlan], 2):
            for src_mac, dst_mac in itertools.product(fdb[src], fdb[dst]):
                send_recv_eth(ptfadapter, src, src_mac, dst, dst_mac)

    # Should we have fdb_facts ansible module for this test?
    res = duthost.command('show mac')
    logger.info('"show mac" output on DUT:\n{}'.format(
        pprint.pformat(res['stdout_lines'])))

    dummy_mac_count = 0
    total_mac_count = 0
    for l in res['stdout_lines']:
        if DUMMY_MAC_PREFIX in l.lower():
            dummy_mac_count += 1
        if "dynamic" in l.lower():
            total_mac_count += 1

    # Verify that the number of dummy MAC entries is expected
    assert dummy_mac_count == DUMMY_MAC_COUNT * vlan_member_count
    # Verify that total number of MAC entries is expected
    assert total_mac_count == DUMMY_MAC_COUNT * vlan_member_count + vlan_member_count
def test_show_platform_psustatus(localhost, ansible_adhoc, testbed):
    """
    @summary: Check output of 'show platform psustatus'
    """
    hostname = testbed['dut']
    ans_host = AnsibleHost(ansible_adhoc, hostname)

    logging.info("Check PSU status using '%s', hostname: %s" %
                 (CMD_PLATFORM_PSUSTATUS, hostname))
    psu_status = ans_host.command(CMD_PLATFORM_PSUSTATUS)
    psu_line_pattern = re.compile(r"PSU\s+\d+\s+(OK|NOT OK)")
    for line in psu_status["stdout_lines"][2:]:
        assert psu_line_pattern.match(line), "Unexpected PSU status output"
Example #8
0
def test_warm_reboot(localhost, ansible_adhoc, testbed):
    """
    @summary: This test case is to perform cold reboot and check platform status
    """
    hostname = testbed['dut']
    ans_host = AnsibleHost(ansible_adhoc, hostname)
    asic_type = ans_host.shell("show platform summary | awk '/ASIC: / {print$2}'")["stdout"].strip()

    if asic_type in ["mellanox"]:
        issu_capability = ans_host.command("show platform mlnx issu")["stdout"]
        if "disabled" in issu_capability:
            pytest.skip("ISSU is not supported on this DUT, skip this test case")

    reboot_and_check(localhost, ans_host, reboot_type="warm")
def test_show_platform_summary(localhost, ansible_adhoc, testbed):
    """
    @summary: Check output of 'show platform summary'
    """
    hostname = testbed['dut']
    ans_host = AnsibleHost(ansible_adhoc, hostname)

    logging.info("Check output of '%s'" % CMD_PLATFORM_SUMMARY)
    platform_summary = ans_host.command(CMD_PLATFORM_SUMMARY)
    expected_fields = set(["Platform", "HwSKU", "ASIC"])
    actual_fields = set()
    for line in platform_summary["stdout_lines"]:
        key_value = line.split(":")
        assert len(
            key_value) == 2, "output format is not 'field_name: field_value'"
        assert len(key_value[1]) > 0, "No value for field %s" % key_value[0]
        actual_fields.add(line.split(":")[0])
    assert actual_fields == expected_fields, \
        "Unexpected output fields, actual=%s, expected=%s" % (str(actual_fields), str(expected_fields))
Example #10
0
def test_bgp_speaker(localhost, ansible_adhoc, testbed, ipv4, ipv6, mtu):
    """setup bgp speaker on T0 topology and verify routes advertised
    by bgp speaker is received by T0 TOR
    """

    hostname = testbed['dut']
    ptf_hostname = testbed['ptf']
    host = AnsibleHost(ansible_adhoc, hostname)
    ptfhost = AnsibleHost(ansible_adhoc, ptf_hostname)

    mg_facts = host.minigraph_facts(host=hostname)['ansible_facts']
    host_facts  = host.setup()['ansible_facts']

    res = host.shell("sonic-cfggen -m -d -y /etc/sonic/constants.yml -v \"constants.deployment_id_asn_map[DEVICE_METADATA['localhost']['deployment_id']]\"")
    bgp_speaker_asn = res['stdout']

    vlan_ips = generate_ips(3, \
            "%s/%s" % (mg_facts['minigraph_vlan_interfaces'][0]['addr'], mg_facts['minigraph_vlan_interfaces'][0]['prefixlen']),
            [IPAddress(mg_facts['minigraph_vlan_interfaces'][0]['addr'])])

    # three speaker ips, two from peer range, another is vlan ip [0]
    speaker_ips = generate_ips(2, mg_facts['minigraph_bgp_peers_with_range'][0]['ip_range'][0], [])
    speaker_ips.append(vlan_ips[0])

    for ip in vlan_ips:
        host.command("ip route flush %s/32" % ip.ip)
        host.command("ip route add %s/32 dev %s" % (ip.ip, mg_facts['minigraph_vlan_interfaces'][0]['attachto']))

    root_dir   = "/root"
    exabgp_dir = "/root/exabgp"
    helper_dir = "/root/helpers"
    port_num = [5000, 6000, 7000]
    cfnames = ["config_1.ini", "config_2.ini", "config_3.ini"]
    vlan_ports = []
    for i in range(0, 3):
        vlan_ports.append(mg_facts['minigraph_port_indices'][mg_facts['minigraph_vlans'][mg_facts['minigraph_vlan_interfaces'][0]['attachto']]['members'][i]])

    ptfhost.file(path=exabgp_dir, state="directory")
    ptfhost.file(path=helper_dir, state="directory")
    ptfhost.copy(src="bgp_speaker/dump.py", dest=helper_dir)
    ptfhost.copy(src="bgp_speaker/http_api.py", dest=helper_dir)
    ptfhost.copy(src="bgp_speaker/announce_routes.py", dest=helper_dir)

    # deploy config file
    extra_vars = \
                { 'helper_dir': helper_dir,
                  'exabgp_dir': exabgp_dir,
                  'lo_addr'   : mg_facts['minigraph_lo_interfaces'][0]['addr'],
                  'lo_addr_prefixlen' : mg_facts['minigraph_lo_interfaces'][0]['prefixlen'],
                  'vlan_addr' : mg_facts['minigraph_vlan_interfaces'][0]['addr'],
                  'peer_range': mg_facts['minigraph_bgp_peers_with_range'][0]['ip_range'][0],
                  'announce_prefix': '10.10.10.0/26',
                  'minigraph_portchannels'  : mg_facts['minigraph_portchannels'],
                  'minigraph_vlans'  : mg_facts['minigraph_vlans'],
                  'minigraph_port_indices'  : mg_facts['minigraph_port_indices'],
                  'peer_asn'  : mg_facts['minigraph_bgp_asn'],
                  'peer_asn'  : mg_facts['minigraph_bgp_asn'],
                  'my_asn'    : bgp_speaker_asn,
                  'vlan_ports' : vlan_ports,
                  'port_num'  : port_num,
                  'speaker_ips': [str(ip) for ip in speaker_ips],
                  'vlan_ips': [str(ip) for ip in vlan_ips],
                  'cfnames': cfnames }

    for i in range(0, 3):
        extra_vars.update({ 'cidx':i })
        extra_vars.update({ 'speaker_ip': str(speaker_ips[i].ip) })
        ptfhost.host.options['variable_manager'].extra_vars.update(extra_vars)
        ptfhost.template(src="bgp_speaker/config.j2", dest="%s/%s" % (exabgp_dir, cfnames[i]))

    # deploy routes
    ptfhost.template(src="bgp_speaker/routes.j2", dest="%s/%s" % (exabgp_dir, "routes"))

    # deploy start script
    ptfhost.template(src="bgp_speaker/start.j2", dest="%s/%s" % (exabgp_dir, "start.sh"), mode="u+rwx")
    # kill exabgp
    res = ptfhost.shell("pkill exabgp || true")
    print res

    # start exabgp instance
    res = ptfhost.shell("bash %s/start.sh" % exabgp_dir)
    print res

    time.sleep(10)

    # announce route
    res = ptfhost.shell("nohup python %s/announce_routes.py %s/routes >/dev/null 2>&1 &" % (helper_dir, exabgp_dir))
    print res

    # make sure routes announced to dynamic bgp neighbors
    time.sleep(60)

    bgp_facts = host.bgp_facts()['ansible_facts']

    # Verify bgp sessions are established
    for k, v in bgp_facts['bgp_neighbors'].items():
        assert v['state'] == 'established'

    # Verify accepted prefixes of the dynamic neighbors are correct
    for ip in speaker_ips:
        assert bgp_facts['bgp_neighbors'][str(ip.ip)]['accepted prefixes'] == 1
    assert bgp_facts['bgp_neighbors'][str(vlan_ips[0].ip)]['accepted prefixes'] == 1


    # Generate route-port map information
    ptfhost.template(src="bgp_speaker/bgp_speaker_route.j2", dest="/root/bgp_speaker_route.txt")

    ptfhost.copy(src="ptftests", dest=root_dir)

    ptf_runner(ptfhost, \
               "ptftests",
               "fib_test.FibTest",
               platform_dir="ptftests",
               params={"testbed_type": "t0",
                      "router_mac": host_facts['ansible_Ethernet0']['macaddress'],
                      "fib_info": "/root/bgp_speaker_route.txt",
                      "ipv4": ipv4,
                      "ipv6": ipv6,
                      "testbed_mtu": mtu },
               log_file="/tmp/bgp_speaker_test.FibTest.log",
               socket_recv_size=16384)

    res = ptfhost.shell("pkill exabgp || true")

    for ip in vlan_ips:
        host.command("ip route flush %s/32" % ip.ip)

    ptfhost.shell("ip addr flush dev eth{}".format(mg_facts['minigraph_port_indices'][mg_facts['minigraph_vlans'][mg_facts['minigraph_vlan_interfaces'][0]['attachto']]['members'][0]]))
Example #11
0
def test_check_sfp_status_and_configure_sfp(localhost, ansible_adhoc, testbed):
    """
    @summary: Check SFP status and configure SFP

    This case is to use the sfputil tool and show command to check SFP status and configure SFP. Currently the
    only configuration is to reset SFP. Commands to be tested:
    * sfputil show presence
    * show interface transceiver presence
    * sfputil show eeprom
    * show interface transceiver eeprom
    * sfputil reset <interface name>
    """
    hostname = testbed['dut']
    ans_host = AnsibleHost(ansible_adhoc, hostname)
    localhost.command("who")
    lab_conn_graph_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), \
        "../../ansible/files/lab_connection_graph.xml")
    conn_graph_facts = localhost.conn_graph_facts(host=hostname, filename=lab_conn_graph_file).\
        contacted['localhost']['ansible_facts']

    cmd_sfp_presence = "sudo sfputil show presence"
    cmd_sfp_eeprom = "sudo sfputil show eeprom"
    cmd_sfp_reset = "sudo sfputil reset"
    cmd_xcvr_presence = "show interface transceiver presence"
    cmd_xcvr_eeprom = "show interface transceiver eeprom"

    logging.info("Check output of '%s'" % cmd_sfp_presence)
    sfp_presence = ans_host.command(cmd_sfp_presence)
    parsed_presence = parse_output(sfp_presence["stdout_lines"][2:])
    for intf in conn_graph_facts["device_conn"]:
        assert intf in parsed_presence, "Interface is not in output of '%s'" % cmd_sfp_presence
        assert parsed_presence[
            intf] == "Present", "Interface presence is not 'Present'"

    logging.info("Check output of '%s'" % cmd_xcvr_presence)
    xcvr_presence = ans_host.command(cmd_xcvr_presence)
    parsed_presence = parse_output(xcvr_presence["stdout_lines"][2:])
    for intf in conn_graph_facts["device_conn"]:
        assert intf in parsed_presence, "Interface is not in output of '%s'" % cmd_xcvr_presence
        assert parsed_presence[
            intf] == "Present", "Interface presence is not 'Present'"

    logging.info("Check output of '%s'" % cmd_sfp_eeprom)
    sfp_eeprom = ans_host.command(cmd_sfp_eeprom)
    parsed_eeprom = parse_eeprom(sfp_eeprom["stdout_lines"])
    for intf in conn_graph_facts["device_conn"]:
        assert intf in parsed_eeprom, "Interface is not in output of 'sfputil show eeprom'"
        assert parsed_eeprom[intf] == "SFP EEPROM detected"

    logging.info("Check output of '%s'" % cmd_xcvr_eeprom)
    xcvr_eeprom = ans_host.command(cmd_xcvr_eeprom)
    parsed_eeprom = parse_eeprom(xcvr_eeprom["stdout_lines"])
    for intf in conn_graph_facts["device_conn"]:
        assert intf in parsed_eeprom, "Interface is not in output of '%s'" % cmd_xcvr_eeprom
        assert parsed_eeprom[intf] == "SFP EEPROM detected"

    logging.info("Test '%s <interface name>'" % cmd_sfp_reset)
    for intf in conn_graph_facts["device_conn"]:
        reset_result = ans_host.command("%s %s" % (cmd_sfp_reset, intf))
        assert reset_result["rc"] == 0, "'%s %s' failed" % (cmd_sfp_reset,
                                                            intf)
    time.sleep(120)  # Wait some time for SFP to fully recover after reset

    logging.info("Check sfp presence again after reset")
    sfp_presence = ans_host.command(cmd_sfp_presence)
    parsed_presence = parse_output(sfp_presence["stdout_lines"][2:])
    for intf in conn_graph_facts["device_conn"]:
        assert intf in parsed_presence, "Interface is not in output of '%s'" % cmd_sfp_presence
        assert parsed_presence[
            intf] == "Present", "Interface presence is not 'Present'"
Example #12
0
def test_check_sfp_low_power_mode(localhost, ansible_adhoc, testbed):
    """
    @summary: Check SFP low power mode

    This case is to use the sfputil tool command to check and set SFP low power mode
    * sfputil show lpmode
    * sfputil lpmode off
    * sfputil lpmode on
    """
    hostname = testbed['dut']
    ans_host = AnsibleHost(ansible_adhoc, hostname)
    localhost.command("who")
    lab_conn_graph_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), \
        "../../ansible/files/lab_connection_graph.xml")
    conn_graph_facts = localhost.conn_graph_facts(host=hostname, filename=lab_conn_graph_file).\
        contacted['localhost']['ansible_facts']

    cmd_sfp_presence = "sudo sfputil show presence"
    cmd_sfp_show_lpmode = "sudo sfputil show lpmode"
    cmd_sfp_set_lpmode = "sudo sfputil lpmode"

    logging.info("Check output of '%s'" % cmd_sfp_show_lpmode)
    lpmode_show = ans_host.command(cmd_sfp_show_lpmode)
    parsed_lpmode = parse_output(lpmode_show["stdout_lines"][2:])
    original_lpmode = copy.deepcopy(parsed_lpmode)
    for intf in conn_graph_facts["device_conn"]:
        assert intf in parsed_lpmode, "Interface is not in output of '%s'" % cmd_sfp_show_lpmode
        assert parsed_lpmode[intf].lower() == "on" or parsed_lpmode[
            intf].lower() == "off", "Unexpected SFP lpmode"

    logging.info("Try to change SFP lpmode")
    for intf in conn_graph_facts["device_conn"]:
        new_lpmode = "off" if original_lpmode[intf].lower() == "on" else "on"
        lpmode_set_result = ans_host.command(
            "%s %s %s" % (cmd_sfp_set_lpmode, new_lpmode, intf))
        assert lpmode_set_result["rc"] == 0, "'%s %s %s' failed" % (
            cmd_sfp_set_lpmode, new_lpmode, intf)
    time.sleep(10)

    logging.info("Check SFP lower power mode again after changing SFP lpmode")
    lpmode_show = ans_host.command(cmd_sfp_show_lpmode)
    parsed_lpmode = parse_output(lpmode_show["stdout_lines"][2:])
    for intf in conn_graph_facts["device_conn"]:
        assert intf in parsed_lpmode, "Interface is not in output of '%s'" % cmd_sfp_show_lpmode
        assert parsed_lpmode[intf].lower() == "on" or parsed_lpmode[
            intf].lower() == "off", "Unexpected SFP lpmode"

    logging.info("Try to change SFP lpmode")
    for intf in conn_graph_facts["device_conn"]:
        new_lpmode = original_lpmode[intf].lower()
        lpmode_set_result = ans_host.command(
            "%s %s %s" % (cmd_sfp_set_lpmode, new_lpmode, intf))
        assert lpmode_set_result["rc"] == 0, "'%s %s %s' failed" % (
            cmd_sfp_set_lpmode, new_lpmode, intf)
    time.sleep(10)

    logging.info("Check SFP lower power mode again after changing SFP lpmode")
    lpmode_show = ans_host.command(cmd_sfp_show_lpmode)
    parsed_lpmode = parse_output(lpmode_show["stdout_lines"][2:])
    for intf in conn_graph_facts["device_conn"]:
        assert intf in parsed_lpmode, "Interface is not in output of '%s'" % cmd_sfp_show_lpmode
        assert parsed_lpmode[intf].lower() == "on" or parsed_lpmode[
            intf].lower() == "off", "Unexpected SFP lpmode"

    logging.info("Check sfp presence again after setting lpmode")
    sfp_presence = ans_host.command(cmd_sfp_presence)
    parsed_presence = parse_output(sfp_presence["stdout_lines"][2:])
    for intf in conn_graph_facts["device_conn"]:
        assert intf in parsed_presence, "Interface is not in output of '%s'" % cmd_sfp_presence
        assert parsed_presence[
            intf] == "Present", "Interface presence is not 'Present'"
def test_turn_on_off_psu_and_check_psustatus(localhost, ansible_adhoc, testbed,
                                             psu_controller):
    """
    @summary: Turn off/on PSU and check PSU status using 'show platform psustatus'
    """
    hostname = testbed['dut']
    ans_host = AnsibleHost(ansible_adhoc, hostname)
    platform_info = parse_platform_summary(
        ans_host.command(CMD_PLATFORM_SUMMARY)["stdout_lines"])

    psu_line_pattern = re.compile(r"PSU\s+\d+\s+(OK|NOT OK|NOT PRESENT)")
    cmd_num_psu = "sudo psuutil numpsus"

    logging.info("Check whether the DUT has enough PSUs for this testing")
    psu_num_out = ans_host.command(cmd_num_psu)
    psu_num = 0
    try:
        psu_num = int(psu_num_out["stdout"])
    except:
        assert False, "Unable to get the number of PSUs using command '%s'" % cmd_num_psu
    if psu_num < 2:
        pytest.skip(
            "At least 2 PSUs required for rest of the testing in this case")

    logging.info("Create PSU controller for testing")
    psu_ctrl = psu_controller(hostname, platform_info["asic"])
    if psu_ctrl is None:
        pytest.skip(
            "No PSU controller for %s, skip rest of the testing in this case" %
            hostname)

    logging.info(
        "To avoid DUT losing power, need to turn on PSUs that are not powered")
    all_psu_status = psu_ctrl.get_psu_status()
    if all_psu_status:
        for psu in all_psu_status:
            if not psu["psu_on"]:
                psu_ctrl.turn_on_psu(psu["psu_id"])
                time.sleep(5)

    logging.info("Initialize test results")
    cli_psu_status = ans_host.command(CMD_PLATFORM_PSUSTATUS)
    psu_test_results = {}
    for line in cli_psu_status["stdout_lines"][2:]:
        fields = line.split()
        psu_test_results[fields[1]] = False
        if " ".join(fields[2:]) == "NOT OK":
            pytest.skip(
                "Some PSUs are still not powered, it is not safe to proceed, skip testing"
            )
    assert len(psu_test_results.keys()) == psu_num, \
        "In consistent PSU number output by '%s' and '%s'" % (CMD_PLATFORM_PSUSTATUS, cmd_num_psu)

    logging.info("Start testing turn off/on PSUs")
    all_psu_status = psu_ctrl.get_psu_status()
    for psu in all_psu_status:
        psu_under_test = None

        logging.info("Turn off PSU %s" % str(psu["psu_id"]))
        psu_ctrl.turn_off_psu(psu["psu_id"])
        time.sleep(5)

        cli_psu_status = ans_host.command(CMD_PLATFORM_PSUSTATUS)
        for line in cli_psu_status["stdout_lines"][2:]:
            assert psu_line_pattern.match(line), "Unexpected PSU status output"
            fields = line.split()
            if fields[2] != "OK":
                psu_under_test = fields[1]
        assert psu_under_test is not None, "No PSU is turned off"

        logging.info("Turn on PSU %s" % str(psu["psu_id"]))
        psu_ctrl.turn_on_psu(psu["psu_id"])
        time.sleep(5)

        cli_psu_status = ans_host.command(CMD_PLATFORM_PSUSTATUS)
        for line in cli_psu_status["stdout_lines"][2:]:
            assert psu_line_pattern.match(line), "Unexpected PSU status output"
            fields = line.split()
            if fields[1] == psu_under_test:
                assert fields[
                    2] == "OK", "Unexpected PSU status after turned it on"

        psu_test_results[psu_under_test] = True

    for psu in psu_test_results:
        assert psu_test_results[psu], "Test psu status of PSU %s failed" % psu