Tests for Downloading Image onto the BMC
- Upload images via REST
- Upload images via TFTP
Resolves openbmc/openbmc-test-automation#510
Change-Id: Id55f12d0d0354024c57ca929953b408e70876b40
Signed-off-by: Saqib Khan <khansa@us.ibm.com>
diff --git a/data/variables.py b/data/variables.py
index 8d86e6f..759bc6c 100644
--- a/data/variables.py
+++ b/data/variables.py
@@ -43,6 +43,9 @@
# Software manager version
SOFTWARE_VERSION_URI = '/xyz/openbmc_project/software/'
ACTIVE = 'xyz.openbmc_project.Software.Activation.Activations.Active'
+READY = 'xyz.openbmc_project.Software.Activation.Activations.Ready'
+INVALID = 'xyz.openbmc_project.Software.Activation.Activations.Invalid'
+ACTIVATING = 'xyz.openbmc_project.Software.Activation.Activations.Activating'
# Inventory URI
HOST_INVENTORY_URI = '/xyz/openbmc_project/inventory/'
diff --git a/extended/test_uploadimage.py b/extended/test_uploadimage.py
new file mode 100644
index 0000000..44a0963
--- /dev/null
+++ b/extended/test_uploadimage.py
@@ -0,0 +1,173 @@
+#!/usr/bin/env python
+
+r"""
+This module is the python counterpart to test_uploadimage.robot.
+"""
+
+import os
+import sys
+import re
+import string
+import tarfile
+import time
+
+robot_pgm_dir_path = os.path.dirname(__file__) + os.sep
+repo_lib_path = re.sub('/extended/', '/lib', robot_pgm_dir_path)
+repo_data_path = re.sub('/extended/', '/data', robot_pgm_dir_path)
+sys.path.append(repo_lib_path)
+sys.path.append(repo_data_path)
+
+import gen_robot_keyword as grk
+import gen_print as gp
+import variables as var
+from robot.libraries.BuiltIn import BuiltIn
+
+
+###############################################################################
+def get_latest_file(dir_path):
+
+ r"""
+ Get the path to the latest uploaded file.
+
+ Description of argument(s):
+ dir_path Path to the dir from which the name of the last
+ updated file or folder will be returned to the
+ calling function.
+ """
+
+ grk.run_key_u("Open Connection And Log In")
+ status, ret_values =\
+ grk.run_key("Execute Command On BMC cd " + dir_path
+ + "; stat -c '%Y %n' * | sort -k1,1nr | head -n 1", ignore=1)
+ return ret_values.split(" ")[-1]
+
+###############################################################################
+
+
+###############################################################################
+def get_version_tar(tar_file_path):
+
+ r"""
+ Read the image version from the MANIFEST inside the tarball.
+
+ Description of argument(s):
+ tar_file_path The path to a tar file that holds the image
+ version inside the MANIFEST.
+ """
+
+ tar = tarfile.open(tar_file_path)
+ for member in tar.getmembers():
+ f=tar.extractfile(member)
+ content=f.read()
+ if "version=" in content:
+ content = content.split("\n")
+ content = [x for x in content if "version=" in x]
+ version = content[0].split("=")[-1]
+ break
+ tar.close()
+ return version
+
+###############################################################################
+
+
+###############################################################################
+def get_image_version(file_path):
+
+ r"""
+ Read the file for a version object.
+
+ Description of argument(s):
+ file_path The path to a file that holds the image version.
+ """
+
+ grk.run_key_u("Open Connection And Log In")
+ status, ret_values =\
+ grk.run_key("Execute Command On BMC cat "
+ + file_path + " | grep \"version=\"")
+ return ret_values.split("=")[-1]
+
+###############################################################################
+
+
+###############################################################################
+def get_image_purpose(file_path):
+
+ r"""
+ Read the file for a purpose object.
+
+ Description of argument(s):
+ file_path The path to a file that holds the image purpose.
+ """
+
+ grk.run_key_u("Open Connection And Log In")
+ status, ret_values =\
+ grk.run_key("Execute Command On BMC cat "
+ + file_path + " | grep \"purpose=\"")
+ return ret_values.split("=")[-1]
+
+###############################################################################
+
+
+###############################################################################
+def get_image_path(image_version):
+
+ r"""
+ Query the upload image dir for the presence of image matching
+ the version that was read from the MANIFEST before uploading
+ the image. Based on the purpose verify the activation object
+ exists and is either READY or INVALID.
+
+ Description of argument(s):
+ image_version The version of the image that should match one
+ of the images in the upload dir.
+ """
+
+ upload_dir = BuiltIn().get_variable_value("${UPLOAD_DIR_PATH}")
+ grk.run_key_u("Open Connection And Log In")
+ status, image_list =\
+ grk.run_key("Execute Command On BMC ls -d " + upload_dir
+ + "*/")
+
+ image_list = image_list.split("\n")
+ retry = 0
+ while (retry < 10):
+ for i in range(0, len(image_list)):
+ version = get_image_version(image_list[i] + "MANIFEST")
+ if (version == image_version):
+ return image_list[i]
+ time.sleep(10)
+ retry += 1
+
+###############################################################################
+
+
+###############################################################################
+def verify_image_upload():
+
+ r"""
+ Verify the image was uploaded correctly and that it created
+ a valid d-bus object
+ """
+
+ image_version = BuiltIn().get_variable_value("${IMAGE_VERSION}")
+ image_path = get_image_path(image_version)
+ image_version_id = image_path.split("/")[-2]
+
+ grk.run_key_u("Open Connection And Log In")
+ image_purpose = get_image_purpose(image_path + "MANIFEST")
+ if (image_purpose == "bmc" or image_purpose == "host"):
+ uri = var.SOFTWARE_VERSION_URI + "/" + image_version_id
+ status, ret_values =\
+ grk.run_key("Read Attribute " + uri + " Activation")
+
+ if ((ret_values == var.READY) or (ret_values == var.INVALID)
+ or (ret_values == var.ACTIVE)):
+ return True
+ else:
+ gp.print_var(ret_values)
+ return False
+ else:
+ gp.print_var(versionPurpose)
+ return False
+
+###############################################################################
diff --git a/extended/test_uploadimage.robot b/extended/test_uploadimage.robot
new file mode 100644
index 0000000..19dc35a
--- /dev/null
+++ b/extended/test_uploadimage.robot
@@ -0,0 +1,81 @@
+*** Settings ***
+Documentation Test Upload Image
+... Execution Method :
+... python -m robot -v OPENBMC_HOST:<hostname>
+... -v TFTP_SERVER:<TFTP server IP>
+... -v TFTP_FILE_NAME:<filename.tar>
+... -v IMAGE_FILE_PATH:<path/*.tar> test_uploadimage.robot
+
+Resource ../lib/connection_client.robot
+Resource ../lib/rest_client.robot
+Resource ../lib/openbmc_ffdc.robot
+Library Collections
+Library String
+Library OperatingSystem
+Library test_uploadimage.py
+
+Test Teardown Upload Image Teardown
+
+*** Variables ***
+${timeout} 10
+${UPLOAD_DIR_PATH} /tmp/images/
+${QUIET} ${1}
+${IMAGE_VERSION} ${EMPTY}
+
+*** Test Cases ***
+
+Upload Image Via REST
+ [Documentation] Upload an image via REST.
+ [Tags] Upload_Image_Via_REST
+
+ OperatingSystem.File Should Exist ${IMAGE_FILE_PATH}
+ ${IMAGE_VERSION}= Get Version Tar ${IMAGE_FILE_PATH}
+ ${image_data}= OperatingSystem.Get Binary File ${IMAGE_FILE_PATH}
+ Upload Post Request /upload/image data=${image_data}
+ ${ret}= Verify Image Upload
+ Should Be True True == ${ret}
+
+Upload Image Via TFTP
+ [Documentation] Upload an image via TFTP.
+ [Tags] Upload_Image_Via_TFTP
+
+ @{image}= Create List ${TFTP_FILE_NAME} ${TFTP_SERVER}
+ ${data}= Create Dictionary data=@{image}
+ ${resp}= OpenBMC Post Request
+ ... ${SOFTWARE_VERSION_URI}/action/DownloadViaTFTP data=${data}
+ Should Be Equal As Strings ${resp.status_code} ${HTTP_OK}
+ Sleep 1 minute
+ ${upload_file}= Get Latest File ${UPLOAD_DIR_PATH}
+ ${IMAGE_VERSION}= Get Image Version
+ ... ${UPLOAD_DIR_PATH}${upload_file}/MANIFEST
+ ${ret}= Verify Image Upload
+ Should Be True True == ${ret}
+
+*** Keywords ***
+
+Upload Image Teardown
+ [Documentation] Log FFDC if test suite fails and collect SOL log for
+ ... debugging purposes.
+
+ Close All Connections
+ FFDC On Test Case Fail
+
+Upload Post Request
+ [Arguments] ${uri} ${timeout}=10 ${quiet}=${QUIET} &{kwargs}
+
+ # Description of arguments:
+ # uri URI for uploading image via REST.
+ # timeout Time allocated for the REST command to return status.
+ # quiet If enabled turns off logging to console.
+ # kwargs A dictionary that maps each keyword to a value.
+
+ Initialize OpenBMC ${timeout} quiet=${quiet}
+ ${base_uri}= Catenate SEPARATOR= ${DBUS_PREFIX} ${uri}
+ ${headers}= Create Dictionary Content-Type=application/octet-stream
+ ... Accept=application/octet-stream
+ Set To Dictionary ${kwargs} headers ${headers}
+ Run Keyword If '${quiet}' == '${0}' Log Request method=Post
+ ... base_uri=${base_uri} args=&{kwargs}
+ ${ret}= Post Request openbmc ${base_uri} &{kwargs} timeout=${timeout}
+ Run Keyword If '${quiet}' == '${0}' Log Response ${ret}
+ Should Be Equal As Strings ${ret.status_code} ${HTTP_OK}
diff --git a/lib/resource.txt b/lib/resource.txt
index 247d251..d3c3cb1 100755
--- a/lib/resource.txt
+++ b/lib/resource.txt
@@ -47,6 +47,11 @@
# BMC debug tarball parameter
${DEBUG_TARBALL_PATH} ${EMPTY}
+# Upload Image parameters
+${TFTP_SERVER} ${EMPTY}
+${TFTP_FILE_NAME} ${EMPTY}
+${IMAGE_FILE_PATH} ${EMPTY}
+
*** Keywords ***
Get Inventory Schema
[Arguments] ${machine}
diff --git a/tools/generate_argumentfile.sh b/tools/generate_argumentfile.sh
index 1a114a3..0529469 100755
--- a/tools/generate_argumentfile.sh
+++ b/tools/generate_argumentfile.sh
@@ -22,3 +22,6 @@
echo "--variable OS_USERNAME:$OS_USERNAME" >> $ARG_FILE
echo "--variable OS_PASSWORD:$OS_PASSWORD" >> $ARG_FILE
echo "--variable DEBUG_TARBALL_PATH:$DEBUG_TARBALL_PATH" >> $ARG_FILE
+echo "--variable TFTP_SERVER:$TFTP_SERVER" >> $ARG_FILE
+echo "--variable TFTP_FILE_NAME:$TFTP_FILE_NAME" >> $ARG_FILE
+echo "--variable IMAGE_FILE_PATH:$IMAGE_FILE_PATH" >> $ARG_FILE