github.com/Andyfoo/golang/x/net@v0.0.0-20190901054642-57c1bf301704/internal/timeseries/timeseries_test.go (about)

     1  // Copyright 2015 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package timeseries
     6  
     7  import (
     8  	"math"
     9  	"testing"
    10  	"time"
    11  )
    12  
    13  func isNear(x *Float, y float64, tolerance float64) bool {
    14  	return math.Abs(x.Value()-y) < tolerance
    15  }
    16  
    17  func isApproximate(x *Float, y float64) bool {
    18  	return isNear(x, y, 1e-2)
    19  }
    20  
    21  func checkApproximate(t *testing.T, o Observable, y float64) {
    22  	x := o.(*Float)
    23  	if !isApproximate(x, y) {
    24  		t.Errorf("Wanted %g, got %g", y, x.Value())
    25  	}
    26  }
    27  
    28  func checkNear(t *testing.T, o Observable, y, tolerance float64) {
    29  	x := o.(*Float)
    30  	if !isNear(x, y, tolerance) {
    31  		t.Errorf("Wanted %g +- %g, got %g", y, tolerance, x.Value())
    32  	}
    33  }
    34  
    35  var baseTime = time.Date(2013, 1, 1, 0, 0, 0, 0, time.UTC)
    36  
    37  func tu(s int64) time.Time {
    38  	return baseTime.Add(time.Duration(s) * time.Second)
    39  }
    40  
    41  func tu2(s int64, ns int64) time.Time {
    42  	return baseTime.Add(time.Duration(s)*time.Second + time.Duration(ns)*time.Nanosecond)
    43  }
    44  
    45  func TestBasicTimeSeries(t *testing.T) {
    46  	ts := NewTimeSeries(NewFloat)
    47  	fo := new(Float)
    48  	*fo = Float(10)
    49  	ts.AddWithTime(fo, tu(1))
    50  	ts.AddWithTime(fo, tu(1))
    51  	ts.AddWithTime(fo, tu(1))
    52  	ts.AddWithTime(fo, tu(1))
    53  	checkApproximate(t, ts.Range(tu(0), tu(1)), 40)
    54  	checkApproximate(t, ts.Total(), 40)
    55  	ts.AddWithTime(fo, tu(3))
    56  	ts.AddWithTime(fo, tu(3))
    57  	ts.AddWithTime(fo, tu(3))
    58  	checkApproximate(t, ts.Range(tu(0), tu(2)), 40)
    59  	checkApproximate(t, ts.Range(tu(2), tu(4)), 30)
    60  	checkApproximate(t, ts.Total(), 70)
    61  	ts.AddWithTime(fo, tu(1))
    62  	ts.AddWithTime(fo, tu(1))
    63  	checkApproximate(t, ts.Range(tu(0), tu(2)), 60)
    64  	checkApproximate(t, ts.Range(tu(2), tu(4)), 30)
    65  	checkApproximate(t, ts.Total(), 90)
    66  	*fo = Float(100)
    67  	ts.AddWithTime(fo, tu(100))
    68  	checkApproximate(t, ts.Range(tu(99), tu(100)), 100)
    69  	checkApproximate(t, ts.Range(tu(0), tu(4)), 36)
    70  	checkApproximate(t, ts.Total(), 190)
    71  	*fo = Float(10)
    72  	ts.AddWithTime(fo, tu(1))
    73  	ts.AddWithTime(fo, tu(1))
    74  	checkApproximate(t, ts.Range(tu(0), tu(4)), 44)
    75  	checkApproximate(t, ts.Range(tu(37), tu2(100, 100e6)), 100)
    76  	checkApproximate(t, ts.Range(tu(50), tu2(100, 100e6)), 100)
    77  	checkApproximate(t, ts.Range(tu(99), tu2(100, 100e6)), 100)
    78  	checkApproximate(t, ts.Total(), 210)
    79  
    80  	for i, l := range ts.ComputeRange(tu(36), tu(100), 64) {
    81  		if i == 63 {
    82  			checkApproximate(t, l, 100)
    83  		} else {
    84  			checkApproximate(t, l, 0)
    85  		}
    86  	}
    87  
    88  	checkApproximate(t, ts.Range(tu(0), tu(100)), 210)
    89  	checkApproximate(t, ts.Range(tu(10), tu(100)), 100)
    90  
    91  	for i, l := range ts.ComputeRange(tu(0), tu(100), 100) {
    92  		if i < 10 {
    93  			checkApproximate(t, l, 11)
    94  		} else if i >= 90 {
    95  			checkApproximate(t, l, 10)
    96  		} else {
    97  			checkApproximate(t, l, 0)
    98  		}
    99  	}
   100  }
   101  
   102  func TestFloat(t *testing.T) {
   103  	f := Float(1)
   104  	if g, w := f.String(), "1"; g != w {
   105  		t.Errorf("Float(1).String = %q; want %q", g, w)
   106  	}
   107  	f2 := Float(2)
   108  	var o Observable = &f2
   109  	f.Add(o)
   110  	if g, w := f.Value(), 3.0; g != w {
   111  		t.Errorf("Float post-add = %v; want %v", g, w)
   112  	}
   113  	f.Multiply(2)
   114  	if g, w := f.Value(), 6.0; g != w {
   115  		t.Errorf("Float post-multiply = %v; want %v", g, w)
   116  	}
   117  	f.Clear()
   118  	if g, w := f.Value(), 0.0; g != w {
   119  		t.Errorf("Float post-clear = %v; want %v", g, w)
   120  	}
   121  	f.CopyFrom(&f2)
   122  	if g, w := f.Value(), 2.0; g != w {
   123  		t.Errorf("Float post-CopyFrom = %v; want %v", g, w)
   124  	}
   125  }
   126  
   127  type mockClock struct {
   128  	time time.Time
   129  }
   130  
   131  func (m *mockClock) Time() time.Time { return m.time }
   132  func (m *mockClock) Set(t time.Time) { m.time = t }
   133  
   134  const buckets = 6
   135  
   136  var testResolutions = []time.Duration{
   137  	10 * time.Second,  // level holds one minute of observations
   138  	100 * time.Second, // level holds ten minutes of observations
   139  	10 * time.Minute,  // level holds one hour of observations
   140  }
   141  
   142  // TestTimeSeries uses a small number of buckets to force a higher
   143  // error rate on approximations from the timeseries.
   144  type TestTimeSeries struct {
   145  	timeSeries
   146  }
   147  
   148  func TestExpectedErrorRate(t *testing.T) {
   149  	ts := new(TestTimeSeries)
   150  	fake := new(mockClock)
   151  	fake.Set(time.Now())
   152  	ts.timeSeries.init(testResolutions, NewFloat, buckets, fake)
   153  	for i := 1; i <= 61*61; i++ {
   154  		fake.Set(fake.Time().Add(1 * time.Second))
   155  		ob := Float(1)
   156  		ts.AddWithTime(&ob, fake.Time())
   157  
   158  		// The results should be accurate within one missing bucket (1/6) of the observations recorded.
   159  		checkNear(t, ts.Latest(0, buckets), min(float64(i), 60), 10)
   160  		checkNear(t, ts.Latest(1, buckets), min(float64(i), 600), 100)
   161  		checkNear(t, ts.Latest(2, buckets), min(float64(i), 3600), 600)
   162  	}
   163  }
   164  
   165  func min(a, b float64) float64 {
   166  	if a < b {
   167  		return a
   168  	}
   169  	return b
   170  }