629 lines
25 KiB
Python
629 lines
25 KiB
Python
import subprocess
|
|
from typing import List, Dict, Optional
|
|
from jinja2 import Environment, FileSystemLoader
|
|
from dataclasses import dataclass, field
|
|
import shutil
|
|
from pathlib import Path
|
|
from paths import PRECICE_REL_OUTPUT_DIR, PRECICE_TOOLS_DIR, PRECICE_REL_REFERENCE_DIR, PRECICE_TESTS_DIR, PRECICE_TUTORIAL_DIR
|
|
|
|
from metadata_parser.metdata import Tutorial, CaseCombination, Case, ReferenceResult
|
|
from .SystemtestArguments import SystemtestArguments
|
|
|
|
from datetime import datetime
|
|
import tarfile
|
|
import time
|
|
|
|
import unicodedata
|
|
import re
|
|
import logging
|
|
import os
|
|
|
|
|
|
GLOBAL_TIMEOUT = 600
|
|
SHORT_TIMEOUT = 10
|
|
|
|
|
|
def slugify(value, allow_unicode=False):
|
|
"""
|
|
Taken from https://github.com/django/django/blob/master/django/utils/text.py
|
|
Convert to ASCII if 'allow_unicode' is False. Convert spaces or repeated
|
|
dashes to single dashes. Remove characters that aren't alphanumerics,
|
|
underscores, or hyphens. Convert to lowercase. Also strip leading and
|
|
trailing whitespace, dashes, and underscores.
|
|
"""
|
|
value = str(value)
|
|
if allow_unicode:
|
|
value = unicodedata.normalize('NFKC', value)
|
|
else:
|
|
value = unicodedata.normalize('NFKD', value).encode(
|
|
'ascii', 'ignore').decode('ascii')
|
|
value = re.sub(r'[^\w\s-]', '', value.lower())
|
|
return re.sub(r'[-\s]+', '-', value).strip('-_')
|
|
|
|
|
|
class Systemtest:
|
|
pass
|
|
|
|
|
|
@dataclass
|
|
class DockerComposeResult:
|
|
exit_code: int
|
|
stdout_data: List[str]
|
|
stderr_data: List[str]
|
|
systemtest: Systemtest
|
|
runtime: float # in seconds
|
|
|
|
|
|
@dataclass
|
|
class FieldCompareResult:
|
|
exit_code: int
|
|
stdout_data: List[str]
|
|
stderr_data: List[str]
|
|
systemtest: Systemtest
|
|
runtime: float # in seconds
|
|
|
|
|
|
@dataclass
|
|
class SystemtestResult:
|
|
success: bool
|
|
stdout_data: List[str]
|
|
stderr_data: List[str]
|
|
systemtest: Systemtest
|
|
build_time: float # in seconds
|
|
solver_time: float # in seconds
|
|
fieldcompare_time: float # in seconds
|
|
|
|
|
|
def display_systemtestresults_as_table(results: List[SystemtestResult]):
|
|
"""
|
|
Prints the result in a nice tabluated way to get an easy overview
|
|
"""
|
|
def _get_length_of_name(results: List[SystemtestResult]) -> int:
|
|
return max(len(str(result.systemtest)) for result in results)
|
|
|
|
max_name_length = _get_length_of_name(results)
|
|
|
|
header = f"| {'systemtest':<{max_name_length + 2}} | {'success':^7} | {'building time [s]':^17} | {'solver time [s]':^15} | {'fieldcompare time [s]':^21} |"
|
|
separator = "+-" + "-" * (max_name_length + 2) + \
|
|
"-+---------+-------------------+-----------------+-----------------------+"
|
|
|
|
print(separator)
|
|
print(header)
|
|
print(separator)
|
|
|
|
for result in results:
|
|
row = f"| {str(result.systemtest):<{max_name_length + 2}} | {result.success:^7} | {result.build_time:^17.2f} | {result.solver_time:^15.2f} | {result.fieldcompare_time:^21.2f} |"
|
|
print(row)
|
|
print(separator)
|
|
|
|
|
|
@dataclass
|
|
class Systemtest:
|
|
"""
|
|
Represents a system test by specifing the cases and the corresponding Tutorial
|
|
"""
|
|
|
|
tutorial: Tutorial
|
|
arguments: SystemtestArguments
|
|
case_combination: CaseCombination
|
|
reference_result: ReferenceResult
|
|
params_to_use: Dict[str, str] = field(init=False)
|
|
env: Dict[str, str] = field(init=False)
|
|
|
|
def __eq__(self, other) -> bool:
|
|
if isinstance(other, Systemtest):
|
|
return (
|
|
self.tutorial == other.tutorial) and (
|
|
self.arguments == other.arguments) and (
|
|
self.case_combination == other.case_combination)
|
|
return False
|
|
|
|
def __hash__(self) -> int:
|
|
return hash(f"{self.tutorial,self.arguments,self.case_combination}")
|
|
|
|
def __post_init__(self):
|
|
self.__init_args_to_use()
|
|
self.env = {}
|
|
|
|
def __init_args_to_use(self):
|
|
"""
|
|
Checks if all required parameters for the realisation of the cases are supplied in the cmdline arguments.
|
|
If a parameter is missing and it's required, an exception is raised.
|
|
Otherwise, the default value is used if available.
|
|
|
|
In the end it populates the args_to_use dict
|
|
|
|
Raises:
|
|
Exception: If a required parameter is missing.
|
|
"""
|
|
self.params_to_use = {}
|
|
needed_parameters = set()
|
|
for case in self.case_combination.cases:
|
|
needed_parameters.update(case.component.parameters)
|
|
|
|
for needed_param in needed_parameters:
|
|
if self.arguments.contains(needed_param.key):
|
|
self.params_to_use[needed_param.key] = self.arguments.get(
|
|
needed_param.key)
|
|
else:
|
|
if needed_param.required:
|
|
raise Exception(
|
|
f"{needed_param} is needed to be given via --params to instantiate the systemtest for {self.tutorial.name}")
|
|
else:
|
|
self.params_to_use[needed_param.key] = needed_param.default
|
|
|
|
def __get_docker_services(self) -> Dict[str, str]:
|
|
"""
|
|
Renders the service templates for each case using the parameters to use.
|
|
|
|
Returns:
|
|
A dictionary of rendered services per case name.
|
|
"""
|
|
try:
|
|
plaform_requested = self.params_to_use.get("PLATFORM")
|
|
except Exception as exc:
|
|
raise KeyError("Please specify a PLATFORM argument") from exc
|
|
|
|
self.dockerfile_context = PRECICE_TESTS_DIR / "dockerfiles" / Path(plaform_requested)
|
|
if not self.dockerfile_context.exists():
|
|
raise ValueError(
|
|
f"The path {self.dockerfile_context.resolve()} resulting from argument PLATFORM={plaform_requested} could not be found in the system")
|
|
|
|
def render_service_template_per_case(case: Case, params_to_use: Dict[str, str]) -> str:
|
|
render_dict = {
|
|
'run_directory': self.run_directory.resolve(),
|
|
'tutorial_folder': self.tutorial_folder,
|
|
'build_arguments': params_to_use,
|
|
'params': params_to_use,
|
|
'case_folder': case.path,
|
|
'run': case.run_cmd,
|
|
'dockerfile_context': self.dockerfile_context,
|
|
}
|
|
jinja_env = Environment(loader=FileSystemLoader(PRECICE_TESTS_DIR))
|
|
template = jinja_env.get_template(case.component.template)
|
|
return template.render(render_dict)
|
|
|
|
rendered_services = {}
|
|
for case in self.case_combination.cases:
|
|
rendered_services[case.name] = render_service_template_per_case(
|
|
case, self.params_to_use)
|
|
return rendered_services
|
|
|
|
def __get_docker_compose_file(self):
|
|
rendered_services = self.__get_docker_services()
|
|
render_dict = {
|
|
'run_directory': self.run_directory.resolve(),
|
|
'tutorial_folder': self.tutorial_folder,
|
|
'tutorial': self.tutorial.path.name,
|
|
'services': rendered_services,
|
|
'build_arguments': self.params_to_use,
|
|
'dockerfile_context': self.dockerfile_context,
|
|
'precice_output_folder': PRECICE_REL_OUTPUT_DIR,
|
|
}
|
|
jinja_env = Environment(loader=FileSystemLoader(PRECICE_TESTS_DIR))
|
|
template = jinja_env.get_template("docker-compose.template.yaml")
|
|
return template.render(render_dict)
|
|
|
|
def __get_field_compare_compose_file(self):
|
|
render_dict = {
|
|
'run_directory': self.run_directory.resolve(),
|
|
'tutorial_folder': self.tutorial_folder,
|
|
'precice_output_folder': PRECICE_REL_OUTPUT_DIR,
|
|
'reference_output_folder': PRECICE_REL_REFERENCE_DIR + "/" + self.reference_result.path.name.replace(".tar.gz", ""),
|
|
}
|
|
jinja_env = Environment(loader=FileSystemLoader(PRECICE_TESTS_DIR))
|
|
template = jinja_env.get_template(
|
|
"docker-compose.field_compare.template.yaml")
|
|
return template.render(render_dict)
|
|
|
|
def _get_git_ref(self, repository: Path, abbrev_ref=False) -> Optional[str]:
|
|
try:
|
|
result = subprocess.run([
|
|
"git",
|
|
"-C", os.fspath(repository.resolve()),
|
|
"rev-parse",
|
|
"--abbrev-ref" if abbrev_ref else
|
|
"HEAD"], stdout=subprocess.PIPE,
|
|
stderr=subprocess.PIPE, text=True, check=True, timeout=60)
|
|
current_ref = result.stdout.strip()
|
|
return current_ref
|
|
except Exception as e:
|
|
raise RuntimeError(f"An error occurred while getting the current Git ref: {e}") from e
|
|
|
|
def _fetch_ref(self, repository: Path, ref: str):
|
|
try:
|
|
result = subprocess.run([
|
|
"git",
|
|
"-C", os.fspath(repository.resolve()),
|
|
"fetch"
|
|
], check=True, timeout=60)
|
|
if result.returncode != 0:
|
|
raise RuntimeError(f"git command returned code {result.returncode}")
|
|
|
|
except Exception as e:
|
|
raise RuntimeError(f"An error occurred while fetching origin '{ref}': {e}")
|
|
|
|
def _checkout_ref_in_subfolder(self, repository: Path, subfolder: Path, ref: str):
|
|
try:
|
|
result = subprocess.run([
|
|
"git",
|
|
"-C", os.fspath(repository.resolve()),
|
|
"checkout", ref,
|
|
"--", os.fspath(subfolder.resolve())
|
|
], check=True, timeout=60)
|
|
if result.returncode != 0:
|
|
raise RuntimeError(f"git command returned code {result.returncode}")
|
|
|
|
except Exception as e:
|
|
raise RuntimeError(f"An error occurred while checking out '{ref}' for folder '{repository}': {e}")
|
|
|
|
def __copy_tutorial_into_directory(self, run_directory: Path):
|
|
"""
|
|
Checks out the requested tutorial ref and copies the entire tutorial into a folder to prepare for running.
|
|
"""
|
|
current_time_string = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
|
self.run_directory = run_directory
|
|
current_ref = self._get_git_ref(PRECICE_TUTORIAL_DIR)
|
|
ref_requested = self.params_to_use.get("TUTORIALS_REF")
|
|
if ref_requested:
|
|
logging.debug(f"Checking out tutorials {ref_requested} before copying")
|
|
self._fetch_ref(PRECICE_TUTORIAL_DIR, ref_requested)
|
|
self._checkout_ref_in_subfolder(PRECICE_TUTORIAL_DIR, self.tutorial.path, ref_requested)
|
|
|
|
self.tutorial_folder = slugify(f'{self.tutorial.path.name}_{self.case_combination.cases}_{current_time_string}')
|
|
destination = run_directory / self.tutorial_folder
|
|
src = self.tutorial.path
|
|
self.system_test_dir = destination
|
|
shutil.copytree(src, destination)
|
|
|
|
if ref_requested:
|
|
with open(destination / "tutorials_ref", 'w') as file:
|
|
file.write(ref_requested)
|
|
self._checkout_ref_in_subfolder(PRECICE_TUTORIAL_DIR, self.tutorial.path, current_ref)
|
|
|
|
def __copy_tools(self, run_directory: Path):
|
|
destination = run_directory / "tools"
|
|
src = PRECICE_TOOLS_DIR
|
|
try:
|
|
shutil.copytree(src, destination)
|
|
except Exception as e:
|
|
logging.debug(f"tools are already copied: {e} ")
|
|
|
|
def __put_gitignore(self, run_directory: Path):
|
|
# Create the .gitignore file with a single asterisk
|
|
gitignore_file = run_directory / ".gitignore"
|
|
with gitignore_file.open("w") as file:
|
|
file.write("*")
|
|
|
|
def __cleanup(self):
|
|
shutil.rmtree(self.run_directory)
|
|
|
|
def __get_uid_gid(self):
|
|
try:
|
|
uid = int(subprocess.check_output(["id", "-u"]).strip())
|
|
gid = int(subprocess.check_output(["id", "-g"]).strip())
|
|
return uid, gid
|
|
except Exception as e:
|
|
logging.error("Error getting group and user id: ", e)
|
|
|
|
def __write_env_file(self):
|
|
with open(self.system_test_dir / ".env", "w") as env_file:
|
|
for key, value in self.env.items():
|
|
env_file.write(f"{key}={value}\n")
|
|
|
|
def __unpack_reference_results(self):
|
|
with tarfile.open(self.reference_result.path) as reference_results_tared:
|
|
# specify which folder to extract to
|
|
reference_results_tared.extractall(self.system_test_dir / PRECICE_REL_REFERENCE_DIR)
|
|
logging.debug(
|
|
f"extracting {self.reference_result.path} into {self.system_test_dir / PRECICE_REL_REFERENCE_DIR}")
|
|
|
|
def _run_field_compare(self):
|
|
"""
|
|
Writes the Docker Compose file to disk, executes docker-compose up, and handles the process output.
|
|
|
|
Args:
|
|
docker_compose_content: The content of the Docker Compose file.
|
|
|
|
Returns:
|
|
A SystemtestResult object containing the state.
|
|
"""
|
|
logging.debug(f"Running fieldcompare for {self}")
|
|
time_start = time.perf_counter()
|
|
self.__unpack_reference_results()
|
|
docker_compose_content = self.__get_field_compare_compose_file()
|
|
stdout_data = []
|
|
stderr_data = []
|
|
|
|
with open(self.system_test_dir / "docker-compose.field_compare.yaml", 'w') as file:
|
|
file.write(docker_compose_content)
|
|
try:
|
|
# Execute docker-compose command
|
|
process = subprocess.Popen(['docker',
|
|
'compose',
|
|
'--file',
|
|
'docker-compose.field_compare.yaml',
|
|
'up',
|
|
'--exit-code-from',
|
|
'field-compare'],
|
|
stdout=subprocess.PIPE,
|
|
stderr=subprocess.PIPE,
|
|
start_new_session=True,
|
|
cwd=self.system_test_dir)
|
|
|
|
try:
|
|
stdout, stderr = process.communicate(timeout=GLOBAL_TIMEOUT)
|
|
except KeyboardInterrupt as k:
|
|
process.kill()
|
|
raise KeyboardInterrupt from k
|
|
except Exception as e:
|
|
logging.critical(
|
|
f"Systemtest {self} had serious issues executing the docker compose command about to kill the docker compose command. Please check the logs! {e}")
|
|
process.kill()
|
|
process.communicate(timeout=SHORT_TIMEOUT)
|
|
stdout_data.extend(stdout.decode().splitlines())
|
|
stderr_data.extend(stderr.decode().splitlines())
|
|
process.poll()
|
|
elapsed_time = time.perf_counter() - time_start
|
|
return FieldCompareResult(process.returncode, stdout_data, stderr_data, self, elapsed_time)
|
|
except Exception as e:
|
|
logging.CRITICAL("Error executing docker compose command:", e)
|
|
elapsed_time = time.perf_counter() - time_start
|
|
return FieldCompareResult(1, stdout_data, stderr_data, self, elapsed_time)
|
|
|
|
def _build_docker(self):
|
|
"""
|
|
Builds the docker image
|
|
"""
|
|
logging.debug(f"Building docker image for {self}")
|
|
time_start = time.perf_counter()
|
|
docker_compose_content = self.__get_docker_compose_file()
|
|
with open(self.system_test_dir / "docker-compose.tutorial.yaml", 'w') as file:
|
|
file.write(docker_compose_content)
|
|
|
|
stdout_data = []
|
|
stderr_data = []
|
|
|
|
try:
|
|
# Execute docker-compose command
|
|
process = subprocess.Popen(['docker',
|
|
'compose',
|
|
'--file',
|
|
'docker-compose.tutorial.yaml',
|
|
'build'],
|
|
stdout=subprocess.PIPE,
|
|
stderr=subprocess.PIPE,
|
|
start_new_session=True,
|
|
cwd=self.system_test_dir)
|
|
|
|
try:
|
|
stdout, stderr = process.communicate(timeout=GLOBAL_TIMEOUT)
|
|
except KeyboardInterrupt as k:
|
|
process.kill()
|
|
# process.send_signal(9)
|
|
raise KeyboardInterrupt from k
|
|
except Exception as e:
|
|
logging.critical(
|
|
f"systemtest {self} had serious issues building the docker images via the `docker compose build` command. About to kill the docker compose command. Please check the logs! {e}")
|
|
process.communicate(timeout=SHORT_TIMEOUT)
|
|
process.kill()
|
|
|
|
stdout_data.extend(stdout.decode().splitlines())
|
|
stderr_data.extend(stderr.decode().splitlines())
|
|
elapsed_time = time.perf_counter() - time_start
|
|
return DockerComposeResult(process.returncode, stdout_data, stderr_data, self, elapsed_time)
|
|
except Exception as e:
|
|
logging.critical(f"Error executing docker compose build command: {e}")
|
|
elapsed_time = time.perf_counter() - time_start
|
|
return DockerComposeResult(1, stdout_data, stderr_data, self, elapsed_time)
|
|
|
|
def _run_tutorial(self):
|
|
"""
|
|
Runs precice couple
|
|
|
|
Returns:
|
|
A DockerComposeResult object containing the state.
|
|
"""
|
|
logging.debug(f"Running tutorial {self}")
|
|
time_start = time.perf_counter()
|
|
stdout_data = []
|
|
stderr_data = []
|
|
try:
|
|
# Execute docker-compose command
|
|
process = subprocess.Popen(['docker',
|
|
'compose',
|
|
'--file',
|
|
'docker-compose.tutorial.yaml',
|
|
'up'],
|
|
stdout=subprocess.PIPE,
|
|
stderr=subprocess.PIPE,
|
|
start_new_session=True,
|
|
cwd=self.system_test_dir)
|
|
|
|
try:
|
|
stdout, stderr = process.communicate(timeout=GLOBAL_TIMEOUT)
|
|
except KeyboardInterrupt as k:
|
|
process.kill()
|
|
# process.send_signal(9)
|
|
raise KeyboardInterrupt from k
|
|
except Exception as e:
|
|
logging.critical(
|
|
f"Systemtest {self} had serious issues executing the docker compose command about to kill the docker compose command. Please check the logs! {e}")
|
|
process.kill()
|
|
stdout, stderr = process.communicate(timeout=SHORT_TIMEOUT)
|
|
process.kill()
|
|
|
|
stdout_data.extend(stdout.decode().splitlines())
|
|
stderr_data.extend(stderr.decode().splitlines())
|
|
elapsed_time = time.perf_counter() - time_start
|
|
return DockerComposeResult(process.returncode, stdout_data, stderr_data, self, elapsed_time)
|
|
except Exception as e:
|
|
logging.critical(f"Error executing docker compose up command: {e}")
|
|
elapsed_time = time.perf_counter() - time_start
|
|
return DockerComposeResult(1, stdout_data, stderr_data, self, elapsed_time)
|
|
|
|
def __repr__(self):
|
|
return f"{self.tutorial.name} {self.case_combination}"
|
|
|
|
def __write_logs(self, stdout_data: List[str], stderr_data: List[str]):
|
|
with open(self.system_test_dir / "stdout.log", 'w') as stdout_file:
|
|
stdout_file.write("\n".join(stdout_data))
|
|
with open(self.system_test_dir / "stderr.log", 'w') as stderr_file:
|
|
stderr_file.write("\n".join(stderr_data))
|
|
|
|
def __prepare_for_run(self, run_directory: Path):
|
|
"""
|
|
Prepares the run_directory with folders and datastructures needed for every systemtest execution
|
|
"""
|
|
self.__copy_tutorial_into_directory(run_directory)
|
|
self.__copy_tools(run_directory)
|
|
self.__put_gitignore(run_directory)
|
|
host_uid, host_gid = self.__get_uid_gid()
|
|
self.params_to_use['PRECICE_UID'] = host_uid
|
|
self.params_to_use['PRECICE_GID'] = host_gid
|
|
|
|
def run(self, run_directory: Path):
|
|
"""
|
|
Runs the system test by generating the Docker Compose file, copying everything into a run folder, and executing docker-compose up.
|
|
"""
|
|
self.__prepare_for_run(run_directory)
|
|
std_out: List[str] = []
|
|
std_err: List[str] = []
|
|
|
|
docker_build_result = self._build_docker()
|
|
std_out.extend(docker_build_result.stdout_data)
|
|
std_err.extend(docker_build_result.stderr_data)
|
|
if docker_build_result.exit_code != 0:
|
|
self.__write_logs(std_out, std_err)
|
|
logging.critical(f"Could not build the docker images, {self} failed")
|
|
return SystemtestResult(
|
|
False,
|
|
std_out,
|
|
std_err,
|
|
self,
|
|
build_time=docker_build_result.runtime,
|
|
solver_time=0,
|
|
fieldcompare_time=0)
|
|
|
|
docker_run_result = self._run_tutorial()
|
|
std_out.extend(docker_run_result.stdout_data)
|
|
std_err.extend(docker_run_result.stderr_data)
|
|
if docker_run_result.exit_code != 0:
|
|
self.__write_logs(std_out, std_err)
|
|
logging.critical(f"Could not run the tutorial, {self} failed")
|
|
return SystemtestResult(
|
|
False,
|
|
std_out,
|
|
std_err,
|
|
self,
|
|
build_time=docker_build_result.runtime,
|
|
solver_time=docker_run_result.runtime,
|
|
fieldcompare_time=0)
|
|
|
|
fieldcompare_result = self._run_field_compare()
|
|
std_out.extend(fieldcompare_result.stdout_data)
|
|
std_err.extend(fieldcompare_result.stderr_data)
|
|
if fieldcompare_result.exit_code != 0:
|
|
self.__write_logs(std_out, std_err)
|
|
logging.critical(f"Fieldcompare returned non zero exit code, therefore {self} failed")
|
|
return SystemtestResult(
|
|
False,
|
|
std_out,
|
|
std_err,
|
|
self,
|
|
build_time=docker_build_result.runtime,
|
|
solver_time=docker_run_result.runtime,
|
|
fieldcompare_time=fieldcompare_result.runtime)
|
|
|
|
# self.__cleanup()
|
|
self.__write_logs(std_out, std_err)
|
|
return SystemtestResult(
|
|
True,
|
|
std_out,
|
|
std_err,
|
|
self,
|
|
build_time=docker_build_result.runtime,
|
|
solver_time=docker_run_result.runtime,
|
|
fieldcompare_time=fieldcompare_result.runtime)
|
|
|
|
def run_for_reference_results(self, run_directory: Path):
|
|
"""
|
|
Runs the system test by generating the Docker Compose files to generate the reference results
|
|
"""
|
|
self.__prepare_for_run(run_directory)
|
|
std_out: List[str] = []
|
|
std_err: List[str] = []
|
|
docker_build_result = self._build_docker()
|
|
std_out.extend(docker_build_result.stdout_data)
|
|
std_err.extend(docker_build_result.stderr_data)
|
|
if docker_build_result.exit_code != 0:
|
|
self.__write_logs(std_out, std_err)
|
|
logging.critical(f"Could not build the docker images, {self} failed")
|
|
return SystemtestResult(
|
|
False,
|
|
std_out,
|
|
std_err,
|
|
self,
|
|
build_time=docker_build_result.runtime,
|
|
solver_time=0,
|
|
fieldcompare_time=0)
|
|
|
|
docker_run_result = self._run_tutorial()
|
|
std_out.extend(docker_run_result.stdout_data)
|
|
std_err.extend(docker_run_result.stderr_data)
|
|
if docker_run_result.exit_code != 0:
|
|
self.__write_logs(std_out, std_err)
|
|
logging.critical(f"Could not run the tutorial, {self} failed")
|
|
return SystemtestResult(
|
|
False,
|
|
std_out,
|
|
std_err,
|
|
self,
|
|
build_time=docker_build_result.runtime,
|
|
solver_time=docker_run_result.runtime,
|
|
fieldcompare_time=0)
|
|
|
|
self.__write_logs(std_out, std_err)
|
|
return SystemtestResult(
|
|
True,
|
|
std_out,
|
|
std_err,
|
|
self,
|
|
build_time=docker_build_result.runtime,
|
|
solver_time=docker_run_result.runtime,
|
|
fieldcompare_time=0)
|
|
|
|
def run_only_build(self, run_directory: Path):
|
|
"""
|
|
Runs only the build commmand, for example to preheat the caches of the docker builder.
|
|
"""
|
|
self.__prepare_for_run(run_directory)
|
|
std_out: List[str] = []
|
|
std_err: List[str] = []
|
|
docker_build_result = self._build_docker()
|
|
std_out.extend(docker_build_result.stdout_data)
|
|
std_err.extend(docker_build_result.stderr_data)
|
|
if docker_build_result.exit_code != 0:
|
|
self.__write_logs(std_out, std_err)
|
|
logging.critical(f"Could not build the docker images, {self} failed")
|
|
return SystemtestResult(
|
|
False,
|
|
std_out,
|
|
std_err,
|
|
self,
|
|
build_time=docker_build_result.runtime,
|
|
solver_time=0,
|
|
fieldcompare_time=0)
|
|
|
|
self.__write_logs(std_out, std_err)
|
|
return SystemtestResult(
|
|
True,
|
|
std_out,
|
|
std_err,
|
|
self,
|
|
build_time=docker_build_result.runtime,
|
|
solver_time=0,
|
|
fieldcompare_time=0)
|
|
|
|
def get_system_test_dir(self) -> Path:
|
|
return self.system_test_dir
|