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)); } }
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())); } }
public void PublishReconnect() { var scheduler = new HistoricalScheduler(); var source = Observable.Interval(TimeSpan.FromMilliseconds(50), scheduler); int result = 0; var published = source.Publish(); var pdis1 = published.Subscribe(i => result++); Assert.AreEqual(0, result, "#0"); var cdis1 = published.Connect(); scheduler.AdvanceBy(TimeSpan.FromMilliseconds(200)); // should be enough to receive some events Assert.AreEqual(4, result, "#1"); pdis1.Dispose(); cdis1.Dispose(); // disconnect scheduler.AdvanceBy(TimeSpan.FromMilliseconds(200)); // should be enough to raise interval event if it were active (which should *not*) Assert.AreEqual(4, result, "#2"); // Step 2: Without any *new* subscription, it does not result in events. var cdis2 = published.Connect(); scheduler.AdvanceBy(TimeSpan.FromMilliseconds(200)); // should be enough to receive some events Assert.AreEqual(4, result, "#3"); cdis2.Dispose(); // Step 3: with new subscription, it should result in events again. var pdis3 = published.Subscribe(i => result++); var cdis3 = published.Connect(); // without any *new* subscription, it does not result in events. scheduler.AdvanceBy(TimeSpan.FromMilliseconds(200)); // should be enough to receive some events Assert.AreEqual(8, result, "#3"); cdis3.Dispose(); pdis3.Dispose(); // This should not result in NRE (possibly because of the internal cleanup). Note that this is in reverse order to pdis1 }
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)); } }
public void RefCount() { int side = 0; var scheduler = new HistoricalScheduler(); var source = Observable.Interval(TimeSpan.FromMilliseconds(50), scheduler).Do(i => side++); int result = 0; var published = source.Publish(); var connected = published.RefCount(); var cdis1 = connected.Subscribe(i => result++); scheduler.AdvanceBy(TimeSpan.FromMilliseconds(400)); Assert.IsTrue(result > 0, "#1"); cdis1.Dispose(); // also disconnects. int oldSide = side; scheduler.AdvanceBy(TimeSpan.FromMilliseconds(400)); Assert.AreEqual(oldSide, side, "#2"); // no advance in sequence var cdis2 = connected.Subscribe(i => result++); scheduler.AdvanceBy(TimeSpan.FromSeconds(1)); Assert.IsTrue(side > oldSide, "#3"); cdis2.Dispose(); }
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())); } }
public void Delay2() { // github issue #12 var scheduler = new HistoricalScheduler(); var source = Observable.Interval(TimeSpan.FromSeconds(1), scheduler).Take(5).Timestamp(); var delayed = source.Delay(TimeSpan.FromSeconds(4), scheduler).Timestamp(); bool done = false; delayed.Subscribe(item => Assert.IsTrue(item.Value.Timestamp < item.Timestamp, "not delayed"), () => done = true); scheduler.AdvanceBy(TimeSpan.FromSeconds(3)); Assert.IsFalse(done, "#1"); scheduler.AdvanceBy(TimeSpan.FromSeconds(10)); Assert.IsTrue(done, "#2"); }
public void GroupJoin() { var scheduler = new HistoricalScheduler(); var source = Observable.GroupJoin( Observable.Interval(TimeSpan.FromMilliseconds(500), scheduler).Take(10), Observable.Interval(TimeSpan.FromMilliseconds(800), scheduler).Delay(TimeSpan.FromSeconds(1), scheduler), l => Observable.Interval(TimeSpan.FromMilliseconds(1500), scheduler), r => Observable.Interval(TimeSpan.FromMilliseconds(1600), scheduler), (l, rob) => new { Left = l, Rights = rob } ); bool done = false; bool [,] results = new bool [10, 10]; bool [] groupDone = new bool [10]; source.Subscribe( v => v.Rights.Subscribe( r => results [v.Left, r] = true, () => groupDone [v.Left] = true), () => done = true); scheduler.AdvanceBy(TimeSpan.FromSeconds(15)); Assert.IsTrue(done, "#1"); Assert.AreEqual(-1, Array.IndexOf(groupDone, false), "#2"); int [] rstarts = new int [] { 0, 0, 0, 0, 0, 0, 1, 1, 2, 3 }; int [] rends = new int [] { 0, 0, 1, 2, 2, 3, 3, 4, 5, 5 }; for (int l = 0; l < 10; l++) { for (int r = 0; r < 10; r++) { Assert.AreEqual(rstarts [l] <= r && r <= rends [l], results [l, r], String.Format("({0}, {1})", l, r)); } } }
public void GroupJoin2() { // almost identical to the previous one, but without delay. And I only test some corner case that could result in difference. var scheduler = new HistoricalScheduler(); var source = Observable.GroupJoin( Observable.Interval(TimeSpan.FromMilliseconds(500), scheduler).Take(10), Observable.Interval(TimeSpan.FromMilliseconds(800), scheduler), l => Observable.Interval(TimeSpan.FromMilliseconds(1500), scheduler), r => Observable.Interval(TimeSpan.FromMilliseconds(1600), scheduler), (l, rob) => new { Left = l, Rights = rob } ); bool done = false; bool [,] results = new bool [10, 10]; bool [] groupDone = new bool [10]; source.Subscribe( v => v.Rights.Subscribe( r => results [v.Left, r] = true, () => groupDone [v.Left] = true), () => done = true); scheduler.AdvanceBy(TimeSpan.FromSeconds(15)); Assert.IsTrue(done, "#1"); // this value could be published *IF* unsubscription is // handled *after* 7 is published as a left value. // Rx does not publish this, likely means a right value // at the end moment of rightDuration is *not* published // ... so we do that too. Assert.IsFalse(results [7, 2], "#2"); }
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); } }
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())); } }
public void Throttle2() { var subject = new Subject <string> (); var scheduler = new HistoricalScheduler(); var input = (from text in subject select text).Throttle(TimeSpan.FromSeconds(0.5), scheduler).Timestamp(scheduler); var sw = new StringWriter(); input.Subscribe( v => sw.WriteLine("THR: {0} at {1:ss.fff} timer:{2:ss.fff}", v.Value, v.Timestamp, scheduler.Now), () => sw.WriteLine("THR: completed: {0:ss.fff}", scheduler.Now)); int [] vals = { 100, 600, 300, 600, 400, 900, 500, 800 }; for (int i = 0; i < 10; i++) { var val = vals [i % vals.Length]; scheduler.AdvanceBy(TimeSpan.FromMilliseconds(val)); subject.OnNext(val.ToString()); } subject.OnCompleted(); string expected = @"THR: 100 at 00.600 timer:00.600 THR: 300 at 01.500 timer:01.500 THR: 400 at 02.500 timer:02.500 THR: 900 at 03.400 timer:03.400 THR: 500 at 03.900 timer:03.900 THR: 100 at 04.800 timer:04.800 THR: 600 at 04.900 timer:04.900 THR: completed: 04.900 ".Replace("\r\n", "\n"); Assert.AreEqual(expected, sw.ToString().Replace("\r\n", "\n"), "#1"); }
public void PublishReconnect() { var scheduler = new HistoricalScheduler (); var source = Observable.Interval (TimeSpan.FromMilliseconds (50), scheduler); int result = 0; var published = source.Publish (); var pdis1 = published.Subscribe (i => result++); Assert.AreEqual (0, result, "#0"); var cdis1 = published.Connect (); scheduler.AdvanceBy (TimeSpan.FromMilliseconds (200)); // should be enough to receive some events Assert.AreEqual (4, result, "#1"); pdis1.Dispose (); cdis1.Dispose (); // disconnect scheduler.AdvanceBy (TimeSpan.FromMilliseconds (200)); // should be enough to raise interval event if it were active (which should *not*) Assert.AreEqual (4, result, "#2"); // Step 2: Without any *new* subscription, it does not result in events. var cdis2 = published.Connect (); scheduler.AdvanceBy (TimeSpan.FromMilliseconds (200)); // should be enough to receive some events Assert.AreEqual (4, result , "#3"); cdis2.Dispose (); // Step 3: with new subscription, it should result in events again. var pdis3 = published.Subscribe (i => result++); var cdis3 = published.Connect (); // without any *new* subscription, it does not result in events. scheduler.AdvanceBy (TimeSpan.FromMilliseconds (200)); // should be enough to receive some events Assert.AreEqual (8, result , "#3"); cdis3.Dispose (); pdis3.Dispose (); // This should not result in NRE (possibly because of the internal cleanup). Note that this is in reverse order to pdis1 }
public void No_Nested_AdvanceBy() { var s = new HistoricalScheduler(); s.Schedule(() => s.AdvanceBy(TimeSpan.FromSeconds(1))); ReactiveAssert.Throws <InvalidOperationException>(() => s.Start()); }
public void RecursiveActionTimeSpan2() { int i = 0; var scheduler = new HistoricalScheduler (); var span = TimeSpan.FromMilliseconds (50); scheduler.Schedule<object> (null, span, (object obj,Action<object,TimeSpan> a) => { i++; a (obj, span); }); scheduler.AdvanceBy (TimeSpan.FromSeconds (1)); Assert.AreEqual (20, i, "#1"); }
public void Clock() { var scheduler = new HistoricalScheduler (); Assert.AreEqual (DateTimeOffset.MinValue, scheduler.Clock, "#1"); // default scheduler.AdvanceBy (TimeSpan.FromDays (1)); Assert.AreEqual (DateTimeOffset.MinValue.AddDays (1), scheduler.Clock, "#2"); scheduler.AdvanceTo (new DateTimeOffset (2012, 1, 1, 0, 0, 0, TimeSpan.Zero)); Assert.AreEqual (2012, scheduler.Clock.Year, "#3"); }
public void Clock() { var scheduler = new HistoricalScheduler(); Assert.AreEqual(DateTimeOffset.MinValue, scheduler.Clock, "#1"); // default scheduler.AdvanceBy(TimeSpan.FromDays(1)); Assert.AreEqual(DateTimeOffset.MinValue.AddDays(1), scheduler.Clock, "#2"); scheduler.AdvanceTo(new DateTimeOffset(2012, 1, 1, 0, 0, 0, TimeSpan.Zero)); Assert.AreEqual(2012, scheduler.Clock.Year, "#3"); }
public void TimeoutOutOfTime() { var scheduler = new HistoricalScheduler(); var source = Observable.Interval(TimeSpan.FromSeconds(1), scheduler).Take(2).Timeout(TimeSpan.FromSeconds(1), scheduler); string s = null; source.Subscribe(v => s += v, ex => s += "error:" + ex.GetType(), () => s += "done"); scheduler.AdvanceBy(TimeSpan.FromSeconds(5)); Assert.AreEqual("error:System.TimeoutException", s, "#1"); }
public void RecursiveActionTimeSpan2() { int i = 0; var scheduler = new HistoricalScheduler(); var span = TimeSpan.FromMilliseconds(50); scheduler.Schedule <object> (null, span, (object obj, Action <object, TimeSpan> a) => { i++; a(obj, span); }); scheduler.AdvanceBy(TimeSpan.FromSeconds(1)); Assert.AreEqual(20, i, "#1"); }
public void Amb() { var scheduler = new HistoricalScheduler(); var s1 = Observable.Range(1, 3).Delay(TimeSpan.FromMilliseconds(500), scheduler); var s2 = Observable.Range(4, 3); var e = s1.Amb(s2).ToEnumerable().ToArray(); scheduler.AdvanceBy(TimeSpan.FromSeconds(1)); Assert.AreEqual(new int [] { 4, 5, 6 }, e, "#1"); }
IEnumerable <IObservable <long> > IntervalSelectTakeDoEnumerable(HistoricalScheduler scheduler, List <string> l, TextWriter sw) { DateTimeOffset start = scheduler.Now; for (int i = 0; i < 5; i++) { int x = i; scheduler.AdvanceBy(TimeSpan.FromMilliseconds(150)); yield return(Observable.Interval(TimeSpan.FromMilliseconds(100), scheduler) #if false .Select(v => x * 10 + v).Take(5) #else // FIXME: this select should work, but it does not give expected "i" or "x" values, likely due to some mcs bug regarding local variable volatility... // ... So I used out-of-scope value comparison here. .Select(v => (long)((scheduler.Now - start).TotalMilliseconds / 20) + v).Take(5) #endif .Do(v => l.Add(String.Format("{0:ss.fff}: {1} {2}", scheduler.Now, i, v)), () => sw.WriteLine())); scheduler.AdvanceBy(TimeSpan.FromMilliseconds(50)); } }
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)); } }
public void WindowTimeSpans2() { var scheduler = new HistoricalScheduler(); var interval = TimeSpan.FromMilliseconds(100); var span = TimeSpan.FromMilliseconds(500); var shift = TimeSpan.FromMilliseconds(300); var total = TimeSpan.FromMilliseconds(1500); var sw = new StringWriter() { NewLine = "\n" }; var sources = Observable.Interval(interval, scheduler).Take(15).Window(span, shift, scheduler); int windows = 0; bool [] windowDone = new bool [6]; sources.Subscribe(source => { int w = windows++; source.Subscribe(v => sw.WriteLine("{0:ss.fff} {1} [{2}]", scheduler.Now, v, w), () => windowDone [w] = true); }, () => sw.WriteLine("done")); scheduler.AdvanceBy(total); string expected = @"00.100 0 [0] 00.200 1 [0] 00.300 2 [0] 00.300 2 [1] 00.400 3 [0] 00.400 3 [1] 00.500 4 [1] 00.600 5 [1] 00.600 5 [2] 00.700 6 [1] 00.700 6 [2] 00.800 7 [2] 00.900 8 [2] 00.900 8 [3] 01.000 9 [2] 01.000 9 [3] 01.100 10 [3] 01.200 11 [3] 01.200 11 [4] 01.300 12 [3] 01.300 12 [4] 01.400 13 [4] 01.500 14 [4] 01.500 14 [5] done " .Replace("\t", "").Replace("\r", ""); Assert.AreEqual(expected, sw.ToString(), "#1"); Assert.AreEqual(-1, Array.IndexOf(windowDone, false), "#2"); }
public void Throttle() { var scheduler = new HistoricalScheduler(); var source = Observable.Range(1, 3).Concat(Observable.Return(2).Delay(TimeSpan.FromMilliseconds(100), scheduler)).Throttle(TimeSpan.FromMilliseconds(50), scheduler); bool done = false; var l = new List <int> (); var dis = source.Subscribe(v => l.Add(v), () => done = true); scheduler.AdvanceBy(TimeSpan.FromSeconds(1)); Assert.IsTrue(done, "#1"); Assert.AreEqual(new int [] { 3, 2 }, l.ToArray(), "#2"); dis.Dispose(); }
public void AdvanceByRaisesEvent2() { // This is actually very complicated pattern of error, caused by all of: // - Concat() when it internally uses SerialDisposable instead of CompositeDisposable. // - Delay() with non-zero duration. // - Delay() with non-CurrentThreadScheduler. var scheduler = new HistoricalScheduler (); var o = Observable.Empty<int> (scheduler).Delay (TimeSpan.FromSeconds (1), scheduler); bool done = false; Observable.Range (0, 3).Concat (o).Subscribe (v => {}, () => done = true); scheduler.AdvanceBy (TimeSpan.FromSeconds (2)); Assert.IsTrue (done, "#1"); }
public async Task DoesntSaveDraftForNonEditingComment() { var scheduler = new HistoricalScheduler(); var drafts = Substitute.For <IMessageDraftStore>(); var target = CreateTarget(drafts: drafts, scheduler: scheduler); await target.AddPlaceholder(false); target.Comments[0].Body = "Edited comment."; scheduler.AdvanceBy(TimeSpan.FromSeconds(1)); await drafts.DidNotReceiveWithAnyArgs().UpdateDraft <CommentDraft>(null, null, null); }
public void AdvanceByRaisesEvent2() { // This is actually very complicated pattern of error, caused by all of: // - Concat() when it internally uses SerialDisposable instead of CompositeDisposable. // - Delay() with non-zero duration. // - Delay() with non-CurrentThreadScheduler. var scheduler = new HistoricalScheduler(); var o = Observable.Empty <int> (scheduler).Delay(TimeSpan.FromSeconds(1), scheduler); bool done = false; Observable.Range(0, 3).Concat(o).Subscribe(v => {}, () => done = true); scheduler.AdvanceBy(TimeSpan.FromSeconds(2)); Assert.IsTrue(done, "#1"); }
public void SelectManyObservable() { var scheduler = new HistoricalScheduler(); Func <int, IObservable <int> > f = x => Observable.Return(x).Delay(TimeSpan.FromSeconds(1), scheduler); var source = Observable.Range(0, 5).SelectMany(n => f(n)); var l = new List <int> (); bool done = false; var dis = source.Subscribe(v => l.Add(v), () => done = true); Assert.IsFalse(done, "#1"); scheduler.AdvanceBy(TimeSpan.FromSeconds(1)); Assert.AreEqual(new int [] { 0, 1, 2, 3, 4 }, l.ToArray(), "#2"); Assert.IsTrue(done, "#3"); }
[Test] // some practical test public void IntervalSelectTakeDo() { var scheduler = new HistoricalScheduler(); var l = new List <string> (); var sw = new StringWriter() { NewLine = "\n" }; foreach (var o in IntervalSelectTakeDoEnumerable(scheduler, l, TextWriter.Null)) { o.Subscribe(v => {}); // dummy } scheduler.AdvanceBy(TimeSpan.FromSeconds(3)); l.Sort(); foreach (var s in l) { sw.WriteLine(s); } string expected = @"00.250: 1 12 00.350: 1 18 00.450: 2 22 00.450: 2 24 00.550: 2 28 00.550: 2 30 00.650: 3 32 00.650: 3 34 00.650: 3 36 00.750: 3 38 00.750: 3 40 00.850: 4 42 00.850: 4 44 00.850: 4 46 00.950: 4 48 00.950: 4 50 01.050: 5 52 01.050: 5 54 01.050: 5 56 01.150: 5 58 01.150: 5 60 01.250: 5 64 01.250: 5 66 01.350: 5 70 01.450: 5 76 " .Replace("\r", "").Replace("\t", ""); Assert.AreEqual(expected, sw.ToString(), "#1"); }
public void Monitor_DoesNotPumpQueueWithZeroSubscribers() { var jobStorage = A.Fake <IDurableJobQueue <Incoming, Incoming> >(); var scheduler = new HistoricalScheduler(); var monitor = new DurableJobQueueMonitor <Incoming, Incoming>(jobStorage, 20, DurableJobQueueMonitor.DefaultPollingInterval, scheduler); A.CallTo(() => jobStorage.NextQueuedItem()).Returns(Item.From(new Incoming() { Id = 1 })); scheduler.AdvanceBy(monitor.PollingInterval.Add(monitor.PollingInterval)); A.CallTo(() => jobStorage.NextQueuedItem()).MustNotHaveHappened(); }
public void Delay() { var scheduler = new HistoricalScheduler(); var source = Observable.Return(2).Delay(TimeSpan.FromMilliseconds(50), scheduler).Materialize(); var l = new List <NotificationKind> (); bool done = false; source.Subscribe(v => l.Add(v.Kind), () => done = true); scheduler.AdvanceBy(TimeSpan.FromMilliseconds(50)); Assert.IsTrue(done, "#2"); Assert.AreEqual(new NotificationKind [] { NotificationKind.OnNext, NotificationKind.OnCompleted }, l.ToArray(), "#3"); }
static void Main() { var scheduler = new HistoricalScheduler(); var interval = TimeSpan.FromSeconds(0.75); var subscription = Observable.Interval(interval, scheduler) .TimeInterval(scheduler) .Scan(TimeSpan.Zero, (acc, cur) => acc + cur.Interval) .Subscribe(DrawBall); scheduler.AdvanceBy(TimeSpan.FromSeconds(5)); subscription.Dispose(); Console.WriteLine("Press any key..."); Console.ReadKey(true); }
public void CancelQueuedAndWaitForExecutingJobsToComplete_WaitsOnJobs() { var scheduler = new HistoricalScheduler(); var queue = _monitoredJobQueueFactory(new HistoricalScheduler(), _durableQueueFactory); foreach (var input in _fixture.CreateMany <TInput>(30)) { queue.AddJob(input); } scheduler.AdvanceBy(TimeSpan.FromSeconds(30)); queue.CancelQueuedAndWaitForExecutingJobsToComplete(TimeSpan.FromSeconds(5)); Assert.True(queue.RunningCount == 0 && queue.QueuedCount == 0); }
public void GroupJoinRightSequenceError() { var scheduler = new HistoricalScheduler(); var source = Observable.GroupJoin( Observable.Interval(TimeSpan.FromMilliseconds(800), scheduler).Delay(TimeSpan.FromSeconds(1), scheduler), Observable.Throw <int> (new SystemException()), l => Observable.Interval(TimeSpan.FromMilliseconds(1500), scheduler), r => Observable.Interval(TimeSpan.FromMilliseconds(1600), scheduler), (l, rob) => new { Left = l, Rights = rob } ); string s = null; source.Subscribe(v => s += v, ex => s += "error:" + ex.GetType(), () => s += "done"); scheduler.AdvanceBy(TimeSpan.FromSeconds(15)); Assert.AreEqual("error:System.SystemException", s, "#1"); }
public void PublishLast() { var scheduler = new HistoricalScheduler (); var hot = Observable.Interval (TimeSpan.FromMilliseconds (20), scheduler).Skip (4).Take (2).PublishLast (); hot.Connect (); var observable = hot.Replay (); observable.Connect (); long result = 0; var dis = observable.Subscribe (i => result += i); scheduler.AdvanceBy (TimeSpan.FromSeconds (1)); Assert.AreEqual (5, result, "#1"); dis.Dispose (); var dis2 = observable.Subscribe (i => result += i); Assert.AreEqual (10, result, "#2"); dis2.Dispose (); }
public void GroupJoinRightDurationError() { var scheduler = new HistoricalScheduler(); var source = Observable.GroupJoin( Observable.Interval(TimeSpan.FromMilliseconds(500), scheduler).Delay(TimeSpan.FromSeconds(1), scheduler), Observable.Interval(TimeSpan.FromMilliseconds(800), scheduler).Delay(TimeSpan.FromSeconds(1), scheduler), l => Observable.Interval(TimeSpan.FromMilliseconds(1600), scheduler), r => Observable.Throw <int> (new SystemException()), (l, rob) => new { Left = l, Rights = rob } ); string s = null; source.Subscribe(v => {}, ex => s += "error:" + ex.GetType(), () => s += "done"); scheduler.AdvanceBy(TimeSpan.FromSeconds(15)); // LAMESPEC: shouldn't this also raise OnError() ? GroupByUntil() does so. Assert.AreEqual("error:System.SystemException", s, "#1"); }
public async Task Updates_Draft_When_Body_Changes() { var scheduler = new HistoricalScheduler(); var draftStore = Substitute.For <IMessageDraftStore>(); var target = CreateTarget(draftStore: draftStore, timerScheduler: scheduler); await InitializeAsync(target); target.Body = "Body changed."; await draftStore.DidNotReceiveWithAnyArgs().UpdateDraft <PullRequestReviewDraft>(null, null, null); scheduler.AdvanceBy(TimeSpan.FromSeconds(1)); await draftStore.Received().UpdateDraft( "pr-review|https://github.com/owner/repo|5", string.Empty, Arg.Is <PullRequestReviewDraft>(x => x.Body == "Body changed.")); }
public void RefCount() { int side = 0; var scheduler = new HistoricalScheduler (); var source = Observable.Interval (TimeSpan.FromMilliseconds (50), scheduler).Do (i => side++); int result = 0; var published = source.Publish (); var connected = published.RefCount (); var cdis1 = connected.Subscribe (i => result++); scheduler.AdvanceBy (TimeSpan.FromMilliseconds (400)); Assert.IsTrue (result > 0, "#1"); cdis1.Dispose (); // also disconnects. int oldSide = side; scheduler.AdvanceBy (TimeSpan.FromMilliseconds (400)); Assert.AreEqual (oldSide, side, "#2"); // no advance in sequence var cdis2 = connected.Subscribe (i => result++); scheduler.AdvanceBy (TimeSpan.FromSeconds (1)); Assert.IsTrue (side > oldSide, "#3"); cdis2.Dispose (); }
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)); } }
/// <summary> /// Simulates the time of the given loglines on the timer with the given speed /// runs the simulation on a different thread so this method does not block /// </summary> /// <param name="timer"></param> /// <param name="lines"></param> private void SimulateLogLines(HistoricalScheduler scheduler, List<ApacheLogLine> logLines, long speed) { Task t1 = new Task(() => { var lastTime = logLines.First().Date; logLines.ForEach(logLine => { var totalSeconds = (logLine.Date - lastTime).TotalMilliseconds; if (totalSeconds < 0) totalSeconds = 0; //Sometimes it seems not all lines are in the correct order var interval = TimeSpan.FromMilliseconds(totalSeconds); var result = TimeSpan.FromMilliseconds(totalSeconds / (double)speed); lastTime = logLine.Date; Thread.Sleep(result); scheduler.AdvanceBy(interval); }); }); t1.Start(); }
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); } }
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())); } }
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(); } }
public void Monitor_DoesNotPumpQueueWithZeroSubscribers() { var jobStorage = A.Fake<IDurableJobQueue<Incoming, Incoming>>(); var scheduler = new HistoricalScheduler(); var monitor = new DurableJobQueueMonitor<Incoming, Incoming>(jobStorage, 20, DurableJobQueueMonitor.DefaultPollingInterval, scheduler); A.CallTo(() => jobStorage.NextQueuedItem()).Returns(Item.From(new Incoming() { Id = 1 })); scheduler.AdvanceBy(monitor.PollingInterval.Add(monitor.PollingInterval)); A.CallTo(() => jobStorage.NextQueuedItem()).MustNotHaveHappened(); }