Merge pull request #50 from pselamy/fix/49

fix: resolve flaky tests in clob_client and websocket (#49)
This commit is contained in:
Patrick Selamy
2026-01-04 19:07:03 -05:00
committed by GitHub
3 changed files with 48 additions and 17 deletions
+10 -5
View File
@@ -7,7 +7,6 @@ import pytest
from polymarket_insider_tracker.ingestor.clob_client import (
ClobClient,
ClobClientError,
RateLimiter,
RetryError,
with_retry,
@@ -253,17 +252,23 @@ class TestClobClient:
assert market.condition_id == "0xabc"
assert len(market.tokens) == 2
@pytest.mark.xfail(reason="Retry logic wraps exception differently - see #49")
def test_get_market_not_found(self, mock_base_client: MagicMock) -> None:
"""Test error handling when market not found."""
"""Test error handling when market not found.
When the underlying API call fails, the @with_retry decorator will
retry the operation. After all retries are exhausted, it raises
RetryError wrapping the original exception.
"""
mock_base_client.get_market.side_effect = Exception("Not found")
client = ClobClient()
with pytest.raises(ClobClientError) as exc_info:
with pytest.raises(RetryError) as exc_info:
client.get_market("0xnotfound")
assert "0xnotfound" in str(exc_info.value)
# The RetryError wraps the original exception
assert "get_market" in str(exc_info.value)
assert exc_info.value.last_exception is not None
def test_get_orderbook(self, mock_base_client: MagicMock) -> None:
"""Test fetching an orderbook."""
+27 -12
View File
@@ -3,7 +3,7 @@
import asyncio
import json
from decimal import Decimal
from unittest.mock import AsyncMock, MagicMock, patch
from unittest.mock import AsyncMock, patch
import pytest
@@ -275,7 +275,6 @@ class TestTradeStreamHandlerIntegration:
"""
@pytest.mark.asyncio
@pytest.mark.xfail(reason="Async mock iterator signature issue - see #49")
async def test_start_and_receive_trades(self) -> None:
"""Test starting handler and receiving trades."""
received_trades: list[TradeEvent] = []
@@ -288,11 +287,6 @@ class TestTradeStreamHandlerIntegration:
initial_reconnect_delay=0.01,
)
# Create mock WebSocket that sends one trade then closes
mock_ws = MagicMock()
mock_ws.send = AsyncMock()
mock_ws.close = AsyncMock()
trade_message = json.dumps(
{
"topic": "activity",
@@ -311,12 +305,33 @@ class TestTradeStreamHandlerIntegration:
}
)
# Mock async iteration
async def mock_iter() -> None:
yield trade_message
await handler.stop() # Stop after first message
# Create a proper async iterable mock WebSocket
class MockWebSocket:
"""Mock WebSocket that yields one message then stops."""
mock_ws.__aiter__ = mock_iter
def __init__(self, handler: TradeStreamHandler, message: str):
self.handler = handler
self.message = message
self.sent = False
async def send(self, _msg: str) -> None:
pass
async def close(self) -> None:
pass
def __aiter__(self):
return self
async def __anext__(self) -> str:
if not self.sent:
self.sent = True
return self.message
# Stop the handler and raise StopAsyncIteration
await self.handler.stop()
raise StopAsyncIteration
mock_ws = MockWebSocket(handler, trade_message)
with patch("websockets.connect", AsyncMock(return_value=mock_ws)):
# Run with timeout to prevent hanging
Generated
+11
View File
@@ -126,6 +126,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e", size = 7490, upload-time = "2025-07-03T22:54:42.156Z" },
]
[[package]]
name = "aiosqlite"
version = "0.22.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/4e/8a/64761f4005f17809769d23e518d915db74e6310474e733e3593cfc854ef1/aiosqlite-0.22.1.tar.gz", hash = "sha256:043e0bd78d32888c0a9ca90fc788b38796843360c855a7262a532813133a0650", size = 14821, upload-time = "2025-12-23T19:25:43.997Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/00/b7/e3bf5133d697a08128598c8d0abc5e16377b51465a33756de24fa7dee953/aiosqlite-0.22.1-py3-none-any.whl", hash = "sha256:21c002eb13823fad740196c5a2e9d8e62f6243bd9e7e4a1f87fb5e44ecb4fceb", size = 17405, upload-time = "2025-12-23T19:25:42.139Z" },
]
[[package]]
name = "alembic"
version = "1.17.2"
@@ -1548,6 +1557,7 @@ dependencies = [
[package.optional-dependencies]
dev = [
{ name = "aiosqlite" },
{ name = "mypy" },
{ name = "pre-commit" },
{ name = "pytest" },
@@ -1559,6 +1569,7 @@ dev = [
[package.metadata]
requires-dist = [
{ name = "aiohttp", specifier = ">=3.9.0" },
{ name = "aiosqlite", marker = "extra == 'dev'", specifier = ">=0.19.0" },
{ name = "alembic", specifier = ">=1.13.0" },
{ name = "httpx", specifier = ">=0.25.0" },
{ name = "mypy", marker = "extra == 'dev'", specifier = ">=1.7.0" },