100 lines
2.5 KiB
Python
100 lines
2.5 KiB
Python
'''
|
|
IB broker event-relay regressions.
|
|
|
|
'''
|
|
from collections.abc import AsyncIterator
|
|
from typing import Any
|
|
|
|
import pytest
|
|
import trio
|
|
|
|
from piker.brokers.ib.broker import deliver_trade_events
|
|
from piker.clearing import OrderDialogs
|
|
from piker.clearing._messages import BrokerdError
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
('error', 'expected_reason'),
|
|
[
|
|
(
|
|
'[code 104] connection failed',
|
|
' connection failed',
|
|
),
|
|
(
|
|
'[Errno 111] Connect call failed',
|
|
' Connect call failed',
|
|
),
|
|
(
|
|
'plain API error',
|
|
'plain API error',
|
|
),
|
|
],
|
|
)
|
|
def test_trade_error_strings_are_relayed(
|
|
error: str,
|
|
expected_reason: str,
|
|
) -> None:
|
|
'''
|
|
Raw IB API error strings must not kill the trade-event relay.
|
|
|
|
``Client.inline_errors()`` can emit bracketed ``[code N]`` and
|
|
``[Errno N]`` strings instead of structured error dictionaries.
|
|
The string branch called ``str.partition()`` without a separator,
|
|
raising ``TypeError`` before EMS received the error and
|
|
terminating all later trade-event delivery. Feed both documented
|
|
bracket forms and an unprefixed control through
|
|
``deliver_trade_events()``. The exact emitted reason and unknown
|
|
request ID prove each event crossed the real relay path without
|
|
crashing or being misclassified.
|
|
|
|
'''
|
|
class FakeEmsStream:
|
|
'''
|
|
Collect messages sent to the EMS stream.
|
|
|
|
'''
|
|
def __init__(self) -> None:
|
|
'''
|
|
Initialize the captured message sequence.
|
|
|
|
'''
|
|
self.messages: list[Any] = []
|
|
|
|
async def send(self, msg: Any) -> None:
|
|
'''
|
|
Capture one relayed broker message.
|
|
|
|
'''
|
|
self.messages.append(msg)
|
|
|
|
async def events() -> AsyncIterator[tuple[str, str]]:
|
|
'''
|
|
Emit the raw IB error under test.
|
|
|
|
'''
|
|
yield 'error', error
|
|
|
|
async def main() -> list[Any]:
|
|
'''
|
|
Drive the broker relay to input exhaustion.
|
|
|
|
'''
|
|
ems_stream = FakeEmsStream()
|
|
await deliver_trade_events(
|
|
events(),
|
|
ems_stream,
|
|
accounts_def={},
|
|
proxies={},
|
|
ledgers={},
|
|
tables={},
|
|
flows=OrderDialogs(_flows={}),
|
|
)
|
|
return ems_stream.messages
|
|
|
|
messages = trio.run(main)
|
|
assert len(messages) == 1
|
|
msg = messages[0]
|
|
assert isinstance(msg, BrokerdError)
|
|
assert msg.reqid == '<unknown>'
|
|
assert msg.reason == expected_reason
|