diff --git a/projects/RabbitMQ.Client/client/impl/RecordedBinding.cs b/projects/RabbitMQ.Client/client/impl/RecordedBinding.cs index 966dea271c..f61567a827 100644 --- a/projects/RabbitMQ.Client/client/impl/RecordedBinding.cs +++ b/projects/RabbitMQ.Client/client/impl/RecordedBinding.cs @@ -85,7 +85,15 @@ public override string ToString() public RecordedBinding WithArguments(IDictionary value) { - Arguments = value; + if (value is null) + { + Arguments = null; + } + else + { + Arguments = new Dictionary(value); + } + return this; } diff --git a/projects/RabbitMQ.Client/client/impl/RecordedConsumer.cs b/projects/RabbitMQ.Client/client/impl/RecordedConsumer.cs index 1470293a97..e9ec141f09 100644 --- a/projects/RabbitMQ.Client/client/impl/RecordedConsumer.cs +++ b/projects/RabbitMQ.Client/client/impl/RecordedConsumer.cs @@ -97,7 +97,15 @@ public string Recover(IModel channelToUse) public RecordedConsumer WithArguments(IDictionary value) { - Arguments = value; + if (value is null) + { + Arguments = null; + } + else + { + Arguments = new Dictionary(value); + } + return this; } diff --git a/projects/RabbitMQ.Client/client/impl/RecordedExchange.cs b/projects/RabbitMQ.Client/client/impl/RecordedExchange.cs index f88616bab5..999fdb8107 100644 --- a/projects/RabbitMQ.Client/client/impl/RecordedExchange.cs +++ b/projects/RabbitMQ.Client/client/impl/RecordedExchange.cs @@ -57,7 +57,15 @@ public override string ToString() public RecordedExchange WithArguments(IDictionary value) { - Arguments = value; + if (value is null) + { + Arguments = null; + } + else + { + Arguments = new Dictionary(value); + } + return this; } diff --git a/projects/RabbitMQ.Client/client/impl/RecordedQueue.cs b/projects/RabbitMQ.Client/client/impl/RecordedQueue.cs index 003548bb4c..1462d5ebaa 100644 --- a/projects/RabbitMQ.Client/client/impl/RecordedQueue.cs +++ b/projects/RabbitMQ.Client/client/impl/RecordedQueue.cs @@ -66,7 +66,15 @@ protected string NameToUseForRecovery public RecordedQueue WithArguments(IDictionary value) { - Arguments = value; + if (value is null) + { + Arguments = null; + } + else + { + Arguments = new Dictionary(value); + } + return this; } diff --git a/projects/Unit/TestConnectionRecovery.cs b/projects/Unit/TestConnectionRecovery.cs index 09c8401c57..3420055565 100644 --- a/projects/Unit/TestConnectionRecovery.cs +++ b/projects/Unit/TestConnectionRecovery.cs @@ -744,10 +744,17 @@ public void TestRecoveringConsumerHandlerOnConnection() [Test] public void TestRecoveringConsumerHandlerOnConnection_EventArgumentsArePassedDown() { - var myArgs = new Dictionary { { "first-argument", "some-value" } }; + const string key = "first-argument"; + const string value = "some-value"; + + IDictionary arguments = new Dictionary + { + { key, value } + }; + string q = Model.QueueDeclare(GenerateQueueName(), false, false, false, null).QueueName; var cons = new EventingBasicConsumer(Model); - string expectedCTag = Model.BasicConsume(cons, q, arguments: myArgs); + string expectedCTag = Model.BasicConsume(cons, q, arguments: arguments); bool ctagMatches = false; bool consumerArgumentMatches = false; @@ -757,14 +764,15 @@ public void TestRecoveringConsumerHandlerOnConnection_EventArgumentsArePassedDow // passed to a CallbackExceptionHandler, instead of failing the test. Instead, we have to do this trick // and assert in the test function. ctagMatches = args.ConsumerTag == expectedCTag; - consumerArgumentMatches = (string)args.ConsumerArguments["first-argument"] == "some-value"; - args.ConsumerArguments["first-argument"] = "event-handler-set-this-value"; + consumerArgumentMatches = (string)args.ConsumerArguments[key] == value; }; CloseAndWaitForRecovery(); Assert.That(ctagMatches, Is.True, "expected consumer tag to match"); Assert.That(consumerArgumentMatches, Is.True, "expected consumer arguments to match"); - Assert.That(myArgs, Does.ContainKey("first-argument").WithValue("event-handler-set-this-value")); + Assert.That(arguments.ContainsKey(key), Is.True); + string actualVal = (string)arguments[key]; + Assert.That(actualVal, Is.EqualTo(value)); } [Test] @@ -1687,6 +1695,51 @@ void MessageReceived(object sender, BasicDeliverEventArgs e) } } + [Test] + public void TestQueueRecoveryWithDlxArgument_RabbitMQUsers_hk5pJ4cKF0c() + { + string tdiWaitExchangeName = GenerateExchangeName(); + string tdiRetryExchangeName = GenerateExchangeName(); + string testRetryQueueName = GenerateQueueName(); + string testQueueName = GenerateQueueName(); + + Model.ExchangeDeclare(exchange: tdiWaitExchangeName, + type: ExchangeType.Topic, durable: true, autoDelete: false, arguments: null); + Model.ExchangeDeclare(exchange: tdiRetryExchangeName, + type: ExchangeType.Topic, durable: true, autoDelete: false, arguments: null); + + var arguments = new Dictionary + { + { "x-dead-letter-exchange", "tdi.retry.exchange" }, + { "x-dead-letter-routing-key", "QueueTest" } + }; + + Model.QueueDeclare(testRetryQueueName, durable: false, exclusive: false, autoDelete: false, arguments); + + arguments["x-dead-letter-exchange"] = "tdi.wait.exchange"; + arguments["x-dead-letter-routing-key"] = "QueueTest"; + + Model.QueueDeclare(testQueueName, durable: false, exclusive: false, autoDelete: false, arguments); + + arguments.Remove("x-dead-letter-exchange"); + arguments.Remove("x-dead-letter-routing-key"); + + Model.QueueBind(testRetryQueueName, tdiWaitExchangeName, testQueueName); + + Model.QueueBind(testQueueName, tdiRetryExchangeName, testQueueName); + + var consumerAsync = new EventingBasicConsumer(Model); + Model.BasicConsume(queue: testQueueName, autoAck: false, consumer: consumerAsync); + + CloseAndWaitForRecovery(); + + QueueDeclareOk q0 = Model.QueueDeclarePassive(testRetryQueueName); + Assert.AreEqual(testRetryQueueName, q0.QueueName); + + QueueDeclareOk q1 = Model.QueueDeclarePassive(testQueueName); + Assert.AreEqual(testQueueName, q1.QueueName); + } + internal bool SendAndConsumeMessage(string queue, string exchange, string routingKey) { using (var ch = Conn.CreateModel())