Skip to content

Commit 1e3526d

Browse files
committed
fix websocket connection error handling and add tests
1 parent 889eb75 commit 1e3526d

File tree

2 files changed

+105
-7
lines changed

2 files changed

+105
-7
lines changed

gdax/orderbook.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
from bintrees import FastRBTree
1515
import aiofiles
1616
import aiohttp
17-
# import websockets
1817

1918
import gdax.trader
2019
import gdax.utils
@@ -106,7 +105,7 @@ async def __aexit__(self, exc_type, exc, traceback):
106105
async def _open_log_file(self):
107106
if self.trade_log_file_path is not None:
108107
self._trade_file = await aiofiles.open(self.trade_log_file_path,
109-
mode='w').__aenter__()
108+
mode='a').__aenter__()
110109

111110
async def _close_log_file(self):
112111
if self._trade_file is not None:
@@ -147,8 +146,8 @@ async def handle_message(self):
147146
except aiohttp.ServerDisconnectedError as exc:
148147
logging.error(
149148
f'Error: Exception: f{exc}. Re-initializing websocket.')
150-
await self._ws_session.__aexit__(None, None, None)
151-
await self._init()
149+
await self.__aexit__(None, None, None)
150+
await self.__aenter__()
152151
return
153152

154153
msg_type = message['type']
@@ -168,8 +167,8 @@ async def handle_message(self):
168167
logging.error(
169168
'Error: messages missing ({} - {}). Re-initializing websocket.'
170169
.format(sequence, self._sequences[product_id]))
171-
await self._ws_session.__aexit__(None, None, None)
172-
await self._init()
170+
await self.__aexit__(None, None, None)
171+
await self.__aenter__()
173172
return
174173

175174
if msg_type == 'open':

tests/test_orderbook.py

Lines changed: 100 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from decimal import Decimal
55

66
import asyncio
7+
import aiohttp
78
import pytest
89
from asynctest import MagicMock, patch, CoroutineMock, call
910

@@ -457,7 +458,7 @@ async def test_orderbook_advanced(self, mock_book, mock_connect):
457458
# TODO
458459

459460
@patch('gdax.trader.Trader.get_product_order_book')
460-
async def test_error(self, mock_book, mock_connect):
461+
async def test_error_message(self, mock_book, mock_connect):
461462
mock_connect.return_value.aenter.receive_str = CoroutineMock()
462463
mock_connect.return_value.aenter.send_json = CoroutineMock()
463464
mock_book.return_value = {'bids': [], 'asks': [], 'sequence': 1}
@@ -482,3 +483,101 @@ async def test_error(self, mock_book, mock_connect):
482483

483484
with pytest.raises(gdax.orderbook.OrderBookError):
484485
message = await orderbook.handle_message()
486+
487+
@patch('gdax.trader.Trader.get_product_order_book')
488+
async def test_disconnect(self, mock_book, mock_connect):
489+
mock_connect.return_value.aenter.receive_str = CoroutineMock()
490+
mock_connect.return_value.aenter.send_json = CoroutineMock()
491+
mock_book.return_value = {'bids': [], 'asks': [], 'sequence': 1}
492+
493+
messages_expected = [
494+
json.dumps({
495+
"type": "done",
496+
"side": "sell",
497+
"order_id": "4eef1226-4b38-422c-a5b1-56def7107f9a",
498+
"reason": "canceled",
499+
"product_id": "ETH-USD",
500+
"price": "2601.76000000",
501+
"remaining_size": "3.09000000",
502+
"sequence": 2,
503+
"time": "2017-06-25T11:23:14.775000Z"
504+
}),
505+
aiohttp.ServerDisconnectedError('error'),
506+
json.dumps({
507+
"type": "done",
508+
"side": "sell",
509+
"order_id": "4eef1226-4b38-422c-a5b1-56def7107f9a",
510+
"reason": "canceled",
511+
"product_id": "ETH-USD",
512+
"price": "2601.76000000",
513+
"remaining_size": "3.09000000",
514+
"sequence": 2,
515+
"time": "2017-06-25T11:23:14.775000Z"
516+
})
517+
]
518+
mock_connect.return_value.aenter.receive_str.side_effect = \
519+
messages_expected
520+
async with gdax.orderbook.OrderBook() as orderbook:
521+
message = await orderbook.handle_message()
522+
assert message == json.loads(messages_expected[0])
523+
524+
message = await orderbook.handle_message()
525+
assert message is None
526+
527+
message = await orderbook.handle_message()
528+
assert message == json.loads(messages_expected[2])
529+
530+
@patch('gdax.trader.Trader.get_product_order_book')
531+
async def test_out_of_order(self, mock_book, mock_connect):
532+
mock_connect.return_value.aenter.receive_str = CoroutineMock()
533+
mock_connect.return_value.aenter.send_json = CoroutineMock()
534+
mock_book.return_value = {'bids': [], 'asks': [], 'sequence': 1}
535+
536+
messages_expected = [
537+
{
538+
"type": "done",
539+
"side": "sell",
540+
"order_id": "4eef1226-4b38-422c-a5b1-56def7107f9a",
541+
"reason": "canceled",
542+
"product_id": "ETH-USD",
543+
"price": "2601.76000000",
544+
"remaining_size": "3.09000000",
545+
"sequence": 2,
546+
"time": "2017-06-25T11:23:14.775000Z"
547+
},
548+
{
549+
"type": "done",
550+
"side": "sell",
551+
"order_id": "4eef1226-4b38-422c-a5b1-56def7107f9a",
552+
"reason": "canceled",
553+
"product_id": "ETH-USD",
554+
"price": "2601.76000000",
555+
"remaining_size": "3.09000000",
556+
"sequence": 4,
557+
"time": "2017-06-25T11:23:14.775000Z"
558+
},
559+
{
560+
"type": "done",
561+
"side": "sell",
562+
"order_id": "4eef1226-4b38-422c-a5b1-56def7107f9a",
563+
"reason": "canceled",
564+
"product_id": "ETH-USD",
565+
"price": "2601.76000000",
566+
"remaining_size": "3.09000000",
567+
"sequence": 2,
568+
"time": "2017-06-25T11:23:14.775000Z"
569+
},
570+
]
571+
mock_connect.return_value.aenter.receive_str.side_effect = [
572+
json.dumps(message_expected)
573+
for message_expected in messages_expected
574+
]
575+
async with gdax.orderbook.OrderBook() as orderbook:
576+
message = await orderbook.handle_message()
577+
assert message == messages_expected[0]
578+
579+
message = await orderbook.handle_message()
580+
assert message is None
581+
582+
message = await orderbook.handle_message()
583+
assert message == messages_expected[2]

0 commit comments

Comments
 (0)