-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathRabbitMqTests.cs
138 lines (112 loc) · 6.54 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
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
using FluentAssertions;
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();
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 static bool ValidatePropagation(ICollection<MockSpansCollector.Collected> collected)
{
var producerSpans = collected.Where(span => span.Span.Kind == Span.Types.SpanKind.Producer).ToList();
producerSpans.Count.Should().Be(3);
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 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";
}
}