From f95dcbca4feca078b38ae03082b317202630c2fa Mon Sep 17 00:00:00 2001 From: Eshaan Aggarwal <96648934+EshaanAgg@users.noreply.github.com> Date: Thu, 25 Jan 2024 15:04:32 +0530 Subject: [PATCH] tests: increase coverage for multiple files in `vitess/go/stats` to 100% (#14997) Signed-off-by: Eshaan Aggarwal <96648934+EshaanAgg@users.noreply.github.com> --- go/stats/histogram.go | 5 ++ go/stats/histogram_test.go | 102 ++++++++++++++++++-------- go/stats/hooks_test.go | 58 +++++++++++++++ go/stats/ring_test.go | 43 +++++++++++ go/stats/snake_case_converter_test.go | 2 +- 5 files changed, 179 insertions(+), 31 deletions(-) create mode 100644 go/stats/hooks_test.go create mode 100644 go/stats/ring_test.go diff --git a/go/stats/histogram.go b/go/stats/histogram.go index 833c09b86bb..4a51098d606 100644 --- a/go/stats/histogram.go +++ b/go/stats/histogram.go @@ -74,6 +74,11 @@ func NewGenericHistogram(name, help string, cutoffs []int64, labels []string, co return h } +// Adds a hook that will be called every time a new value is added to the histogram +func (h *Histogram) AddHook(hook func(int64)) { + h.hook = hook +} + // Add adds a new measurement to the Histogram. func (h *Histogram) Add(value int64) { for i := range h.labels { diff --git a/go/stats/histogram_test.go b/go/stats/histogram_test.go index 1c7b05d8e9a..caa2a6ba722 100644 --- a/go/stats/histogram_test.go +++ b/go/stats/histogram_test.go @@ -19,6 +19,8 @@ package stats import ( "expvar" "testing" + + "github.com/stretchr/testify/assert" ) func TestHistogram(t *testing.T) { @@ -27,30 +29,28 @@ func TestHistogram(t *testing.T) { for i := 0; i < 10; i++ { h.Add(int64(i)) } - want := `{"1": 2, "5": 4, "inf": 4, "Count": 10, "Total": 45}` - if h.String() != want { - t.Errorf("got %v, want %v", h.String(), want) - } + + assert.Equal(t, h.String(), `{"1": 2, "5": 4, "inf": 4, "Count": 10, "Total": 45}`) + counts := h.Counts() counts["Count"] = h.Count() counts["Total"] = h.Total() - for k, want := range map[string]int64{ + for key, want := range map[string]int64{ "1": 2, "5": 4, "inf": 4, "Count": 10, "Total": 45, } { - if got := counts[k]; got != want { - t.Errorf("histogram counts [%v]: got %d, want %d", k, got, want) - } - } - if got, want := h.CountLabel(), "Count"; got != want { - t.Errorf("got %v, want %v", got, want) - } - if got, want := h.TotalLabel(), "Total"; got != want { - t.Errorf("got %v, want %v", got, want) + assert.Equal(t, counts[key], want) } + + assert.Equal(t, h.CountLabel(), "Count") + assert.Equal(t, h.TotalLabel(), "Total") + assert.Equal(t, h.Labels(), []string{"1", "5", "inf"}) + assert.Equal(t, h.Cutoffs(), []int64{1, 5}) + assert.Equal(t, h.Buckets(), []int64{2, 4, 4}) + assert.Equal(t, h.Help(), "help") } func TestGenericHistogram(t *testing.T) { @@ -63,27 +63,69 @@ func TestGenericHistogram(t *testing.T) { "count", "total", ) - want := `{"one": 0, "five": 0, "max": 0, "count": 0, "total": 0}` - if got := h.String(); got != want { - t.Errorf("got %v, want %v", got, want) - } + assert.Equal(t, h.String(), `{"one": 0, "five": 0, "max": 0, "count": 0, "total": 0}`) +} + +func TestInvalidGenericHistogram(t *testing.T) { + // Use a deferred function to capture the panic that the code should throw + defer func() { + r := recover() + assert.NotNil(t, r) + assert.Equal(t, r, "mismatched cutoff and label lengths") + }() + + clearStats() + NewGenericHistogram( + "histgen", + "help", + []int64{1, 5}, + []string{"one", "five"}, + "count", + "total", + ) } func TestHistogramHook(t *testing.T) { - var gotname string - var gotv *Histogram + // Check the results of Register hook function + var gotName string + var gotV *Histogram clearStats() Register(func(name string, v expvar.Var) { - gotname = name - gotv = v.(*Histogram) + gotName = name + gotV = v.(*Histogram) }) - name := "hist2" - v := NewHistogram(name, "help", []int64{1}) - if gotname != name { - t.Errorf("got %v; want %v", gotname, name) - } - if gotv != v { - t.Errorf("got %#v, want %#v", gotv, v) - } + v := NewHistogram("hist2", "help", []int64{1}) + + assert.Equal(t, gotName, "hist2") + assert.Equal(t, gotV, v) + + // Check the results of AddHook function + hookCalled := false + var addedValue int64 + + v.AddHook(func(value int64) { + hookCalled = true + addedValue = value + }) + + v.Add(42) + assert.Equal(t, hookCalled, true) + assert.Equal(t, addedValue, int64(42)) + + // Check the results of RegisterHistogramHook function + hookCalled = false + addedValue = 0 + gotName = "" + + RegisterHistogramHook(func(name string, value int64) { + hookCalled = true + gotName = name + addedValue = value + }) + + v.Add(10) + assert.Equal(t, gotName, "hist2") + assert.Equal(t, hookCalled, true) + assert.Equal(t, addedValue, int64(10)) } diff --git a/go/stats/hooks_test.go b/go/stats/hooks_test.go new file mode 100644 index 00000000000..72b6d1071c7 --- /dev/null +++ b/go/stats/hooks_test.go @@ -0,0 +1,58 @@ +/* +Copyright 2024 The Vitess 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 stats + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestStatsdHook(t *testing.T) { + t.Run("RegisterTimerHook", func(t *testing.T) { + defaultStatsdHook = statsdHook{} + + // Create a dummy timerHook function + dummyTimerHook := func(name, tags string, value int64, timings *Timings) { + assert.Equal(t, "dummyName", name) + assert.Equal(t, "dummyTags", tags) + assert.Equal(t, int64(42), value) + } + + // Register the dummy timerHook and then call the same + RegisterTimerHook(dummyTimerHook) + + assert.NotNil(t, defaultStatsdHook.timerHook) + assert.Nil(t, defaultStatsdHook.histogramHook) + defaultStatsdHook.timerHook("dummyName", "dummyTags", 42, nil) + }) + + t.Run("RegisterHistogramHook", func(t *testing.T) { + defaultStatsdHook = statsdHook{} + + // Create a dummy histogramHook function + dummyHistogramHook := func(name string, value int64) { + assert.Equal(t, "dummyName", name) + assert.Equal(t, int64(42), value) + } + + RegisterHistogramHook(dummyHistogramHook) + + assert.NotNil(t, defaultStatsdHook.histogramHook) + assert.Nil(t, defaultStatsdHook.timerHook) + defaultStatsdHook.histogramHook("dummyName", 42) + }) +} diff --git a/go/stats/ring_test.go b/go/stats/ring_test.go new file mode 100644 index 00000000000..d6f8ddb73af --- /dev/null +++ b/go/stats/ring_test.go @@ -0,0 +1,43 @@ +/* +Copyright 2024 The Vitess 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 stats + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestRingInt64(t *testing.T) { + t.Run("Add Values", func(t *testing.T) { + ri := NewRingInt64(3) + ri.Add(1) + ri.Add(2) + ri.Add(3) + + assert.Equal(t, []int64{1, 2, 3}, ri.Values()) + + ri.Add(4) + ri.Add(5) + assert.Equal(t, []int64{3, 4, 5}, ri.Values()) + }) + + t.Run("Empty Ring", func(t *testing.T) { + ri := NewRingInt64(3) + assert.Empty(t, ri.Values()) + }) +} diff --git a/go/stats/snake_case_converter_test.go b/go/stats/snake_case_converter_test.go index 2552ade8df3..c8a3892020e 100644 --- a/go/stats/snake_case_converter_test.go +++ b/go/stats/snake_case_converter_test.go @@ -36,7 +36,7 @@ func TestToSnakeCase(t *testing.T) { } for _, tt := range snakeCaseTest { - if got, want := toSnakeCase(tt.input), tt.output; got != want { + if got, want := GetSnakeName(tt.input), tt.output; got != want { t.Errorf("want '%s', got '%s'", want, got) } }