// 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 #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_milliseconds(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_milliseconds(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 duration_cast(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(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(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 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