1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "cast/streaming/ntp_time.h"
6
7 #include <chrono>
8
9 #include "gtest/gtest.h"
10 #include "util/chrono_helpers.h"
11
12 namespace openscreen {
13 namespace cast {
14
TEST(NtpTimestampTest,SplitsIntoParts)15 TEST(NtpTimestampTest, SplitsIntoParts) {
16 // 1 Jan 1900.
17 NtpTimestamp timestamp = UINT64_C(0x0000000000000000);
18 EXPECT_EQ(NtpSeconds::zero(), NtpSecondsPart(timestamp));
19 EXPECT_EQ(NtpFraction::zero(), NtpFractionPart(timestamp));
20
21 // 1 Jan 1900 plus 10 ms.
22 timestamp = UINT64_C(0x00000000028f5c29);
23 EXPECT_EQ(NtpSeconds::zero(), NtpSecondsPart(timestamp));
24 EXPECT_EQ(milliseconds(10), to_milliseconds(NtpFractionPart(timestamp)));
25
26 // 1 Jan 1970 minus 2^-32 seconds.
27 timestamp = UINT64_C(0x83aa7e80ffffffff);
28 EXPECT_EQ(NtpSeconds(INT64_C(2208988800)), NtpSecondsPart(timestamp));
29 EXPECT_EQ(NtpFraction(0xffffffff), NtpFractionPart(timestamp));
30
31 // 2019-03-23 17:25:50.500.
32 timestamp = UINT64_C(0xe0414d0e80000000);
33 EXPECT_EQ(NtpSeconds(INT64_C(3762375950)), NtpSecondsPart(timestamp));
34 EXPECT_EQ(milliseconds(500), to_milliseconds(NtpFractionPart(timestamp)));
35 }
36
TEST(NtpTimestampTest,AssemblesFromParts)37 TEST(NtpTimestampTest, AssemblesFromParts) {
38 // 1 Jan 1900.
39 NtpTimestamp timestamp =
40 AssembleNtpTimestamp(NtpSeconds::zero(), NtpFraction::zero());
41 EXPECT_EQ(UINT64_C(0x0000000000000000), timestamp);
42
43 // 1 Jan 1900 plus 10 ms. Note that the duration_cast<NtpFraction>(10ms)
44 // truncates rather than rounds the 10ms value, so the resulting timestamp is
45 // one fractional tick less than the one found in the SplitsIntoParts test.
46 // The ~0.4 nanosecond error in the conversion is totally insignificant to a
47 // live system.
48 timestamp = AssembleNtpTimestamp(
49 NtpSeconds::zero(),
50 std::chrono::duration_cast<NtpFraction>(milliseconds(10)));
51 EXPECT_EQ(UINT64_C(0x00000000028f5c28), timestamp);
52
53 // 1 Jan 1970 minus 2^-32 seconds.
54 timestamp = AssembleNtpTimestamp(NtpSeconds(INT64_C(2208988799)),
55 NtpFraction(0xffffffff));
56 EXPECT_EQ(UINT64_C(0x83aa7e7fffffffff), timestamp);
57
58 // 2019-03-23 17:25:50.500.
59 timestamp = AssembleNtpTimestamp(
60 NtpSeconds(INT64_C(3762375950)),
61 std::chrono::duration_cast<NtpFraction>(milliseconds(500)));
62 EXPECT_EQ(UINT64_C(0xe0414d0e80000000), timestamp);
63 }
64
TEST(NtpTimeConverterTest,ConvertsToNtpTimeAndBack)65 TEST(NtpTimeConverterTest, ConvertsToNtpTimeAndBack) {
66 // There is an undetermined amount of delay between the sampling of the two
67 // clocks, but that is accounted for in the design (see class comments).
68 // Normally, sampling real clocks in unit tests is a recipe for flakiness
69 // down-the-road. However, if there is flakiness in this test, then some of
70 // our core assumptions (or the design) about the time math are wrong and
71 // should be looked into!
72 const Clock::time_point steady_clock_start = Clock::now();
73 const seconds wall_clock_start = GetWallTimeSinceUnixEpoch();
74 SCOPED_TRACE(::testing::Message()
75 << "steady_clock_start.time_since_epoch().count() is "
76 << steady_clock_start.time_since_epoch().count()
77 << ", wall_clock_start.count() is " << wall_clock_start.count());
78
79 const NtpTimeConverter converter(steady_clock_start, wall_clock_start);
80
81 // Convert time points between the start time and 5 seconds later, in 10 ms
82 // increments. Allow the converted-back time point to be at most 1 clock tick
83 // off from the original value, but all converted values should always be
84 // monotonically increasing.
85 const Clock::time_point end_point = steady_clock_start + milliseconds(5000);
86 NtpTimestamp last_ntp_timestamp = 0;
87 Clock::time_point last_converted_back_time_point = Clock::time_point::min();
88 for (Clock::time_point t = steady_clock_start; t < end_point;
89 t += milliseconds(10)) {
90 const NtpTimestamp ntp_timestamp = converter.ToNtpTimestamp(t);
91 ASSERT_GT(ntp_timestamp, last_ntp_timestamp);
92 last_ntp_timestamp = ntp_timestamp;
93
94 const Clock::time_point converted_back_time_point =
95 converter.ToLocalTime(ntp_timestamp);
96 ASSERT_GT(converted_back_time_point, last_converted_back_time_point);
97 last_converted_back_time_point = converted_back_time_point;
98
99 ASSERT_NEAR(t.time_since_epoch().count(),
100 converted_back_time_point.time_since_epoch().count(),
101 1 /* tick */);
102 }
103 }
104
105 } // namespace cast
106 } // namespace openscreen
107