A previous `git pull --rebase origin main` dropped 177 local commits,
losing 3400+ files across admin-v2, backend, studio-v2, website,
klausur-service, and many other services. The partial restore attempt
(660295e2) only recovered some files.
This commit restores all missing files from pre-rebase ref 98933f5e
while preserving post-rebase additions (night-scheduler, night-mode UI,
NightModeWidget dashboard integration).
Restored features include:
- AI Module Sidebar (FAB), OCR Labeling, OCR Compare
- GPU Dashboard, RAG Pipeline, Magic Help
- Klausur-Korrektur (8 files), Abitur-Archiv (5+ files)
- Companion, Zeugnisse-Crawler, Screen Flow
- Full backend, studio-v2, website, klausur-service
- All compliance SDKs, agent-core, voice-service
- CI/CD configs, documentation, scripts
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
184 lines
6.0 KiB
Python
184 lines
6.0 KiB
Python
"""
|
|
Tests für AlertItem Model.
|
|
"""
|
|
|
|
import pytest
|
|
from datetime import datetime
|
|
|
|
from alerts_agent.models.alert_item import AlertItem, AlertSource, AlertStatus
|
|
|
|
|
|
class TestAlertItemCreation:
|
|
"""Tests für AlertItem Erstellung."""
|
|
|
|
def test_create_minimal_alert(self):
|
|
"""Test minimale Alert-Erstellung."""
|
|
alert = AlertItem(title="Test Alert", url="https://example.com/article")
|
|
|
|
assert alert.title == "Test Alert"
|
|
assert alert.url == "https://example.com/article"
|
|
assert alert.id is not None
|
|
assert len(alert.id) == 36 # UUID format
|
|
assert alert.status == AlertStatus.NEW
|
|
assert alert.source == AlertSource.GOOGLE_ALERTS_RSS
|
|
|
|
def test_create_full_alert(self):
|
|
"""Test vollständige Alert-Erstellung."""
|
|
alert = AlertItem(
|
|
source=AlertSource.GOOGLE_ALERTS_EMAIL,
|
|
topic_label="Inklusion Bayern",
|
|
title="Neue Inklusions-Richtlinie",
|
|
url="https://example.com/inklusion",
|
|
snippet="Die neue Richtlinie für inklusive Bildung...",
|
|
lang="de",
|
|
published_at=datetime(2024, 1, 15, 10, 30),
|
|
)
|
|
|
|
assert alert.source == AlertSource.GOOGLE_ALERTS_EMAIL
|
|
assert alert.topic_label == "Inklusion Bayern"
|
|
assert alert.lang == "de"
|
|
assert alert.published_at.year == 2024
|
|
|
|
def test_url_hash_generated(self):
|
|
"""Test dass URL Hash automatisch generiert wird."""
|
|
alert = AlertItem(
|
|
title="Test",
|
|
url="https://example.com/test"
|
|
)
|
|
|
|
assert alert.url_hash is not None
|
|
assert len(alert.url_hash) == 16 # 16 hex chars
|
|
|
|
def test_canonical_url_generated(self):
|
|
"""Test dass kanonische URL generiert wird."""
|
|
alert = AlertItem(
|
|
title="Test",
|
|
url="https://EXAMPLE.com/path/"
|
|
)
|
|
|
|
# Sollte lowercase und ohne trailing slash sein
|
|
assert alert.canonical_url == "https://example.com/path"
|
|
|
|
|
|
class TestURLNormalization:
|
|
"""Tests für URL Normalisierung."""
|
|
|
|
def test_remove_tracking_params(self):
|
|
"""Test Entfernung von Tracking-Parametern."""
|
|
alert = AlertItem(
|
|
title="Test",
|
|
url="https://example.com/article?utm_source=google&utm_medium=email&id=123"
|
|
)
|
|
|
|
# utm_source und utm_medium sollten entfernt werden, id bleibt
|
|
assert "utm_source" not in alert.canonical_url
|
|
assert "utm_medium" not in alert.canonical_url
|
|
assert "id=123" in alert.canonical_url
|
|
|
|
def test_lowercase_domain(self):
|
|
"""Test Domain wird lowercase."""
|
|
alert = AlertItem(
|
|
title="Test",
|
|
url="https://WWW.EXAMPLE.COM/Article"
|
|
)
|
|
|
|
assert "www.example.com" in alert.canonical_url
|
|
|
|
def test_remove_fragment(self):
|
|
"""Test Fragment wird entfernt."""
|
|
alert = AlertItem(
|
|
title="Test",
|
|
url="https://example.com/article#section1"
|
|
)
|
|
|
|
assert "#" not in alert.canonical_url
|
|
|
|
def test_same_url_same_hash(self):
|
|
"""Test gleiche URL produziert gleichen Hash."""
|
|
alert1 = AlertItem(title="Test", url="https://example.com/test")
|
|
alert2 = AlertItem(title="Test", url="https://example.com/test")
|
|
|
|
assert alert1.url_hash == alert2.url_hash
|
|
|
|
def test_different_url_different_hash(self):
|
|
"""Test verschiedene URLs produzieren verschiedene Hashes."""
|
|
alert1 = AlertItem(title="Test", url="https://example.com/test1")
|
|
alert2 = AlertItem(title="Test", url="https://example.com/test2")
|
|
|
|
assert alert1.url_hash != alert2.url_hash
|
|
|
|
|
|
class TestAlertSerialization:
|
|
"""Tests für Serialisierung."""
|
|
|
|
def test_to_dict(self):
|
|
"""Test Konvertierung zu Dictionary."""
|
|
alert = AlertItem(
|
|
title="Test Alert",
|
|
url="https://example.com",
|
|
topic_label="Test Topic",
|
|
)
|
|
|
|
data = alert.to_dict()
|
|
|
|
assert data["title"] == "Test Alert"
|
|
assert data["url"] == "https://example.com"
|
|
assert data["topic_label"] == "Test Topic"
|
|
assert data["source"] == "google_alerts_rss"
|
|
assert data["status"] == "new"
|
|
|
|
def test_from_dict(self):
|
|
"""Test Erstellung aus Dictionary."""
|
|
data = {
|
|
"id": "test-id-123",
|
|
"title": "Test Alert",
|
|
"url": "https://example.com",
|
|
"source": "google_alerts_email",
|
|
"status": "scored",
|
|
"relevance_score": 0.85,
|
|
}
|
|
|
|
alert = AlertItem.from_dict(data)
|
|
|
|
assert alert.id == "test-id-123"
|
|
assert alert.title == "Test Alert"
|
|
assert alert.source == AlertSource.GOOGLE_ALERTS_EMAIL
|
|
assert alert.status == AlertStatus.SCORED
|
|
assert alert.relevance_score == 0.85
|
|
|
|
def test_round_trip(self):
|
|
"""Test Serialisierung und Deserialisierung."""
|
|
original = AlertItem(
|
|
title="Round Trip Test",
|
|
url="https://example.com/roundtrip",
|
|
topic_label="Testing",
|
|
relevance_score=0.75,
|
|
relevance_decision="KEEP",
|
|
)
|
|
|
|
data = original.to_dict()
|
|
restored = AlertItem.from_dict(data)
|
|
|
|
assert restored.title == original.title
|
|
assert restored.url == original.url
|
|
assert restored.relevance_score == original.relevance_score
|
|
|
|
|
|
class TestAlertStatus:
|
|
"""Tests für Alert Status."""
|
|
|
|
def test_status_enum_values(self):
|
|
"""Test Status Enum Werte."""
|
|
assert AlertStatus.NEW.value == "new"
|
|
assert AlertStatus.PROCESSED.value == "processed"
|
|
assert AlertStatus.DUPLICATE.value == "duplicate"
|
|
assert AlertStatus.SCORED.value == "scored"
|
|
assert AlertStatus.REVIEWED.value == "reviewed"
|
|
assert AlertStatus.ARCHIVED.value == "archived"
|
|
|
|
def test_source_enum_values(self):
|
|
"""Test Source Enum Werte."""
|
|
assert AlertSource.GOOGLE_ALERTS_RSS.value == "google_alerts_rss"
|
|
assert AlertSource.GOOGLE_ALERTS_EMAIL.value == "google_alerts_email"
|
|
assert AlertSource.MANUAL.value == "manual"
|