github.com/zorawar87/trillian@v1.2.1/client/backoff/backoff_test.go (about) 1 // Copyright 2017 Google Inc. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package backoff 16 17 import ( 18 "context" 19 "errors" 20 "testing" 21 "time" 22 23 _ "github.com/golang/glog" 24 ) 25 26 func TestBackoff(t *testing.T) { 27 b := Backoff{ 28 Min: time.Duration(1), 29 Max: time.Duration(100), 30 Factor: 2, 31 } 32 for _, test := range []struct { 33 b Backoff 34 times int 35 want time.Duration 36 }{ 37 {b, 1, time.Duration(1)}, 38 {b, 2, time.Duration(2)}, 39 {b, 3, time.Duration(4)}, 40 {b, 4, time.Duration(8)}, 41 {b, 8, time.Duration(100)}, 42 } { 43 test.b.Reset() 44 var got time.Duration 45 for i := 0; i < test.times; i++ { 46 got = test.b.Duration() 47 } 48 if got != test.want { 49 t.Errorf("Duration() %v times: %v, want %v", test.times, got, test.want) 50 } 51 } 52 } 53 54 func TestJitter(t *testing.T) { 55 b := Backoff{ 56 Min: 1 * time.Second, 57 Max: 100 * time.Second, 58 Factor: 2, 59 Jitter: true, 60 } 61 for _, test := range []struct { 62 b Backoff 63 times int 64 min time.Duration 65 max time.Duration 66 }{ 67 {b, 1, 1 * time.Second, 2 * time.Second}, 68 {b, 2, 2 * time.Second, 4 * time.Second}, 69 {b, 3, 4 * time.Second, 8 * time.Second}, 70 {b, 4, 8 * time.Second, 16 * time.Second}, 71 {b, 8, 100 * time.Second, 200 * time.Second}, 72 } { 73 test.b.Reset() 74 var got1 time.Duration 75 for i := 0; i < test.times; i++ { 76 got1 = test.b.Duration() 77 } 78 if got1 < test.min || got1 > test.max { 79 t.Errorf("Duration() %v times, want %v < %v < %v", test.times, test.min, got1, test.max) 80 } 81 82 // Ensure a random value is being produced. 83 test.b.Reset() 84 var got2 time.Duration 85 for i := 0; i < test.times; i++ { 86 got2 = test.b.Duration() 87 } 88 if got1 == got2 { 89 t.Errorf("Duration() %v times == Duration() %v times, want %v != %v", 90 test.times, test.times, got1, got2) 91 } 92 } 93 } 94 95 func TestRetry(t *testing.T) { 96 b := Backoff{ 97 Min: 50 * time.Millisecond, 98 Max: 200 * time.Millisecond, 99 Factor: 2, 100 } 101 102 // callCount is used by some test funcs to count how many times they've been called. 103 var callCount int 104 // ctx used by Retry(), declared here to that test.ctxFunc can set it. 105 var ctx context.Context 106 var cancel context.CancelFunc 107 108 for _, test := range []struct { 109 name string 110 f func() error 111 ctxFunc func() 112 wantErr bool 113 }{ 114 { 115 name: "func that immediately succeeds", 116 f: func() error { return nil }, 117 }, 118 { 119 name: "func that succeeds on second attempt", 120 f: func() error { 121 callCount++ 122 if callCount == 1 { 123 return errors.New("error") 124 } 125 return nil 126 }, 127 }, 128 { 129 name: "func that takes too long to succeed", 130 f: func() error { 131 // Cancel the context and return an error. This func will succeed on 132 // any future calls, but it should not be retried due to the context 133 // being cancelled. 134 if ctx.Err() == nil { 135 cancel() 136 return errors.New("error") 137 } 138 return nil 139 }, 140 wantErr: true, 141 }, 142 { 143 name: "context done before Retry() called", 144 f: func() error { 145 return nil 146 }, 147 ctxFunc: func() { 148 ctx, cancel = context.WithCancel(context.Background()) 149 cancel() 150 }, 151 wantErr: true, 152 }, 153 } { 154 if test.ctxFunc != nil { 155 test.ctxFunc() 156 } else { 157 ctx, cancel = context.WithCancel(context.Background()) 158 } 159 160 callCount = 0 161 err := b.Retry(ctx, test.f) 162 cancel() 163 if gotErr := err != nil; gotErr != test.wantErr { 164 t.Errorf("%v: Retry() = %v, want err? %v", test.name, err, test.wantErr) 165 } 166 } 167 }