public void Constructor_AllParametersAreSet_ObjectIsInstantiated()
        {
            // Arrange
            var systemInformationSender = new Mock<ISystemInformationSender>();
            var workQueue = new Mock<IMessageQueue<SystemInformation>>();
            var errorQueue = new Mock<IMessageQueue<SystemInformation>>();

            // Act
            var messageQueueWorker = new SystemInformationMessageQueueWorker(systemInformationSender.Object, workQueue.Object, errorQueue.Object);

            // Assert
            Assert.IsNotNull(messageQueueWorker);
        }
        public void Constructor_InitialStatusIsStopped()
        {
            // Arrange
            var systemInformationSender = new Mock<ISystemInformationSender>();
            var workQueue = new Mock<IMessageQueue<SystemInformation>>();
            workQueue.Setup(w => w.Dequeue()).Returns(new SystemInformationQueueItem(new SystemInformation()));

            var errorQueue = new Mock<IMessageQueue<SystemInformation>>();

            // Act
            using (var messageQueueWorker = new SystemInformationMessageQueueWorker(systemInformationSender.Object, workQueue.Object, errorQueue.Object))
            {
                // Assert
                Assert.AreEqual(ServiceStatus.Stopped, messageQueueWorker.GetStatus());
            }
        }
        public void WorkerIsStarted_QueueIsEmpty_WorkerKeepsPollingForItemsInQueue()
        {
            // Arrange
            int maxRuntime = SystemInformationMessageQueueWorker.WorkIntervalInMilliseconds * 5;

            var workQueue = new Mock<IMessageQueue<SystemInformation>>();
            workQueue.Setup(q => q.IsEmpty()).Returns(true);

            SystemInformationQueueItem queueItem = null;
            workQueue.Setup(q => q.Dequeue()).Returns(queueItem);

            var errorQueue = new Mock<IMessageQueue<SystemInformation>>();
            var systemInformationSender = new Mock<ISystemInformationSender>();

            using (var messageQueueWorker = new SystemInformationMessageQueueWorker(systemInformationSender.Object, workQueue.Object, errorQueue.Object))
            {
                // Act
                var worker = new Task(messageQueueWorker.Start);
                worker.Start();
                Task.WaitAll(new[] { worker }, maxRuntime);
                messageQueueWorker.Stop();

                // Assert
                workQueue.Verify(q => q.Dequeue(), Times.Between(4, 5, Range.Inclusive));
            }
        }
        public void WorkerIsStarted_QueueIsEmpty_SendIsNotCalled()
        {
            // Arrange
            int maxRuntime = SystemInformationMessageQueueWorker.WorkIntervalInMilliseconds * 2;

            var workQueue = new Mock<IMessageQueue<SystemInformation>>();
            workQueue.Setup(q => q.IsEmpty()).Returns(true);

            SystemInformationQueueItem queueItem = null;
            workQueue.Setup(q => q.Dequeue()).Returns(queueItem);

            var errorQueue = new Mock<IMessageQueue<SystemInformation>>();
            var systemInformationSender = new Mock<ISystemInformationSender>();

            var messageQueueWorker = new SystemInformationMessageQueueWorker(systemInformationSender.Object, workQueue.Object, errorQueue.Object);

            // Act
            var worker = new Task(messageQueueWorker.Start);
            worker.Start();
            Task.WaitAll(new[] { worker }, maxRuntime);
            messageQueueWorker.Stop();

            // Assert
            systemInformationSender.Verify(s => s.Send(It.IsAny<SystemInformation>()), Times.Never());
        }
        public void Stop_StatusIsChangedToStopped()
        {
            // Arrange
            var systemInformationSender = new Mock<ISystemInformationSender>();
            var workQueue = new Mock<IMessageQueue<SystemInformation>>();
            workQueue.Setup(w => w.Dequeue()).Returns(new SystemInformationQueueItem(new SystemInformation()));

            var errorQueue = new Mock<IMessageQueue<SystemInformation>>();
            using (var messageQueueWorker = new SystemInformationMessageQueueWorker(systemInformationSender.Object, workQueue.Object, errorQueue.Object))
            {
                var workerTaks = new Task(messageQueueWorker.Start);
                workerTaks.Start();
                Thread.Sleep(500);

                // Act
                messageQueueWorker.Stop();

                Thread.Sleep(500);

                // Assert
                Assert.AreEqual(ServiceStatus.Stopped, messageQueueWorker.GetStatus());
            }
        }
        public void Stop_ServiceIsNotStartet_StatusIsNotChanged()
        {
            // Arrange
            var systemInformationSender = new Mock<ISystemInformationSender>();
            var workQueue = new Mock<IMessageQueue<SystemInformation>>();
            workQueue.Setup(w => w.Dequeue()).Returns(new SystemInformationQueueItem(new SystemInformation()));

            var errorQueue = new Mock<IMessageQueue<SystemInformation>>();
            using (var messageQueueWorker = new SystemInformationMessageQueueWorker(systemInformationSender.Object, workQueue.Object, errorQueue.Object))
            {
                var statusBefore = messageQueueWorker.GetStatus();

                // Act
                messageQueueWorker.Stop();
                var statusAfter = messageQueueWorker.GetStatus();

                // Assert
                Assert.AreEqual(statusBefore, statusAfter);
            }
        }
        public void Stop_EndsTheWorkerLoop()
        {
            // Arrange
            int timeToWaitBeforeStop = SystemInformationMessageQueueWorker.WorkIntervalInMilliseconds * 5;

            var workQueue = new Mock<IMessageQueue<SystemInformation>>();
            workQueue.Setup(q => q.IsEmpty()).Returns(true);

            SystemInformationQueueItem queueItem = null;
            workQueue.Setup(q => q.Dequeue()).Returns(queueItem);

            var errorQueue = new Mock<IMessageQueue<SystemInformation>>();
            var systemInformationSender = new Mock<ISystemInformationSender>();

            using (var messageQueueWorker = new SystemInformationMessageQueueWorker(systemInformationSender.Object, workQueue.Object, errorQueue.Object))
            {
                // Act
                var stopwatch = new Stopwatch();
                stopwatch.Start();

                var worker = new Task(messageQueueWorker.Start);
                worker.Start();

                Thread.Sleep(timeToWaitBeforeStop);
                messageQueueWorker.Stop();

                Task.WaitAll(new[] { worker }, timeToWaitBeforeStop);

                stopwatch.Stop();

                // Assert
                Assert.LessOrEqual(stopwatch.ElapsedMilliseconds - timeToWaitBeforeStop, SystemInformationMessageQueueWorker.WorkIntervalInMilliseconds + 100);
            }
        }
        public void Start_RunFor3Intervals_SendIsCalledAtLeastTwoTimes()
        {
            // Arrange
            int durationInMilliseconds = SystemInformationMessageQueueWorker.WorkIntervalInMilliseconds * 3;

            var systemInformationSender = new Mock<ISystemInformationSender>();
            var workQueue = new Mock<IMessageQueue<SystemInformation>>();
            workQueue.Setup(w => w.Dequeue()).Returns(new SystemInformationQueueItem(new SystemInformation()));

            var errorQueue = new Mock<IMessageQueue<SystemInformation>>();
            using (var messageQueueWorker = new SystemInformationMessageQueueWorker(systemInformationSender.Object, workQueue.Object, errorQueue.Object))
            {
                // Act
                var workerTaks = new Task(messageQueueWorker.Start);
                workerTaks.Start();

                Task.WaitAll(new[] { workerTaks }, durationInMilliseconds);

                // Assert
                systemInformationSender.Verify(s => s.Send(It.IsAny<SystemInformation>()), Times.AtLeast(2));
            }
        }
        public void GetStatus_ServiceIsStarted_ResultIsRunning()
        {
            // Arrange
            var systemInformationSender = new Mock<ISystemInformationSender>();
            var workQueue = new Mock<IMessageQueue<SystemInformation>>();
            workQueue.Setup(w => w.Dequeue()).Returns(new SystemInformationQueueItem(new SystemInformation()));

            var errorQueue = new Mock<IMessageQueue<SystemInformation>>();
            using (var messageQueueWorker = new SystemInformationMessageQueueWorker(systemInformationSender.Object, workQueue.Object, errorQueue.Object))
            {
                var workerTaks = new Task(messageQueueWorker.Start);
                workerTaks.Start();

                Thread.Sleep(500);

                // Act
                var status = messageQueueWorker.GetStatus();

                // Assert
                Assert.AreEqual(ServiceStatus.Running, status);
            }
        }
        public void QueueIsFilled_SendCausesFatalException_WorkerStops()
        {
            // Arrange
            int maxRuntime = SystemInformationMessageQueueWorker.WorkIntervalInMilliseconds * 2;

            var workQueue = new Mock<IMessageQueue<SystemInformation>>();
            workQueue.Setup(q => q.IsEmpty()).Returns(false);
            workQueue.Setup(q => q.Dequeue()).Returns(
                () => new SystemInformationQueueItem(new SystemInformation { MachineName = Environment.MachineName, Timestamp = DateTime.UtcNow }));

            var errorQueue = new Mock<IMessageQueue<SystemInformation>>();
            var systemInformationSender = new Mock<ISystemInformationSender>();
            systemInformationSender.Setup(s => s.Send(It.IsAny<SystemInformation>())).Throws(new FatalSystemInformationSenderException("Some fatal exception."));

            using (var messageQueueWorker = new SystemInformationMessageQueueWorker(systemInformationSender.Object, workQueue.Object, errorQueue.Object))
            {
                // Act
                var stopwatch = new Stopwatch();
                stopwatch.Start();

                var worker = new Task(messageQueueWorker.Start);
                worker.Start();
                Task.WaitAll(new[] { worker }, maxRuntime);

                stopwatch.Stop();

                // Assert
                Assert.LessOrEqual(stopwatch.ElapsedMilliseconds, maxRuntime);
            }
        }
        public void QueueIsFilled_SendCausesFatalException_AllItemsInQueueAreMovedToTheFailedRequestQueue()
        {
            // Arrange
            var workQueue = new Mock<IMessageQueue<SystemInformation>>();
            workQueue.Setup(q => q.IsEmpty()).Returns(false);
            workQueue.Setup(q => q.Dequeue()).Returns(
                () => new SystemInformationQueueItem(new SystemInformation { MachineName = Environment.MachineName, Timestamp = DateTime.UtcNow }));

            var items = new[]
                {
                    new SystemInformationQueueItem(new SystemInformation { MachineName = Environment.MachineName + "1", Timestamp = DateTime.UtcNow }),
                    new SystemInformationQueueItem(new SystemInformation { MachineName = Environment.MachineName + "2", Timestamp = DateTime.UtcNow }),
                    new SystemInformationQueueItem(new SystemInformation { MachineName = Environment.MachineName + "3", Timestamp = DateTime.UtcNow })
                };

            workQueue.Setup(q => q.PurgeAllItems()).Returns(items);

            var errorQueue = new Mock<IMessageQueue<SystemInformation>>();
            var systemInformationSender = new Mock<ISystemInformationSender>();
            systemInformationSender.Setup(s => s.Send(It.IsAny<SystemInformation>())).Throws(new FatalSystemInformationSenderException("Some fatal exception."));

            using (var messageQueueWorker = new SystemInformationMessageQueueWorker(systemInformationSender.Object, workQueue.Object, errorQueue.Object))
            {
                // Act
                messageQueueWorker.Start();

                // Assert
                errorQueue.Verify(q => q.Enqueue(items), Times.Once());
            }
        }
        public void QueueIsFilled_SendCausesExceptionWhichJustifiesARetry_RetryCountHasNotBeenExceeded_ItemIsAddedToQueue()
        {
            // Arrange
            int maxRuntime = SystemInformationMessageQueueWorker.WorkIntervalInMilliseconds * 2;

            var workQueue = new Mock<IMessageQueue<SystemInformation>>();
            workQueue.Setup(q => q.IsEmpty()).Returns(false);

            bool itemHasBeenAccessed = false;
            var systemInfo = new SystemInformation { MachineName = Environment.MachineName, Timestamp = DateTime.UtcNow };
            var queueItem = new SystemInformationQueueItem(systemInfo);
            workQueue.Setup(q => q.Dequeue()).Returns(() =>
                {
                    if (!itemHasBeenAccessed)
                    {
                        itemHasBeenAccessed = true;
                        return queueItem;
                    }

                    return null;
                });

            var errorQueue = new Mock<IMessageQueue<SystemInformation>>();
            var systemInformationSender = new Mock<ISystemInformationSender>();
            systemInformationSender.Setup(s => s.Send(systemInfo)).Throws(
                new SendSystemInformationFailedException("Some minor exception which justifies a retry", null));

            using (var messageQueueWorker = new SystemInformationMessageQueueWorker(systemInformationSender.Object, workQueue.Object, errorQueue.Object))
            {
                // Act
                var worker = new Task(messageQueueWorker.Start);
                worker.Start();
                Task.WaitAll(new[] { worker }, maxRuntime);

                // Assert
                workQueue.Verify(q => q.Enqueue(It.IsAny<SystemInformationQueueItem>()), Times.Once());
            }
        }
        public void QueueIsFilled_EveryItemInQueueIsSent()
        {
            // Arrange
            int maxRuntime = SystemInformationMessageQueueWorker.WorkIntervalInMilliseconds * 5;

            var workQueue = new Mock<IMessageQueue<SystemInformation>>();
            workQueue.Setup(q => q.IsEmpty()).Returns(false);

            int maxCount = 3;
            int itemIndex = 1;
            workQueue.Setup(q => q.Dequeue()).Returns(() =>
                {
                    if (itemIndex <= maxCount)
                    {
                        itemIndex++;
                        return new SystemInformationQueueItem(new SystemInformation { MachineName = itemIndex.ToString(), Timestamp = DateTime.UtcNow });
                    }

                    return null;
                });

            var errorQueue = new Mock<IMessageQueue<SystemInformation>>();
            var systemInformationSender = new Mock<ISystemInformationSender>();

            using (var messageQueueWorker = new SystemInformationMessageQueueWorker(systemInformationSender.Object, workQueue.Object, errorQueue.Object))
            {
                // Act
                var worker = new Task(messageQueueWorker.Start);
                worker.Start();
                Task.WaitAll(new[] { worker }, maxRuntime);

                // Assert
                systemInformationSender.Verify(s => s.Send(It.IsAny<SystemInformation>()), Times.Exactly(maxCount));
            }
        }
        public void Pause_RunFor6Intervals_PauseIsCalledAfter3Intervals_SendIsCalledAtMostThreeTimes()
        {
            // Arrange
            int durationInMilliseconds = SystemInformationMessageQueueWorker.WorkIntervalInMilliseconds * 6;

            var systemInformationSender = new Mock<ISystemInformationSender>();
            var workQueue = new Mock<IMessageQueue<SystemInformation>>();
            workQueue.Setup(w => w.Dequeue()).Returns(new SystemInformationQueueItem(new SystemInformation()));

            var errorQueue = new Mock<IMessageQueue<SystemInformation>>();
            using (var messageQueueWorker = new SystemInformationMessageQueueWorker(systemInformationSender.Object, workQueue.Object, errorQueue.Object))
            {
                // Act
                var workerTaks = new Task(messageQueueWorker.Start);
                workerTaks.Start();

                Thread.Sleep(durationInMilliseconds / 2);

                messageQueueWorker.Pause();

                // Assert
                systemInformationSender.Verify(s => s.Send(It.IsAny<SystemInformation>()), Times.AtMost(3));
            }
        }
        public void Resume_ServiceIsRunning_StatusIsNotChanged()
        {
            // Arrange
            var systemInformationSender = new Mock<ISystemInformationSender>();
            var workQueue = new Mock<IMessageQueue<SystemInformation>>();
            workQueue.Setup(w => w.Dequeue()).Returns(new SystemInformationQueueItem(new SystemInformation()));

            var errorQueue = new Mock<IMessageQueue<SystemInformation>>();
            using (var messageQueueWorker = new SystemInformationMessageQueueWorker(systemInformationSender.Object, workQueue.Object, errorQueue.Object))
            {
                var workerTaks = new Task(messageQueueWorker.Start);
                workerTaks.Start();

                Thread.Sleep(500);

                var statusBeforeResume = messageQueueWorker.GetStatus();

                // Act
                messageQueueWorker.Resume();
                Thread.Sleep(500);

                var statusAfterResume = messageQueueWorker.GetStatus();

                // Assert
                Assert.AreEqual(statusBeforeResume, statusAfterResume);
            }
        }
        public void RunFor10Seconds_SendFailsForAllItems_DispatcherStopsOnlyIfTheQueueIsEmptyAndAllRetryAttempsHaveFailed()
        {
            // Arrange
            int runtimeInMilliseconds = 10 * 1000;
            int itemsReturnedFromSystemInformationProvider = 0;
            int attemptsToSend = 0;

            // prepare system information provider
            var provider = new Mock<ISystemInformationProvider>();
            provider.Setup(p => p.GetSystemInfo()).Returns(() =>
                {
                    itemsReturnedFromSystemInformationProvider++;
                    return new SystemInformation { MachineName = Environment.MachineName, Timestamp = DateTime.UtcNow };
                });

            // prepare sender
            var sender = new Mock<ISystemInformationSender>();
            sender.Setup(s => s.Send(It.IsAny<SystemInformation>())).Callback(() => { attemptsToSend++; }).Throws(new SendSystemInformationFailedException("Send failed.", null));

            IMessageQueue<SystemInformation> workQueue = new SystemInformationMessageQueue();
            IMessageQueue<SystemInformation> errorQueue = new SystemInformationMessageQueue();
            IMessageQueueProvider<SystemInformation> messageQueueProvider = new SystemInformationMessageQueueProvider(workQueue, errorQueue);

            IMessageQueueFeeder messageQueueFeeder = new SystemInformationMessageQueueFeeder(provider.Object, workQueue);
            IMessageQueueWorker messageQueueWorker = new SystemInformationMessageQueueWorker(sender.Object, workQueue, errorQueue);

            var agentCoordinationService = new Mock<IAgentCoordinationService>();
            var agentCoordinationServiceFactory = new Mock<IAgentCoordinationServiceFactory>();
            agentCoordinationServiceFactory.Setup(f => f.GetAgentCoordinationService(It.IsAny<Action>(), It.IsAny<Action>())).Returns(
                agentCoordinationService.Object);

            var messageQueueFeederFactory = new Mock<IMessageQueueFeederFactory>();
            messageQueueFeederFactory.Setup(f => f.GetMessageQueueFeeder()).Returns(messageQueueFeeder);

            var messageQueueWorkerFactory = new Mock<IMessageQueueWorkerFactory>();
            messageQueueWorkerFactory.Setup(f => f.GetMessageQueueWorker()).Returns(messageQueueWorker);

            IMessageQueuePersistence<SystemInformation> messageQueuePersistence =
                new JSONSystemInformationMessageQueuePersistence(this.jsonMessageQueuePersistenceConfigurationProvider, this.encodingProvider);

            var systemInformationDispatchingService = new SystemInformationDispatchingService(
                agentCoordinationServiceFactory.Object,
                messageQueueFeederFactory.Object,
                messageQueueWorkerFactory.Object,
                messageQueueProvider,
                messageQueuePersistence);

            // Act
            var stopwatch = new Stopwatch();
            stopwatch.Start();

            var dispatcher = new Task(systemInformationDispatchingService.Start);
            dispatcher.Start();

            Thread.Sleep(runtimeInMilliseconds);
            systemInformationDispatchingService.Stop();

            Task.WaitAll(new[] { dispatcher });

            stopwatch.Stop();

            // Assert
            int queueSize = workQueue.GetSize();
            Console.WriteLine(
                "After a runtime of {0} milliseconds the dispatcher has been stopped with {1} items in queue. It took {2} milliseconds until the queue worker stopped sending out all queue items (Attempts To Send: {3}).",
                runtimeInMilliseconds,
                itemsReturnedFromSystemInformationProvider,
                stopwatch.ElapsedMilliseconds,
                attemptsToSend);

            Assert.AreEqual(0, queueSize);
        }
        public void Dispose_ServiceIsStopped()
        {
            // Arrange
            var maxWaitTime = SystemInformationMessageQueueWorker.WorkIntervalInMilliseconds * 3;

            var systemInformationSender = new Mock<ISystemInformationSender>();
            var workQueue = new Mock<IMessageQueue<SystemInformation>>();
            workQueue.Setup(w => w.IsEmpty()).Returns(true);

            var errorQueue = new Mock<IMessageQueue<SystemInformation>>();
            var messageQueueWorker = new SystemInformationMessageQueueWorker(systemInformationSender.Object, workQueue.Object, errorQueue.Object);
            var workerTaks = new Task(messageQueueWorker.Start);
            workerTaks.Start();

            Thread.Sleep(500);

            // Act
            messageQueueWorker.Dispose();
            Task.WaitAll(new[] { workerTaks }, maxWaitTime);

            // Assert
            Assert.AreEqual(ServiceStatus.Stopped, messageQueueWorker.GetStatus());
        }