[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(); }