From 8320ea0ee7b75541fe88c82baf00e2cda99115ce Mon Sep 17 00:00:00 2001 From: Sven Alaric Brandt Date: Fri, 7 Nov 2025 09:13:54 +0000 Subject: [PATCH 1/2] Add unit tests for onchain_agent.py --- .../core/__pycache__/config.cpython-313.pyc | Bin 1570 -> 1570 bytes .../__pycache__/orchestrator.cpython-313.pyc | Bin 19087 -> 19215 bytes .../report_processor.cpython-313.pyc | Bin 3157 -> 3157 bytes ...e_audit_agent.cpython-313-pytest-8.4.2.pyc | Bin 25503 -> 25503 bytes ...onchain_agent.cpython-313-pytest-8.4.2.pyc | Bin 24092 -> 47586 bytes .../agents/tests/test_onchain_agent.py | 129 ++++++++++++++++++ backend/logs/app.log | 116 ++++++++++++++++ ..._orchestrator.cpython-313-pytest-8.4.2.pyc | Bin 8445 -> 8445 bytes ...trator_config.cpython-313-pytest-8.4.2.pyc | Bin 12663 -> 12663 bytes 9 files changed, 245 insertions(+) diff --git a/backend/app/core/__pycache__/config.cpython-313.pyc b/backend/app/core/__pycache__/config.cpython-313.pyc index 45775915f35f5da1f7f824bd17b585f43d0b88e7..3107c7bc87a4647487584937af486485383d7701 100644 GIT binary patch delta 20 acmZ3)vxtZLGcPX}0}urB@NMK4X9EB*fCI$< delta 20 acmZ3)vxtZLGcPX}0}xEx%e#?VoDBdrb_BQp diff --git a/backend/app/core/__pycache__/orchestrator.cpython-313.pyc b/backend/app/core/__pycache__/orchestrator.cpython-313.pyc index 15bf2520fa2aabd7de5661bce3dc60e956a633ec..09e930ded98cd20f25caed2396e0c1501c7761b6 100644 GIT binary patch delta 566 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%0DeW6a!~Y-rc*IEvv7QROl}NZ2#Meg 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 Fe+ROOHhusA delta 2165 zcmb`IO>7fK7=|Ca;-nW+$2?VHzA`oZh-3V{uni3$E{Agx&zS()d z_nXtVHXs3f0c>Z*u#nk}<{plyKrLvu00V#_rQv`$RS*?*fKr*7 zGH4nzf`Anm1f0NLzz#ToA@+B;OHdkkJGkse4Z+=pV5N0E8PhJd&O7!?FA0xXLw#ve zUsI(%*s(S`;)agYCO;9i6Ppr_;ub7j;o53#+KE`BG?HkU0-7rYz#y6ejPf!q@l<-k zLa~tj0A|9Eh_B?N2hlTLa|o>?Y&N$369pE&v59VEw_~4^)7rzB-I=T=sce+)QsoIT zFXyDJQoSBoWLvQL|7-EEDYa@XE|dCJ>*}E8eM&IGG9v*NPk4!}?Mgf%)+}Fv{m~ZC zX50O?;0inwd;?ktyv=a-NV0 zZ9{*`CP-Is+*V!_C30?(qT~&JwC#2}Z7H0a!{eT3-R|X*lGc=B@vv^Z3YaGNauZxlYJgwxR!1?OwXi!sd=PkDFWm zfMn8hcW7TTicP#Ci<*VGqww;F2caJ>@{J^`>+Tr17M0buAq)AoED|8?G z@lH?u5P!5}n85DcnJMZPDX;3*lTudIEs9E)zQ5L7hEC{?jPiXxE6H>eL1TajoCaiI z3P7dN^S}%+%TcPKVYH18m~%%?K3SL)`{+-6j31^N1z)g#Erby5@o&$F>$$a_^coSb E0Z1p5umAu6 diff --git a/backend/app/services/agents/tests/test_onchain_agent.py b/backend/app/services/agents/tests/test_onchain_agent.py index 6899f39..8ae2ecc 100644 --- a/backend/app/services/agents/tests/test_onchain_agent.py +++ b/backend/app/services/agents/tests/test_onchain_agent.py @@ -206,3 +206,132 @@ async def test_fetch_tokenomics_unexpected_error_raises_onchainagentexception(mo with pytest.raises(OnchainAgentException): await fetch_tokenomics(url="http://test.com/tokenomics") assert mock_client_instance.get.call_count == 3 # Retries should still happen + +# --- New tests for successful fetching and schema validation --- + +@pytest.mark.asyncio +@patch('httpx.AsyncClient') +async def test_fetch_onchain_metrics_success_and_schema(mock_async_client): + mock_client_instance = AsyncMock() + mock_async_client.return_value.__aenter__.return_value = mock_client_instance + + expected_metrics = { + "total_transactions": 1000, + "active_users": 500, + "average_transaction_value": 150.75, + "timestamp": "2023-10-27T10:00:00Z" + } + mock_client_instance.get.return_value = create_mock_response(200, expected_metrics) + + result = await fetch_onchain_metrics(url="http://test.com/onchain") + assert result == expected_metrics + assert "total_transactions" in result + assert "active_users" in result + assert "average_transaction_value" in result + assert "timestamp" in result + assert isinstance(result["total_transactions"], int) + assert isinstance(result["active_users"], int) + assert isinstance(result["average_transaction_value"], float) + assert isinstance(result["timestamp"], str) + +@pytest.mark.asyncio +@patch('httpx.AsyncClient') +async def test_fetch_tokenomics_success_and_schema(mock_async_client): + mock_client_instance = AsyncMock() + mock_async_client.return_value.__aenter__.return_value = mock_client_instance + + expected_tokenomics = { + "total_supply": "1000000000", + "circulating_supply": "800000000", + "market_cap_usd": "1500000000.50", + "token_price_usd": "1.50", + "last_updated": "2023-10-27T10:00:00Z" + } + mock_client_instance.get.return_value = create_mock_response(200, expected_tokenomics) + + result = await fetch_tokenomics(url="http://test.com/tokenomics") + assert result == expected_tokenomics + assert "total_supply" in result + assert "circulating_supply" in result + assert "market_cap_usd" in result + assert "token_price_usd" in result + assert "last_updated" in result + assert isinstance(result["total_supply"], str) + assert isinstance(result["circulating_supply"], str) + assert isinstance(result["market_cap_usd"], str) + assert isinstance(result["token_price_usd"], str) + assert isinstance(result["last_updated"], str) + +# --- New tests for handling missing fields --- + +@pytest.mark.asyncio +@patch('httpx.AsyncClient') +async def test_fetch_onchain_metrics_missing_fields(mock_async_client): + mock_client_instance = AsyncMock() + mock_async_client.return_value.__aenter__.return_value = mock_client_instance + + # Simulate a response with some missing fields + incomplete_metrics = { + "total_transactions": 1234, + "timestamp": "2023-10-27T11:00:00Z" + } + mock_client_instance.get.return_value = create_mock_response(200, incomplete_metrics) + + result = await fetch_onchain_metrics(url="http://test.com/onchain") + assert result == incomplete_metrics + # The agent should return whatever it gets, schema validation is typically done downstream + assert "total_transactions" in result + assert "active_users" not in result + assert "average_transaction_value" not in result + assert "timestamp" in result + +@pytest.mark.asyncio +@patch('httpx.AsyncClient') +async def test_fetch_tokenomics_missing_fields(mock_async_client): + mock_client_instance = AsyncMock() + mock_async_client.return_value.__aenter__.return_value = mock_client_instance + + # Simulate a response with some missing fields + incomplete_tokenomics = { + "total_supply": "999999999", + "token_price_usd": "2.10" + } + mock_client_instance.get.return_value = create_mock_response(200, incomplete_tokenomics) + + result = await fetch_tokenomics(url="http://test.com/tokenomics") + assert result == incomplete_tokenomics + assert "total_supply" in result + assert "circulating_supply" not in result + assert "market_cap_usd" not in result + assert "token_price_usd" in result + assert "last_updated" not in result + +# --- New tests for invalid token IDs (simulated via API response) --- + +@pytest.mark.asyncio +@patch('httpx.AsyncClient') +async def test_fetch_onchain_metrics_invalid_token_id(mock_async_client): + mock_client_instance = AsyncMock() + mock_async_client.return_value.__aenter__.return_value = mock_client_instance + + # Simulate an API response indicating an invalid token ID (e.g., 400 Bad Request) + error_response_data = {"error": "Invalid token ID provided"} + mock_client_instance.get.return_value = create_mock_response(400, error_response_data) + + with pytest.raises(OnchainAgentHTTPError) as excinfo: + await fetch_onchain_metrics(url="http://test.com/onchain", params={"token_id": "invalid"}) + assert excinfo.value.status_code == 400 + +@pytest.mark.asyncio +@patch('httpx.AsyncClient') +async def test_fetch_tokenomics_invalid_token_id(mock_async_client): + mock_client_instance = AsyncMock() + mock_async_client.return_value.__aenter__.return_value = mock_client_instance + + # Simulate an API response indicating an invalid token ID (e.g., 404 Not Found) + error_response_data = {"message": "Token not found"} + mock_client_instance.get.return_value = create_mock_response(404, error_response_data) + + with pytest.raises(OnchainAgentHTTPError) as excinfo: + await fetch_tokenomics(url="http://test.com/tokenomics", params={"token_id": "nonexistent"}) + assert excinfo.value.status_code == 404 \ No newline at end of file diff --git a/backend/logs/app.log b/backend/logs/app.log index d756dab..26f1561 100644 --- a/backend/logs/app.log +++ b/backend/logs/app.log @@ -3765,3 +3765,119 @@ Exception: Agent failed 2025-11-07 09:20:00,606 - services - WARNING - Report with id non_existent_report not found when attempting to retrieve data. 2025-11-07 09:20:00,606 - api - ERROR - Report with id non_existent_report not found or not completed for data request. 2025-11-07 09:20:00,606 - api - ERROR - ReportNotFoundException: Report not found or not completed +2025-11-07 15:13:21,600 - orchestrator - WARNING - Configuration Error: ONCHAIN_METRICS_URL is missing. Skipping agent registration. +2025-11-07 15:13:21,600 - orchestrator - WARNING - Onchain Data Agent will not be registered due to invalid configuration. +2025-11-07 15:13:21,600 - orchestrator - INFO - Registering agent: social_sentiment_agent +2025-11-07 15:13:21,600 - orchestrator - INFO - Registering agent: team_documentation_agent +2025-11-07 15:13:21,600 - orchestrator - WARNING - Configuration Error: CODE_AUDIT_REPO_URL is missing. Skipping agent registration. +2025-11-07 15:13:21,600 - orchestrator - WARNING - Code/Audit Agent will not be registered due to invalid CODE_AUDIT_REPO_URL configuration. +2025-11-07 15:13:21,600 - orchestrator - INFO - Registering agent: AgentOne +2025-11-07 15:13:21,600 - orchestrator - INFO - Registering agent: AgentTwo +2025-11-07 15:13:48,005 - orchestrator - INFO - Registering agent: price_agent +2025-11-07 15:13:48,005 - orchestrator - INFO - Registering agent: trend_agent +2025-11-07 15:13:48,005 - orchestrator - INFO - Registering agent: volume_agent +2025-11-07 15:13:48,005 - orchestrator - INFO - Executing agents for report_id: test_report_1, token_id: test_token_1 +2025-11-07 15:13:48,005 - orchestrator - INFO - Agent price_agent completed for report test_report_1. +2025-11-07 15:13:48,005 - orchestrator - INFO - Agent trend_agent completed for report test_report_1. +2025-11-07 15:13:48,005 - orchestrator - INFO - Agent volume_agent completed for report test_report_1. +2025-11-07 15:13:48,006 - orchestrator - INFO - Aggregating results from executed agents. +2025-11-07 15:13:48,011 - orchestrator - INFO - Registering agent: price_agent +2025-11-07 15:13:48,011 - orchestrator - INFO - Registering agent: trend_agent +2025-11-07 15:13:48,011 - orchestrator - INFO - Registering agent: volume_agent +2025-11-07 15:13:48,011 - orchestrator - INFO - Executing agents for report_id: test_report_3, token_id: test_token_3 +2025-11-07 15:13:48,011 - orchestrator - ERROR - Agent price_agent failed for report test_report_3 +Traceback (most recent call last): + File "/home/repositories/LumintelAnalytics/ChainReport-API/backend/app/core/orchestrator.py", line 54, in execute_agents + result = await asyncio.wait_for(task, timeout=settings.AGENT_TIMEOUT) # Added timeout + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/lib/python3.13/asyncio/tasks.py", line 507, in wait_for + return await fut + ^^^^^^^^^ + File "/usr/lib/python3.13/unittest/mock.py", line 2321, in _execute_mock_call + raise effect +Exception: Agent error +2025-11-07 15:13:48,112 - orchestrator - INFO - Agent trend_agent completed for report test_report_3. +2025-11-07 15:13:48,112 - orchestrator - INFO - Agent volume_agent completed for report test_report_3. +2025-11-07 15:13:48,112 - orchestrator - INFO - Aggregating results from executed agents. +2025-11-07 15:13:48,118 - orchestrator - INFO - Registering agent: price_agent +2025-11-07 15:13:48,119 - orchestrator - INFO - Registering agent: trend_agent +2025-11-07 15:13:48,119 - orchestrator - INFO - Registering agent: volume_agent +2025-11-07 15:13:48,119 - orchestrator - INFO - Executing agents for report_id: concurrent_report, token_id: concurrent_token +2025-11-07 15:13:48,123 - orchestrator - INFO - Agent price_agent completed for report concurrent_report. +2025-11-07 15:13:48,123 - orchestrator - INFO - Agent trend_agent completed for report concurrent_report. +2025-11-07 15:13:48,123 - orchestrator - INFO - Agent volume_agent completed for report concurrent_report. +2025-11-07 15:13:48,123 - orchestrator - INFO - Aggregating results from executed agents. +2025-11-07 15:13:48,126 - orchestrator - INFO - Registering agent: AgentOne +2025-11-07 15:13:48,126 - orchestrator - INFO - Registering agent: AgentTwo +2025-11-07 15:13:48,126 - orchestrator - INFO - Executing agents concurrently for report_id: test_report_id_success, token_id: test_token_id +2025-11-07 15:13:48,126 - orchestrator - INFO - Executing agents for report_id: test_report_id_success, token_id: test_token_id +2025-11-07 15:13:48,126 - orchestrator - INFO - Agent AgentOne completed for report test_report_id_success. +2025-11-07 15:13:48,126 - orchestrator - INFO - Agent AgentTwo completed for report test_report_id_success. +2025-11-07 15:13:48,126 - orchestrator - INFO - Aggregating results from executed agents. +2025-11-07 15:13:48,126 - orchestrator - INFO - Report test_report_id_success status updated to completed. +2025-11-07 15:13:48,128 - orchestrator - INFO - Registering agent: AgentOne +2025-11-07 15:13:48,128 - orchestrator - INFO - Registering agent: AgentFailing +2025-11-07 15:13:48,128 - orchestrator - INFO - Executing agents concurrently for report_id: test_report_id_failure, token_id: test_token_id +2025-11-07 15:13:48,128 - orchestrator - INFO - Executing agents for report_id: test_report_id_failure, token_id: test_token_id +2025-11-07 15:13:48,129 - orchestrator - INFO - Agent AgentOne completed for report test_report_id_failure. +2025-11-07 15:13:48,129 - orchestrator - ERROR - Agent AgentFailing failed for report test_report_id_failure +Traceback (most recent call last): + File "/home/repositories/LumintelAnalytics/ChainReport-API/backend/app/core/orchestrator.py", line 54, in execute_agents + result = await asyncio.wait_for(task, timeout=settings.AGENT_TIMEOUT) # Added timeout + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/lib/python3.13/asyncio/tasks.py", line 507, in wait_for + return await fut + ^^^^^^^^^ + File "/usr/lib/python3.13/unittest/mock.py", line 2321, in _execute_mock_call + raise effect +Exception: Agent failed +2025-11-07 15:13:48,129 - orchestrator - INFO - Aggregating results from executed agents. +2025-11-07 15:13:48,129 - orchestrator - ERROR - Report test_report_id_failure failed due to one or more agent failures. +2025-11-07 15:13:48,129 - orchestrator - INFO - Report test_report_id_failure status updated to failed. +2025-11-07 15:13:48,131 - orchestrator - INFO - Registering agent: a +2025-11-07 15:13:48,132 - orchestrator - WARNING - Configuration Error: ONCHAIN_METRICS_URL is missing. Skipping agent registration. +2025-11-07 15:13:48,132 - orchestrator - WARNING - Onchain Data Agent will not be registered due to invalid configuration. +2025-11-07 15:13:48,132 - orchestrator - INFO - Registering agent: social_sentiment_agent +2025-11-07 15:13:48,132 - orchestrator - INFO - Registering agent: team_documentation_agent +2025-11-07 15:13:48,132 - orchestrator - WARNING - Configuration Error: CODE_AUDIT_REPO_URL is missing. Skipping agent registration. +2025-11-07 15:13:48,132 - orchestrator - WARNING - Code/Audit Agent will not be registered due to invalid CODE_AUDIT_REPO_URL configuration. +2025-11-07 15:13:48,133 - orchestrator - INFO - Registering agent: dummy_agent +2025-11-07 15:13:48,133 - orchestrator - WARNING - Configuration Error: ONCHAIN_METRICS_URL is missing. Skipping agent registration. +2025-11-07 15:13:48,133 - orchestrator - WARNING - Onchain Data Agent will not be registered due to invalid configuration. +2025-11-07 15:13:48,133 - orchestrator - INFO - Registering agent: social_sentiment_agent +2025-11-07 15:13:48,133 - orchestrator - INFO - Registering agent: team_documentation_agent +2025-11-07 15:13:48,133 - orchestrator - WARNING - Configuration Error: CODE_AUDIT_REPO_URL is missing. Skipping agent registration. +2025-11-07 15:13:48,133 - orchestrator - WARNING - Code/Audit Agent will not be registered due to invalid CODE_AUDIT_REPO_URL configuration. +2025-11-07 15:13:48,157 - api - INFO - Received report generation request for token_id: test_token +2025-11-07 15:13:48,158 - services - INFO - Generating new report for token_id: test_token +2025-11-07 15:13:48,160 - api - INFO - Received data request for report_id: 5f665296-6ffe-454a-8e19-12dfa670b608 +2025-11-07 15:13:48,160 - services - INFO - Attempting to retrieve data for report_id: 5f665296-6ffe-454a-8e19-12dfa670b608 +2025-11-07 15:13:48,160 - services - INFO - Report 5f665296-6ffe-454a-8e19-12dfa670b608 is in status: processing, returning status only. +2025-11-07 15:13:48,160 - api - WARNING - Report 5f665296-6ffe-454a-8e19-12dfa670b608 is still processing. +2025-11-07 15:13:48,167 - api - INFO - Received report generation request for token_id: test_token +2025-11-07 15:13:48,167 - services - INFO - Generating new report for token_id: test_token +2025-11-07 15:13:48,167 - orchestrator - INFO - Executing agents concurrently for report_id: a398972f-0aa2-4e73-a15b-2787dbfd7d47, token_id: test_token +2025-11-07 15:13:48,167 - orchestrator - INFO - Executing agents for report_id: a398972f-0aa2-4e73-a15b-2787dbfd7d47, token_id: test_token +2025-11-07 15:13:48,167 - orchestrator - INFO - Calling Social Sentiment Agent for report_id: a398972f-0aa2-4e73-a15b-2787dbfd7d47, token_id: test_token +2025-11-07 15:13:48,167 - orchestrator - INFO - Calling Team and Documentation Agent for report_id: a398972f-0aa2-4e73-a15b-2787dbfd7d47, token_id: test_token +2025-11-07 15:13:48,167 - orchestrator - INFO - Scraping team profiles for token test_token from URLs: [] +2025-11-07 15:13:48,168 - orchestrator - INFO - Team profile scraping completed for token test_token. +2025-11-07 15:13:48,168 - orchestrator - WARNING - No whitepaper text source provided for token test_token. Skipping whitepaper analysis. +2025-11-07 15:13:51,227 - orchestrator - INFO - Social Sentiment Agent completed for report a398972f-0aa2-4e73-a15b-2787dbfd7d47. +2025-11-07 15:13:51,227 - orchestrator - INFO - Agent social_sentiment_agent completed for report a398972f-0aa2-4e73-a15b-2787dbfd7d47. +2025-11-07 15:13:51,227 - orchestrator - INFO - Agent team_documentation_agent completed for report a398972f-0aa2-4e73-a15b-2787dbfd7d47. +2025-11-07 15:13:51,227 - orchestrator - INFO - Agent AgentOne completed for report a398972f-0aa2-4e73-a15b-2787dbfd7d47. +2025-11-07 15:13:51,227 - orchestrator - INFO - Agent AgentTwo completed for report a398972f-0aa2-4e73-a15b-2787dbfd7d47. +2025-11-07 15:13:51,227 - orchestrator - INFO - Aggregating results from executed agents. +2025-11-07 15:13:51,227 - orchestrator - INFO - Report a398972f-0aa2-4e73-a15b-2787dbfd7d47 status updated to completed. +2025-11-07 15:13:51,229 - api - INFO - Received status request for report_id: a398972f-0aa2-4e73-a15b-2787dbfd7d47 +2025-11-07 15:13:51,229 - services - INFO - Retrieving status for report_id: a398972f-0aa2-4e73-a15b-2787dbfd7d47 from memory. +2025-11-07 15:13:51,231 - api - INFO - Received data request for report_id: a398972f-0aa2-4e73-a15b-2787dbfd7d47 +2025-11-07 15:13:51,231 - services - INFO - Attempting to retrieve data for report_id: a398972f-0aa2-4e73-a15b-2787dbfd7d47 +2025-11-07 15:13:51,231 - services - INFO - Report a398972f-0aa2-4e73-a15b-2787dbfd7d47 is completed, returning data. +2025-11-07 15:13:51,231 - api - INFO - Returning data for report_id: a398972f-0aa2-4e73-a15b-2787dbfd7d47 +2025-11-07 15:13:51,239 - api - INFO - Received data request for report_id: non_existent_report +2025-11-07 15:13:51,240 - services - INFO - Attempting to retrieve data for report_id: non_existent_report +2025-11-07 15:13:51,240 - services - WARNING - Report with id non_existent_report not found when attempting to retrieve data. +2025-11-07 15:13:51,240 - api - ERROR - Report with id non_existent_report not found or not completed for data request. +2025-11-07 15:13:51,240 - api - ERROR - ReportNotFoundException: Report not found or not completed diff --git a/backend/tests/__pycache__/test_orchestrator.cpython-313-pytest-8.4.2.pyc b/backend/tests/__pycache__/test_orchestrator.cpython-313-pytest-8.4.2.pyc index e4faa70f8f40191dc8513cf5c27af6c0e54dc6af..8340d2fd81a0904bf59d8b7b945d531324f705f4 100644 GIT binary patch delta 20 acmezC_}7v9GcPX}0}urB@NMM&qyPX%Mg`gc delta 20 acmezC_}7v9GcPX}0}y=L&byKOlL7!woChNS diff --git a/backend/tests/__pycache__/test_orchestrator_config.cpython-313-pytest-8.4.2.pyc b/backend/tests/__pycache__/test_orchestrator_config.cpython-313-pytest-8.4.2.pyc index 1a35732108b135228703a4c9411020b0ff0c1a96..2a2dcc168eca594ec3e58dba6c5e6dae66c345f6 100644 GIT binary patch delta 20 acmeyK^gW6DGcPX}0}urB@NMMIF$4fg3k911 delta 20 acmeyK^gW6DGcPX}0}$-q$Ged`#}EKf3I? Date: Fri, 7 Nov 2025 09:25:31 +0000 Subject: [PATCH 2/2] Fix: Explicitly patch retry in onchain agent tests for consistent error handling --- ...onchain_agent.cpython-313-pytest-8.4.2.pyc | Bin 47586 -> 49368 bytes .../agents/tests/test_onchain_agent.py | 36 +++++++++++------- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/backend/app/services/agents/tests/__pycache__/test_onchain_agent.cpython-313-pytest-8.4.2.pyc b/backend/app/services/agents/tests/__pycache__/test_onchain_agent.cpython-313-pytest-8.4.2.pyc index 0e463455404f2d244485169fea8b8f85f970ab42..ee7e242f7cbaf9234dcc7c921a113d631940c70c 100644 GIT binary patch delta 2812 zcmeHJZA=?w9KYvU?%L~Jucf851+K@N6b7^mMi8|dP@vlKwzCsg2_wP>G6Sr0Q%A5t zKRCA!Ec@#cH5&b*Q2V$e^L7(|INQ9k%QM|n3o3Pww~o<-T8~zaG{YR|SEi@Kqxkdq?km&*-Xw8hi9S38l1-xq! zT=4ouUSo)?;{@pGBwTrT173WPE8$DEB@9LNv5KG=!>kvnJ6*)HF?b|r10D9l&lM6l z8|-k%??~Uj5#Rdl(<%%M_|vz~Ebf@uv}fkgV0v=iv7nx5L5k`2jQp`PUqd&W;0@8K zZKRvi0Qp*2bMw**_{o8((gEYeB0SY_+~C9Ki5|pDp%YHLQLUeC#*TJ05bM}eN*zDGh zB!+OJ0Dr&S)`{`uy3K}7FbDlr7ogL_#~4azMCw>y31z=yz#Tzz`ml=HFlt>}?ZU@? zrWS={bX`*#5;fP$GJ?L830?>mvl9*!EaWDfT7spu}Mutj7)0g$O66i@D%E zhUrQj$@;huub>$?Vf8On+Ti zTOFXN{;(S#lU&_jP*g;Q?-a>~MVF$Au423BptVR=B`0I?xnZ$LK(Z>n(I7|YYrx$} zEz(IiP;W@q3=A7`Hx$RHier+BVq9OsFZo0(0iU00okIGJ8vxl%VdyAcOLfKz& z6J|@#$5=uFLWMSz(6|2b&nXfpAQTDM2t@)Zgd&aQgd&YzLJ@)`Kf;Mgmkt+A7U*%q zq!;1DWH}e04U_lja5jA^g$r2pQzDCtrfggwkDZd)K!Hk;J0ARh^x$6D@Zgxw1nMm`8Z!cCuB^}ztN zM($@mCtT@PxiS$UUZ`?qw;%3h3h~2o?1yctABM0W28kd3-D8VER*fV6=_5xhXd#|C z@U0X58vo;5wa8j9&rkaB8{YZcc<0Nt0_!G$SJng5Z{@J)V0`)NUYo>_*V+I8 delta 2310 zcmeHHU1(Eh7(U-QC+9c6OWT;*Hs>TVm7Yek)YVm@P1V#E7F!QlJ7q4lR&ABGMEApf zsBQy6WTU(yj3FiBwN#HQtHPuTWqPw@YmFBJ%fO2XLT4^S@WSs)(wc;Ipy2RgAIZ!6 zyzhDQ@#cBXbN2-EXO^~REf$Hw=eXHAaPOT;sG5i{TvuohQ>Rm9RpM+mpEfyzv zj2xZT8R*=*iteT%8K|I#gD`fe0^G5c;Pxt&Y>aC}x~XS-BfWtwOmNVQ(*px2xgxOUq&Ps?`Io0iW=f|K^J5EdXz%~e5=;OM2`yh z-gCowtCJmKbqQ?UuA+{PyyF%+4G!lj_@G^@v42;4s&>|;&58{Z zu0O24)S7VG+L{qsQ$j0rPo5l|W9#qAo{a2E%f1vF%*g(XQ`Mjg1MG2-}=317UvUcVdC)Ok7Im?4L&ka;#TySp(OtuvEgYpfVcZ9 z?C*F3O|Q3fP|S1)wTHOr%`DDu&~2M=<5mb^aGR1kZ2WCWz?D9PrxwqW#NKAWA$1Xr zRc|OfKvN2}r(A3yI3K`tGdc^&cU^GtvQlY^nXt~dp2i}b@i6&Q7mRzWpms`uU)^TJ zL())TAtu7Hsl3)c!kzgel1nIPjMGJ3ig5*v@i0GC54PhXMB^(!yBbjB=x6rWQ2(bR z{e8#!_bdI0#Bd_<7TzQgBtZkM(+f|o*kNyHm3@Ge21&4xAi%lKv)l!o9u@NJcdZ*; zWPeU)Kabt!>7|ifeq>7($ z2)I&CJpaGBl)Bl!o67(o_~!lk<;*2@wF5Tpj&lal*s=~&m-1~%TU#Y9UP{) zOla6)!p|Kh@j2e6TsL{yy#9uPWOy2{kw?h;U*ZrB80@u`JA{ZGVh23vZRc(lxx~IQ zmnh-yKXHkTFXj@@$uq|L5>9@WEHlW$_-?P!{K;fBdT9JT)@(zvp(PJnI0bwC(H|g? zeABpjQQ=V&#II?FeR8J>Z8zfA=9mgIYRobeT|+|U0*m274TOJQQ6ZN$FkGn4HC|+* Kj!eM)>)B_L`+M&I diff --git a/backend/app/services/agents/tests/test_onchain_agent.py b/backend/app/services/agents/tests/test_onchain_agent.py index 8ae2ecc..55a6f12 100644 --- a/backend/app/services/agents/tests/test_onchain_agent.py +++ b/backend/app/services/agents/tests/test_onchain_agent.py @@ -156,10 +156,12 @@ async def test_fetch_onchain_metrics_http_error_raises_onchainagenthttperror(moc create_mock_response(404) # All attempts fail ] - with pytest.raises(OnchainAgentHTTPError) as excinfo: - await fetch_onchain_metrics(url="http://test.com/onchain") - assert excinfo.value.status_code == 404 - assert mock_client_instance.get.call_count == 3 # Retries should still happen + with patch.object(fetch_onchain_metrics.retry, 'wait', new=wait_fixed(0.01)), \ + patch.object(fetch_onchain_metrics.retry, 'stop', new=stop_after_attempt(3)): + with pytest.raises(OnchainAgentHTTPError) as excinfo: + await fetch_onchain_metrics(url="http://test.com/onchain") + assert excinfo.value.status_code == 404 + assert mock_client_instance.get.call_count == 3 # Retries should still happen @pytest.mark.asyncio @patch('httpx.AsyncClient') @@ -172,9 +174,11 @@ async def test_fetch_onchain_metrics_unexpected_error_raises_onchainagentexcepti Exception("Unexpected error") ] - with pytest.raises(OnchainAgentException): - await fetch_onchain_metrics(url="http://test.com/onchain") - assert mock_client_instance.get.call_count == 3 # Retries should still happen + with patch.object(fetch_onchain_metrics.retry, 'wait', new=wait_fixed(0.01)), \ + patch.object(fetch_onchain_metrics.retry, 'stop', new=stop_after_attempt(3)): + with pytest.raises(OnchainAgentException): + await fetch_onchain_metrics(url="http://test.com/onchain") + assert mock_client_instance.get.call_count == 3 # Retries should still happen @pytest.mark.asyncio @patch('httpx.AsyncClient') @@ -187,10 +191,12 @@ async def test_fetch_tokenomics_http_error_raises_onchainagenthttperror(mock_asy create_mock_response(403) ] - with pytest.raises(OnchainAgentHTTPError) as excinfo: - await fetch_tokenomics(url="http://test.com/tokenomics") - assert excinfo.value.status_code == 403 - assert mock_client_instance.get.call_count == 3 # Retries should still happen + with patch.object(fetch_tokenomics.retry, 'wait', new=wait_fixed(0.01)), \ + patch.object(fetch_tokenomics.retry, 'stop', new=stop_after_attempt(3)): + with pytest.raises(OnchainAgentHTTPError) as excinfo: + await fetch_tokenomics(url="http://test.com/tokenomics") + assert excinfo.value.status_code == 403 + assert mock_client_instance.get.call_count == 3 # Retries should still happen @pytest.mark.asyncio @patch('httpx.AsyncClient') @@ -203,9 +209,11 @@ async def test_fetch_tokenomics_unexpected_error_raises_onchainagentexception(mo Exception("Another unexpected error") ] - with pytest.raises(OnchainAgentException): - await fetch_tokenomics(url="http://test.com/tokenomics") - assert mock_client_instance.get.call_count == 3 # Retries should still happen + with patch.object(fetch_tokenomics.retry, 'wait', new=wait_fixed(0.01)), \ + patch.object(fetch_tokenomics.retry, 'stop', new=stop_after_attempt(3)): + with pytest.raises(OnchainAgentException): + await fetch_tokenomics(url="http://test.com/tokenomics") + assert mock_client_instance.get.call_count == 3 # Retries should still happen # --- New tests for successful fetching and schema validation ---