| 193 | } |
| 194 | |
| 195 | func TestSlottedTicker(t *testing.T) { |
| 196 | t.Parallel() |
| 197 | testCases := map[string]struct { |
| 198 | duration time.Duration |
| 199 | totalSlots int |
| 200 | slotNumber int |
| 201 | }{ |
| 202 | "No Slots should spread across all the interval": { |
| 203 | duration: 300 * time.Millisecond, |
| 204 | totalSlots: 1, |
| 205 | slotNumber: 0, |
| 206 | }, |
| 207 | "Get first slot": { |
| 208 | duration: 300 * time.Millisecond, |
| 209 | totalSlots: 5, |
| 210 | slotNumber: 0, |
| 211 | }, |
| 212 | "Get 3th slot": { |
| 213 | duration: 300 * time.Millisecond, |
| 214 | totalSlots: 5, |
| 215 | slotNumber: 3, |
| 216 | }, |
| 217 | "Get last slot": { |
| 218 | duration: 300 * time.Millisecond, |
| 219 | totalSlots: 5, |
| 220 | slotNumber: 4, |
| 221 | }, |
| 222 | } |
| 223 | for name, c := range testCases { |
| 224 | tc := c |
| 225 | t.Run(name, func(t *testing.T) { |
| 226 | infoFunc := func() (int, int) { |
| 227 | return tc.slotNumber, tc.totalSlots |
| 228 | } |
| 229 | ticker := NewSlottedTicker(infoFunc, tc.duration, 0) |
| 230 | slotSize := tc.duration.Milliseconds() / int64(tc.totalSlots) |
| 231 | successCount := 0 |
| 232 | |
| 233 | test.Poll(t, 5*time.Second, true, func() any { |
| 234 | tTime := <-ticker.C |
| 235 | slotShiftInMs := tTime.UnixMilli() % tc.duration.Milliseconds() |
| 236 | slot := slotShiftInMs / slotSize |
| 237 | if slot == int64(tc.slotNumber) { |
| 238 | successCount++ |
| 239 | } else { |
| 240 | successCount-- |
| 241 | } |
| 242 | |
| 243 | return successCount == 10 |
| 244 | }) |
| 245 | ticker.Stop() |
| 246 | }) |
| 247 | } |
| 248 | |
| 249 | t.Run("Change slot size", func(t *testing.T) { |
| 250 | slotSize := atomic.NewInt32(10) |
| 251 | d := 300 * time.Millisecond |
| 252 | infoFunc := func() (int, int) { |