forked from ChipaDevTeam/PocketOptionAPI
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtest_async_api.py
More file actions
370 lines (301 loc) · 12.8 KB
/
test_async_api.py
File metadata and controls
370 lines (301 loc) · 12.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
"""
Professional test suite for the Async PocketOption API
"""
import pytest
from unittest.mock import AsyncMock, MagicMock, patch
from datetime import datetime, timedelta
from pocketoptionapi_async import (
AsyncPocketOptionClient,
OrderDirection,
OrderStatus,
Balance,
Order,
OrderResult,
ConnectionError,
InvalidParameterError,
ConnectionStatus,
)
class TestAsyncPocketOptionClient:
"""Test suite for AsyncPocketOptionClient"""
@pytest.fixture
def client(self):
"""Create test client"""
return AsyncPocketOptionClient(ssid="test_session", is_demo=True, uid=12345)
@pytest.fixture
def mock_websocket(self):
"""Mock WebSocket client"""
mock = AsyncMock()
mock.is_connected = True
mock.connection_info = MagicMock()
mock.connection_info.status = "connected"
return mock
def test_client_initialization(self, client):
"""Test client initialization"""
assert client.session_id == "test_session"
assert client.is_demo is True
assert client.uid == 12345
assert client._balance is None
@pytest.mark.asyncio
async def test_connect_success(self, client, mock_websocket):
"""Test successful connection"""
with patch.object(client, "_websocket", mock_websocket):
mock_websocket.connect.return_value = True
result = await client.connect()
assert result is True
mock_websocket.connect.assert_called_once()
@pytest.mark.asyncio
async def test_connect_failure(self, client, mock_websocket):
"""Test connection failure"""
with patch.object(client, "_websocket", mock_websocket):
mock_websocket.connect.side_effect = Exception("Connection failed")
with pytest.raises(ConnectionError):
await client.connect()
@pytest.mark.asyncio
async def test_disconnect(self, client, mock_websocket):
"""Test disconnection"""
with patch.object(client, "_websocket", mock_websocket):
await client.disconnect()
mock_websocket.disconnect.assert_called_once()
@pytest.mark.asyncio
async def test_get_balance_success(self, client):
"""Test getting balance"""
# Set up test balance
test_balance = Balance(balance=1000.0, currency="USD", is_demo=True)
client._balance = test_balance
# Mock websocket as connected
client._websocket.websocket = MagicMock()
client._websocket.websocket.closed = False
client._websocket.connection_info = MagicMock()
client._websocket.connection_info.status = ConnectionStatus.CONNECTED
balance = await client.get_balance()
assert balance.balance == 1000.0
assert balance.currency == "USD"
assert balance.is_demo is True
@pytest.mark.asyncio
async def test_get_balance_not_connected(self, client):
"""Test getting balance when not connected"""
# Mock websocket as not connected
client._websocket.websocket = None
with pytest.raises(ConnectionError):
await client.get_balance()
def test_validate_order_parameters_valid(self, client):
"""Test order parameter validation with valid parameters"""
# Should not raise any exception
client._validate_order_parameters(
asset="EURUSD_otc", amount=10.0, direction=OrderDirection.CALL, duration=120
)
def test_validate_order_parameters_invalid_asset(self, client):
"""Test order parameter validation with invalid asset"""
with pytest.raises(InvalidParameterError):
client._validate_order_parameters(
asset="INVALID_ASSET",
amount=10.0,
direction=OrderDirection.CALL,
duration=120,
)
def test_validate_order_parameters_invalid_amount(self, client):
"""Test order parameter validation with invalid amount"""
with pytest.raises(InvalidParameterError):
client._validate_order_parameters(
asset="EURUSD_otc",
amount=0.5, # Too low
direction=OrderDirection.CALL,
duration=120,
)
def test_validate_order_parameters_invalid_duration(self, client):
"""Test order parameter validation with invalid duration"""
with pytest.raises(InvalidParameterError):
client._validate_order_parameters(
asset="EURUSD_otc",
amount=10.0,
direction=OrderDirection.CALL,
duration=30, # Too short
)
@pytest.mark.asyncio
async def test_place_order_success(self, client, mock_websocket):
"""Test successful order placement"""
with patch.object(client, "_websocket", mock_websocket):
# Mock websocket as connected
mock_websocket.websocket = MagicMock()
mock_websocket.websocket.closed = False
mock_websocket.connection_info = MagicMock()
mock_websocket.connection_info.status = ConnectionStatus.CONNECTED
# Mock order result
test_order_result = OrderResult(
order_id="test_order_123",
asset="EURUSD_otc",
amount=10.0,
direction=OrderDirection.CALL,
duration=120,
status=OrderStatus.ACTIVE,
placed_at=datetime.now(),
expires_at=datetime.now() + timedelta(seconds=120),
)
with patch.object(
client, "_wait_for_order_result", return_value=test_order_result
):
result = await client.place_order(
asset="EURUSD_otc",
amount=10.0,
direction=OrderDirection.CALL,
duration=120,
)
assert result.order_id == "test_order_123"
assert result.status == OrderStatus.ACTIVE
assert result.asset == "EURUSD_otc"
@pytest.mark.asyncio
async def test_place_order_not_connected(self, client):
"""Test order placement when not connected"""
# Mock websocket as not connected
client._websocket.websocket = None
with pytest.raises(ConnectionError):
await client.place_order(
asset="EURUSD_otc",
amount=10.0,
direction=OrderDirection.CALL,
duration=120,
)
@pytest.mark.asyncio
async def test_get_candles_success(self, client, mock_websocket):
"""Test successful candles retrieval"""
with patch.object(client, "_websocket", mock_websocket):
# Mock websocket as connected
mock_websocket.websocket = MagicMock()
mock_websocket.websocket.closed = False
mock_websocket.connection_info = MagicMock()
mock_websocket.connection_info.status = ConnectionStatus.CONNECTED
# Mock candles data
test_candles = [
{
"timestamp": datetime.now(),
"open": 1.1000,
"high": 1.1010,
"low": 1.0990,
"close": 1.1005,
"asset": "EURUSD_otc",
"timeframe": 60,
}
]
with patch.object(client, "_request_candles", return_value=test_candles):
candles = await client.get_candles(
asset="EURUSD_otc", timeframe="1m", count=100
)
assert len(candles) == 1
assert candles[0]["asset"] == "EURUSD_otc"
@pytest.mark.asyncio
async def test_get_candles_invalid_timeframe(self, client):
"""Test candles retrieval with invalid timeframe"""
# Mock websocket as connected
client._websocket.websocket = MagicMock()
client._websocket.websocket.closed = False
client._websocket.connection_info = MagicMock()
client._websocket.connection_info.status = ConnectionStatus.CONNECTED
with pytest.raises(InvalidParameterError):
await client.get_candles(asset="EURUSD_otc", timeframe="invalid", count=100)
@pytest.mark.asyncio
async def test_get_candles_invalid_asset(self, client):
"""Test candles retrieval with invalid asset"""
# Mock websocket as connected
client._websocket.websocket = MagicMock()
client._websocket.websocket.closed = False
client._websocket.connection_info = MagicMock()
client._websocket.connection_info.status = ConnectionStatus.CONNECTED
with pytest.raises(InvalidParameterError):
await client.get_candles(asset="INVALID_ASSET", timeframe="1m", count=100)
def test_add_event_callback(self, client):
"""Test adding event callback"""
def test_callback(data):
pass
client.add_event_callback("test_event", test_callback)
assert "test_event" in client._event_callbacks
assert test_callback in client._event_callbacks["test_event"]
def test_remove_event_callback(self, client):
"""Test removing event callback"""
def test_callback(data):
pass
client.add_event_callback("test_event", test_callback)
client.remove_event_callback("test_event", test_callback)
assert test_callback not in client._event_callbacks.get("test_event", [])
@pytest.mark.asyncio
async def test_context_manager(self, client, mock_websocket):
"""Test async context manager"""
with patch.object(client, "_websocket", mock_websocket):
mock_websocket.connect.return_value = True
async with client:
assert mock_websocket.connect.called
mock_websocket.disconnect.assert_called_once()
class TestModels:
"""Test Pydantic models"""
def test_balance_model(self):
"""Test Balance model"""
balance = Balance(balance=1000.0, currency="USD", is_demo=True)
assert balance.balance == 1000.0
assert balance.currency == "USD"
assert balance.is_demo is True
assert isinstance(balance.last_updated, datetime)
def test_order_model_valid(self):
"""Test Order model with valid data"""
order = Order(
asset="EURUSD_otc", amount=10.0, direction=OrderDirection.CALL, duration=120
)
assert order.asset == "EURUSD_otc"
assert order.amount == 10.0
assert order.direction == OrderDirection.CALL
assert order.duration == 120
assert order.request_id is not None
def test_order_model_invalid_amount(self):
"""Test Order model with invalid amount"""
with pytest.raises(ValueError):
Order(
asset="EURUSD_otc",
amount=-10.0, # Negative amount
direction=OrderDirection.CALL,
duration=120,
)
def test_order_model_invalid_duration(self):
"""Test Order model with invalid duration"""
with pytest.raises(ValueError):
Order(
asset="EURUSD_otc",
amount=10.0,
direction=OrderDirection.CALL,
duration=30, # Too short
)
def test_order_result_model(self):
"""Test OrderResult model"""
result = OrderResult(
order_id="test_123",
asset="EURUSD_otc",
amount=10.0,
direction=OrderDirection.CALL,
duration=120,
status=OrderStatus.WIN,
placed_at=datetime.now(),
expires_at=datetime.now() + timedelta(seconds=120),
profit=8.0,
)
assert result.order_id == "test_123"
assert result.status == OrderStatus.WIN
assert result.profit == 8.0
class TestUtilities:
"""Test utility functions"""
def test_format_session_id(self):
"""Test session ID formatting"""
from pocketoptionapi_async.utils import format_session_id
formatted = format_session_id("test_session", True, 123, 1)
assert "test_session" in formatted
assert '"isDemo": 1' in formatted
assert '"uid": 123' in formatted
def test_calculate_payout_percentage_win(self):
"""Test payout calculation for winning trade"""
from pocketoptionapi_async.utils import calculate_payout_percentage
payout = calculate_payout_percentage(1.1000, 1.1010, "call", 0.8)
assert payout == 0.8
def test_calculate_payout_percentage_loss(self):
"""Test payout calculation for losing trade"""
from pocketoptionapi_async.utils import calculate_payout_percentage
payout = calculate_payout_percentage(1.1000, 1.0990, "call", 0.8)
assert payout == -1.0
if __name__ == "__main__":
# Run tests with: python -m pytest tests/test_async_api.py -v
pytest.main([__file__, "-v"])