1 /*
2 * Copyright 2004 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "rtc_base/time_utils.h"
12
13 #include <memory>
14
15 #include "api/units/time_delta.h"
16 #include "rtc_base/event.h"
17 #include "rtc_base/fake_clock.h"
18 #include "rtc_base/helpers.h"
19 #include "rtc_base/thread.h"
20 #include "test/gtest.h"
21
22 namespace rtc {
23 using ::webrtc::TimeDelta;
24
TEST(TimeTest,TimeInMs)25 TEST(TimeTest, TimeInMs) {
26 int64_t ts_earlier = TimeMillis();
27 Thread::SleepMs(100);
28 int64_t ts_now = TimeMillis();
29 // Allow for the thread to wakeup ~20ms early.
30 EXPECT_GE(ts_now, ts_earlier + 80);
31 // Make sure the Time is not returning in smaller unit like microseconds.
32 EXPECT_LT(ts_now, ts_earlier + 1000);
33 }
34
TEST(TimeTest,Intervals)35 TEST(TimeTest, Intervals) {
36 int64_t ts_earlier = TimeMillis();
37 int64_t ts_later = TimeAfter(500);
38
39 // We can't depend on ts_later and ts_earlier to be exactly 500 apart
40 // since time elapses between the calls to TimeMillis() and TimeAfter(500)
41 EXPECT_LE(500, TimeDiff(ts_later, ts_earlier));
42 EXPECT_GE(-500, TimeDiff(ts_earlier, ts_later));
43
44 // Time has elapsed since ts_earlier
45 EXPECT_GE(TimeSince(ts_earlier), 0);
46
47 // ts_earlier is earlier than now, so TimeUntil ts_earlier is -ve
48 EXPECT_LE(TimeUntil(ts_earlier), 0);
49
50 // ts_later likely hasn't happened yet, so TimeSince could be -ve
51 // but within 500
52 EXPECT_GE(TimeSince(ts_later), -500);
53
54 // TimeUntil ts_later is at most 500
55 EXPECT_LE(TimeUntil(ts_later), 500);
56 }
57
TEST(TimeTest,TestTimeDiff64)58 TEST(TimeTest, TestTimeDiff64) {
59 int64_t ts_diff = 100;
60 int64_t ts_earlier = rtc::TimeMillis();
61 int64_t ts_later = ts_earlier + ts_diff;
62 EXPECT_EQ(ts_diff, rtc::TimeDiff(ts_later, ts_earlier));
63 EXPECT_EQ(-ts_diff, rtc::TimeDiff(ts_earlier, ts_later));
64 }
65
66 class TimestampWrapAroundHandlerTest : public ::testing::Test {
67 public:
TimestampWrapAroundHandlerTest()68 TimestampWrapAroundHandlerTest() {}
69
70 protected:
71 TimestampWrapAroundHandler wraparound_handler_;
72 };
73
TEST_F(TimestampWrapAroundHandlerTest,Unwrap)74 TEST_F(TimestampWrapAroundHandlerTest, Unwrap) {
75 // Start value.
76 int64_t ts = 2;
77 EXPECT_EQ(ts,
78 wraparound_handler_.Unwrap(static_cast<uint32_t>(ts & 0xffffffff)));
79
80 // Wrap backwards.
81 ts = -2;
82 EXPECT_EQ(ts,
83 wraparound_handler_.Unwrap(static_cast<uint32_t>(ts & 0xffffffff)));
84
85 // Forward to 2 again.
86 ts = 2;
87 EXPECT_EQ(ts,
88 wraparound_handler_.Unwrap(static_cast<uint32_t>(ts & 0xffffffff)));
89
90 // Max positive skip ahead, until max value (0xffffffff).
91 for (uint32_t i = 0; i <= 0xf; ++i) {
92 ts = (i << 28) + 0x0fffffff;
93 EXPECT_EQ(
94 ts, wraparound_handler_.Unwrap(static_cast<uint32_t>(ts & 0xffffffff)));
95 }
96
97 // Wrap around.
98 ts += 2;
99 EXPECT_EQ(ts,
100 wraparound_handler_.Unwrap(static_cast<uint32_t>(ts & 0xffffffff)));
101
102 // Max wrap backward...
103 ts -= 0x0fffffff;
104 EXPECT_EQ(ts,
105 wraparound_handler_.Unwrap(static_cast<uint32_t>(ts & 0xffffffff)));
106
107 // ...and back again.
108 ts += 0x0fffffff;
109 EXPECT_EQ(ts,
110 wraparound_handler_.Unwrap(static_cast<uint32_t>(ts & 0xffffffff)));
111 }
112
TEST_F(TimestampWrapAroundHandlerTest,NoNegativeStart)113 TEST_F(TimestampWrapAroundHandlerTest, NoNegativeStart) {
114 int64_t ts = 0xfffffff0;
115 EXPECT_EQ(ts,
116 wraparound_handler_.Unwrap(static_cast<uint32_t>(ts & 0xffffffff)));
117 }
118
119 class TmToSeconds : public ::testing::Test {
120 public:
TmToSeconds()121 TmToSeconds() {
122 // Set use of the test RNG to get deterministic expiration timestamp.
123 rtc::SetRandomTestMode(true);
124 }
~TmToSeconds()125 ~TmToSeconds() override {
126 // Put it back for the next test.
127 rtc::SetRandomTestMode(false);
128 }
129
TestTmToSeconds(int times)130 void TestTmToSeconds(int times) {
131 static char mdays[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
132 for (int i = 0; i < times; i++) {
133 // First generate something correct and check that TmToSeconds is happy.
134 int year = rtc::CreateRandomId() % 400 + 1970;
135
136 bool leap_year = false;
137 if (year % 4 == 0)
138 leap_year = true;
139 if (year % 100 == 0)
140 leap_year = false;
141 if (year % 400 == 0)
142 leap_year = true;
143
144 std::tm tm;
145 tm.tm_year = year - 1900; // std::tm is year 1900 based.
146 tm.tm_mon = rtc::CreateRandomId() % 12;
147 tm.tm_mday = rtc::CreateRandomId() % mdays[tm.tm_mon] + 1;
148 tm.tm_hour = rtc::CreateRandomId() % 24;
149 tm.tm_min = rtc::CreateRandomId() % 60;
150 tm.tm_sec = rtc::CreateRandomId() % 60;
151 int64_t t = rtc::TmToSeconds(tm);
152 EXPECT_TRUE(t >= 0);
153
154 // Now damage a random field and check that TmToSeconds is unhappy.
155 switch (rtc::CreateRandomId() % 11) {
156 case 0:
157 tm.tm_year = 1969 - 1900;
158 break;
159 case 1:
160 tm.tm_mon = -1;
161 break;
162 case 2:
163 tm.tm_mon = 12;
164 break;
165 case 3:
166 tm.tm_mday = 0;
167 break;
168 case 4:
169 tm.tm_mday = mdays[tm.tm_mon] + (leap_year && tm.tm_mon == 1) + 1;
170 break;
171 case 5:
172 tm.tm_hour = -1;
173 break;
174 case 6:
175 tm.tm_hour = 24;
176 break;
177 case 7:
178 tm.tm_min = -1;
179 break;
180 case 8:
181 tm.tm_min = 60;
182 break;
183 case 9:
184 tm.tm_sec = -1;
185 break;
186 case 10:
187 tm.tm_sec = 60;
188 break;
189 }
190 EXPECT_EQ(rtc::TmToSeconds(tm), -1);
191 }
192 // Check consistency with the system gmtime_r. With time_t, we can only
193 // portably test dates until 2038, which is achieved by the % 0x80000000.
194 for (int i = 0; i < times; i++) {
195 time_t t = rtc::CreateRandomId() % 0x80000000;
196 #if defined(WEBRTC_WIN)
197 std::tm* tm = std::gmtime(&t);
198 EXPECT_TRUE(tm);
199 EXPECT_TRUE(rtc::TmToSeconds(*tm) == t);
200 #else
201 std::tm tm;
202 EXPECT_TRUE(gmtime_r(&t, &tm));
203 EXPECT_TRUE(rtc::TmToSeconds(tm) == t);
204 #endif
205 }
206 }
207 };
208
TEST_F(TmToSeconds,TestTmToSeconds)209 TEST_F(TmToSeconds, TestTmToSeconds) {
210 TestTmToSeconds(100000);
211 }
212
213 // Test that all the time functions exposed by TimeUtils get time from the
214 // fake clock when it's set.
TEST(FakeClock,TimeFunctionsUseFakeClock)215 TEST(FakeClock, TimeFunctionsUseFakeClock) {
216 FakeClock clock;
217 SetClockForTesting(&clock);
218
219 clock.SetTime(webrtc::Timestamp::Micros(987654));
220 EXPECT_EQ(987u, Time32());
221 EXPECT_EQ(987, TimeMillis());
222 EXPECT_EQ(987654, TimeMicros());
223 EXPECT_EQ(987654000, TimeNanos());
224 EXPECT_EQ(1000u, TimeAfter(13));
225
226 SetClockForTesting(nullptr);
227 // After it's unset, we should get a normal time.
228 EXPECT_NE(987, TimeMillis());
229 }
230
TEST(FakeClock,InitialTime)231 TEST(FakeClock, InitialTime) {
232 FakeClock clock;
233 EXPECT_EQ(0, clock.TimeNanos());
234 }
235
TEST(FakeClock,SetTime)236 TEST(FakeClock, SetTime) {
237 FakeClock clock;
238 clock.SetTime(webrtc::Timestamp::Micros(123));
239 EXPECT_EQ(123000, clock.TimeNanos());
240 clock.SetTime(webrtc::Timestamp::Micros(456));
241 EXPECT_EQ(456000, clock.TimeNanos());
242 }
243
TEST(FakeClock,AdvanceTime)244 TEST(FakeClock, AdvanceTime) {
245 FakeClock clock;
246 clock.AdvanceTime(webrtc::TimeDelta::Micros(1u));
247 EXPECT_EQ(1000, clock.TimeNanos());
248 clock.AdvanceTime(webrtc::TimeDelta::Micros(2222u));
249 EXPECT_EQ(2223000, clock.TimeNanos());
250 clock.AdvanceTime(webrtc::TimeDelta::Millis(3333u));
251 EXPECT_EQ(3335223000, clock.TimeNanos());
252 clock.AdvanceTime(webrtc::TimeDelta::Seconds(4444u));
253 EXPECT_EQ(4447335223000, clock.TimeNanos());
254 }
255
256 // When the clock is advanced, threads that are waiting in a socket select
257 // should wake up and look at the new time. This allows tests using the
258 // fake clock to run much faster, if the test is bound by time constraints
259 // (such as a test for a STUN ping timeout).
TEST(FakeClock,SettingTimeWakesThreads)260 TEST(FakeClock, SettingTimeWakesThreads) {
261 int64_t real_start_time_ms = TimeMillis();
262
263 ThreadProcessingFakeClock clock;
264 SetClockForTesting(&clock);
265
266 std::unique_ptr<Thread> worker(Thread::CreateWithSocketServer());
267 worker->Start();
268
269 // Post an event that won't be executed for 10 seconds.
270 Event message_handler_dispatched;
271 worker->PostDelayedTask(
272 [&message_handler_dispatched] { message_handler_dispatched.Set(); },
273 TimeDelta::Seconds(60));
274
275 // Wait for a bit for the worker thread to be started and enter its socket
276 // select(). Otherwise this test would be trivial since the worker thread
277 // would process the event as soon as it was started.
278 Thread::Current()->SleepMs(1000);
279
280 // Advance the fake clock, expecting the worker thread to wake up
281 // and dispatch the message instantly.
282 clock.AdvanceTime(webrtc::TimeDelta::Seconds(60u));
283 EXPECT_TRUE(message_handler_dispatched.Wait(webrtc::TimeDelta::Zero()));
284 worker->Stop();
285
286 SetClockForTesting(nullptr);
287
288 // The message should have been dispatched long before the 60 seconds fully
289 // elapsed (just a sanity check).
290 int64_t real_end_time_ms = TimeMillis();
291 EXPECT_LT(real_end_time_ms - real_start_time_ms, 10000);
292 }
293
294 } // namespace rtc
295