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