Spaces:
Paused
Paused
File size: 3,670 Bytes
82eac1b | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | """
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 βββββββββββββββββββββββββββββββββββββββββββββββββββ
@pytest.fixture(autouse=True)
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
|