Skip to content

Commit e2faa36

Browse files
committed
feat: add test on open connexion
1 parent 9bb228a commit e2faa36

File tree

3 files changed

+183
-6
lines changed

3 files changed

+183
-6
lines changed

projects/RabbitMQ.Client/Impl/RabbitMQActivitySource.cs

-6
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,6 @@ namespace RabbitMQ.Client
1111
{
1212
public static class RabbitMQActivitySource
1313
{
14-
private const string ExceptionEventName = "exception";
15-
private const string ExceptionMessageTag = "exception.message";
16-
private const string ExceptionStackTraceTag = "exception.stacktrace";
17-
18-
private const string ExceptionTypeTag = "exception.type";
19-
2014
// These constants are defined in the OpenTelemetry specification:
2115
// https://opentelemetry.io/docs/specs/semconv/messaging/messaging-spans/#messaging-attributes
2216
internal const string MessageId = "messaging.message.id";
+170
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
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-2025 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-2025 Broadcom. All Rights Reserved.
30+
//---------------------------------------------------------------------------
31+
32+
using System;
33+
using System.Collections.Generic;
34+
using System.Diagnostics;
35+
using System.Linq;
36+
using System.Text;
37+
using System.Threading;
38+
using Xunit;
39+
40+
namespace Test
41+
{
42+
public class ActivityRecorder : IDisposable
43+
{
44+
private string _activitySourceName;
45+
private string _activityName;
46+
47+
private readonly ActivityListener _listener;
48+
private List<Activity> _finishedActivities = new();
49+
50+
private int _started;
51+
private int _stopped;
52+
53+
public int Started => _started;
54+
public int Stopped => _stopped;
55+
56+
public Predicate<Activity> Filter { get; set; } = _ => true;
57+
public bool VerifyParent { get; set; } = true;
58+
public Activity ExpectedParent { get; set; }
59+
60+
public Activity LastStartedActivity { get; private set; }
61+
public Activity LastFinishedActivity { get; private set; }
62+
public IEnumerable<Activity> FinishedActivities => _finishedActivities;
63+
64+
public ActivityRecorder(string activitySourceName, string activityName)
65+
{
66+
_activitySourceName = activitySourceName;
67+
_activityName = activityName;
68+
_listener = new ActivityListener
69+
{
70+
ShouldListenTo = (activitySource) => activitySource.Name == _activitySourceName,
71+
Sample = (ref ActivityCreationOptions<ActivityContext> options) => ActivitySamplingResult.AllData,
72+
ActivityStarted = (activity) =>
73+
{
74+
if (activity.OperationName == _activityName && Filter(activity))
75+
{
76+
if (VerifyParent)
77+
{
78+
Assert.Same(ExpectedParent, activity.Parent);
79+
}
80+
81+
Interlocked.Increment(ref _started);
82+
83+
LastStartedActivity = activity;
84+
}
85+
},
86+
ActivityStopped = (activity) =>
87+
{
88+
if (activity.OperationName == _activityName && Filter(activity))
89+
{
90+
if (VerifyParent)
91+
{
92+
Assert.Same(ExpectedParent, activity.Parent);
93+
}
94+
95+
Interlocked.Increment(ref _stopped);
96+
97+
lock (_finishedActivities)
98+
{
99+
LastFinishedActivity = activity;
100+
_finishedActivities.Add(activity);
101+
}
102+
}
103+
}
104+
};
105+
106+
ActivitySource.AddActivityListener(_listener);
107+
}
108+
109+
public void Dispose() => _listener.Dispose();
110+
111+
public void VerifyActivityRecorded(int times)
112+
{
113+
Assert.Equal(times, Started);
114+
Assert.Equal(times, Stopped);
115+
}
116+
117+
public Activity VerifyActivityRecordedOnce()
118+
{
119+
VerifyActivityRecorded(1);
120+
return LastFinishedActivity;
121+
}
122+
}
123+
124+
public static class ActivityAssert
125+
{
126+
public static KeyValuePair<string, object> HasTag(Activity activity, string name)
127+
{
128+
KeyValuePair<string, object> tag = activity.TagObjects.SingleOrDefault(t => t.Key == name);
129+
if (tag.Key is null)
130+
{
131+
Assert.Fail($"The Activity tags should contain {name}.");
132+
}
133+
return tag;
134+
}
135+
136+
public static void HasTag<T>(Activity activity, string name, T expectedValue)
137+
{
138+
KeyValuePair<string, object> tag = HasTag(activity, name);
139+
Assert.Equal(expectedValue, (T)tag.Value);
140+
}
141+
142+
public static void HasNoTag(Activity activity, string name)
143+
{
144+
bool contains = activity.TagObjects.Any(t => t.Key == name);
145+
Assert.False(contains, $"The Activity tags should not contain {name}.");
146+
}
147+
148+
public static void FinishedInOrder(Activity first, Activity second)
149+
{
150+
Assert.True(first.StartTimeUtc + first.Duration < second.StartTimeUtc + second.Duration, $"{first.OperationName} should stop before {second.OperationName}");
151+
}
152+
153+
public static string CamelToSnake(string camel)
154+
{
155+
if (string.IsNullOrEmpty(camel)) return camel;
156+
StringBuilder bld = new();
157+
bld.Append(char.ToLower(camel[0]));
158+
for (int i = 1; i < camel.Length; i++)
159+
{
160+
char c = camel[i];
161+
if (char.IsUpper(c))
162+
{
163+
bld.Append('_');
164+
}
165+
bld.Append(char.ToLower(c));
166+
}
167+
return bld.ToString();
168+
}
169+
}
170+
}

projects/Test/Integration/TestConnectionFactory.cs

+13
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131

3232
using System;
3333
using System.Collections.Generic;
34+
using System.Diagnostics;
3435
using System.Net.Sockets;
3536
using System.Threading;
3637
using System.Threading.Tasks;
@@ -434,5 +435,17 @@ public async Task TestCreateConnectionAsync_TruncatesWhenClientNameIsLong_GH980(
434435
Assert.Contains(conn.ClientProvidedName, cpn);
435436
}
436437
}
438+
439+
[Fact]
440+
public async Task TestCreateConnectionRegisterAnActivity()
441+
{
442+
using ActivityRecorder recorder =
443+
new ActivityRecorder(RabbitMQActivitySource.ConnectionSourceName, "connection attempt");
444+
ConnectionFactory cf = CreateConnectionFactory();
445+
await using IConnection conn = await cf.CreateConnectionAsync();
446+
recorder.VerifyActivityRecordedOnce();
447+
448+
await conn.CloseAsync();
449+
}
437450
}
438451
}

0 commit comments

Comments
 (0)