from __future__ import annotations import pytest from yuxi.channel.adapters import ( HttpErrorClassifier, MediaUploadAdapter, TokenAuthAdapter, TypingIndicatorAdapter, WebhookSignatureAdapter, ) from yuxi.channel.exceptions import ChannelErrorClassification class TestHttpErrorClassifier: @pytest.fixture def classifier(self): return HttpErrorClassifier() def test_429_returns_rate_limited(self, classifier): assert classifier.classify(429) == ChannelErrorClassification.RATE_LIMITED def test_400_returns_permanent(self, classifier): assert classifier.classify(400) == ChannelErrorClassification.PERMANENT def test_404_returns_permanent(self, classifier): assert classifier.classify(404) == ChannelErrorClassification.PERMANENT def test_500_returns_retryable(self, classifier): assert classifier.classify(500) == ChannelErrorClassification.RETRYABLE def test_503_returns_retryable(self, classifier): assert classifier.classify(503) == ChannelErrorClassification.RETRYABLE def test_none_status_returns_retryable(self, classifier): assert classifier.classify(None) == ChannelErrorClassification.RETRYABLE class TestMediaUploadAdapter: @pytest.fixture def adapter(self): return MediaUploadAdapter(base_url="https://example.com") async def test_upload_returns_none(self, adapter): assert await adapter.upload({"url": "a.jpg"}) is None async def test_download_returns_none(self, adapter): assert await adapter.download("https://example.com/a.jpg") is None def test_base_url_stored(self): adapter = MediaUploadAdapter(base_url="https://cdn.example.com") assert adapter.base_url == "https://cdn.example.com" class TestTokenAuthAdapter: @pytest.fixture def adapter(self): return TokenAuthAdapter(app_id="app", app_secret="secret", token_url="https://example.com/token") async def test_get_token_returns_none(self, adapter): assert await adapter.get_token() is None async def test_refresh_token_returns_none(self, adapter): assert await adapter.refresh_token() is None def test_credentials_stored(self): adapter = TokenAuthAdapter(app_id="a", app_secret="s", token_url="https://t") assert adapter.app_id == "a" assert adapter.app_secret == "s" assert adapter.token_url == "https://t" class TestTypingIndicatorAdapter: @pytest.fixture def adapter(self): return TypingIndicatorAdapter(interval_seconds=3.0) async def test_start_returns_none(self, adapter): assert await adapter.start("session-1") is None async def test_stop_returns_none(self, adapter): assert await adapter.stop("session-1") is None def test_interval_stored(self): adapter = TypingIndicatorAdapter(interval_seconds=7.0) assert adapter.interval_seconds == 7.0 class TestWebhookSignatureAdapter: @pytest.fixture def adapter(self): return WebhookSignatureAdapter(secret="shhh", signature_header="X-Signature") def test_compute_signature_returns_none(self, adapter): assert adapter.compute_signature(b"body") is None def test_validate_with_no_signature_returns_true(self, adapter): assert adapter.validate(b"body", None) is True def test_validate_with_signature_returns_false(self, adapter): assert adapter.validate(b"body", "sig") is False def test_config_stored(self): adapter = WebhookSignatureAdapter(secret="secret", signature_header="X-Hub-Signature") assert adapter.secret == "secret" assert adapter.signature_header == "X-Hub-Signature"