*** Settings ***

Documentation    Module to test IPMI SEL functionality.
Resource         ../lib/ipmi_client.robot
Resource         ../lib/openbmc_ffdc.robot
Library          ../lib/ipmi_utils.py
Variables        ../data/ipmi_raw_cmd_table.py

Test Setup       Test Setup Execution
Test Teardown    FFDC On Test Case Fail

*** Variables ***

# Based on 13th byte of add SEL entry command as per IPMI spec
# event_dir and event_type variable value needs to be given.
${sel_no_entry_msg}  SEL has no entries
${event_type}        Lower Non-critical going low
${event_dir}         Asserted

*** Test Cases ***

Verify IPMI SEL Version
    [Documentation]  Verify IPMI SEL's version info.
    [Tags]  Verify_IPMI_SEL_Version
    ${version_info}=  Get IPMI SEL Setting  Version
    ${setting_status}=  Fetch From Left  ${version_info}  (
    ${setting_status}=  Evaluate  $setting_status.replace(' ','')

    Should Be True  ${setting_status} >= 1.5
    Should Contain  ${version_info}  v2 compliant  case_insensitive=True


Verify Empty SEL
    [Documentation]  Verify IPMI sel clear command clears the SEL entry.
    [Tags]  Verify_Empty_SEL

    # Generate an error log and verify there is one at least.
    Create Test PEL Log
    ${resp}=  Run IPMI Standard Command  sel elist last 1
    Log To Console  ${resp}

    Should Contain Any  ${resp}  system hardware failure   Asserted
    ...  msg=Add SEL Entry failed.

    # Send SEL clear command and verify if it really clears up the SEL entry.
    Run IPMI Standard Command  sel clear
    Sleep  5s

    ${resp}=  Run IPMI Standard Command  sel list
    Should Contain  ${resp}  SEL has no entries  case_insensitive=True


Verify Add SEL Entry
    [Documentation]  Verify add SEL entry.
    [Tags]  Verify_Add_SEL_Entry
    [Teardown]  Run Keywords  FFDC On Test Case Fail  AND  Run IPMI Standard Command  sel clear

    # The IPMI raw command to generate Temp sensor  error is no longer working.
    # Our aim is to check if the SEL command is listed in IPMI or not.
    # Original keyword "Create User Defined SEL" for reference
    Create Test PEL Log

    # Get last SEL entry.
    ${resp}=  Run IPMI Standard Command  sel elist last 1
    #  output:
    #  1 | 11/17/2021 | 07:49:20 | System Event #0x01 | Undetermined system hardware failure | Asserted
    Run Keywords  Should Contain  ${resp}  system hardware failure  AND
    ...  Should Contain  ${resp}  Asserted  msg=Add SEL Entry failed.


Verify Add SEL Entry For Any Random Sensor
    [Documentation]  Create SEL entry and verify for any given random sensor.
    [Tags]  Verify_Add_SEL_Entry_For_Any_Random_Sensor
    [Teardown]  Run Keywords  FFDC On Test Case Fail  AND  Run IPMI Standard Command  sel clear

    # Get any sensor available from sensor list.
    ${sensor_name}=  Fetch One Threshold Sensor From Sensor List

    # Get Sensor ID from SDR get "sensor".
    ${sensor_data1}=  Fetch Sensor Details From SDR  ${sensor_name}  Sensor ID
    ${sensor_number}=  Get Bytes From SDR Sensor  ${sensor_data1}

    # Get Sensor Type from SDR get "sensor".
    ${sensor_data2}=  Fetch Sensor Details From SDR  ${sensor_name}  Sensor Type (Threshold)
    ${sensor_type_id}=  Get Bytes From SDR Sensor  ${sensor_data2}

    # Add SEL Entry.
    # ${sel_entry_id} is the Record ID for added record (LSB First).
    ${sel_create_resp}=  Create SEL  ${sensor_type_id}  ${sensor_number}
    ${sel_entry_id}=  Split String  ${sel_create_resp}

    # Get last SEL entry.
    ${resp}=  Run IPMI Standard Command  sel elist
    Should Not Contain  ${resp}  ${sel_no_entry_msg}

    # Output of the Sel elist.
    # Below example is a continuous line statement.
    #    N | MM/DD/YYYY | HH:MM:SS | Sensor_Type Sensor_Name |
    #    Lower Non-critical going low  | Asserted | Reading 0.

    ${get_sel_entry}=  Get Lines Containing String  ${resp}  ${sensor_name}
    ${sel_entry}=  Get Lines Containing String  ${get_sel_entry}  ${event_type}
    Should Contain  ${sel_entry}  ${event_dir}  msg=Add SEL Entry failed.

    # Get SEL Entry IPMI Raw Command.
    ${entry}=  Get SEL Entry Via IPMI  ${sel_entry_id[0]}  ${sel_entry_id[1]}

    # Compare SEL Record ID.
    ${sel_record_id}=  Set Variable  ${entry[2:4]}
    Should Be Equal  ${sel_record_id}  ${sel_entry_id}

    # Sensor type compare.
    Should Be Equal  ${sensor_type_id}  ${entry[12]}

    # Sensor number compare.
    Should Be Equal  ${sensor_number}  ${entry[13]}


Verify Reserve SEL
    [Documentation]  Verify reserve SEL.
    [Tags]  Verify_Reserve_SEL

    ${resp}=  Run IPMI Standard Command
    ...  raw ${IPMI_RAW_CMD['SEL_entry']['Reserve'][0]}
    ${reserve_id}=  Split String  ${resp}

    # Execute clear SEL raw command with Reservation ID.
    # Command will not execute unless the correct Reservation ID value is provided.
    Run IPMI Standard Command
    ...  raw 0x0a 0x47 0x${reserve_id[0]} 0x${reserve_id[1]} 0x43 0x4c 0x52 0xaa

    # Check SEL list.
    ${resp}=  Run IPMI Standard Command  sel list
    Should Contain  ${resp}  SEL has no entries  case_insensitive=True


Verify IPMI SEL Most Recent Addition Timestamp
    [Documentation]  Verify most recent addition timestamp in SEL info.
    [Tags]  Verify_IPMI_SEL_Most_Recent_Addition_Timestamp

    # Get Most Recent Addition Timestamp from SEL Info.
    ${addition_timestamp}=  Get Most Recent Addition Timestamp From SEL Info

    IF  '${addition_timestamp}' != 'ffffffff'
        # Convert to epoch timestamp.
        ${epoch_addition}=  Convert To Integer  ${addition_timestamp}  16

        # Get SEL List last 1 entry date and time and convert to epoch timestamp.
        ${sel_epoch_time}=  Get SEL Elist Last Entry Date In Epoch

        # Compare epoch of sel entry timestamp and last addition timestamp.
        ${diff}=  Evaluate  int(${sel_epoch_time}) - int(${epoch_addition})
        Should Be True  ${diff}<=600

    ELSE
        # Get any Sensor available from Sensor list
        ${sensor_name}=  Fetch One Threshold Sensor From Sensor List

        # Get Sensor ID from SDR Get "sensor" and Identify Sensor ID.
        ${sensor_data1}=  Fetch Sensor Details From SDR  ${sensor_name}  Sensor ID
        ${sensor_number}=  Get Bytes From SDR Sensor  ${sensor_data1}

        # Get Sensor Type from SDR Get "sensor" and Identify Sensor Type.
        ${sensor_data2}=  Fetch Sensor Details From SDR  ${sensor_name}  Sensor Type (Threshold)
        ${sensor_type_id}=  Get Bytes From SDR Sensor  ${sensor_data2}

        # Add SEL Entry.
        ${sel_create_resp}=  Create SEL  ${sensor_type_id}  ${sensor_number}

        # Get SEL List last 1 entry date and time and convert to epoch timestamp.
        ${sel_epoch_time}=  Get SEL Elist Last Entry Date In Epoch

        # Get Most Recent Addition Timestamp from SEL Info.
        ${addition}=  Get Most Recent Addition Timestamp From SEL Info
        ${epoch_addition}=  Convert To Integer  ${addition}  16

        # Compare epoch of sel entry timestamp and last addition timestamp.
        ${diff}=  Evaluate  int(${epoch_addition}) - int(${sel_epoch_time})
        Should Be True  ${diff}<=5
    END


Verify IPMI SEL Most Recent Erase Timestamp
    [Documentation]  Verify Most Recent Erase Timestamp In SEL Info with current
    ...              BMC epoch timestamp.
    [Tags]  Verify_IPMI_SEL_Most_Recent_Erase_Timestamp

    # Get BMC Current Time.
    ${bmc_epoch_time}=  Get BMC Time In Epoch

    # Get Most Recent Addition Timestamp from SEL Info.
    ${addition_timestamp}=  Get Most Recent Addition Timestamp From SEL Info
    Should Be Equal  ${addition_timestamp}  ffffffff

    # Get Most Recent Erase Timestamp from SEL Info.
    ${erase_timestamp}=  Get Most Recent Erase Timestamp From SEL Info
    ${epoch_erase}=  Convert To Integer  ${erase_timestamp}  16

    # Compare epoch of erase timestamp and current bmc timestamp.
    ${diff}=  Evaluate  int(${epoch_erase}) - int(${bmc_epoch_time})
    Should Be True  ${diff}<=5


Verify Clear SEL With Invalid Reservation ID
    [Documentation]  Verify clear SEL After generating another reserve ID.
    [Tags]  Verify_Clear_SEL_With_Invalid_Reservation_ID

    # Reserve Sel command - 1.
    ${resp}=  Run IPMI Standard Command
    ...  raw ${IPMI_RAW_CMD['SEL_entry']['Reserve'][0]}
    ${reserve_id}=  Split String  ${resp}

    # Reserve Sel command - 2.
    ${resp}=  Run IPMI Standard Command
    ...  raw ${IPMI_RAW_CMD['SEL_entry']['Reserve'][0]}

    ${cmd}=  Catenate  ${IPMI_RAW_CMD['SEL_entry']['Clear_SEL'][0]} 0x${reserve_id[0]}
    ...  0x${reserve_id[1]} ${IPMI_RAW_CMD['SEL_entry']['Clear_SEL'][1]}

    # Clear SEL command.
    ${clear_resp}=  Run Keyword and Expect Error  *${IPMI_RAW_CMD['SEL_entry']['Clear_SEL'][4]}*
    ...  Run IPMI Standard Command  raw ${cmd}
    Should Contain  ${clear_resp}  ${IPMI_RAW_CMD['SEL_entry']['Clear_SEL'][5]}


Verify Reservation ID Erasure Status
    [Documentation]  Verify Erasure status by clearing SEL with Reserve ID and verify the response byte,
    ...  whether erasure status is updated in clear sel command response data using new Reserve ID.
    [Tags]  Verify_Reservation_ID_Erasure_Status

    # Generate Reserve ID 1.
    ${resp}=  Run IPMI Standard Command
    ...  raw ${IPMI_RAW_CMD['SEL_entry']['Reserve'][0]}
    ${reserve_id}=  Split String  ${resp}

    ${cmd1}=  Catenate  ${IPMI_RAW_CMD['SEL_entry']['Clear_SEL'][0]} 0x${reserve_id[0]}
    ...  0x${reserve_id[1]} ${IPMI_RAW_CMD['SEL_entry']['Clear_SEL'][1]}

    # Execute clear SEL raw command with Reservation ID.
    # Command will not execute unless the correct Reservation ID value is provided.
    Run IPMI Standard Command  raw ${cmd1}

    # Generate Reserver ID 2.
    ${resp}=  Run IPMI Standard Command
    ...  raw ${IPMI_RAW_CMD['SEL_entry']['Reserve'][0]}
    ${reserve_id}=  Split String  ${resp}

    ${cmd2}=  Catenate  ${IPMI_RAW_CMD['SEL_entry']['Clear_SEL'][0]} 0x${reserve_id[0]}
    ...  0x${reserve_id[1]} ${IPMI_RAW_CMD['SEL_entry']['Clear_SEL'][6]}

    # Check the Erasure status of Clear SEL.
    ${data}=  Run IPMI Standard Command  raw ${cmd2}

    # 00 - Erasure in Progress , 01 - Erasure Complete.
    Should Contain Any  ${data}  00  01


Verify Clear SEL After Cold Reset
    [Documentation]  Verify Clear SEL for a reserve SEL ID after Cold Reset.
    [Tags]  Verify_Clear_SEL_After_Cold_Reset

    # Reserve Sel command.
    ${resp}=  Run IPMI Standard Command
    ...  raw ${IPMI_RAW_CMD['SEL_entry']['Reserve'][0]}
    ${reserve_id}=  Split String  ${resp}

    # Run Cold Reset.
    IPMI MC Reset Cold (off)

    ${cmd}=  Catenate  ${IPMI_RAW_CMD['SEL_entry']['Clear_SEL'][0]} 0x${reserve_id[0]}
    ...  0x${reserve_id[1]} ${IPMI_RAW_CMD['SEL_entry']['Clear_SEL'][1]}

    # Clear SEL command.
    ${clear_resp}=  Run Keyword and Expect Error  *${IPMI_RAW_CMD['SEL_entry']['Clear_SEL'][5]}*
    ...  Run IPMI Standard Command  raw ${cmd}

    Should Contain  ${clear_resp}  ${IPMI_RAW_CMD['SEL_entry']['Clear_SEL'][4]}


*** Keywords ***

Create User Defined SEL
    [Documentation]  Create a user defined tempearature sensor SEL.

    # Create a SEL.
    # Example:
    # a | 02/14/2020 | 01:16:58 | Temperature #0x17 |  | Asserted
    Run IPMI Command
    ...  0x0a 0x44 0x00 0x00 0x02 0x00 0x00 0x00 0x00 0x00 0x00 0x04 0x01 ${sensor_number} 0x00 0xa0 0x04 0x07


Get SEL Entry Via IPMI
    [Documentation]  Get SEL Entry Via IPMI raw command.
    [Arguments]  ${record1}  ${record2}

    # Description of Argument(s):
    # ${record1}    Record ID for added record, LS Byte
    # ${record2}    Record ID for added record, MS Byte

    # For example, when a first sel entry is added with IPMI raw command, the response will be "01 00".
    # Here, ${record1} is 01, and ${record2} is 00.

    ${cmd}=  Catenate  ${IPMI_RAW_CMD['SEL_entry']['Get_SEL_Entry'][0]} 0x${record1}
    ...  0x${record2} ${IPMI_RAW_CMD['SEL_entry']['Get_SEL_Entry'][1]}

    # Get SEL Entry Raw command.
    ${resp}=  Run IPMI Standard Command  raw ${cmd}
    ${resp}=  Split String  ${resp}

    [Return]  ${resp}


Get Most Recent Addition Timestamp From SEL Info
    [Documentation]  Get Most recent addition timestamp From SEL Info.

    # Get SEL Info raw command.
    ${sel_info}=  Get SEL Info Via IPMI

    # Get Most Recent Addition timestamp in hex.
    ${addition_timestamp}=  Set Variable  ${sel_info[5:9]}
    Reverse List  ${addition_timestamp}
    ${addition_timestamp}=  Evaluate  "".join(${addition_timestamp})

    [Return]  ${addition_timestamp}


Get Most Recent Erase Timestamp From SEL Info
    [Documentation]  Get Most recent erase timestamp From SEL Info.

    # Get SEL Info Raw command.
    ${sel_info}=  Get SEL Info Via IPMI

    # Get Most Recent Erase timestamp in hex.
    ${erase_timestamp}=  Set Variable  ${sel_info[9:13]}
    Reverse List  ${erase_timestamp}
    ${erase_timestamp}=  Evaluate  "".join(${erase_timestamp})

    [Return]  ${erase_timestamp}


Get SEL Elist Last Entry Date In Epoch
    [Documentation]  Get the time from SEL elist last entry and returns epoch time.

    # Get SEL list last entry.
    ${resp}=  Run IPMI Standard Command  sel elist last 1

    # Get date from the sel entry and convert to epoch timestamp.
    ${sel_entry_date}=  Fetch Added SEL Date  ${resp}
    ${epoch_date}=  Convert Date  ${sel_entry_date}  epoch  exclude_millis=yes  date_format=%m/%d/%Y %H:%M:%S

    [Return]  ${epoch_date}


Get BMC Time In Epoch
    [Documentation]  Get the current time from BMC and returns epoch time.

    # Get the bmc native bmc date command response.
    ${date}=  Get Current Date from BMC

    ${epoch_date}=  Convert Date  ${date}  epoch  exclude_millis=yes  date_format=%m/%d/%Y %H:%M:%S

    [Return]   ${epoch_date}


Test Setup Execution
    [Documentation]  Do test setup tasks.

    Run IPMI Standard Command  sel clear
    Sleep  5s