| OLD | NEW |
| 1 package looper | 1 package looper |
| 2 | 2 |
| 3 import ( | 3 import ( |
| 4 "fmt" | 4 "fmt" |
| 5 "testing" | 5 "testing" |
| 6 "time" | 6 "time" |
| 7 | 7 |
| 8 "github.com/luci/luci-go/common/clock" |
| 8 "github.com/luci/luci-go/common/clock/testclock" | 9 "github.com/luci/luci-go/common/clock/testclock" |
| 9 "golang.org/x/net/context" | 10 "golang.org/x/net/context" |
| 10 ) | 11 ) |
| 11 | 12 |
| 12 // Run f once, then cancel. | 13 // Run f once, then cancel. |
| 13 func TestLoopOnce(t *testing.T) { | 14 func TestLoopOnce(t *testing.T) { |
| 14 » ctx := context.Background() | 15 » ctx, c := testclock.UseTime(context.Background(), time.Unix(0, 0)) |
| 15 » _, c := testclock.UseTime(context.Background(), time.Unix(0, 0)) | |
| 16 | 16 |
| 17 nCalls := 0 | 17 nCalls := 0 |
| 18 called := make(chan interface{}, 1) | |
| 19 f := func(ctx context.Context) error { | 18 f := func(ctx context.Context) error { |
| 20 nCalls++ | 19 nCalls++ |
| 21 called <- nil | |
| 22 return nil | 20 return nil |
| 23 } | 21 } |
| 24 | 22 |
| 25 ctx, cancel := context.WithCancel(ctx) | 23 ctx, cancel := context.WithCancel(ctx) |
| 26 » done := make(chan struct{}) | 24 » c.SetTimerCallback(func(d time.Duration, t clock.Timer) { |
| 27 » go func() { | 25 » » cancel() |
| 28 » » res := Run(ctx, f, 1*time.Second, 1, c) | 26 » }) |
| 29 » » if !res.Success { | 27 » res := Run(ctx, f, 1*time.Second, 1, c) |
| 30 » » » t.Errorf("Should have succeeded.") | 28 » if !res.Success { |
| 31 » » } | 29 » » t.Errorf("Should have succeeded.") |
| 32 » » if nCalls != 1 { | 30 » } |
| 33 » » » t.Errorf("Want %d got %d", 1, nCalls) | 31 » if nCalls != 1 { |
| 34 » » } | 32 » » t.Errorf("Want %d got %d", 1, nCalls) |
| 35 » » close(done) | 33 » } |
| 36 » }() | |
| 37 | |
| 38 » <-called | |
| 39 » cancel() | |
| 40 » <-done | |
| 41 } | 34 } |
| 42 | 35 |
| 43 // Run for 5s, every 1s. Should run 5 times before returning Success. | 36 // Run for 5s, every 1s. Should run 5 times before returning Success. |
| 44 func TestLoopMultiple(t *testing.T) { | 37 func TestLoopMultiple(t *testing.T) { |
| 45 » ctx := context.Background() | 38 » ctx, c := testclock.UseTime(context.Background(), time.Unix(0, 0)) |
| 46 » _, c := testclock.UseTime(context.Background(), time.Unix(0, 0)) | |
| 47 | 39 |
| 48 nCalls := 0 | 40 nCalls := 0 |
| 49 called := make(chan interface{}, 1) | |
| 50 f := func(ctx context.Context) error { | 41 f := func(ctx context.Context) error { |
| 51 nCalls++ | 42 nCalls++ |
| 52 called <- nil | |
| 53 return nil | 43 return nil |
| 54 } | 44 } |
| 55 | 45 |
| 56 ctx, cancel := context.WithCancel(ctx) | 46 ctx, cancel := context.WithCancel(ctx) |
| 57 » done := make(chan struct{}) | 47 » i := 0 |
| 58 | 48 » c.SetTimerCallback(func(d time.Duration, t clock.Timer) { |
| 59 » go func() { | 49 » » if i++; i >= 5 { |
| 60 » » res := Run(ctx, f, 1*time.Second, 1, c) | 50 » » » cancel() |
| 61 » » if !res.Success { | |
| 62 » » » t.Errorf("Should have succeeded.") | |
| 63 } | 51 } |
| 64 » » if nCalls != 5 { | 52 » » c.Add(d) |
| 65 » » » t.Errorf("Want %d got %d", 5, nCalls) | 53 » }) |
| 66 » » } | 54 » res := Run(ctx, f, 1*time.Second, 1, c) |
| 67 » » close(done) | 55 » if !res.Success { |
| 68 » }() | 56 » » t.Errorf("Should have succeeded.") |
| 69 | |
| 70 » // Read off the rest of the timer ticks. | |
| 71 » for i := 0; i < 5; i++ { | |
| 72 » » c.Add(1 * time.Second) | |
| 73 » » <-called | |
| 74 } | 57 } |
| 75 | 58 » if nCalls != 5 { |
| 76 » cancel() | 59 » » t.Errorf("Want %d got %d", 5, nCalls) |
| 77 » <-done | 60 » } |
| 78 } | 61 } |
| 79 | 62 |
| 80 // Run for 10s, every 1s. Every other task takes 1.5s to run. 3 + 3*1.5? | 63 // Run for 10s, every 1s. Every other task takes 1.5s to run. 3 + 3*1.5? |
| 81 func TestLoopOverrunSome(t *testing.T) { | 64 func TestLoopOverrunSome(t *testing.T) { |
| 82 » // TODO(vadimsh): This test is flaky. Sometimes fails with | 65 » ctx, c := testclock.UseTime(context.Background(), time.Unix(0, 0)) |
| 83 » // Want 5 Overruns got 6. | |
| 84 » ctx := context.Background() | |
| 85 » _, c := testclock.UseTime(context.Background(), time.Unix(0, 0)) | |
| 86 | 66 |
| 87 nCalls := 0 | 67 nCalls := 0 |
| 88 called := make(chan interface{}, 1) | |
| 89 f := func(ctx context.Context) error { | 68 f := func(ctx context.Context) error { |
| 90 if nCalls%2 == 0 { | 69 if nCalls%2 == 0 { |
| 91 c.Add(1500 * time.Millisecond) | 70 c.Add(1500 * time.Millisecond) |
| 92 } else { | 71 } else { |
| 93 c.Add(500 * time.Millisecond) | 72 c.Add(500 * time.Millisecond) |
| 94 } | 73 } |
| 95 nCalls++ | 74 nCalls++ |
| 96 called <- nil | |
| 97 return nil | 75 return nil |
| 98 } | 76 } |
| 99 ctx, cancel := context.WithCancel(ctx) | 77 ctx, cancel := context.WithCancel(ctx) |
| 78 i := 0 |
| 79 c.SetTimerCallback(func(d time.Duration, t clock.Timer) { |
| 80 if i++; i >= 10 { |
| 81 cancel() |
| 82 } |
| 83 c.Add(d) |
| 84 }) |
| 100 | 85 |
| 101 » done := make(chan struct{}) | 86 » res := Run(ctx, f, 1*time.Second, 3, c) |
| 102 » go func() { | 87 » if !res.Success { |
| 103 » » res := Run(ctx, f, 1*time.Second, 3, c) | 88 » » t.Errorf("Should have succeeded.") |
| 104 » » if !res.Success { | |
| 105 » » » t.Errorf("Should have succeeded.") | |
| 106 » » } | |
| 107 » » if nCalls != 10 { | |
| 108 » » » t.Errorf("Want %d calls got %d", 10, nCalls) | |
| 109 » » } | |
| 110 » » if res.Errs != 0 { | |
| 111 » » » t.Errorf("Want %d Errs got %d", 0, res.Errs) | |
| 112 » » } | |
| 113 » » if res.Overruns != 5 { | |
| 114 » » » t.Errorf("Want %d Overruns got %d", 5, res.Overruns) | |
| 115 » » } | |
| 116 » » close(done) | |
| 117 » }() | |
| 118 | |
| 119 » for i := 0; i < 10; i++ { | |
| 120 » » c.Add(1 * time.Second) | |
| 121 » » <-called | |
| 122 } | 89 } |
| 123 » cancel() | 90 » if nCalls != 10 { |
| 124 » <-done | 91 » » t.Errorf("Want %d calls got %d", 10, nCalls) |
| 92 » } |
| 93 » if res.Errs != 0 { |
| 94 » » t.Errorf("Want %d Errs got %d", 0, res.Errs) |
| 95 » } |
| 96 » if res.Overruns != 5 { |
| 97 » » t.Errorf("Want %d Overruns got %d", 5, res.Overruns) |
| 98 » } |
| 125 } | 99 } |
| 126 | 100 |
| 127 func TestLoopOverrunAll(t *testing.T) { | 101 func TestLoopOverrunAll(t *testing.T) { |
| 128 » ctx := context.Background() | 102 » ctx, c := testclock.UseTime(context.Background(), time.Unix(0, 0)) |
| 129 » _, c := testclock.UseTime(ctx, time.Unix(0, 0)) | |
| 130 | 103 |
| 131 nCalls := 0 | 104 nCalls := 0 |
| 132 called := make(chan interface{}, 1) | |
| 133 f := func(ctx context.Context) error { | 105 f := func(ctx context.Context) error { |
| 134 if nCalls < 4 { | 106 if nCalls < 4 { |
| 135 c.Add(1001 * time.Millisecond) | 107 c.Add(1001 * time.Millisecond) |
| 136 } | 108 } |
| 137 nCalls++ | 109 nCalls++ |
| 138 called <- nil | |
| 139 return nil | 110 return nil |
| 140 } | 111 } |
| 141 | 112 |
| 142 ctx, cancel := context.WithCancel(ctx) | 113 ctx, cancel := context.WithCancel(ctx) |
| 143 » done := make(chan struct{}) | 114 » i := 0 |
| 144 » go func() { | 115 » c.SetTimerCallback(func(d time.Duration, t clock.Timer) { |
| 145 » » res := Run(ctx, f, 1*time.Second, 3, c) | 116 » » if i++; i >= 5 { |
| 146 » » if !res.Success { | 117 » » » cancel() |
| 147 » » » t.Errorf("Should have succeeded.") | |
| 148 } | 118 } |
| 149 » » if nCalls != 5 { | 119 » » c.Add(d) |
| 150 » » » t.Errorf("Want %d calls got %d", 5, nCalls) | 120 » }) |
| 151 » » } | 121 » res := Run(ctx, f, 1*time.Second, 3, c) |
| 152 » » if res.Errs != 0 { | 122 » if !res.Success { |
| 153 » » » t.Errorf("Want %d Errs got %d", 0, res.Errs) | 123 » » t.Errorf("Should have succeeded.") |
| 154 » » } | |
| 155 » » if res.Overruns != 4 { | |
| 156 » » » t.Errorf("Want %d Overruns got %d", 4, res.Overruns) | |
| 157 » » } | |
| 158 » » close(done) | |
| 159 » }() | |
| 160 | |
| 161 » for i := 0; i < 5; i++ { | |
| 162 » » c.Add(1 * time.Second) | |
| 163 » » <-called | |
| 164 } | 124 } |
| 165 | 125 » if nCalls != 5 { |
| 166 » cancel() | 126 » » t.Errorf("Want %d calls got %d", 5, nCalls) |
| 167 » <-done | 127 » } |
| 128 » if res.Errs != 0 { |
| 129 » » t.Errorf("Want %d Errs got %d", 0, res.Errs) |
| 130 » } |
| 131 » if res.Overruns != 4 { |
| 132 » » t.Errorf("Want %d Overruns got %d", 4, res.Overruns) |
| 133 » } |
| 168 } | 134 } |
| 169 | 135 |
| 170 // Run for 10s, every 1s. Return errors on 2nd, 4th, 6th, 7th and 8th calls. | 136 // Run for 10s, every 1s. Return errors on 2nd, 4th, 6th, 7th and 8th calls. |
| 171 func TestLoopMaxErrors(t *testing.T) { | 137 func TestLoopMaxErrors(t *testing.T) { |
| 172 » ctx := context.Background() | 138 » ctx, c := testclock.UseTime(context.Background(), time.Unix(0, 0)) |
| 173 » _, c := testclock.UseTime(context.Background(), time.Unix(0, 0)) | |
| 174 | 139 |
| 175 nCalls := 0 | 140 nCalls := 0 |
| 176 called := make(chan interface{}, 1) | |
| 177 f := func(ctx context.Context) error { | 141 f := func(ctx context.Context) error { |
| 178 nCalls++ | 142 nCalls++ |
| 179 called <- nil | |
| 180 if nCalls%2 == 0 || nCalls > 5 { | 143 if nCalls%2 == 0 || nCalls > 5 { |
| 181 return fmt.Errorf("this is an error: %d", nCalls) | 144 return fmt.Errorf("this is an error: %d", nCalls) |
| 182 } | 145 } |
| 183 return nil | 146 return nil |
| 184 } | 147 } |
| 185 | 148 |
| 186 ctx, cancel := context.WithCancel(ctx) | 149 ctx, cancel := context.WithCancel(ctx) |
| 187 » done := make(chan struct{}) | 150 » i := 0 |
| 188 » go func() { | 151 » c.SetTimerCallback(func(d time.Duration, t clock.Timer) { |
| 189 » » res := Run(ctx, f, 1*time.Second, 3, c) | 152 » » if i++; i >= 8 { |
| 190 » » if res.Success { | 153 » » » cancel() |
| 191 » » » t.Errorf("Should have failed.") | |
| 192 } | 154 } |
| 193 » » if nCalls != 8 { | 155 » » c.Add(d) |
| 194 » » » t.Errorf("Want %d calls got %d", 6, nCalls) | 156 » }) |
| 195 » » } | 157 » res := Run(ctx, f, 1*time.Second, 3, c) |
| 196 » » if res.Errs != 5 { | 158 » if res.Success { |
| 197 » » » t.Errorf("Want %d Errs got %d", 4, res.Errs) | 159 » » t.Errorf("Should have failed.") |
| 198 » » } | |
| 199 » » close(done) | |
| 200 » }() | |
| 201 | |
| 202 » for i := 0; i < 8; i++ { | |
| 203 » » c.Add(1 * time.Second) | |
| 204 » » <-called | |
| 205 } | 160 } |
| 206 | 161 » if nCalls != 8 { |
| 207 » cancel() | 162 » » t.Errorf("Want %d calls got %d", 6, nCalls) |
| 208 » <-done | 163 » } |
| 164 » if res.Errs != 5 { |
| 165 » » t.Errorf("Want %d Errs got %d", 4, res.Errs) |
| 166 » } |
| 209 } | 167 } |
| OLD | NEW |