mirror of
https://github.com/hanzoai/oxy.git
synced 2026-09-30 23:42:31 +00:00
154 lines
3.7 KiB
Go
154 lines
3.7 KiB
Go
package memmetrics
|
|
|
|
import (
|
|
"runtime"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"github.com/vulcand/oxy/v2/internal/holsterv4/clock"
|
|
"github.com/vulcand/oxy/v2/testutils"
|
|
)
|
|
|
|
func TestNewRTMetrics_defaults(t *testing.T) {
|
|
testutils.FreezeTime(t)
|
|
|
|
rr, err := NewRTMetrics()
|
|
require.NoError(t, err)
|
|
require.NotNil(t, rr)
|
|
|
|
rr.Record(200, clock.Second)
|
|
rr.Record(502, 2*clock.Second)
|
|
rr.Record(200, clock.Second)
|
|
rr.Record(200, clock.Second)
|
|
|
|
assert.EqualValues(t, 1, rr.NetworkErrorCount())
|
|
assert.EqualValues(t, 4, rr.TotalCount())
|
|
assert.Equal(t, map[int]int64{502: 1, 200: 3}, rr.StatusCodesCounts())
|
|
assert.Equal(t, float64(1)/float64(4), rr.NetworkErrorRatio())
|
|
assert.Equal(t, 1.0/3.0, rr.ResponseCodeRatio(500, 503, 200, 300))
|
|
|
|
h, err := rr.LatencyHistogram()
|
|
require.NoError(t, err)
|
|
assert.Equal(t, 2, int(h.LatencyAtQuantile(100)/clock.Second))
|
|
|
|
rr.Reset()
|
|
assert.EqualValues(t, 0, rr.NetworkErrorCount())
|
|
assert.EqualValues(t, 0, rr.TotalCount())
|
|
assert.Equal(t, map[int]int64{}, rr.StatusCodesCounts())
|
|
assert.Equal(t, float64(0), rr.NetworkErrorRatio())
|
|
assert.Equal(t, float64(0), rr.ResponseCodeRatio(500, 503, 200, 300))
|
|
|
|
h, err = rr.LatencyHistogram()
|
|
require.NoError(t, err)
|
|
assert.Equal(t, time.Duration(0), h.LatencyAtQuantile(100))
|
|
}
|
|
|
|
func TestRTMetrics_Append(t *testing.T) {
|
|
testutils.FreezeTime(t)
|
|
|
|
rr, err := NewRTMetrics()
|
|
require.NoError(t, err)
|
|
require.NotNil(t, rr)
|
|
|
|
rr.Record(200, clock.Second)
|
|
rr.Record(502, 2*clock.Second)
|
|
rr.Record(200, clock.Second)
|
|
rr.Record(200, clock.Second)
|
|
|
|
rr2, err := NewRTMetrics()
|
|
require.NoError(t, err)
|
|
require.NotNil(t, rr2)
|
|
|
|
rr2.Record(200, 3*clock.Second)
|
|
rr2.Record(501, 3*clock.Second)
|
|
rr2.Record(200, 3*clock.Second)
|
|
rr2.Record(200, 3*clock.Second)
|
|
|
|
require.NoError(t, rr2.Append(rr))
|
|
assert.Equal(t, map[int]int64{501: 1, 502: 1, 200: 6}, rr2.StatusCodesCounts())
|
|
assert.EqualValues(t, 1, rr2.NetworkErrorCount())
|
|
|
|
h, err := rr2.LatencyHistogram()
|
|
require.NoError(t, err)
|
|
assert.EqualValues(t, 3, h.LatencyAtQuantile(100)/clock.Second)
|
|
}
|
|
|
|
func TestRTMetrics_concurrentRecords(t *testing.T) {
|
|
// This test asserts a race condition which requires parallelism
|
|
runtime.GOMAXPROCS(100)
|
|
|
|
rr, err := NewRTMetrics()
|
|
require.NoError(t, err)
|
|
|
|
for code := range 100 {
|
|
for range 10 {
|
|
go func(statusCode int) {
|
|
_ = rr.recordStatusCode(statusCode)
|
|
}(code)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestRTMetric_Export_returnsNewCopy(t *testing.T) {
|
|
a := RTMetrics{
|
|
statusCodes: map[int]*RollingCounter{},
|
|
statusCodesLock: sync.RWMutex{},
|
|
histogram: &RollingHDRHistogram{},
|
|
histogramLock: sync.RWMutex{},
|
|
}
|
|
|
|
var err error
|
|
|
|
a.total, err = NewCounter(1, clock.Second)
|
|
require.NoError(t, err)
|
|
|
|
a.netErrors, err = NewCounter(1, clock.Second)
|
|
require.NoError(t, err)
|
|
|
|
a.newCounter = func() (*RollingCounter, error) {
|
|
return NewCounter(counterBuckets, counterResolution)
|
|
}
|
|
a.newHist = func() (*RollingHDRHistogram, error) {
|
|
return NewRollingHDRHistogram(histMin, histMax, histSignificantFigures, histPeriod, histBuckets)
|
|
}
|
|
|
|
b := a.Export()
|
|
a.total = nil
|
|
a.netErrors = nil
|
|
a.statusCodes = nil
|
|
a.histogram = nil
|
|
a.newCounter = nil
|
|
a.newHist = nil
|
|
|
|
assert.NotNil(t, b.total)
|
|
assert.NotNil(t, b.netErrors)
|
|
assert.NotNil(t, b.statusCodes)
|
|
assert.NotNil(t, b.histogram)
|
|
assert.NotNil(t, b.newCounter)
|
|
assert.NotNil(t, b.newHist)
|
|
|
|
// a and b should have different locks
|
|
locksSucceed := make(chan bool)
|
|
|
|
go func() {
|
|
a.statusCodesLock.Lock()
|
|
b.statusCodesLock.Lock()
|
|
a.histogramLock.Lock()
|
|
b.histogramLock.Lock()
|
|
|
|
locksSucceed <- true
|
|
}()
|
|
|
|
for {
|
|
select {
|
|
case <-locksSucceed:
|
|
return
|
|
case <-clock.After(10 * clock.Second):
|
|
t.FailNow()
|
|
}
|
|
}
|
|
}
|