public void Setup()
 {
     _sub = new Core.Services.PersistentSubscription.PersistentSubscription(
         PersistentSubscriptionParamsBuilder.CreateFor("streamName", "groupName")
             .WithEventLoader(new FakeStreamReader(x => { }))
             .WithCheckpointReader(new FakeCheckpointReader())
             .WithCheckpointWriter(new FakeCheckpointWriter(x => { }))
             .WithMessageParker(new FakeMessageParker()));
 }
        public void events_are_skipped_if_assigned_client_full()
        {
            var          client1Envelope    = new FakeEnvelope();
            var          client2Envelope    = new FakeEnvelope();
            var          reader             = new FakeCheckpointReader();
            const string subsctiptionStream = "$ce-streamName";
            var          sub = new Core.Services.PersistentSubscription.PersistentSubscription(
                PersistentSubscriptionParamsBuilder.CreateFor(subsctiptionStream, "groupName")
                .WithEventLoader(new FakeStreamReader(x => { }))
                .WithCheckpointReader(reader)
                .WithCheckpointWriter(new FakeCheckpointWriter(x => { }))
                .WithMessageParker(new FakeMessageParker())
                .CustomConsumerStrategy(new PinnedPersistentSubscriptionConsumerStrategy(new XXHashUnsafe()))
                .StartFromCurrent());

            reader.Load(null);

            var correlationId = Guid.NewGuid();

            sub.AddClient(correlationId, Guid.NewGuid(), "connection-1", client1Envelope, 1, "foo", "bar");

            sub.AddClient(Guid.NewGuid(), Guid.NewGuid(), "connection-2", client2Envelope, 1, "foo", "bar");


            var message1 = Guid.NewGuid();

            sub.NotifyLiveSubscriptionMessage(Helper.BuildLinkEvent(message1, subsctiptionStream, 0,
                                                                    Helper.BuildFakeEvent(Guid.NewGuid(), "type", "streamName-1", 0), false));

            Assert.That(client1Envelope.Replies.Count, Is.EqualTo(1));
            Assert.That(client2Envelope.Replies.Count, Is.EqualTo(0));

            sub.NotifyLiveSubscriptionMessage(Helper.BuildLinkEvent(Guid.NewGuid(), subsctiptionStream, 1,
                                                                    Helper.BuildFakeEvent(Guid.NewGuid(), "type", "streamName-1", 0), false));

            Assert.That(client1Envelope.Replies.Count, Is.EqualTo(1));
            Assert.That(client2Envelope.Replies.Count, Is.EqualTo(0));
            Assert.That(sub._streamBuffer.BufferCount, Is.EqualTo(1));

            sub.NotifyLiveSubscriptionMessage(Helper.BuildLinkEvent(Guid.NewGuid(), subsctiptionStream, 2,
                                                                    Helper.BuildFakeEvent(Guid.NewGuid(), "type", "streamName-2", 0), false));

            Assert.That(client1Envelope.Replies.Count, Is.EqualTo(1));
            Assert.That(client2Envelope.Replies.Count, Is.EqualTo(1));

            Assert.That(sub._streamBuffer.BufferCount, Is.EqualTo(1));

            sub.AcknowledgeMessagesProcessed(correlationId, new[] { message1 });

            Assert.That(client1Envelope.Replies.Count, Is.EqualTo(2));
            Assert.That(client2Envelope.Replies.Count, Is.EqualTo(1));

            Assert.That(sub._streamBuffer.BufferCount, Is.EqualTo(0));
        }
        public void null_checkpoint_reader_throws_argument_null()
        {
            Assert.Throws<ArgumentNullException>(() =>
            {
                _sub = new Core.Services.PersistentSubscription.PersistentSubscription(
                    PersistentSubscriptionParamsBuilder.CreateFor("streamName", "groupName")
                        .WithEventLoader(new FakeStreamReader(x => { }))
                        .WithCheckpointReader(null)
                        .WithCheckpointWriter(new FakeCheckpointWriter(x => { }))
                        .WithMessageParker(new FakeMessageParker()));

            });
        }
        public void available_capacity_is_tracked_with_acked_messages()
        {
            var          client1Envelope          = new FakeEnvelope();
            var          client2Envelope          = new FakeEnvelope();
            var          reader                   = new FakeCheckpointReader();
            const string subsctiptionStream       = "$ce-streamName";
            PersistentSubscriptionParams settings = PersistentSubscriptionToStreamParamsBuilder
                                                    .CreateFor(subsctiptionStream, "groupName")
                                                    .WithEventLoader(new FakeStreamReader())
                                                    .WithCheckpointReader(reader)
                                                    .WithCheckpointWriter(new FakeCheckpointWriter(x => { }))
                                                    .WithMessageParker(new FakeMessageParker())
                                                    .CustomConsumerStrategy(new PinnedPersistentSubscriptionConsumerStrategy(new XXHashUnsafe()))
                                                    .StartFromCurrent();
            var consumerStrategy = (PinnedPersistentSubscriptionConsumerStrategy)settings.ConsumerStrategy;
            var sub = new Core.Services.PersistentSubscription.PersistentSubscription(settings);

            reader.Load(null);
            var correlationId1 = Guid.NewGuid();

            sub.AddClient(correlationId1, Guid.NewGuid(), "connection-1", client1Envelope, 14, "foo", "bar");
            Assert.That(consumerStrategy.AvailableCapacity, Is.EqualTo(14));

            var correlationId2 = Guid.NewGuid();

            sub.AddClient(correlationId2, Guid.NewGuid(), "connection-2", client2Envelope, 10, "foo", "bar");

            Assert.That(consumerStrategy.AvailableCapacity, Is.EqualTo(24));

            var message1 = Guid.NewGuid();

            sub.NotifyLiveSubscriptionMessage(Helper.BuildLinkEvent(message1, subsctiptionStream, 0,
                                                                    Helper.BuildFakeEvent(Guid.NewGuid(), "type", "streamName-1", 0), false));

            Assert.That(consumerStrategy.AvailableCapacity, Is.EqualTo(23));

            var message2 = Guid.NewGuid();

            sub.NotifyLiveSubscriptionMessage(Helper.BuildLinkEvent(message2, subsctiptionStream, 1,
                                                                    Helper.BuildFakeEvent(Guid.NewGuid(), "type", "streamName-2", 0), false));

            Assert.That(consumerStrategy.AvailableCapacity, Is.EqualTo(22));

            sub.AcknowledgeMessagesProcessed(correlationId1, new[] { message1 });

            Assert.That(consumerStrategy.AvailableCapacity, Is.EqualTo(23));

            sub.AcknowledgeMessagesProcessed(correlationId2, new[] { message2 });

            Assert.That(consumerStrategy.AvailableCapacity, Is.EqualTo(24));
        }
        public void resolved_link_events_use_event_stream_id()
        {
            var          client1Envelope    = new FakeEnvelope();
            var          client2Envelope    = new FakeEnvelope();
            var          reader             = new FakeCheckpointReader();
            const string subsctiptionStream = "$ce-streamName";
            var          sub = new Core.Services.PersistentSubscription.PersistentSubscription(
                PersistentSubscriptionToStreamParamsBuilder.CreateFor(subsctiptionStream, "groupName")
                .WithEventLoader(new FakeStreamReader())
                .WithCheckpointReader(reader)
                .WithCheckpointWriter(new FakeCheckpointWriter(x => { }))
                .WithMessageParker(new FakeMessageParker())
                .CustomConsumerStrategy(new PinnedPersistentSubscriptionConsumerStrategy(new XXHashUnsafe()))
                .StartFromCurrent());

            reader.Load(null);
            sub.AddClient(Guid.NewGuid(), Guid.NewGuid(), "connection-1", client1Envelope, 10, "foo", "bar");
            sub.AddClient(Guid.NewGuid(), Guid.NewGuid(), "connection-2", client2Envelope, 10, "foo", "bar");

            sub.NotifyLiveSubscriptionMessage(Helper.BuildLinkEvent(Guid.NewGuid(), subsctiptionStream, 0,
                                                                    Helper.BuildFakeEvent(Guid.NewGuid(), "type", "streamName-1", 0)));

            Assert.AreEqual(1, client1Envelope.Replies.Count);
            Assert.AreEqual(0, client2Envelope.Replies.Count);

            sub.NotifyLiveSubscriptionMessage(Helper.BuildLinkEvent(Guid.NewGuid(), subsctiptionStream, 1,
                                                                    Helper.BuildFakeEvent(Guid.NewGuid(), "type", "streamName-2", 0)));

            Assert.AreEqual(1, client1Envelope.Replies.Count);
            Assert.AreEqual(1, client2Envelope.Replies.Count);

            sub.NotifyLiveSubscriptionMessage(Helper.BuildLinkEvent(Guid.NewGuid(), subsctiptionStream, 2,
                                                                    Helper.BuildFakeEvent(Guid.NewGuid(), "type", "streamName-3", 0)));

            Assert.AreEqual(2, client1Envelope.Replies.Count);
            Assert.AreEqual(1, client2Envelope.Replies.Count);

            sub.NotifyLiveSubscriptionMessage(Helper.BuildLinkEvent(Guid.NewGuid(), subsctiptionStream, 3,
                                                                    Helper.BuildFakeEvent(Guid.NewGuid(), "type", "streamName-4", 0)));

            Assert.AreEqual(2, client1Envelope.Replies.Count);
            Assert.AreEqual(2, client2Envelope.Replies.Count);
        }
        public void new_subscription_gets_work()
        {
            var          client1Envelope    = new FakeEnvelope();
            var          client2Envelope    = new FakeEnvelope();
            var          client3Envelope    = new FakeEnvelope();
            var          reader             = new FakeCheckpointReader();
            const string subsctiptionStream = "$ce-streamName";
            var          sub = new Core.Services.PersistentSubscription.PersistentSubscription(
                PersistentSubscriptionToStreamParamsBuilder.CreateFor(subsctiptionStream, "groupName")
                .WithEventLoader(new FakeStreamReader())
                .WithCheckpointReader(reader)
                .WithCheckpointWriter(new FakeCheckpointWriter(x => { }))
                .WithMessageParker(new FakeMessageParker())
                .CustomConsumerStrategy(new PinnedPersistentSubscriptionConsumerStrategy(new ByLengthHasher()))
                .StartFromCurrent());

            reader.Load(null);
            sub.AddClient(Guid.NewGuid(), Guid.NewGuid(), "connection-1", client1Envelope, 10, "foo", "bar");
            sub.AddClient(Guid.NewGuid(), Guid.NewGuid(), "connection-2", client2Envelope, 10, "foo", "bar");

            sub.NotifyLiveSubscriptionMessage(Helper.BuildFakeEvent(Guid.NewGuid(), "type", "1", 0));
            sub.NotifyLiveSubscriptionMessage(Helper.BuildFakeEvent(Guid.NewGuid(), "type", "11", 1));
            sub.NotifyLiveSubscriptionMessage(Helper.BuildFakeEvent(Guid.NewGuid(), "type", "111", 2));
            sub.NotifyLiveSubscriptionMessage(Helper.BuildFakeEvent(Guid.NewGuid(), "type", "1111", 3));
            sub.NotifyLiveSubscriptionMessage(Helper.BuildFakeEvent(Guid.NewGuid(), "type", "11111", 4));
            sub.NotifyLiveSubscriptionMessage(Helper.BuildFakeEvent(Guid.NewGuid(), "type", "111111", 5));

            Assert.AreEqual(3, client1Envelope.Replies.Count);
            Assert.AreEqual(3, client2Envelope.Replies.Count);

            sub.AddClient(Guid.NewGuid(), Guid.NewGuid(), "connection-3", client3Envelope, 10, "foo", "bar");

            sub.NotifyLiveSubscriptionMessage(Helper.BuildFakeEvent(Guid.NewGuid(), "type", "1", 6));
            sub.NotifyLiveSubscriptionMessage(Helper.BuildFakeEvent(Guid.NewGuid(), "type", "11", 7));
            sub.NotifyLiveSubscriptionMessage(Helper.BuildFakeEvent(Guid.NewGuid(), "type", "111", 8));
            sub.NotifyLiveSubscriptionMessage(Helper.BuildFakeEvent(Guid.NewGuid(), "type", "1111", 9));
            sub.NotifyLiveSubscriptionMessage(Helper.BuildFakeEvent(Guid.NewGuid(), "type", "11111", 10));
            sub.NotifyLiveSubscriptionMessage(Helper.BuildFakeEvent(Guid.NewGuid(), "type", "111111", 11));

            Assert.AreEqual(5, client1Envelope.Replies.Count);
            Assert.AreEqual(5, client2Envelope.Replies.Count);
            Assert.AreEqual(2, client3Envelope.Replies.Count);
        }
        public void live_subscription_with_pinned_pushes_events_to_same_client_for_stream_id()
        {
            var client1Envelope = new FakeEnvelope();
            var client2Envelope = new FakeEnvelope();
            var reader          = new FakeCheckpointReader();

            var sub = new Core.Services.PersistentSubscription.PersistentSubscription(
                PersistentSubscriptionToStreamParamsBuilder.CreateFor("$ce-streamName", "groupName")
                .WithEventLoader(new FakeStreamReader())
                .WithCheckpointReader(reader)
                .WithCheckpointWriter(new FakeCheckpointWriter(x => { }))
                .WithMessageParker(new FakeMessageParker())
                .CustomConsumerStrategy(new PinnedPersistentSubscriptionConsumerStrategy(new XXHashUnsafe()))
                .StartFromCurrent());

            reader.Load(null);
            sub.AddClient(Guid.NewGuid(), Guid.NewGuid(), "connection-1", client1Envelope, 10, "foo", "bar");
            sub.AddClient(Guid.NewGuid(), Guid.NewGuid(), "connection-2", client2Envelope, 10, "foo", "bar");

            sub.NotifyLiveSubscriptionMessage(Helper.BuildFakeEvent(Guid.NewGuid(), "type", "streamName-1", 0));
            sub.NotifyLiveSubscriptionMessage(Helper.BuildFakeEvent(Guid.NewGuid(), "type", "streamName-1", 1));

            Assert.AreEqual(2, client1Envelope.Replies.Count);
            Assert.AreEqual(0, client2Envelope.Replies.Count);

            sub.NotifyLiveSubscriptionMessage(Helper.BuildFakeEvent(Guid.NewGuid(), "type", "streamName-2", 2));
            sub.NotifyLiveSubscriptionMessage(Helper.BuildFakeEvent(Guid.NewGuid(), "type", "streamName-2", 3));

            Assert.AreEqual(2, client1Envelope.Replies.Count);
            Assert.AreEqual(2, client2Envelope.Replies.Count);

            sub.NotifyLiveSubscriptionMessage(Helper.BuildFakeEvent(Guid.NewGuid(), "type", "streamName-1", 4));

            Assert.AreEqual(3, client1Envelope.Replies.Count);
            Assert.AreEqual(2, client2Envelope.Replies.Count);

            sub.NotifyLiveSubscriptionMessage(Helper.BuildFakeEvent(Guid.NewGuid(), "type", "streamName-3", 5));

            Assert.AreEqual(4, client1Envelope.Replies.Count);
            Assert.AreEqual(2, client2Envelope.Replies.Count);
        }
        public void live_subscription_with_pinned_pushes_events_to_same_client_for_stream_id()
        {
            var client1Envelope = new FakeEnvelope();
            var client2Envelope = new FakeEnvelope();
            var reader = new FakeCheckpointReader();

            var sub = new Core.Services.PersistentSubscription.PersistentSubscription(
                PersistentSubscriptionParamsBuilder.CreateFor("$ce-streamName", "groupName")
                    .WithEventLoader(new FakeStreamReader(x => { }))
                    .WithCheckpointReader(reader)
                    .WithCheckpointWriter(new FakeCheckpointWriter(x => { }))
                    .WithMessageParker(new FakeMessageParker())
                    .CustomConsumerStrategy(new PinnedPersistentSubscriptionConsumerStrategy(new XXHashUnsafe()))
                    .StartFromCurrent());
            reader.Load(null);
            sub.AddClient(Guid.NewGuid(), Guid.NewGuid(), client1Envelope, 10, "foo", "bar");
            sub.AddClient(Guid.NewGuid(), Guid.NewGuid(), client2Envelope, 10, "foo", "bar");

            sub.NotifyLiveSubscriptionMessage(Helper.BuildFakeEvent(Guid.NewGuid(), "type", "streamName-1", 0));
            sub.NotifyLiveSubscriptionMessage(Helper.BuildFakeEvent(Guid.NewGuid(), "type", "streamName-1", 1));

            Assert.AreEqual(2, client1Envelope.Replies.Count);
            Assert.AreEqual(0, client2Envelope.Replies.Count);

            sub.NotifyLiveSubscriptionMessage(Helper.BuildFakeEvent(Guid.NewGuid(), "type", "streamName-2", 2));
            sub.NotifyLiveSubscriptionMessage(Helper.BuildFakeEvent(Guid.NewGuid(), "type", "streamName-2", 3));

            Assert.AreEqual(2, client1Envelope.Replies.Count);
            Assert.AreEqual(2, client2Envelope.Replies.Count);

            sub.NotifyLiveSubscriptionMessage(Helper.BuildFakeEvent(Guid.NewGuid(), "type", "streamName-1", 4));

            Assert.AreEqual(3, client1Envelope.Replies.Count);
            Assert.AreEqual(2, client2Envelope.Replies.Count);

            sub.NotifyLiveSubscriptionMessage(Helper.BuildFakeEvent(Guid.NewGuid(), "type", "streamName-3", 5));

            Assert.AreEqual(4, client1Envelope.Replies.Count);
            Assert.AreEqual(2, client2Envelope.Replies.Count);
        }
        public void available_capacity_is_tracked()
        {
            var          client1Envelope          = new FakeEnvelope();
            var          client2Envelope          = new FakeEnvelope();
            var          reader                   = new FakeCheckpointReader();
            const string subsctiptionStream       = "$ce-streamName";
            PersistentSubscriptionParams settings = PersistentSubscriptionToStreamParamsBuilder
                                                    .CreateFor(subsctiptionStream, "groupName")
                                                    .WithEventLoader(new FakeStreamReader())
                                                    .WithCheckpointReader(reader)
                                                    .WithCheckpointWriter(new FakeCheckpointWriter(x => { }))
                                                    .WithMessageParker(new FakeMessageParker())
                                                    .CustomConsumerStrategy(new PinnedPersistentSubscriptionConsumerStrategy(new XXHashUnsafe()))
                                                    .StartFromCurrent();
            var consumerStrategy = (PinnedPersistentSubscriptionConsumerStrategy)settings.ConsumerStrategy;
            var sub = new Core.Services.PersistentSubscription.PersistentSubscription(settings);

            reader.Load(null);
            var client1Id = Guid.NewGuid();

            sub.AddClient(Guid.NewGuid(), client1Id, "connection-1", client1Envelope, 14, "foo", "bar");

            Assert.That(consumerStrategy.AvailableCapacity, Is.EqualTo(14));

            var client2Id = Guid.NewGuid();

            sub.AddClient(Guid.NewGuid(), client2Id, "connection-2", client2Envelope, 10, "foo", "bar");

            Assert.That(consumerStrategy.AvailableCapacity, Is.EqualTo(24));

            sub.RemoveClientByConnectionId(client2Id);

            Assert.That(consumerStrategy.AvailableCapacity, Is.EqualTo(14));

            sub.RemoveClientByConnectionId(client1Id);

            Assert.That(consumerStrategy.AvailableCapacity, Is.EqualTo(0));
        }
        public void bad_availablecapacity_scneanrio_causing_null_reference()
        {
            var          client1Envelope    = new FakeEnvelope();
            var          client2Envelope    = new FakeEnvelope();
            var          reader             = new FakeCheckpointReader();
            const string subsctiptionStream = "$ce-streamName";
            var          sub = new Core.Services.PersistentSubscription.PersistentSubscription(
                PersistentSubscriptionToStreamParamsBuilder.CreateFor(subsctiptionStream, "groupName")
                .WithEventLoader(new FakeStreamReader())
                .WithCheckpointReader(reader)
                .WithCheckpointWriter(new FakeCheckpointWriter(x => { }))
                .WithMessageParker(new FakeMessageParker())
                .CustomConsumerStrategy(new PinnedPersistentSubscriptionConsumerStrategy(new ByLengthHasher()))
                .StartFromCurrent());

            reader.Load(null);
            var conn1Id = Guid.NewGuid();

            sub.AddClient(Guid.NewGuid(), conn1Id, "connection-1", client1Envelope, 10, "foo", "bar");

            sub.NotifyLiveSubscriptionMessage(Helper.BuildFakeEvent(Guid.NewGuid(), "type", "1", 0));
            sub.NotifyLiveSubscriptionMessage(Helper.BuildFakeEvent(Guid.NewGuid(), "type", "11", 1));
            sub.NotifyLiveSubscriptionMessage(Helper.BuildFakeEvent(Guid.NewGuid(), "type", "111", 2));

            Assert.AreEqual(3, client1Envelope.Replies.Count);

            var conn2Id = Guid.NewGuid();

            sub.AddClient(Guid.NewGuid(), conn2Id, "connection-2", client2Envelope, 10, "foo", "bar");

            Assert.AreEqual(3, client1Envelope.Replies.Count);
            Assert.AreEqual(0, client2Envelope.Replies.Count);

            sub.RemoveClientByConnectionId(conn1Id);

            // Used to throw a null reference exception.
            Assert.That(() => sub.RemoveClientByConnectionId(conn2Id), Throws.Nothing);
        }
        public void timeout_park_correctly_tracks_the_available_client_slots()
        {
            var envelope1 = new FakeEnvelope();
            var reader = new FakeCheckpointReader();
            var parker = new FakeMessageParker();
            var sub = new Core.Services.PersistentSubscription.PersistentSubscription(
                PersistentSubscriptionParamsBuilder.CreateFor("streamName", "groupName")
                    .WithEventLoader(new FakeStreamReader(x => { }))
                    .WithCheckpointReader(reader)
                    .WithCheckpointWriter(new FakeCheckpointWriter(i => { }))
                    .WithMessageParker(parker)
                    .WithMaxRetriesOf(0)
                    .WithMessageTimeoutOf(TimeSpan.Zero)
                    .StartFromBeginning());
            reader.Load(null);
            sub.AddClient(Guid.NewGuid(), Guid.NewGuid(), envelope1, 2, "foo", "bar");

            sub.HandleReadCompleted(new[]
            {
                Helper.BuildFakeEvent(Guid.NewGuid(), "type", "streamName", 0),
                Helper.BuildFakeEvent(Guid.NewGuid(), "type", "streamName", 1)
            }, 1, false);

            Assert.AreEqual(2, envelope1.Replies.Count);

            // Should expire first 2 and send to park.
            sub.NotifyClockTick(DateTime.Now.AddSeconds(1));
            parker.ParkMessageCompleted(0, OperationResult.Success);
            parker.ParkMessageCompleted(1, OperationResult.Success);
            Assert.AreEqual(2, parker.ParkedEvents.Count);

            // The next 2 should still be sent to client.
            sub.HandleReadCompleted(new[]
            {
                Helper.BuildFakeEvent(Guid.NewGuid(), "type", "streamName", 0),
                Helper.BuildFakeEvent(Guid.NewGuid(), "type", "streamName", 1)
            }, 1, false);

            Assert.AreEqual(4, envelope1.Replies.Count);
        }
 public void multiple_messages_get_timed_out_and_parked_after_max_retry_count()
 {
     var envelope1 = new FakeEnvelope();
     var reader = new FakeCheckpointReader();
     var parker = new FakeMessageParker();
     var sub = new Core.Services.PersistentSubscription.PersistentSubscription(
         PersistentSubscriptionParamsBuilder.CreateFor("streamName", "groupName")
             .WithEventLoader(new FakeStreamReader(x => { }))
             .WithCheckpointReader(reader)
             .WithCheckpointWriter(new FakeCheckpointWriter(i => { }))
             .WithMessageParker(parker)
             .PreferDispatchToSingle()
             .StartFromBeginning()
             .WithMaxRetriesOf(0)
             .WithMessageTimeoutOf(TimeSpan.FromSeconds(1)));
     reader.Load(null);
     sub.AddClient(Guid.NewGuid(), Guid.NewGuid(), envelope1, 10, "foo", "bar");
     var id1 = Guid.NewGuid();
     var id2 = Guid.NewGuid();
     sub.HandleReadCompleted(new[]
     {
         Helper.BuildFakeEvent(id1, "type", "streamName", 0),
         Helper.BuildFakeEvent(id2, "type", "streamName", 1),
     }, 1, false);
     envelope1.Replies.Clear();
     sub.NotifyClockTick(DateTime.Now.AddSeconds(3));
     Assert.AreEqual(0, envelope1.Replies.Count);
     Assert.AreEqual(2, parker.ParkedEvents.Count);
     Assert.IsTrue(id1 == parker.ParkedEvents[0].OriginalEvent.EventId ||
                   id1 == parker.ParkedEvents[1].OriginalEvent.EventId);
     Assert.IsTrue(id2 == parker.ParkedEvents[0].OriginalEvent.EventId ||
                   id2 == parker.ParkedEvents[1].OriginalEvent.EventId);
 }
        public void disconnected_client_has_assigned_streams_sent_to_another_client()
        {
            var client1Envelope = new FakeEnvelope();
            var client2Envelope = new FakeEnvelope();
            var reader = new FakeCheckpointReader();
            const string subsctiptionStream = "$ce-streamName";
            var sub = new Core.Services.PersistentSubscription.PersistentSubscription(
                PersistentSubscriptionParamsBuilder.CreateFor(subsctiptionStream, "groupName")
                    .WithEventLoader(new FakeStreamReader(x => { }))
                    .WithCheckpointReader(reader)
                    .WithCheckpointWriter(new FakeCheckpointWriter(x => { }))
                    .WithMessageParker(new FakeMessageParker())
                    .CustomConsumerStrategy(new PinnedPersistentSubscriptionConsumerStrategy(new XXHashUnsafe()))
                    .StartFromCurrent());
            reader.Load(null);
            sub.AddClient(Guid.NewGuid(), Guid.NewGuid(), client1Envelope, 10, "foo", "bar");
            var client2Id = Guid.NewGuid();
            sub.AddClient(Guid.NewGuid(), client2Id, client2Envelope, 10, "foo", "bar");

            sub.NotifyLiveSubscriptionMessage(Helper.BuildLinkEvent(Guid.NewGuid(), subsctiptionStream, 0, Helper.BuildFakeEvent(Guid.NewGuid(), "type", "streamName-1", 0), false));
            sub.NotifyLiveSubscriptionMessage(Helper.BuildLinkEvent(Guid.NewGuid(), subsctiptionStream, 1, Helper.BuildFakeEvent(Guid.NewGuid(), "type", "streamName-2", 0), false));

            Assert.AreEqual(1, client1Envelope.Replies.Count);
            Assert.AreEqual(1, client2Envelope.Replies.Count);

            sub.RemoveClientByConnectionId(client2Id);

            // Message 2 should be retried on client 1 as it wasn't acked.
            Assert.AreEqual(2, client1Envelope.Replies.Count);
            Assert.AreEqual(1, client2Envelope.Replies.Count);
        }
 public void subscription_does_write_checkpoint_for_disconnected_clients_on_time_when_min_is_hit()
 {
     int cp = -1;
     var reader = new FakeCheckpointReader();
     var sub = new Core.Services.PersistentSubscription.PersistentSubscription(
         PersistentSubscriptionParamsBuilder.CreateFor("streamName", "groupName")
             .WithEventLoader(new FakeStreamReader(x => { }))
             .WithCheckpointReader(reader)
             .WithCheckpointWriter(new FakeCheckpointWriter(i => cp = i))
             .WithMessageParker(new FakeMessageParker())
             .StartFromBeginning()
             .MinimumToCheckPoint(1)
             .MaximumToCheckPoint(5));
     reader.Load(null);
     var corrid = Guid.NewGuid();
     var eventId1 = Guid.NewGuid();
     var eventId2 = Guid.NewGuid();
     sub.HandleReadCompleted(new[]
     {
         Helper.BuildFakeEvent(eventId1, "type", "streamName", 0),
         Helper.BuildFakeEvent(eventId2, "type", "streamName", 1),
     }, 1, false);
     sub.GetNextNOrLessMessages(2).ToArray();
     sub.AcknowledgeMessagesProcessed(corrid, new[] { eventId1, eventId2 });
     sub.NotifyClockTick(DateTime.UtcNow);
     Assert.AreEqual(1, cp);
 }
        public void adding_a_client_adds_the_client()
        {
            var sub = new Core.Services.PersistentSubscription.PersistentSubscription(
                PersistentSubscriptionParamsBuilder.CreateFor("streamName", "groupName")
                    .WithEventLoader(new FakeStreamReader(x => { }))
                    .WithCheckpointReader(new FakeCheckpointReader())
                    .WithMessageParker(new FakeMessageParker())
                    .WithCheckpointWriter(new FakeCheckpointWriter(x => { })));

            sub.AddClient(Guid.NewGuid(), Guid.NewGuid(), new FakeEnvelope(), 1, "foo", "bar");
            Assert.IsTrue(sub.HasClients);
            Assert.AreEqual(1, sub.ClientCount);
        }
 public void subscription_with_more_than_n_events_returns_n_events_to_the_client()
 {
     var reader = new FakeCheckpointReader();
     var sub = new Core.Services.PersistentSubscription.PersistentSubscription(
         PersistentSubscriptionParamsBuilder.CreateFor("streamName", "groupName")
             .WithEventLoader(new FakeStreamReader(x => { }))
             .WithCheckpointReader(reader)
             .WithCheckpointWriter(new FakeCheckpointWriter(x => { }))
             .WithMessageParker(new FakeMessageParker())
             .StartFromBeginning());
     reader.Load(null);
     var id1 = Guid.NewGuid();
     var id2 = Guid.NewGuid();
     var id3 = Guid.NewGuid();
     var id4 = Guid.NewGuid();
     sub.HandleReadCompleted(new[]
     {
         Helper.BuildFakeEvent(id1, "type", "streamName", 0),
         Helper.BuildFakeEvent(id2, "type", "streamName", 1),
         Helper.BuildFakeEvent(id3, "type", "streamName", 2),
         Helper.BuildFakeEvent(id4, "type", "streamName", 3)
     }, 1, false);
     var result = sub.GetNextNOrLessMessages(2).ToArray();
     Assert.AreEqual(2, result.Length);
     Assert.AreEqual(id1, result[0].Event.EventId);
     Assert.AreEqual(id2, result[1].Event.EventId);
 }
 public void subscription_with_live_data_does_not_crash_if_not_ready_yet()
 {
     var envelope1 = new FakeEnvelope();
     var reader = new FakeCheckpointReader();
     var sub = new Core.Services.PersistentSubscription.PersistentSubscription(
         PersistentSubscriptionParamsBuilder.CreateFor("streamName", "groupName")
             .WithEventLoader(new FakeStreamReader(x => { }))
             .WithCheckpointReader(reader)
             .WithCheckpointWriter(new FakeCheckpointWriter(x => { }))
             .WithMessageParker(new FakeMessageParker())
             .StartFromBeginning());
     Assert.DoesNotThrow(() =>
     {
         sub.AddClient(Guid.NewGuid(), Guid.NewGuid(), envelope1, 10, "foo", "bar");
         sub.NotifyLiveSubscriptionMessage(Helper.BuildFakeEvent(Guid.NewGuid(), "type", "streamName", 0));
     });
 }
        public void new_subscription_gets_work()
        {
            var client1Envelope = new FakeEnvelope();
            var client2Envelope = new FakeEnvelope();
            var client3Envelope = new FakeEnvelope();
            var reader = new FakeCheckpointReader();
            const string subsctiptionStream = "$ce-streamName";
            var sub = new Core.Services.PersistentSubscription.PersistentSubscription(
                PersistentSubscriptionParamsBuilder.CreateFor(subsctiptionStream, "groupName")
                    .WithEventLoader(new FakeStreamReader(x => { }))
                    .WithCheckpointReader(reader)
                    .WithCheckpointWriter(new FakeCheckpointWriter(x => { }))
                    .WithMessageParker(new FakeMessageParker())
                    .CustomConsumerStrategy(new PinnedPersistentSubscriptionConsumerStrategy(new ByLengthHasher()))
                    .StartFromCurrent());
            reader.Load(null);
            sub.AddClient(Guid.NewGuid(), Guid.NewGuid(), client1Envelope, 10, "foo", "bar");
            sub.AddClient(Guid.NewGuid(), Guid.NewGuid(), client2Envelope, 10, "foo", "bar");

            sub.NotifyLiveSubscriptionMessage(Helper.BuildFakeEvent(Guid.NewGuid(), "type", "1", 0));
            sub.NotifyLiveSubscriptionMessage(Helper.BuildFakeEvent(Guid.NewGuid(), "type", "11", 1));
            sub.NotifyLiveSubscriptionMessage(Helper.BuildFakeEvent(Guid.NewGuid(), "type", "111", 2));
            sub.NotifyLiveSubscriptionMessage(Helper.BuildFakeEvent(Guid.NewGuid(), "type", "1111", 3));
            sub.NotifyLiveSubscriptionMessage(Helper.BuildFakeEvent(Guid.NewGuid(), "type", "11111", 4));
            sub.NotifyLiveSubscriptionMessage(Helper.BuildFakeEvent(Guid.NewGuid(), "type", "111111", 5));

            Assert.AreEqual(3, client1Envelope.Replies.Count);
            Assert.AreEqual(3, client2Envelope.Replies.Count);

            sub.AddClient(Guid.NewGuid(), Guid.NewGuid(), client3Envelope, 10, "foo", "bar");

            sub.NotifyLiveSubscriptionMessage(Helper.BuildFakeEvent(Guid.NewGuid(), "type", "1", 6));
            sub.NotifyLiveSubscriptionMessage(Helper.BuildFakeEvent(Guid.NewGuid(), "type", "11", 7));
            sub.NotifyLiveSubscriptionMessage(Helper.BuildFakeEvent(Guid.NewGuid(), "type", "111", 8));
            sub.NotifyLiveSubscriptionMessage(Helper.BuildFakeEvent(Guid.NewGuid(), "type", "1111", 9));
            sub.NotifyLiveSubscriptionMessage(Helper.BuildFakeEvent(Guid.NewGuid(), "type", "11111", 10));
            sub.NotifyLiveSubscriptionMessage(Helper.BuildFakeEvent(Guid.NewGuid(), "type", "111111", 11));

            Assert.AreEqual(5, client1Envelope.Replies.Count);
            Assert.AreEqual(5, client2Envelope.Replies.Count);
            Assert.AreEqual(2, client3Envelope.Replies.Count);
        }
        public void available_capacity_is_tracked()
        {
            var client1Envelope = new FakeEnvelope();
            var client2Envelope = new FakeEnvelope();
            var reader = new FakeCheckpointReader();
            const string subsctiptionStream = "$ce-streamName";
            PersistentSubscriptionParams settings = PersistentSubscriptionParamsBuilder.CreateFor(subsctiptionStream, "groupName")
                .WithEventLoader(new FakeStreamReader(x => { }))
                .WithCheckpointReader(reader)
                .WithCheckpointWriter(new FakeCheckpointWriter(x => { }))
                .WithMessageParker(new FakeMessageParker())
                .CustomConsumerStrategy(new PinnedPersistentSubscriptionConsumerStrategy(new XXHashUnsafe()))
                .StartFromCurrent();
            var consumerStrategy = (PinnedPersistentSubscriptionConsumerStrategy)settings.ConsumerStrategy;
            var sub = new Core.Services.PersistentSubscription.PersistentSubscription(settings);
            reader.Load(null);
            var client1Id = Guid.NewGuid();
            sub.AddClient(Guid.NewGuid(), client1Id, client1Envelope, 14, "foo", "bar");

            Assert.That(consumerStrategy.AvailableCapacity, Is.EqualTo(14));

            var client2Id = Guid.NewGuid();
            sub.AddClient(Guid.NewGuid(), client2Id, client2Envelope, 10, "foo", "bar");

            Assert.That(consumerStrategy.AvailableCapacity, Is.EqualTo(24));

            sub.RemoveClientByConnectionId(client2Id);

            Assert.That(consumerStrategy.AvailableCapacity, Is.EqualTo(14));

            sub.RemoveClientByConnectionId(client1Id);

            Assert.That(consumerStrategy.AvailableCapacity, Is.EqualTo(0));
        }
 public void live_subscription_with_prefer_one_and_two_pushes_events_to_both()
 {
     var envelope1 = new FakeEnvelope();
     var envelope2 = new FakeEnvelope();
     var reader = new FakeCheckpointReader();
     var sub = new Core.Services.PersistentSubscription.PersistentSubscription(
         PersistentSubscriptionParamsBuilder.CreateFor("streamName", "groupName")
             .WithEventLoader(new FakeStreamReader(x => { }))
             .WithCheckpointReader(reader)
             .WithCheckpointWriter(new FakeCheckpointWriter(x => { }))
             .WithMessageParker(new FakeMessageParker())
             .PreferDispatchToSingle()
             .StartFromCurrent());
     reader.Load(null);
     sub.AddClient(Guid.NewGuid(), Guid.NewGuid(), envelope1, 10, "foo", "bar");
     sub.AddClient(Guid.NewGuid(), Guid.NewGuid(), envelope2, 10, "foo", "bar");
     sub.NotifyLiveSubscriptionMessage(Helper.BuildFakeEvent(Guid.NewGuid(), "type", "streamName", 0));
     sub.NotifyLiveSubscriptionMessage(Helper.BuildFakeEvent(Guid.NewGuid(), "type", "streamName", 1));
     Assert.AreEqual(2, envelope1.Replies.Count);
 }
        public void explicit_nak_with_retry_correctly_tracks_the_available_client_slots()
        {
            var envelope1 = new FakeEnvelope();
            var reader = new FakeCheckpointReader();
            var parker = new FakeMessageParker();
            var sub = new Core.Services.PersistentSubscription.PersistentSubscription(
                PersistentSubscriptionParamsBuilder.CreateFor("streamName", "groupName")
                    .WithEventLoader(new FakeStreamReader(x => { }))
                    .WithCheckpointReader(reader)
                    .WithCheckpointWriter(new FakeCheckpointWriter(i => { }))
                    .WithMaxRetriesOf(10)
                    .WithMessageParker(parker)
                    .StartFromBeginning());
            reader.Load(null);
            var corrid = Guid.NewGuid();
            sub.AddClient(corrid, Guid.NewGuid(), envelope1, 10, "foo", "bar");
            var id1 = Guid.NewGuid();
            var ev = Helper.BuildFakeEvent(id1, "type", "streamName", 0);
            sub.HandleReadCompleted(new[]
            {
                ev,
            }, 1, false);

            for (int i = 1; i < 11; i++)
            {
                sub.NotAcknowledgeMessagesProcessed(corrid, new[] { id1 }, NakAction.Retry, "a reason from client.");
                Assert.AreEqual(i + 1, envelope1.Replies.Count);
            }

            Assert.That(parker.ParkedEvents, Has.No.Member(ev));

            //This time should be parked
            sub.NotAcknowledgeMessagesProcessed(corrid, new[] { id1 }, NakAction.Retry, "a reason from client.");
            Assert.AreEqual(11, envelope1.Replies.Count);
            Assert.That(parker.ParkedEvents, Has.Member(ev));
        }
 public void messages_dont_get_retried_when_acked_on_synchronous_reads()
 {
     var reader = new FakeCheckpointReader();
     var parker = new FakeMessageParker();
     var sub = new Core.Services.PersistentSubscription.PersistentSubscription(
         PersistentSubscriptionParamsBuilder.CreateFor("streamName", "groupName")
             .WithEventLoader(new FakeStreamReader(x => { }))
             .WithCheckpointReader(reader)
             .WithCheckpointWriter(new FakeCheckpointWriter(i => { }))
             .WithMessageParker(parker)
             .PreferDispatchToSingle()
             .StartFromBeginning()
             .WithMessageTimeoutOf(TimeSpan.FromSeconds(1)));
     reader.Load(null);
     var id1 = Guid.NewGuid();
     var id2 = Guid.NewGuid();
     sub.HandleReadCompleted(new[]
     {
         Helper.BuildFakeEvent(id1, "type", "streamName", 0),
         Helper.BuildFakeEvent(id2, "type", "streamName", 1)
     }, 1, false);
     sub.GetNextNOrLessMessages(2).ToArray();
     sub.AcknowledgeMessagesProcessed(Guid.Empty, new[] { id1, id2 });
     sub.NotifyClockTick(DateTime.Now.AddSeconds(3));
     var retries = sub.GetNextNOrLessMessages(2).ToArray();
     Assert.AreEqual(0, retries.Length);
     Assert.AreEqual(0, parker.ParkedEvents.Count);
 }
 public void messages_get_timed_out_and_resent_to_clients()
 {
     var envelope1 = new FakeEnvelope();
     var reader = new FakeCheckpointReader();
     var parker = new FakeMessageParker();
     var sub = new Core.Services.PersistentSubscription.PersistentSubscription(
         PersistentSubscriptionParamsBuilder.CreateFor("streamName", "groupName")
             .WithEventLoader(new FakeStreamReader(x => { }))
             .WithCheckpointReader(reader)
             .WithCheckpointWriter(new FakeCheckpointWriter(i => { }))
             .WithMessageParker(parker)
             .PreferDispatchToSingle()
             .StartFromBeginning()
             .WithMessageTimeoutOf(TimeSpan.FromSeconds(1)));
     reader.Load(null);
     sub.AddClient(Guid.NewGuid(), Guid.NewGuid(), envelope1, 1, "foo", "bar");
     sub.AddClient(Guid.NewGuid(), Guid.NewGuid(), envelope1, 1, "foo", "bar");
     var id1 = Guid.NewGuid();
     var id2 = Guid.NewGuid();
     sub.HandleReadCompleted(new[]
     {
         Helper.BuildFakeEvent(id1, "type", "streamName", 0),
         Helper.BuildLinkEvent(id2, "streamName", 1, Helper.BuildFakeEvent(Guid.NewGuid(), "type", "streamSource", 0))
         
     }, 1, false);
     envelope1.Replies.Clear();
     sub.NotifyClockTick(DateTime.UtcNow.AddSeconds(3));
     Assert.AreEqual(2, envelope1.Replies.Count);
     var msg1 = (Messages.ClientMessage.PersistentSubscriptionStreamEventAppeared)envelope1.Replies[0];
     var msg2 = (Messages.ClientMessage.PersistentSubscriptionStreamEventAppeared)envelope1.Replies[1];
     Assert.IsTrue(id1 == msg1.Event.OriginalEvent.EventId || id1 == msg2.Event.OriginalEvent.EventId);
     Assert.IsTrue(id2 == msg1.Event.OriginalEvent.EventId || id2 == msg2.Event.OriginalEvent.EventId);
     Assert.AreEqual(0, parker.ParkedEvents.Count);
 }
 public void explicit_nak_with_retry_retries_the_message()
 {
     var envelope1 = new FakeEnvelope();
     var reader = new FakeCheckpointReader();
     var parker = new FakeMessageParker();
     var sub = new Core.Services.PersistentSubscription.PersistentSubscription(
         PersistentSubscriptionParamsBuilder.CreateFor("streamName", "groupName")
             .WithEventLoader(new FakeStreamReader(x => { }))
             .WithCheckpointReader(reader)
             .WithCheckpointWriter(new FakeCheckpointWriter(i => { }))
             .WithMessageParker(parker)
             .StartFromBeginning());
     reader.Load(null);
     var corrid = Guid.NewGuid();
     sub.AddClient(corrid, Guid.NewGuid(), envelope1, 10, "foo", "bar");
     var id1 = Guid.NewGuid();
     sub.HandleReadCompleted(new[]
     {
         Helper.BuildFakeEvent(id1, "type", "streamName", 0),
     }, 1, false);
     envelope1.Replies.Clear();
     sub.NotAcknowledgeMessagesProcessed(corrid, new[] { id1 }, NakAction.Retry, "a reason from client.");
     Assert.AreEqual(1, envelope1.Replies.Count);
     Assert.AreEqual(id1, ((ClientMessage.PersistentSubscriptionStreamEventAppeared)envelope1.Replies[0]).Event.Event.EventId);
     Assert.AreEqual(0, parker.ParkedEvents.Count);
 }
 public void subscription_with_pull_and_prefer_one_set_and_two_clients_sends_data_to_one_client()
 {
     var envelope1 = new FakeEnvelope();
     var envelope2 = new FakeEnvelope();
     var reader = new FakeCheckpointReader();
     var sub = new Core.Services.PersistentSubscription.PersistentSubscription(
         PersistentSubscriptionParamsBuilder.CreateFor("streamName", "groupName")
             .WithEventLoader(new FakeStreamReader(x => { }))
             .WithCheckpointReader(reader)
             .WithCheckpointWriter(new FakeCheckpointWriter(x => { }))
             .WithMessageParker(new FakeMessageParker())
             .PreferDispatchToSingle()
             .StartFromBeginning());
     reader.Load(null);
     sub.AddClient(Guid.NewGuid(), Guid.NewGuid(), envelope1, 10, "foo", "bar");
     sub.AddClient(Guid.NewGuid(), Guid.NewGuid(), envelope2, 10, "foo", "bar");
     var id1 = Guid.NewGuid();
     var id2 = Guid.NewGuid();
     sub.HandleReadCompleted(new[]
     {
         Helper.BuildFakeEvent(id1, "type", "streamName", 0),
         Helper.BuildFakeEvent(id2, "type", "streamName", 1)
     }, 1, false);
     Assert.AreEqual(2, envelope1.Replies.Count);
 }
        public void explicit_nak_with_park_correctly_tracks_the_available_client_slots()
        {
            var envelope1 = new FakeEnvelope();
            var reader = new FakeCheckpointReader();
            var parker = new FakeMessageParker();
            var sub = new Core.Services.PersistentSubscription.PersistentSubscription(
                PersistentSubscriptionParamsBuilder.CreateFor("streamName", "groupName")
                    .WithEventLoader(new FakeStreamReader(x => { }))
                    .WithCheckpointReader(reader)
                    .WithCheckpointWriter(new FakeCheckpointWriter(i => { }))
                    .WithMessageParker(parker)
                    .WithMaxRetriesOf(0)
                    .WithMessageTimeoutOf(TimeSpan.Zero)
                    .StartFromBeginning());
            reader.Load(null);
            var corrid = Guid.NewGuid();
            sub.AddClient(corrid, Guid.NewGuid(), envelope1, 1, "foo", "bar");

            var id1 = Guid.NewGuid();
            var id2 = Guid.NewGuid();
            sub.HandleReadCompleted(new[]
            {
                Helper.BuildFakeEvent(id1, "type", "streamName", 0),
                Helper.BuildFakeEvent(id2, "type", "streamName", 1),
                Helper.BuildFakeEvent(Guid.NewGuid(), "type", "streamName", 2)
            }, 1, false);

            Assert.AreEqual(1, envelope1.Replies.Count);

            sub.NotAcknowledgeMessagesProcessed(corrid, new[] { id1 }, NakAction.Park, "a reason from client.");
            Assert.AreEqual(2, envelope1.Replies.Count);

            sub.NotAcknowledgeMessagesProcessed(corrid, new[] { id2 }, NakAction.Park, "a reason from client.");
            Assert.AreEqual(3, envelope1.Replies.Count);
        }
        public void bad_availablecapacity_scneanrio_causing_null_reference()
        {
            var client1Envelope = new FakeEnvelope();
            var client2Envelope = new FakeEnvelope();
            var reader = new FakeCheckpointReader();
            const string subsctiptionStream = "$ce-streamName";
            var sub = new Core.Services.PersistentSubscription.PersistentSubscription(
                PersistentSubscriptionParamsBuilder.CreateFor(subsctiptionStream, "groupName")
                    .WithEventLoader(new FakeStreamReader(x => { }))
                    .WithCheckpointReader(reader)
                    .WithCheckpointWriter(new FakeCheckpointWriter(x => { }))
                    .WithMessageParker(new FakeMessageParker())
                    .CustomConsumerStrategy(new PinnedPersistentSubscriptionConsumerStrategy(new ByLengthHasher()))
                    .StartFromCurrent());
            reader.Load(null);
            var conn1Id = Guid.NewGuid();
            sub.AddClient(Guid.NewGuid(), conn1Id, client1Envelope, 10, "foo", "bar");

            sub.NotifyLiveSubscriptionMessage(Helper.BuildFakeEvent(Guid.NewGuid(), "type", "1", 0));
            sub.NotifyLiveSubscriptionMessage(Helper.BuildFakeEvent(Guid.NewGuid(), "type", "11", 1));
            sub.NotifyLiveSubscriptionMessage(Helper.BuildFakeEvent(Guid.NewGuid(), "type", "111", 2));

            Assert.AreEqual(3, client1Envelope.Replies.Count);

            var conn2Id = Guid.NewGuid();
            sub.AddClient(Guid.NewGuid(), conn2Id, client2Envelope, 10, "foo", "bar");

            Assert.AreEqual(3, client1Envelope.Replies.Count);
            Assert.AreEqual(0, client2Envelope.Replies.Count);

            sub.RemoveClientByConnectionId(conn1Id);

            // Used to throw a null reference exception.
            Assert.That(() => sub.RemoveClientByConnectionId(conn2Id), Throws.Nothing);
        }
        public void disconnecting_a_client_retries_inflight_messages_immediately()
        {
            var client1Envelope = new FakeEnvelope();
            var client2Envelope = new FakeEnvelope();

            var fakeCheckpointReader = new FakeCheckpointReader();
            var sub = new Core.Services.PersistentSubscription.PersistentSubscription(
                PersistentSubscriptionParamsBuilder.CreateFor("streamName", "groupName")
                    .WithEventLoader(new FakeStreamReader(x => { }))
                    .WithCheckpointReader(fakeCheckpointReader)
                    .WithMessageParker(new FakeMessageParker())
                    .PreferRoundRobin()
                    .StartFromCurrent()
            .WithCheckpointWriter(new FakeCheckpointWriter(x => { })));

            fakeCheckpointReader.Load(null);

            sub.AddClient(Guid.NewGuid(), Guid.NewGuid(), client1Envelope, 10, "foo", "bar");
            var connectionId = Guid.NewGuid();
            sub.AddClient(Guid.NewGuid(), connectionId, client2Envelope, 10, "foo", "bar");

            Assert.IsTrue(sub.HasClients);
            Assert.AreEqual(2, sub.ClientCount);

            sub.NotifyLiveSubscriptionMessage(Helper.BuildFakeEvent(Guid.NewGuid(), "type", "streamName", 0));
            sub.NotifyLiveSubscriptionMessage(Helper.BuildFakeEvent(Guid.NewGuid(), "type", "streamName", 1));

            Assert.AreEqual(1, client1Envelope.Replies.Count);
            Assert.AreEqual(1, client2Envelope.Replies.Count);

            sub.RemoveClientByConnectionId(connectionId);

            Assert.AreEqual(1, sub.ClientCount);

            // Message 2 should be retried on client 1 as it wasn't acked.
            Assert.AreEqual(2, client1Envelope.Replies.Count);
            Assert.AreEqual(1, client2Envelope.Replies.Count);
        }
        public void events_are_skipped_if_assigned_client_full()
        {
            var client1Envelope = new FakeEnvelope();
            var client2Envelope = new FakeEnvelope();
            var reader = new FakeCheckpointReader();
            const string subsctiptionStream = "$ce-streamName";
            var sub = new Core.Services.PersistentSubscription.PersistentSubscription(PersistentSubscriptionParamsBuilder.CreateFor(subsctiptionStream, "groupName")
                .WithEventLoader(new FakeStreamReader(x => { }))
                .WithCheckpointReader(reader)
                .WithCheckpointWriter(new FakeCheckpointWriter(x => { }))
                .WithMessageParker(new FakeMessageParker())
                .CustomConsumerStrategy(new PinnedPersistentSubscriptionConsumerStrategy(new XXHashUnsafe()))
                .StartFromCurrent());
            reader.Load(null);

            var correlationId = Guid.NewGuid();
            sub.AddClient(correlationId, Guid.NewGuid(), client1Envelope, 1, "foo", "bar");

            sub.AddClient(Guid.NewGuid(), Guid.NewGuid(), client2Envelope, 1, "foo", "bar");


            var message1 = Guid.NewGuid();
            sub.NotifyLiveSubscriptionMessage(Helper.BuildLinkEvent(message1, subsctiptionStream, 0, Helper.BuildFakeEvent(Guid.NewGuid(), "type", "streamName-1", 0), false));

            Assert.That(client1Envelope.Replies.Count, Is.EqualTo(1));
            Assert.That(client2Envelope.Replies.Count, Is.EqualTo(0));

            sub.NotifyLiveSubscriptionMessage(Helper.BuildLinkEvent(Guid.NewGuid(), subsctiptionStream, 1, Helper.BuildFakeEvent(Guid.NewGuid(), "type", "streamName-1", 0), false));

            Assert.That(client1Envelope.Replies.Count, Is.EqualTo(1));
            Assert.That(client2Envelope.Replies.Count, Is.EqualTo(0));
            Assert.That(sub._streamBuffer.BufferCount, Is.EqualTo(1));

            sub.NotifyLiveSubscriptionMessage(Helper.BuildLinkEvent(Guid.NewGuid(), subsctiptionStream, 2, Helper.BuildFakeEvent(Guid.NewGuid(), "type", "streamName-2", 0), false));

            Assert.That(client1Envelope.Replies.Count, Is.EqualTo(1));
            Assert.That(client2Envelope.Replies.Count, Is.EqualTo(1));

            Assert.That(sub._streamBuffer.BufferCount, Is.EqualTo(1));

            sub.AcknowledgeMessagesProcessed(correlationId, new[] { message1 });

            Assert.That(client1Envelope.Replies.Count, Is.EqualTo(2));
            Assert.That(client2Envelope.Replies.Count, Is.EqualTo(1));

            Assert.That(sub._streamBuffer.BufferCount, Is.EqualTo(0));
        }
        public void resolved_link_events_use_event_stream_id()
        {
            var client1Envelope = new FakeEnvelope();
            var client2Envelope = new FakeEnvelope();
            var reader = new FakeCheckpointReader();
            const string subsctiptionStream = "$ce-streamName";
            var sub = new Core.Services.PersistentSubscription.PersistentSubscription(
                PersistentSubscriptionParamsBuilder.CreateFor(subsctiptionStream, "groupName")
                    .WithEventLoader(new FakeStreamReader(x => { }))
                    .WithCheckpointReader(reader)
                    .WithCheckpointWriter(new FakeCheckpointWriter(x => { }))
                    .WithMessageParker(new FakeMessageParker())
                    .CustomConsumerStrategy(new PinnedPersistentSubscriptionConsumerStrategy(new XXHashUnsafe()))
                    .StartFromCurrent());
            reader.Load(null);
            sub.AddClient(Guid.NewGuid(), Guid.NewGuid(), client1Envelope, 10, "foo", "bar");
            sub.AddClient(Guid.NewGuid(), Guid.NewGuid(), client2Envelope, 10, "foo", "bar");

            sub.NotifyLiveSubscriptionMessage(Helper.BuildLinkEvent(Guid.NewGuid(), subsctiptionStream, 0, Helper.BuildFakeEvent(Guid.NewGuid(), "type", "streamName-1", 0)));

            Assert.AreEqual(1, client1Envelope.Replies.Count);
            Assert.AreEqual(0, client2Envelope.Replies.Count);

            sub.NotifyLiveSubscriptionMessage(Helper.BuildLinkEvent(Guid.NewGuid(), subsctiptionStream, 1, Helper.BuildFakeEvent(Guid.NewGuid(), "type", "streamName-2", 0)));

            Assert.AreEqual(1, client1Envelope.Replies.Count);
            Assert.AreEqual(1, client2Envelope.Replies.Count);

            sub.NotifyLiveSubscriptionMessage(Helper.BuildLinkEvent(Guid.NewGuid(), subsctiptionStream, 2, Helper.BuildFakeEvent(Guid.NewGuid(), "type", "streamName-3", 0)));

            Assert.AreEqual(2, client1Envelope.Replies.Count);
            Assert.AreEqual(1, client2Envelope.Replies.Count);

            sub.NotifyLiveSubscriptionMessage(Helper.BuildLinkEvent(Guid.NewGuid(), subsctiptionStream, 3, Helper.BuildFakeEvent(Guid.NewGuid(), "type", "streamName-4", 0)));

            Assert.AreEqual(2, client1Envelope.Replies.Count);
            Assert.AreEqual(2, client2Envelope.Replies.Count);
        }
 public void with_no_timeouts_to_happen_no_timeouts_happen()
 {
     var envelope1 = new FakeEnvelope();
     var reader = new FakeCheckpointReader();
     var parker = new FakeMessageParker();
     var sub = new Core.Services.PersistentSubscription.PersistentSubscription(
         PersistentSubscriptionParamsBuilder.CreateFor("streamName", "groupName")
             .WithEventLoader(new FakeStreamReader(x => { }))
             .WithCheckpointReader(reader)
             .WithCheckpointWriter(new FakeCheckpointWriter(i => { }))
             .WithMessageParker(parker)
             .PreferDispatchToSingle()
             .StartFromBeginning()
             .WithMessageTimeoutOf(TimeSpan.FromSeconds(3)));
     reader.Load(null);
     sub.AddClient(Guid.NewGuid(), Guid.NewGuid(), envelope1, 10, "foo", "bar");
     var id1 = Guid.NewGuid();
     var id2 = Guid.NewGuid();
     sub.HandleReadCompleted(new[]
     {
         Helper.BuildFakeEvent(id1, "type", "streamName", 0),
         Helper.BuildFakeEvent(id2, "type", "streamName", 1)
     }, 1, false);
     envelope1.Replies.Clear();
     sub.NotifyClockTick(DateTime.Now.AddSeconds(1));
     Assert.AreEqual(0, envelope1.Replies.Count);
     Assert.AreEqual(0, parker.ParkedEvents.Count);
 }
 public void subscription_deletes_parked_messages_when_deleted()
 {
     var reader = new FakeCheckpointReader();
     var deleted = false;
     var sub = new Core.Services.PersistentSubscription.PersistentSubscription(
         PersistentSubscriptionParamsBuilder.CreateFor("streamName", "groupName")
             .WithEventLoader(new FakeStreamReader(x => { }))
             .WithCheckpointReader(reader)
             .WithCheckpointWriter(new FakeCheckpointWriter(x => { }))
             .WithMessageParker(new FakeMessageParker(() => { deleted = true; }))
             .StartFromCurrent());
     reader.Load(null);
     sub.Delete();
     Assert.IsTrue(deleted);
 }
 public void subscription_with_no_events_returns_no_events_to_the_client()
 {
     var reader = new FakeCheckpointReader();
     var sub = new Core.Services.PersistentSubscription.PersistentSubscription(
         PersistentSubscriptionParamsBuilder.CreateFor("streamName", "groupName")
             .WithEventLoader(new FakeStreamReader(x => { }))
             .WithCheckpointReader(reader)
             .WithCheckpointWriter(new FakeCheckpointWriter(x => { }))
             .WithMessageParker(new FakeMessageParker())
             .StartFromBeginning());
     reader.Load(null);
     var result = sub.GetNextNOrLessMessages(5);
     Assert.AreEqual(0, result.Count());
 }
 public void subscription_does_not_write_checkpoint_on_time_when_min_is_not_hit()
 {
     int cp = -1;
     var envelope1 = new FakeEnvelope();
     var reader = new FakeCheckpointReader();
     var sub = new Core.Services.PersistentSubscription.PersistentSubscription(
         PersistentSubscriptionParamsBuilder.CreateFor("streamName", "groupName")
             .WithEventLoader(new FakeStreamReader(x => { }))
             .WithCheckpointReader(reader)
             .WithCheckpointWriter(new FakeCheckpointWriter(i => cp = i))
             .WithMessageParker(new FakeMessageParker())
             .PreferDispatchToSingle()
             .StartFromBeginning()
             .MinimumToCheckPoint(2)
             .MaximumToCheckPoint(5));
     reader.Load(null);
     var corrid = Guid.NewGuid();
     sub.AddClient(corrid, Guid.NewGuid(), envelope1, 10, "foo", "bar");
     sub.AddClient(Guid.NewGuid(), Guid.NewGuid(), envelope1, 10, "foo", "bar");
     var id = Guid.NewGuid();
     sub.HandleReadCompleted(new[]
     {
         Helper.BuildFakeEvent(id, "type", "streamName", 0),
         Helper.BuildFakeEvent(Guid.NewGuid(), "type", "streamName", 1)
     }, 1, false);
     sub.AcknowledgeMessagesProcessed(corrid, new[] { id });
     sub.NotifyClockTick(DateTime.Now);
     Assert.AreEqual(1, cp);
 }
        public void available_capacity_is_tracked_with_acked_messages()
        {
            var client1Envelope = new FakeEnvelope();
            var client2Envelope = new FakeEnvelope();
            var reader = new FakeCheckpointReader();
            const string subsctiptionStream = "$ce-streamName";
            PersistentSubscriptionParams settings = PersistentSubscriptionParamsBuilder.CreateFor(subsctiptionStream, "groupName")
                .WithEventLoader(new FakeStreamReader(x => { }))
                .WithCheckpointReader(reader)
                .WithCheckpointWriter(new FakeCheckpointWriter(x => { }))
                .WithMessageParker(new FakeMessageParker())
                .CustomConsumerStrategy(new PinnedPersistentSubscriptionConsumerStrategy(new XXHashUnsafe()))
                .StartFromCurrent();
            var consumerStrategy = (PinnedPersistentSubscriptionConsumerStrategy)settings.ConsumerStrategy;
            var sub = new Core.Services.PersistentSubscription.PersistentSubscription(settings);
            reader.Load(null);
            var correlationId1 = Guid.NewGuid();
            sub.AddClient(correlationId1, Guid.NewGuid(), client1Envelope, 14, "foo", "bar");
            Assert.That(consumerStrategy.AvailableCapacity, Is.EqualTo(14));

            var correlationId2 = Guid.NewGuid();
            sub.AddClient(correlationId2, Guid.NewGuid(), client2Envelope, 10, "foo", "bar");

            Assert.That(consumerStrategy.AvailableCapacity, Is.EqualTo(24));

            var message1 = Guid.NewGuid();
            sub.NotifyLiveSubscriptionMessage(Helper.BuildLinkEvent(message1, subsctiptionStream, 0, Helper.BuildFakeEvent(Guid.NewGuid(), "type", "streamName-1", 0), false));

            Assert.That(consumerStrategy.AvailableCapacity, Is.EqualTo(23));

            var message2 = Guid.NewGuid();
            sub.NotifyLiveSubscriptionMessage(Helper.BuildLinkEvent(message2, subsctiptionStream, 1, Helper.BuildFakeEvent(Guid.NewGuid(), "type", "streamName-2", 0), false));

            Assert.That(consumerStrategy.AvailableCapacity, Is.EqualTo(22));

            sub.AcknowledgeMessagesProcessed(correlationId1, new[] { message1 });

            Assert.That(consumerStrategy.AvailableCapacity, Is.EqualTo(23));

            sub.AcknowledgeMessagesProcessed(correlationId2, new[] { message2 });

            Assert.That(consumerStrategy.AvailableCapacity, Is.EqualTo(24));

        }