Ejemplo n.º 1
0
        [Test] // AMQP-249
        public void DontHangConsumerThread()
        {
            var mockConnectionFactory = new Mock <ConnectionFactory>();
            var mockConnection        = new Mock <IConnection>();
            var mockChannel           = new Mock <IModel>();

            mockConnectionFactory.Setup(m => m.CreateConnection()).Returns(mockConnection.Object);
            mockConnection.Setup(m => m.IsOpen).Returns(true);
            mockConnection.Setup(m => m.CreateModel()).Returns(mockChannel.Object);
            mockChannel.Setup(m => m.QueueDeclare()).Returns(new QueueDeclareOk("foo", 0, 0));
            mockChannel.Setup(m => m.CreateBasicProperties()).Returns(() => new BasicProperties());

            var consumer = new AtomicReference <DefaultBasicConsumer>();

            mockChannel.Setup(m => m.BasicConsume(It.IsAny <string>(), It.IsAny <bool>(), It.IsAny <string>(), It.IsAny <bool>(), It.IsAny <bool>(), It.IsAny <IDictionary>(), It.IsAny <IBasicConsumer>())).Callback
            <string, bool, string, bool, bool, IDictionary, IBasicConsumer>(
                (a1, a2, a3, a4, a5, a6, a7) => consumer.LazySet((DefaultBasicConsumer)a7));

            var template = new RabbitTemplate(new SingleConnectionFactory(mockConnectionFactory.Object));

            template.ReplyTimeout = 1;
            var input = new Message(Encoding.UTF8.GetBytes("Hello, world!"), new MessageProperties());
            var doSendAndReceiveWithTemporaryMethod = typeof(RabbitTemplate).GetMethod("DoSendAndReceiveWithTemporary", BindingFlags.NonPublic | BindingFlags.Instance);

            doSendAndReceiveWithTemporaryMethod.Invoke(template, new object[] { "foo", "bar", input });
            var envelope = new BasicGetResult(1, false, "foo", "bar", 0, new BasicProperties(), null);

            // used to hang here because of the SynchronousQueue and DoSendAndReceive() already exited
            consumer.Value.HandleBasicDeliver("foo", envelope.DeliveryTag, envelope.Redelivered, envelope.Exchange, envelope.RoutingKey, new BasicProperties(), new byte[0]);
        }
        public void TestMessageListener()
        {
            var mockConnectionFactory = new Mock <ConnectionFactory>();
            var mockConnection        = new Mock <IConnection>();
            var onlyChannel           = new Mock <IModel>();

            onlyChannel.Setup(m => m.IsOpen).Returns(true);
            onlyChannel.Setup(m => m.CreateBasicProperties()).Returns(() => new BasicProperties());

            var cachingConnectionFactory = new CachingConnectionFactory(mockConnectionFactory.Object);

            mockConnectionFactory.Setup(m => m.CreateConnection()).Returns(mockConnection.Object);
            mockConnection.Setup(m => m.IsOpen).Returns(true);

            var tooManyChannels = new AtomicReference <Exception>();
            var done            = false;

            mockConnection.Setup(m => m.CreateModel()).Returns(
                () =>
            {
                if (!done)
                {
                    done = true;
                    return(onlyChannel.Object);
                }

                tooManyChannels.LazySet(new Exception("More than one channel requested"));
                var channel = new Mock <IModel>();
                channel.Setup(m => m.IsOpen).Returns(true);
                return(channel.Object);
            });

            var consumer = new BlockingCollection <IBasicConsumer>(1);

            onlyChannel.Setup(m => m.BasicConsume(It.IsAny <string>(), It.IsAny <bool>(), It.IsAny <IBasicConsumer>())).Callback <string, bool, IBasicConsumer>(
                (a1, a2, a3) => consumer.Add(a3));

            var commitLatch = new CountdownEvent(1);

            onlyChannel.Setup(m => m.TxCommit()).Callback(
                () =>
            {
                if (commitLatch.CurrentCount > 0)
                {
                    commitLatch.Signal();
                }
            });

            var latch     = new CountdownEvent(1);
            var container = new SimpleMessageListenerContainer(cachingConnectionFactory);

            container.MessageListener = new Action <Message>(
                message =>
            {
                var rabbitTemplate = new RabbitTemplate(cachingConnectionFactory);
                rabbitTemplate.ChannelTransacted = true;

                // should use same channel as container
                rabbitTemplate.ConvertAndSend("foo", "bar", "baz");
                if (latch.CurrentCount > 0)
                {
                    latch.Signal();
                }
            });

            container.QueueNames         = new[] { "queue" };
            container.ChannelTransacted  = true;
            container.ShutdownTimeout    = 100;
            container.TransactionManager = DummyTxManager.Instance();
            container.AfterPropertiesSet();
            container.Start();

            IBasicConsumer currentConsumer;

            consumer.TryTake(out currentConsumer, this.timeout);
            Assert.IsNotNull(currentConsumer, "Timed out getting consumer.");
            currentConsumer.HandleBasicDeliver("qux", 1, false, "foo", "bar", new BasicProperties(), new byte[] { 0 });

            Assert.IsTrue(latch.Wait(new TimeSpan(0, 0, 10)));

            var e = tooManyChannels.Value;

            if (e != null)
            {
                throw e;
            }

            mockConnection.Verify(m => m.CreateModel(), Times.Once());
            Assert.True(commitLatch.Wait(new TimeSpan(0, 0, 10)));
            onlyChannel.Verify(m => m.TxCommit(), Times.Once());
            onlyChannel.Verify(m => m.BasicPublish(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <bool>(), It.IsAny <bool>(), It.IsAny <IBasicProperties>(), It.IsAny <byte[]>()), Times.Once());

            // verify close() was never called on the channel
            var cachedChannelsTransactionalField = typeof(CachingConnectionFactory).GetField("cachedChannelsTransactional", BindingFlags.NonPublic | BindingFlags.Instance);
            var channels = (LinkedList <IChannelProxy>)cachedChannelsTransactionalField.GetValue(cachingConnectionFactory);

            Assert.AreEqual(0, channels.Count);

            container.Stop();
            container.Dispose();
            container = null;
        }
        [Test] // AMQP-249
        public void DontHangConsumerThread()
        {
            var mockConnectionFactory = new Mock<ConnectionFactory>();
            var mockConnection = new Mock<IConnection>();
            var mockChannel = new Mock<IModel>();

            mockConnectionFactory.Setup(m => m.CreateConnection()).Returns(mockConnection.Object);
            mockConnection.Setup(m => m.IsOpen).Returns(true);
            mockConnection.Setup(m => m.CreateModel()).Returns(mockChannel.Object);
            mockChannel.Setup(m => m.QueueDeclare()).Returns(new QueueDeclareOk("foo", 0, 0));
            mockChannel.Setup(m => m.CreateBasicProperties()).Returns(() => new BasicProperties());

            var consumer = new AtomicReference<DefaultBasicConsumer>();
            mockChannel.Setup(m => m.BasicConsume(It.IsAny<string>(), It.IsAny<bool>(), It.IsAny<string>(), It.IsAny<bool>(), It.IsAny<bool>(), It.IsAny<IDictionary>(), It.IsAny<IBasicConsumer>())).Callback
                <string, bool, string, bool, bool, IDictionary, IBasicConsumer>(
                    (a1, a2, a3, a4, a5, a6, a7) => consumer.LazySet((DefaultBasicConsumer)a7));

            var template = new RabbitTemplate(new SingleConnectionFactory(mockConnectionFactory.Object));
            template.ReplyTimeout = 1;
            var input = new Message(Encoding.UTF8.GetBytes("Hello, world!"), new MessageProperties());
            var doSendAndReceiveWithTemporaryMethod = typeof(RabbitTemplate).GetMethod("DoSendAndReceiveWithTemporary", BindingFlags.NonPublic | BindingFlags.Instance);
            doSendAndReceiveWithTemporaryMethod.Invoke(template, new object[] { "foo", "bar", input });
            var envelope = new BasicGetResult(1, false, "foo", "bar", 0, new BasicProperties(), null);

            // used to hang here because of the SynchronousQueue and DoSendAndReceive() already exited
            consumer.Value.HandleBasicDeliver("foo", envelope.DeliveryTag, envelope.Redelivered, envelope.Exchange, envelope.RoutingKey, new BasicProperties(), new byte[0]);
        }
        public void TestStartupWithNonDurable()
        {
            var queue = new Queue("test.queue", false, false, false);
            this.context.ObjectFactory.RegisterSingleton("foo", queue);
            this.rabbitAdmin.AfterPropertiesSet();

            var connectionHolder = new AtomicReference<IConnection>();

            var rabbitTemplate = new RabbitTemplate(this.connectionFactory);

            // Force RabbitAdmin to initialize the queue
            var exists = rabbitTemplate.Execute<bool>(delegate(IModel channel)
            {
                var result = channel.QueueDeclarePassive(queue.Name);
                connectionHolder.LazySet(((CachedModel)channel).Connection);
                return result != null;
            });
            Assert.True(exists, "Expected Queue to exist");

            Assert.True(this.QueueExists(connectionHolder.Value, queue));

            // simulate broker going down and coming back up...
            this.rabbitAdmin.DeleteQueue(queue.Name);
            this.connectionFactory.Dispose();
            Assert.False(this.QueueExists(null, queue));

            // Broker auto-deleted queue, but it is re-created by the connection listener
            exists = rabbitTemplate.Execute<bool>(delegate(IModel channel)
            {
                var result = channel.QueueDeclarePassive(queue.Name);
                connectionHolder.LazySet(((CachedModel)channel).Connection);
                return result != null;
            });
            Assert.True(exists, "Expected Queue to exist");

            Assert.True(this.QueueExists(connectionHolder.Value, queue));
            Assert.True(this.rabbitAdmin.DeleteQueue(queue.Name));
            Assert.False(this.QueueExists(null, queue));
        }
        public void TestChannelAwareMessageListenerDontExpose()
        {
            var mockConnectionFactory = new Mock<ConnectionFactory>();
            var mockConnection = new Mock<IConnection>();
            var firstChannel = new Mock<IModel>();
            firstChannel.Setup(m => m.IsOpen).Returns(true);
            firstChannel.Setup(m => m.CreateBasicProperties()).Returns(() => new BasicProperties());

            var secondChannel = new Mock<IModel>();
            secondChannel.Setup(m => m.IsOpen).Returns(true);
            secondChannel.Setup(m => m.CreateBasicProperties()).Returns(() => new BasicProperties());

            var singleConnectionFactory = new SingleConnectionFactory(mockConnectionFactory.Object);

            mockConnectionFactory.Setup(m => m.CreateConnection()).Returns(mockConnection.Object);
            mockConnection.Setup(m => m.IsOpen).Returns(true);

            var tooManyChannels = new BlockingCollection<Exception>(1);
            var done = false;
            mockConnection.Setup(m => m.CreateModel()).Returns(
                () =>
                {
                    if (!done)
                    {
                        done = true;
                        return firstChannel.Object;
                    }

                    return secondChannel.Object;
                });

            var consumer = new BlockingCollection<IBasicConsumer>(1);

            firstChannel.Setup(m => m.BasicConsume(It.IsAny<string>(), It.IsAny<bool>(), It.IsAny<IBasicConsumer>())).Callback<string, bool, IBasicConsumer>(
                (a1, a2, a3) => consumer.Add(a3));

            var commitLatch = new CountdownEvent(1);
            firstChannel.Setup(m => m.TxCommit()).Callback(() => commitLatch.Signal());

            var latch = new CountdownEvent(1);
            var exposed = new AtomicReference<IModel>();
            var container = new SimpleMessageListenerContainer(singleConnectionFactory);
            var mockListener = new Mock<IChannelAwareMessageListener>();
            mockListener.Setup(m => m.OnMessage(It.IsAny<Message>(), It.IsAny<IModel>())).Callback<Message, IModel>(
                (message, channel) =>
                {
                    exposed.LazySet(channel);
                    var rabbitTemplate = new RabbitTemplate(singleConnectionFactory);
                    rabbitTemplate.ChannelTransacted = true;

                    // should use same channel as container
                    rabbitTemplate.ConvertAndSend("foo", "bar", "baz");
                    latch.Signal();
                });
            container.MessageListener = mockListener.Object;

            container.QueueNames = new[] { "queue" };
            container.ChannelTransacted = true;
            container.ExposeListenerChannel = false;
            container.ShutdownTimeout = 100;
            container.AfterPropertiesSet();
            container.Start();

            IBasicConsumer currentConsumer;
            consumer.TryTake(out currentConsumer, timeout);
            Assert.IsNotNull(currentConsumer, "Timed out getting consumer.");
            currentConsumer.HandleBasicDeliver("qux", 1, false, "foo", "bar", new BasicProperties(), new byte[] { 0 });

            Assert.IsTrue(latch.Wait(new TimeSpan(0, 0, 10)));

            var e = tooManyChannels.Count;
            if (e > 0)
            {
                throw tooManyChannels.Take();
            }

            // once for listener, once for exposed + 0 for template (used bound)
            mockConnection.Verify(m => m.CreateModel(), Times.Exactly(2));
            Assert.IsTrue(commitLatch.Wait(new TimeSpan(0, 0, 10)));
            firstChannel.Verify(m => m.TxCommit(), Times.Once());
            secondChannel.Verify(m => m.TxCommit(), Times.Once());
            secondChannel.Verify(m => m.BasicPublish(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<bool>(), It.IsAny<bool>(), It.IsAny<IBasicProperties>(), It.IsAny<byte[]>()), Times.Once());

            Assert.AreSame(secondChannel.Object, exposed.Value);

            firstChannel.Verify(m => m.Close(), Times.Never());
            secondChannel.Verify(m => m.Close(), Times.Once());
            container.Stop();
        }
        public void TestMessageListener()
        {
            var mockConnectionFactory = new Mock<ConnectionFactory>();
            var mockConnection = new Mock<IConnection>();
            var onlyChannel = new Mock<IModel>();
            onlyChannel.Setup(m => m.IsOpen).Returns(true);
            onlyChannel.Setup(m => m.CreateBasicProperties()).Returns(() => new BasicProperties());

            var cachingConnectionFactory = new CachingConnectionFactory(mockConnectionFactory.Object);

            mockConnectionFactory.Setup(m => m.CreateConnection()).Returns(mockConnection.Object);
            mockConnection.Setup(m => m.IsOpen).Returns(true);

            var tooManyChannels = new AtomicReference<Exception>();
            var done = false;
            mockConnection.Setup(m => m.CreateModel()).Returns(
                () =>
                {
                    if (!done)
                    {
                        done = true;
                        return onlyChannel.Object;
                    }

                    tooManyChannels.LazySet(new Exception("More than one channel requested"));
                    var channel = new Mock<IModel>();
                    channel.Setup(m => m.IsOpen).Returns(true);
                    return channel.Object;
                });

            var consumer = new BlockingCollection<IBasicConsumer>(1);

            onlyChannel.Setup(m => m.BasicConsume(It.IsAny<string>(), It.IsAny<bool>(), It.IsAny<IBasicConsumer>())).Callback<string, bool, IBasicConsumer>(
                (a1, a2, a3) => consumer.Add(a3));

            var commitLatch = new CountdownEvent(1);
            onlyChannel.Setup(m => m.TxCommit()).Callback(
                () =>
                {
                    if (commitLatch.CurrentCount > 0)
                    {
                        commitLatch.Signal();
                    }
                });

            var latch = new CountdownEvent(1);
            var container = new SimpleMessageListenerContainer(cachingConnectionFactory);
            container.MessageListener = new Action<Message>(
                message =>
                {
                    var rabbitTemplate = new RabbitTemplate(cachingConnectionFactory);
                    rabbitTemplate.ChannelTransacted = true;

                    // should use same channel as container
                    rabbitTemplate.ConvertAndSend("foo", "bar", "baz");
                    if (latch.CurrentCount > 0)
                    {
                        latch.Signal();
                    }
                });

            container.QueueNames = new[] { "queue" };
            container.ChannelTransacted = true;
            container.ShutdownTimeout = 100;
            container.TransactionManager = DummyTxManager.Instance();
            container.AfterPropertiesSet();
            container.Start();

            IBasicConsumer currentConsumer;
            consumer.TryTake(out currentConsumer, this.timeout);
            Assert.IsNotNull(currentConsumer, "Timed out getting consumer.");
            currentConsumer.HandleBasicDeliver("qux", 1, false, "foo", "bar", new BasicProperties(), new byte[] { 0 });

            Assert.IsTrue(latch.Wait(new TimeSpan(0, 0, 10)));

            var e = tooManyChannels.Value;
            if (e != null)
            {
                throw e;
            }

            mockConnection.Verify(m => m.CreateModel(), Times.Once());
            Assert.True(commitLatch.Wait(new TimeSpan(0, 0, 10)));
            onlyChannel.Verify(m => m.TxCommit(), Times.Once());
            onlyChannel.Verify(m => m.BasicPublish(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<bool>(), It.IsAny<bool>(), It.IsAny<IBasicProperties>(), It.IsAny<byte[]>()), Times.Once());

            // verify close() was never called on the channel
            var cachedChannelsTransactionalField = typeof(CachingConnectionFactory).GetField("cachedChannelsTransactional", BindingFlags.NonPublic | BindingFlags.Instance);
            var channels = (LinkedList<IChannelProxy>)cachedChannelsTransactionalField.GetValue(cachingConnectionFactory);
            Assert.AreEqual(0, channels.Count);

            container.Stop();
            container.Dispose();
            container = null;
        }
        public void TestChannelAwareMessageListenerDontExpose()
        {
            var mockConnectionFactory = new Mock <ConnectionFactory>();
            var mockConnection        = new Mock <IConnection>();
            var firstChannel          = new Mock <IModel>();

            firstChannel.Setup(m => m.IsOpen).Returns(true);
            firstChannel.Setup(m => m.CreateBasicProperties()).Returns(() => new BasicProperties());

            var secondChannel = new Mock <IModel>();

            secondChannel.Setup(m => m.IsOpen).Returns(true);
            secondChannel.Setup(m => m.CreateBasicProperties()).Returns(() => new BasicProperties());

            var singleConnectionFactory = new SingleConnectionFactory(mockConnectionFactory.Object);

            mockConnectionFactory.Setup(m => m.CreateConnection()).Returns(mockConnection.Object);
            mockConnection.Setup(m => m.IsOpen).Returns(true);

            var tooManyChannels = new BlockingCollection <Exception>(1);
            var done            = false;

            mockConnection.Setup(m => m.CreateModel()).Returns(
                () =>
            {
                if (!done)
                {
                    done = true;
                    return(firstChannel.Object);
                }

                return(secondChannel.Object);
            });

            var consumer = new BlockingCollection <IBasicConsumer>(1);

            firstChannel.Setup(m => m.BasicConsume(It.IsAny <string>(), It.IsAny <bool>(), It.IsAny <IBasicConsumer>())).Callback <string, bool, IBasicConsumer>(
                (a1, a2, a3) => consumer.Add(a3));

            var commitLatch = new CountdownEvent(1);

            firstChannel.Setup(m => m.TxCommit()).Callback(() => commitLatch.Signal());

            var latch        = new CountdownEvent(1);
            var exposed      = new AtomicReference <IModel>();
            var container    = new SimpleMessageListenerContainer(singleConnectionFactory);
            var mockListener = new Mock <IChannelAwareMessageListener>();

            mockListener.Setup(m => m.OnMessage(It.IsAny <Message>(), It.IsAny <IModel>())).Callback <Message, IModel>(
                (message, channel) =>
            {
                exposed.LazySet(channel);
                var rabbitTemplate = new RabbitTemplate(singleConnectionFactory);
                rabbitTemplate.ChannelTransacted = true;

                // should use same channel as container
                rabbitTemplate.ConvertAndSend("foo", "bar", "baz");
                latch.Signal();
            });
            container.MessageListener = mockListener.Object;

            container.QueueNames            = new[] { "queue" };
            container.ChannelTransacted     = true;
            container.ExposeListenerChannel = false;
            container.ShutdownTimeout       = 100;
            container.AfterPropertiesSet();
            container.Start();

            IBasicConsumer currentConsumer;

            consumer.TryTake(out currentConsumer, timeout);
            Assert.IsNotNull(currentConsumer, "Timed out getting consumer.");
            currentConsumer.HandleBasicDeliver("qux", 1, false, "foo", "bar", new BasicProperties(), new byte[] { 0 });

            Assert.IsTrue(latch.Wait(new TimeSpan(0, 0, 10)));

            var e = tooManyChannels.Count;

            if (e > 0)
            {
                throw tooManyChannels.Take();
            }

            // once for listener, once for exposed + 0 for template (used bound)
            mockConnection.Verify(m => m.CreateModel(), Times.Exactly(2));
            Assert.IsTrue(commitLatch.Wait(new TimeSpan(0, 0, 10)));
            firstChannel.Verify(m => m.TxCommit(), Times.Once());
            secondChannel.Verify(m => m.TxCommit(), Times.Once());
            secondChannel.Verify(m => m.BasicPublish(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <bool>(), It.IsAny <bool>(), It.IsAny <IBasicProperties>(), It.IsAny <byte[]>()), Times.Once());

            Assert.AreSame(secondChannel.Object, exposed.Value);

            firstChannel.Verify(m => m.Close(), Times.Never());
            secondChannel.Verify(m => m.Close(), Times.Once());
            container.Stop();
        }