File tree 2 files changed +29
-1
lines changed
2 files changed +29
-1
lines changed Original file line number Diff line number Diff line change @@ -37,6 +37,12 @@ class BackoffMachine {
37
37
/// maximizes the range while preserving a capped exponential shape on
38
38
/// the expected value. Greg discusses this in more detail at:
39
39
/// https://github.com/zulip/zulip-mobile/pull/3841
40
+ ///
41
+ /// The duration is always positive; [Duration] works in microseconds, so
42
+ /// we deviate from the idealized uniform distribution just by rounding
43
+ /// the smallest durations up to one microsecond instead of down to zero.
44
+ /// Because in the real world any delay takes nonzero time, this mainly
45
+ /// affects tests that use fake time, and keeps their behavior more realistic.
40
46
Future <void > wait () async {
41
47
_startTime ?? = DateTime .now ();
42
48
@@ -45,7 +51,8 @@ class BackoffMachine {
45
51
* min (_durationCeilingMs,
46
52
_firstDurationMs * pow (_base, _waitsCompleted));
47
53
48
- await Future <void >.delayed (Duration (milliseconds: durationMs.round ()));
54
+ await Future <void >.delayed (Duration (
55
+ microseconds: max (1 , (1000 * durationMs).round ())));
49
56
50
57
_waitsCompleted++ ;
51
58
}
Original file line number Diff line number Diff line change 1
1
import 'dart:async' ;
2
+ import 'dart:math' ;
2
3
3
4
import 'package:checks/checks.dart' ;
4
5
import 'package:clock/clock.dart' ;
@@ -51,4 +52,24 @@ void main() {
51
52
check (maxFromAllTrials).isGreaterThan (expectedMax * 0.75 );
52
53
}
53
54
});
55
+
56
+ test ('BackoffMachine timeouts are always positive' , () {
57
+ // Regression test for: https://github.com/zulip/zulip-flutter/issues/602
58
+ // This is a randomized test with a false-failure rate of zero.
59
+
60
+ // In the pre-#602 implementation, the first timeout was zero
61
+ // when a random number from [0, 100] was below 0.5.
62
+ // [numTrials] is chosen so that an implementation with that behavior
63
+ // will fail the test with probability 99%.
64
+ const hypotheticalFailureRate = 0.5 / 100 ;
65
+ const numTrials = 2 * ln10 / hypotheticalFailureRate;
66
+
67
+ awaitFakeAsync ((async ) async {
68
+ for (int i = 0 ; i < numTrials; i++ ) {
69
+ final duration = await measureWait (BackoffMachine ().wait ());
70
+ check (duration).isGreaterThan (Duration .zero);
71
+ }
72
+ check (async .pendingTimers).isEmpty ();
73
+ });
74
+ });
54
75
}
You can’t perform that action at this time.
0 commit comments