new-features (#5)

* refactoring and rework: runner now has setups / tests / cleanups as lists
* add nextcloud runner
* add email testing prototype with imap fixture
* add dependency resolution (sort env files in input so that test order is correct)

Reviewed-on: local-it-infrastructure/e2e_tests#5
Co-authored-by: Daniel <d.brummerloh@gmail.com>
Co-committed-by: Daniel <d.brummerloh@gmail.com>
This commit is contained in:
Daniel 2023-12-04 12:46:30 +01:00 committed by dan
parent 2e33f8f014
commit d3dc0f942a
32 changed files with 573 additions and 247 deletions

View file

@ -5,21 +5,24 @@ from dotenv import dotenv_values
from loguru import logger
from src.dirmanager import DirManager
from src.env_file_helper import DependencyRule, EnvFile, sort_env_files_by_rule
from src.html_helper import merge_html_files
from src.runner import Runner
from src.tests_authentik.runner_authentik import RunnerAuthentik
from src.tests_nextcloud.runner_nextcloud import RunnerNextcloud
from src.tests_wordpress.runner_wordpress import RunnerWordpress
from src.utils import rmtree
# Register all runners here. Each .env file with TYPE=authentik will be ran with RunnerAuthentik
# Register all runners here. Each .env file with TYPE=authentik will be run with RunnerAuthentik
RUNNER_DICT: dict[str, type[Runner]] = {
"authentik": RunnerAuthentik,
"wordpress": RunnerWordpress,
"nextcloud": RunnerNextcloud,
}
class Coordinator:
def __init__(self, env_paths_list: list[Path], output_dir: Path, session_id: str):
def __init__(self, env_paths_list: list[Path], output_dir: Path, session_id: str) -> None:
out_string = "".join([e.name + "\n" for e in env_paths_list])
out_string += f"output_dir = {output_dir}\n"
out_string += f"session_id = {session_id}"
@ -29,47 +32,67 @@ class Coordinator:
self.output_dir = output_dir
self.session_id = session_id
self.env_paths: dict[str, Path] = dict()
self.env_configs: dict[str, dict[str, str]] = dict() # todo: needed?
self._parse_env_files(env_paths_list)
# parse env files
self.env_files: list[EnvFile] = self._getn_env_files_list(env_paths_list)
self.dependency_rules: list[DependencyRule] = self._get_dependency_rules(self.env_files)
def _parse_env_files(self, env_paths: list[Path]):
@staticmethod
def _getn_env_files_list(env_paths: list[Path]) -> list[EnvFile]:
"""Returns a list of EnvFile objects created from the given env files"""
env_files: list[EnvFile] = []
for env_path in env_paths:
assert env_path.is_file(), f"the env file {env_path} does not exist"
config: dict[str, str] = dotenv_values(env_path) # type: ignore
assert "TYPE" in config, f"the env file {env_path} does not specify the required TYPE key."
env_type = config["TYPE"]
self.env_paths[env_type] = env_path
self.env_configs[env_type] = config # todo: needed?
env_files.append(EnvFile(env_path=env_path, config=config, env_type=env_type))
return env_files
def setup_test(self):
@staticmethod
def _get_dependency_rules(env_files: list[EnvFile]) -> list[DependencyRule]:
dependency_rules: list[DependencyRule] = []
for env_file in env_files:
child_runner_class = RUNNER_DICT[env_file.env_type]
for dependency in child_runner_class.dependencies:
dependency_rule = DependencyRule(child=child_runner_class.name, dependency=dependency.name)
dependency_rules.append(dependency_rule)
return dependency_rules
def setup_test(self) -> None:
logger.info("calling setup_test()")
self.DIR.create_all_dirs()
self._copy_env_files()
def _copy_env_files(self):
"""Copies all env filesto STATES/env_files. Files will be renamed to their own TYPE value."""
def _copy_env_files(self) -> None:
"""Copies all env files to STATES/env_files. Files will be renamed to their own TYPE value."""
env_files_dir = self.DIR.STATES / "env_files"
env_files_dir.mkdir(exist_ok=True)
for type_key, env_path in self.env_paths.items():
shutil.copy(env_path, env_files_dir / type_key)
for env_file in self.env_files:
shutil.copy(env_file.env_path, env_files_dir / env_file.env_type)
def run_test(self):
def run_test(self) -> None:
logger.info("calling run_test()")
self.runners: list[Runner] = self._load_runners(self.env_paths.values())
self.runners: list[Runner] = self._load_runners(self.env_files)
for runner in self.runners:
runner.run_setups()
for runner in self.runners:
runner.run_tests()
for runner in self.runners:
runner.run_cleanups()
logger.info("run_test() finished")
def _load_runners(self, env_files: list[Path]) -> list[Runner]:
def _load_runners(self, env_files: list[EnvFile]) -> list[Runner]:
"""Creates an instance of the correct Runner class for each given env file"""
runners = []
for env_file in env_files:
config: dict[str, str] = dotenv_values(env_file) # type: ignore
RunnerClass = RUNNER_DICT[config["TYPE"]]
runners.append(RunnerClass(dotenv_path=env_file, output_dir=self.output_dir, session_id=self.session_id))
RunnerClass = RUNNER_DICT[env_file.config["TYPE"]]
runners.append(
RunnerClass(dotenv_path=env_file.env_path, output_dir=self.output_dir, session_id=self.session_id)
)
return runners
def combine_html(self):
def combine_html(self) -> None:
"""combines all generated pytest html reports into one"""
in_path = str(self.DIR.RECORDS / "html")
out_path = str(self.DIR.RECORDS / "full-report.html")
title = "combined.html"