...

Source file src/github.com/go-kit/kit/metrics/teststat/teststat.go

Documentation: github.com/go-kit/kit/metrics/teststat

     1  // Package teststat provides helpers for testing metrics backends.
     2  package teststat
     3  
     4  import (
     5  	"errors"
     6  	"fmt"
     7  	"math"
     8  	"math/rand"
     9  	"reflect"
    10  	"sort"
    11  	"strings"
    12  
    13  	"github.com/go-kit/kit/metrics"
    14  )
    15  
    16  // TestCounter puts some deltas through the counter, and then calls the value
    17  // func to check that the counter has the correct final value.
    18  func TestCounter(counter metrics.Counter, value func() float64) error {
    19  	want := FillCounter(counter)
    20  	if have := value(); want != have {
    21  		return fmt.Errorf("want %f, have %f", want, have)
    22  	}
    23  
    24  	return nil
    25  }
    26  
    27  // FillCounter puts some deltas through the counter and returns the total value.
    28  func FillCounter(counter metrics.Counter) float64 {
    29  	a := rand.Perm(100)
    30  	n := rand.Intn(len(a))
    31  
    32  	var want float64
    33  	for i := 0; i < n; i++ {
    34  		f := float64(a[i])
    35  		counter.Add(f)
    36  		want += f
    37  	}
    38  	return want
    39  }
    40  
    41  // TestGauge puts some values through the gauge, and then calls the value func
    42  // to check that the gauge has the correct final value.
    43  func TestGauge(gauge metrics.Gauge, value func() []float64) error {
    44  	a := rand.Perm(100)
    45  	n := rand.Intn(len(a))
    46  
    47  	var want []float64
    48  	for i := 0; i < n; i++ {
    49  		f := float64(a[i])
    50  		gauge.Set(f)
    51  		want = append(want, f)
    52  	}
    53  
    54  	for i := 0; i < n; i++ {
    55  		f := float64(a[i])
    56  		gauge.Add(f)
    57  		want = append(want, want[len(want)-1]+f)
    58  	}
    59  
    60  	have := value()
    61  
    62  	switch len(have) {
    63  	case 0:
    64  		return fmt.Errorf("got 0 values")
    65  	case 1: // provider doesn't support multi value
    66  		if have[0] != want[len(want)-1] {
    67  			return fmt.Errorf("want %f, have %f", want, have)
    68  		}
    69  	default: // provider support multi value gauges
    70  		sort.Float64s(want)
    71  		sort.Float64s(have)
    72  		if !reflect.DeepEqual(want, have) {
    73  			return fmt.Errorf("want %f, have %f", want, have)
    74  		}
    75  	}
    76  
    77  	return nil
    78  }
    79  
    80  // TestHistogram puts some observations through the histogram, and then calls
    81  // the quantiles func to checks that the histogram has computed the correct
    82  // quantiles within some tolerance
    83  func TestHistogram(histogram metrics.Histogram, quantiles func() (p50, p90, p95, p99 float64), tolerance float64) error {
    84  	PopulateNormalHistogram(histogram, rand.Int())
    85  
    86  	want50, want90, want95, want99 := normalQuantiles()
    87  	have50, have90, have95, have99 := quantiles()
    88  
    89  	var errs []string
    90  	if want, have := want50, have50; !cmp(want, have, tolerance) {
    91  		errs = append(errs, fmt.Sprintf("p50: want %f, have %f", want, have))
    92  	}
    93  	if want, have := want90, have90; !cmp(want, have, tolerance) {
    94  		errs = append(errs, fmt.Sprintf("p90: want %f, have %f", want, have))
    95  	}
    96  	if want, have := want95, have95; !cmp(want, have, tolerance) {
    97  		errs = append(errs, fmt.Sprintf("p95: want %f, have %f", want, have))
    98  	}
    99  	if want, have := want99, have99; !cmp(want, have, tolerance) {
   100  		errs = append(errs, fmt.Sprintf("p99: want %f, have %f", want, have))
   101  	}
   102  	if len(errs) > 0 {
   103  		return errors.New(strings.Join(errs, "; "))
   104  	}
   105  
   106  	return nil
   107  }
   108  
   109  var (
   110  	// Count is the number of observations.
   111  	Count = 12345
   112  
   113  	// Mean is the center of the normal distribution of observations.
   114  	Mean = 500
   115  
   116  	// Stdev of the normal distribution of observations.
   117  	Stdev = 25
   118  )
   119  
   120  // ExpectedObservationsLessThan returns the number of observations that should
   121  // have a value less than or equal to the given value, given a normal
   122  // distribution of observations described by Count, Mean, and Stdev.
   123  func ExpectedObservationsLessThan(bucket int64) int64 {
   124  	// https://code.google.com/p/gostat/source/browse/stat/normal.go
   125  	cdf := ((1.0 / 2.0) * (1 + math.Erf((float64(bucket)-float64(Mean))/(float64(Stdev)*math.Sqrt2))))
   126  	return int64(cdf * float64(Count))
   127  }
   128  
   129  func cmp(want, have, tol float64) bool {
   130  	if (math.Abs(want-have) / want) > tol {
   131  		return false
   132  	}
   133  	return true
   134  }
   135  

View as plain text