• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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