175 lines
4.8 KiB
Python
175 lines
4.8 KiB
Python
import asyncio
|
||
import tempfile
|
||
from collections.abc import Generator
|
||
from pathlib import Path
|
||
from unittest.mock import AsyncMock, MagicMock
|
||
|
||
import pytest
|
||
from openai.types.chat import ChatCompletion, ChatCompletionMessage
|
||
from openai.types.chat.chat_completion import Choice
|
||
|
||
from src.models import AppConfig, Article, ArticleCreate, ProcessingStatus
|
||
|
||
|
||
@pytest.fixture(scope="session")
|
||
def event_loop() -> Generator[asyncio.AbstractEventLoop, None, None]:
|
||
loop = asyncio.new_event_loop()
|
||
yield loop
|
||
loop.close()
|
||
|
||
|
||
@pytest.fixture
|
||
def test_config() -> AppConfig:
|
||
with tempfile.TemporaryDirectory() as temp_dir:
|
||
db_path = Path(temp_dir) / "test.db"
|
||
return AppConfig(
|
||
openai_api_key="test_key",
|
||
openai_model="gpt-4o-mini",
|
||
db_path=str(db_path),
|
||
max_concurrent_llm=2,
|
||
openai_rpm=10,
|
||
max_concurrent_wiki=5,
|
||
prompt_template_path="src/prompt.txt",
|
||
log_level="DEBUG",
|
||
)
|
||
|
||
|
||
@pytest.fixture
|
||
def sample_wiki_urls() -> list[str]:
|
||
return [
|
||
"https://ru.wikipedia.org/wiki/Тест",
|
||
"https://ru.wikipedia.org/wiki/Пример",
|
||
"https://ru.wikipedia.org/wiki/Образец",
|
||
]
|
||
|
||
|
||
@pytest.fixture
|
||
def invalid_urls() -> list[str]:
|
||
return [
|
||
"https://example.com/invalid",
|
||
"https://en.wikipedia.org/wiki/English",
|
||
"not_a_url",
|
||
"",
|
||
"https://ru.wikipedia.org/wiki/",
|
||
]
|
||
|
||
|
||
@pytest.fixture
|
||
def sample_wikitext() -> str:
|
||
return """'''Тест''' — это проверка чего-либо.
|
||
|
||
== Определение ==
|
||
Тест может проводиться для различных целей:
|
||
* Проверка знаний
|
||
* Проверка работоспособности
|
||
* Проверка качества
|
||
|
||
== История ==
|
||
Тесты использовались с древних времён.
|
||
|
||
{{навигация|тема=Тестирование}}
|
||
|
||
[[Категория:Тестирование]]"""
|
||
|
||
|
||
@pytest.fixture
|
||
def simplified_text() -> str:
|
||
return """'''Тест''' — это проверка чего-либо для школьников.
|
||
|
||
== Что такое тест ==
|
||
Тест помогает проверить:
|
||
* Знания учеников
|
||
* Как работают устройства
|
||
* Качество продуктов
|
||
|
||
== Когда появились тесты ==
|
||
Люди проверяли друг друга очень давно.
|
||
|
||
###END###"""
|
||
|
||
|
||
@pytest.fixture
|
||
def sample_article_data() -> ArticleCreate:
|
||
return ArticleCreate(
|
||
url="https://ru.wikipedia.org/wiki/Тест",
|
||
title="Тест",
|
||
raw_text="Тестовый wiki-текст",
|
||
)
|
||
|
||
|
||
@pytest.fixture
|
||
def sample_article(sample_article_data: ArticleCreate) -> Article:
|
||
return Article(
|
||
id=1,
|
||
url=sample_article_data.url,
|
||
title=sample_article_data.title,
|
||
raw_text=sample_article_data.raw_text,
|
||
status=ProcessingStatus.PENDING,
|
||
)
|
||
|
||
|
||
@pytest.fixture
|
||
def completed_article(sample_article: Article, simplified_text: str) -> Article:
|
||
article = sample_article.model_copy()
|
||
article.mark_completed(
|
||
simplified_text=simplified_text,
|
||
token_count_raw=100,
|
||
token_count_simplified=50,
|
||
processing_time=2.5,
|
||
)
|
||
return article
|
||
|
||
|
||
@pytest.fixture
|
||
def mock_openai_response() -> ChatCompletion:
|
||
return ChatCompletion(
|
||
id="test_completion",
|
||
object="chat.completion",
|
||
created=1234567890,
|
||
model="gpt-4o-mini",
|
||
choices=[
|
||
Choice(
|
||
index=0,
|
||
message=ChatCompletionMessage(
|
||
role="assistant",
|
||
content="Упрощённый текст для школьников.\n\n###END###",
|
||
),
|
||
finish_reason="stop",
|
||
)
|
||
],
|
||
usage=None,
|
||
)
|
||
|
||
|
||
@pytest.fixture
|
||
def temp_input_file(sample_wiki_urls: list[str]) -> Generator[str, None, None]:
|
||
with tempfile.NamedTemporaryFile(mode="w", suffix=".txt", delete=False) as f:
|
||
for url in sample_wiki_urls:
|
||
f.write(f"{url}\n")
|
||
f.write("# Комментарий\n")
|
||
f.write("\n")
|
||
f.write("https://ru.wikipedia.org/wiki/Дубликат\n")
|
||
f.write("https://ru.wikipedia.org/wiki/Дубликат\n")
|
||
temp_path = f.name
|
||
|
||
yield temp_path
|
||
|
||
Path(temp_path).unlink(missing_ok=True)
|
||
|
||
|
||
@pytest.fixture
|
||
async def mock_wiki_client() -> AsyncMock:
|
||
mock_client = AsyncMock()
|
||
mock_page = MagicMock()
|
||
mock_page.exists = True
|
||
mock_page.redirect = False
|
||
mock_page.text.return_value = "Тестовый wiki-текст"
|
||
mock_client.pages = {"Тест": mock_page}
|
||
return mock_client
|
||
|
||
|
||
@pytest.fixture
|
||
async def mock_openai_client() -> AsyncMock:
|
||
mock_client = AsyncMock()
|
||
return mock_client
|