Skip to content

Commit 84cba1e

Browse files
[Out-of-process-collection] Add tests for Metrics Implementation (open-telemetry#4346)
* Add tests for Metrics Implementation * Update metrictests + impl * Add remaining tests * IsSumNonMonotonic update * Monotonic test fix
1 parent 7a16596 commit 84cba1e

18 files changed

+2425
-3
lines changed

next-gen/src/OpenTelemetry.AutoInstrumentation.Sdk/Metrics/Metric.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public Metric(
1919
string name,
2020
AggregationTemporality aggregationTemporality)
2121
{
22-
ArgumentException.ThrowIfNullOrEmpty(name);
22+
ArgumentException.ThrowIfNullOrWhiteSpace(name);
2323

2424
MetricType = metricType;
2525
Name = name;
@@ -60,10 +60,10 @@ public Metric(
6060
/// <summary>
6161
/// Gets a value indicating whether or not the metric is sum non-monotonic.
6262
/// </summary>
63-
public bool IsSumNonMonotonic => ((byte)MetricType & 0x80) == 1;
63+
public bool IsSumNonMonotonic => ((byte)MetricType & 0x80) != 0;
6464

6565
/// <summary>
6666
/// Gets a value indicating whether or not the metric is a floating point value.
6767
/// </summary>
68-
public bool IsFloatingPoint => ((byte)MetricType & 0x0c) == 1;
68+
public bool IsFloatingPoint => ((byte)MetricType & 0x0c) == 0x0c;
6969
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
using OpenTelemetry.Metrics;
5+
using Xunit;
6+
7+
namespace OpenTelemetry.AutoInstrumentation.Sdk.Tests.Metrics;
8+
9+
public class AggregationTemporalityTests
10+
{
11+
[Theory]
12+
[InlineData(AggregationTemporality.Unspecified, 0)]
13+
[InlineData(AggregationTemporality.Delta, 1)]
14+
[InlineData(AggregationTemporality.Cumulative, 2)]
15+
public void AggregationTemporality_HasCorrectValue(AggregationTemporality temporality, int expectedValue)
16+
{
17+
Assert.Equal(expectedValue, (int)temporality);
18+
}
19+
20+
[Fact]
21+
public void AggregationTemporality_AllValuesAreDefined()
22+
{
23+
var definedValues = Enum.GetValues<AggregationTemporality>();
24+
25+
Assert.Contains(AggregationTemporality.Unspecified, definedValues);
26+
Assert.Contains(AggregationTemporality.Delta, definedValues);
27+
Assert.Contains(AggregationTemporality.Cumulative, definedValues);
28+
Assert.Equal(3, definedValues.Length);
29+
}
30+
}
Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
using OpenTelemetry.Metrics;
5+
using Xunit;
6+
7+
namespace OpenTelemetry.AutoInstrumentation.Sdk.Tests.Metrics;
8+
9+
public class ExemplarTests
10+
{
11+
[Fact]
12+
public void Constructor_WithLongValue_SetsProperties()
13+
{
14+
// Arrange
15+
var timestamp = DateTime.UtcNow;
16+
var traceId = ActivityTraceId.CreateRandom();
17+
var spanId = ActivitySpanId.CreateRandom();
18+
var value = 123L;
19+
var attributes = new KeyValuePair<string, object?>[]
20+
{
21+
new("key1", "value1"),
22+
new("key2", 42)
23+
};
24+
25+
// Act
26+
var exemplar = new Exemplar(timestamp, traceId, spanId, value, attributes);
27+
28+
// Assert
29+
Assert.Equal(timestamp, exemplar.TimestampUtc);
30+
Assert.Equal(traceId, exemplar.TraceId);
31+
Assert.Equal(spanId, exemplar.SpanId);
32+
Assert.Equal(value, exemplar.ValueAsLong);
33+
34+
// Since it's a union, the double value will be the bit representation
35+
Assert.Equal(BitConverter.Int64BitsToDouble(value), exemplar.ValueAsDouble);
36+
}
37+
38+
[Fact]
39+
public void Constructor_WithDoubleValue_SetsProperties()
40+
{
41+
// Arrange
42+
var timestamp = DateTime.UtcNow;
43+
var traceId = ActivityTraceId.CreateRandom();
44+
var spanId = ActivitySpanId.CreateRandom();
45+
var value = 123.45;
46+
var attributes = new KeyValuePair<string, object?>[]
47+
{
48+
new("key1", "value1"),
49+
new("key2", 42)
50+
};
51+
52+
// Act
53+
var exemplar = new Exemplar(timestamp, traceId, spanId, value, attributes);
54+
55+
// Assert
56+
Assert.Equal(timestamp, exemplar.TimestampUtc);
57+
Assert.Equal(traceId, exemplar.TraceId);
58+
Assert.Equal(spanId, exemplar.SpanId);
59+
Assert.Equal(value, exemplar.ValueAsDouble);
60+
61+
// Since it's a union, the long value will be the bit representation
62+
Assert.Equal(BitConverter.DoubleToInt64Bits(value), exemplar.ValueAsLong);
63+
}
64+
65+
[Fact]
66+
public void Constructor_WithEmptyAttributes_CreatesExemplar()
67+
{
68+
// Arrange
69+
var timestamp = DateTime.UtcNow;
70+
var traceId = ActivityTraceId.CreateRandom();
71+
var spanId = ActivitySpanId.CreateRandom();
72+
var value = 100L;
73+
74+
// Act
75+
var exemplar = new Exemplar(timestamp, traceId, spanId, value);
76+
77+
// Assert
78+
Assert.Equal(timestamp, exemplar.TimestampUtc);
79+
Assert.Equal(traceId, exemplar.TraceId);
80+
Assert.Equal(spanId, exemplar.SpanId);
81+
Assert.Equal(value, exemplar.ValueAsLong);
82+
}
83+
84+
[Fact]
85+
public void GetFilteredAttributesReference_ReturnsCorrectReference()
86+
{
87+
// Arrange
88+
var attributes = new KeyValuePair<string, object?>[]
89+
{
90+
new("key1", "value1"),
91+
new("key2", 42)
92+
};
93+
var exemplar = new Exemplar(
94+
DateTime.UtcNow,
95+
ActivityTraceId.CreateRandom(),
96+
ActivitySpanId.CreateRandom(),
97+
100L,
98+
attributes);
99+
100+
// Act
101+
ref readonly var filteredAttributes = ref Exemplar.GetFilteredAttributesReference(in exemplar);
102+
103+
// Assert
104+
Assert.Equal(2, filteredAttributes.Count);
105+
Assert.Contains(new KeyValuePair<string, object?>("key1", "value1"), filteredAttributes);
106+
Assert.Contains(new KeyValuePair<string, object?>("key2", 42), filteredAttributes);
107+
}
108+
109+
[Theory]
110+
[InlineData(0L)]
111+
[InlineData(long.MaxValue)]
112+
[InlineData(long.MinValue)]
113+
[InlineData(-1L)]
114+
public void Constructor_WithSpecialLongValues_HandlesCorrectly(long value)
115+
{
116+
// Arrange & Act
117+
var exemplar = new Exemplar(
118+
DateTime.UtcNow,
119+
ActivityTraceId.CreateRandom(),
120+
ActivitySpanId.CreateRandom(),
121+
value);
122+
123+
// Assert
124+
Assert.Equal(value, exemplar.ValueAsLong);
125+
}
126+
127+
[Theory]
128+
[InlineData(0.0)]
129+
[InlineData(double.MaxValue)]
130+
[InlineData(double.MinValue)]
131+
[InlineData(double.PositiveInfinity)]
132+
[InlineData(double.NegativeInfinity)]
133+
[InlineData(double.NaN)]
134+
public void Constructor_WithSpecialDoubleValues_HandlesCorrectly(double value)
135+
{
136+
// Arrange & Act
137+
var exemplar = new Exemplar(
138+
DateTime.UtcNow,
139+
ActivityTraceId.CreateRandom(),
140+
ActivitySpanId.CreateRandom(),
141+
value);
142+
143+
// Assert
144+
if (double.IsNaN(value))
145+
{
146+
Assert.True(double.IsNaN(exemplar.ValueAsDouble));
147+
}
148+
else
149+
{
150+
Assert.Equal(value, exemplar.ValueAsDouble);
151+
}
152+
}
153+
154+
[Fact]
155+
public void UnionBehavior_DoubleAndLongShareMemory()
156+
{
157+
// Arrange
158+
var timestamp = DateTime.UtcNow;
159+
var traceId = ActivityTraceId.CreateRandom();
160+
var spanId = ActivitySpanId.CreateRandom();
161+
162+
// Test that the double and long values are stored in the same memory location
163+
var doubleValue = 123.456;
164+
var longValue = 789L;
165+
166+
// Act
167+
var doubleExemplar = new Exemplar(timestamp, traceId, spanId, doubleValue);
168+
var longExemplar = new Exemplar(timestamp, traceId, spanId, longValue);
169+
170+
// Assert
171+
Assert.Equal(doubleValue, doubleExemplar.ValueAsDouble);
172+
Assert.Equal(BitConverter.DoubleToInt64Bits(doubleValue), doubleExemplar.ValueAsLong);
173+
174+
Assert.Equal(longValue, longExemplar.ValueAsLong);
175+
Assert.Equal(BitConverter.Int64BitsToDouble(longValue), longExemplar.ValueAsDouble);
176+
}
177+
178+
[Fact]
179+
public void Exemplar_IsReadOnlyRecordStruct()
180+
{
181+
// Verify that Exemplar is a readonly record struct
182+
var exemplarType = typeof(Exemplar);
183+
Assert.True(exemplarType.IsValueType);
184+
185+
// Check that it has record struct characteristics
186+
var toStringMethod = exemplarType.GetMethod("ToString", Type.EmptyTypes);
187+
Assert.NotNull(toStringMethod);
188+
Assert.True(toStringMethod!.IsVirtual); // Records override ToString
189+
}
190+
191+
[Fact]
192+
public void Constructor_WithNullAttributeValues_HandlesCorrectly()
193+
{
194+
// Arrange
195+
var attributes = new KeyValuePair<string, object?>[]
196+
{
197+
new("key1", null),
198+
new("key2", "value2")
199+
};
200+
201+
// Act
202+
var exemplar = new Exemplar(
203+
DateTime.UtcNow,
204+
ActivityTraceId.CreateRandom(),
205+
ActivitySpanId.CreateRandom(),
206+
100L,
207+
attributes);
208+
209+
// Assert
210+
ref readonly var filteredAttributes = ref Exemplar.GetFilteredAttributesReference(in exemplar);
211+
Assert.Equal(2, filteredAttributes.Count);
212+
Assert.Contains(new KeyValuePair<string, object?>("key1", null), filteredAttributes);
213+
Assert.Contains(new KeyValuePair<string, object?>("key2", "value2"), filteredAttributes);
214+
}
215+
}

0 commit comments

Comments
 (0)