Spaces:
Paused
Paused
| """ | |
| Unit Tests β Webhook Server | |
| """ | |
| import hashlib | |
| import hmac | |
| import base64 | |
| import pytest | |
| from fastapi.testclient import TestClient | |
| from unittest.mock import AsyncMock, patch | |
| # βββ Signature Helper ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def make_signature(body: bytes, secret: str) -> str: | |
| h = hmac.new(secret.encode(), body, hashlib.sha256).digest() | |
| return base64.b64encode(h).decode() | |
| # βββ Fixture: mock settings βββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def mock_settings(monkeypatch): | |
| monkeypatch.setenv("LINE_CHANNEL_SECRET", "test_secret") | |
| monkeypatch.setenv("LINE_CHANNEL_ACCESS_TOKEN", "test_token") | |
| monkeypatch.setenv("HF_API_TOKEN", "hf_test") | |
| monkeypatch.setenv("DATABASE_URL", "postgresql://u:p@localhost/test") | |
| monkeypatch.setenv("REDIS_URL", "redis://localhost:6379") | |
| # βββ Tests ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| class TestSignatureVerification: | |
| def test_valid_signature(self): | |
| from app.main import verify_line_signature | |
| body = b'{"test": "data"}' | |
| sig = make_signature(body, "test_secret") | |
| assert verify_line_signature(body, sig) is True | |
| def test_invalid_signature(self): | |
| from app.main import verify_line_signature | |
| body = b'{"test": "data"}' | |
| assert verify_line_signature(body, "wrong_sig") is False | |
| def test_empty_signature(self): | |
| from app.main import verify_line_signature | |
| assert verify_line_signature(b"body", "") is False | |
| class TestPayloadParsing: | |
| def test_parse_text_message(self): | |
| from app.models import LineWebhookPayload | |
| raw = """{ | |
| "destination": "U123", | |
| "events": [{ | |
| "type": "message", | |
| "timestamp": 1700000000000, | |
| "replyToken": "token123", | |
| "source": {"type": "user", "userId": "Uabc"}, | |
| "message": {"id": "m1", "type": "text", "text": "ΰΈͺΰΈ§ΰΈ±ΰΈͺΰΈΰΈ΅ΰΈΰΈ£ΰΈ±ΰΈ"} | |
| }] | |
| }""" | |
| payload = LineWebhookPayload.model_validate_json(raw) | |
| assert len(payload.events) == 1 | |
| assert payload.events[0].message.text == "ΰΈͺΰΈ§ΰΈ±ΰΈͺΰΈΰΈ΅ΰΈΰΈ£ΰΈ±ΰΈ" | |
| def test_skip_non_text_event(self): | |
| from app.models import LineWebhookPayload | |
| raw = """{ | |
| "destination": "U123", | |
| "events": [{ | |
| "type": "follow", | |
| "timestamp": 1700000000000, | |
| "source": {"type": "user", "userId": "Uabc"} | |
| }] | |
| }""" | |
| payload = LineWebhookPayload.model_validate_json(raw) | |
| assert payload.events[0].type == "follow" | |
| assert payload.events[0].message is None | |
| class TestSentimentResult: | |
| def test_label_mapping_positive(self): | |
| from app.models import SentimentResult | |
| r = SentimentResult( | |
| label="positive", | |
| score=0.91, | |
| raw_scores={"positive": 0.91, "neutral": 0.07, "negative": 0.02}, | |
| ) | |
| assert r.label == "positive" | |
| assert r.score == 0.91 | |
| def test_fallback_is_neutral(self): | |
| from app.sentiment import _fallback_result | |
| r = _fallback_result() | |
| assert r.label == "neutral" | |
| assert r.score == 0.0 | |