async def drop_subscription(convo, reason=SubscriptionDropReason): response = proto.SubscriptionDropped() response.reason = reason await convo.respond_to( InboundMessage(uuid4(), TcpCommand.SubscriptionDropped, response.SerializeToString()), None, )
async def test_ping_response(): output = TeeQueue() conversation = Ping() await conversation.start(output) await conversation.respond_to( InboundMessage(conversation.conversation_id, TcpCommand.Pong, b""), output) assert conversation.is_complete
async def complete_subscription(convo, result): response = proto.CreatePersistentSubscriptionCompleted() response.result = result await convo.respond_to( InboundMessage( uuid4(), TcpCommand.CreatePersistentSubscriptionCompleted, response.SerializeToString(), ), None, )
async def confirm_subscription(convo, output_queue=None, event_number=1, commit_pos=1): response = proto.SubscriptionConfirmation() response.last_event_number = event_number response.last_commit_position = commit_pos await convo.respond_to( InboundMessage( uuid4(), TcpCommand.SubscriptionConfirmation, response.SerializeToString() ), output_queue, ) return await convo.result
async def test_when_server_responds_to_heartbeat(): output = TeeQueue() id = uuid4() conversation = Heartbeat(id, direction=Heartbeat.OUTBOUND) await conversation.respond_to( InboundMessage(conversation.conversation_id, TcpCommand.HeartbeatResponse, b""), output, ) await conversation.result assert conversation.is_complete
async def test_when_receiving_a_heartbeat_request(): """ When we receive a HeartbeatRequest from the server, we should immediately respond with a HeartbeatResponse """ out_queue = TeeQueue() pace_maker = PaceMaker(out_queue, None) heartbeat_id = uuid.uuid4() await pace_maker.handle_request( InboundMessage(heartbeat_id, TcpCommand.HeartbeatRequest, bytes()) ) response = await out_queue.get() assert response == OutboundMessage( heartbeat_id, TcpCommand.HeartbeatResponse, bytes() )
async def confirm_subscription(convo, commit=23, event_number=56, subscription_id="FUUBARRBAXX", queue=None): response = proto.PersistentSubscriptionConfirmation() response.last_commit_position = commit response.last_event_number = event_number response.subscription_id = subscription_id await convo.respond_to( InboundMessage( convo.conversation_id, TcpCommand.PersistentSubscriptionConfirmation, response.SerializeToString(), ), queue, )
async def test_when_the_conversation_raises_an_error(): """ If the conversation raises an error, that error should be returned to the caller. """ out_queue = TeeQueue() dispatcher = MessageDispatcher() conversation = Ping() future = await dispatcher.start_conversation(conversation) await dispatcher.dispatch( InboundMessage(conversation.conversation_id, TcpCommand.NotAuthenticated, bytes()), out_queue, ) with pytest.raises(NotAuthenticated): await asyncio.wait_for(future, 1) assert not dispatcher.has_conversation(conversation.conversation_id)
async def test_when_the_heartbeat_succeeds(): """ If the heartbeat receives a response within the timeout period we should record the success. """ heartbeat_id = uuid.uuid4() out_queue = TeeQueue() connector = FakeConnector() pace_maker = PaceMaker(out_queue, connector, heartbeat_id=heartbeat_id) await pace_maker.send_heartbeat() await pace_maker.handle_response( InboundMessage(heartbeat_id, TcpCommand.HeartbeatResponse, bytes()) ) await pace_maker.await_heartbeat_response() assert connector.failures == [] assert connector.successes == 1
async def test_persistent_subscription_already_exists(): output = Queue() convo = CreatePersistentSubscription("my-other-subscription", "my-other-stream") await convo.start(output) response = proto.CreatePersistentSubscriptionCompleted() response.result = SubscriptionResult.AlreadyExists await convo.respond_to( InboundMessage( uuid4(), TcpCommand.CreatePersistentSubscriptionCompleted, response.SerializeToString(), ), output, ) with pytest.raises(exceptions.SubscriptionCreationFailed): await convo.result
def event_appeared(event_id, commit_position=1, prepare_position=1): message_id = uuid4() response = proto.StreamEventAppeared() response.event.event.event_stream_id = "stream-123" response.event.event.event_number = 32 response.event.event.event_id = event_id.bytes_le response.event.event.event_type = "event-type" response.event.event.data_content_type = ContentType.Json response.event.event.metadata_content_type = ContentType.Binary response.event.commit_position = commit_position response.event.prepare_position = prepare_position response.event.event.data = """ { 'color': 'blue', 'winner': false } """.encode("UTF-8") return InboundMessage(message_id, TcpCommand.StreamEventAppeared, response.SerializeToString())
async def test_stream_event_appeared(): convo = ConnectPersistentSubscription("my-subscription", "my-stream", max_in_flight=57) event_id = uuid4() await confirm_subscription(convo) response = event_appeared(event_id) await convo.respond_to( InboundMessage( uuid4(), TcpCommand.PersistentSubscriptionStreamEventAppeared, response.SerializeToString(), ), None, ) subscription = await convo.result event = await subscription.events.anext() assert event.event.id == event_id
async def test_when_the_conversation_receives_an_unexpected_response(): """ If the conversation receives an unhandled response, an error should be returned to the caller. This is a separate code path for now, but should probably be cleaned up in the Conversation. Maybe use a decorator? """ out_queue = TeeQueue() dispatcher = MessageDispatcher() conversation = Ping() future = await dispatcher.start_conversation(conversation) await dispatcher.dispatch( InboundMessage(conversation.conversation_id, TcpCommand.WriteEventsCompleted, bytes()), out_queue, ) with pytest.raises(PayloadUnreadable): await asyncio.wait_for(future, 1) assert not dispatcher.has_conversation(conversation.conversation_id)