blob: 325e75877f2fa4e2d9ddb7e832dc0d4904b12f88 [file] [log] [blame]
// 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