from __future__ import annotations from unittest.mock import AsyncMock, patch import pytest from fastapi.testclient import TestClient from mcp_sentiment.server import create_app from mcp_common.auth import Principal, TokenStore @pytest.fixture def http(): store = TokenStore( tokens={ "ct": Principal("core", {"core"}), "ot": Principal("observer", {"observer"}), } ) app = create_app(cryptopanic_key="testkey", token_store=store) return TestClient(app) # --- Health --- def test_health(http): assert http.get("/health").status_code == 200 # --- get_crypto_news --- def test_get_crypto_news_core_ok(http): with patch( "mcp_sentiment.server.fetch_crypto_news", new=AsyncMock(return_value={"headlines": []}), ): r = http.post( "/tools/get_crypto_news", headers={"Authorization": "Bearer ct"}, json={"limit": 5}, ) assert r.status_code == 200 def test_get_crypto_news_observer_ok(http): with patch( "mcp_sentiment.server.fetch_crypto_news", new=AsyncMock(return_value={"headlines": []}), ): r = http.post( "/tools/get_crypto_news", headers={"Authorization": "Bearer ot"}, json={}, ) assert r.status_code == 200 def test_get_crypto_news_no_auth_401(http): r = http.post("/tools/get_crypto_news", json={}) assert r.status_code == 401 # --- get_social_sentiment --- def test_get_social_sentiment_core_ok(http): with patch( "mcp_sentiment.server.fetch_social_sentiment", new=AsyncMock(return_value={"fear_greed_index": 65, "fear_greed_label": "Greed"}), ): r = http.post( "/tools/get_social_sentiment", headers={"Authorization": "Bearer ct"}, json={}, ) assert r.status_code == 200 assert r.json()["fear_greed_index"] == 65 def test_get_social_sentiment_observer_ok(http): with patch( "mcp_sentiment.server.fetch_social_sentiment", new=AsyncMock(return_value={"fear_greed_index": 65}), ): r = http.post( "/tools/get_social_sentiment", headers={"Authorization": "Bearer ot"}, json={}, ) assert r.status_code == 200 def test_get_social_sentiment_no_auth_401(http): r = http.post("/tools/get_social_sentiment", json={}) assert r.status_code == 401 # --- get_funding_rates --- def test_get_funding_rates_core_ok(http): with patch( "mcp_sentiment.server.fetch_funding_rates", new=AsyncMock(return_value={"rates": []}), ): r = http.post( "/tools/get_funding_rates", headers={"Authorization": "Bearer ct"}, json={}, ) assert r.status_code == 200 def test_get_funding_rates_observer_ok(http): with patch( "mcp_sentiment.server.fetch_funding_rates", new=AsyncMock(return_value={"rates": []}), ): r = http.post( "/tools/get_funding_rates", headers={"Authorization": "Bearer ot"}, json={}, ) assert r.status_code == 200 def test_get_funding_rates_no_auth_401(http): r = http.post("/tools/get_funding_rates", json={}) assert r.status_code == 401 # --- get_world_news --- def test_get_world_news_core_ok(http): with patch( "mcp_sentiment.server.fetch_world_news", new=AsyncMock(return_value={"articles": [], "count": 0}), ): r = http.post( "/tools/get_world_news", headers={"Authorization": "Bearer ct"}, json={}, ) assert r.status_code == 200 def test_get_world_news_observer_ok(http): with patch( "mcp_sentiment.server.fetch_world_news", new=AsyncMock(return_value={"articles": [], "count": 0}), ): r = http.post( "/tools/get_world_news", headers={"Authorization": "Bearer ot"}, json={}, ) assert r.status_code == 200 def test_get_world_news_no_auth_401(http): r = http.post("/tools/get_world_news", json={}) assert r.status_code == 401