Test to do repeated, random boots
Utilizes additional keywords:
Validate Connection
Intersect Lists
Search List
Change-Id: I29a2a4805bb685a0519d4e0f7eec5ab1568edca0
Signed-off-by: Gunnar Mills <gmills@us.ibm.com>
diff --git a/lib/connection_client.robot b/lib/connection_client.robot
index 5616071..7e88882 100755
--- a/lib/connection_client.robot
+++ b/lib/connection_client.robot
@@ -68,3 +68,69 @@
${https_num}= Convert To Integer ${HTTPS_PORT}
Set Global Variable ${AUTH_URI} https://${OPENBMC_HOST}:${https_num}
+
+Validate Or Open Connection
+ [Documentation] Checks for an open connection to a host or alias.
+ [Arguments] ${alias}=None ${host}=${EMPTY} &{connection_args}
+
+ # alias The alias of the connection to validate.
+ # host The DNS name or IP of the host to validate.
+ # connection_args A dictionary of arguments to pass to Open Conection
+ # and Log In (see above) if the connection is not open. May
+ # contain, but does not need to contain, the host or alias.
+
+ # Check to make sure we have an alias or host to search for.
+ Run Keyword If '${host}' == '${EMPTY}' Should Not Be Equal ${alias} None
+ ... msg=Need to provide a host or an alias. values=False
+
+ # Search the dictionary to see if it includes the host and alias.
+ ${host_exists}= Run Keyword and Return Status
+ ... Dictionary Should Contain Key ${connection_args} host
+ ${alias_exists}= Run Keyword and Return Status
+ ... Dictionary Should Contain Key ${connection_args} alias
+
+ # Add the alias and host back into the dictionary of connection arguments,
+ # if needed.
+ Run Keyword If '${host}' != '${EMPTY}' and ${host_exists} == ${FALSE}
+ ... Set to Dictionary ${connection_args} host ${host}
+ Run Keyword If '${alias}' != 'None' and ${alias_exists} == ${FALSE}
+ ... Set to Dictionary ${connection_args} alias ${alias}
+
+ @{open_connections}= Get Connections
+ # If there are no open connections, open one and return.
+ Run Keyword If '${open_connections}' == '[]'
+ ... Open Connection and Log In &{connection_args}
+ Return From Keyword If '${open_connections}' == '[]'
+
+ # Connect to the alias or host that matches. If both are given, only connect
+ # to a connection that has both.
+ :FOR ${connection} IN @{open_connections}
+ \ Log ${connection}
+ \ ${alias_match}= Evaluate '${alias}' == '${connection.alias}'
+ \ ${host_match}= Evaluate '${host}' == '${connection.host}'
+ \ ${given_alias}= Evaluate '${alias}' != 'None'
+ \ ${no_alias}= Evaluate '${alias}' == 'None'
+ \ ${given_host}= Evaluate '${host}' != '${EMPTY}'
+ \ ${no_host}= Evaluate '${host}' == '${EMPTY}'
+ \ Run Keyword If
+ ... ${given_alias} and ${given_host} and ${alias_match} and ${host_match}
+ ... Run Keywords
+ ... Switch Connection ${alias} AND
+ ... Log to Console Found connection. Switched to ${alias} ${host} AND
+ ... Return From Keyword If ${alias_match} and ${host_match}
+ ... ELSE Run Keyword If
+ ... ${given_alias} and ${no_host} and ${alias_match}
+ ... Run Keywords
+ ... Switch Connection ${alias} AND
+ ... Log to Console Found connection. Switched to: ${alias} AND
+ ... Return From Keyword If ${alias_match}
+ ... ELSE Run Keyword If
+ ... ${given_host} and ${no_alias} and ${host_match}
+ ... Run Keywords
+ ... Switch Connection ${connection.index} AND
+ ... Log to Console Found Connection. Switched to: ${host} AND
+ ... Return From Keyword If ${host_match}
+
+ # If no connections are found, open a connection with the provided args.
+ Log No connection with provided arguments. Opening a connection.
+ Open Connection and Log In &{connection_args}
diff --git a/lib/dvt/obmc_call_points.robot b/lib/dvt/obmc_call_points.robot
new file mode 100644
index 0000000..1d8db7c
--- /dev/null
+++ b/lib/dvt/obmc_call_points.robot
@@ -0,0 +1,36 @@
+*** Settings ***
+Documentation This module contains keywords within tests/obmc_boot_test that
+... are points at which to call plug-ins.
+
+Resource obmc_driver_vars.txt
+
+*** Keywords ***
+Call Point Setup
+ [Documentation] Call any plugins that have a cp_setup program
+ [Teardown] Log to Console **Plugin** end call point: cp_setup${\n}
+
+ Log to Console ${\n}**Plugin** start call point: cp_setup
+
+Call Point Pre Boot
+ [Documentation] Call any plugins that have a cp_pre_boot program
+ [Teardown] Log to Console **Plugin** end call point: cp_pre_boot${\n}
+
+ Log to Console ${\n}**Plugin** start call point: cp_pre_boot
+
+Call Point Post Boot
+ [Documentation] Call any plugins that have a cp_post_boot program
+ [Teardown] Log to Console **Plugin** end call point: cp_post_boot${\n}
+
+ Log to Console ${\n}**Plugin** start call point: cp_post_boot
+
+Call Point FFDC
+ [Documentation] Call any plugins that have a cp_ffdc program
+ [Teardown] Log to Console **Plugin** end call point: cp_ffdc${\n}
+
+ Log to Console ${\n}**Plugin** start call point: cp_ffdc
+
+Call Point Stop Check
+ [Documentation] Call any plugins that have a cp_stop_check program
+ [Teardown] Log to Console **Plugin** end call point: cp_stop_check${\n}
+
+ Log to Console ${\n}**Plugin** start call point: cp_stop_check
diff --git a/lib/dvt/obmc_driver_vars.txt b/lib/dvt/obmc_driver_vars.txt
new file mode 100644
index 0000000..41bc6eb
--- /dev/null
+++ b/lib/dvt/obmc_driver_vars.txt
@@ -0,0 +1,35 @@
+*** Settings ***
+Documentation This file includes all the varaibles used by obmc_boot_test.robot
+
+*** Variables ***
+# Alias of the master connection to the BMC
+${master_alias} master
+
+# The count of the IPL we're currently doing - used in the FOR loop
+${IPL_COUNT} ${0}
+
+# The total number of IPLs we plan on doing
+${IPL_TOTAL} ${3}
+
+# The total number of IPLs that have passed and failed
+${IPL_PASSED} ${0}
+${IPL_FAILED} ${0}
+
+# The status of the last IPL that finished
+${IPL_STATUS} ${EMPTY}
+
+# A list of the last 10 IPLs that have been performed (see Log Last Ten)
+@{LAST_TEN}
+
+# A list of keywords of valid IPLs that can be performed
+@{VALID_POWER_ON} BMC Power On
+@{VALID_POWER_OFF} BMC Power Off
+#@{VALID_ACCYCLE}
+#@{VALID_REBOOT}
+
+# The master list of all IPLs possible, for reference. (Currently not in use).
+@{MASTER_IPL_LIST} BMC Power On BMC Power Off
+
+# The list of available IPLs - Modifying this will limit what IPLs can be done.
+# This list is also used by: Setup Run Table, Log Run Table
+@{AVAIL_IPLS} BMC Power On BMC Power Off
diff --git a/lib/list_utils.robot b/lib/list_utils.robot
new file mode 100644
index 0000000..472294b
--- /dev/null
+++ b/lib/list_utils.robot
@@ -0,0 +1,32 @@
+*** Settings ***
+Documentation This module contains keywords for list manipulation.
+Library Collections
+
+*** Keywords ***
+Intersect Lists
+ [Documentation] Intersects the two lists passed in. Returns a list of
+ ... values common to both lists with no duplicates.
+ [Arguments] ${list1} ${list2}
+
+ # list1 The first list to intersect.
+ # list2 The second list to intersect.
+
+ ${length1}= Get Length ${list1}
+ ${length2}= Get Length ${list2}
+
+ @{intersected_list} Create List
+
+ @{larger_list}= Set Variable If ${length1} >= ${length2} ${list1}
+ ... ${length1} < ${length2} ${list2}
+ @{smaller_list}= Set Variable If ${length1} >= ${length2} ${list2}
+ ... ${length1} < ${length2} ${list1}
+
+ :FOR ${element} IN @{larger_list}
+ \ ${rc}= Run Keyword and Return Status List Should Contain Value ${smaller_list}
+ ... ${element}
+ \ Run Keyword If '${rc}' == 'True' Append to List ${intersected_list}
+ ... ${element}
+
+ @{intersected_list}= Remove Duplicates ${intersected_list}
+
+ [return] @{intersected_list}
diff --git a/tests/obmc_boot_test.robot b/tests/obmc_boot_test.robot
new file mode 100644
index 0000000..b7664bd
--- /dev/null
+++ b/tests/obmc_boot_test.robot
@@ -0,0 +1,186 @@
+*** Settings ***
+Documentation Does random repeated IPLs based on the state of the machine. The
+... number of repetitions is designated by ${IPL_TOTAL}. Keyword names that are
+... listed in @{AVAIL_IPLS} become the selection of possible IPLs for the test.
+
+Resource ../lib/boot/boot_resource_master.robot
+Resource ../lib/dvt/obmc_call_points.robot
+Resource ../lib/dvt/obmc_driver_vars.txt
+Resource ../lib/list_utils.robot
+
+*** Test Cases ***
+Repeated Testing
+ [Documentation] Performs random, repeated IPLs.
+
+ # Call the Main keyword to prevent any dots from appearing in the console
+ # due to top level keywords.
+ Main
+
+*** Keywords ***
+Main
+ Log to Console ${SUITE NAME}
+
+ Do Test Setup
+ Call Point Setup
+
+ Log Doing ${IPL_TOTAL} IPLs console=True
+
+ :FOR ${IPL_COUNT} IN RANGE ${IPL_TOTAL}
+ \ Log ${\n}***Starting IPL ${IPL_COUNT+1} of ${IPL_TOTAL}*** console=True
+ \ Validate Or Open Connection alias=${master_alias}
+ \ ${cur_state}= Get Power State
+ \ ${next_IPL}= Select IPL ${cur_state}
+ \ Call Point Pre Boot
+ \ Log We are doing a ${next_IPL}${\n} console=True
+ \ Update Last Ten ${next_IPL}
+ \ Run Keyword and Continue On Failure Run IPL ${next_IPL}
+ \ Call Point Post Boot
+ \ Run Keyword If '${IPL_STATUS}' == 'PASS'
+ ... Log IPL_SUCCESS: "${next_IPL}" succeeded. console=True
+ ... ELSE Log IPL_FAILED: ${next_IPL} failed. console=True
+ \ Update Run Table Values ${next_IPL}
+ \ Log FFDC Dump requested! console=True
+ \ Log ***Beginning dump of FFDC*** console=True
+ \ Call Point FFDC
+ \ Log Defect Information
+ \ Log Last Ten IPLs
+ \ Log FFDC Files
+ \ Log ***Finished dumping of FFDC*** console=True
+ \ Call Point Stop Check
+ \ Log FFDC Summary
+ \ Log Run Table
+ \ Log ${\n}***Finished IPL ${IPL_COUNT+1} of ${IPL_TOTAL}*** console=True
+
+Do Test Setup
+ [Documentation] Do any setup that needs to be done before running a series
+ ... of IPLs.
+
+ Should Not Be Empty ${AVAIL_IPLS}
+
+ Setup Run Table
+ Log ***Start of status file for ${OPENBMC_HOST}*** console=True
+
+Setup Run Table
+ [Documentation] For each available IPL, create a variable that stores the
+ ... number of passes and fails for each IPL.
+
+ Log to Console Setting up run table.
+
+ :FOR ${ipl} IN @{AVAIL_IPLS}
+ \ Set Global Variable ${${ipl}_PASS} ${0}
+ \ Set Global Variable ${${ipl}_FAIL} ${0}
+
+Select IPL
+ [Documentation] Contains all of the logic for which IPLs can be chosen
+ ... given the inputted state. Returns the chosen IPL.
+ [Arguments] ${cur_state}
+
+ # cur_state The power state of the machine, either zero or one.
+
+ ${ipl}= Run Keyword If ${cur_state} == ${0} Select Power On
+ ... ELSE Run Keyword If ${cur_state} == ${1} Select Power Off
+ ... ELSE Run Keywords Log to Console
+ ... **ERROR** BMC not in state to power on or off: "${cur_state}" AND
+ ... Fatal Error
+
+ [return] ${ipl}
+
+Select Power On
+ [Documentation] Randomly chooses an IPL from the list of Power On IPLs.
+
+ @{power_on_choices}= Intersect Lists ${VALID_POWER_ON} ${AVAIL_IPLS}
+
+ ${length}= Get Length ${power_on_choices}
+
+ # Currently selects the first IPL in the list of options, rather than
+ # selecting randomly.
+ ${chosen}= Set Variable @{power_on_choices}[0]
+
+ [return] ${chosen}
+
+Select Power Off
+ [Documentation] Randomly chooses an IPL from the list of Power Off IPLs.
+
+ @{power_off_choices}= Intersect Lists ${VALID_POWER_OFF} ${AVAIL_IPLS}
+
+ ${length}= Get Length ${power_off_choices}
+
+ # Currently selects the first IPL in the list of options, rather than
+ # selecting randomly.
+ ${chosen}= Set Variable @{power_off_choices}[0]
+
+ [return] ${chosen}
+
+Run IPL
+ [Documentation] Runs the selected IPL and marks the status when complete.
+ [Arguments] ${ipl_keyword}
+ [Teardown] Set Global Variable ${IPL_STATUS} ${KEYWORD STATUS}
+
+ # ipl_keyword The name of the IPL to run, which corresponds to the
+ # keyword to run. (i.e "BMC Power On")
+
+ Run Keyword ${ipl_keyword}
+
+Log Defect Information
+ [Documentation] Logs information needed for a defect. This information
+ ... can also be found within the FFDC gathered.
+
+ Log Copy this data to the defect: console=True
+
+Log Last Ten IPLs
+ [Documentation] Logs the last ten IPLs that were performed with their
+ ... starting time stamp.
+
+ Log ${\n}----------------------------------${\n}Last 10 IPLs${\n}
+ ... console=True
+ :FOR ${ipl} IN @{LAST_TEN}
+ \ Log ${ipl} console=True
+ Log ----------------------------------${\n} console=True
+
+Log FFDC Files
+ [Documentation] Logs the files outputted during FFDC gathering.
+ Log This is where the list of FFDC files would be. console=True
+
+Log FFDC Summary
+ [Documentation] Logs finding from within the FFDC files gathered.
+ Log This is where the FFDC summary would go. console=True
+
+Log Run Table
+ [Documentation] Logs the table of IPLs that have passed and failed based on
+ ... the available IPLs, as well as the total passes and failures.
+
+ Log ${\n}IPL type${space*14}Pass${space*3}Fail console=True
+ Log ================================== console=True
+ :FOR ${ipl} IN @{AVAIL_IPLS}
+ \ ${length}= Get Length ${ipl}
+ \ ${space_num}= Set Variable ${24-${length}}
+ \ Log ${ipl}${space*${space_num}}${${ipl}_PASS}${space*5}${${ipl}_FAIL}
+ ... console=True
+ Log ================================== console=True
+ Log Totals:${space*17}${IPL_PASSED}${space*5}${IPL_FAILED}${\n}
+ ... console=True
+
+Update Run Table Values
+ [Documentation] Updates the table of IPLs that have passed and failed. See
+ ... the "Log Run Table" keyword for more information.
+ [Arguments] ${last_ipl}
+
+ # last_ipl The name of the last IPL that ran (i.e "BMC Power On").
+
+ ${cur_value}= Get Variable Value ${${last_ipl}_${IPL_STATUS}}
+ Set Global Variable ${${last_ipl}_${IPL_STATUS}} ${cur_value+1}
+ ${total_value}= Run Keyword If '${IPL_STATUS}' == 'PASS'
+ ... Get Variable Value ${IPL_PASSED}
+ ... ELSE Get Variable Value ${IPL_FAILED}
+ Run Keyword If '${IPL_STATUS}' == 'PASS'
+ ... Set Global Variable ${IPL_PASSED} ${total_value+1}
+ ... ELSE Set Global Variable ${IPL_FAILED} ${total_value+1}
+
+Update Last Ten
+ [Documentation] Updates the list of last ten IPLs
+ [Arguments] ${last_ipl}
+
+ # last_ipl The name of the last IPL that ran (i.e. "BMC Power On")
+
+ ${time}= Get Time
+ Append to List ${LAST_TEN} ${time} - Doing "${last_ipl}"