1 #![warn(rust_2018_idioms)]
2 #![cfg(feature = "full")]
3
4 use tokio::time::{self, Duration, Instant, MissedTickBehavior};
5 use tokio_test::{assert_pending, assert_ready_eq, task};
6
7 use std::task::Poll;
8
9 // Takes the `Interval` task, `start` variable, and optional time deltas
10 // For each time delta, it polls the `Interval` and asserts that the result is
11 // equal to `start` + the specific time delta. Then it asserts that the
12 // `Interval` is pending.
13 macro_rules! check_interval_poll {
14 ($i:ident, $start:ident, $($delta:expr),*$(,)?) => {
15 $(
16 assert_ready_eq!(poll_next(&mut $i), $start + ms($delta));
17 )*
18 assert_pending!(poll_next(&mut $i));
19 };
20 ($i:ident, $start:ident) => {
21 check_interval_poll!($i, $start,);
22 };
23 }
24
25 #[tokio::test]
26 #[should_panic]
interval_zero_duration()27 async fn interval_zero_duration() {
28 let _ = time::interval_at(Instant::now(), ms(0));
29 }
30
31 // Expected ticks: | 1 | 2 | 3 | 4 | 5 | 6 |
32 // Actual ticks: | work -----| delay | work | work | work -| work -----|
33 // Poll behavior: | | | | | | | |
34 // | | | | | | | |
35 // Ready(s) | | Ready(s + 2p) | | | |
36 // Pending | Ready(s + 3p) | | |
37 // Ready(s + p) Ready(s + 4p) | |
38 // Ready(s + 5p) |
39 // Ready(s + 6p)
40 #[tokio::test(start_paused = true)]
burst()41 async fn burst() {
42 let start = Instant::now();
43
44 // This is necessary because the timer is only so granular, and in order for
45 // all our ticks to resolve, the time needs to be 1ms ahead of what we
46 // expect, so that the runtime will see that it is time to resolve the timer
47 time::advance(ms(1)).await;
48
49 let mut i = task::spawn(time::interval_at(start, ms(300)));
50
51 check_interval_poll!(i, start, 0);
52
53 time::advance(ms(100)).await;
54 check_interval_poll!(i, start);
55
56 time::advance(ms(200)).await;
57 check_interval_poll!(i, start, 300);
58
59 time::advance(ms(650)).await;
60 check_interval_poll!(i, start, 600, 900);
61
62 time::advance(ms(200)).await;
63 check_interval_poll!(i, start);
64
65 time::advance(ms(100)).await;
66 check_interval_poll!(i, start, 1200);
67
68 time::advance(ms(250)).await;
69 check_interval_poll!(i, start, 1500);
70
71 time::advance(ms(300)).await;
72 check_interval_poll!(i, start, 1800);
73 }
74
75 // Expected ticks: | 1 | 2 | 3 | 4 | 5 | 6 |
76 // Actual ticks: | work -----| delay | work -----| work -----| work -----|
77 // Poll behavior: | | | | | | | |
78 // | | | | | | | |
79 // Ready(s) | | Ready(s + 2p) | | | |
80 // Pending | Pending | | |
81 // Ready(s + p) Ready(s + 2p + d) | |
82 // Ready(s + 3p + d) |
83 // Ready(s + 4p + d)
84 #[tokio::test(start_paused = true)]
delay()85 async fn delay() {
86 let start = Instant::now();
87
88 // This is necessary because the timer is only so granular, and in order for
89 // all our ticks to resolve, the time needs to be 1ms ahead of what we
90 // expect, so that the runtime will see that it is time to resolve the timer
91 time::advance(ms(1)).await;
92
93 let mut i = task::spawn(time::interval_at(start, ms(300)));
94 i.set_missed_tick_behavior(MissedTickBehavior::Delay);
95
96 check_interval_poll!(i, start, 0);
97
98 time::advance(ms(100)).await;
99 check_interval_poll!(i, start);
100
101 time::advance(ms(200)).await;
102 check_interval_poll!(i, start, 300);
103
104 time::advance(ms(650)).await;
105 check_interval_poll!(i, start, 600);
106
107 time::advance(ms(100)).await;
108 check_interval_poll!(i, start);
109
110 // We have to add one here for the same reason as is above.
111 // Because `Interval` has reset its timer according to `Instant::now()`,
112 // we have to go forward 1 more millisecond than is expected so that the
113 // runtime realizes that it's time to resolve the timer.
114 time::advance(ms(201)).await;
115 // We add one because when using the `Delay` behavior, `Interval`
116 // adds the `period` from `Instant::now()`, which will always be off by one
117 // because we have to advance time by 1 (see above).
118 check_interval_poll!(i, start, 1251);
119
120 time::advance(ms(300)).await;
121 // Again, we add one.
122 check_interval_poll!(i, start, 1551);
123
124 time::advance(ms(300)).await;
125 check_interval_poll!(i, start, 1851);
126 }
127
128 // Expected ticks: | 1 | 2 | 3 | 4 | 5 | 6 |
129 // Actual ticks: | work -----| delay | work ---| work -----| work -----|
130 // Poll behavior: | | | | | | |
131 // | | | | | | |
132 // Ready(s) | | Ready(s + 2p) | | |
133 // Pending | Ready(s + 4p) | |
134 // Ready(s + p) Ready(s + 5p) |
135 // Ready(s + 6p)
136 #[tokio::test(start_paused = true)]
skip()137 async fn skip() {
138 let start = Instant::now();
139
140 // This is necessary because the timer is only so granular, and in order for
141 // all our ticks to resolve, the time needs to be 1ms ahead of what we
142 // expect, so that the runtime will see that it is time to resolve the timer
143 time::advance(ms(1)).await;
144
145 let mut i = task::spawn(time::interval_at(start, ms(300)));
146 i.set_missed_tick_behavior(MissedTickBehavior::Skip);
147
148 check_interval_poll!(i, start, 0);
149
150 time::advance(ms(100)).await;
151 check_interval_poll!(i, start);
152
153 time::advance(ms(200)).await;
154 check_interval_poll!(i, start, 300);
155
156 time::advance(ms(650)).await;
157 check_interval_poll!(i, start, 600);
158
159 time::advance(ms(250)).await;
160 check_interval_poll!(i, start, 1200);
161
162 time::advance(ms(300)).await;
163 check_interval_poll!(i, start, 1500);
164
165 time::advance(ms(300)).await;
166 check_interval_poll!(i, start, 1800);
167 }
168
169 #[tokio::test(start_paused = true)]
reset()170 async fn reset() {
171 let start = Instant::now();
172
173 // This is necessary because the timer is only so granular, and in order for
174 // all our ticks to resolve, the time needs to be 1ms ahead of what we
175 // expect, so that the runtime will see that it is time to resolve the timer
176 time::advance(ms(1)).await;
177
178 let mut i = task::spawn(time::interval_at(start, ms(300)));
179
180 check_interval_poll!(i, start, 0);
181
182 time::advance(ms(100)).await;
183 check_interval_poll!(i, start);
184
185 time::advance(ms(200)).await;
186 check_interval_poll!(i, start, 300);
187
188 time::advance(ms(100)).await;
189 check_interval_poll!(i, start);
190
191 i.reset();
192
193 time::advance(ms(250)).await;
194 check_interval_poll!(i, start);
195
196 time::advance(ms(50)).await;
197 // We add one because when using `reset` method, `Interval` adds the
198 // `period` from `Instant::now()`, which will always be off by one
199 check_interval_poll!(i, start, 701);
200
201 time::advance(ms(300)).await;
202 check_interval_poll!(i, start, 1001);
203 }
204
poll_next(interval: &mut task::Spawn<time::Interval>) -> Poll<Instant>205 fn poll_next(interval: &mut task::Spawn<time::Interval>) -> Poll<Instant> {
206 interval.enter(|cx, mut interval| interval.poll_tick(cx))
207 }
208
ms(n: u64) -> Duration209 fn ms(n: u64) -> Duration {
210 Duration::from_millis(n)
211 }
212