- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / network_time / network_time_tracker_unittest.cc
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
17 namespace {
18
19 // These are all in milliseconds.
20 const int64 kLatency1 = 50;
21 const int64 kLatency2 = 500;
22
23 // Can not be smaller than 15, it's the NowFromSystemTime() resolution.
24 const int64 kResolution1 = 17;
25 const int64 kResolution2 = 177;
26
27 const int64 kPseudoSleepTime1 = 500000001;
28 const int64 kPseudoSleepTime2 = 1888;
29
30 // A custom tick clock that will return an arbitrary time.
31 class 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
46 class 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.
149 TEST_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.
160 TEST_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.
200 TEST_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.
212 TEST_F(NetworkTimeTrackerTest, UpdateAfterTrackerDestroyed) {
213   StartTracker();
214   StopTracker();
215   UpdateNetworkTime(
216       Now(),
217       base::TimeDelta::FromMilliseconds(kResolution1),
218       base::TimeDelta::FromMilliseconds(kLatency1),
219       TicksNow());
220 }