Source code for fm_weck.smoke_test_mode

# This file is part of fm-weck: executing fm-tools in containerized environments.
# https://gitlab.com/sosy-lab/software/fm-weck
#
# SPDX-FileCopyrightText: 2024 Dirk Beyer <https://www.sosy-lab.org>
#
# SPDX-License-Identifier: Apache-2.0

import logging
import os
import subprocess
from pathlib import Path

from fm_tools.fmtoolversion import FmToolVersion

from .engine import CACHE_MOUNT_LOCATION, Engine

logger = logging.getLogger(__name__)


[docs] class SmokeTestError(Exception): """Custom exception for smoke test errors.""" pass
[docs] class NoSmokeTestFileError(SmokeTestError): """Exception raised when no smoke test file is found.""" pass
[docs] class SmokeTestFileIsEmptyError(SmokeTestError): """Exception raised when the smoke test file is empty.""" pass
[docs] class SmokeTestFileIsNotExecutableError(SmokeTestError): """Exception raised when the smoke test file is not executable.""" smoke_test_file: Path def __init__(self, smoke_test_file: Path): self.smoke_test_file = smoke_test_file super().__init__(f"Smoke test file is not executable: {smoke_test_file}") pass
[docs] def locate_and_check_smoke_test_file(shelve_space: Path) -> str: """Check if the smoke test file exists, is executable, and is not empty. Args: shelve_space: Path to the shelve space directory. Returns: The relative path to the smoke test file as a string. Raises: NoSmokeTestFileError: If the smoke test file does not exist. SmokeTestFileIsEmptyError: If the smoke test file is empty. SmokeTestFileIsNotExecutableError: If the smoke test file is not executable. """ file_path = shelve_space / "smoketest.sh" if not file_path.exists(): raise NoSmokeTestFileError(f"Smoke test file 'smoketest.sh' not found in: {shelve_space}") if not file_path.stat().st_mode & os.X_OK: raise SmokeTestFileIsNotExecutableError(file_path.relative_to(shelve_space)) if file_path.stat().st_size == 0: raise SmokeTestFileIsEmptyError(f"Smoke test file is empty: {file_path}") return f"./{file_path.name}"
[docs] def run_smoke_test(fm_data, shelve_space, config): if not shelve_space.exists() or not shelve_space.is_dir(): raise ValueError(f"Invalid shelve space path: {shelve_space}") engine = Engine.from_config(fm_data, config) tool_dir = shelve_space.relative_to(config.cache_location) engine.work_dir = CACHE_MOUNT_LOCATION / tool_dir command = locate_and_check_smoke_test_file(shelve_space) # Return the result so callers can react to failures and print diagnostics return engine.run(command)
[docs] def run_smoke_test_gitlab_ci(fm_data: FmToolVersion, tool_dir: Path): """ Run smoke test in GitLab CI mode. This mode directly installs required packages using apt instead of building/pulling images. Args: fm_data: The FmToolVersion object containing tool information tool_dir: The directory containing the tool's smoketest.sh script """ # Get required packages from fm_data required_packages = fm_data.get_images().required_packages if required_packages: logger.info("Installing required packages: %s", " ".join(required_packages)) # Install packages try: subprocess.run(["apt", "install", "-y", *required_packages], check=True) logger.info("Successfully installed packages: %s", " ".join(required_packages)) except subprocess.CalledProcessError: logger.error("Failed to install packages.") raise else: logger.info("No required packages specified for this tool") script_command = locate_and_check_smoke_test_file(tool_dir) logger.info("Running smoke test script: %s", script_command) try: subprocess.run([script_command], cwd=tool_dir, check=True) logger.info("Smoke test completed successfully") except subprocess.CalledProcessError as e: logger.error("Smoke test failed with return code %d", e.returncode) raise