refactor(generator): разнесён сервис генератора по src-пакету
- Зачем: - перед активными визитами нужно отделить генеративную модель от Kafka, состояния и сервисного цикла. - Что: - перенесены модули генератора в пакет `src/clickstream_generator`. - `generator.py` оставлен фасадом и точкой входа с совместимыми импортами. - обновлены Dockerfile, тесты, README, спека и issue 02.5. - Проверка: - `docker build -t generator:test generator`. - `docker run --rm -v /home/dmitry/sources/clickstream-ch-kafka-superset-demo:/workspace -w /workspace/generator generator:test pytest tests/ -q`. - `python -m py_compile generator.py src/clickstream_generator/*.py` в Docker.
This commit is contained in:
@@ -5,8 +5,11 @@ Pytest fixtures для тестирования генератора.
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
# Добавляем родительскую директорию в путь
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent))
|
||||
GENERATOR_DIR = Path(__file__).parent.parent
|
||||
|
||||
# Добавляем фасад generator.py и src-пакет в путь
|
||||
sys.path.insert(0, str(GENERATOR_DIR))
|
||||
sys.path.insert(0, str(GENERATOR_DIR / "src"))
|
||||
|
||||
import pytest
|
||||
from generator import Config, EventDictionary
|
||||
|
||||
@@ -7,7 +7,7 @@ from dataclasses import replace
|
||||
from datetime import datetime
|
||||
|
||||
import pytest
|
||||
from generator import EventGenerator, EventDictionary
|
||||
from generator import EventGenerator, EventDictionary, generate_tick_batch
|
||||
|
||||
|
||||
ALLOWED_PAGE_PATHS = {
|
||||
@@ -95,7 +95,7 @@ class TestEventGeneration:
|
||||
"""Тиковый батч набирает целевой бюджет из одного или нескольких визитов."""
|
||||
generator = EventGenerator(event_dictionary, base_config)
|
||||
|
||||
batch = generator.generate_tick_batch(20)
|
||||
batch = generate_tick_batch(generator, 20)
|
||||
|
||||
assert len(batch["browser_events"]) == 20
|
||||
assert len(batch["location_events"]) == 20
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
"""
|
||||
Контракт уборки сервиса генератора.
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
from generator import (
|
||||
Config,
|
||||
EventDictionary,
|
||||
EventGenerator,
|
||||
GeneratorService,
|
||||
KafkaPublisher,
|
||||
GeneratorState,
|
||||
)
|
||||
|
||||
|
||||
def test_dockerfile_copies_split_python_modules():
|
||||
"""Контейнерный запуск видит все модули генератора после разбиения."""
|
||||
dockerfile = (Path(__file__).parent.parent / "Dockerfile").read_text(encoding="utf-8")
|
||||
|
||||
assert "COPY src ./src" in dockerfile
|
||||
assert 'ENV PYTHONPATH="/app/src"' in dockerfile
|
||||
|
||||
|
||||
def test_generator_facade_imports_without_pythonpath():
|
||||
"""Локальный фасад сам находит src-пакет без внешнего PYTHONPATH."""
|
||||
generator_dir = Path(__file__).parent.parent
|
||||
|
||||
result = subprocess.run(
|
||||
[sys.executable, "-c", "import generator"],
|
||||
cwd=generator_dir,
|
||||
env={"PATH": ""},
|
||||
text=True,
|
||||
capture_output=True,
|
||||
check=False,
|
||||
)
|
||||
|
||||
assert result.returncode == 0, result.stderr
|
||||
|
||||
|
||||
def test_generator_facade_preserves_public_imports_after_split():
|
||||
"""Старый импорт из generator работает, но классы живут в отдельных модулях."""
|
||||
assert Config.__module__ == "clickstream_generator.config"
|
||||
assert EventDictionary.__module__ == "clickstream_generator.dictionary"
|
||||
assert EventGenerator.__module__ == "clickstream_generator.generation"
|
||||
assert KafkaPublisher.__module__ == "clickstream_generator.kafka_io"
|
||||
assert GeneratorState.__module__ == "clickstream_generator.state"
|
||||
assert GeneratorService.__module__ == "clickstream_generator.service"
|
||||
|
||||
|
||||
def test_tick_batch_is_not_part_of_pure_visit_generation():
|
||||
"""Временная сборка тика вынесена из чистой модели одного визита."""
|
||||
assert not hasattr(EventGenerator, "generate_tick_batch")
|
||||
Reference in New Issue
Block a user