github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/net/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 }