1010using System . Threading . Tasks ;
1111using Datadog . Trace . Configuration ;
1212using Datadog . Trace . TestHelpers ;
13+ using Datadog . Trace . Vendors . Newtonsoft . Json ;
14+ using Datadog . Trace . Vendors . Newtonsoft . Json . Linq ;
1315using FluentAssertions ;
1416using FluentAssertions . Execution ;
1517using VerifyXunit ;
@@ -72,7 +74,6 @@ public class OpenTelemetrySdkTests : TracingIntegrationTest
7274
7375 private readonly Regex _versionRegex = new ( @"telemetry.sdk.version: (0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)" ) ;
7476 private readonly Regex _timeUnixNanoRegex = new ( @"time_unix_nano"":([0-9]{10}[0-9]+)" ) ;
75- private readonly Regex _timeUnixNanoRegexMetrics = new ( @"TimeUnixNano: ([0-9]{10}[0-9]+)" ) ;
7677 private readonly Regex _exceptionStacktraceRegex = new ( @"exception.stacktrace"":""System.ArgumentException: Example argument exception.*"",""" ) ;
7778
7879 public OpenTelemetrySdkTests ( ITestOutputHelper output )
@@ -89,8 +90,9 @@ public static IEnumerable<object[]> GetMetricsTestData()
8990 {
9091 foreach ( var packageVersion in PackageVersions . OpenTelemetry )
9192 {
92- yield return [ packageVersion [ 0 ] , "false" , "true" ] ;
93- yield return [ packageVersion [ 0 ] , "true" , "false" ] ;
93+ yield return [ packageVersion [ 0 ] , "false" , "true" , "grpc" ] ;
94+ yield return [ packageVersion [ 0 ] , "false" , "true" , "http/protobuf" ] ;
95+ yield return [ packageVersion [ 0 ] , "true" , "false" , "http/protobuf" ] ;
9496 }
9597 }
9698#endif
@@ -213,10 +215,11 @@ public async Task IntegrationDisabled(string packageVersion)
213215 [ SkippableTheory ]
214216 [ Trait ( "Category" , "EndToEnd" ) ]
215217 [ Trait ( "RunOnWindows" , "True" ) ]
218+ [ Trait ( "RequiresDockerDependency" , "true" ) ]
216219 [ MemberData ( nameof ( GetMetricsTestData ) ) ]
217- public async Task SubmitsOtlpMetrics ( string packageVersion , string datadogMetricsEnabled , string otelMetricsEnabled )
220+ public async Task SubmitsOtlpMetrics ( string packageVersion , string datadogMetricsEnabled , string otelMetricsEnabled , string protocol )
218221 {
219- var parsedVersion = Version . Parse ( ! string . IsNullOrEmpty ( packageVersion ) ? packageVersion : "1.12.0 " ) ;
222+ var parsedVersion = Version . Parse ( ! string . IsNullOrEmpty ( packageVersion ) ? packageVersion : "1.13.1 " ) ;
220223 var runtimeMajor = Environment . Version . Major ;
221224
222225 var snapshotName = runtimeMajor switch
@@ -227,94 +230,71 @@ public async Task SubmitsOtlpMetrics(string packageVersion, string datadogMetric
227230 _ => throw new SkipException ( $ "Skipping test due to irrelevant runtime and OTel versions mix: .NET { runtimeMajor } & Otel v{ parsedVersion } ")
228231 } ;
229232
230- var initialAgentPort = TcpPortProvider . GetOpenPort ( ) ;
233+ var testAgentHost = Environment . GetEnvironmentVariable ( "TEST_AGENT_HOST" ) ?? "localhost" ;
234+ var otlpPort = protocol == "grpc" ? 4317 : 4318 ;
235+
236+ using ( var httpClient = new System . Net . Http . HttpClient ( ) )
237+ {
238+ await httpClient . GetAsync ( $ "http://{ testAgentHost } :4318/test/session/clear") ;
239+ }
231240
232241 SetEnvironmentVariable ( "DD_ENV" , string . Empty ) ;
233242 SetEnvironmentVariable ( "DD_SERVICE" , string . Empty ) ;
234243 SetEnvironmentVariable ( "DD_METRICS_OTEL_METER_NAMES" , "OpenTelemetryMetricsMeter" ) ;
235244 SetEnvironmentVariable ( "DD_METRICS_OTEL_ENABLED" , datadogMetricsEnabled ) ;
236245 SetEnvironmentVariable ( "OTEL_METRICS_EXPORTER_ENABLED" , otelMetricsEnabled ) ;
237- SetEnvironmentVariable ( "OTEL_EXPORTER_OTLP_PROTOCOL" , "http/protobuf" ) ;
238- SetEnvironmentVariable ( "OTEL_EXPORTER_OTLP_ENDPOINT" , $ "http://127.0.0.1: { initialAgentPort } ") ;
246+ SetEnvironmentVariable ( "OTEL_EXPORTER_OTLP_PROTOCOL" , protocol ) ;
247+ SetEnvironmentVariable ( "OTEL_EXPORTER_OTLP_ENDPOINT" , $ "http://{ testAgentHost } : { otlpPort } ") ;
239248 SetEnvironmentVariable ( "OTEL_METRIC_EXPORT_INTERVAL" , "1000" ) ;
240249
241250 // Up until Sdk version 1.6.0 Otel didn't support reading from the env var
242251 SetEnvironmentVariable ( "OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE" , runtimeMajor >= 9 ? "delta" : "cumulative" ) ;
243252
244- using var agent = EnvironmentHelper . GetMockAgent ( fixedPort : initialAgentPort ) ;
245- using ( await RunSampleAndWaitForExit ( agent , packageVersion : packageVersion ?? "1.12.0 " ) )
253+ using var agent = EnvironmentHelper . GetMockAgent ( ) ;
254+ using ( await RunSampleAndWaitForExit ( agent , packageVersion : packageVersion ?? "1.13.1 " ) )
246255 {
247- // Collect requests from both MockTracerAgent and MockOtlpGrpcServer
248- var metricRequests = agent . OtlpRequests
249- . Where ( r => r . PathAndQuery . StartsWith ( "/v1/metrics" ) || r . PathAndQuery . Contains ( "MetricsService" ) )
250- . ToList ( ) ;
251-
252- metricRequests . Should ( ) . NotBeEmpty ( "Expected OTLP metric requests were not received." ) ;
253-
254- // Group the scope metrics by the resource metrics and schema URL (should only be one unique combination)
255- var resourceMetricByResource = metricRequests
256- . SelectMany ( r => r . MetricsData . ResourceMetrics )
257- . GroupBy ( r => new Tuple < global ::OpenTelemetry . Proto . Resource . V1 . Resource , string > ( r . Resource , r . SchemaUrl ) )
258- . Should ( )
259- . ContainSingle ( )
260- . Subject ;
261-
262- // Group the individual metrics by scope metric and schema URL (should only be one unique combination since we're only using one ActivitySource)
263- // This may result in multiple entries for metrics that are repeated multiple times before the test exits
264- var scopeMetricsByResource = resourceMetricByResource
265- . SelectMany ( r => r . ScopeMetrics )
266- . GroupBy ( r => new Tuple < global ::OpenTelemetry . Proto . Common . V1 . InstrumentationScope , string > ( r . Scope , r . SchemaUrl ) )
267- . OrderBy ( group => group . Key . Item1 . Name ) ;
268-
269- var scopeMetrics = new List < object > ( ) ;
270- foreach ( var scopeMetricByResource in scopeMetricsByResource )
256+ await Task . Delay ( 2000 ) ;
257+
258+ using var httpClient = new System . Net . Http . HttpClient ( ) ;
259+ var metricsResponse = await httpClient . GetAsync ( $ "http://{ testAgentHost } :4318/test/session/metrics") ;
260+ metricsResponse . EnsureSuccessStatusCode ( ) ;
261+
262+ var metricsJson = await metricsResponse . Content . ReadAsStringAsync ( ) ;
263+ var metricsData = JToken . Parse ( metricsJson ) ;
264+
265+ metricsData . Should ( ) . NotBeNullOrEmpty ( ) ;
266+
267+ foreach ( var attribute in metricsData . SelectTokens ( "$..resource.attributes[?(@.key == 'telemetry.sdk.version')]" ) )
271268 {
272- var metrics = scopeMetricByResource
273- . SelectMany ( r => r . Metrics )
274- . GroupBy ( r => r . Name )
275- . OrderBy ( group => group . Key )
276- . Select ( group => group . First ( ) )
277- . ToList ( ) ;
278-
279- scopeMetrics . Add ( new
280- {
281- Scope = scopeMetricByResource . Key . Item1 ,
282- Metrics = metrics ,
283- SchemaUrl = scopeMetricByResource . Key . Item2
284- } ) ;
269+ attribute [ "value" ] ! [ "string_value" ] = "sdk-version" ;
285270 }
286271
287- // Filter out the telemetry resource name, if any
288- foreach ( var attribute in resourceMetricByResource . Key . Item1 . Attributes )
272+ foreach ( var attribute in metricsData . SelectTokens ( "$..resource.attributes[?(@.key == 'telemetry.sdk.name')]" ) )
289273 {
290- if ( attribute . Key . Equals ( "telemetry.sdk.version" ) )
291- {
292- attribute . Value . StringValue = "sdk-version" ;
293- }
294- else if ( attribute . Key . Equals ( "telemetry.sdk.name" ) )
295- {
296- attribute . Value . StringValue = "sdk-name" ;
297- }
274+ attribute [ "value" ] ! [ "string_value" ] = "sdk-name" ;
275+ }
276+
277+ foreach ( var dataPoint in metricsData . SelectTokens ( "$..data_points[*]" ) )
278+ {
279+ dataPoint [ "start_time_unix_nano" ] = "0" ;
280+ dataPoint [ "time_unix_nano" ] = "0" ;
298281 }
299282
300- // Although there's only one resource, let's still emit snapshot data in the expected array format
301- var resourceMetrics = new object [ ]
283+ foreach ( var scopeMetric in metricsData . SelectTokens ( "$..scope_metrics[*]" ) )
302284 {
303- new
285+ if ( scopeMetric [ "metrics" ] is JArray metricsArray )
304286 {
305- Resource = resourceMetricByResource . Key . Item1 ,
306- ScopeMetrics = scopeMetrics ,
307- SchemaUrl = resourceMetricByResource . Key . Item2 ,
287+ var sorted = new JArray ( metricsArray . OrderBy ( m => m [ "name" ] ? . ToString ( ) ) ) ;
288+ scopeMetric [ "metrics" ] = sorted ;
308289 }
309- } ;
290+ }
310291
292+ var formattedJson = metricsData . ToString ( Formatting . Indented ) ;
311293 var settings = VerifyHelper . GetSpanVerifierSettings ( ) ;
312- settings . AddRegexScrubber ( _timeUnixNanoRegexMetrics , @"TimeUnixNano"": <DateTimeOffset.Now>" ) ;
313-
314294 var suffix = GetSuffix ( packageVersion ) ;
315295 var fileName = $ "{ nameof ( OpenTelemetrySdkTests ) } .SubmitsOtlpMetrics{ suffix } { snapshotName } ";
316296
317- await Verifier . Verify ( resourceMetrics , settings )
297+ await Verifier . Verify ( formattedJson , settings )
318298 . UseFileName ( fileName )
319299 . DisableRequireUniquePrefix ( ) ;
320300 }
0 commit comments