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