# -*- coding: utf-8 -*- """Tests for the extracted trading service app surface.""" from fastapi.testclient import TestClient from backend.apps.trading_service import create_app from shared.schema import CompanyNews, FinancialMetrics, InsiderTrade, LineItem, Price def test_trading_service_routes_are_exposed(): app = create_app() paths = {route.path for route in app.routes} assert "/health" in paths assert "/api/prices" in paths assert "/api/financials" in paths assert "/api/news" in paths assert "/api/insider-trades" in paths assert "/api/market/status" in paths assert "/api/market-cap" in paths assert "/api/line-items" in paths def test_trading_service_prices_endpoint(monkeypatch): monkeypatch.setattr( "backend.domains.trading.get_prices_payload", lambda ticker, start_date, end_date: { "ticker": ticker, "prices": [ Price( open=1.0, close=2.0, high=2.5, low=0.5, volume=100, time="2026-03-20", ) ], }, ) with TestClient(create_app()) as client: response = client.get( "/api/prices", params={ "ticker": "AAPL", "start_date": "2026-03-01", "end_date": "2026-03-20", }, ) assert response.status_code == 200 assert response.json()["ticker"] == "AAPL" assert response.json()["prices"][0]["close"] == 2.0 def test_trading_service_financials_endpoint(monkeypatch): monkeypatch.setattr( "backend.domains.trading.get_financials_payload", lambda ticker, end_date, period, limit: { "financial_metrics": [ FinancialMetrics( ticker=ticker, report_period=end_date, period=period, currency="USD", market_cap=123.0, enterprise_value=None, price_to_earnings_ratio=None, price_to_book_ratio=None, price_to_sales_ratio=None, enterprise_value_to_ebitda_ratio=None, enterprise_value_to_revenue_ratio=None, free_cash_flow_yield=None, peg_ratio=None, gross_margin=None, operating_margin=None, net_margin=None, return_on_equity=None, return_on_assets=None, return_on_invested_capital=None, asset_turnover=None, inventory_turnover=None, receivables_turnover=None, days_sales_outstanding=None, operating_cycle=None, working_capital_turnover=None, current_ratio=None, quick_ratio=None, cash_ratio=None, operating_cash_flow_ratio=None, debt_to_equity=None, debt_to_assets=None, interest_coverage=None, revenue_growth=None, earnings_growth=None, book_value_growth=None, earnings_per_share_growth=None, free_cash_flow_growth=None, operating_income_growth=None, ebitda_growth=None, payout_ratio=None, earnings_per_share=None, book_value_per_share=None, free_cash_flow_per_share=None, ) ] }, ) with TestClient(create_app()) as client: response = client.get( "/api/financials", params={"ticker": "AAPL", "end_date": "2026-03-20"}, ) assert response.status_code == 200 assert response.json()["financial_metrics"][0]["ticker"] == "AAPL" def test_trading_service_news_and_insider_endpoints(monkeypatch): monkeypatch.setattr( "backend.domains.trading.get_news_payload", lambda ticker, end_date, start_date=None, limit=1000: { "news": [ CompanyNews( ticker=ticker, title="News title", source="polygon", url="https://example.com/news", date=end_date, ) ] }, ) monkeypatch.setattr( "backend.domains.trading.get_insider_trades_payload", lambda ticker, end_date, start_date=None, limit=1000: { "insider_trades": [ InsiderTrade(ticker=ticker, filing_date=end_date) ] }, ) with TestClient(create_app()) as client: news_response = client.get( "/api/news", params={"ticker": "AAPL", "end_date": "2026-03-20"}, ) insider_response = client.get( "/api/insider-trades", params={"ticker": "AAPL", "end_date": "2026-03-20"}, ) assert news_response.status_code == 200 assert news_response.json()["news"][0]["title"] == "News title" assert insider_response.status_code == 200 assert insider_response.json()["insider_trades"][0]["ticker"] == "AAPL" def test_trading_service_market_status_endpoint(monkeypatch): class _FakeMarketService: def get_market_status(self): return {"status": "open", "status_text": "Open"} monkeypatch.setattr( "backend.domains.trading.get_market_status_payload", lambda: _FakeMarketService().get_market_status(), ) with TestClient(create_app()) as client: response = client.get("/api/market/status") assert response.status_code == 200 assert response.json() == {"status": "open", "status_text": "Open"} def test_trading_service_market_cap_endpoint(monkeypatch): monkeypatch.setattr( "backend.domains.trading.get_market_cap_payload", lambda ticker, end_date: { "ticker": ticker, "end_date": end_date, "market_cap": 3.5e12, }, ) with TestClient(create_app()) as client: response = client.get( "/api/market-cap", params={"ticker": "AAPL", "end_date": "2026-03-20"}, ) assert response.status_code == 200 assert response.json() == { "ticker": "AAPL", "end_date": "2026-03-20", "market_cap": 3.5e12, } def test_trading_service_contract_stability(): """Verify trading service API maintains contract stability.""" app = create_app() routes = {route.path: route for route in app.routes if hasattr(route, "methods")} # Health endpoint assert "/health" in routes # Trading data endpoints assert "/api/prices" in routes assert "/api/financials" in routes assert "/api/news" in routes assert "/api/insider-trades" in routes assert "/api/market/status" in routes assert "/api/market-cap" in routes assert "/api/line-items" in routes # Verify all are GET endpoints (read-only service) for path in ["/api/prices", "/api/financials", "/api/news", "/api/insider-trades", "/api/market/status", "/api/market-cap", "/api/line-items"]: assert "GET" in routes[path].methods def test_trading_service_prices_contract(monkeypatch): """Test prices endpoint maintains response contract.""" monkeypatch.setattr( "backend.domains.trading.get_prices_payload", lambda ticker, start_date, end_date: { "ticker": ticker, "prices": [ Price( open=1.0, close=2.0, high=2.5, low=0.5, volume=100, time="2026-03-20", ) ], }, ) with TestClient(create_app()) as client: response = client.get( "/api/prices", params={ "ticker": "AAPL", "start_date": "2026-03-01", "end_date": "2026-03-20", }, ) assert response.status_code == 200 payload = response.json() assert "ticker" in payload assert "prices" in payload assert isinstance(payload["prices"], list) if payload["prices"]: price = payload["prices"][0] assert "open" in price assert "close" in price assert "high" in price assert "low" in price assert "volume" in price assert "time" in price def test_trading_service_financials_contract(monkeypatch): """Test financials endpoint maintains response contract.""" monkeypatch.setattr( "backend.domains.trading.get_financials_payload", lambda ticker, end_date, period, limit: { "financial_metrics": [ FinancialMetrics( ticker=ticker, report_period=end_date, period=period, currency="USD", market_cap=123.0, enterprise_value=None, price_to_earnings_ratio=None, price_to_book_ratio=None, price_to_sales_ratio=None, enterprise_value_to_ebitda_ratio=None, enterprise_value_to_revenue_ratio=None, free_cash_flow_yield=None, peg_ratio=None, gross_margin=None, operating_margin=None, net_margin=None, return_on_equity=None, return_on_assets=None, return_on_invested_capital=None, asset_turnover=None, inventory_turnover=None, receivables_turnover=None, days_sales_outstanding=None, operating_cycle=None, working_capital_turnover=None, current_ratio=None, quick_ratio=None, cash_ratio=None, operating_cash_flow_ratio=None, debt_to_equity=None, debt_to_assets=None, interest_coverage=None, revenue_growth=None, earnings_growth=None, book_value_growth=None, earnings_per_share_growth=None, free_cash_flow_growth=None, operating_income_growth=None, ebitda_growth=None, payout_ratio=None, earnings_per_share=None, book_value_per_share=None, free_cash_flow_per_share=None, ) ] }, ) with TestClient(create_app()) as client: response = client.get( "/api/financials", params={"ticker": "AAPL", "end_date": "2026-03-20"}, ) assert response.status_code == 200 payload = response.json() assert "financial_metrics" in payload assert isinstance(payload["financial_metrics"], list) def test_trading_service_market_status_contract(monkeypatch): """Test market status endpoint maintains response contract.""" monkeypatch.setattr( "backend.domains.trading.get_market_status_payload", lambda: {"status": "open", "status_text": "Open", "next_open": "09:30"}, ) with TestClient(create_app()) as client: response = client.get("/api/market/status") assert response.status_code == 200 payload = response.json() assert "status" in payload def test_trading_service_market_cap_contract(monkeypatch): """Test market cap endpoint maintains response contract.""" monkeypatch.setattr( "backend.domains.trading.get_market_cap_payload", lambda ticker, end_date: { "ticker": ticker, "end_date": end_date, "market_cap": 3.5e12, }, ) with TestClient(create_app()) as client: response = client.get( "/api/market-cap", params={"ticker": "AAPL", "end_date": "2026-03-20"}, ) assert response.status_code == 200 payload = response.json() assert "ticker" in payload assert "end_date" in payload assert "market_cap" in payload def test_trading_service_line_items_endpoint(monkeypatch): monkeypatch.setattr( "backend.domains.trading.get_line_items_payload", lambda ticker, line_items, end_date, period, limit: { "search_results": [ LineItem( ticker=ticker, report_period=end_date, period=period, currency="USD", free_cash_flow=123.0, ) ] }, ) with TestClient(create_app()) as client: response = client.get( "/api/line-items", params=[ ("ticker", "AAPL"), ("line_items", "free_cash_flow"), ("end_date", "2026-03-20"), ], ) assert response.status_code == 200 assert response.json()["search_results"][0]["ticker"] == "AAPL" assert response.json()["search_results"][0]["free_cash_flow"] == 123.0