Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds the option to ignore timestamps in metric data tests. #3076

Merged
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 48 additions & 14 deletions sdk/metric/metricdata/metricdatatest/assertion.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,38 +44,66 @@ type Datatypes interface {
// Aggregation and Value type from metricdata are not included here.
}

type config struct {
ignoreTimestamp bool
}

// Option allows for fine grain control over how AssertEqual operates.
type Option interface {
apply(cfg config) config
}

type fnOption func(cfg config) config

func (fn fnOption) apply(cfg config) config {
return fn(cfg)
}

// IgnoreTimestamp disables checking if timestamps are different.
func IgnoreTimestamp() Option {
return fnOption(func(cfg config) config {
cfg.ignoreTimestamp = true
return cfg
})
}

// AssertEqual asserts that the two concrete data-types from the metricdata
// package are equal.
func AssertEqual[T Datatypes](t *testing.T, expected, actual T) bool {
func AssertEqual[T Datatypes](t *testing.T, expected, actual T, opts ...Option) bool {
t.Helper()

cfg := config{}
for _, opt := range opts {
cfg = opt.apply(cfg)
}

// Generic types cannot be type asserted. Use an interface instead.
aIface := interface{}(actual)

var r []string
switch e := interface{}(expected).(type) {
case metricdata.DataPoint[int64]:
r = equalDataPoints(e, aIface.(metricdata.DataPoint[int64]))
r = equalDataPoints(e, aIface.(metricdata.DataPoint[int64]), cfg)
case metricdata.DataPoint[float64]:
r = equalDataPoints(e, aIface.(metricdata.DataPoint[float64]))
r = equalDataPoints(e, aIface.(metricdata.DataPoint[float64]), cfg)
case metricdata.Gauge[int64]:
r = equalGauges(e, aIface.(metricdata.Gauge[int64]))
r = equalGauges(e, aIface.(metricdata.Gauge[int64]), cfg)
case metricdata.Gauge[float64]:
r = equalGauges(e, aIface.(metricdata.Gauge[float64]))
r = equalGauges(e, aIface.(metricdata.Gauge[float64]), cfg)
case metricdata.Histogram:
r = equalHistograms(e, aIface.(metricdata.Histogram))
r = equalHistograms(e, aIface.(metricdata.Histogram), cfg)
case metricdata.HistogramDataPoint:
r = equalHistogramDataPoints(e, aIface.(metricdata.HistogramDataPoint))
r = equalHistogramDataPoints(e, aIface.(metricdata.HistogramDataPoint), cfg)
case metricdata.Metrics:
r = equalMetrics(e, aIface.(metricdata.Metrics))
r = equalMetrics(e, aIface.(metricdata.Metrics), cfg)
case metricdata.ResourceMetrics:
r = equalResourceMetrics(e, aIface.(metricdata.ResourceMetrics))
r = equalResourceMetrics(e, aIface.(metricdata.ResourceMetrics), cfg)
case metricdata.ScopeMetrics:
r = equalScopeMetrics(e, aIface.(metricdata.ScopeMetrics))
r = equalScopeMetrics(e, aIface.(metricdata.ScopeMetrics), cfg)
case metricdata.Sum[int64]:
r = equalSums(e, aIface.(metricdata.Sum[int64]))
r = equalSums(e, aIface.(metricdata.Sum[int64]), cfg)
case metricdata.Sum[float64]:
r = equalSums(e, aIface.(metricdata.Sum[float64]))
r = equalSums(e, aIface.(metricdata.Sum[float64]), cfg)
default:
// We control all types passed to this, panic to signal developers
// early they changed things in an incompatible way.
Expand All @@ -90,9 +118,15 @@ func AssertEqual[T Datatypes](t *testing.T, expected, actual T) bool {
}

// AssertAggregationsEqual asserts that two Aggregations are equal.
func AssertAggregationsEqual(t *testing.T, expected, actual metricdata.Aggregation) bool {
func AssertAggregationsEqual(t *testing.T, expected, actual metricdata.Aggregation, opts ...Option) bool {
t.Helper()
if r := equalAggregations(expected, actual); len(r) > 0 {

cfg := config{}
for _, opt := range opts {
cfg = opt.apply(cfg)
}

if r := equalAggregations(expected, actual, cfg); len(r) > 0 {
t.Error(r)
return false
}
Expand Down
114 changes: 104 additions & 10 deletions sdk/metric/metricdata/metricdatatest/assertion_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,18 @@ var (
Time: endB,
Value: 2.0,
}
dataPointInt64C = metricdata.DataPoint[int64]{
Attributes: attrA,
StartTime: startB,
Time: endB,
Value: -1,
}
dataPointFloat64C = metricdata.DataPoint[float64]{
Attributes: attrA,
StartTime: startB,
Time: endB,
Value: -1.0,
}

max, min = 99.0, 3.
histogramDataPointA = metricdata.HistogramDataPoint{
Expand All @@ -85,6 +97,15 @@ var (
Min: &min,
Sum: 3,
}
histogramDataPointC = metricdata.HistogramDataPoint{
Attributes: attrA,
StartTime: startB,
Time: endB,
Count: 2,
Bounds: []float64{0, 10},
BucketCounts: []uint64{1, 1},
Sum: 2,
}

gaugeInt64A = metricdata.Gauge[int64]{
DataPoints: []metricdata.DataPoint[int64]{dataPointInt64A},
Expand All @@ -98,6 +119,12 @@ var (
gaugeFloat64B = metricdata.Gauge[float64]{
DataPoints: []metricdata.DataPoint[float64]{dataPointFloat64B},
}
gaugeInt64C = metricdata.Gauge[int64]{
DataPoints: []metricdata.DataPoint[int64]{dataPointInt64C},
}
gaugeFloat64C = metricdata.Gauge[float64]{
DataPoints: []metricdata.DataPoint[float64]{dataPointFloat64C},
}

sumInt64A = metricdata.Sum[int64]{
Temporality: metricdata.CumulativeTemporality,
Expand All @@ -119,6 +146,16 @@ var (
IsMonotonic: true,
DataPoints: []metricdata.DataPoint[float64]{dataPointFloat64B},
}
sumInt64C = metricdata.Sum[int64]{
Temporality: metricdata.CumulativeTemporality,
IsMonotonic: true,
DataPoints: []metricdata.DataPoint[int64]{dataPointInt64C},
}
sumFloat64C = metricdata.Sum[float64]{
Temporality: metricdata.CumulativeTemporality,
IsMonotonic: true,
DataPoints: []metricdata.DataPoint[float64]{dataPointFloat64C},
}

histogramA = metricdata.Histogram{
Temporality: metricdata.CumulativeTemporality,
Expand All @@ -128,6 +165,10 @@ var (
Temporality: metricdata.DeltaTemporality,
DataPoints: []metricdata.HistogramDataPoint{histogramDataPointB},
}
histogramC = metricdata.Histogram{
Temporality: metricdata.CumulativeTemporality,
DataPoints: []metricdata.HistogramDataPoint{histogramDataPointC},
}

metricsA = metricdata.Metrics{
Name: "A",
Expand All @@ -141,6 +182,12 @@ var (
Unit: unit.Bytes,
Data: gaugeFloat64B,
}
metricsC = metricdata.Metrics{
Name: "A",
Description: "A desc",
Unit: unit.Dimensionless,
Data: sumInt64C,
}

scopeMetricsA = metricdata.ScopeMetrics{
Scope: instrumentation.Scope{Name: "A"},
Expand All @@ -150,6 +197,10 @@ var (
Scope: instrumentation.Scope{Name: "B"},
Metrics: []metricdata.Metrics{metricsB},
}
scopeMetricsC = metricdata.ScopeMetrics{
Scope: instrumentation.Scope{Name: "A"},
Metrics: []metricdata.Metrics{metricsC},
}

resourceMetricsA = metricdata.ResourceMetrics{
Resource: resource.NewSchemaless(attribute.String("resource", "A")),
Expand All @@ -159,20 +210,34 @@ var (
Resource: resource.NewSchemaless(attribute.String("resource", "B")),
ScopeMetrics: []metricdata.ScopeMetrics{scopeMetricsB},
}
resourceMetricsC = metricdata.ResourceMetrics{
Resource: resource.NewSchemaless(attribute.String("resource", "A")),
ScopeMetrics: []metricdata.ScopeMetrics{scopeMetricsC},
}
)

type equalFunc[T Datatypes] func(T, T) []string
type equalFunc[T Datatypes] func(T, T, config) []string

func testDatatype[T Datatypes](a, b T, f equalFunc[T]) func(*testing.T) {
return func(t *testing.T) {
AssertEqual(t, a, a)
AssertEqual(t, b, b)

r := f(a, b)
r := f(a, b, config{})
assert.Greaterf(t, len(r), 0, "%v == %v", a, b)
}
}

func testDatatypeIgnoreTime[T Datatypes](a, b T, f equalFunc[T]) func(*testing.T) {
return func(t *testing.T) {
AssertEqual(t, a, a)
AssertEqual(t, b, b)

r := f(a, b, config{ignoreTimestamp: true})
assert.Equalf(t, len(r), 0, "%v == %v", a, b)
}
}

func TestAssertEqual(t *testing.T) {
t.Run("ResourceMetrics", testDatatype(resourceMetricsA, resourceMetricsB, equalResourceMetrics))
t.Run("ScopeMetrics", testDatatype(scopeMetricsA, scopeMetricsB, equalScopeMetrics))
Expand All @@ -187,6 +252,20 @@ func TestAssertEqual(t *testing.T) {
t.Run("DataPointFloat64", testDatatype(dataPointFloat64A, dataPointFloat64B, equalDataPoints[float64]))
}

func TestAssertEqualIgnoreTime(t *testing.T) {
t.Run("ResourceMetrics", testDatatypeIgnoreTime(resourceMetricsA, resourceMetricsC, equalResourceMetrics))
t.Run("ScopeMetrics", testDatatypeIgnoreTime(scopeMetricsA, scopeMetricsC, equalScopeMetrics))
t.Run("Metrics", testDatatypeIgnoreTime(metricsA, metricsC, equalMetrics))
t.Run("Histogram", testDatatypeIgnoreTime(histogramA, histogramC, equalHistograms))
t.Run("SumInt64", testDatatypeIgnoreTime(sumInt64A, sumInt64C, equalSums[int64]))
t.Run("SumFloat64", testDatatypeIgnoreTime(sumFloat64A, sumFloat64C, equalSums[float64]))
t.Run("GaugeInt64", testDatatypeIgnoreTime(gaugeInt64A, gaugeInt64C, equalGauges[int64]))
t.Run("GaugeFloat64", testDatatypeIgnoreTime(gaugeFloat64A, gaugeFloat64C, equalGauges[float64]))
t.Run("HistogramDataPoint", testDatatypeIgnoreTime(histogramDataPointA, histogramDataPointC, equalHistogramDataPoints))
t.Run("DataPointInt64", testDatatypeIgnoreTime(dataPointInt64A, dataPointInt64C, equalDataPoints[int64]))
t.Run("DataPointFloat64", testDatatypeIgnoreTime(dataPointFloat64A, dataPointFloat64C, equalDataPoints[float64]))
}

type unknownAggregation struct {
metricdata.Aggregation
}
Expand All @@ -199,27 +278,42 @@ func TestAssertAggregationsEqual(t *testing.T) {
AssertAggregationsEqual(t, gaugeFloat64A, gaugeFloat64A)
AssertAggregationsEqual(t, histogramA, histogramA)

r := equalAggregations(sumInt64A, nil)
r := equalAggregations(sumInt64A, nil, config{})
assert.Len(t, r, 1, "should return nil comparison mismatch only")

r = equalAggregations(sumInt64A, gaugeInt64A)
r = equalAggregations(sumInt64A, gaugeInt64A, config{})
assert.Len(t, r, 1, "should return with type mismatch only")

r = equalAggregations(unknownAggregation{}, unknownAggregation{})
r = equalAggregations(unknownAggregation{}, unknownAggregation{}, config{})
assert.Len(t, r, 1, "should return with unknown aggregation only")

r = equalAggregations(sumInt64A, sumInt64B)
r = equalAggregations(sumInt64A, sumInt64B, config{})
assert.Greaterf(t, len(r), 0, "%v == %v", sumInt64A, sumInt64B)

r = equalAggregations(sumFloat64A, sumFloat64B)
r = equalAggregations(sumInt64A, sumInt64C, config{ignoreTimestamp: true})
assert.Equalf(t, len(r), 0, "%v == %v", sumInt64A, sumInt64C)

r = equalAggregations(sumFloat64A, sumFloat64B, config{})
assert.Greaterf(t, len(r), 0, "%v == %v", sumFloat64A, sumFloat64B)

r = equalAggregations(gaugeInt64A, gaugeInt64B)
r = equalAggregations(sumFloat64A, sumFloat64C, config{ignoreTimestamp: true})
assert.Equalf(t, len(r), 0, "%v == %v", sumFloat64A, sumFloat64C)

r = equalAggregations(gaugeInt64A, gaugeInt64B, config{})
assert.Greaterf(t, len(r), 0, "%v == %v", gaugeInt64A, gaugeInt64B)

r = equalAggregations(gaugeFloat64A, gaugeFloat64B)
r = equalAggregations(gaugeInt64A, gaugeInt64C, config{ignoreTimestamp: true})
assert.Equalf(t, len(r), 0, "%v == %v", gaugeInt64A, gaugeInt64C)

r = equalAggregations(gaugeFloat64A, gaugeFloat64B, config{})
assert.Greaterf(t, len(r), 0, "%v == %v", gaugeFloat64A, gaugeFloat64B)

r = equalAggregations(histogramA, histogramB)
r = equalAggregations(gaugeFloat64A, gaugeFloat64C, config{ignoreTimestamp: true})
assert.Equalf(t, len(r), 0, "%v == %v", gaugeFloat64A, gaugeFloat64C)

r = equalAggregations(histogramA, histogramB, config{})
assert.Greaterf(t, len(r), 0, "%v == %v", histogramA, histogramB)

r = equalAggregations(histogramA, histogramC, config{ignoreTimestamp: true})
assert.Equalf(t, len(r), 0, "%v == %v", histogramA, histogramC)
}
Loading