예제 #1
0
        public static void Subscribe_PublishesExactSequenceOfItemsOverMultipleElapsedIntervals()
        {
            var jobStorage = A.Fake<IDurableJobQueue<Incoming, Incoming>>();
            var scheduler = new HistoricalScheduler();
            var monitor = new DurableJobQueueMonitor<Incoming, Incoming>(jobStorage, 20, DurableJobQueueMonitor.DefaultPollingInterval, scheduler);

            List<Incoming> incomingItems = new List<Incoming>();

            var queuedItems = Enumerable.Repeat(Item.From(new Incoming() { Id = 1 }), 5)
                .Concat(new [] { Item.None<Incoming>() })
                .Concat(Enumerable.Repeat(Item.From(new Incoming() { Id = 2 }), 5))
                .Concat(new [] { Item.None<Incoming>() })
                .Concat(Enumerable.Repeat(Item.From(new Incoming() { Id = 1 }), 2))
                .Concat(new [] { Item.None<Incoming>() }).ToArray();

            using (var subscription = monitor.Subscribe(publishedItem =>{ incomingItems.Add(publishedItem);}))
            {
                A.CallTo(() => jobStorage.NextQueuedItem()).ReturnsNextFromSequence(queuedItems);

                scheduler.AdvanceBy(monitor.PollingInterval);
                scheduler.AdvanceBy(monitor.PollingInterval);
                scheduler.AdvanceBy(monitor.PollingInterval);

                Assert.True(queuedItems.Where(item => item.Success)
                .Select(item => item.Value)
                .SequenceEqual(incomingItems, GenericEqualityComparer<Incoming>.ByAllMembers()));
            }
        }
예제 #2
0
        public void Subscribe_TakesNoMoreThanMaximumSpecifiedItemsPerInterval()
        {
            int maxToSlurp = 3;
            var jobStorage = A.Fake <IDurableJobQueue <Incoming, Incoming> >();

            A.CallTo(() => jobStorage.NextQueuedItem()).Returns(Item.From(new Incoming()
            {
                Id = 1
            }));
            var scheduler = new HistoricalScheduler();
            var monitor   = new DurableJobQueueMonitor <Incoming, Incoming>(jobStorage, maxToSlurp, DurableJobQueueMonitor.DefaultPollingInterval,
                                                                            scheduler);
            var completion = new ManualResetEventSlim(false);

            List <Incoming> incomingItems = new List <Incoming>();

            using (var subscription = monitor.Subscribe(publishedItem =>
            {
                incomingItems.Add(publishedItem);
                if (incomingItems.Count >= maxToSlurp)
                {
                    completion.Set();
                }
            }))
            {
                scheduler.AdvanceBy(monitor.PollingInterval + TimeSpan.FromTicks(1));
                completion.Wait(TimeSpan.FromSeconds(3));

                Assert.Equal(maxToSlurp, incomingItems.Count);
            }
        }
예제 #3
0
        public void Subscribe_PublishesExactSequenceOfItemsAsTheyArePulledFromDurableStorage()
        {
            var jobStorage = A.Fake <IDurableJobQueue <Incoming, Incoming> >();
            var scheduler  = new HistoricalScheduler();
            var monitor    = new DurableJobQueueMonitor <Incoming, Incoming>(jobStorage, 20, DurableJobQueueMonitor.DefaultPollingInterval, scheduler);

            List <Incoming> incomingItems = new List <Incoming>();

            var queuedItems = Enumerable.Repeat(Item.From(new Incoming()
            {
                Id = 1
            }), 5)
                              .Concat(Enumerable.Repeat(Item.From(new Incoming()
            {
                Id = 5
            }), 2))
                              .Concat(Enumerable.Repeat(Item.From(new Incoming()
            {
                Id = 2
            }), 4))
                              .Concat(Enumerable.Repeat(Item.From(new Incoming()
            {
                Id = 3
            }), 3))
                              .ToArray();

            A.CallTo(() => jobStorage.NextQueuedItem()).ReturnsNextFromSequence(queuedItems.Concat(new [] { Item.None <Incoming>() }).ToArray());

            using (var subscription = monitor.Subscribe(publishedItem => { incomingItems.Add(publishedItem); }))
            {
                scheduler.AdvanceBy(monitor.PollingInterval);

                Assert.True(queuedItems.Select(item => item.Value).SequenceEqual(incomingItems, GenericEqualityComparer <Incoming> .ByAllMembers()));
            }
        }
예제 #4
0
        public static void Subscribe_CallsTransitionNextQueuedItemCorrectNumberOfTimesOverMultipleElapsedIntervals()
        {
            var jobStorage = A.Fake <IDurableJobQueue <Incoming, Incoming> >();
            var scheduler  = new HistoricalScheduler();
            var monitor    = new DurableJobQueueMonitor <Incoming, Incoming>(jobStorage, 20, DurableJobQueueMonitor.DefaultPollingInterval, scheduler);

            var queuedItems = Enumerable.Repeat(Item.From(new Incoming()
            {
                Id = 1
            }), 5)
                              .Concat(new [] { Item.None <Incoming>() })
                              .Concat(Enumerable.Repeat(Item.From(new Incoming()
            {
                Id = 2
            }), 5))
                              .Concat(new [] { Item.None <Incoming>() }).ToArray();

            using (var subscription = monitor.Subscribe())
            {
                A.CallTo(() => jobStorage.NextQueuedItem()).ReturnsNextFromSequence(queuedItems);

                scheduler.AdvanceBy(monitor.PollingInterval);
                scheduler.AdvanceBy(monitor.PollingInterval);

                A.CallTo(() => jobStorage.NextQueuedItem()).MustHaveHappened(Repeated.Exactly.Times(queuedItems.Length));
            }
        }
예제 #5
0
        public void Monitor_AwaitsFirstSubscriberBeforePublishing()
        {
            var jobStorage = A.Fake <IDurableJobQueue <Incoming, Incoming> >();
            var scheduler  = new HistoricalScheduler();
            var monitor    = new DurableJobQueueMonitor <Incoming, Incoming>(jobStorage, 20, DurableJobQueueMonitor.DefaultPollingInterval, scheduler);

            //X items + a null terminator per each elapsed interval
            var incomingItems = Enumerable.Repeat(Item.From(new Incoming()
            {
                Id = 2
            }), 5)
                                .Concat(new[] { Item.None <Incoming>(), Item.None <Incoming>() }).ToArray();

            A.CallTo(() => jobStorage.NextQueuedItem()).ReturnsNextFromSequence(incomingItems);

            //advance the amount of time that would normally cause our queue to be totally flushed
            scheduler.AdvanceBy(monitor.PollingInterval.Add(monitor.PollingInterval));
            using (var subscription = monitor.Subscribe())
            {
                //and now that we have a subscriber, elapse enough time to publish the queue contents
                scheduler.AdvanceBy(monitor.PollingInterval);
                scheduler.AdvanceBy(monitor.PollingInterval);

                //our transition method should have been called X times based on the list of valid items + 1 time for the null on the first scheduled execution, then an additional time w/ null for the next scheduled execution
                A.CallTo(() => jobStorage.NextQueuedItem()).MustHaveHappened(Repeated.Exactly.Times(incomingItems.Length));
            }
        }
예제 #6
0
        public void Subscribe_ResumesInProperQueuePositionAfterReadingMaximumDuringInterval()
        {
            int maxToSlurp = 3;
            var jobStorage = A.Fake <IDurableJobQueue <Incoming, Incoming> >();
            var scheduler  = new HistoricalScheduler();
            var monitor    = new DurableJobQueueMonitor <Incoming, Incoming>(jobStorage, maxToSlurp, DurableJobQueueMonitor.DefaultPollingInterval,
                                                                             scheduler);

            List <Incoming> incomingItems = new List <Incoming>();

            var queuedItems = Enumerable.Repeat(Item.From(new Incoming()
            {
                Id = 1
            }), 3)
                              .Concat(new []
            {
                Item.From(new Incoming()
                {
                    Id = 456
                }),
                Item.From(new Incoming()
                {
                    Id = 222
                }),
                Item.From(new Incoming()
                {
                    Id = 8714
                })
            })
                              .Concat(Enumerable.Repeat(Item.From(new Incoming()
            {
                Id = 5
            }), 2))
                              .Concat(Enumerable.Repeat(Item.From(new Incoming()
            {
                Id = 2
            }), 4))
                              .Concat(Enumerable.Repeat(Item.From(new Incoming()
            {
                Id = 3
            }), 3))
                              .ToArray();

            A.CallTo(() => jobStorage.NextQueuedItem()).ReturnsNextFromSequence(queuedItems);

            using (var subscription = monitor.Subscribe(publishedItem => { incomingItems.Add(publishedItem); }))
            {
                scheduler.AdvanceBy(monitor.PollingInterval);
                scheduler.AdvanceBy(monitor.PollingInterval);

                Assert.True(queuedItems.Take(maxToSlurp * 2)
                            .Select(item => item.Value)
                            .SequenceEqual(incomingItems, GenericEqualityComparer <Incoming> .ByAllMembers()));
            }
        }
예제 #7
0
        public void Monitor_PollsOnSpecifiedInterval(int minutes)
        {
            var jobStorage = A.Fake <IDurableJobQueue <Incoming, Incoming> >();
            var scheduler  = new HistoricalScheduler();
            var interval   = TimeSpan.FromMinutes(minutes);
            var monitor    = new DurableJobQueueMonitor <Incoming, Incoming>(jobStorage, 20, interval, scheduler);

            using (var subscription = monitor.Subscribe())
            {
                A.CallTo(() => jobStorage.NextQueuedItem()).Returns(Item.From(new Incoming()
                {
                    Id = 1
                }));

                //this is a little hacky, but give ourselves a 2 second timespan to make the call against our fake
                scheduler.AdvanceBy(interval - TimeSpan.FromSeconds(2));
                A.CallTo(() => jobStorage.NextQueuedItem()).MustNotHaveHappened();
            }
        }
예제 #8
0
        public static void Subscribe_CallsTransitionNextQueuedItemCorrectNumberOfTimesOverMultipleElapsedIntervals()
        {
            var jobStorage = A.Fake<IDurableJobQueue<Incoming, Incoming>>();
            var scheduler = new HistoricalScheduler();
            var monitor = new DurableJobQueueMonitor<Incoming, Incoming>(jobStorage, 20, DurableJobQueueMonitor.DefaultPollingInterval, scheduler);

            var queuedItems = Enumerable.Repeat(Item.From(new Incoming() { Id = 1 }), 5)
                .Concat(new [] { Item.None<Incoming>() })
                .Concat(Enumerable.Repeat(Item.From(new Incoming() { Id = 2 }), 5))
                .Concat(new [] { Item.None<Incoming>() }).ToArray();

            using (var subscription = monitor.Subscribe())
            {
                A.CallTo(() => jobStorage.NextQueuedItem()).ReturnsNextFromSequence(queuedItems);

                scheduler.AdvanceBy(monitor.PollingInterval);
                scheduler.AdvanceBy(monitor.PollingInterval);

                A.CallTo(() => jobStorage.NextQueuedItem()).MustHaveHappened(Repeated.Exactly.Times(queuedItems.Length));
            }
        }
예제 #9
0
        public void Subscribe_TakesNoMoreThanMaximumSpecifiedItemsPerInterval()
        {
            int maxToSlurp = 3;
            var jobStorage = A.Fake<IDurableJobQueue<Incoming, Incoming>>();
            A.CallTo(() => jobStorage.NextQueuedItem()).Returns(Item.From(new Incoming() { Id = 1 }));
            var scheduler = new HistoricalScheduler();
            var monitor = new DurableJobQueueMonitor<Incoming, Incoming>(jobStorage, maxToSlurp, DurableJobQueueMonitor.DefaultPollingInterval,
            scheduler);
            var completion = new ManualResetEventSlim(false);

            List<Incoming> incomingItems = new List<Incoming>();

            using (var subscription = monitor.Subscribe(publishedItem =>
            {
                incomingItems.Add(publishedItem);
                if (incomingItems.Count >= maxToSlurp)
                {
                    completion.Set();
                }
            }))
            {
                scheduler.AdvanceBy(monitor.PollingInterval + TimeSpan.FromTicks(1));
                completion.Wait(TimeSpan.FromSeconds(3));

                Assert.Equal(maxToSlurp, incomingItems.Count);
            }
        }
예제 #10
0
        public void Subscribe_ResumesInProperQueuePositionAfterReadingMaximumDuringInterval()
        {
            int maxToSlurp = 3;
            var jobStorage = A.Fake<IDurableJobQueue<Incoming, Incoming>>();
            var scheduler = new HistoricalScheduler();
            var monitor = new DurableJobQueueMonitor<Incoming, Incoming>(jobStorage, maxToSlurp, DurableJobQueueMonitor.DefaultPollingInterval,
            scheduler);

            List<Incoming> incomingItems = new List<Incoming>();

            var queuedItems = Enumerable.Repeat(Item.From(new Incoming() { Id = 1 }), 3)
                .Concat(new []
                {
                    Item.From(new Incoming() { Id = 456 }),
                    Item.From(new Incoming() { Id = 222 }),
                    Item.From(new Incoming() { Id = 8714 })
                })
                .Concat(Enumerable.Repeat(Item.From(new Incoming() { Id = 5 }), 2))
                .Concat(Enumerable.Repeat(Item.From(new Incoming() { Id = 2 }), 4))
                .Concat(Enumerable.Repeat(Item.From(new Incoming() { Id = 3 }), 3))
                .ToArray();

            A.CallTo(() => jobStorage.NextQueuedItem()).ReturnsNextFromSequence(queuedItems);

            using (var subscription = monitor.Subscribe(publishedItem =>{ incomingItems.Add(publishedItem);}))
            {
                scheduler.AdvanceBy(monitor.PollingInterval);
                scheduler.AdvanceBy(monitor.PollingInterval);

                Assert.True(queuedItems.Take(maxToSlurp * 2)
                    .Select(item => item.Value)
                    .SequenceEqual(incomingItems, GenericEqualityComparer<Incoming>.ByAllMembers()));
            }
        }
예제 #11
0
        public void Monitor_PollsOnSpecifiedInterval(int minutes)
        {
            var jobStorage = A.Fake<IDurableJobQueue<Incoming, Incoming>>();
            var scheduler = new HistoricalScheduler();
            var interval = TimeSpan.FromMinutes(minutes);
            var monitor = new DurableJobQueueMonitor<Incoming, Incoming>(jobStorage, 20, interval, scheduler);

            using (var subscription = monitor.Subscribe())
            {
                A.CallTo(() => jobStorage.NextQueuedItem()).Returns(Item.From(new Incoming() { Id = 1 }));

                //this is a little hacky, but give ourselves a 2 second timespan to make the call against our fake
                scheduler.AdvanceBy(interval - TimeSpan.FromSeconds(2));
                A.CallTo(() => jobStorage.NextQueuedItem()).MustNotHaveHappened();
            }
        }
예제 #12
0
        public void Monitor_AwaitsFirstSubscriberBeforePublishing()
        {
            var jobStorage = A.Fake<IDurableJobQueue<Incoming, Incoming>>();
            var scheduler = new HistoricalScheduler();
            var monitor = new DurableJobQueueMonitor<Incoming, Incoming>(jobStorage, 20, DurableJobQueueMonitor.DefaultPollingInterval, scheduler);

            //X items + a null terminator per each elapsed interval
            var incomingItems = Enumerable.Repeat(Item.From(new Incoming() { Id = 2 }), 5)
                .Concat(new[] { Item.None<Incoming>(), Item.None<Incoming>() }).ToArray();

            A.CallTo(() => jobStorage.NextQueuedItem()).ReturnsNextFromSequence(incomingItems);

            //advance the amount of time that would normally cause our queue to be totally flushed
            scheduler.AdvanceBy(monitor.PollingInterval.Add(monitor.PollingInterval));
            using (var subscription = monitor.Subscribe())
            {
                //and now that we have a subscriber, elapse enough time to publish the queue contents
                scheduler.AdvanceBy(monitor.PollingInterval);
                scheduler.AdvanceBy(monitor.PollingInterval);

                //our transition method should have been called X times based on the list of valid items + 1 time for the null on the first scheduled execution, then an additional time w/ null for the next scheduled execution
                A.CallTo(() => jobStorage.NextQueuedItem()).MustHaveHappened(Repeated.Exactly.Times(incomingItems.Length));
            }
        }