github.com/core-coin/go-core/v2@v2.1.9/les/lespay/client/timestats_test.go (about) 1 // Copyright 2020 by the Authors 2 // This file is part of the go-core library. 3 // 4 // The go-core library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-core library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-core library. If not, see <http://www.gnu.org/licenses/>. 16 17 package client 18 19 import ( 20 "math" 21 "math/rand" 22 "testing" 23 "time" 24 25 "github.com/core-coin/go-core/v2/les/utils" 26 ) 27 28 func TestTransition(t *testing.T) { 29 var epsilon = 0.01 30 var cases = []time.Duration{ 31 time.Millisecond, minResponseTime, 32 time.Second, time.Second * 5, maxResponseTime, 33 } 34 for _, c := range cases { 35 got := StatScaleToTime(TimeToStatScale(c)) 36 if float64(got)*(1+epsilon) < float64(c) || float64(got)*(1-epsilon) > float64(c) { 37 t.Fatalf("Failed to transition back") 38 } 39 } 40 // If the time is too large(exceeds the max response time. 41 got := StatScaleToTime(TimeToStatScale(2 * maxResponseTime)) 42 if float64(got)*(1+epsilon) < float64(maxResponseTime) || float64(got)*(1-epsilon) > float64(maxResponseTime) { 43 t.Fatalf("Failed to transition back") 44 } 45 } 46 47 var maxResponseWeights = TimeoutWeights(maxResponseTime) 48 49 func TestValue(t *testing.T) { 50 noexp := utils.ExpirationFactor{Factor: 1} 51 for i := 0; i < 1000; i++ { 52 max := minResponseTime + time.Duration(rand.Int63n(int64(maxResponseTime-minResponseTime))) 53 min := minResponseTime + time.Duration(rand.Int63n(int64(max-minResponseTime))) 54 timeout := max/2 + time.Duration(rand.Int63n(int64(maxResponseTime-max/2))) 55 s := makeRangeStats(min, max, 1000, noexp) 56 value := s.Value(TimeoutWeights(timeout), noexp) 57 // calculate the average weight (the average of the given range of the half cosine 58 // weight function). 59 minx := math.Pi / 2 * float64(min) / float64(timeout) 60 maxx := math.Pi / 2 * float64(max) / float64(timeout) 61 avgWeight := (math.Sin(maxx) - math.Sin(minx)) / (maxx - minx) 62 expv := 1000 * avgWeight 63 if expv < 0 { 64 expv = 0 65 } 66 if value < expv-10 || value > expv+10 { 67 t.Errorf("Value failed (expected %v, got %v)", expv, value) 68 } 69 } 70 } 71 72 func TestAddSubExpire(t *testing.T) { 73 var ( 74 sum1, sum2 ResponseTimeStats 75 sum1ValueExp, sum2ValueExp float64 76 logOffset utils.Fixed64 77 ) 78 for i := 0; i < 1000; i++ { 79 exp := utils.ExpFactor(logOffset) 80 max := minResponseTime + time.Duration(rand.Int63n(int64(maxResponseTime-minResponseTime))) 81 min := minResponseTime + time.Duration(rand.Int63n(int64(max-minResponseTime))) 82 s := makeRangeStats(min, max, 1000, exp) 83 value := s.Value(maxResponseWeights, exp) 84 sum1.AddStats(&s) 85 sum1ValueExp += value 86 if rand.Intn(2) == 1 { 87 sum2.AddStats(&s) 88 sum2ValueExp += value 89 } 90 logOffset += utils.Float64ToFixed64(0.001 / math.Log(2)) 91 sum1ValueExp -= sum1ValueExp * 0.001 92 sum2ValueExp -= sum2ValueExp * 0.001 93 } 94 exp := utils.ExpFactor(logOffset) 95 sum1Value := sum1.Value(maxResponseWeights, exp) 96 if sum1Value < sum1ValueExp*0.99 || sum1Value > sum1ValueExp*1.01 { 97 t.Errorf("sum1Value failed (expected %v, got %v)", sum1ValueExp, sum1Value) 98 } 99 sum2Value := sum2.Value(maxResponseWeights, exp) 100 if sum2Value < sum2ValueExp*0.99 || sum2Value > sum2ValueExp*1.01 { 101 t.Errorf("sum2Value failed (expected %v, got %v)", sum2ValueExp, sum2Value) 102 } 103 diff := sum1 104 diff.SubStats(&sum2) 105 diffValue := diff.Value(maxResponseWeights, exp) 106 diffValueExp := sum1ValueExp - sum2ValueExp 107 if diffValue < diffValueExp*0.99 || diffValue > diffValueExp*1.01 { 108 t.Errorf("diffValue failed (expected %v, got %v)", diffValueExp, diffValue) 109 } 110 } 111 112 func TestTimeout(t *testing.T) { 113 testTimeoutRange(t, 0, time.Second) 114 testTimeoutRange(t, time.Second, time.Second*2) 115 testTimeoutRange(t, time.Second, maxResponseTime) 116 } 117 118 func testTimeoutRange(t *testing.T, min, max time.Duration) { 119 s := makeRangeStats(min, max, 1000, utils.ExpirationFactor{Factor: 1}) 120 for i := 2; i < 9; i++ { 121 to := s.Timeout(float64(i) / 10) 122 exp := max - (max-min)*time.Duration(i)/10 123 tol := (max - min) / 50 124 if to < exp-tol || to > exp+tol { 125 t.Errorf("Timeout failed (expected %v, got %v)", exp, to) 126 } 127 } 128 } 129 130 func makeRangeStats(min, max time.Duration, amount float64, exp utils.ExpirationFactor) ResponseTimeStats { 131 var s ResponseTimeStats 132 amount /= 1000 133 for i := 0; i < 1000; i++ { 134 s.Add(min+(max-min)*time.Duration(i)/999, amount, exp) 135 } 136 return s 137 }