mirror of
https://github.com/prometheus/statsd_exporter.git
synced 2025-01-21 20:08:07 +00:00
a125dac85b
Signed-off-by: Pedro Tanaka <pedro.tanaka@shopify.com>
272 lines
7.4 KiB
Go
272 lines
7.4 KiB
Go
// Copyright 2013 The Prometheus Authors
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package event
|
|
|
|
import (
|
|
"reflect"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/prometheus/client_golang/prometheus"
|
|
"github.com/prometheus/statsd_exporter/pkg/clock"
|
|
"github.com/prometheus/statsd_exporter/pkg/mapper"
|
|
)
|
|
|
|
var eventsFlushed = prometheus.NewCounter(
|
|
prometheus.CounterOpts{
|
|
Name: "statsd_exporter_event_queue_flushed_total",
|
|
Help: "Number of times events were flushed to exporter",
|
|
},
|
|
)
|
|
|
|
func TestEventThresholdFlush(t *testing.T) {
|
|
c := make(chan Events, 100)
|
|
// We're not going to flush during this test, so the duration doesn't matter.
|
|
eq := NewEventQueue(c, 5, time.Second, eventsFlushed)
|
|
e := make(Events, 13)
|
|
go func() {
|
|
eq.Queue(e)
|
|
}()
|
|
|
|
batch := <-c
|
|
if len(batch) != 5 {
|
|
t.Fatalf("Expected event batch to be 5 elements, but got %v", len(batch))
|
|
}
|
|
batch = <-c
|
|
if len(batch) != 5 {
|
|
t.Fatalf("Expected event batch to be 5 elements, but got %v", len(batch))
|
|
}
|
|
batch = <-c
|
|
if len(batch) != 3 {
|
|
t.Fatalf("Expected event batch to be 3 elements, but got %v", len(batch))
|
|
}
|
|
}
|
|
|
|
func TestEventIntervalFlush(t *testing.T) {
|
|
// Mock a time.NewTicker
|
|
tickerCh := make(chan time.Time)
|
|
clock.ClockInstance = &clock.Clock{
|
|
TickerCh: tickerCh,
|
|
}
|
|
clock.ClockInstance.Instant = time.Unix(0, 0)
|
|
|
|
c := make(chan Events, 100)
|
|
eq := NewEventQueue(c, 1000, time.Second*1000, eventsFlushed)
|
|
e := make(Events, 10)
|
|
eq.Queue(e)
|
|
|
|
if eq.Len() != 10 {
|
|
t.Fatal("Expected 10 events to be queued, but got", eq.Len())
|
|
}
|
|
|
|
if len(eq.C) != 0 {
|
|
t.Fatal("Expected 0 events in the event channel, but got", len(eq.C))
|
|
}
|
|
|
|
// Tick time forward to trigger a flush
|
|
clock.ClockInstance.Instant = time.Unix(10000, 0)
|
|
clock.ClockInstance.TickerCh <- time.Unix(10000, 0)
|
|
|
|
events := <-eq.C
|
|
if eq.Len() != 0 {
|
|
t.Fatal("Expected 0 events to be queued, but got", eq.Len())
|
|
}
|
|
|
|
if len(events) != 10 {
|
|
t.Fatal("Expected 10 events in the event channel, but got", len(events))
|
|
}
|
|
}
|
|
|
|
func TestMultiValueEvent(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
event MultiValueEvent
|
|
wantValues []float64
|
|
wantName string
|
|
wantType mapper.MetricType
|
|
wantLabels map[string]string
|
|
}{
|
|
{
|
|
name: "MultiObserverEvent with single value",
|
|
event: &MultiObserverEvent{
|
|
OMetricName: "test_metric",
|
|
OValues: []float64{1.0},
|
|
OLabels: map[string]string{"label": "value"},
|
|
SampleRate: 0,
|
|
},
|
|
wantValues: []float64{1.0},
|
|
wantName: "test_metric",
|
|
wantType: mapper.MetricTypeObserver,
|
|
wantLabels: map[string]string{"label": "value"},
|
|
},
|
|
{
|
|
name: "MultiObserverEvent with multiple values",
|
|
event: &MultiObserverEvent{
|
|
OMetricName: "test_metric",
|
|
OValues: []float64{1.0, 2.0, 3.0},
|
|
OLabels: map[string]string{"label": "value"},
|
|
SampleRate: 0.5,
|
|
},
|
|
wantValues: []float64{1.0, 2.0, 3.0},
|
|
wantName: "test_metric",
|
|
wantType: mapper.MetricTypeObserver,
|
|
wantLabels: map[string]string{"label": "value"},
|
|
},
|
|
{
|
|
name: "CounterEvent implements MultiValueEvent",
|
|
event: &CounterEvent{
|
|
CMetricName: "test_counter",
|
|
CValue: 42.0,
|
|
CLabels: map[string]string{"label": "value"},
|
|
},
|
|
wantValues: []float64{42.0},
|
|
wantName: "test_counter",
|
|
wantType: mapper.MetricTypeCounter,
|
|
wantLabels: map[string]string{"label": "value"},
|
|
},
|
|
{
|
|
name: "GaugeEvent implements MultiValueEvent",
|
|
event: &GaugeEvent{
|
|
GMetricName: "test_gauge",
|
|
GValue: 123.0,
|
|
GLabels: map[string]string{"label": "value"},
|
|
},
|
|
wantValues: []float64{123.0},
|
|
wantName: "test_gauge",
|
|
wantType: mapper.MetricTypeGauge,
|
|
wantLabels: map[string]string{"label": "value"},
|
|
},
|
|
{
|
|
name: "ObserverEvent implements MultiValueEvent",
|
|
event: &ObserverEvent{
|
|
OMetricName: "test_observer",
|
|
OValue: 99.0,
|
|
OLabels: map[string]string{"label": "value"},
|
|
},
|
|
wantValues: []float64{99.0},
|
|
wantName: "test_observer",
|
|
wantType: mapper.MetricTypeObserver,
|
|
wantLabels: map[string]string{"label": "value"},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if got := tt.event.Values(); !reflect.DeepEqual(got, tt.wantValues) {
|
|
t.Errorf("MultiValueEvent.Values() = %v, want %v", got, tt.wantValues)
|
|
}
|
|
if got := tt.event.MetricName(); got != tt.wantName {
|
|
t.Errorf("MultiValueEvent.MetricName() = %v, want %v", got, tt.wantName)
|
|
}
|
|
if got := tt.event.MetricType(); got != tt.wantType {
|
|
t.Errorf("MultiValueEvent.MetricType() = %v, want %v", got, tt.wantType)
|
|
}
|
|
if got := tt.event.Labels(); !reflect.DeepEqual(got, tt.wantLabels) {
|
|
t.Errorf("MultiValueEvent.Labels() = %v, want %v", got, tt.wantLabels)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestMultiObserverEvent_Expand(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
event *MultiObserverEvent
|
|
wantEvents []Event
|
|
}{
|
|
{
|
|
name: "single value no sampling",
|
|
event: &MultiObserverEvent{
|
|
OMetricName: "test_metric",
|
|
OValues: []float64{1.0},
|
|
OLabels: map[string]string{"label": "value"},
|
|
SampleRate: 0,
|
|
},
|
|
wantEvents: []Event{
|
|
&MultiObserverEvent{
|
|
OMetricName: "test_metric",
|
|
OValues: []float64{1.0},
|
|
OLabels: map[string]string{"label": "value"},
|
|
SampleRate: 0,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "multiple values no sampling",
|
|
event: &MultiObserverEvent{
|
|
OMetricName: "test_metric",
|
|
OValues: []float64{1.0, 2.0, 3.0},
|
|
OLabels: map[string]string{"label": "value"},
|
|
SampleRate: 0,
|
|
},
|
|
wantEvents: []Event{
|
|
&ObserverEvent{
|
|
OMetricName: "test_metric",
|
|
OValue: 1.0,
|
|
OLabels: map[string]string{"label": "value"},
|
|
},
|
|
&ObserverEvent{
|
|
OMetricName: "test_metric",
|
|
OValue: 2.0,
|
|
OLabels: map[string]string{"label": "value"},
|
|
},
|
|
&ObserverEvent{
|
|
OMetricName: "test_metric",
|
|
OValue: 3.0,
|
|
OLabels: map[string]string{"label": "value"},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "multiple values with sampling",
|
|
event: &MultiObserverEvent{
|
|
OMetricName: "test_metric",
|
|
OValues: []float64{1.0, 2.0},
|
|
OLabels: map[string]string{"label": "value"},
|
|
SampleRate: 0.5,
|
|
},
|
|
wantEvents: []Event{
|
|
&ObserverEvent{
|
|
OMetricName: "test_metric",
|
|
OValue: 1.0,
|
|
OLabels: map[string]string{"label": "value"},
|
|
},
|
|
&ObserverEvent{
|
|
OMetricName: "test_metric",
|
|
OValue: 2.0,
|
|
OLabels: map[string]string{"label": "value"},
|
|
},
|
|
&ObserverEvent{
|
|
OMetricName: "test_metric",
|
|
OValue: 1.0,
|
|
OLabels: map[string]string{"label": "value"},
|
|
},
|
|
&ObserverEvent{
|
|
OMetricName: "test_metric",
|
|
OValue: 2.0,
|
|
OLabels: map[string]string{"label": "value"},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got := tt.event.Expand()
|
|
if !reflect.DeepEqual(got, tt.wantEvents) {
|
|
t.Errorf("MultiObserverEvent.Expand() = %v, want %v", got, tt.wantEvents)
|
|
}
|
|
})
|
|
}
|
|
}
|