Newer
Older
L. Bower
committed
from unittest import TestSuite, TestLoader, TestCase, TestResult
from HTMLTestRunner import HTMLTestRunner
from ews.coordinator.processor_base import ProcessorBase
from ews.coordinator.utils import processor_utils
EMAIL_CRED_PATH: str = "../../test_data/test_deployment/envs/Cred_gmail.json"
LOGGING_CONFIG_PATH: str = "../../test_data/test_deployment/envs/test_log_config.json"
DEFAULT_SYS_CONFIG_FILE_PATH: str = "../../test_data/test_deployment/regions/EastAfrica/resources/configs/coordinator/sys_config_EastAfrica_fc_live.json"
DEFAULT_DEPO_CONFIG_FILE_PATH: str = "../../test_data/test_deployment/regions/EastAfrica/resources/configs/coordinator/depo_config_EastAfrica_fc_live.json"
DEFAULT_ENV_SUIT_CONFIG_FILE_PATH: str = "../../test_data/test_deployment/regions/EastAfrica/resources/configs/coordinator/env_suit_config_EastAfrica_fc_live.json"
DEFAULT_EPI_CONFIG_FILE_PATH: str = "../../test_data/test_deployment/regions/EastAfrica/resources/configs/coordinator/epi_config_EastAfrica_fc_live.json"
DEFAULT_SURVEY_CONFIG_FILE_PATH: str = "../../test_data/test_deployment/regions/EastAfrica/resources/configs/coordinator/survey_config_EastAfrica_fc_live.json"
DEFAULT_ADVISORY_CONFIG_FILE_PATH: str = "../../test_data/test_deployment/regions/EastAfrica/resources/configs/coordinator/advisory_config_EastAfrica_fc_live.json"
L. Bower
committed
TEST_WORKSPACE_PATH: str = "../../test_data/test_deployment/regions/EastAfrica/workspace/"
"""
The RUN_SYS_CONFIG_FILE_PATH and RUN_CONFIG_FILE_PATH variables are used to store the file paths of the json configs
that are written in the job dir for a specific test run. They are used by partial and full integration tests.
"""
RUN_SYS_CONFIG_FILE_PATH: str = None
RUN_CONFIG_FILE_PATH: str = None
L. Bower
committed
TEST_ASSETS_PATH: str = "../../test_data/test_deployment/regions/EastAfrica/resources/assets/coordinator/"
L. Bower
committed
EXAMPLE_SURVEY_FILE_PATH: str = TEST_ASSETS_PATH + "example_survey_run.zip"
EXAMPLE_DEPO_FILE_PATH: str = TEST_ASSETS_PATH + "example_depo_run.zip"
EXAMPLE_ENV_SUIT_FILE_PATH: str = TEST_ASSETS_PATH + "example_env_suit_run.zip"
'''
The TEST_OUT_PATH root dir is set in the partial integration tests in the 'write_temp_run_config_files' method
e.g.:
TestAdvisory.write_temp_run_config_files
For full integration tests, the out dir is passed in as a command line arg and is set in:
IntegrationTestUtils.run_full_integration_test_pipeline
'''
'''
The TEST_START_DATE and TEST_JOB_DIR is set in the partial integration tests in the 'set_expected_values' method
e.g.:
TestAdvisory.set_expected_values
For Full integration tests, the date and out dir are passed in as a command line arg and is set in:
IntegrationTestUtils.run_full_integration_test_pipeline
'''
TEST_START_DATE: str = None
TEST_JOB_DIR: str = None
L. Bower
committed
@staticmethod
def check_resources_exist():
"""
do a single check for the email cred file, which will raise an error suggesting that the user may not have set
their pythonpath correctly
"""
emailcred_exists = os.path.exists(IntegrationTestUtils.EMAIL_CRED_PATH)
if not emailcred_exists:
raise FileNotFoundError(f"email cred file {IntegrationTestUtils.EMAIL_CRED_PATH} not found - have you set "
f"the working directory to the same directory as the tests you are running?"
f" (tests use a path relative to the test directory)")
@staticmethod
def build_arg_parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser()
parser.add_argument('--config', required = True)
parser.add_argument('--outdir', required = True)
parser.add_argument('--email_cred', required = True)
parser.add_argument('--test_report_dir', required = False)
# parser.add_argument('--run_date_type', required = False)
parser.add_argument('--custom_run_date', required = False)
parser.add_argument('--custom_dir_prefix', required = False, help = "prefix for the test dir, a sensible value will be set as default")
parser.add_argument('unittest_args', nargs='*')
return parser
@staticmethod
def generate_output_path(filename_prefix: str) -> str:
# if an environment variable "TEST_OUTDIR" is set, use that as the output path
if os.getenv("TEST_OUTDIR"):
result = os.getenv("TEST_OUTDIR") + filename_prefix + "/"
else:
result = IntegrationTestUtils.TEST_WORKSPACE_PATH + filename_prefix + "/"
return result
def run_full_integration_test_pipeline(test_case: [TestCase],
L. Bower
committed
processor_dir: str) -> bool:
"""
Runs the full integration tests on the production server GitlabRunner. The full integration tests are run on
a GitlabRunner that runs on the production server, and mounts the local file system to use the production
configuration files.
:param test_case:
:param test_prefix:
:param processor_dir:
:return:
"""
_parser = IntegrationTestUtils.build_arg_parser()
_args = _parser.parse_args()
_sys_config_file: str = _args.sys_config
_run_config_file: str = _args.config
_outdir: str = _args.outdir
_email_cred_path: str = _args.email_cred
_test_report_dir: str = _args.test_report_dir
# _run_date_type: str = _args.run_date_type
_custom_run_date: str = _args.custom_run_date
_custom_dir_prefix: str = _args.custom_dir_prefix
"""
We store paths to the production run json files here, these are then read into a dict, output paths are
overridden to point to the test dir, then re-written as the json config in the test dir. When the test-specific
files are written, the paths are overridden to point to the test dir files.
"""
IntegrationTestUtils.RUN_SYS_CONFIG_FILE_PATH = _sys_config_file
IntegrationTestUtils.RUN_CONFIG_FILE_PATH = _run_config_file
if _custom_dir_prefix is None:
nowstring: str = IntegrationTestUtils.get_now_string()
prefix: str = f"temp_{test_prefix}_" + nowstring
# prefix: str = f"temp_{test_prefix}"
else:
prefix = _custom_dir_prefix
IntegrationTestUtils.TEST_OUT_PATH = _outdir + prefix + os.sep
IntegrationTestUtils.EMAIL_CRED_PATH = _email_cred_path
IntegrationTestUtils.TEST_START_DATE = _custom_run_date
IntegrationTestUtils.TEST_JOB_DIR = os.path.join(IntegrationTestUtils.TEST_OUT_PATH,
tests: TestSuite = TestLoader().loadTestsFromTestCase(test_case)
the HTMLTestRunner will create the directory if it does not exist, we are putting the output into the
_test_report_dir, which defaults to TEST_OUT_PATH, which is the top-level test directory for this run, not the
TEST_JOB_DIR, which is the dir for the pipeline being tested. We need to make sure the TEST_JOB_DIR does not
exist before the test is instantiated, to ensure the initial pipeline run takes place. Setting the test report
to go into the TEST_JOB_DIR will create the parent dir and stop the pipeline from running
runner = HTMLTestRunner(output = _test_report_dir, log = True, report_name = f"{test_prefix}_results")
result: TestResult = runner.run(tests)
return result.wasSuccessful()
L. Bower
committed
@staticmethod
def load_json_file(file: str) -> dict:
with open(file) as config_file:
config: dict = json.load(config_file)
return config
@staticmethod
def write_json_file(values: dict, file: str):
with open(file, 'w') as file:
json.dump(values, file, indent = 4)
@staticmethod
def get_now_string() -> str:
L. Bower
committed
nowstring: str = datetime.datetime.today().strftime('%Y-%m-%d_%H%M%S')
@staticmethod
def unpack_zip(zip_to_unpack: str, out_file: str):
with ZipFile(zip_to_unpack) as zf: # open the zip file
for target_file in zf.namelist(): # check if the file exists in the archive
zf.extract(target_file, out_file)
@staticmethod
def count_files_in_wildcard(wildcard: str) -> int:
results = glob.glob(wildcard)
return len(results)
def check_file_not_empty(file_path: str) -> bool:
@staticmethod
def check_file_exists(file_path: str) -> bool:
return os.path.isfile(file_path)
@staticmethod
def check_wildcard_exists_and_not_empty(wildcard: str) -> bool:
"""
requires at least one file matching the wildcard to exist and not be empty
"""
result = False
files: List[str] = glob.glob(wildcard)
for file in files:
result = IntegrationTestUtils.check_file_not_empty(file)
if result is False:
break
return result
@staticmethod
def check_file_exists_and_not_empty(file_path: str) -> bool:
file_exists = IntegrationTestUtils.check_file_exists(file_path)
file_not_empty = IntegrationTestUtils.check_file_not_empty(file_path)
return file_exists and file_not_empty
@staticmethod
def run_partial_integration_test_pipeline(component: str,
shortname: str,
**kwargs):
"""
Runs the "run_Process" function in Processor.py with the given arguments for the partial integration tests.
The full integration pipeline is run in the "run_full_integration_test_pipeline" function.
:param shortname:
:param start_date:
:param kwargs:
:return:
"""
args_dict: dict = {}
sys_config_path = IntegrationTestUtils.RUN_SYS_CONFIG_FILE_PATH
L. Bower
committed
config_path = IntegrationTestUtils.RUN_CONFIG_FILE_PATH
# note, possible to override these values in the kwargs loop below
args_dict['live'] = False
args_dict['noupload'] = True
args_dict['start_date'] = start_date
args_dict['component'] = component
args_dict['short_name'] = shortname
args_dict['log_level'] = 'info'
for key, value in kwargs.items():
args_dict[key] = value
# need EMAIL_CRED in the environment before we run a Processor
os.environ["EMAIL_CRED"] = IntegrationTestUtils.EMAIL_CRED_PATH
try:
config: dict = processor.build_config(args_dict, config_path, sys_config_path)
job_path: str = processor.generate_job_directory_path(config)
processor.prepare_job_directory(job_path)
L. Bower
committed
processor_utils.setup_logging(job_path, config) # logging set up after the job dir is prepared
processor.run_process(config)
# we will eventually want to throw these to the calling class to be dealt with
pass
@staticmethod
def run_external_pipeline(component: str,
config_path: str = IntegrationTestUtils.RUN_CONFIG_FILE_PATH
sys_config_path: str = IntegrationTestUtils.RUN_SYS_CONFIG_FILE_PATH
# note, possible to override these values in the additional_args loop below
args_dict['live'] = False
args_dict['noupload'] = True
args_dict['start_date'] = start_date
args_dict['component'] = component
args_dict['log_level'] = 'info'
args_dict['clearup'] = True
for key, value in additional_args.items():
# need EMAIL_CRED in the environment before we run a Processor
os.environ["EMAIL_CRED"] = IntegrationTestUtils.EMAIL_CRED_PATH
config: dict = processor.build_config(args_dict, config_path, sys_config_path)
job_path: str = processor.generate_job_directory_path(config)
processor.prepare_job_directory(job_path)
processor_utils.setup_logging(job_path, config) # logging set up after the job dir is prepared
processor.run_process(config)
# allow this error to be thrown to the calling class - is dealt with by the test framework
@staticmethod
def get_day_before_as_string(input_date_string: str) -> str:
date_format = "%Y%m%d"
input_date: datetime = datetime.datetime.strptime(input_date_string, date_format)
yesterday_date = input_date - datetime.timedelta(days = 1)
yesterday_string = yesterday_date.strftime(date_format)
return yesterday_string
L. Bower
committed
@staticmethod
def count_tokens_in_file(file_path: str, token_to_find: str) -> int:
fig_not_found_count = 0
with open(file_path, 'r') as log_file:
lines = log_file.readlines()
for line in lines:
if token_to_find in line:
fig_not_found_count += 1
return fig_not_found_count