"""
Файл конфигурации pytest с фикстурами для тестирования ML моделей.
"""
import pytest
import json
import os
from pathlib import Path
# Импортируем утилиты внутри функций, чтобы избежать проблем с импортами
[документация]
def get_project_root():
"""Возвращает корневую директорию проекта."""
return Path(__file__).parent.parent
[документация]
def pytest_addoption(parser):
"""Добавляет опции командной строки для выбора категорий тестов."""
parser.addoption(
"--test-category",
action="store",
default="all",
choices=["all", "smoke", "attack", "model", "dataset", "strategic"],
help="Выбрать категорию тестов: all, smoke, attack, model, dataset, strategic"
)
[документация]
def get_config_paths_by_category(category):
"""Получает пути к конфигам по категории."""
project_root = get_project_root()
configs_dir = project_root / "abs_art_tabular" / "configs"
config_paths = []
# Функция для поиска конфигов с поддержкой разных расширений
def find_configs_in_dir(directory):
"""Находит все .json и .yaml/.yml файлы в директории."""
configs = []
if directory.exists():
# Ищем файлы с разными расширениями
for pattern in ["*.json", "*.yaml", "*.yml"]:
configs.extend(list(directory.glob(pattern)))
return [str(p.relative_to(project_root)) for p in configs]
if category in ["all", "smoke", "strategic"]:
# Ищем smoke конфиги с разными расширениями
smoke_dir = project_root / "abs_art_tabular" / "configs"
if smoke_dir.exists():
for pattern in ["smoke_test.*"]:
smoke_configs = list(smoke_dir.glob(pattern))
config_paths.extend([str(p.relative_to(project_root)) for p in smoke_configs])
# Если не нашли с шаблоном, ищем конкретные имена
if not config_paths:
for name in ["smoke_test.json", "smoke_test.yaml", "smoke_test.yml"]:
smoke_config = project_root / "abs_art_tabular" / "configs" / name
if smoke_config.exists():
config_paths.append(str(smoke_config.relative_to(project_root)))
if category in ["all", "attack", "strategic"]:
attack_dir = configs_dir / "attack_coverage"
config_paths.extend(find_configs_in_dir(attack_dir))
if category in ["all", "model", "strategic"]:
model_dir = configs_dir / "model_coverage"
config_paths.extend(find_configs_in_dir(model_dir))
if category in ["all", "dataset", "strategic"]:
dataset_dir = configs_dir / "dataset_coverage"
config_paths.extend(find_configs_in_dir(dataset_dir))
return config_paths
[документация]
@pytest.fixture
def categorized_config_path(request):
"""Фикстура, предоставляющая пути к конфигам по категориям."""
category = request.config.getoption("--test-category")
config_paths = get_config_paths_by_category(category)
if not config_paths:
pytest.skip(f"No configs found for category: {category}")
return config_paths
[документация]
@pytest.fixture
def smoke_config_path():
"""Фикстура для smoke тестов."""
project_root = get_project_root()
# Ищем smoke конфиг с любым поддерживаемым расширением
for ext in ['.json', '.yaml', '.yml']:
smoke_config = project_root / "abs_art_tabular" / "configs" / f"smoke_test{ext}"
if smoke_config.exists():
return str(smoke_config.relative_to(project_root))
# Если не нашли, возвращаем дефолтный путь (для совместимости)
return "abs_art_tabular/configs/smoke_test.json"
[документация]
@pytest.fixture
def prepared_test_environment(categorized_config_path, tmp_path):
"""Фикстура для подготовки тестового окружения."""
# Импортируем здесь, чтобы избежать проблем с импортами
from test_suite.test_utils import get_project_root, create_temp_config, run_attack, find_report_paths
# Выбираем конфиг из списка или используем как есть
if isinstance(categorized_config_path, list):
if categorized_config_path:
config_path = categorized_config_path[0] # Берем первый для простоты
else:
pytest.skip("No config paths provided")
else:
config_path = categorized_config_path
project_root = get_project_root()
original_config_path = project_root / config_path
# Проверяем существование файла
if not original_config_path.exists():
pytest.skip(f"Config file not found: {config_path}")
# Создаём временный конфиг с путями к временной директории
temp_config_path = create_temp_config(str(original_config_path), str(tmp_path))
# Запускаем атаку
result = run_attack(temp_config_path)
# Проверяем успешность выполнения (минимальная проверка)
assert result.returncode == 0, (
f"Attack failed with exit code {result.returncode}\n"
f"=== STDERR ===\n{result.stderr}\n"
f"=== STDOUT ===\n{result.stdout}"
)
# Проверяем создание отчетов используя пути из временной директории
json_report_path, html_report_path = find_report_paths(result.stdout, result.stderr, str(tmp_path))
assert json_report_path is not None, "JSON report path not found in output"
assert html_report_path is not None, "HTML report path not found in output"
assert os.path.exists(json_report_path), f"JSON report file not found at {json_report_path}"
assert os.path.exists(html_report_path), f"HTML report not found at {html_report_path}"
return {
"result": result,
"json_report_path": json_report_path,
"html_report_path": html_report_path,
"tmp_path": tmp_path,
"config_path": config_path
}