async def test_should_perform_a_catchup_when_subscription_is_confirmed(): """ When we have read all the events in the stream, we should send a request to subscribe for new events. We should start reading catchup events from the `next_event_number` returned by the historical event read. """ convo = CatchupSubscription("my-stream") output = TeeQueue() await convo.start(output) await reply_to( convo, ReadStreamEventsResponseBuilder().with_next_event_number( 17).at_end_of_stream().build(), output, ) await confirm_subscription(convo, output, event_number=42, commit_pos=40) [read_historial, subscribe, catch_up] = await output.next_event(3) assert read_historial.command == msg.TcpCommand.ReadStreamEventsForward assert subscribe.command == msg.TcpCommand.SubscribeToStream assert catch_up.command == msg.TcpCommand.ReadStreamEventsForward payload = proto.ReadStreamEvents() payload.ParseFromString(catch_up.payload) assert payload.event_stream_id == "my-stream" assert payload.from_event_number == 17
async def test_stream_paging(): output = TeeQueue() convo = IterStreamEvents("my-stream") response = proto.ReadStreamEventsCompleted() response.result = msg.ReadEventResult.Success response.next_event_number = 10 response.last_event_number = 9 response.is_end_of_stream = False response.last_commit_position = 8 await convo.respond_to( msg.InboundMessage( uuid4(), msg.TcpCommand.ReadStreamEventsForwardCompleted, response.SerializeToString(), ), output, ) reply = await output.get() body = proto.ReadStreamEvents() body.ParseFromString(reply.payload) assert body.from_event_number == 10
async def test_start_read_phase(): """ A "catchup" subscription starts by iterating the events in the stream until it reaches the most recent event. This is the "Read" phase. """ output = TeeQueue() conversation_id = uuid.uuid4() convo = CatchupSubscription("my-stream", start_from=0, conversation_id=conversation_id) await convo.start(output) [request] = output.items body = proto.ReadStreamEvents() body.ParseFromString(request.payload) assert request.command is msg.TcpCommand.ReadStreamEventsForward assert body.event_stream_id == "my-stream" assert body.from_event_number == 0 assert body.resolve_link_tos is True assert body.require_master is False assert body.max_count == 100
async def test_reconnect_at_last_event_number(): output = TeeQueue() event_1_id = uuid4() event_2_id = uuid4() convo = IterStreamEvents("my-stream", from_event=32) await convo.start(output) response = proto.ReadStreamEventsCompleted() response.result = msg.ReadEventResult.Success response.next_event_number = 32 response.last_event_number = 31 response.is_end_of_stream = False response.last_commit_position = 31 event_1 = proto.ResolvedIndexedEvent() event_1.event.event_stream_id = "stream-123" event_1.event.event_number = 32 event_1.event.event_id = event_1_id.bytes_le event_1.event.event_type = "event-type" event_1.event.data_content_type = msg.ContentType.Json event_1.event.metadata_content_type = msg.ContentType.Binary event_1.event.data = """ { 'color': 'red', 'winner': true } """.encode("UTF-8") event_2 = proto.ResolvedIndexedEvent() event_2.CopyFrom(event_1) event_2.event.event_type = "event-2-type" event_2.event.event_id = event_2_id.bytes_le event_2.event.event_number = 33 response.events.extend([event_1, event_2]) await convo.respond_to( msg.InboundMessage( uuid4(), msg.TcpCommand.ReadStreamEventsForwardCompleted, response.SerializeToString(), ), output, ) await convo.start(output) request = output.items[-1] body = proto.ReadStreamEvents() body.ParseFromString(request.payload) assert request.command is msg.TcpCommand.ReadStreamEventsForward assert body.event_stream_id == "my-stream" assert body.from_event_number == 33 assert body.resolve_link_tos is True assert body.require_master is False assert body.max_count == 100
async def test_read_stream_request(): output = TeeQueue() convo = IterStreamEvents("my-stream") await convo.start(output) request = await output.get() body = proto.ReadStreamEvents() body.ParseFromString(request.payload) assert request.command is msg.TcpCommand.ReadStreamEventsForward assert body.event_stream_id == "my-stream" assert body.from_event_number == 0 assert body.resolve_link_tos is True assert body.require_master is False assert body.max_count == 100
def _fetch_page_message(self, from_event): if self.direction == StreamDirection.Forward: command = TcpCommand.ReadStreamEventsForward else: command = TcpCommand.ReadStreamEventsBackward msg = proto.ReadStreamEvents() msg.event_stream_id = self.stream msg.from_event_number = from_event msg.max_count = self.max_count msg.require_master = self.require_master msg.resolve_link_tos = self.resolve_link_tos data = msg.SerializeToString() return OutboundMessage(self.conversation_id, command, data, self.credential)
async def test_paging(): """ During the read phase, we expect to page through multiple batches of events. In this scenario we have two batches, each of two events. """ convo = CatchupSubscription("my-stream") output = TeeQueue() await convo.start(output) await output.get() event_1_id = uuid.uuid4() event_2_id = uuid.uuid4() event_3_id = uuid.uuid4() event_4_id = uuid.uuid4() first_response = (ReadStreamEventsResponseBuilder().with_event( event_id=event_1_id, event_number=32).with_event( event_id=event_2_id, event_number=33).with_next_event_number(34)).build() second_response = (ReadStreamEventsResponseBuilder().with_event( event_id=event_3_id, event_number=34).with_event(event_id=event_4_id, event_number=35)).build() await reply_to(convo, first_response, output) subscription = await convo.result event_1 = await anext(subscription.events) event_2 = await anext(subscription.events) assert event_1.id == event_1_id assert event_2.id == event_2_id reply = await output.get() body = proto.ReadStreamEvents() body.ParseFromString(reply.payload) assert body.from_event_number == 34 await reply_to(convo, second_response, output) event_3 = await anext(subscription.events) event_4 = await anext(subscription.events) assert event_3.id == event_3_id assert event_4.id == event_4_id
async def test_paging_projection(): """ """ convo = CatchupSubscription("my-stream") output = TeeQueue() await convo.start(output) await output.get() event_1_id = uuid.uuid4() event_2_id = uuid.uuid4() event_3_id = uuid.uuid4() event_4_id = uuid.uuid4() first_response = (ReadStreamEventsResponseBuilder().with_event( event_id=event_1_id, event_number=0, link_event_number=32).with_event( event_id=event_2_id, event_number=0, link_event_number=33).with_next_event_number(34)).build() second_response = (ReadStreamEventsResponseBuilder().with_event( event_id=event_3_id, event_number=0, link_event_number=34).with_event(event_id=event_4_id, event_number=0, link_event_number=35)).build() await reply_to(convo, first_response, output) subscription = await convo.result event_1 = await anext(subscription.events) event_2 = await anext(subscription.events) assert event_1.id == event_1_id assert event_2.id == event_2_id reply = await output.get() body = proto.ReadStreamEvents() body.ParseFromString(reply.payload) assert body.from_event_number == 34 await reply_to(convo, second_response, output) event_3 = await anext(subscription.events) event_4 = await anext(subscription.events) assert event_3.id == event_3_id assert event_4.id == event_4_id
async def test_read_stream_backward(): output = Queue() convo = ReadStreamEvents("my-stream", 50, direction=msg.StreamDirection.Backward, max_count=10) await convo.start(output) request = await output.get() body = proto.ReadStreamEvents() body.ParseFromString(request.payload) assert request.command is msg.TcpCommand.ReadStreamEventsBackward assert body.event_stream_id == "my-stream" assert body.from_event_number == 50 assert body.resolve_link_tos is True assert body.require_master is False assert body.max_count == 10