| // Copyright 2019 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "cast/streaming/ntp_time.h" |
| |
| #include <chrono> |
| |
| #include "gtest/gtest.h" |
| #include "util/chrono_helpers.h" |
| |
| namespace openscreen { |
| namespace cast { |
| |
| TEST(NtpTimestampTest, SplitsIntoParts) { |
| // 1 Jan 1900. |
| NtpTimestamp timestamp = UINT64_C(0x0000000000000000); |
| EXPECT_EQ(NtpSeconds::zero(), NtpSecondsPart(timestamp)); |
| EXPECT_EQ(NtpFraction::zero(), NtpFractionPart(timestamp)); |
| |
| // 1 Jan 1900 plus 10 ms. |
| timestamp = UINT64_C(0x00000000028f5c29); |
| EXPECT_EQ(NtpSeconds::zero(), NtpSecondsPart(timestamp)); |
| EXPECT_EQ(milliseconds(10), to_microseconds(NtpFractionPart(timestamp))); |
| |
| // 1 Jan 1970 minus 2^-32 seconds. |
| timestamp = UINT64_C(0x83aa7e80ffffffff); |
| EXPECT_EQ(NtpSeconds(INT64_C(2208988800)), NtpSecondsPart(timestamp)); |
| EXPECT_EQ(NtpFraction(0xffffffff), NtpFractionPart(timestamp)); |
| |
| // 2019-03-23 17:25:50.500. |
| timestamp = UINT64_C(0xe0414d0e80000000); |
| EXPECT_EQ(NtpSeconds(INT64_C(3762375950)), NtpSecondsPart(timestamp)); |
| EXPECT_EQ(milliseconds(500), to_microseconds(NtpFractionPart(timestamp))); |
| } |
| |
| TEST(NtpTimestampTest, AssemblesFromParts) { |
| // 1 Jan 1900. |
| NtpTimestamp timestamp = |
| AssembleNtpTimestamp(NtpSeconds::zero(), NtpFraction::zero()); |
| EXPECT_EQ(UINT64_C(0x0000000000000000), timestamp); |
| |
| // 1 Jan 1900 plus 10 ms. Note that the |
| // std::chrono::duration_cast<NtpFraction>(10ms) truncates rather than rounds |
| // the 10ms value, so the resulting timestamp is one fractional tick less than |
| // the one found in the SplitsIntoParts test. The ~0.4 nanosecond error in the |
| // conversion is totally insignificant to a live system. |
| timestamp = AssembleNtpTimestamp( |
| NtpSeconds::zero(), |
| std::chrono::duration_cast<NtpFraction>(milliseconds(10))); |
| EXPECT_EQ(UINT64_C(0x00000000028f5c28), timestamp); |
| |
| // 1 Jan 1970 minus 2^-32 seconds. |
| timestamp = AssembleNtpTimestamp(NtpSeconds(INT64_C(2208988799)), |
| NtpFraction(0xffffffff)); |
| EXPECT_EQ(UINT64_C(0x83aa7e7fffffffff), timestamp); |
| |
| // 2019-03-23 17:25:50.500. |
| timestamp = AssembleNtpTimestamp( |
| NtpSeconds(INT64_C(3762375950)), |
| std::chrono::duration_cast<NtpFraction>(milliseconds(500))); |
| EXPECT_EQ(UINT64_C(0xe0414d0e80000000), timestamp); |
| } |
| |
| TEST(NtpTimeConverterTest, ConvertsToNtpTimeAndBack) { |
| // There is an undetermined amount of delay between the sampling of the two |
| // clocks, but that is accounted for in the design (see class comments). |
| // Normally, sampling real clocks in unit tests is a recipe for flakiness |
| // down-the-road. However, if there is flakiness in this test, then some of |
| // our core assumptions (or the design) about the time math are wrong and |
| // should be looked into! |
| const Clock::time_point steady_clock_start = Clock::now(); |
| const std::chrono::seconds wall_clock_start = GetWallTimeSinceUnixEpoch(); |
| SCOPED_TRACE(::testing::Message() |
| << "steady_clock_start.time_since_epoch().count() is " |
| << steady_clock_start.time_since_epoch().count() |
| << ", wall_clock_start.count() is " << wall_clock_start.count()); |
| |
| const NtpTimeConverter converter(steady_clock_start, wall_clock_start); |
| |
| // Convert time points between the start time and 5 seconds later, in 10 ms |
| // increments. Allow the converted-back time point to be at most 1 clock tick |
| // off from the original value, but all converted values should always be |
| // monotonically increasing. |
| const Clock::time_point end_point = steady_clock_start + milliseconds(5000); |
| NtpTimestamp last_ntp_timestamp = 0; |
| Clock::time_point last_converted_back_time_point = Clock::time_point::min(); |
| for (Clock::time_point t = steady_clock_start; t < end_point; |
| t += milliseconds(10)) { |
| const NtpTimestamp ntp_timestamp = converter.ToNtpTimestamp(t); |
| ASSERT_GT(ntp_timestamp, last_ntp_timestamp); |
| last_ntp_timestamp = ntp_timestamp; |
| |
| const Clock::time_point converted_back_time_point = |
| converter.ToLocalTime(ntp_timestamp); |
| ASSERT_GT(converted_back_time_point, last_converted_back_time_point); |
| last_converted_back_time_point = converted_back_time_point; |
| |
| ASSERT_NEAR(t.time_since_epoch().count(), |
| converted_back_time_point.time_since_epoch().count(), |
| 1 /* tick */); |
| } |
| } |
| |
| } // namespace cast |
| } // namespace openscreen |