public void ShouldScheduleParallelInParallel()
        {
            var testScheduler  = new TestScheduler();
            var testObservable = testScheduler.CreateColdObservable(
                OnNext(100, Unit.Default),
                OnCompleted(100, Unit.Default)
                );
            var testObserver = testScheduler.CreateObserver <Unit>();

            using IScheduler s = new ProcessScheduler(new TestLoggerFactory(_testOutputHelper), null);

            s.Start();
            for (var i = 0; i < 8; i++)
            {
                s.Add(RequestProcessType.Parallel, "bogus", testObservable.Do(testObserver));
            }

            testScheduler.Start();

            testObservable.Subscriptions.Count.Should().Be(8);
            testObserver.Messages
            .Where(z => z.Value.Kind != NotificationKind.OnCompleted).Should()
            .ContainInOrder(
                OnNext(100, Unit.Default),
                OnNext(100, Unit.Default),
                OnNext(100, Unit.Default),
                OnNext(100, Unit.Default),
                OnNext(100, Unit.Default),
                OnNext(100, Unit.Default),
                OnNext(100, Unit.Default),
                OnNext(100, Unit.Default)
                );
        }
        public void Should_Handle_Exceptions_Tasks()
        {
            var testScheduler  = new TestScheduler();
            var testObservable = testScheduler.CreateColdObservable(
                OnNext(100, Unit.Default),
                OnCompleted(100, Unit.Default)
                );
            var errorObservable = testScheduler.CreateColdObservable(
                OnError(100, new NotSameException(), Unit.Default)
                );
            var testObserver = testScheduler.CreateObserver <Unit>();

            using IScheduler s = new ProcessScheduler(new TestLoggerFactory(_testOutputHelper), null);

            s.Start();
            s.Add(RequestProcessType.Serial, "bogus", testObservable.Do(testObserver));
            s.Add(RequestProcessType.Serial, "somethingelse", errorObservable.Do(testObserver));
            s.Add(RequestProcessType.Serial, "bogus", testObservable.Do(testObserver));

            testScheduler.Start();

            testObservable.Subscriptions.Count.Should().Be(2);
            var messages = testObserver.Messages
                           .Where(z => z.Value.Kind != NotificationKind.OnCompleted)
                           .ToArray();

            messages.Should().Contain(x => x.Value.Kind == NotificationKind.OnNext && x.Time == 100);
            messages.Should().Contain(x => x.Value.Kind == NotificationKind.OnError && x.Time == 200 && x.Value.Exception is NotSameException);
            messages.Should().Contain(x => x.Value.Kind == NotificationKind.OnNext && x.Time == 300);
        }
        public void Should_Handle_Exceptions_Tasks()
        {
            var testScheduler  = new TestScheduler();
            var testObservable = testScheduler.CreateColdObservable(
                OnNext(Subscribed, Unit.Default),
                OnCompleted(Subscribed, Unit.Default)
                );
            var errorObservable = testScheduler.CreateColdObservable(
                OnError(Subscribed, new NotSameException(), Unit.Default)
                );
            var testObserver = testScheduler.CreateObserver <Unit>();

            using var s = new ProcessScheduler(new TestLoggerFactory(_testOutputHelper), false, null, TimeSpan.FromSeconds(30), testScheduler);

            s.Add(RequestProcessType.Serial, "bogus", DoStuff(testObservable, testObserver));
            s.Add(RequestProcessType.Serial, "somethingelse", DoStuff(errorObservable, testObserver));
            s.Add(RequestProcessType.Serial, "bogus", DoStuff(testObservable, testObserver));

            testScheduler.Start();

            testObservable.Subscriptions.Count.Should().Be(2);
            errorObservable.Subscriptions.Should().HaveCount(1);
            var messages = testObserver.Messages
                           .Where(z => z.Value.Kind != NotificationKind.OnCompleted)
                           .ToArray();

            messages.Should().Contain(x => x.Value.Kind == NotificationKind.OnNext && x.Time == Subscribed);
            messages.Should().Contain(x => x.Value.Kind == NotificationKind.OnError && x.Time == Subscribed * 2 && x.Value.Exception is NotSameException);
            messages.Should().Contain(x => x.Value.Kind == NotificationKind.OnNext && x.Time == Subscribed * 3);
        }
        public void ShouldScheduleSerialInOrder()
        {
            var testScheduler  = new TestScheduler();
            var testObservable = testScheduler.CreateColdObservable(
                OnNext(Subscribed, Unit.Default),
                OnCompleted(Subscribed, Unit.Default)
                );
            var testObserver = testScheduler.CreateObserver <Unit>();

            using var s = new ProcessScheduler(new TestLoggerFactory(_testOutputHelper), false, null, TimeSpan.FromSeconds(30), testScheduler);


            for (var i = 0; i < 8; i++)
            {
                s.Add(RequestProcessType.Serial, "bogus", DoStuff(testObservable, testObserver));
            }

            testScheduler.Start();

            testObservable.Subscriptions.Count.Should().Be(8);
            testObserver.Messages
            .Where(z => z.Value.Kind != NotificationKind.OnCompleted).Should()
            .ContainInOrder(
                OnNext(Subscribed, Unit.Default),
                OnNext(Subscribed * 2, Unit.Default),
                OnNext(Subscribed * 3, Unit.Default),
                OnNext(Subscribed * 4, Unit.Default),
                OnNext(Subscribed * 5, Unit.Default),
                OnNext(Subscribed * 6, Unit.Default),
                OnNext(Subscribed * 7, Unit.Default),
                OnNext(Subscribed * 8, Unit.Default)
                );
        }
        public void ShouldScheduleSerialInOrder()
        {
            using (IScheduler s = new ProcessScheduler(new TestLoggerFactory(_testOutputHelper)))
            {
                var done    = new CountdownEvent(3); // 3x s.Add
                var running = 0;
                var peek    = 0;

                Func <Task> HandlePeek = async() =>
                {
                    var p = Interlocked.Increment(ref running);
                    lock (this) peek = Math.Max(peek, p);
                    await Task.Delay(SLEEPTIME_MS); // give a different HandlePeek task a chance to run

                    Interlocked.Decrement(ref running);
                    done.Signal();
                };

                s.Start();
                for (var i = 0; i < done.CurrentCount; i++)
                {
                    s.Add(RequestProcessType.Serial, "bogus", HandlePeek);
                }

                done.Wait(ALONGTIME_MS).Should().Be(true, because: "all tasks have to run");
                running.Should().Be(0, because: "all tasks have to run normally");
                peek.Should().Be(1, because: "all tasks must not overlap");
                s.Dispose();
                Interlocked.Read(ref ((ProcessScheduler)s)._TestOnly_NonCompleteTaskCount).Should().Be(0, because: "the scheduler must not wait for tasks to complete after disposal");
            }
        }
 public void ShouldScheduleAwaitableTask()
 {
     using (IScheduler s = new ProcessScheduler(new TestLoggerFactory(_testOutputHelper)))
     {
         var done = new CountdownEvent(1);
         s.Start();
         s.Add(RequestProcessType.Serial, "bogus", async() =>
         {
             await Task.Yield();
             done.Signal();
         });
         done.Wait(ALONGTIME_MS).Should().Be(true, because: "all tasks have to run");
     }
 }
 public void ShouldScheduleCompletedTask(RequestProcessType type)
 {
     using (IScheduler s = new ProcessScheduler(new TestLoggerFactory(_testOutputHelper)))
     {
         var done = new CountdownEvent(1);
         s.Start();
         s.Add(type, "bogus", () =>
         {
             done.Signal();
             return(Task.CompletedTask);
         });
         done.Wait(ALONGTIME_MS).Should().Be(true, because: "all tasks have to run");
     }
 }
        public void ShouldScheduleCompletedTask(RequestProcessType type)
        {
            var testScheduler  = new TestScheduler();
            var testObservable = testScheduler.CreateColdObservable(
                OnNext(100, Unit.Default),
                OnCompleted(100, Unit.Default)
                );
            var testObserver = testScheduler.CreateObserver <Unit>();

            using IScheduler s = new ProcessScheduler(new TestLoggerFactory(_testOutputHelper), null);

            s.Start();
            s.Add(type, "bogus", testObservable.Do(testObserver));

            testScheduler.AdvanceTo(50);

            testObservable.Subscriptions.Count.Should().Be(1);

            testScheduler.AdvanceTo(101);

            testObservable.Subscriptions.Count.Should().Be(1);
            testObserver.Messages.Should().Contain(z => z.Value.Kind == NotificationKind.OnNext);
            testObserver.Messages.Should().Contain(z => z.Value.Kind == NotificationKind.OnCompleted);
        }
        public void ShouldScheduleCompletedTask(RequestProcessType type)
        {
            var testScheduler  = new TestScheduler();
            var testObservable = testScheduler.CreateColdObservable(
                OnNext(Subscribed, Unit.Default),
                OnCompleted(Subscribed, Unit.Default)
                );
            var testObserver = testScheduler.CreateObserver <Unit>();

            using var s = new ProcessScheduler(new TestLoggerFactory(_testOutputHelper), false, null, TimeSpan.FromSeconds(30), testScheduler);


            s.Add(type, "bogus", DoStuff(testObservable, testObserver));

            testScheduler.AdvanceTo(Subscribed / 2);

            testObservable.Subscriptions.Count.Should().Be(1);

            testScheduler.AdvanceTo(Subscribed + 1);

            testObservable.Subscriptions.Count.Should().Be(1);
            testObserver.Messages.Should().Contain(z => z.Value.Kind == NotificationKind.OnNext);
            testObserver.Messages.Should().Contain(z => z.Value.Kind == NotificationKind.OnCompleted);
        }
        public void ShouldScheduleWithConcurrency_WithContentModified()
        {
            var testScheduler  = new TestScheduler();
            var testObservable = testScheduler.CreateColdObservable(
                OnNext(Subscribed, Unit.Default),
                OnCompleted(Subscribed, Unit.Default)
                );
            var testObserver = testScheduler.CreateObserver <Unit>();

            using var s = new ProcessScheduler(new TestLoggerFactory(_testOutputHelper), true, 3, TimeSpan.FromSeconds(30), testScheduler);

            s.Add(RequestProcessType.Parallel, "bogus", DoStuff(testObservable, testObserver));
            s.Add(RequestProcessType.Parallel, "bogus", DoStuff(testObservable, testObserver));
            s.Add(RequestProcessType.Parallel, "bogus", DoStuff(testObservable, testObserver));
            s.Add(RequestProcessType.Parallel, "bogus", DoStuff(testObservable, testObserver));
            s.Add(RequestProcessType.Serial, "bogus", DoStuff(testObservable, testObserver));
            s.Add(RequestProcessType.Parallel, "bogus", DoStuff(testObservable, testObserver));
            s.Add(RequestProcessType.Parallel, "bogus", DoStuff(testObservable, testObserver));
            s.Add(RequestProcessType.Serial, "bogus", DoStuff(testObservable, testObserver));
            s.Add(RequestProcessType.Parallel, "bogus", DoStuff(testObservable, testObserver));
            s.Add(RequestProcessType.Parallel, "bogus", DoStuff(testObservable, testObserver));
            s.Add(RequestProcessType.Parallel, "bogus", DoStuff(testObservable, testObserver));

            testScheduler.Start();

            testObservable.Subscriptions.Count.Should().Be(11);
            testObserver.Messages
            .Where(z => z.Value.Kind != NotificationKind.OnCompleted).Should()
            .ContainInOrder(
                OnNext(Subscribed, Unit.Default),
                OnNext(Subscribed * 2, Unit.Default),
                OnNext(Subscribed * 3, Unit.Default),
                OnNext(Subscribed * 3, Unit.Default),
                OnNext(Subscribed * 3, Unit.Default)
                );
        }