-
Notifications
You must be signed in to change notification settings - Fork 99
/
Copy pathRabbitMqTests.cs
165 lines (135 loc) · 7.29 KB
/
RabbitMqTests.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
using IntegrationTests.Helpers;
using OpenTelemetry.Proto.Common.V1;
using OpenTelemetry.Proto.Trace.V1;
using Xunit.Abstractions;
namespace IntegrationTests;
[Collection(RabbitMqCollection.Name)]
public class RabbitMqTests : TestHelper
{
// https://github.com/open-telemetry/semantic-conventions/blob/d515887174e20a3546e89df5cb5a306231e1424b/docs/messaging/rabbitmq.md
// Required messaging attributes set by the instrumentation
private const string MessagingSystemAttributeName = "messaging.system";
private const string MessagingOperationAttributeName = "messaging.operation";
private const string MessagingDestinationAttributeName = "messaging.destination.name";
// Required RabbitMQ attributes set by the instrumentation
private const string RabbitMqRoutingKeyAttributeName = "messaging.rabbitmq.destination.routing_key";
private const string RabbitMqDeliveryTagAttributeName = "messaging.rabbitmq.delivery_tag";
// Recommended messaging attributes set by the instrumentation
private const string MessagingBodySizeAttributeName = "messaging.message.body.size";
// Required network attributes set by the instrumentation
private const string ServerAddressAttributeName = "server.address";
private const string ServerPortAttributeName = "server.port";
// Recommended network attributes set by the instrumentation
private const string NetworkTypeAttributeName = "network.type";
private const string NetworkPeerAddressAttributeName = "network.peer.address";
private const string NetworkPeerPortAttributeName = "network.peer.port";
private readonly RabbitMqFixture _rabbitMq;
public RabbitMqTests(ITestOutputHelper output, RabbitMqFixture rabbitMq)
: base("RabbitMq", output)
{
_rabbitMq = rabbitMq;
}
[SkippableTheory]
[Trait("Category", "EndToEnd")]
[Trait("Containers", "Linux")]
[MemberData(nameof(LibraryVersion.RabbitMq), MemberType = typeof(LibraryVersion))]
public void SubmitsTraces(string packageVersion)
{
// Skip the test if fixture does not support current platform
_rabbitMq.SkipIfUnsupportedPlatform();
if (string.IsNullOrEmpty(packageVersion) || Version.Parse(packageVersion) >= new Version(7, 0, 0))
{
TestRabbitMq7Plus(packageVersion);
}
else
{
TestRabbitMq6(packageVersion);
}
}
private static bool ValidatePropagation(ICollection<MockSpansCollector.Collected> collected)
{
var producerSpans = collected.Where(span => span.Span.Kind == Span.Types.SpanKind.Producer).ToList();
Assert.Equal(3, producerSpans.Count);
return producerSpans.All(span => VerifySingleMatchingConsumerSpan(span));
bool VerifySingleMatchingConsumerSpan(MockSpansCollector.Collected producerSpan)
{
return collected.Count(spans =>
spans.Span.Kind == Span.Types.SpanKind.Consumer &&
spans.Span.Links[0].TraceId == producerSpan.Span.TraceId &&
spans.Span.Links[0].SpanId == producerSpan.Span.SpanId) == 1;
}
}
private static bool ValidateBasicSpanAttributes(IReadOnlyCollection<KeyValue> attributes, string operationName)
{
var messagingSystem = attributes.Single(kv => kv.Key == MessagingSystemAttributeName).Value.StringValue;
var messagingOperation = attributes.Single(kv => kv.Key == MessagingOperationAttributeName).Value.StringValue;
var destinationName = attributes.Single(kv => kv.Key == MessagingDestinationAttributeName).Value.StringValue;
var routingKey = attributes.Single(kv => kv.Key == RabbitMqRoutingKeyAttributeName).Value.StringValue;
var bodySize = attributes.Single(kv => kv.Key == MessagingBodySizeAttributeName).Value.IntValue;
return messagingSystem == "rabbitmq" &&
messagingOperation == operationName &&
destinationName == "amq.default" &&
routingKey == "hello" &&
bodySize == 13;
}
private void TestRabbitMq7Plus(string packageVersion)
{
using var collector = new MockSpansCollector(Output);
SetExporter(collector);
collector.Expect("RabbitMQ.Client.Publisher");
collector.Expect("RabbitMQ.Client.Subscriber");
RunTestApplication(new()
{
Arguments = $"--rabbitmq {_rabbitMq.Port}",
PackageVersion = packageVersion
});
collector.AssertExpectations();
}
private void TestRabbitMq6(string packageVersion)
{
using var collector = new MockSpansCollector(Output);
SetExporter(collector);
collector.Expect("OpenTelemetry.AutoInstrumentation.RabbitMq", span => ValidateProducerSpan(span));
collector.Expect("OpenTelemetry.AutoInstrumentation.RabbitMq", span => ValidateProducerSpan(span));
collector.Expect("OpenTelemetry.AutoInstrumentation.RabbitMq", span => ValidateProducerSpan(span));
collector.Expect("OpenTelemetry.AutoInstrumentation.RabbitMq", span => ValidateConsumerSpan(span, "receive"));
collector.Expect("OpenTelemetry.AutoInstrumentation.RabbitMq", span => ValidateConsumerSpan(span, "deliver"));
collector.Expect("OpenTelemetry.AutoInstrumentation.RabbitMq", span => ValidateConsumerSpan(span, "deliver"));
collector.ExpectCollected(collected => ValidatePropagation(collected));
EnableBytecodeInstrumentation();
RunTestApplication(new()
{
Arguments = $"--rabbitmq {_rabbitMq.Port}",
PackageVersion = packageVersion
});
collector.AssertExpectations();
}
private bool ValidateConsumerSpan(Span span, string operationName)
{
var deliveryTag = span.Attributes.SingleOrDefault(kv => kv.Key == RabbitMqDeliveryTagAttributeName)?.Value.StringValue;
return span.Kind == Span.Types.SpanKind.Consumer &&
span.Links.Count == 1 &&
ValidateBasicSpanAttributes(span.Attributes, operationName) &&
(operationName != "receive" || ValidateNetworkAttributes(span.Attributes)) &&
!string.IsNullOrEmpty(deliveryTag);
}
private bool ValidateProducerSpan(Span span)
{
return span.Kind == Span.Types.SpanKind.Producer && ValidateBasicSpanAttributes(span.Attributes, "publish") && ValidateNetworkAttributes(span.Attributes);
}
private bool ValidateNetworkAttributes(IReadOnlyCollection<KeyValue> spanAttributes)
{
var serverAddress = spanAttributes.Single(kv => kv.Key == ServerAddressAttributeName).Value.StringValue;
var serverPort = spanAttributes.Single(kv => kv.Key == ServerPortAttributeName).Value.IntValue;
var networkType = spanAttributes.Single(kv => kv.Key == NetworkTypeAttributeName).Value.StringValue;
var networkPeerAddress = spanAttributes.Single(kv => kv.Key == NetworkPeerAddressAttributeName).Value.StringValue;
var networkPeerPort = spanAttributes.Single(kv => kv.Key == NetworkPeerPortAttributeName).Value.IntValue;
return serverAddress == "localhost" &&
serverPort == _rabbitMq.Port &&
networkPeerAddress is "127.0.0.1" or "::1" &&
networkPeerPort == _rabbitMq.Port &&
networkType is "ipv4" or "ipv6";
}
}