feat(airflow): добавлен пульт управления генератором
- Зачем: - нужен основной ручной интерфейс стенда для backfill/import/check без консольной матрицы переменных. - Что: - добавлен DAG generator_control с параметрами Airflow, ветвлением операций и ожиданием ETL. - вынесена общая логика запуска и предпроверок генератора для Airflow. - обновлены compose-настройки, зависимости, тесты и документация по пульту. - Проверка: - uv run --with pytest --with-requirements generator/requirements.txt pytest generator/tests -q. - docker compose config --quiet.
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
"""
|
||||
Контракт DAG generator_control без запуска Airflow.
|
||||
"""
|
||||
|
||||
import ast
|
||||
from pathlib import Path
|
||||
|
||||
from clickstream_generator.launch import PROFILES
|
||||
|
||||
|
||||
DAG_PATH = Path(__file__).parents[2] / "airflow" / "dags" / "generator_control_dag.py"
|
||||
REPO_ROOT = Path(__file__).parents[2]
|
||||
|
||||
|
||||
def _tree():
|
||||
return ast.parse(DAG_PATH.read_text(encoding="utf-8"))
|
||||
|
||||
|
||||
def test_dag_file_exists_and_uses_dynamic_profiles():
|
||||
"""DAG берёт варианты профилей из PROFILES, а не из ручного списка."""
|
||||
text = DAG_PATH.read_text(encoding="utf-8")
|
||||
|
||||
assert "dag_id=\"generator_control\"" in text
|
||||
assert "sorted(PROFILES)" in text
|
||||
for profile in PROFILES:
|
||||
assert profile not in {"hardcoded-profile"}
|
||||
|
||||
|
||||
def test_trigger_form_has_expected_param_enums():
|
||||
"""Форма запуска ограничивает операции и профили."""
|
||||
text = DAG_PATH.read_text(encoding="utf-8")
|
||||
|
||||
assert 'enum=["backfill", "import", "check"]' in text
|
||||
assert "enum=sorted(PROFILES)" in text
|
||||
assert '"duration": Param(' in text
|
||||
assert '"artifact_path": Param(' in text
|
||||
|
||||
|
||||
def test_dag_branches_and_waits_for_etl_completion():
|
||||
"""Backfill/import запускают ETL и ждут его завершения перед check."""
|
||||
text = DAG_PATH.read_text(encoding="utf-8")
|
||||
|
||||
assert "BranchPythonOperator" in text
|
||||
assert "TriggerDagRunOperator" in text
|
||||
assert 'trigger_dag_id="etl_pipeline"' in text
|
||||
assert "wait_for_completion=True" in text
|
||||
assert 'allowed_states=["success"]' in text
|
||||
assert 'failed_states=["failed"]' in text
|
||||
|
||||
|
||||
def test_no_docker_or_continue_operation_in_dag():
|
||||
"""Пульт не управляет Docker и не содержит операцию continue."""
|
||||
text = DAG_PATH.read_text(encoding="utf-8")
|
||||
|
||||
assert "docker" not in text.lower()
|
||||
assert '"continue"' not in text
|
||||
|
||||
|
||||
def test_compose_mounts_generator_code_without_socket_and_gates_live_service():
|
||||
"""Airflow видит код генератора, но не получает Docker socket."""
|
||||
text = (REPO_ROOT / "docker-compose.yml").read_text(encoding="utf-8")
|
||||
|
||||
assert "PYTHONPATH: /opt/airflow/generator_src" in text
|
||||
assert "./generator/src:/opt/airflow/generator_src:ro" in text
|
||||
assert "/var/run/docker.sock" not in text
|
||||
assert "profiles:\n - live-generator" in text
|
||||
|
||||
|
||||
def test_airflow_and_generator_kafka_dependency_versions_match():
|
||||
"""Airflow и генератор используют одну версию kafka-python."""
|
||||
airflow_req = (REPO_ROOT / "airflow" / "requirements.txt").read_text(encoding="utf-8")
|
||||
generator_req = (REPO_ROOT / "generator" / "requirements.txt").read_text(encoding="utf-8")
|
||||
|
||||
assert "kafka-python==2.0.6" in airflow_req
|
||||
assert "kafka-python==2.0.6" in generator_req
|
||||
assert "prometheus-client==0.21.1" in airflow_req
|
||||
Reference in New Issue
Block a user