public void TestBrokenListener()
        {
            MessageLog log = new MessageLog();
            ActionPerformer performer1 = new ActionPerformer(log);
            ActionPerformer performer2 = new ActionPerformer(log);
            EventManager eventManager = new EventManager();

            const string eventType = "ET";

            eventManager.Start();

            eventManager.Watch(eventType, performer1.BrokenAction);
            eventManager.Watch(eventType, performer2.BrokenAction);

            log.Log("Event fired.");
            eventManager.Notify(eventType);

            Thread.Sleep(200);

            Assert.That(log.GetLog(), Is.EqualTo(new string[]
            {
                "Event fired.",
                "BrokenAction invoked.",
                "BrokenAction invoked."
            }));

            log.Log("Event fired.");
            eventManager.Notify(eventType);

            Thread.Sleep(200);

            Assert.That(log.GetLog(), Is.EqualTo(new string[]
            {
                "Event fired.",
                "BrokenAction invoked.",
                "BrokenAction invoked.",
                "Event fired.",
                "BrokenAction invoked.",
                "BrokenAction invoked."
            }));
        }
        public void TestNoBlock()
        {
            BlockingThreadPool threadPool = new BlockingThreadPool(2, 2);
            MessageLog log = new MessageLog();

            for (int i = 0; i < TestIterationsCount; i++)
            {
                log.Clear();

                Assert.That(threadPool.Execute(() =>
                {
                    log.Log("task 1: started"); // T = 0
                    Thread.Sleep(200);
                    log.Log("task 1: finished"); // T = 200
                }, 100), Is.True);

                Thread.Sleep(50); // T = 50

                Assert.That(threadPool.Execute(() =>
                {
                    log.Log("task 2: started"); // T = 50
                    Thread.Sleep(200);
                    log.Log("task 2: finished"); // T = 250
                }, 100), Is.True);

                Thread.Sleep(50);
                log.Log("main: wait started"); // T = 100
                Thread.Sleep(200);
                log.Log("main: wait finished"); // T = 300

                Assert.That(log.GetLog(), Is.EqualTo(new string[]
                {
                    "task 1: started",
                    "task 2: started",
                    "main: wait started",
                    "task 1: finished",
                    "task 2: finished",
                    "main: wait finished"
                }));
            }

            Assert.That(threadPool.Stop(1000), Is.True);
        }
        public void TestBrokenDispose()
        {
            MessageLog log = new MessageLog();

            NodeServiceCollection services = new NodeServiceCollection();

            TestNodeServiceFactory service1 = new TestNodeServiceFactory(log, TimeSpan.Zero, true);
            TestNodeServiceFactory service2 = new TestNodeServiceFactory(log, TimeSpan.Zero, true);

            services.AddFactory(service1);
            services.AddFactory(service2);

            CancellationTokenSource cts = new CancellationTokenSource();

            services.CreateServices(null, cts.Token);

            services.Start();

            //Sleep to avoid arbitrary order of start and stop events.
            Thread.Sleep(50);

            cts.Cancel();

            Assert.True(services.Join(TimeSpan.FromMilliseconds(100)));

            services.DisposeServices();

            Assert.That(log.GetLog(), Is.EqualTo(new string[]
            {
                "Service created.",
                "Service created.",
                "Service started.",
                "Service started.",
                "Service stopped.",
                "Service stopped.",
                "Service disposal failed.",
                "Service disposal failed."
            }));
        }
        public void TestSlowCancellation()
        {
            MessageLog log = new MessageLog();

            NodeServiceCollection services = new NodeServiceCollection();

            TestNodeServiceFactory service1 = new TestNodeServiceFactory(log, TimeSpan.FromMilliseconds(200), false);
            TestNodeServiceFactory service2 = new TestNodeServiceFactory(log, TimeSpan.FromMilliseconds(200), false);

            services.AddFactory(service1);
            services.AddFactory(service2);

            CancellationTokenSource cts = new CancellationTokenSource();

            services.CreateServices(null, cts.Token);

            services.Start();

            cts.Cancel();

            Stopwatch sw = Stopwatch.StartNew();

            Assert.False(services.Join(TimeSpan.FromMilliseconds(150)));

            Assert.That(sw.Elapsed, Is.GreaterThanOrEqualTo(TimeSpan.FromMilliseconds(130)));
            Assert.That(sw.Elapsed, Is.LessThanOrEqualTo(TimeSpan.FromMilliseconds(170)));

            Assert.That(log.GetLog(), Is.EqualTo(new string[]
            {
                "Service created.",
                "Service created.",
                "Service started.",
                "Service started."
            }));

            Assert.True(services.Join(TimeSpan.FromMilliseconds(100)));

            Assert.That(sw.Elapsed, Is.GreaterThanOrEqualTo(TimeSpan.FromMilliseconds(180)));
            Assert.That(sw.Elapsed, Is.LessThanOrEqualTo(TimeSpan.FromMilliseconds(220)));

            services.DisposeServices();

            Assert.That(log.GetLog(), Is.EqualTo(new string[]
            {
                "Service created.",
                "Service created.",
                "Service started.",
                "Service started.",
                "Service stopped.",
                "Service stopped.",
                "Service disposed.",
                "Service disposed."
            }));
        }
        public void TestSlowListener()
        {
            MessageLog log = new MessageLog();
            ActionPerformer performer = new ActionPerformer(log);
            EventManager eventManager = new EventManager();

            const string eventType = "ET";

            eventManager.Start();

            eventManager.Watch(eventType, performer.SlowAction);

            log.Log("Event fired.");
            eventManager.Notify(eventType);

            Thread.Sleep(150);

            const int eventsCount = 10000;

            Stopwatch sw = Stopwatch.StartNew();
            log.Log($"Starting to fire a series of {eventsCount} events.");
            for (int i = 0; i < eventsCount; i++)
            {
                eventManager.Notify(eventType);
            }
            log.Log($"Finished to fire a series of {eventsCount} events.");
            Assert.That(sw.ElapsedMilliseconds, Is.LessThan(100));

            Thread.Sleep(1000);

            eventManager.Stop();

            Assert.That(log.GetLog(), Is.EqualTo(new string[]
            {
                "Event fired.",
                "SlowAction started.",
                $"Starting to fire a series of {eventsCount} events.",
                $"Finished to fire a series of {eventsCount} events.",
                "SlowAction completed.",
                "SlowAction started.",
                "SlowAction completed."
            }));
        }
        public void TestSmoke()
        {
            MessageLog log = new MessageLog();
            ActionPerformer performer = new ActionPerformer(log);
            EventManager eventManager = new EventManager();

            const string eventType1 = "ET1";
            const string eventType2 = "ET2";

            eventManager.Watch(eventType1, performer.Action1);
            eventManager.Watch(eventType2, performer.Action2);

            eventManager.Start();

            log.Log($"Fired {eventType1} event.");
            eventManager.Notify(eventType1);

            Thread.Sleep(200);

            log.Log($"Fired {eventType2} event.");
            eventManager.Notify(eventType2);

            Thread.Sleep(200);

            Assert.That(log.GetLog(), Is.EqualTo(new string[]
            {
                $"Fired {eventType1} event.",
                $"Action1 invoked.",
                $"Fired {eventType2} event.",
                $"Action2 invoked."
            }));

            // testing that attempt to remove non-existent event listeners does not affect existing watchers
            eventManager.Unwatch(eventType1, performer.Action2);
            eventManager.Unwatch(eventType2, performer.Action1);

            log.Clear();
            log.Log("Attempted to remove non-existent event listeners.");

            log.Log($"Fired {eventType1} event.");
            eventManager.Notify(eventType1);

            Thread.Sleep(200);

            log.Log($"Fired {eventType2} event.");
            eventManager.Notify(eventType2);

            Thread.Sleep(200);

            Assert.That(log.GetLog(), Is.EqualTo(new string[]
            {
                $"Attempted to remove non-existent event listeners.",
                $"Fired {eventType1} event.",
                $"Action1 invoked.",
                $"Fired {eventType2} event.",
                $"Action2 invoked."
            }));

            eventManager.Unwatch(eventType1, performer.Action1);

            log.Clear();
            log.Log($"Removed event-listener for {eventType1}.");

            log.Log($"Fired {eventType1} event.");
            eventManager.Notify(eventType1);

            log.Log($"Fired {eventType2} event.");
            eventManager.Notify(eventType2);

            Thread.Sleep(200);

            Assert.That(log.GetLog(), Is.EqualTo(new string[]
            {
                $"Removed event-listener for {eventType1}.",
                $"Fired {eventType1} event.",
                $"Fired {eventType2} event.",
                $"Action2 invoked."
            }));
        }
        public void TestStopBusy()
        {
            MessageLog log = new MessageLog();

            for (int i = 0; i < TestIterationsCount; i++)
            {
                BlockingThreadPool threadPool = new BlockingThreadPool(3, 3);
                log.Clear();

                threadPool.Execute(() =>
                {
                    log.Log("task 1: started"); // T = 0
                    try
                    {
                        // finally block is required to ignore Thread.Interrupt and Thread.Abort
                    }
                    finally
                    {
                        Thread.Sleep(200);
                    }
                    log.Log("task 1: finished"); // T = 200
                }, 100);

                Thread.Sleep(50); // T = 50

                threadPool.Execute(() =>
                {
                    log.Log("task 2: started"); // T = 50
                    try
                    {
                        // finally block is required to ignore Thread.Interrupt and Thread.Abort
                    }
                    finally
                    {
                        Thread.Sleep(250);
                    }
                    log.Log("task 2: finished"); // T = 300
                }, 100);

                Thread.Sleep(50); // T = 50

                threadPool.Execute(() =>
                {
                    log.Log("task 3: started"); // T = 100
                    log.Log($"task 4 queued: {threadPool.Execute(() => { }, 300)}"); // T = 150
                    log.Log("task 3: finished"); // T = 150
                }, 100);

                Thread.Sleep(50); // T = 150

                Stopwatch sw = Stopwatch.StartNew();
                Assert.That(threadPool.Stop(100), Is.False); // T = 250
                Assert.That(sw.ElapsedMilliseconds, Is.GreaterThan(75).And.LessThan(125));

                sw.Restart();
                Assert.That(threadPool.Execute(() => { }, 100), Is.False);
                Assert.That(sw.ElapsedMilliseconds, Is.LessThan(25));

                sw.Restart();
                Assert.That(threadPool.Stop(100), Is.True); // T = 300
                Assert.That(sw.ElapsedMilliseconds, Is.GreaterThan(25).And.LessThan(75));

                //check that Stop does not fail on a stopped pool
                sw.Restart();
                Assert.That(threadPool.Stop(100), Is.True); // T = 300
                Assert.That(sw.ElapsedMilliseconds, Is.LessThan(25));

                Assert.That(log.GetLog(), Is.EqualTo(new string[]
                {
                    "task 1: started",
                    "task 2: started",
                    "task 3: started",
                    "task 4 queued: False",
                    "task 3: finished",
                    "task 1: finished",
                    "task 2: finished"
                }));
            }
        }