3b98a48102
Initial submission of a patch series with code of the robot test suite used for Deployment + Provisioning + Sanity Test. - runner: Staring point of the suite exposing all the different options available on the suite as well as initializing all needed features on the host according to the configuration selected. - README: Instructions to setup the suite and basic usage examples. Change-Id: I6ead335412150fb8d64a6abf7909cf702d0d248c Signed-off-by: Jose Perez Carranza <jose.perez.carranza@intel.com>
375 lines
13 KiB
Python
Executable File
375 lines
13 KiB
Python
Executable File
#!/usr/bin/env python
|
|
# -*- coding: utf-8 -*-
|
|
"""Runner for StarlingX test suite"""
|
|
|
|
from __future__ import print_function
|
|
|
|
import argparse
|
|
import getpass
|
|
import os
|
|
from shutil import copy
|
|
from Config import config
|
|
import sys
|
|
|
|
import robot
|
|
import Utils.common as common
|
|
from Libraries.common import update_config_ini, get_controllers_ip
|
|
|
|
# Global variables
|
|
CURRENT_USER = getpass.getuser()
|
|
SUITE_DIR = os.path.dirname(os.path.abspath(__file__))
|
|
MAIN_SUITE = os.path.join(SUITE_DIR, 'Tests')
|
|
LOG_NAME = 'debug.log'
|
|
|
|
# Set PYHTHONPATH variable
|
|
os.environ["PYTHONPATH"] = SUITE_DIR
|
|
|
|
|
|
def update_general_config_file(configuration, config_type, env, config_file,
|
|
yaml_file):
|
|
"""Update general configuration file with selected options
|
|
|
|
Args:
|
|
- configuration: The configuration to be setup, the possible options
|
|
are:
|
|
1. for simplex configuration
|
|
2. for duplex configuration
|
|
3. for multinode controller storage configuration
|
|
4. for multinode dedicated storage configuration
|
|
- config_type: The type of configuration selected from the command
|
|
line
|
|
- env: The environment selected from the command line
|
|
- config_file: The stx-configuration.ini file to be setup in
|
|
the controller
|
|
"""
|
|
config_path = os.path.join(SUITE_DIR, 'Config', 'config.ini')
|
|
# Get Controller(s) IPs from the stx specific config file
|
|
stx_config_path = os.path.join(SUITE_DIR, 'Config', config_file)
|
|
if env == 'baremetal':
|
|
lab_yaml = ('{}.yaml').format(config_type)
|
|
lab_config = os.path.join(SUITE_DIR, 'baremetal', 'configs', lab_yaml)
|
|
else:
|
|
lab_config = os.path.join(SUITE_DIR, yaml_file)
|
|
|
|
unit_ips = get_controllers_ip(env, stx_config_path, config_type,
|
|
lab_config)
|
|
# Update configuration info
|
|
if env == 'baremetal':
|
|
update_config_ini(config_ini=config_path, KERNEL_OPTION=configuration,
|
|
CONFIGURATION_TYPE=config_type, ENVIRONMENT=env,
|
|
CONFIGURATION_FILE=config_file,
|
|
IP_UNIT_0_ADDRESS=unit_ips['IP_UNIT_0_ADDRESS'],
|
|
IP_UNIT_1_ADDRESS=unit_ips['IP_UNIT_1_ADDRESS'],
|
|
OAM=unit_ips['OAM_IF'],
|
|
MGMT=unit_ips['MGMT_IF'],
|
|
ENV_YAML_FILE=yaml_file)
|
|
else:
|
|
update_config_ini(config_ini=config_path, KERNEL_OPTION=configuration,
|
|
CONFIGURATION_TYPE=config_type, ENVIRONMENT=env,
|
|
CONFIGURATION_FILE=config_file,
|
|
IP_UNIT_0_ADDRESS=unit_ips['IP_UNIT_0_ADDRESS'],
|
|
IP_UNIT_1_ADDRESS=unit_ips['IP_UNIT_1_ADDRESS'],
|
|
ENV_YAML_FILE=yaml_file)
|
|
|
|
if ARGS.update:
|
|
print('''Suite Updated !!!
|
|
Following values are now set on Config/config.ini file
|
|
-----
|
|
KERNEL_OPTION={}
|
|
CONFIGURATION_TYPE={}
|
|
ENVIRONMENT={}
|
|
CONFIGURATION_FILE={}
|
|
IP_UNIT_0_ADDRESS={}
|
|
IP_UNIT_1_ADDRESS={}
|
|
ENV_YAML_FILE={}'''.format(configuration, config_type, env, config_file,
|
|
unit_ips['IP_UNIT_0_ADDRESS'],
|
|
unit_ips['IP_UNIT_1_ADDRESS'],
|
|
yaml_file))
|
|
if env == 'baremetal':
|
|
print('''
|
|
OAM={}
|
|
MGMT={}'''.format(unit_ips['OAM_IF'], unit_ips['MGMT_IF']))
|
|
|
|
|
|
# Only update configuration hence exit
|
|
sys.exit(0)
|
|
|
|
def update_yaml_file(config_opt, env):
|
|
"""Overwrite the yaml file for specific yaml file used
|
|
|
|
This function overwrite the current yaml file into environment folder
|
|
for a specific configuration file from environment/configs.
|
|
|
|
:param config_opt: the argument from the command line given by the user
|
|
:param env: environemnt argument from the command line given by the user
|
|
:return
|
|
- conf_type: the type of configuration selected from the
|
|
command line
|
|
- conf_file: the configuration to be use during config controller
|
|
command in the node
|
|
"""
|
|
|
|
conf_type = ''
|
|
conf_file = ''
|
|
|
|
if config_opt == '1':
|
|
conf_type = 'simplex'
|
|
conf_file = 'stx-simplex.yml'
|
|
elif config_opt == '2':
|
|
conf_type = 'duplex'
|
|
conf_file = 'stx-duplex.yml'
|
|
elif config_opt == '3':
|
|
conf_type = 'multinode_controller_storage'
|
|
conf_file = 'stx-multinode.yml'
|
|
elif config_opt == '4':
|
|
conf_type = 'multinode_dedicated_storage'
|
|
conf_file = 'stx-multinode.yml'
|
|
|
|
# Update yaml file of selected environment
|
|
if env == 'virtual':
|
|
env_dir = 'Qemu'
|
|
env_setup_file = 'qemu_setup.yaml'
|
|
else:
|
|
env_dir = 'baremetal'
|
|
env_setup_file = 'baremetal_setup.yaml'
|
|
|
|
origin = os.path.join(SUITE_DIR, '{}/configs/{}.yaml'
|
|
.format(env_dir, conf_type))
|
|
destination = os.path.join(SUITE_DIR, '{}/{}'
|
|
.format(env_dir, env_setup_file))
|
|
copy(origin, destination)
|
|
|
|
|
|
return {'ctype': conf_type, 'cfile': conf_file,
|
|
'eyaml': '{}/{}'.format(env_dir, env_setup_file,)}
|
|
|
|
|
|
def kernel_option(configuration):
|
|
"""Return the correct kernel option
|
|
|
|
This function return the kernel option to install the correct
|
|
configuration selected by the user
|
|
|
|
:param configuration: the argument from the command line given by the user
|
|
:return:
|
|
- kernel_opt: which is the kernel option for boot the controller-0
|
|
"""
|
|
|
|
kernel_opt = ''
|
|
|
|
if configuration == '1' or configuration == '2':
|
|
kernel_opt = '3'
|
|
elif configuration == '3' or configuration == '4':
|
|
kernel_opt = '1'
|
|
|
|
return kernel_opt
|
|
|
|
|
|
def get_args():
|
|
"""Define and handle arguments with options to run the script
|
|
|
|
Return:
|
|
parser.parse_args(): list arguments as objects assigned
|
|
as attributes of a namespace
|
|
"""
|
|
|
|
description = 'Script used to run sxt-test-suite'
|
|
parser = argparse.ArgumentParser(description=description)
|
|
# optional args
|
|
parser.add_argument(
|
|
'--list-suites', dest='list_suite_name',
|
|
nargs='?', const=os.path.basename(MAIN_SUITE),
|
|
help=(
|
|
'List the suite and sub-suites including test cases of the '
|
|
'specified suite, if no value is given the entire suites tree '
|
|
'is displayed.'))
|
|
# groups args
|
|
group = parser.add_argument_group(
|
|
'Execution Suite', 'One of this arguments is mandatory - Suite(s) to '
|
|
'be run')
|
|
group.add_argument('--run-all', dest='run_all',
|
|
action='store_true', help='Run all available suites')
|
|
group.add_argument('--run-suite', dest='run_suite_name',
|
|
help='Run the specified suite')
|
|
group_configuration = parser.add_argument_group(
|
|
'Execution Environment and Configuration',
|
|
'Environment and Configuration to be run in the host'
|
|
'- This option is only required if `--run-suite` is equal to `Setup`')
|
|
group_configuration.add_argument(
|
|
'--environment', dest='environment', choices=['virtual', 'baremetal'],
|
|
help=('The environment where the suite will run'))
|
|
group_configuration.add_argument(
|
|
'--configuration', dest='configuration', choices=['1', '2', '3', '4'],
|
|
help=(
|
|
'{}: will deploy configurations for the host. '
|
|
'1=simplex, 2=duplex, 3=multinode-controller-storage, 4='
|
|
'multinode-dedicated-storage')
|
|
.format(__file__))
|
|
group_configuration.add_argument(
|
|
'--update-only', dest='update', action='store_true',
|
|
help=('Update execution parameters on the suite.'))
|
|
group_extras = parser.add_argument_group(
|
|
'Execution Extras', 'Extra options to be used on the suite execution.')
|
|
group_extras.add_argument(
|
|
'--include', dest='tags',
|
|
help=(
|
|
'Executes only the test cases with specified tags.'
|
|
'Tags and patterns can also be combined together with `AND`, `OR`,'
|
|
'and `NOT` operators.'
|
|
'Examples: --include foo --include bar* --include foo AND bar*'))
|
|
group_extras.add_argument(
|
|
'--test', dest='tests', nargs='+', default='*',
|
|
help=(
|
|
'Select test cases to run by name. '
|
|
'Name is case and space insensitive. '
|
|
'Test cases should be separated by a blank space, '
|
|
'if the test case has spaces on the name send it beetwen "". '
|
|
'Examples: --test "TEST 1" TEST_2 "Test 3"'))
|
|
|
|
return parser.parse_args()
|
|
|
|
def list_suites_option(suite_to_list):
|
|
"""Display the suite tree including test cases
|
|
|
|
Args:
|
|
suite_to_list: name of the suite to display on stdout
|
|
"""
|
|
|
|
# Get suite details
|
|
suite = common.Suite(suite_to_list, MAIN_SUITE)
|
|
print(
|
|
'''
|
|
Suite is located at: {}
|
|
=== INFORMATION ====
|
|
[S] = Suite
|
|
(T) = Test Case
|
|
====================
|
|
|
|
=== SUITE TREE ====
|
|
'''.format(suite.path))
|
|
|
|
common.list_suites(suite.data, '')
|
|
|
|
def get_config_tag(configuration):
|
|
"""Associate to the configuration selected wit a tag
|
|
|
|
Args:
|
|
configuration: Configuration selected
|
|
Return:
|
|
tag: Tag ssociate to the configuration
|
|
"""
|
|
|
|
tags_dict = {
|
|
'simplex': 'Simplex',
|
|
'duplex': 'Duplex',
|
|
'multinode_controller_storage': 'MN-Local',
|
|
'multinode_dedicated_storage': 'MN-External'
|
|
}
|
|
|
|
return tags_dict.get(configuration)
|
|
|
|
def get_iso_name():
|
|
"""Check real name of the ISO used on the deployment
|
|
|
|
Return:
|
|
real_name: ISO real name
|
|
"""
|
|
|
|
name = config.get('general', 'STX_ISO_FILE')
|
|
# Check if synlink was used instead of updating config file
|
|
try:
|
|
real_name = os.readlink('{}/{}'.format(SUITE_DIR, name))
|
|
except OSError:
|
|
real_name = name
|
|
|
|
return real_name
|
|
|
|
def get_metadata():
|
|
"""Construct default metadata to be displayed on reports
|
|
|
|
Return:
|
|
metadata_list: List with names and values to be added as metadata
|
|
"""
|
|
|
|
metadata_list = []
|
|
system = ('System:{}'.format(config.get('general', 'CONFIGURATION_TYPE')))
|
|
iso = ('ISO:{}'.format(get_iso_name()))
|
|
metadata_list.extend([system, iso])
|
|
|
|
return metadata_list
|
|
|
|
def run_suite_option(suite_name):
|
|
"""Run Specified Test Suite and creates the results structure
|
|
|
|
Args:
|
|
- suite_name: name of the suite that will be executed
|
|
"""
|
|
|
|
# Get suite details
|
|
suite = common.Suite(suite_name, MAIN_SUITE)
|
|
# Create results directory if does not exist
|
|
results_dir = common.check_results_dir(SUITE_DIR)
|
|
# Create output directory to store execution results
|
|
output_dir = common.create_output_dir(results_dir, suite.name)
|
|
# Create a link pointing to the latest run
|
|
common.link_latest_run(SUITE_DIR, output_dir)
|
|
# Updating config.ini LOG_PATH variable with output_dir
|
|
config_path = os.path.join(SUITE_DIR, 'Config', 'config.ini')
|
|
update_config_ini(config_ini=config_path, LOG_PATH=output_dir)
|
|
# Get configuration and environent from general config file
|
|
config_type = config.get('general', 'CONFIGURATION_TYPE')
|
|
env = config.get('general', 'ENVIRONMENT')
|
|
env_yaml = config.get('general', 'ENV_YAML_FILE')
|
|
# Check configuration and add it as default to the tags
|
|
default_tag = get_config_tag(config_type)
|
|
# Select tags to be used, empty if not set to execute all
|
|
include_tags = ('{0}AND{1}'.format(default_tag, ARGS.tags)
|
|
if ARGS.tags else default_tag)
|
|
if ARGS.run_suite_name == 'Setup':
|
|
include_tags = ('{0}AND{1}'.format(include_tags, ARGS.environment))
|
|
metadata_list = get_metadata()
|
|
# Run sxt-test-suite using robot framework
|
|
return robot.run(suite.path, outputdir=output_dir, debugfile=LOG_NAME,
|
|
test=ARGS.tests,
|
|
variable=['CONFIGURATION_TYPE :{}'.format(default_tag),
|
|
'ENVIRONMENT :{}'.format(env),
|
|
'ENV_YAML :{}'.format(env_yaml)],
|
|
include=include_tags, tagstatinclude=include_tags,
|
|
metadata=metadata_list)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
if CURRENT_USER == 'root':
|
|
raise RuntimeError('DO NOT RUN AS ROOT')
|
|
# Validate if script is called with at least one argument
|
|
# Get args variables
|
|
ARGS = get_args()
|
|
|
|
if not (ARGS.run_suite_name or ARGS.run_all or ARGS.list_suite_name):
|
|
sys.exit('Execution Suite could not be empty')
|
|
|
|
env_configuration = (
|
|
False if not (ARGS.environment and ARGS.configuration) else True)
|
|
|
|
if ARGS.run_suite_name == 'Setup':
|
|
if not env_configuration:
|
|
sys.exit('Execution Environment arguments are required')
|
|
else:
|
|
config_dict = update_yaml_file(ARGS.configuration,
|
|
ARGS.environment)
|
|
configuration_type = config_dict['ctype']
|
|
configuration_file = config_dict['cfile']
|
|
environment_yaml = config_dict['eyaml']
|
|
# Update configuration file with values selected from command line
|
|
update_general_config_file(kernel_option(ARGS.configuration),
|
|
configuration_type, ARGS.environment,
|
|
configuration_file, environment_yaml)
|
|
|
|
# Check options selected
|
|
if ARGS.list_suite_name:
|
|
list_suites_option(ARGS.list_suite_name)
|
|
elif ARGS.run_all:
|
|
sys.exit(run_suite_option(ARGS.run_suite_name))
|
|
elif ARGS.run_suite_name:
|
|
sys.exit(run_suite_option(ARGS.run_suite_name))
|