featurebase/stats_test.go

346 lines
10 KiB
Go

package pilosa_test
import (
"context"
"io"
"io/ioutil"
"net/http"
"strings"
"testing"
"time"
"github.com/pilosa/pilosa"
"github.com/pilosa/pilosa/test"
)
// TestMultiStatClient_Expvar run the multistat client with exp var
// since the EXPVAR data is stored in a global we should run these in one test function
func TestMultiStatClient_Expvar(t *testing.T) {
hldr := test.MustOpenHolder()
defer hldr.Close()
c := pilosa.NewExpvarStatsClient()
ms := make(pilosa.MultiStatsClient, 1)
ms[0] = c
hldr.Stats = ms
hldr.Stats.SetLogger(ioutil.Discard)
hldr.MustCreateFragmentIfNotExists("d", "f", pilosa.ViewStandard, 0).SetBit(0, 0)
hldr.MustCreateFragmentIfNotExists("d", "f", pilosa.ViewStandard, 0).SetBit(0, 1)
hldr.MustCreateFragmentIfNotExists("d", "f", pilosa.ViewStandard, 1).SetBit(0, SliceWidth)
hldr.MustCreateFragmentIfNotExists("d", "f", pilosa.ViewStandard, 1).SetBit(0, SliceWidth+2)
hldr.MustCreateFragmentIfNotExists("d", "f", pilosa.ViewStandard, 0).ClearBit(0, 1)
if pilosa.Expvar.String() != `{"index:d": {"frame:f": {"view:standard": {"slice:0": {"clearBit": 1, "rows": 0, "setBit": 2}, "slice:1": {"rows": 0, "setBit": 2}}}}}` {
t.Fatalf("unexpected expvar : %s", pilosa.Expvar.String())
}
hldr.Stats.CountWithCustomTags("cc", 1, 1.0, []string{"foo:bar"})
if pilosa.Expvar.String() != `{"cc": 1, "index:d": {"frame:f": {"view:standard": {"slice:0": {"clearBit": 1, "rows": 0, "setBit": 2}, "slice:1": {"rows": 0, "setBit": 2}}}}}` {
t.Fatalf("unexpected expvar : %s", pilosa.Expvar.String())
}
// Gauge creates a unique key, subsequent Gauge calls will overwrite
hldr.Stats.Gauge("g", 5, 1.0)
hldr.Stats.Gauge("g", 8, 1.0)
if pilosa.Expvar.String() != `{"cc": 1, "g": 8, "index:d": {"frame:f": {"view:standard": {"slice:0": {"clearBit": 1, "rows": 0, "setBit": 2}, "slice:1": {"rows": 0, "setBit": 2}}}}}` {
t.Fatalf("unexpected expvar : %s", pilosa.Expvar.String())
}
// Set creates a unique key, subsequent sets will overwrite
hldr.Stats.Set("s", "4", 1.0)
hldr.Stats.Set("s", "7", 1.0)
if pilosa.Expvar.String() != `{"cc": 1, "g": 8, "index:d": {"frame:f": {"view:standard": {"slice:0": {"clearBit": 1, "rows": 0, "setBit": 2}, "slice:1": {"rows": 0, "setBit": 2}}}}, "s": "7"}` {
t.Fatalf("unexpected expvar : %s", pilosa.Expvar.String())
}
// Record timing duration and a uniquely Set key/value
dur, _ := time.ParseDuration("123us")
hldr.Stats.Timing("tt", dur, 1.0)
if pilosa.Expvar.String() != `{"cc": 1, "g": 8, "index:d": {"frame:f": {"view:standard": {"slice:0": {"clearBit": 1, "rows": 0, "setBit": 2}, "slice:1": {"rows": 0, "setBit": 2}}}}, "s": "7", "tt": 123µs}` {
t.Fatalf("unexpected expvar : %s", pilosa.Expvar.String())
}
// Expvar histogram is implemented as a gauge
hldr.Stats.Histogram("hh", 3, 1.0)
if pilosa.Expvar.String() != `{"cc": 1, "g": 8, "hh": 3, "index:d": {"frame:f": {"view:standard": {"slice:0": {"clearBit": 1, "rows": 0, "setBit": 2}, "slice:1": {"rows": 0, "setBit": 2}}}}, "s": "7", "tt": 123µs}` {
t.Fatalf("unexpected expvar : %s", pilosa.Expvar.String())
}
// Expvar should ignore earlier set tags from setbit
if hldr.Stats.Tags() != nil {
t.Fatalf("unexpected tag")
}
}
func TestStatsCount_TopN(t *testing.T) {
hldr := test.MustOpenHolder()
defer hldr.Close()
hldr.MustCreateFragmentIfNotExists("d", "f", pilosa.ViewStandard, 0).SetBit(0, 0)
hldr.MustCreateFragmentIfNotExists("d", "f", pilosa.ViewStandard, 0).SetBit(0, 1)
hldr.MustCreateFragmentIfNotExists("d", "f", pilosa.ViewStandard, 1).SetBit(0, SliceWidth)
hldr.MustCreateFragmentIfNotExists("d", "f", pilosa.ViewStandard, 1).SetBit(0, SliceWidth+2)
// Execute query.
called := false
e := test.NewExecutor(hldr.Holder, test.NewCluster(1))
e.Holder.Stats = &MockStats{
mockCountWithTags: func(name string, value int64, rate float64, tags []string) {
if name != "TopN" {
t.Errorf("Expected TopN, Results %s", name)
}
if tags[0] != "index:d" {
t.Errorf("Expected db, Results %s", tags[0])
}
called = true
return
},
}
if _, err := e.Execute(context.Background(), "d", test.MustParse(`TopN(frame=f, n=2)`), nil, nil); err != nil {
t.Fatal(err)
}
if !called {
t.Error("CountWithCustomTags name isn't called")
}
}
func TestStatsCount_Bitmap(t *testing.T) {
hldr := test.MustOpenHolder()
defer hldr.Close()
hldr.MustCreateFragmentIfNotExists("d", "f", pilosa.ViewStandard, 0).SetBit(0, 0)
hldr.MustCreateFragmentIfNotExists("d", "f", pilosa.ViewStandard, 0).SetBit(0, 1)
called := false
e := test.NewExecutor(hldr.Holder, test.NewCluster(1))
e.Holder.Stats = &MockStats{
mockCountWithTags: func(name string, value int64, rate float64, tags []string) {
if name != "Bitmap" {
t.Errorf("Expected Bitmap, Results %s", name)
}
if tags[0] != "index:d" {
t.Errorf("Expected db, Results %s", tags[0])
}
called = true
return
},
}
if _, err := e.Execute(context.Background(), "d", test.MustParse(`Bitmap(frame=f, rowID=0)`), nil, nil); err != nil {
t.Fatal(err)
}
if !called {
t.Error("CountWithCustomTags name isn't called")
}
}
func TestStatsCount_SetBitmapAttrs(t *testing.T) {
hldr := test.MustOpenHolder()
defer hldr.Close()
hldr.MustCreateFragmentIfNotExists("d", "f", pilosa.ViewStandard, 0).SetBit(10, 0)
hldr.MustCreateFragmentIfNotExists("d", "f", pilosa.ViewStandard, 0).SetBit(10, 1)
called := false
e := test.NewExecutor(hldr.Holder, test.NewCluster(1))
frame := e.Holder.Frame("d", "f")
if frame == nil {
t.Fatal("frame not found")
}
frame.Stats = &MockStats{
mockCount: func(name string, value int64, rate float64) {
if name != "SetBitmapAttrs" {
t.Errorf("Expected SetBitmapAttrs, Results %s", name)
}
called = true
return
},
}
if _, err := e.Execute(context.Background(), "d", test.MustParse(`SetRowAttrs(rowID=10, frame=f, foo="bar")`), nil, nil); err != nil {
t.Fatal(err)
}
if !called {
t.Error("Count isn't called")
}
}
func TestStatsCount_SetProfileAttrs(t *testing.T) {
hldr := test.MustOpenHolder()
defer hldr.Close()
hldr.MustCreateFragmentIfNotExists("d", "f", pilosa.ViewStandard, 0).SetBit(10, 0)
hldr.MustCreateFragmentIfNotExists("d", "f", pilosa.ViewStandard, 0).SetBit(10, 1)
called := false
e := test.NewExecutor(hldr.Holder, test.NewCluster(1))
idx := e.Holder.Index("d")
if idx == nil {
t.Fatal("idex not found")
}
idx.Stats = &MockStats{
mockCount: func(name string, value int64, rate float64) {
if name != "SetProfileAttrs" {
t.Errorf("Expected SetProfilepAttrs, Results %s", name)
}
called = true
return
},
}
if _, err := e.Execute(context.Background(), "d", test.MustParse(`SetColumnAttrs(id=10, frame=f, foo="bar")`), nil, nil); err != nil {
t.Fatal(err)
}
if !called {
t.Error("Count isn't called")
}
}
func TestStatsCount_CreateIndex(t *testing.T) {
hldr := test.MustOpenHolder()
defer hldr.Close()
s := test.NewServer()
s.Handler.Holder = hldr.Holder
defer s.Close()
called := false
s.Handler.Holder.Stats = &MockStats{
mockCount: func(name string, value int64, rate float64) {
if name != "createIndex" {
t.Errorf("Expected createIndex, Results %s", name)
}
called = true
return
},
}
http.DefaultClient.Do(test.MustNewHTTPRequest("POST", s.URL+"/index/i", nil))
if !called {
t.Error("Count isn't called")
}
}
func TestStatsCount_DeleteIndex(t *testing.T) {
hldr := test.MustOpenHolder()
defer hldr.Close()
s := test.NewServer()
s.Handler.Holder = hldr.Holder
defer s.Close()
// Create index.
if _, err := hldr.CreateIndexIfNotExists("i", pilosa.IndexOptions{}); err != nil {
t.Fatal(err)
}
called := false
s.Handler.Holder.Stats = &MockStats{
mockCount: func(name string, value int64, rate float64) {
if name != "deleteIndex" {
t.Errorf("Expected deleteIndex, Results %s", name)
}
called = true
return
},
}
http.DefaultClient.Do(test.MustNewHTTPRequest("DELETE", s.URL+"/index/i", strings.NewReader("")))
if !called {
t.Error("Count isn't called")
}
}
func TestStatsCount_CreateFrame(t *testing.T) {
hldr := test.MustOpenHolder()
defer hldr.Close()
s := test.NewServer()
s.Handler.Holder = hldr.Holder
defer s.Close()
// Create index.
if _, err := hldr.CreateIndexIfNotExists("i", pilosa.IndexOptions{}); err != nil {
t.Fatal(err)
}
called := false
s.Handler.Holder.Stats = &MockStats{
mockCountWithTags: func(name string, value int64, rate float64, index []string) {
if name != "createFrame" {
t.Errorf("Expected createFrame, Results %s", name)
}
if index[0] != "index:i" {
t.Errorf("Expected index:i, Results %s", index)
}
called = true
return
},
}
http.DefaultClient.Do(test.MustNewHTTPRequest("POST", s.URL+"/index/i/frame/f", nil))
if !called {
t.Error("Count isn't called")
}
}
func TestStatsCount_DeleteFrame(t *testing.T) {
hldr := test.MustOpenHolder()
defer hldr.Close()
s := test.NewServer()
s.Handler.Holder = hldr.Holder
defer s.Close()
called := false
// Create index.
indx, _ := hldr.CreateIndexIfNotExists("i", pilosa.IndexOptions{})
if _, err := indx.CreateFrameIfNotExists("test", pilosa.FrameOptions{}); err != nil {
t.Fatal(err)
}
s.Handler.Holder.Stats = &MockStats{
mockCountWithTags: func(name string, value int64, rate float64, index []string) {
if name != "deleteFrame" {
t.Errorf("Expected deleteFrame, Results %s", name)
}
if index[0] != "index:i" {
t.Errorf("Expected index:i, Results %s", index)
}
called = true
return
},
}
http.DefaultClient.Do(test.MustNewHTTPRequest("DELETE", s.URL+"/index/i/frame/f", strings.NewReader("")))
if !called {
t.Error("Count isn't called")
}
}
type MockStats struct {
mockCount func(name string, value int64, rate float64)
mockCountWithTags func(name string, value int64, rate float64, tags []string)
}
func (s *MockStats) Count(name string, value int64, rate float64) {
if s.mockCount != nil {
s.mockCount(name, value, rate)
return
}
return
}
func (s *MockStats) CountWithCustomTags(name string, value int64, rate float64, tags []string) {
if s.mockCountWithTags != nil {
s.mockCountWithTags(name, value, rate, tags)
return
}
return
}
func (c *MockStats) Tags() []string { return nil }
func (c *MockStats) WithTags(tags ...string) pilosa.StatsClient { return c }
func (c *MockStats) Gauge(name string, value float64, rate float64) {}
func (c *MockStats) Histogram(name string, value float64, rate float64) {}
func (c *MockStats) Set(name string, value string, rate float64) {}
func (c *MockStats) Timing(name string, value time.Duration, rate float64) {}
func (c *MockStats) SetLogger(logger io.Writer) {}