github.com/weaviate/weaviate@v1.24.6/entities/cyclemanager/ticker_test.go (about) 1 // _ _ 2 // __ _____ __ ___ ___ __ _| |_ ___ 3 // \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \ 4 // \ V V / __/ (_| |\ V /| | (_| | || __/ 5 // \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___| 6 // 7 // Copyright © 2016 - 2024 Weaviate B.V. All rights reserved. 8 // 9 // CONTACT: hello@weaviate.io 10 // 11 12 package cyclemanager 13 14 import ( 15 "context" 16 "testing" 17 "time" 18 19 "github.com/stretchr/testify/assert" 20 ) 21 22 func Test_FixedIntervalTicker(t *testing.T) { 23 t.Run("channel is empty before started", func(t *testing.T) { 24 interval := 10 * time.Millisecond 25 ticker := NewFixedTicker(10 * time.Millisecond) 26 27 assert.Len(t, ticker.C(), 0) 28 29 ticker.Start() 30 time.Sleep(2 * interval) 31 32 assert.Len(t, ticker.C(), 1) 33 }) 34 35 t.Run("interval is fixed", func(t *testing.T) { 36 interval := 50 * time.Millisecond 37 tolerance := 25 * time.Millisecond 38 39 ticker := NewFixedTicker(interval) 40 ticker.Start() 41 42 t0 := time.Now() 43 val1 := <-ticker.C() 44 t1 := time.Now() 45 val2 := <-ticker.C() 46 t2 := time.Now() 47 val3 := <-ticker.C() 48 t3 := time.Now() 49 val4 := <-ticker.C() 50 t4 := time.Now() 51 52 ticker.Stop() 53 54 assertTimeDiffEquals(t, val1, val2, interval, tolerance) 55 assertTimeDiffEquals(t, val2, val3, interval, tolerance) 56 assertTimeDiffEquals(t, val3, val4, interval, tolerance) 57 assertTimeDiffEquals(t, t0, t1, interval, tolerance) 58 assertTimeDiffEquals(t, t1, t2, interval, tolerance) 59 assertTimeDiffEquals(t, t2, t3, interval, tolerance) 60 assertTimeDiffEquals(t, t3, t4, interval, tolerance) 61 }) 62 63 t.Run("interval does not change on CycleExecuted call", func(t *testing.T) { 64 interval := 50 * time.Millisecond 65 tolerance := 25 * time.Millisecond 66 67 ticker := NewFixedTicker(interval) 68 ticker.Start() 69 70 t0 := time.Now() 71 val1 := <-ticker.C() 72 t1 := time.Now() 73 val2 := <-ticker.C() 74 t2 := time.Now() 75 76 ticker.CycleExecuted(false) 77 78 val3 := <-ticker.C() 79 t3 := time.Now() 80 val4 := <-ticker.C() 81 t4 := time.Now() 82 83 ticker.CycleExecuted(true) 84 85 val5 := <-ticker.C() 86 t5 := time.Now() 87 val6 := <-ticker.C() 88 t6 := time.Now() 89 90 ticker.Stop() 91 92 assertTimeDiffEquals(t, val1, val2, interval, tolerance) 93 assertTimeDiffEquals(t, val2, val3, interval, tolerance) 94 assertTimeDiffEquals(t, val3, val4, interval, tolerance) 95 assertTimeDiffEquals(t, val4, val5, interval, tolerance) 96 assertTimeDiffEquals(t, val5, val6, interval, tolerance) 97 assertTimeDiffEquals(t, t0, t1, interval, tolerance) 98 assertTimeDiffEquals(t, t1, t2, interval, tolerance) 99 assertTimeDiffEquals(t, t2, t3, interval, tolerance) 100 assertTimeDiffEquals(t, t3, t4, interval, tolerance) 101 assertTimeDiffEquals(t, t4, t5, interval, tolerance) 102 assertTimeDiffEquals(t, t5, t6, interval, tolerance) 103 }) 104 105 t.Run("no ticks after stop", func(t *testing.T) { 106 interval := 50 * time.Millisecond 107 tolerance := 25 * time.Millisecond 108 109 ticker := NewFixedTicker(interval) 110 ticker.Start() 111 112 t0 := time.Now() 113 val1 := <-ticker.C() 114 t1 := time.Now() 115 val2 := <-ticker.C() 116 t2 := time.Now() 117 118 ticker.Stop() 119 120 tickOccurred := false 121 ctx, cancel := context.WithTimeout(context.Background(), 2*interval) 122 defer cancel() 123 124 select { 125 case <-ticker.C(): 126 tickOccurred = true 127 case <-ctx.Done(): 128 tickOccurred = false 129 } 130 131 assert.False(t, tickOccurred) 132 133 assertTimeDiffEquals(t, val1, val2, interval, tolerance) 134 assertTimeDiffEquals(t, t0, t1, interval, tolerance) 135 assertTimeDiffEquals(t, t1, t2, interval, tolerance) 136 }) 137 138 t.Run("ticker starts again", func(t *testing.T) { 139 interval := 50 * time.Millisecond 140 tolerance := 25 * time.Millisecond 141 142 ticker := NewFixedTicker(interval) 143 ticker.Start() 144 145 t01 := time.Now() 146 val1 := <-ticker.C() 147 t1 := time.Now() 148 val2 := <-ticker.C() 149 t2 := time.Now() 150 151 ticker.Stop() 152 ticker.Start() 153 154 t02 := time.Now() 155 val3 := <-ticker.C() 156 t3 := time.Now() 157 val4 := <-ticker.C() 158 t4 := time.Now() 159 160 ticker.Stop() 161 162 assertTimeDiffEquals(t, val1, val2, interval, tolerance) 163 assertTimeDiffEquals(t, val3, val4, interval, tolerance) 164 assertTimeDiffEquals(t, t01, t1, interval, tolerance) 165 assertTimeDiffEquals(t, t1, t2, interval, tolerance) 166 assertTimeDiffEquals(t, t02, t3, interval, tolerance) 167 assertTimeDiffEquals(t, t3, t4, interval, tolerance) 168 }) 169 170 t.Run("ticker does not run with <= 0 interval", func(t *testing.T) { 171 interval := time.Duration(0) 172 173 ticker := NewFixedTicker(interval) 174 ticker.Start() 175 176 tickOccurred := false 177 ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond) 178 defer cancel() 179 180 select { 181 case <-ticker.C(): 182 tickOccurred = true 183 case <-ctx.Done(): 184 tickOccurred = false 185 } 186 187 assert.False(t, tickOccurred) 188 189 ticker.Stop() 190 }) 191 } 192 193 func Test_SeriesTicker(t *testing.T) { 194 t.Run("channel is empty before started", func(t *testing.T) { 195 intervals := []time.Duration{10 * time.Millisecond, 20 * time.Millisecond} 196 ticker := NewSeriesTicker(intervals) 197 198 assert.Len(t, ticker.C(), 0) 199 200 ticker.Start() 201 time.Sleep(2 * intervals[0]) 202 203 assert.Len(t, ticker.C(), 1) 204 }) 205 206 t.Run("interval is fixed between CycleExecuted calls, advances on false, resets on true", func(t *testing.T) { 207 intervals := []time.Duration{50 * time.Millisecond, 100 * time.Millisecond, 150 * time.Millisecond} 208 tolerance := 25 * time.Millisecond 209 210 ticker := NewSeriesTicker(intervals) 211 ticker.Start() 212 213 t0 := time.Now() 214 val1 := <-ticker.C() 215 t1 := time.Now() 216 val2 := <-ticker.C() 217 t2 := time.Now() 218 219 ticker.CycleExecuted(false) 220 221 val3 := <-ticker.C() 222 t3 := time.Now() 223 val4 := <-ticker.C() 224 t4 := time.Now() 225 226 ticker.CycleExecuted(false) 227 228 val5 := <-ticker.C() 229 t5 := time.Now() 230 val6 := <-ticker.C() 231 t6 := time.Now() 232 233 ticker.CycleExecuted(false) 234 235 val7 := <-ticker.C() 236 t7 := time.Now() 237 val8 := <-ticker.C() 238 t8 := time.Now() 239 240 ticker.CycleExecuted(true) 241 242 val9 := <-ticker.C() 243 t9 := time.Now() 244 val10 := <-ticker.C() 245 t10 := time.Now() 246 247 ticker.Stop() 248 249 assertTimeDiffEquals(t, val1, val2, intervals[0], tolerance) 250 assertTimeDiffEquals(t, val2, val3, intervals[1], tolerance) 251 assertTimeDiffEquals(t, val3, val4, intervals[1], tolerance) 252 assertTimeDiffEquals(t, val4, val5, intervals[2], tolerance) 253 assertTimeDiffEquals(t, val5, val6, intervals[2], tolerance) 254 assertTimeDiffEquals(t, val6, val7, intervals[2], tolerance) 255 assertTimeDiffEquals(t, val7, val8, intervals[2], tolerance) 256 assertTimeDiffEquals(t, val8, val9, intervals[0], tolerance) 257 assertTimeDiffEquals(t, val9, val10, intervals[0], tolerance) 258 assertTimeDiffEquals(t, t0, t1, intervals[0], tolerance) 259 assertTimeDiffEquals(t, t1, t2, intervals[0], tolerance) 260 assertTimeDiffEquals(t, t2, t3, intervals[1], tolerance) 261 assertTimeDiffEquals(t, t3, t4, intervals[1], tolerance) 262 assertTimeDiffEquals(t, t4, t5, intervals[2], tolerance) 263 assertTimeDiffEquals(t, t5, t6, intervals[2], tolerance) 264 assertTimeDiffEquals(t, t6, t7, intervals[2], tolerance) 265 assertTimeDiffEquals(t, t7, t8, intervals[2], tolerance) 266 assertTimeDiffEquals(t, t8, t9, intervals[0], tolerance) 267 assertTimeDiffEquals(t, t9, t10, intervals[0], tolerance) 268 }) 269 270 t.Run("no ticks after stop", func(t *testing.T) { 271 intervals := []time.Duration{50 * time.Millisecond} 272 tolerance := 25 * time.Millisecond 273 274 ticker := NewSeriesTicker(intervals) 275 ticker.Start() 276 277 t0 := time.Now() 278 val1 := <-ticker.C() 279 t1 := time.Now() 280 val2 := <-ticker.C() 281 t2 := time.Now() 282 283 ticker.Stop() 284 285 tickOccurred := false 286 ctx, cancel := context.WithTimeout(context.Background(), 2*intervals[0]) 287 defer cancel() 288 289 select { 290 case <-ticker.C(): 291 tickOccurred = true 292 case <-ctx.Done(): 293 tickOccurred = false 294 } 295 296 assert.False(t, tickOccurred) 297 298 assertTimeDiffEquals(t, val1, val2, intervals[0], tolerance) 299 assertTimeDiffEquals(t, t0, t1, intervals[0], tolerance) 300 assertTimeDiffEquals(t, t1, t2, intervals[0], tolerance) 301 }) 302 303 t.Run("ticker starts again", func(t *testing.T) { 304 intervals := []time.Duration{50 * time.Millisecond} 305 tolerance := 25 * time.Millisecond 306 307 ticker := NewSeriesTicker(intervals) 308 ticker.Start() 309 310 t01 := time.Now() 311 val1 := <-ticker.C() 312 t1 := time.Now() 313 val2 := <-ticker.C() 314 t2 := time.Now() 315 316 ticker.Stop() 317 ticker.Start() 318 319 t02 := time.Now() 320 val3 := <-ticker.C() 321 t3 := time.Now() 322 val4 := <-ticker.C() 323 t4 := time.Now() 324 325 ticker.Stop() 326 327 assertTimeDiffEquals(t, val1, val2, intervals[0], tolerance) 328 assertTimeDiffEquals(t, val3, val4, intervals[0], tolerance) 329 assertTimeDiffEquals(t, t01, t1, intervals[0], tolerance) 330 assertTimeDiffEquals(t, t1, t2, intervals[0], tolerance) 331 assertTimeDiffEquals(t, t02, t3, intervals[0], tolerance) 332 assertTimeDiffEquals(t, t3, t4, intervals[0], tolerance) 333 }) 334 335 t.Run("ticker does not run with invalid params", func(t *testing.T) { 336 run := func(t *testing.T, ticker CycleTicker) { 337 ticker.Start() 338 339 tickOccurred := false 340 ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond) 341 defer cancel() 342 343 select { 344 case <-ticker.C(): 345 tickOccurred = true 346 case <-ctx.Done(): 347 tickOccurred = false 348 } 349 350 assert.False(t, tickOccurred) 351 352 ticker.Stop() 353 } 354 355 t.Run("any interval <= 0", func(t *testing.T) { 356 ticker := NewSeriesTicker([]time.Duration{50 * time.Millisecond, 0}) 357 358 run(t, ticker) 359 }) 360 361 t.Run("no intervals", func(t *testing.T) { 362 ticker := NewSeriesTicker([]time.Duration{}) 363 364 run(t, ticker) 365 }) 366 }) 367 } 368 369 func Test_LinearTicker(t *testing.T) { 370 t.Run("channel is empty before started", func(t *testing.T) { 371 minInterval := 10 * time.Millisecond 372 maxInterval := 50 * time.Millisecond 373 steps := uint(2) 374 ticker := NewLinearTicker(minInterval, maxInterval, steps) 375 376 assert.Len(t, ticker.C(), 0) 377 378 ticker.Start() 379 time.Sleep(2 * minInterval) 380 381 assert.Len(t, ticker.C(), 1) 382 }) 383 384 t.Run("interval is fixed between CycleExecuted calls, advances on false, resets on true", func(t *testing.T) { 385 ms50 := 50 * time.Millisecond 386 ms75 := 75 * time.Millisecond 387 ms100 := 100 * time.Millisecond 388 tolerance := 25 * time.Millisecond 389 390 minInterval := ms50 391 maxInterval := ms100 392 steps := uint(2) 393 394 ticker := NewLinearTicker(minInterval, maxInterval, steps) 395 ticker.Start() 396 397 t0 := time.Now() 398 val1 := <-ticker.C() 399 t1 := time.Now() 400 val2 := <-ticker.C() 401 t2 := time.Now() 402 403 ticker.CycleExecuted(false) 404 405 val3 := <-ticker.C() 406 t3 := time.Now() 407 val4 := <-ticker.C() 408 t4 := time.Now() 409 410 ticker.CycleExecuted(false) 411 412 val5 := <-ticker.C() 413 t5 := time.Now() 414 val6 := <-ticker.C() 415 t6 := time.Now() 416 417 ticker.CycleExecuted(false) 418 419 val7 := <-ticker.C() 420 t7 := time.Now() 421 val8 := <-ticker.C() 422 t8 := time.Now() 423 424 ticker.CycleExecuted(true) 425 426 val9 := <-ticker.C() 427 t9 := time.Now() 428 val10 := <-ticker.C() 429 t10 := time.Now() 430 431 ticker.Stop() 432 433 assertTimeDiffEquals(t, val1, val2, ms50, tolerance) 434 assertTimeDiffEquals(t, val2, val3, ms75, tolerance) 435 assertTimeDiffEquals(t, val3, val4, ms75, tolerance) 436 assertTimeDiffEquals(t, val4, val5, ms100, tolerance) 437 assertTimeDiffEquals(t, val5, val6, ms100, tolerance) 438 assertTimeDiffEquals(t, val6, val7, ms100, tolerance) 439 assertTimeDiffEquals(t, val7, val8, ms100, tolerance) 440 assertTimeDiffEquals(t, val8, val9, ms50, tolerance) 441 assertTimeDiffEquals(t, val9, val10, ms50, tolerance) 442 assertTimeDiffEquals(t, t0, t1, ms50, tolerance) 443 assertTimeDiffEquals(t, t1, t2, ms50, tolerance) 444 assertTimeDiffEquals(t, t2, t3, ms75, tolerance) 445 assertTimeDiffEquals(t, t3, t4, ms75, tolerance) 446 assertTimeDiffEquals(t, t4, t5, ms100, tolerance) 447 assertTimeDiffEquals(t, t5, t6, ms100, tolerance) 448 assertTimeDiffEquals(t, t6, t7, ms100, tolerance) 449 assertTimeDiffEquals(t, t7, t8, ms100, tolerance) 450 assertTimeDiffEquals(t, t8, t9, ms50, tolerance) 451 assertTimeDiffEquals(t, t9, t10, ms50, tolerance) 452 }) 453 454 t.Run("no ticks after stop", func(t *testing.T) { 455 minInterval := 50 * time.Millisecond 456 maxInterval := 100 * time.Millisecond 457 steps := uint(2) 458 tolerance := 10 * time.Millisecond 459 460 ticker := NewLinearTicker(minInterval, maxInterval, steps) 461 ticker.Start() 462 463 t0 := time.Now() 464 val1 := <-ticker.C() 465 t1 := time.Now() 466 val2 := <-ticker.C() 467 t2 := time.Now() 468 469 ticker.Stop() 470 471 tickOccurred := false 472 ctx, cancel := context.WithTimeout(context.Background(), 2*minInterval) 473 defer cancel() 474 475 select { 476 case <-ticker.C(): 477 tickOccurred = true 478 case <-ctx.Done(): 479 tickOccurred = false 480 } 481 482 assert.False(t, tickOccurred) 483 484 assertTimeDiffEquals(t, val1, val2, minInterval, tolerance) 485 assertTimeDiffEquals(t, t0, t1, minInterval, tolerance) 486 assertTimeDiffEquals(t, t1, t2, minInterval, tolerance) 487 }) 488 489 t.Run("ticker starts again", func(t *testing.T) { 490 minInterval := 50 * time.Millisecond 491 maxInterval := 100 * time.Millisecond 492 steps := uint(2) 493 tolerance := 25 * time.Millisecond 494 495 ticker := NewLinearTicker(minInterval, maxInterval, steps) 496 ticker.Start() 497 498 t01 := time.Now() 499 val1 := <-ticker.C() 500 t1 := time.Now() 501 val2 := <-ticker.C() 502 t2 := time.Now() 503 504 ticker.Stop() 505 ticker.Start() 506 507 t02 := time.Now() 508 val3 := <-ticker.C() 509 t3 := time.Now() 510 val4 := <-ticker.C() 511 t4 := time.Now() 512 513 ticker.Stop() 514 515 assertTimeDiffEquals(t, val1, val2, minInterval, tolerance) 516 assertTimeDiffEquals(t, val3, val4, minInterval, tolerance) 517 assertTimeDiffEquals(t, t01, t1, minInterval, tolerance) 518 assertTimeDiffEquals(t, t1, t2, minInterval, tolerance) 519 assertTimeDiffEquals(t, t02, t3, minInterval, tolerance) 520 assertTimeDiffEquals(t, t3, t4, minInterval, tolerance) 521 }) 522 523 t.Run("ticker does not run with invalid params", func(t *testing.T) { 524 run := func(t *testing.T, ticker CycleTicker) { 525 ticker.Start() 526 527 tickOccurred := false 528 ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond) 529 defer cancel() 530 531 select { 532 case <-ticker.C(): 533 tickOccurred = true 534 case <-ctx.Done(): 535 tickOccurred = false 536 } 537 538 assert.False(t, tickOccurred) 539 540 ticker.Stop() 541 } 542 543 t.Run("minInterval <= 0", func(t *testing.T) { 544 ticker := NewLinearTicker(0, 100*time.Millisecond, 1) 545 546 run(t, ticker) 547 }) 548 549 t.Run("maxInterval <= 0", func(t *testing.T) { 550 ticker := NewLinearTicker(50*time.Millisecond, 0, 1) 551 552 run(t, ticker) 553 }) 554 555 t.Run("steps = 0", func(t *testing.T) { 556 ticker := NewLinearTicker(50*time.Millisecond, 100*time.Millisecond, 0) 557 558 run(t, ticker) 559 }) 560 561 t.Run("minInterval > maxInterval", func(t *testing.T) { 562 ticker := NewLinearTicker(100*time.Millisecond, 50*time.Millisecond, 0) 563 564 run(t, ticker) 565 }) 566 }) 567 } 568 569 func Test_ExpTicker(t *testing.T) { 570 t.Run("channel is empty before started", func(t *testing.T) { 571 minInterval := 10 * time.Millisecond 572 maxInterval := 20 * time.Millisecond 573 base := uint(2) 574 steps := uint(2) 575 ticker := NewExpTicker(minInterval, maxInterval, base, steps) 576 577 assert.Len(t, ticker.C(), 0) 578 579 ticker.Start() 580 time.Sleep(2 * minInterval) 581 582 assert.Len(t, ticker.C(), 1) 583 }) 584 585 t.Run("interval is fixed between CycleExecuted calls, advances on false, resets on true", func(t *testing.T) { 586 ms25 := 25 * time.Millisecond 587 ms50 := 50 * time.Millisecond 588 ms100 := 100 * time.Millisecond 589 tolerance := 25 * time.Millisecond 590 591 minInterval := ms25 592 maxInterval := ms100 593 base := uint(2) 594 steps := uint(2) 595 596 ticker := NewExpTicker(minInterval, maxInterval, base, steps) 597 ticker.Start() 598 599 t0 := time.Now() 600 val1 := <-ticker.C() 601 t1 := time.Now() 602 val2 := <-ticker.C() 603 t2 := time.Now() 604 605 ticker.CycleExecuted(false) 606 607 val3 := <-ticker.C() 608 t3 := time.Now() 609 val4 := <-ticker.C() 610 t4 := time.Now() 611 612 ticker.CycleExecuted(false) 613 614 val5 := <-ticker.C() 615 t5 := time.Now() 616 val6 := <-ticker.C() 617 t6 := time.Now() 618 619 ticker.CycleExecuted(false) 620 621 val7 := <-ticker.C() 622 t7 := time.Now() 623 val8 := <-ticker.C() 624 t8 := time.Now() 625 626 ticker.CycleExecuted(true) 627 628 val9 := <-ticker.C() 629 t9 := time.Now() 630 val10 := <-ticker.C() 631 t10 := time.Now() 632 633 ticker.Stop() 634 635 assertTimeDiffEquals(t, val1, val2, ms25, tolerance) 636 assertTimeDiffEquals(t, val2, val3, ms50, tolerance) 637 assertTimeDiffEquals(t, val3, val4, ms50, tolerance) 638 assertTimeDiffEquals(t, val4, val5, ms100, tolerance) 639 assertTimeDiffEquals(t, val5, val6, ms100, tolerance) 640 assertTimeDiffEquals(t, val6, val7, ms100, tolerance) 641 assertTimeDiffEquals(t, val7, val8, ms100, tolerance) 642 assertTimeDiffEquals(t, val8, val9, ms25, tolerance) 643 assertTimeDiffEquals(t, val9, val10, ms25, tolerance) 644 assertTimeDiffEquals(t, t0, t1, ms25, tolerance) 645 assertTimeDiffEquals(t, t1, t2, ms25, tolerance) 646 assertTimeDiffEquals(t, t2, t3, ms50, tolerance) 647 assertTimeDiffEquals(t, t3, t4, ms50, tolerance) 648 assertTimeDiffEquals(t, t4, t5, ms100, tolerance) 649 assertTimeDiffEquals(t, t5, t6, ms100, tolerance) 650 assertTimeDiffEquals(t, t6, t7, ms100, tolerance) 651 assertTimeDiffEquals(t, t7, t8, ms100, tolerance) 652 assertTimeDiffEquals(t, t8, t9, ms25, tolerance) 653 assertTimeDiffEquals(t, t9, t10, ms25, tolerance) 654 }) 655 656 t.Run("no ticks after stop", func(t *testing.T) { 657 minInterval := 25 * time.Millisecond 658 maxInterval := 100 * time.Millisecond 659 base := uint(2) 660 steps := uint(2) 661 tolerance := 25 * time.Millisecond 662 663 ticker := NewExpTicker(minInterval, maxInterval, base, steps) 664 ticker.Start() 665 666 t0 := time.Now() 667 val1 := <-ticker.C() 668 t1 := time.Now() 669 val2 := <-ticker.C() 670 t2 := time.Now() 671 672 ticker.Stop() 673 674 tickOccurred := false 675 ctx, cancel := context.WithTimeout(context.Background(), 2*minInterval) 676 defer cancel() 677 678 select { 679 case <-ticker.C(): 680 tickOccurred = true 681 case <-ctx.Done(): 682 tickOccurred = false 683 } 684 685 assert.False(t, tickOccurred) 686 687 assertTimeDiffEquals(t, val1, val2, minInterval, tolerance) 688 assertTimeDiffEquals(t, t0, t1, minInterval, tolerance) 689 assertTimeDiffEquals(t, t1, t2, minInterval, tolerance) 690 }) 691 692 t.Run("ticker starts again", func(t *testing.T) { 693 minInterval := 25 * time.Millisecond 694 maxInterval := 100 * time.Millisecond 695 base := uint(2) 696 steps := uint(2) 697 tolerance := 25 * time.Millisecond 698 699 ticker := NewExpTicker(minInterval, maxInterval, base, steps) 700 ticker.Start() 701 702 t01 := time.Now() 703 val1 := <-ticker.C() 704 t1 := time.Now() 705 val2 := <-ticker.C() 706 t2 := time.Now() 707 708 ticker.Stop() 709 ticker.Start() 710 711 t02 := time.Now() 712 val3 := <-ticker.C() 713 t3 := time.Now() 714 val4 := <-ticker.C() 715 t4 := time.Now() 716 717 ticker.Stop() 718 719 assertTimeDiffEquals(t, val1, val2, minInterval, tolerance) 720 assertTimeDiffEquals(t, val3, val4, minInterval, tolerance) 721 assertTimeDiffEquals(t, t01, t1, minInterval, tolerance) 722 assertTimeDiffEquals(t, t1, t2, minInterval, tolerance) 723 assertTimeDiffEquals(t, t02, t3, minInterval, tolerance) 724 assertTimeDiffEquals(t, t3, t4, minInterval, tolerance) 725 }) 726 727 t.Run("ticker does not run with invalid params", func(t *testing.T) { 728 run := func(t *testing.T, ticker CycleTicker) { 729 ticker.Start() 730 731 tickOccurred := false 732 ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond) 733 defer cancel() 734 735 select { 736 case <-ticker.C(): 737 tickOccurred = true 738 case <-ctx.Done(): 739 tickOccurred = false 740 } 741 742 assert.False(t, tickOccurred) 743 744 ticker.Stop() 745 } 746 747 t.Run("minInterval <= 0", func(t *testing.T) { 748 ticker := NewExpTicker(0, 100*time.Millisecond, 2, 2) 749 750 run(t, ticker) 751 }) 752 753 t.Run("maxInterval <= 0", func(t *testing.T) { 754 ticker := NewExpTicker(100*time.Millisecond, 0, 2, 2) 755 756 run(t, ticker) 757 }) 758 759 t.Run("base == 0", func(t *testing.T) { 760 ticker := NewExpTicker(25*time.Millisecond, 100*time.Millisecond, 0, 2) 761 762 run(t, ticker) 763 }) 764 765 t.Run("steps = 0", func(t *testing.T) { 766 ticker := NewExpTicker(25*time.Millisecond, 100*time.Millisecond, 2, 0) 767 768 run(t, ticker) 769 }) 770 771 t.Run("minInterval > maxInterval", func(t *testing.T) { 772 ticker := NewExpTicker(100*time.Millisecond, 25*time.Millisecond, 2, 2) 773 774 run(t, ticker) 775 }) 776 }) 777 } 778 779 func Test_LinearToIntervals(t *testing.T) { 780 type testCase struct { 781 name string 782 minInterval time.Duration 783 maxInterval time.Duration 784 steps uint 785 expected []time.Duration 786 } 787 788 testCases := []testCase{ 789 { 790 name: "100 => 5000; steps 2", 791 minInterval: 100 * time.Millisecond, 792 maxInterval: 5 * time.Second, 793 steps: 2, 794 expected: []time.Duration{ 795 100_000_000, 796 2_550_000_000, 797 5_000_000_000, 798 }, 799 }, 800 { 801 name: "100 => 5000; steps 3", 802 minInterval: 100 * time.Millisecond, 803 maxInterval: 5 * time.Second, 804 steps: 3, 805 expected: []time.Duration{ 806 100_000_000, 807 1_733_333_333, 808 3_366_666_666, 809 5_000_000_000, 810 }, 811 }, 812 { 813 name: "100 => 5000; steps 4", 814 minInterval: 100 * time.Millisecond, 815 maxInterval: 5 * time.Second, 816 steps: 4, 817 expected: []time.Duration{ 818 100_000_000, 819 1_325_000_000, 820 2_550_000_000, 821 3_775_000_000, 822 5_000_000_000, 823 }, 824 }, 825 } 826 827 for _, tc := range testCases { 828 t.Run(tc.name, func(t *testing.T) { 829 res := linearToIntervals(tc.minInterval, tc.maxInterval, tc.steps) 830 831 assert.ElementsMatch(t, res, tc.expected) 832 }) 833 } 834 } 835 836 func Test_ExpToIntervals(t *testing.T) { 837 type testCase struct { 838 name string 839 minInterval time.Duration 840 maxInterval time.Duration 841 base uint 842 steps uint 843 expected []time.Duration 844 } 845 846 testCases := []testCase{ 847 { 848 name: "100 => 5000; base 2; steps 2", 849 minInterval: 100 * time.Millisecond, 850 maxInterval: 5 * time.Second, 851 base: 2, 852 steps: 2, 853 expected: []time.Duration{ 854 100_000_000, 855 1_733_333_333, 856 5_000_000_000, 857 }, 858 }, 859 { 860 name: "100 => 5000; base 2; steps 3", 861 minInterval: 100 * time.Millisecond, 862 maxInterval: 5 * time.Second, 863 base: 2, 864 steps: 3, 865 expected: []time.Duration{ 866 100_000_000, 867 800_000_000, 868 2_200_000_000, 869 5_000_000_000, 870 }, 871 }, 872 { 873 name: "100 => 5000; base 2; steps 4", 874 minInterval: 100 * time.Millisecond, 875 maxInterval: 5 * time.Second, 876 base: 2, 877 steps: 4, 878 expected: []time.Duration{ 879 100_000_000, 880 426_666_666, 881 1_080_000_000, 882 2_386_666_666, 883 5_000_000_000, 884 }, 885 }, 886 { 887 name: "100 => 5000; base 3; steps 2", 888 minInterval: 100 * time.Millisecond, 889 maxInterval: 5 * time.Second, 890 base: 3, 891 steps: 2, 892 expected: []time.Duration{ 893 100_000_000, 894 1_325_000_000, 895 5_000_000_000, 896 }, 897 }, 898 { 899 name: "100 => 5000; base 3; steps 3", 900 minInterval: 100 * time.Millisecond, 901 maxInterval: 5 * time.Second, 902 base: 3, 903 steps: 3, 904 expected: []time.Duration{ 905 100_000_000, 906 476_923_076, 907 1_607_692_307, 908 5_000_000_000, 909 }, 910 }, 911 { 912 name: "100 => 5000; base 3; steps 4", 913 minInterval: 100 * time.Millisecond, 914 maxInterval: 5 * time.Second, 915 base: 3, 916 steps: 4, 917 expected: []time.Duration{ 918 100_000_000, 919 222_500_000, 920 590_000_000, 921 1_692_500_000, 922 5_000_000_000, 923 }, 924 }, 925 } 926 927 for _, tc := range testCases { 928 t.Run(tc.name, func(t *testing.T) { 929 res := expToIntervals(tc.minInterval, tc.maxInterval, tc.base, tc.steps) 930 931 assert.ElementsMatch(t, res, tc.expected) 932 }) 933 } 934 } 935 936 func assertTimeDiffEquals(t *testing.T, time1, time2 time.Time, expected time.Duration, tolerance time.Duration) { 937 diff := time2.Sub(time1) 938 assert.GreaterOrEqual(t, diff, expected-tolerance) 939 assert.LessOrEqual(t, diff, expected+tolerance) 940 }