public void Can_return_message_after_queue_has_been_disposed()
        {
            // Arrange
            var item1 = new DispatchItem(new XUri("http://a"), new DispatcherEvent(new XDoc("msg"), new XUri("http://channl"), new XUri("http://resource")), "a");

            var dispatchResult = new Result<bool>();
            var dispatchQueue = new MemoryPubSubDispatchQueue("queue", TaskTimerFactory.Current, 1.Minutes(), (item) => dispatchResult);
            dispatchQueue.Enqueue(item1);

            // Act
            dispatchQueue.Dispose();
            dispatchResult.Return(true);

            // Assert

            // should not have thrown on the return, that is all
        }
        public void Can_dispatch_items()
        {
            // Arrange
            var dispatched = new List<DispatchItem>();
            Func<DispatchItem, Result<bool>> handler = (i) => {
                dispatched.Add(i);
                var result = new Result<bool>();
                result.Return(true);
                return result;
            };
            var dispatchQueue = new MemoryPubSubDispatchQueue("queue", TaskTimerFactory.Current, 1.Seconds(), handler);
            var item1 = new DispatchItem(new XUri("http://a"), new DispatcherEvent(new XDoc("msg"), new XUri("http://channl"), new XUri("http://resource")), "a");
            var item2 = new DispatchItem(new XUri("http://b"), new DispatcherEvent(new XDoc("msg"), new XUri("http://channl"), new XUri("http://resource")), "b");

            // Act
            dispatchQueue.Enqueue(item1);
            dispatchQueue.Enqueue(item2);

            // Assert
            Assert.IsTrue(Wait.For(() => dispatched.Count == 2, 5.Seconds()), "items were not dispatched in time");
            Assert.AreEqual(item1.Location, dispatched[0].Location, "wrong item location for first dispatched item");
            Assert.AreEqual(item2.Location, dispatched[1].Location, "wrong item location for second dispatched item");
        }
 public void RegisterOrUpdate(PubSubSubscriptionSet set)
 {
     lock(_repository) {
         if(_repository.ContainsKey(set.Location)) {
             return;
         }
         var queue = new MemoryPubSubDispatchQueue(set.Location, _taskTimerFactory, _retryTime, _handler);
         _repository[set.Location] = queue;
     }
 }
        public void Disposed_queue_throws_on_access()
        {
            // Arrange
            var dispatchQueue = new MemoryPubSubDispatchQueue("queue", TaskTimerFactory.Current, 1.Minutes(), i => new Result<bool>().WithReturn(true));

            // Act
            dispatchQueue.Dispose();

            // Assert
            try {
                var item = new DispatchItem(new XUri("http://a"), new DispatcherEvent(new XDoc("msg"), new XUri("http://channl"), new XUri("http://resource")), "a");
                dispatchQueue.Enqueue(item);
                Assert.Fail("Enqueue didn't throw");
            } catch(ObjectDisposedException) {
            } catch(Exception e) {
                Assert.Fail(string.Format("Enqueue threw unexpected exception: {0}", e));
            }
        }
        public void Failed_dispatch_retries_after_sleep()
        {
            // Arrange
            var item1 = new DispatchItem(new XUri("http://a"), new DispatcherEvent(new XDoc("msg"), new XUri("http://channl"), new XUri("http://resource")), "a");
            var item2 = new DispatchItem(new XUri("http://b"), new DispatcherEvent(new XDoc("msg"), new XUri("http://channl"), new XUri("http://resource")), "b");

            var dispatched = new List<Tuplet<DateTime, DispatchItem>>();
            var dispatchCounter = 0;
            Func<DispatchItem, Result<bool>> handler = (i) => {
                dispatchCounter++;
                dispatched.Add(new Tuplet<DateTime, DispatchItem>(DateTime.UtcNow, i));
                var result = new Result<bool>();
                result.Return(dispatchCounter > 2);
                return result;
            };
            var dispatchQueue = new MemoryPubSubDispatchQueue("queue", TaskTimerFactory.Current, 1.Seconds(), handler);

            // Act
            dispatchQueue.Enqueue(item1);
            dispatchQueue.Enqueue(item2);

            // Assert
            Assert.IsTrue(Wait.For(() => dispatched.Count >= 4, 10.Seconds()), "items were not dispatched in time");
            Assert.AreEqual(item1.Location, dispatched[0].Item2.Location, "wrong item location for first failure item");
            var dispatchTiming1 = dispatched[1].Item1 - dispatched[0].Item1;
            Assert.IsTrue(dispatchTiming1 >= 1.Seconds(), "expected re-try in more than 1 second, was " + dispatchTiming1);
            Assert.AreEqual(item1.Location, dispatched[1].Item2.Location, "wrong item location for second failure item");
            var dispatchTiming2 = dispatched[2].Item1 - dispatched[1].Item1;
            Assert.IsTrue(dispatchTiming2 >= 1.Seconds(), "expected re-try in more than 1 second, was " + dispatchTiming2);
            Assert.AreEqual(item1.Location, dispatched[2].Item2.Location, "wrong item location for first success item");
            var dispatchTiming3 = dispatched[3].Item1 - dispatched[2].Item1;
            Assert.IsTrue(dispatchTiming3 < 1.Seconds(), "expected successful dispatch in less than 1 second, was " + dispatchTiming3);
            Assert.AreEqual(item2.Location, dispatched[3].Item2.Location, "wrong item location for second success item");
        }
        public void Dispose_is_idempotent()
        {
            // Arrange
            var dispatchQueue = new MemoryPubSubDispatchQueue("queue", TaskTimerFactory.Current, 1.Minutes(), i => new Result<bool>().WithReturn(true));

            // Act
            dispatchQueue.Dispose();

            // Assert
            dispatchQueue.Dispose();
        }