Первый настоящий автоматический тест-суит проекта — раньше регрессии ловились руками. Покрыта чистая логика детекции и форматирования (без БД/Redis/GPU/Ollama): - worker-indexer: L1 Winnowing (точные совпадения, идемпотентность отпечатка, диапазон signed int64) и L2 MinHash LSH (шинглы, Jaccard, near-duplicate + upsert через in-memory-фолбэк). - worker-gpu: L3 FAISS — возврат doc_id из PostgreSQL (IndexIDMap2), идемпотентность add_vectors (remove-before-add, без дублей), self-match ≈ 1, ранжирование. Прямо стережёт баги, из-за которых индекс переписывался. - worker-gost: ГОСТ 7.1-2003 и 7.0.5-2008 — авторы (≤3 / 4+ «и др.»/et al.), статья/книга/web, DOI, порядок сортировки кириллица→латиница, стр. в ссылке. Обвязка: per-service pytest.ini/conftest/requirements-test. scripts/run_tests.sh гоняет тесты в изолированных python:3.11-slim контейнерах (не засоряя хост), через Tsinghua-зеркало. CI: job `test` теперь гейтит `deploy` (needs: test) — падение тестов блокирует прод-деплой. make test / make test-one SVC=... Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
63 lines
2.6 KiB
Python
63 lines
2.6 KiB
Python
"""Юнит-тесты MinHash LSH (уровень 2 — нечёткие совпадения).
|
|
|
|
Redis в тестовом окружении недоступен → get_lsh() детерминированно падает в
|
|
in-memory-фолбэк, что и проверяется здесь.
|
|
"""
|
|
|
|
from app.algorithms import minhash
|
|
|
|
|
|
def test_get_shingles_basic():
|
|
assert minhash.get_shingles("один два три четыре", k=3) == {
|
|
"один два три",
|
|
"два три четыре",
|
|
}
|
|
|
|
|
|
def test_get_shingles_short_text():
|
|
assert minhash.get_shingles("одно", k=3) == {"одно"}
|
|
assert minhash.get_shingles("", k=3) == set()
|
|
|
|
|
|
def test_identical_text_jaccard_is_one():
|
|
t = "нейронные сети глубокого обучения распознают образы на изображениях точно"
|
|
assert minhash.compute_jaccard_minhash(t, t) == 1.0
|
|
|
|
|
|
def test_disjoint_text_jaccard_near_zero():
|
|
a = "квантовая физика элементарных частиц и теория поля"
|
|
b = "кулинарные рецепты домашней выпечки пшеничного хлеба"
|
|
assert minhash.compute_jaccard_minhash(a, b) < 0.1
|
|
|
|
|
|
def test_lsh_finds_near_duplicate_and_ignores_unrelated():
|
|
minhash.reset_lsh()
|
|
try:
|
|
base = (
|
|
"нейронные сети глубокого обучения применяются для распознавания "
|
|
"образов на цифровых изображениях и в задачах компьютерного зрения"
|
|
)
|
|
minhash.add_to_lsh("doc:1", base)
|
|
|
|
near = base.replace("изображениях", "фотографиях")
|
|
assert "doc:1" in minhash.find_similar(near)
|
|
|
|
unrelated = (
|
|
"экономический анализ рынка недвижимости в крупных городах страны "
|
|
"за последние несколько отчётных финансовых кварталов подряд"
|
|
)
|
|
assert "doc:1" not in minhash.find_similar(unrelated)
|
|
finally:
|
|
minhash.reset_lsh()
|
|
|
|
|
|
def test_lsh_upsert_does_not_duplicate():
|
|
minhash.reset_lsh()
|
|
try:
|
|
text = "обработка естественного языка методами машинного обучения и статистики"
|
|
minhash.add_to_lsh("doc:9", text)
|
|
minhash.add_to_lsh("doc:9", text) # повторно тот же ключ — upsert, не дубль
|
|
assert minhash.find_similar(text).count("doc:9") == 1
|
|
finally:
|
|
minhash.reset_lsh()
|