blob: 1e50eeb3fd9110059affff3afd099e8d82162556 [file] [log] [blame]
package events
import (
"context"
"os"
"testing"
"time"
"github.com/stretchr/testify/require"
bt_testutil "go.skia.org/infra/go/bt/testutil"
"go.skia.org/infra/go/testutils"
)
func TestAggregateMetric(t *testing.T) {
tmp, err := os.MkdirTemp("", "")
require.NoError(t, err)
defer testutils.RemoveAll(t, tmp)
project, instance, cleanup := bt_testutil.SetupBigTable(t, BT_TABLE, BT_COLUMN_FAMILY)
defer cleanup()
db, err := NewBTEventDB(context.Background(), project, instance, nil)
require.NoError(t, err)
m, err := NewEventMetrics(db, "test-metrics")
require.NoError(t, err)
s := "my-events"
now := time.Now()
k1 := now.Add(-3 * time.Second)
v1 := 0.05
require.NoError(t, m.db.Insert(&Event{
Stream: s,
Timestamp: k1,
Data: encodeEvent(v1),
}))
period := 20 * time.Minute
called := false
require.NoError(t, m.AggregateMetric(s, nil, period, func(vs []*Event) (float64, error) {
called = true
require.Equal(t, 1, len(vs))
require.Equal(t, v1, decodeEvent(vs[0].Data))
return 0.0, nil
}))
require.False(t, called)
require.NoError(t, m.updateMetrics(now))
require.True(t, called)
}
func TestDynamicMetric(t *testing.T) {
tmp, err := os.MkdirTemp("", "")
require.NoError(t, err)
defer testutils.RemoveAll(t, tmp)
project, instance, cleanup := bt_testutil.SetupBigTable(t, BT_TABLE, BT_COLUMN_FAMILY)
defer cleanup()
db, err := NewBTEventDB(context.Background(), project, instance, nil)
require.NoError(t, err)
m, err := NewEventMetrics(db, "test-dynamic-metrics")
require.NoError(t, err)
s := "my-events"
now := time.Now()
k := now.Add(-5 * 20 * time.Minute)
for i := 0; i < 20; i++ {
v := 0.05 * float64(i)
require.NoError(t, m.db.Insert(&Event{
Stream: s,
Timestamp: k,
Data: encodeEvent(v),
}))
k = k.Add(5 * time.Minute)
}
period := 100 * time.Minute
require.NoError(t, m.DynamicMetric(s, nil, period, func(vs []*Event) ([]map[string]string, []float64, error) {
tags := []map[string]string{}
vals := []float64{}
for _, e := range vs {
t := map[string]string{}
v := decodeEvent(e.Data)
if v >= 0.5 {
t["category"] = "large"
} else {
t["category"] = "small"
}
tags = append(tags, t)
vals = append(vals, v)
}
return tags, vals, nil
}))
require.NoError(t, m.updateMetrics(now))
// Ensure that we got the right dynamic metrics.
require.Equal(t, 2, len(m.currentDynamicMetrics))
// Wait for the "small" events to scroll off, ensure that we deleted the
// old metric.
t1 := now.Add(50 * time.Minute)
require.NoError(t, m.updateMetrics(t1))
require.Equal(t, 1, len(m.currentDynamicMetrics))
}
func TestMean(t *testing.T) {
test := func(name string, input []float64, expect float64) {
t.Run(name, func(t *testing.T) {
require.Equal(t, expect, mean(input))
})
}
test("empty", []float64{}, 0.0)
test("singleValue", []float64{1.0}, 1.0)
test("multipleValues", []float64{1.0, 2.0, 3.0, 4.0}, 2.5)
}
func TestVariance(t *testing.T) {
test := func(name string, input []float64, expect float64) {
t.Run(name, func(t *testing.T) {
require.Equal(t, expect, variance(input))
})
}
test("empty", []float64{}, 0.0)
test("singleValue", []float64{1.0}, 0.0)
test("multipleValues", []float64{1.0, 2.0, 3.0, 4.0}, 1.25)
}
func TestPercentile(t *testing.T) {
test := func(name string, input []float64, percent, expect float64) {
t.Run(name, func(t *testing.T) {
require.Equal(t, expect, percentile(input, percent))
})
}
test("empty", []float64{}, 0.5, 0.0)
test("singleValue", []float64{1.0}, 0.5, 1.0)
test("twoValues", []float64{1.0, 2.0}, 0.5, 1.5)
test("fourValues", []float64{1.0, 2.0, 3.0, 4.0}, 0.5, 2.5)
test("fiveValues", []float64{1.0, 2.0, 3.0, 4.0, 5.0}, 0.5, 3.0)
test("tenValues_fiftieth", []float64{1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0}, 0.5, 5.5)
test("tenValues_ninetieth", []float64{1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0}, 0.9, 9.1)
test("tenValues_fifth", []float64{1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0}, 0.05, 1.45)
}