Added New script for IPMI Cold Reset command

The Cold reset command directs the Responder to perform a ‘Cold Reset’ action, which causes default setting of interrupt enables, event message generation, sensor scanning, threshold values, and other ‘power up default’ state to be restored.

The script consist of 3 testcases:
-  Cold_Reset_Via_IPMI
-  Cold_Reset_With_Invalid_Data_Request_Via_IPMI
-  Verify_Cold_Reset_Impact_On_Sensor_Threshold_Via_IPMI

Request data for cold reset present in data/ipmi_raw_cmd_table.py

Python basic operations under file lib/ipmi_utils.py like threshold value calculation - 'Identify Threshold'  and under lib/utils.py for striping extra characters across the strings - 'Remove Whitespace' fucntion (check commit - https://gerrit.openbmc-project.xyz/c/openbmc/openbmc-test-automation/+/51641 for remove_whitespace function).

The script verifies command execution for cold reset, invalid data request verification of cold reset and impact on sensor threshold value change with cold reset.

The script changes sensor threshold value for Fan sensor, executes cold reset IPMI command, verifies sensor threshold values of initial and reading after cold reset.

Tested: Run robot ipmi/test_ipmi_cold_reset.robot

Signed-off-by: chithrag <chithrag@ami.com>
Change-Id: I116fad1fc8c8c9c7c3b1e4d6d26fc9a4412a5637
diff --git a/ipmi/test_ipmi_cold_reset.robot b/ipmi/test_ipmi_cold_reset.robot
new file mode 100644
index 0000000..6c435eb
--- /dev/null
+++ b/ipmi/test_ipmi_cold_reset.robot
@@ -0,0 +1,200 @@
+*** Settings ***
+Documentation       This suite tests IPMI Cold Reset in OpenBMC.
+...
+...                 The Cold reset command directs the Responder to perform
+...                 a 'Cold Reset' action, which causes default setting of
+...                 interrupt enables, event message generation,sensor scanning,
+...                 threshold values, and other 'power up' default state to be restored.
+...
+...                 The script consist of 3 testcases:
+...                 -  Cold_Reset_Via_IPMI
+...                 -  Cold_Reset_With_Invalid_Data_Request_Via_IPMI
+...                 -  Verify_Cold_Reset_Impact_On_Sensor_Threshold_Via_IPMI
+...
+...                 Request data for cold reset present under data/ipmi_raw_cmd_table.py
+...
+...                 Python basic operations under new file lib/functions.py like
+...                 threshold value calculation and striping extra characters
+...                 across the strings.
+...
+...                 The script verifies command execution for cold reset,
+...                 invalid data request verification of cold reset and
+...                 impact on sensor threshold value change with cold reset.
+...
+...                 The script changes sensor threshold value for Fan sensor,
+...                 executes cold reset IPMI command,
+...                 compares sensor threshold values of initial and reading after cold reset.
+
+Library             Collections
+Library             ../lib/ipmi_utils.py
+Resource            ../lib/ipmi_client.robot
+Resource            ../lib/openbmc_ffdc.robot
+Variables           ../data/ipmi_raw_cmd_table.py
+
+#Test Teardown       FFDC On Test Case Fail
+
+
+*** Variables ***
+
+${NETWORK_RESTART_TIME}    30s
+@{thresholds_list}         lcr   lnc   unc   ucr
+
+
+*** Test Cases ***
+
+Cold Reset Via IPMI
+    [Documentation]  Verify Cold Reset via IPMI.
+    [Tags]  Cold_Reset_Via_IPMI
+
+    # Cold Reset Via IPMI raw command.
+    Run External IPMI Raw Command  ${IPMI_RAW_CMD['Cold Reset']['reset'][0]}
+
+    # Get the BMC Status.
+    Wait Until Keyword Succeeds  3 min  10 sec  Is BMC Unpingable
+    Wait Until Keyword Succeeds  3 min  10 sec  Is BMC Operational
+
+    # Verify if BMC restarted with Get Device ID command.
+
+    ${resp}=  Run External IPMI Raw Command  ${IPMI_RAW_CMD['Device ID']['Get'][0]}
+    Should Not Contain  ${resp}  ${IPMI_RAW_CMD['Device ID']['Get'][1]}
+
+
+Cold Reset With Invalid Data Request Via IPMI
+    [Documentation]  Verify Cold Reset with invalid data request via IPMI.
+    [Tags]  Cold_Reset_With_Invalid_Data_Request_Via_IPMI
+
+    # Verify cold reset with invalid length of the request data and expect error.
+    ${resp}=  Run Keyword and Expect Error  *Request data length invalid*
+    ...  Run External IPMI Raw Command  ${IPMI_RAW_CMD['Cold Reset']['reset'][0]} 0x00
+
+
+Verify Cold Reset Impact On Sensor Threshold Via IPMI
+    [Documentation]  Modify sensor threshold, perform cold reset,
+    ...  and verify if sensor threshold reverts back to initial value.
+    [Tags]  Verify_Cold_Reset_Impact_On_Sensor_Threshold_Via_IPMI
+
+    # Get sensor list.
+    ${Sensor_list}=  Get Sensor List
+
+    # Get initial sensor threshold readings.
+    ${initial_sensor_threshold}  ${sensor_name}=  Get The Sensor Threshold For Sensor  ${sensor_list}
+
+    # Identify sensor threshold values to modify.
+    ${threshold_dict}=  Identify Sensor Threshold Values   ${initial_sensor_threshold}
+
+    # Set sensor threshold for given sensor and compare with initial reading.
+    ${set_sensor_threshold}=  Set Sensor Threshold For given Sensor  ${threshold_dict}  ${sensor_name}
+    Should Not Be Equal  ${set_sensor_threshold}  ${initial_sensor_threshold}
+
+    # Execute cold reset command via IPMI and check status.
+    Run External IPMI Raw Command  ${IPMI_RAW_CMD['Cold Reset']['reset'][0]}
+    Wait Until Keyword Succeeds  3 min  10 sec  Is BMC Unpingable
+    Wait Until Keyword Succeeds  3 min  10 sec  Is BMC Operational
+
+    # Get sensor data for the sensor identified.
+    ${data_after_coldreset}=  Wait Until Keyword Succeeds  2 min  30 sec
+    ...  Run IPMI Standard Command   sensor | grep -i RPM | grep "${sensor_name}"
+
+    # Get sensor threshold readings after BMC restarts.
+    ${sensor_threshold_after_reset}  ${sensor_name_after_reset}=  Get The Sensor Threshold For Sensor  ${data_after_coldreset}
+
+    # Compare with initial sensor threshold values.
+    Should Be Equal  ${sensor_threshold_after_reset}  ${initial_sensor_threshold}
+
+
+*** Keywords ***
+
+Get Sensor List
+    [Documentation]  To get the list of sensors via IPMI sensor list.
+
+    # BMC may take time to populate all the sensors once BMC Cold reset completes.
+    ${data}=  Wait Until Keyword Succeeds  2 min  30 sec
+    ...  Run IPMI Standard Command   sensor | grep -i RPM
+
+    [Return]  ${data}
+
+Identify Sensor
+    [Documentation]  To identify the sensor via IPMI sensor list.
+    [Arguments]  ${data}
+
+    # Find Sensor detail of sensor list first entry.
+    # Description of Argument(s):
+    #    ${data}     All the sensors listed with ipmi sensor list command.
+    ${data}=  Split To Lines  ${data}
+    ${data}=  Set Variable  ${data[0]}
+
+    [Return]  ${data}
+
+
+Get Sensor Readings For The Sensor
+    [Documentation]  To get the sensor reading of the given sensor using IPMI.
+    [Arguments]  ${Sensors_all}
+
+    # Split Sensor details in a list.
+    # Description of Argument(s):
+    #    ${Sensors_all}     All the sensors listed with ipmi sensor list command.
+    ${sensor}=  Identify Sensor  ${Sensors_all}
+    ${data}=  Split String  ${sensor}  |
+
+    # Locate the sensor name.
+    ${sensor_name}=  Set Variable  ${data[0]}
+    # Function defined in lib/utils.py.
+    ${sensor_name}=  Remove Whitespace  ${sensor_name}
+
+    [Return]  ${data}  ${sensor_name}
+
+
+Get The Sensor Threshold For Sensor
+    [Documentation]  To get the sensor threshold for given sensor using IPMI.
+    [Arguments]  ${Sensor_list}
+
+    # Description of Argument(s):
+    #    ${Sensor_list}    All the sensors listed with ipmi sensor list command.
+
+    # Gets the sensor data and sensor name for the required sensor.
+    ${data}  ${sensor_name}=  Get Sensor Readings For The Sensor  ${Sensor_list}
+    # Gets the threshold values in a list.
+    ${threshold}=  Set Variable  ${data[5:9]}
+
+    [Return]  ${threshold}  ${sensor_name}
+
+
+Identify Sensor Threshold Values
+    [Documentation]  Identify New Sensor Threshold Values with adding 100 to old threshold values.
+    [Arguments]  ${old_threshold}
+
+    # Description of Argument(s):
+    #    ${old_threshold}   original threshold values list of the given sensor.
+
+    # Retrieves modified threshold values of the original threshold value.
+    ${threshold_dict}=  Identify Threshold  ${old_threshold}  ${thresholds_list}
+
+    [Return]  ${threshold_dict}
+
+
+Set Sensor Threshold For given Sensor
+    [Documentation]  Set Sensor Threshold for given sensor with given Upper and Lower critical and non-critical values Via IPMI
+    [Arguments]  ${threshold_list}  ${sensor}
+
+    # Description of Argument(s):
+    #    ${threshold_list}    New thresholds to be set.
+    #    ${sensor}            Sensor name.
+
+    # Set critical and non-critical values for the given sensor.
+    FOR  ${criticals}  IN  @{threshold_list}
+        # Set Lower/Upper critical and non-critical values if a threshold is available.
+        Run keyword if  '${threshold_list['${criticals}']}' != 'na'
+        ...  Run IPMI Standard Command
+        ...  sensor thresh "${sensor}" ${criticals} ${threshold_list['${criticals}']}
+        # Allow Network restart sleep time for the readings to get reflected.
+        Sleep  ${NETWORK_RESTART_TIME}
+    END
+
+    # Get sensor list for the sensor name identified.
+    ${data}=  Wait Until Keyword Succeeds  2 min  30 sec
+    ...  Run IPMI Standard Command   sensor | grep -i RPM | grep "${sensor}"
+
+    # Get new threshold value set from sensor list.
+    ${threshold_new}  ${sensor_name}=  Get The Sensor Threshold For Sensor  ${data}
+
+    [Return]  ${threshold_new}
diff --git a/lib/ipmi_utils.py b/lib/ipmi_utils.py
index af5ee6d..16c50e3 100644
--- a/lib/ipmi_utils.py
+++ b/lib/ipmi_utils.py
@@ -759,3 +759,34 @@
         item = "0x" + item
         listy.append(item)
     return listy
+
+
+def identify_threshold(old_threshold, threshold_list):
+    r"""
+    Gets threshold values and threshold levels from sensor list.
+    Modify the values and returns updated threshold.
+    Description of argument(s):
+
+        old_threshold              List of thresold values of sensor,
+        threshold_list             List of higher and lower of critical and non-critical values.
+
+    For example :
+        If old_threshold list is [ 1, 2, 3, 4] then the newthreshold_list will be [ 101, 102, 103, 104 ].
+        If old_threshold has 'na' the same will be appended to new list.
+
+    The newthreshold_list will be zipped to dictionary with threshold_list levels,
+    Example : threshold_dict = { 'lcr': 101, 'lnc': 102, 'unc': 103, 'ucr': 104 }
+    """
+
+    n = 100
+    newthreshold_list = []
+    for th in old_threshold:
+        th = th.strip()
+        if th == 'na':
+            newthreshold_list.append('na')
+        else:
+            x = int(float(th)) + n
+            newthreshold_list.append(x)
+            n = n + 100
+    threshold_dict = dict(zip(threshold_list, newthreshold_list))
+    return newthreshold_list, threshold_dict