Skip to content
This repository was archived by the owner on Apr 26, 2026. It is now read-only.

Commit 237578a

Browse files
authored
Merge pull request #49 from ChipaDevTeam/copilot/fix-event-handler-error
Fix event handler signatures for keep-alive connection events
2 parents ca04fea + 25dcf06 commit 237578a

2 files changed

Lines changed: 177 additions & 3 deletions

File tree

pocketoptionapi_async/client.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1301,7 +1301,7 @@ def _parse_stream_candles(
13011301
logger.error(f"Error parsing stream candles: {e}")
13021302
return candles
13031303

1304-
async def _on_keep_alive_connected(self):
1304+
async def _on_keep_alive_connected(self, data: Dict[str, Any] = None):
13051305
"""Handle event when keep-alive connection is established"""
13061306
logger.info("Keep-alive connection established")
13071307

@@ -1318,7 +1318,7 @@ async def _on_keep_alive_connected(self):
13181318
except Exception as e:
13191319
logger.error(f"Error in connected callback: {e}")
13201320

1321-
async def _on_keep_alive_reconnected(self):
1321+
async def _on_keep_alive_reconnected(self, data: Dict[str, Any] = None):
13221322
"""Handle event when keep-alive connection is re-established"""
13231323
logger.info("Keep-alive connection re-established")
13241324

@@ -1335,8 +1335,10 @@ async def _on_keep_alive_reconnected(self):
13351335
except Exception as e:
13361336
logger.error(f"Error in reconnected callback: {e}")
13371337

1338-
async def _on_keep_alive_message(self, message):
1338+
async def _on_keep_alive_message(self, data: Dict[str, Any] = None):
13391339
"""Handle messages received via keep-alive connection"""
1340+
# Extract message from data dictionary
1341+
message = data.get("message", "") if isinstance(data, dict) else str(data) if data else ""
13401342
# Process the message
13411343
if message.startswith("42"):
13421344
try:
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
"""
2+
Test script for verifying event handler signatures are correct
3+
This specifically tests the fix for issue #43:
4+
"Error in event handler for connected: AsyncPocketOptionClient._on_keep_alive_connected()
5+
takes 1 positional argument but 2 were given"
6+
"""
7+
8+
import asyncio
9+
import pytest
10+
from unittest.mock import AsyncMock, MagicMock, patch
11+
12+
13+
@pytest.fixture
14+
def mock_client():
15+
"""Create a mock client for testing event handlers"""
16+
from pocketoptionapi_async.client import AsyncPocketOptionClient
17+
18+
with patch.object(AsyncPocketOptionClient, '_setup_event_handlers'):
19+
client = AsyncPocketOptionClient(
20+
ssid='42["auth",{"session":"test","isDemo":1,"uid":0,"platform":1}]',
21+
is_demo=True,
22+
enable_logging=False,
23+
)
24+
return client
25+
26+
27+
class TestEventHandlerSignatures:
28+
"""Test that event handlers accept the correct parameters"""
29+
30+
@pytest.mark.asyncio
31+
async def test_on_keep_alive_connected_accepts_data_parameter(self, mock_client):
32+
"""Test that _on_keep_alive_connected accepts a data parameter"""
33+
# Mock _initialize_data to prevent actual initialization
34+
mock_client._initialize_data = AsyncMock()
35+
36+
# Call with data parameter (as ConnectionKeepAlive._emit_event would)
37+
data = {"url": "wss://test.example.com", "region": "TEST"}
38+
39+
# This should not raise TypeError
40+
await mock_client._on_keep_alive_connected(data)
41+
42+
# Verify _initialize_data was called
43+
mock_client._initialize_data.assert_called_once()
44+
45+
@pytest.mark.asyncio
46+
async def test_on_keep_alive_connected_accepts_no_data(self, mock_client):
47+
"""Test that _on_keep_alive_connected works without data parameter"""
48+
mock_client._initialize_data = AsyncMock()
49+
50+
# Call without data parameter (default value)
51+
await mock_client._on_keep_alive_connected()
52+
53+
mock_client._initialize_data.assert_called_once()
54+
55+
@pytest.mark.asyncio
56+
async def test_on_keep_alive_reconnected_accepts_data_parameter(self, mock_client):
57+
"""Test that _on_keep_alive_reconnected accepts a data parameter"""
58+
mock_client._initialize_data = AsyncMock()
59+
60+
# Call with data parameter (as ConnectionKeepAlive._emit_event would)
61+
data = {"attempt": 1, "url": "wss://test.example.com"}
62+
63+
# This should not raise TypeError
64+
await mock_client._on_keep_alive_reconnected(data)
65+
66+
mock_client._initialize_data.assert_called_once()
67+
68+
@pytest.mark.asyncio
69+
async def test_on_keep_alive_reconnected_accepts_no_data(self, mock_client):
70+
"""Test that _on_keep_alive_reconnected works without data parameter"""
71+
mock_client._initialize_data = AsyncMock()
72+
73+
await mock_client._on_keep_alive_reconnected()
74+
75+
mock_client._initialize_data.assert_called_once()
76+
77+
@pytest.mark.asyncio
78+
async def test_on_keep_alive_message_accepts_data_dict(self, mock_client):
79+
"""Test that _on_keep_alive_message accepts a data dictionary"""
80+
# Call with data dictionary (as ConnectionKeepAlive._emit_event would)
81+
data = {"message": "42[\"test\", {}]"}
82+
83+
# This should not raise TypeError
84+
await mock_client._on_keep_alive_message(data)
85+
86+
@pytest.mark.asyncio
87+
async def test_on_keep_alive_message_processes_message_correctly(self, mock_client):
88+
"""Test that _on_keep_alive_message correctly extracts and processes messages"""
89+
mock_client._on_authenticated = AsyncMock()
90+
91+
# Simulate a message from ConnectionKeepAlive
92+
data = {"message": '42["authenticated", {"status": "success"}]'}
93+
94+
await mock_client._on_keep_alive_message(data)
95+
96+
# Verify authentication handler was called
97+
mock_client._on_authenticated.assert_called_once()
98+
99+
@pytest.mark.asyncio
100+
async def test_on_keep_alive_message_handles_empty_data(self, mock_client):
101+
"""Test that _on_keep_alive_message handles empty or None data"""
102+
# Should not raise an exception
103+
await mock_client._on_keep_alive_message(None)
104+
await mock_client._on_keep_alive_message({})
105+
await mock_client._on_keep_alive_message({"message": ""})
106+
107+
@pytest.mark.asyncio
108+
async def test_event_handler_integration_with_emit(self):
109+
"""Test that event handlers work correctly when called through _emit_event pattern"""
110+
from pocketoptionapi_async.client import AsyncPocketOptionClient
111+
112+
with patch.object(AsyncPocketOptionClient, '_setup_event_handlers'):
113+
client = AsyncPocketOptionClient(
114+
ssid='42["auth",{"session":"test","isDemo":1,"uid":0,"platform":1}]',
115+
is_demo=True,
116+
enable_logging=False,
117+
)
118+
119+
client._initialize_data = AsyncMock()
120+
121+
# Simulate the emit pattern from ConnectionKeepAlive._emit_event
122+
handlers = [client._on_keep_alive_connected, client._on_keep_alive_reconnected]
123+
124+
for handler in handlers:
125+
data = {"test": "data"}
126+
# This should work without raising TypeError
127+
if asyncio.iscoroutinefunction(handler):
128+
await handler(data)
129+
else:
130+
handler(data)
131+
132+
133+
class TestEventCallbackPropagation:
134+
"""Test that events are properly propagated to registered callbacks"""
135+
136+
@pytest.mark.asyncio
137+
async def test_connected_event_callback_called(self, mock_client):
138+
"""Test that connected event callback is called after _on_keep_alive_connected"""
139+
mock_client._initialize_data = AsyncMock()
140+
141+
callback_called = False
142+
143+
def on_connected():
144+
nonlocal callback_called
145+
callback_called = True
146+
147+
mock_client.add_event_callback("connected", on_connected)
148+
149+
await mock_client._on_keep_alive_connected({"url": "test", "region": "TEST"})
150+
151+
assert callback_called is True
152+
153+
@pytest.mark.asyncio
154+
async def test_reconnected_event_callback_called(self, mock_client):
155+
"""Test that reconnected event callback is called after _on_keep_alive_reconnected"""
156+
mock_client._initialize_data = AsyncMock()
157+
158+
callback_called = False
159+
160+
def on_reconnected():
161+
nonlocal callback_called
162+
callback_called = True
163+
164+
mock_client.add_event_callback("reconnected", on_reconnected)
165+
166+
await mock_client._on_keep_alive_reconnected({"attempt": 1, "url": "test"})
167+
168+
assert callback_called is True
169+
170+
171+
if __name__ == "__main__":
172+
pytest.main([__file__, "-v"])

0 commit comments

Comments
 (0)