Skip to content

Commit 89d472d

Browse files
authored
Merge pull request #1616 from rabbitmq/rabbitmq-users-hk5pJ4cKF0c
Ensure that arguments passed to recorded entities are copied.
2 parents 6673bd5 + 870a1f4 commit 89d472d

File tree

6 files changed

+140
-9
lines changed

6 files changed

+140
-9
lines changed

projects/RabbitMQ.Client/client/impl/RecordedBinding.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,15 @@ public RecordedBinding(bool isQueueBinding, string destination, string source, s
5757
_source = source;
5858
_routingKey = routingKey;
5959
_arguments = arguments;
60+
61+
if (arguments is null)
62+
{
63+
_arguments = null;
64+
}
65+
else
66+
{
67+
_arguments = new Dictionary<string, object>(arguments);
68+
}
6069
}
6170

6271
public RecordedBinding(string destination, in RecordedBinding old)

projects/RabbitMQ.Client/client/impl/RecordedConsumer.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,15 @@ public RecordedConsumer(AutorecoveringChannel channel, IBasicConsumer consumer,
8484

8585
_autoAck = autoAck;
8686
_exclusive = exclusive;
87-
_arguments = arguments;
87+
88+
if (arguments is null)
89+
{
90+
_arguments = null;
91+
}
92+
else
93+
{
94+
_arguments = new Dictionary<string, object>(arguments);
95+
}
8896
}
8997

9098
public AutorecoveringChannel Channel => _channel;

projects/RabbitMQ.Client/client/impl/RecordedExchange.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,15 @@ public RecordedExchange(string name, string type, bool durable, bool autoDelete,
5656
_type = type;
5757
_durable = durable;
5858
_autoDelete = autoDelete;
59-
_arguments = arguments;
59+
60+
if (arguments is null)
61+
{
62+
_arguments = null;
63+
}
64+
else
65+
{
66+
_arguments = new Dictionary<string, object>(arguments);
67+
}
6068
}
6169

6270
public Task RecoverAsync(IChannel channel, CancellationToken cancellationToken)

projects/RabbitMQ.Client/client/impl/RecordedQueue.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,15 @@ public RecordedQueue(string name, bool isServerNamed, bool durable, bool exclusi
5959
_durable = durable;
6060
_exclusive = exclusive;
6161
_autoDelete = autoDelete;
62-
_arguments = arguments;
62+
63+
if (arguments is null)
64+
{
65+
_arguments = null;
66+
}
67+
else
68+
{
69+
_arguments = new Dictionary<string, object>(arguments);
70+
}
6371
}
6472

6573
public RecordedQueue(string newName, in RecordedQueue old)

projects/Test/Integration/ConnectionRecovery/EventHandlerRecovery/Connection/TestRecoveringConsumerEventHandlers.cs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,17 @@ public async Task TestRecoveringConsumerEventHandlers_Called(int iterations)
6969
[Fact]
7070
public async Task TestRecoveringConsumerEventHandler_EventArgumentsArePassedDown()
7171
{
72-
var myArgs = new Dictionary<string, object> { { "first-argument", "some-value" } };
72+
const string key = "first-argument";
73+
const string value = "some-value";
74+
75+
IDictionary<string, object> arguments = new Dictionary<string, object>
76+
{
77+
{ key, value }
78+
};
79+
7380
RabbitMQ.Client.QueueDeclareOk q = await _channel.QueueDeclareAsync(GenerateQueueName(), false, false, false);
7481
var cons = new EventingBasicConsumer(_channel);
75-
string expectedCTag = await _channel.BasicConsumeAsync(cons, q, arguments: myArgs);
82+
string expectedCTag = await _channel.BasicConsumeAsync(cons, q, arguments: arguments);
7683

7784
bool ctagMatches = false;
7885
bool consumerArgumentMatches = false;
@@ -82,15 +89,14 @@ public async Task TestRecoveringConsumerEventHandler_EventArgumentsArePassedDown
8289
// passed to a CallbackExceptionHandler, instead of failing the test. Instead, we have to do this trick
8390
// and assert in the test function.
8491
ctagMatches = args.ConsumerTag == expectedCTag;
85-
consumerArgumentMatches = (string)args.ConsumerArguments["first-argument"] == "some-value";
86-
args.ConsumerArguments["first-argument"] = "event-handler-set-this-value";
92+
consumerArgumentMatches = (string)args.ConsumerArguments[key] == value;
8793
};
8894

8995
await CloseAndWaitForRecoveryAsync();
9096
Assert.True(ctagMatches, "expected consumer tag to match");
9197
Assert.True(consumerArgumentMatches, "expected consumer arguments to match");
92-
string actualVal = (string)Assert.Contains("first-argument", myArgs as IDictionary<string, object>);
93-
Assert.Equal("event-handler-set-this-value", actualVal);
98+
string actualVal = (string)Assert.Contains(key, arguments);
99+
Assert.Equal(value, actualVal);
94100
}
95101
}
96102
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
// This source code is dual-licensed under the Apache License, version
2+
// 2.0, and the Mozilla Public License, version 2.0.
3+
//
4+
// The APL v2.0:
5+
//
6+
//---------------------------------------------------------------------------
7+
// Copyright (c) 2007-2024 Broadcom. All Rights Reserved.
8+
//
9+
// Licensed under the Apache License, Version 2.0 (the "License");
10+
// you may not use this file except in compliance with the License.
11+
// You may obtain a copy of the License at
12+
//
13+
// https://www.apache.org/licenses/LICENSE-2.0
14+
//
15+
// Unless required by applicable law or agreed to in writing, software
16+
// distributed under the License is distributed on an "AS IS" BASIS,
17+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18+
// See the License for the specific language governing permissions and
19+
// limitations under the License.
20+
//---------------------------------------------------------------------------
21+
//
22+
// The MPL v2.0:
23+
//
24+
//---------------------------------------------------------------------------
25+
// This Source Code Form is subject to the terms of the Mozilla Public
26+
// License, v. 2.0. If a copy of the MPL was not distributed with this
27+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
28+
//
29+
// Copyright (c) 2007-2024 Broadcom. All Rights Reserved.
30+
//---------------------------------------------------------------------------
31+
32+
using System.Collections.Generic;
33+
using System.Threading.Tasks;
34+
using RabbitMQ.Client;
35+
using RabbitMQ.Client.Events;
36+
using Xunit;
37+
using Xunit.Abstractions;
38+
39+
namespace Test.Integration.ConnectionRecovery
40+
{
41+
public class TestQueueRecoveryWithArguments : TestConnectionRecoveryBase
42+
{
43+
public TestQueueRecoveryWithArguments(ITestOutputHelper output) : base(output)
44+
{
45+
}
46+
47+
[Fact]
48+
public async Task TestQueueRecoveryWithDlxArgument_RabbitMQUsers_hk5pJ4cKF0c()
49+
{
50+
string tdiWaitExchangeName = GenerateExchangeName();
51+
string tdiRetryExchangeName = GenerateExchangeName();
52+
string testRetryQueueName = GenerateQueueName();
53+
string testQueueName = GenerateQueueName();
54+
55+
await _channel.ExchangeDeclareAsync(exchange: tdiWaitExchangeName,
56+
type: ExchangeType.Topic, durable: true, autoDelete: false, arguments: null);
57+
await _channel.ExchangeDeclareAsync(exchange: tdiRetryExchangeName,
58+
type: ExchangeType.Topic, durable: true, autoDelete: false, arguments: null);
59+
60+
var arguments = new Dictionary<string, object>
61+
{
62+
{ "x-dead-letter-exchange", "tdi.retry.exchange" },
63+
{ "x-dead-letter-routing-key", "QueueTest" }
64+
};
65+
66+
await _channel.QueueDeclareAsync(testRetryQueueName, durable: false, exclusive: false, autoDelete: false, arguments);
67+
68+
arguments["x-dead-letter-exchange"] = "tdi.wait.exchange";
69+
arguments["x-dead-letter-routing-key"] = "QueueTest";
70+
71+
await _channel.QueueDeclareAsync(testQueueName, durable: false, exclusive: false, autoDelete: false, arguments);
72+
73+
arguments.Remove("x-dead-letter-exchange");
74+
arguments.Remove("x-dead-letter-routing-key");
75+
76+
await _channel.QueueBindAsync(testRetryQueueName, tdiWaitExchangeName, testQueueName);
77+
78+
await _channel.QueueBindAsync(testQueueName, tdiRetryExchangeName, testQueueName);
79+
80+
var consumerAsync = new EventingBasicConsumer(_channel);
81+
await _channel.BasicConsumeAsync(queue: testQueueName, autoAck: false, consumer: consumerAsync);
82+
83+
await CloseAndWaitForRecoveryAsync();
84+
85+
QueueDeclareOk q0 = await _channel.QueueDeclarePassiveAsync(testRetryQueueName);
86+
Assert.Equal(testRetryQueueName, q0.QueueName);
87+
88+
QueueDeclareOk q1 = await _channel.QueueDeclarePassiveAsync(testQueueName);
89+
Assert.Equal(testQueueName, q1.QueueName);
90+
}
91+
}
92+
}

0 commit comments

Comments
 (0)