1// Copyright 2013 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chrome/browser/network_time/network_time_tracker.h" 6 7#include <math.h> 8 9#include "base/bind.h" 10#include "base/bind_helpers.h" 11#include "base/compiler_specific.h" 12#include "base/message_loop/message_loop.h" 13#include "content/public/test/test_browser_thread.h" 14#include "net/base/network_time_notifier.h" 15#include "testing/gtest/include/gtest/gtest.h" 16 17namespace { 18 19// These are all in milliseconds. 20const int64 kLatency1 = 50; 21const int64 kLatency2 = 500; 22 23// Can not be smaller than 15, it's the NowFromSystemTime() resolution. 24const int64 kResolution1 = 17; 25const int64 kResolution2 = 177; 26 27const int64 kPseudoSleepTime1 = 500000001; 28const int64 kPseudoSleepTime2 = 1888; 29 30// A custom tick clock that will return an arbitrary time. 31class TestTickClock : public base::TickClock { 32 public: 33 explicit TestTickClock(base::TimeTicks* ticks_now) : ticks_now_(ticks_now) {} 34 virtual ~TestTickClock() {} 35 36 virtual base::TimeTicks NowTicks() OVERRIDE { 37 return *ticks_now_; 38 } 39 40 private: 41 base::TimeTicks* ticks_now_; 42}; 43 44} // namespace 45 46class NetworkTimeTrackerTest : public testing::Test { 47 public: 48 NetworkTimeTrackerTest() 49 : ui_thread(content::BrowserThread::UI, &message_loop_), 50 io_thread(content::BrowserThread::IO, &message_loop_), 51 now_(base::Time::NowFromSystemTime()), 52 tick_clock_(new TestTickClock(&ticks_now_)), 53 network_time_notifier_( 54 new net::NetworkTimeNotifier( 55 tick_clock_.PassAs<base::TickClock>())) {} 56 virtual ~NetworkTimeTrackerTest() {} 57 58 virtual void TearDown() OVERRIDE { 59 message_loop_.RunUntilIdle(); 60 } 61 62 base::Time Now() const { 63 return now_ + (ticks_now_ - base::TimeTicks()); 64 } 65 66 base::TimeTicks TicksNow() const { 67 return ticks_now_; 68 } 69 70 void AddToTicksNow(int64 ms) { 71 ticks_now_ += base::TimeDelta::FromMilliseconds(ms); 72 } 73 74 void StartTracker() { 75 network_time_tracker_.reset(new NetworkTimeTracker()); 76 network_time_notifier_->AddObserver( 77 network_time_tracker_->BuildObserverCallback()); 78 message_loop_.RunUntilIdle(); 79 } 80 81 void StopTracker() { 82 network_time_tracker_.reset(); 83 } 84 85 // Updates the notifier's time with the specified parameters and waits until 86 // the observers have been updated. 87 void UpdateNetworkTime(const base::Time& network_time, 88 const base::TimeDelta& resolution, 89 const base::TimeDelta& latency, 90 const base::TimeTicks& post_time) { 91 message_loop_.PostTask( 92 FROM_HERE, 93 base::Bind(&net::NetworkTimeNotifier::UpdateNetworkTime, 94 base::Unretained(network_time_notifier_.get()), 95 network_time, 96 resolution, 97 latency, 98 post_time)); 99 message_loop_.RunUntilIdle(); 100 } 101 102 // Ensures the network time tracker has a network time and that the 103 // disparity between the network time version of |ticks_now_| and the actual 104 // |ticks_now_| value is within the uncertainty (should always be true 105 // because the network time notifier uses |ticks_now_| for the tick clock). 106 testing::AssertionResult ValidateExpectedTime() const { 107 base::Time network_time; 108 base::TimeDelta uncertainty; 109 if (!network_time_tracker_->GetNetworkTime(TicksNow(), 110 &network_time, 111 &uncertainty)) 112 return testing::AssertionFailure() << "Failed to get network time."; 113 if (fabs(static_cast<double>(Now().ToInternalValue() - 114 network_time.ToInternalValue())) > 115 static_cast<double>(uncertainty.ToInternalValue())) { 116 return testing::AssertionFailure() 117 << "Expected network time not within uncertainty."; 118 } 119 return testing::AssertionSuccess(); 120 } 121 122 NetworkTimeTracker* network_time_tracker() { 123 return network_time_tracker_.get(); 124 } 125 126 private: 127 // Message loop and threads for the tracker's internal logic. 128 base::MessageLoop message_loop_; 129 content::TestBrowserThread ui_thread; 130 content::TestBrowserThread io_thread; 131 132 // Used in building the current time that |tick_clock_| reports. See Now() 133 // for details. 134 base::Time now_; 135 base::TimeTicks ticks_now_; 136 137 // A custom clock that allows arbitrary time delays. 138 scoped_ptr<TestTickClock> tick_clock_; 139 140 // The network time notifier that receives time updates and posts them to 141 // the tracker. 142 scoped_ptr<net::NetworkTimeNotifier> network_time_notifier_; 143 144 // The network time tracker being tested. 145 scoped_ptr<NetworkTimeTracker> network_time_tracker_; 146}; 147 148// Should not return a value before UpdateNetworkTime gets called. 149TEST_F(NetworkTimeTrackerTest, Uninitialized) { 150 base::Time network_time; 151 base::TimeDelta uncertainty; 152 StartTracker(); 153 EXPECT_FALSE(network_time_tracker()->GetNetworkTime(base::TimeTicks(), 154 &network_time, 155 &uncertainty)); 156} 157 158// Verify that the the tracker receives and properly handles updates to the 159// network time. 160TEST_F(NetworkTimeTrackerTest, NetworkTimeUpdates) { 161 StartTracker(); 162 UpdateNetworkTime( 163 Now(), 164 base::TimeDelta::FromMilliseconds(kResolution1), 165 base::TimeDelta::FromMilliseconds(kLatency1), 166 TicksNow()); 167 EXPECT_TRUE(ValidateExpectedTime()); 168 169 // Fake a wait for kPseudoSleepTime1 to make sure we keep tracking. 170 AddToTicksNow(kPseudoSleepTime1); 171 EXPECT_TRUE(ValidateExpectedTime()); 172 173 // Update the time with a new now value and kLatency2. 174 UpdateNetworkTime( 175 Now(), 176 base::TimeDelta::FromMilliseconds(kResolution2), 177 base::TimeDelta::FromMilliseconds(kLatency2), 178 TicksNow()); 179 180 // Fake a wait for kPseudoSleepTime2 to make sure we keep tracking still. 181 AddToTicksNow(kPseudoSleepTime2); 182 EXPECT_TRUE(ValidateExpectedTime()); 183 184 // Fake a long delay between update task post time and the network notifier 185 // updating its network time. The uncertainty should account for the 186 // disparity. 187 base::Time old_now = Now(); 188 base::TimeTicks old_ticks = TicksNow(); 189 AddToTicksNow(kPseudoSleepTime2); 190 UpdateNetworkTime( 191 old_now, 192 base::TimeDelta::FromMilliseconds(kResolution2), 193 base::TimeDelta::FromMilliseconds(kLatency2), 194 old_ticks); 195 EXPECT_TRUE(ValidateExpectedTime()); 196} 197 198// Starting the tracker after the network time has been set with the notifier 199// should update the tracker's time as well. 200TEST_F(NetworkTimeTrackerTest, UpdateThenStartTracker) { 201 UpdateNetworkTime( 202 Now(), 203 base::TimeDelta::FromMilliseconds(kResolution1), 204 base::TimeDelta::FromMilliseconds(kLatency1), 205 TicksNow()); 206 StartTracker(); 207 EXPECT_TRUE(ValidateExpectedTime()); 208} 209 210// Time updates after the tracker has been destroyed should not attempt to 211// dereference the destroyed tracker. 212TEST_F(NetworkTimeTrackerTest, UpdateAfterTrackerDestroyed) { 213 StartTracker(); 214 StopTracker(); 215 UpdateNetworkTime( 216 Now(), 217 base::TimeDelta::FromMilliseconds(kResolution1), 218 base::TimeDelta::FromMilliseconds(kLatency1), 219 TicksNow()); 220} 221