1// Copyright The OpenTelemetry Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package aggregator_test // import "go.opentelemetry.io/otel/sdk/metric/aggregator"
16
17import (
18	"errors"
19	"math"
20	"testing"
21
22	"github.com/stretchr/testify/require"
23
24	"go.opentelemetry.io/otel/metric"
25	"go.opentelemetry.io/otel/metric/number"
26	"go.opentelemetry.io/otel/sdk/export/metric/aggregation"
27	"go.opentelemetry.io/otel/sdk/metric/aggregator"
28	"go.opentelemetry.io/otel/sdk/metric/aggregator/lastvalue"
29	"go.opentelemetry.io/otel/sdk/metric/aggregator/sum"
30)
31
32func TestInconsistentAggregatorErr(t *testing.T) {
33	err := aggregator.NewInconsistentAggregatorError(&sum.New(1)[0], &lastvalue.New(1)[0])
34	require.Equal(
35		t,
36		"inconsistent aggregator types: *sum.Aggregator and *lastvalue.Aggregator",
37		err.Error(),
38	)
39	require.True(t, errors.Is(err, aggregation.ErrInconsistentType))
40}
41
42func testRangeNaN(t *testing.T, desc *metric.Descriptor) {
43	// If the descriptor uses int64 numbers, this won't register as NaN
44	nan := number.NewFloat64Number(math.NaN())
45	err := aggregator.RangeTest(nan, desc)
46
47	if desc.NumberKind() == number.Float64Kind {
48		require.Equal(t, aggregation.ErrNaNInput, err)
49	} else {
50		require.Nil(t, err)
51	}
52}
53
54func testRangeNegative(t *testing.T, desc *metric.Descriptor) {
55	var neg, pos number.Number
56
57	if desc.NumberKind() == number.Float64Kind {
58		pos = number.NewFloat64Number(+1)
59		neg = number.NewFloat64Number(-1)
60	} else {
61		pos = number.NewInt64Number(+1)
62		neg = number.NewInt64Number(-1)
63	}
64
65	posErr := aggregator.RangeTest(pos, desc)
66	negErr := aggregator.RangeTest(neg, desc)
67
68	require.Nil(t, posErr)
69	require.Equal(t, negErr, aggregation.ErrNegativeInput)
70}
71
72func TestRangeTest(t *testing.T) {
73	// Only Counters implement a range test.
74	for _, nkind := range []number.Kind{number.Float64Kind, number.Int64Kind} {
75		t.Run(nkind.String(), func(t *testing.T) {
76			desc := metric.NewDescriptor(
77				"name",
78				metric.CounterInstrumentKind,
79				nkind,
80			)
81			testRangeNegative(t, &desc)
82		})
83	}
84}
85
86func TestNaNTest(t *testing.T) {
87	for _, nkind := range []number.Kind{number.Float64Kind, number.Int64Kind} {
88		t.Run(nkind.String(), func(t *testing.T) {
89			for _, mkind := range []metric.InstrumentKind{
90				metric.CounterInstrumentKind,
91				metric.ValueRecorderInstrumentKind,
92				metric.ValueObserverInstrumentKind,
93			} {
94				desc := metric.NewDescriptor(
95					"name",
96					mkind,
97					nkind,
98				)
99				testRangeNaN(t, &desc)
100			}
101		})
102	}
103}
104