aboutsummaryrefslogtreecommitdiff
path: root/cast/streaming/ntp_time_unittest.cc
blob: 6c72a1876ba5f1a03d6028cdcb464cda26b5ca27 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
// 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 "gtest/gtest.h"

using openscreen::Clock;
using std::chrono::duration_cast;
using std::chrono::microseconds;
using std::chrono::milliseconds;

namespace cast {
namespace streaming {

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),
            duration_cast<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),
            duration_cast<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<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(), 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)),
                           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 =
      openscreen::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 streaming
}  // namespace cast