Skip to content

Commit d4cf693

Browse files
authored
Add unit test to check that metric dimensions are order insensitive (#2788)
1 parent fcb6b40 commit d4cf693

File tree

1 file changed

+217
-0
lines changed

1 file changed

+217
-0
lines changed

test/OpenTelemetry.Tests/Metrics/MetricAPITest.cs

Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,188 @@ public void ObservableCounterAggregationTest(bool exportDelta)
382382
}
383383
}
384384

385+
[Theory]
386+
[InlineData(true)]
387+
[InlineData(false)]
388+
public void DimensionsAreOrderInsensitiveWithSortedKeysFirst(bool exportDelta)
389+
{
390+
var exportedItems = new List<Metric>();
391+
392+
using var meter = new Meter($"{Utils.GetCurrentMethodName()}.{exportDelta}");
393+
var counterLong = meter.CreateCounter<long>("Counter");
394+
using var meterProvider = Sdk.CreateMeterProviderBuilder()
395+
.AddMeter(meter.Name)
396+
.AddReader(new BaseExportingMetricReader(new InMemoryExporter<Metric>(exportedItems))
397+
{
398+
Temporality = exportDelta ? AggregationTemporality.Delta : AggregationTemporality.Cumulative,
399+
})
400+
.Build();
401+
402+
// Emit the first metric with the sorted order of tag keys
403+
counterLong.Add(5, new("Key1", "Value1"), new("Key2", "Value2"), new("Key3", "Value3"));
404+
counterLong.Add(10, new("Key1", "Value1"), new("Key3", "Value3"), new("Key2", "Value2"));
405+
counterLong.Add(10, new("Key2", "Value20"), new("Key1", "Value10"), new("Key3", "Value30"));
406+
407+
// Emit a metric with different set of keys but the same set of values as one of the previous metric points
408+
counterLong.Add(25, new("Key4", "Value1"), new("Key5", "Value3"), new("Key6", "Value2"));
409+
counterLong.Add(25, new("Key4", "Value1"), new("Key6", "Value3"), new("Key5", "Value2"));
410+
411+
meterProvider.ForceFlush(MaxTimeToAllowForFlush);
412+
413+
List<KeyValuePair<string, object>> expectedTagsForFirstMetricPoint = new List<KeyValuePair<string, object>>()
414+
{
415+
new("Key1", "Value1"),
416+
new("Key2", "Value2"),
417+
new("Key3", "Value3"),
418+
};
419+
420+
List<KeyValuePair<string, object>> expectedTagsForSecondMetricPoint = new List<KeyValuePair<string, object>>()
421+
{
422+
new("Key1", "Value10"),
423+
new("Key2", "Value20"),
424+
new("Key3", "Value30"),
425+
};
426+
427+
List<KeyValuePair<string, object>> expectedTagsForThirdMetricPoint = new List<KeyValuePair<string, object>>()
428+
{
429+
new("Key4", "Value1"),
430+
new("Key5", "Value3"),
431+
new("Key6", "Value2"),
432+
};
433+
434+
List<KeyValuePair<string, object>> expectedTagsForFourthMetricPoint = new List<KeyValuePair<string, object>>()
435+
{
436+
new("Key4", "Value1"),
437+
new("Key5", "Value2"),
438+
new("Key6", "Value3"),
439+
};
440+
441+
Assert.Equal(4, GetNumberOfMetricPoints(exportedItems));
442+
CheckTagsForNthMetricPoint(exportedItems, expectedTagsForFirstMetricPoint, 1);
443+
CheckTagsForNthMetricPoint(exportedItems, expectedTagsForSecondMetricPoint, 2);
444+
CheckTagsForNthMetricPoint(exportedItems, expectedTagsForThirdMetricPoint, 3);
445+
CheckTagsForNthMetricPoint(exportedItems, expectedTagsForFourthMetricPoint, 4);
446+
long sumReceived = GetLongSum(exportedItems);
447+
Assert.Equal(75, sumReceived);
448+
449+
exportedItems.Clear();
450+
451+
counterLong.Add(5, new("Key2", "Value2"), new("Key1", "Value1"), new("Key3", "Value3"));
452+
counterLong.Add(5, new("Key2", "Value2"), new("Key1", "Value1"), new("Key3", "Value3"));
453+
counterLong.Add(10, new("Key2", "Value2"), new("Key3", "Value3"), new("Key1", "Value1"));
454+
counterLong.Add(10, new("Key2", "Value20"), new("Key3", "Value30"), new("Key1", "Value10"));
455+
counterLong.Add(20, new("Key4", "Value1"), new("Key6", "Value2"), new("Key5", "Value3"));
456+
counterLong.Add(20, new("Key4", "Value1"), new("Key5", "Value2"), new("Key6", "Value3"));
457+
458+
meterProvider.ForceFlush(MaxTimeToAllowForFlush);
459+
460+
Assert.Equal(4, GetNumberOfMetricPoints(exportedItems));
461+
CheckTagsForNthMetricPoint(exportedItems, expectedTagsForFirstMetricPoint, 1);
462+
CheckTagsForNthMetricPoint(exportedItems, expectedTagsForSecondMetricPoint, 2);
463+
CheckTagsForNthMetricPoint(exportedItems, expectedTagsForThirdMetricPoint, 3);
464+
CheckTagsForNthMetricPoint(exportedItems, expectedTagsForFourthMetricPoint, 4);
465+
sumReceived = GetLongSum(exportedItems);
466+
if (exportDelta)
467+
{
468+
Assert.Equal(70, sumReceived);
469+
}
470+
else
471+
{
472+
Assert.Equal(145, sumReceived);
473+
}
474+
}
475+
476+
[Theory]
477+
[InlineData(true)]
478+
[InlineData(false)]
479+
public void DimensionsAreOrderInsensitiveWithUnsortedKeysFirst(bool exportDelta)
480+
{
481+
var exportedItems = new List<Metric>();
482+
483+
using var meter = new Meter($"{Utils.GetCurrentMethodName()}.{exportDelta}");
484+
var counterLong = meter.CreateCounter<long>("Counter");
485+
using var meterProvider = Sdk.CreateMeterProviderBuilder()
486+
.AddMeter(meter.Name)
487+
.AddReader(new BaseExportingMetricReader(new InMemoryExporter<Metric>(exportedItems))
488+
{
489+
Temporality = exportDelta ? AggregationTemporality.Delta : AggregationTemporality.Cumulative,
490+
})
491+
.Build();
492+
493+
// Emit the first metric with the unsorted order of tag keys
494+
counterLong.Add(5, new("Key1", "Value1"), new("Key3", "Value3"), new("Key2", "Value2"));
495+
counterLong.Add(10, new("Key1", "Value1"), new("Key2", "Value2"), new("Key3", "Value3"));
496+
counterLong.Add(10, new("Key2", "Value20"), new("Key1", "Value10"), new("Key3", "Value30"));
497+
498+
// Emit a metric with different set of keys but the same set of values as one of the previous metric points
499+
counterLong.Add(25, new("Key4", "Value1"), new("Key5", "Value3"), new("Key6", "Value2"));
500+
counterLong.Add(25, new("Key4", "Value1"), new("Key6", "Value3"), new("Key5", "Value2"));
501+
502+
meterProvider.ForceFlush(MaxTimeToAllowForFlush);
503+
504+
List<KeyValuePair<string, object>> expectedTagsForFirstMetricPoint = new List<KeyValuePair<string, object>>()
505+
{
506+
new("Key1", "Value1"),
507+
new("Key2", "Value2"),
508+
new("Key3", "Value3"),
509+
};
510+
511+
List<KeyValuePair<string, object>> expectedTagsForSecondMetricPoint = new List<KeyValuePair<string, object>>()
512+
{
513+
new("Key1", "Value10"),
514+
new("Key2", "Value20"),
515+
new("Key3", "Value30"),
516+
};
517+
518+
List<KeyValuePair<string, object>> expectedTagsForThirdMetricPoint = new List<KeyValuePair<string, object>>()
519+
{
520+
new("Key4", "Value1"),
521+
new("Key5", "Value3"),
522+
new("Key6", "Value2"),
523+
};
524+
525+
List<KeyValuePair<string, object>> expectedTagsForFourthMetricPoint = new List<KeyValuePair<string, object>>()
526+
{
527+
new("Key4", "Value1"),
528+
new("Key5", "Value2"),
529+
new("Key6", "Value3"),
530+
};
531+
532+
Assert.Equal(4, GetNumberOfMetricPoints(exportedItems));
533+
CheckTagsForNthMetricPoint(exportedItems, expectedTagsForFirstMetricPoint, 1);
534+
CheckTagsForNthMetricPoint(exportedItems, expectedTagsForSecondMetricPoint, 2);
535+
CheckTagsForNthMetricPoint(exportedItems, expectedTagsForThirdMetricPoint, 3);
536+
CheckTagsForNthMetricPoint(exportedItems, expectedTagsForFourthMetricPoint, 4);
537+
long sumReceived = GetLongSum(exportedItems);
538+
Assert.Equal(75, sumReceived);
539+
540+
exportedItems.Clear();
541+
542+
counterLong.Add(5, new("Key2", "Value2"), new("Key1", "Value1"), new("Key3", "Value3"));
543+
counterLong.Add(5, new("Key2", "Value2"), new("Key1", "Value1"), new("Key3", "Value3"));
544+
counterLong.Add(10, new("Key2", "Value2"), new("Key3", "Value3"), new("Key1", "Value1"));
545+
counterLong.Add(10, new("Key2", "Value20"), new("Key3", "Value30"), new("Key1", "Value10"));
546+
counterLong.Add(20, new("Key4", "Value1"), new("Key6", "Value2"), new("Key5", "Value3"));
547+
counterLong.Add(20, new("Key4", "Value1"), new("Key5", "Value2"), new("Key6", "Value3"));
548+
549+
meterProvider.ForceFlush(MaxTimeToAllowForFlush);
550+
551+
Assert.Equal(4, GetNumberOfMetricPoints(exportedItems));
552+
CheckTagsForNthMetricPoint(exportedItems, expectedTagsForFirstMetricPoint, 1);
553+
CheckTagsForNthMetricPoint(exportedItems, expectedTagsForSecondMetricPoint, 2);
554+
CheckTagsForNthMetricPoint(exportedItems, expectedTagsForThirdMetricPoint, 3);
555+
CheckTagsForNthMetricPoint(exportedItems, expectedTagsForFourthMetricPoint, 4);
556+
sumReceived = GetLongSum(exportedItems);
557+
if (exportDelta)
558+
{
559+
Assert.Equal(70, sumReceived);
560+
}
561+
else
562+
{
563+
Assert.Equal(145, sumReceived);
564+
}
565+
}
566+
385567
[Theory]
386568
[InlineData(AggregationTemporality.Cumulative)]
387569
[InlineData(AggregationTemporality.Delta)]
@@ -658,6 +840,41 @@ private static double GetDoubleSum(List<Metric> metrics)
658840
return sum;
659841
}
660842

843+
private static int GetNumberOfMetricPoints(List<Metric> metrics)
844+
{
845+
int count = 0;
846+
foreach (var metric in metrics)
847+
{
848+
foreach (ref readonly var metricPoint in metric.GetMetricPoints())
849+
{
850+
count++;
851+
}
852+
}
853+
854+
return count;
855+
}
856+
857+
// Provide tags input sorted by Key
858+
private static void CheckTagsForNthMetricPoint(List<Metric> metrics, List<KeyValuePair<string, object>> tags, int n)
859+
{
860+
var metric = metrics[0];
861+
var metricPointEnumerator = metric.GetMetricPoints().GetEnumerator();
862+
863+
for (int i = 0; i < n; i++)
864+
{
865+
Assert.True(metricPointEnumerator.MoveNext());
866+
}
867+
868+
int index = 0;
869+
var metricPoint = metricPointEnumerator.Current;
870+
foreach (var tag in metricPoint.Tags)
871+
{
872+
Assert.Equal(tags[index].Key, tag.Key);
873+
Assert.Equal(tags[index].Value, tag.Value);
874+
index++;
875+
}
876+
}
877+
661878
private static void CounterUpdateThread<T>(object obj)
662879
where T : struct, IComparable
663880
{

0 commit comments

Comments
 (0)