public void WillSaveOnce() {
            var latch = new CountDownLatch(2);
            var storage = new InMemoryFileStorage();
            var dict = new PersistedDictionary("test.json", storage, new DefaultJsonSerializer(), 50);
            dict.Saved += (sender, args) => latch.Signal();
            for (int i = 0; i < 10; i++)
                dict["test" + i] = i.ToString();
            Assert.Equal(10, dict.Count);
            bool success = latch.Wait(250);
            Assert.False(success, "Dictionary was saved multiple times.");
            Assert.Equal(1, latch.Remaining);
            Assert.True(storage.Exists("test.json"));

            dict["test"] = "test";
            Assert.Equal(11, dict.Count);
            success = latch.Wait(250);
            Assert.True(success, "Failed to save dictionary.");
            Assert.True(storage.Exists("test.json"));
        }
        public void CanTolerateSubscriberFailure() {
            var latch = new CountDownLatch(2);
            var messageBus = new InMemoryMessageBus();
            messageBus.Subscribe<SimpleMessageA>(msg => {
                throw new ApplicationException();
            });
            messageBus.Subscribe<SimpleMessageA>(msg => {
                Assert.Equal("Hello", msg.Data);
                latch.Signal();
            });
            messageBus.Subscribe<SimpleMessageA>(msg => {
                Assert.Equal("Hello", msg.Data);
                latch.Signal();
            });
            messageBus.PublishAsync(new SimpleMessageA {
                Data = "Hello"
            });

            bool success = latch.Wait(900);
            Assert.True(success, "Failed to receive all messages.");
        }
        public void CanSendMessageToMultipleSubscribers() {
            var latch = new CountDownLatch(3);
            var messageBus = new InMemoryMessageBus();
            messageBus.Subscribe<SimpleMessageA>(msg => {
                Assert.Equal("Hello", msg.Data);
                latch.Signal();
            });
            messageBus.Subscribe<SimpleMessageA>(msg => {
                Assert.Equal("Hello", msg.Data);
                latch.Signal();
            });
            messageBus.Subscribe<SimpleMessageA>(msg => {
                Assert.Equal("Hello", msg.Data);
                latch.Signal();
            });
            messageBus.PublishAsync(new SimpleMessageA {
                Data = "Hello"
            });

            bool success = latch.Wait(100);
            Assert.True(success, "Failed to receive all messages.");
        }
        public void CanSendMessageToMultipleSubscribers() {
            if (_messageBus == null)
                return;

            var latch = new CountDownLatch(3);
            _messageBus.Subscribe<SimpleMessageA>(msg => {
                Assert.Equal("Hello", msg.Data);
                latch.Signal();
            });
            _messageBus.Subscribe<SimpleMessageA>(msg => {
                Assert.Equal("Hello", msg.Data);
                latch.Signal();
            });
            _messageBus.Subscribe<SimpleMessageA>(msg => {
                Assert.Equal("Hello", msg.Data);
                latch.Signal();
            });
            _messageBus.Publish(new SimpleMessageA {
                Data = "Hello"
            });

            bool success = latch.Wait(15000);
            Assert.True(success, "Failed to receive all messages.");
        }
        public void WillReceiveDerivedMessageTypes() {
            var latch = new CountDownLatch(2);
            var messageBus = new InMemoryMessageBus();
            messageBus.Subscribe<ISimpleMessage>(msg => {
                Assert.Equal("Hello", msg.Data);
                latch.Signal();
            });
            messageBus.PublishAsync(new SimpleMessageA {
                Data = "Hello"
            });
            messageBus.PublishAsync(new SimpleMessageB {
                Data = "Hello"
            });
            messageBus.PublishAsync(new SimpleMessageC {
                Data = "Hello"
            });

            bool success = latch.Wait(100);
            Assert.True(success, "Failed to receive all messages.");
        }
        public void CanSubscribeToAllMessageTypes() {
            var latch = new CountDownLatch(3);
            var messageBus = new InMemoryMessageBus();
            messageBus.Subscribe<object>(msg => {
                latch.Signal();
            });
            messageBus.PublishAsync(new SimpleMessageA {
                Data = "Hello"
            });
            messageBus.PublishAsync(new SimpleMessageB {
                Data = "Hello"
            });
            messageBus.PublishAsync(new SimpleMessageC {
                Data = "Hello"
            });

            bool success = latch.Wait(100);
            Assert.True(success, "Failed to receive all messages.");
        }
        public void CanSubscribeToAllMessageTypes() {
            if (_messageBus == null)
                return;

            var latch = new CountDownLatch(3);
            _messageBus.Subscribe<object>(msg => {
                latch.Signal();
            });
            _messageBus.Publish(new SimpleMessageA {
                Data = "Hello"
            });
            _messageBus.Publish(new SimpleMessageB {
                Data = "Hello"
            });
            _messageBus.Publish(new SimpleMessageC {
                Data = "Hello"
            });

            bool success = latch.Wait(5000);
            Assert.True(success, "Failed to receive all messages.");
        }
        public void WillReceiveDerivedMessageTypes() {
            if (_messageBus == null)
                return;

            var latch = new CountDownLatch(2);
            _messageBus.Subscribe<ISimpleMessage>(msg => {
                Assert.Equal("Hello", msg.Data);
                latch.Signal();
            });
            _messageBus.Publish(new SimpleMessageA {
                Data = "Hello"
            });
            _messageBus.Publish(new SimpleMessageB {
                Data = "Hello"
            });
            _messageBus.Publish(new SimpleMessageC {
                Data = "Hello"
            });

            bool success = latch.Wait(5000);
            Assert.True(success, "Failed to receive all messages.");
        }
        private void DoWork(QueueEntry<SimpleWorkItem> w, CountDownLatch latch, ref int abandonCount, ref int errorCount) {
            Assert.Equal("Hello", w.Value.Data);
            latch.Signal();

            // randomly complete, abandon or blowup.
            if (RandomHelper.GetBool()) {
                Console.WriteLine("Completing: {0}", w.Value.Id);
                w.CompleteAsync().Wait();
            } else if (RandomHelper.GetBool()) {
                Console.WriteLine("Abandoning: {0}", w.Value.Id);
                w.AbandonAsync();
                Interlocked.Increment(ref abandonCount);
            } else {
                Console.WriteLine("Erroring: {0}", w.Value.Id);
                Interlocked.Increment(ref errorCount);
                throw new ApplicationException();
            }
        }
        public void CanHaveMultipleWorkers() {
            const int workItemCount = 50;
            var latch = new CountDownLatch(workItemCount);
            int errorCount = 0;
            int abandonCount = 0;
            var queue = new InMemoryQueue<SimpleWorkItem>(retries: 1, workItemTimeoutMilliseconds: 50);
            Task.Factory.StartNew(() => queue.StartWorking(w => DoWork(w, latch, ref abandonCount, ref errorCount)));
            Task.Factory.StartNew(() => queue.StartWorking(w => DoWork(w, latch, ref abandonCount, ref errorCount)));
            Task.Factory.StartNew(() => queue.StartWorking(w => DoWork(w, latch, ref abandonCount, ref errorCount)));

            Parallel.For(0, workItemCount, i => queue.EnqueueAsync(new SimpleWorkItem {
                Data = "Hello",
                Id = i
            }));

            bool success = latch.Wait(1000);
            Assert.True(success, "Failed to receive all work items.");
            Task.Delay(50).Wait();
            Assert.Equal(workItemCount, queue.Completed + queue.DeadletterCount);
            Assert.Equal(errorCount, queue.WorkerErrors);
            Assert.Equal(abandonCount + errorCount, queue.Abandoned);
        }
        public void CanHaveMultipleWorkers() {
            if (_queue == null)
                return;

            const int workItemCount = 50;
            var latch = new CountDownLatch(workItemCount);
            int errorCount = 0;
            int abandonCount = 0;
            Task.Factory.StartNew(() => _queue.StartWorking(w => DoWork(w, latch, ref abandonCount, ref errorCount)));
            Task.Factory.StartNew(() => _queue.StartWorking(w => DoWork(w, latch, ref abandonCount, ref errorCount)));
            Task.Factory.StartNew(() => _queue.StartWorking(w => DoWork(w, latch, ref abandonCount, ref errorCount)));

            Parallel.For(0, workItemCount, i => _queue.EnqueueAsync(new SimpleWorkItem {
                Data = "Hello",
                Id = i
            }));

            Assert.Equal(workItemCount, _queue.Enqueued);
            bool success = latch.Wait(60000);
            Task.Delay(5000).Wait();
            Assert.True(success, "Failed to receive all work items.");
            Assert.Equal(workItemCount, _queue.Completed + _queue.DeadletterCount);
            Assert.Equal(errorCount, _queue.WorkerErrors);
            Assert.Equal(abandonCount + errorCount, _queue.Abandoned);
        }