async def test_completing_write_events_twice():

    output = Queue()
    conversation = given_a_write_events_message()

    await conversation.start(output)

    await output.get()
    payload = proto.WriteEventsCompleted()
    payload.result = msg.OperationResult.Success
    payload.first_event_number = 73
    payload.last_event_number = 73

    await conversation.respond_to(
        msg.InboundMessage(
            conversation.conversation_id,
            msg.TcpCommand.WriteEventsCompleted,
            payload.SerializeToString(),
        ),
        output,
    )

    with pytest.raises(asyncio.base_futures.InvalidStateError) as exn:

        await conversation.respond_to(
            msg.InboundMessage(
                conversation.conversation_id,
                msg.TcpCommand.WriteEventsCompleted,
                payload.SerializeToString(),
            ),
            output,
        )
Exemple #2
0
async def test_stream_not_found():

    output = TeeQueue()
    convo = IterStreamEvents("my-stream")
    response = proto.ReadStreamEventsCompleted()
    response.result = msg.ReadStreamResult.NoStream
    response.is_end_of_stream = False
    response.next_event_number = 0
    response.last_event_number = 0
    response.last_commit_position = 0

    await convo.respond_to(
        msg.InboundMessage(
            uuid4(),
            msg.TcpCommand.ReadStreamEventsForwardCompleted,
            response.SerializeToString(),
        ),
        output,
    )

    with pytest.raises(exceptions.StreamNotFound) as exn:
        await convo.result
        assert exn.stream == "my-stream"
        assert exn.conversation_id == convo.conversation_id

    assert not output.items
async def test_end_of_stream():

    output = TeeQueue()
    event_1_id = uuid4()
    event_2_id = uuid4()

    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 = True
    response.last_commit_position = 8

    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.ReadEventCompleted, response.SerializeToString()
        ),
        output,
    )

    # Todo: Use a slice here so that we can give information
    # to the iterator about its position in the stream?
    # assert isinstance(reply.result, msg.StreamSlice)

    result = await convo.result
    [event_1, event_2] = [e async for e in result]
    assert event_1.event.stream == "stream-123"
    assert event_1.event.id == event_1_id
    assert event_1.event.type == "event-type"
    assert event_1.event.event_number == 32

    assert event_2.event.stream == "stream-123"
    assert event_2.event.id == event_2_id
    assert event_2.event.type == "event-2-type"
    assert event_2.event.event_number == 33
async def test_one_event_response():

    output = Queue()
    conversation = given_a_write_events_message()

    await conversation.start(output)

    await output.get()
    payload = proto.WriteEventsCompleted()
    payload.result = msg.OperationResult.Success
    payload.first_event_number = 73
    payload.last_event_number = 73

    await conversation.respond_to(
        msg.InboundMessage(
            conversation.conversation_id,
            msg.TcpCommand.WriteEventsCompleted,
            payload.SerializeToString(),
        ),
        output,
    )

    result = await conversation.result

    assert result.first_event_number == 73
    assert result.last_event_number == 73
    assert result.result == msg.OperationResult.Success
    assert conversation.is_complete
async def test_stream_paging():

    output = TeeQueue()
    convo = IterAllEvents()
    response = proto.ReadAllEventsCompleted()
    response.result = msg.ReadEventResult.Success
    response.commit_position = 10
    response.prepare_position = 10
    response.next_commit_position = 11
    response.next_prepare_position = 12

    await convo.respond_to(
        msg.InboundMessage(
            uuid4(),
            msg.TcpCommand.ReadStreamEventsForwardCompleted,
            response.SerializeToString(),
        ),
        output,
    )

    reply = await output.get()
    body = proto.ReadAllEvents()
    body.ParseFromString(reply.payload)

    assert body.commit_position == 11
    assert body.prepare_position == 12
async def test_read_single_event_success():

    event_id = uuid4()

    convo = ReadEvent("my-stream", 23)
    response = proto.ReadEventCompleted()
    response.result = msg.ReadEventResult.Success

    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 = msg.ContentType.Json
    response.event.event.metadata_content_type = msg.ContentType.Binary
    response.event.event.data = """
    {
        'color': 'red',
        'winner': true
    }
    """.encode("UTF-8")

    await convo.respond_to(
        msg.InboundMessage(uuid4(), msg.TcpCommand.ReadEventCompleted,
                           response.SerializeToString()),
        None,
    )

    result = await convo.result

    assert result.event.stream == "stream-123"
    assert result.event.id == event_id
    assert result.event.type == "event-type"
    assert result.event.event_number == 32

    assert result.link is None
async def test_not_authenticated():

    output = TeeQueue()

    event_id = uuid4()
    conversation_id = uuid4()
    error_message = "Dude, like who even are you?"

    event_type = "pony_jumped"
    data = {"pony_name": "Burning Sulphur", "distance": 6}
    event_data = msg.NewEventData(event_id, event_type, data, None)

    conversation = WriteEvents("my-stream", [event_data],
                               conversation_id=conversation_id)

    await conversation.start(output)
    await conversation.respond_to(
        msg.InboundMessage(
            conversation_id,
            msg.TcpCommand.NotAuthenticated,
            error_message.encode("UTF-8"),
        ),
        output,
    )

    with pytest.raises(exn.NotAuthenticated) as exc:
        await conversation.result
        assert exc.message == error_message
Exemple #8
0
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_bad_request():

    output = TeeQueue()

    event_id = uuid4()
    conversation_id = uuid4()
    error_message = "That's not an acceptable message, man"

    event_type = "pony_jumped"
    data = {"pony_name": "Burning Sulphur", "distance": 6}
    event_data = msg.NewEventData(event_id, event_type, data, None)

    conversation = WriteEvents("my-stream", [event_data],
                               conversation_id=conversation_id)

    await conversation.start(output)
    await conversation.respond_to(
        msg.InboundMessage(conversation_id, msg.TcpCommand.BadRequest,
                           error_message.encode("UTF-8")),
        output,
    )

    with pytest.raises(exn.BadRequest) as exc:
        await conversation.result
        assert exc.message == error_message
Exemple #10
0
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_success():

    event_1_id = uuid4()
    event_2_id = uuid4()

    convo = ReadStreamEvents("my-stream", 0)
    response = proto.ReadStreamEventsCompleted()
    response.result = msg.ReadEventResult.Success
    response.next_event_number = 10
    response.last_event_number = 9
    response.is_end_of_stream = True
    response.last_commit_position = 8

    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.ReadEventCompleted,
                           response.SerializeToString()),
        None,
    )

    result = await convo.result

    assert isinstance(result, msg.StreamSlice)

    [event_1, event_2] = result.events
    assert event_1.event.stream == "stream-123"
    assert event_1.event.id == event_1_id
    assert event_1.event.type == "event-type"
    assert event_1.event.event_number == 32

    assert event_2.event.stream == "stream-123"
    assert event_2.event.id == event_2_id
    assert event_2.event.type == "event-2-type"
    assert event_2.event.event_number == 33
Exemple #12
0
def read_stream_events_failure(conversation_id, result):
    payload = proto.ReadStreamEventsCompleted()
    payload.result = result
    payload.last_event_number = 1
    payload.next_event_number = 1
    payload.last_commit_position = 1
    payload.is_end_of_stream = False

    return msg.InboundMessage(
        conversation_id,
        msg.TcpCommand.ReadStreamEventsForwardCompleted,
        payload.SerializeToString(),
    )
Exemple #13
0
async def test_error_mid_stream():

    output = TeeQueue()
    convo = IterStreamEvents("my-stream")
    response = proto.ReadStreamEventsCompleted()
    response.result = msg.ReadStreamResult.Success
    response.is_end_of_stream = False
    response.next_event_number = 0
    response.last_event_number = 0
    response.last_commit_position = 0

    await convo.respond_to(
        msg.InboundMessage(
            uuid4(),
            msg.TcpCommand.ReadStreamEventsForwardCompleted,
            response.SerializeToString(),
        ),
        output,
    )

    response.result = msg.ReadStreamResult.AccessDenied

    await convo.respond_to(
        msg.InboundMessage(
            uuid4(),
            msg.TcpCommand.ReadStreamEventsForwardCompleted,
            response.SerializeToString(),
        ),
        output,
    )

    iterator = await convo.result
    with pytest.raises(exceptions.AccessDenied) as exn:
        await iterator.anext()

        assert exn.conversation_id == convo.conversation_id
        assert exn.conversation_type == "IterStreamEvents"

    assert len(output.items) == 1
async def test_access_denied():
    convo = ReadEvent("my-stream", 23)
    await convo.respond_to(
        msg.InboundMessage(
            uuid4(),
            msg.TcpCommand.ReadEventCompleted,
            error_result(msg.ReadEventResult.AccessDenied),
        ),
        None,
    )

    with pytest.raises(exceptions.AccessDenied) as exn:
        await convo.result
        assert exn.conversation_type == "ReadEvent"
async def test_read_error():
    convo = ReadEvent("my-stream", 23)
    await convo.respond_to(
        msg.InboundMessage(
            uuid4(),
            msg.TcpCommand.ReadEventCompleted,
            error_result(msg.ReadEventResult.Error),
        ),
        None,
    )

    with pytest.raises(exceptions.ReadError) as exn:
        await convo.result
        assert exn.stream == "my-stream"
Exemple #16
0
async def drop_subscription(
    convo, output, reason=msg.SubscriptionDropReason.Unsubscribed
):

    response = proto.SubscriptionDropped()
    response.reason = reason

    await convo.respond_to(
        msg.InboundMessage(
            uuid.uuid4(),
            msg.TcpCommand.SubscriptionDropped,
            response.SerializeToString(),
        ),
        output,
    )
async def test_event_not_found():

    convo = ReadEvent("my-stream", 23)
    await convo.respond_to(
        msg.InboundMessage(
            uuid4(),
            msg.TcpCommand.ReadEventCompleted,
            error_result(msg.ReadEventResult.NotFound),
        ),
        None,
    )

    with pytest.raises(exceptions.EventNotFound) as exn:
        await convo.result
        assert exn.stream == "my-stream"
        assert exn.event_number == 23
async def test_not_master():

    output = TeeQueue()
    payload = proto.NotHandled()
    payload.reason = msg.NotHandledReason.NotMaster

    conversation = Ping()
    await conversation.respond_to(
        msg.InboundMessage(uuid4(), msg.TcpCommand.NotHandled,
                           payload.SerializeToString()),
        output,
    )

    with pytest.raises(exn.NotMaster) as exc:
        await conversation.result
        assert exc.conversation_id == conversation.conversation_id
Exemple #19
0
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(
        msg.InboundMessage(
            uuid.uuid4(),
            msg.TcpCommand.SubscriptionConfirmation,
            response.SerializeToString(),
        ),
        output_queue,
    )

    return await convo.result
async def test_decode_error():
    """
    If we give the conversation an invalid payload, it should
    raise PayloadUnreadable.
    """

    output = TeeQueue()
    conversation = Ping()
    await conversation.respond_to(
        msg.InboundMessage(uuid4(), msg.TcpCommand.NotHandled, b"\x08\2A"),
        output)

    with pytest.raises(exn.PayloadUnreadable) as exc:
        await conversation.result
        assert exc.conversation_id == conversation.conversation_id

    assert conversation.is_complete
async def test_notready_message():

    output = TeeQueue()
    payload = proto.NotHandled()
    payload.reason = msg.NotHandledReason.NotReady
    conversation = Ping()

    with pytest.raises(exn.NotReady):
        await conversation.respond_to(
            msg.InboundMessage(uuid4(), msg.TcpCommand.NotHandled,
                               payload.SerializeToString()),
            output,
        )

        await conversation.result

    assert conversation.is_complete
async def test_event_exposes_event_record():
    """
    See github.com/madedotcom/photon-pump/issues/42

    Briefly, the Event type should expose the properties of its wrapped
    EventRecord to make things more usable.
    """

    event_id = uuid4()

    convo = ReadEvent("my-stream", 23)
    response = proto.ReadEventCompleted()
    response.result = msg.ReadEventResult.Success

    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 = msg.ContentType.Json
    response.event.event.metadata_content_type = msg.ContentType.Binary
    response.event.event.data = """
    {
        'color': 'red',
        'winner': true
    }
    """.encode("UTF-8")

    await convo.respond_to(
        msg.InboundMessage(uuid4(), msg.TcpCommand.ReadEventCompleted,
                           response.SerializeToString()),
        None,
    )

    result = await convo.result

    assert result.stream == "stream-123"
    assert result.id == event_id
    assert result.type == "event-type"
    assert result.event_number == 32

    assert result.link is None
Exemple #23
0
async def test_all_events_access_denied():

    convo = ReadAllEvents()
    response = proto.ReadAllEventsCompleted()
    response.result = msg.ReadAllResult.AccessDenied
    response.next_commit_position = 10
    response.next_prepare_position = 10
    response.commit_position = 9
    response.prepare_position = 9

    await convo.respond_to(
        msg.InboundMessage(uuid4(), msg.TcpCommand.ReadAllEventsForward,
                           response.SerializeToString()),
        None,
    )

    with pytest.raises(exceptions.AccessDenied) as exn:
        await convo.result

        assert exn.conversation_id == convo.conversation_id
        assert exn.conversation_type == "ReadAllEvents"
Exemple #24
0
def subscription_event_appeared(
    conversation_id: UUID,
    event: msg.NewEventData,
    stream: str = "my-stream",
    event_number: int = 1,
):
    payload = proto.PersistentSubscriptionStreamEventAppeared()
    e = payload.event.event
    e.event_stream_id = stream
    e.event_number = event_number
    e.event_id = event.id.bytes_le
    e.event_type = event.type
    e.data_content_type = msg.ContentType.Json
    e.metadata_content_type = msg.ContentType.Binary
    e.data = json.dumps(event.data).encode("UTF-8")

    return msg.InboundMessage(
        conversation_id,
        msg.TcpCommand.PersistentSubscriptionStreamEventAppeared,
        payload.SerializeToString(),
    )
async def test_stream_deleted():

    convo = ReadStreamEvents("my-stream")
    response = proto.ReadStreamEventsCompleted()
    response.result = msg.ReadStreamResult.StreamDeleted
    response.is_end_of_stream = False
    response.next_event_number = 0
    response.last_event_number = 0
    response.last_commit_position = 0

    await convo.respond_to(
        msg.InboundMessage(
            uuid4(),
            msg.TcpCommand.ReadStreamEventsForwardCompleted,
            response.SerializeToString(),
        ),
        None,
    )

    with pytest.raises(exceptions.StreamDeleted) as exn:
        await convo.result
        assert exn.stream == "my-stream"
        assert exn.conversation_id == convo.conversation_id
Exemple #26
0
def read_stream_events_completed(conversation_id, stream, events, end_of_stream=False):
    payload = proto.ReadStreamEventsCompleted()
    payload.result = msg.ReadStreamResult.Success
    payload.is_end_of_stream = end_of_stream

    for (idx, event) in enumerate(events):
        payload.next_event_number = idx + 1
        payload.last_event_number = idx
        payload.last_commit_position = idx

        e = payload.events.add()
        e.event.event_stream_id = stream
        e.event.event_number = idx
        e.event.event_id = event.id.bytes_le
        e.event.event_type = event.type
        e.event.data_content_type = msg.ContentType.Json
        e.event.metadata_content_type = msg.ContentType.Binary
        e.event.data = json.dumps(event.data).encode("UTF-8")

    return msg.InboundMessage(
        conversation_id,
        msg.TcpCommand.ReadStreamEventsForwardCompleted,
        payload.SerializeToString(),
    )
async def test_read_error():

    convo = ReadStreamEvents("my-stream")
    response = proto.ReadStreamEventsCompleted()
    response.result = msg.ReadStreamResult.Error
    response.is_end_of_stream = False
    response.next_event_number = 0
    response.last_event_number = 0
    response.last_commit_position = 0
    response.error = "Something really weird just happened"

    await convo.respond_to(
        msg.InboundMessage(
            uuid4(),
            msg.TcpCommand.ReadStreamEventsForwardCompleted,
            response.SerializeToString(),
        ),
        None,
    )

    with pytest.raises(exceptions.ReadError) as exn:
        await convo.result
        assert exn.stream == "my-stream"
        assert exn.conversation_id == convo.conversation_id
Exemple #28
0
async def test_all_events_error():

    convo = ReadAllEvents()
    response = proto.ReadAllEventsCompleted()
    response.result = msg.ReadAllResult.Error
    response.next_commit_position = 10
    response.next_prepare_position = 10
    response.commit_position = 9
    response.prepare_position = 9
    response.error = "Something really weird just happened"

    await convo.respond_to(
        msg.InboundMessage(
            uuid4(),
            msg.TcpCommand.ReadAllEventsForwardCompleted,
            response.SerializeToString(),
        ),
        None,
    )

    with pytest.raises(exceptions.ReadError) as exn:
        await convo.result
        assert exn.stream == "$all"
        assert exn.conversation_id == convo.conversation_id
Exemple #29
0
async def test_read_all_success():

    event_1_id = uuid4()
    event_2_id = uuid4()

    convo = ReadAllEvents()
    response = proto.ReadAllEventsCompleted()
    response.result = msg.ReadEventResult.Success
    response.next_commit_position = 10
    response.next_prepare_position = 10
    response.commit_position = 9
    response.prepare_position = 9

    event_1 = proto.ResolvedEvent()
    event_1.commit_position = 8
    event_1.prepare_position = 8
    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.ResolvedEvent()
    event_2.CopyFrom(event_1)
    event_2.event.event_stream_id = "stream-456"
    event_2.event.event_type = "event-2-type"
    event_2.event.event_id = event_2_id.bytes_le
    event_2.event.event_number = 32

    response.events.extend([event_1, event_2])

    await convo.respond_to(
        msg.InboundMessage(
            uuid4(),
            msg.TcpCommand.ReadAllEventsForwardCompleted,
            response.SerializeToString(),
        ),
        None,
    )

    result = await convo.result

    assert isinstance(result, msg.AllStreamSlice)

    [event_1, event_2] = result.events
    assert event_1.stream == "stream-123"
    assert event_1.id == event_1_id
    assert event_1.type == "event-type"
    assert event_1.event_number == 32

    assert event_2.stream == "stream-456"
    assert event_2.id == event_2_id
    assert event_2.type == "event-2-type"
    assert event_2.event_number == 32
Exemple #30
0
async def reply_to(convo, message, output):
    command, payload = message
    await convo.respond_to(msg.InboundMessage(uuid.uuid4(), command, payload), output)