bd5eb6e9d074d622cde7b6335e91f3320e95e8b2
[platform/framework/web/crosswalk.git] / src / content / browser / geolocation / location_arbitrator_impl_unittest.cc
1 // Copyright (c) 2012 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 "base/bind.h"
6 #include "base/memory/scoped_ptr.h"
7 #include "content/browser/geolocation/fake_access_token_store.h"
8 #include "content/browser/geolocation/location_arbitrator_impl.h"
9 #include "content/browser/geolocation/mock_location_provider.h"
10 #include "content/public/common/geoposition.h"
11 #include "testing/gmock/include/gmock/gmock.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13
14 using ::testing::NiceMock;
15
16 namespace content {
17
18 class MockLocationObserver {
19  public:
20   // Need a vtable for GMock.
21   virtual ~MockLocationObserver() {}
22   void InvalidateLastPosition() {
23     last_position_.latitude = 100;
24     last_position_.error_code = Geoposition::ERROR_CODE_NONE;
25     ASSERT_FALSE(last_position_.Validate());
26   }
27   // Delegate
28   void OnLocationUpdate(const Geoposition& position) {
29     last_position_ = position;
30   }
31
32   Geoposition last_position_;
33 };
34
35 double g_fake_time_now_secs = 1;
36
37 base::Time GetTimeNowForTest() {
38   return base::Time::FromDoubleT(g_fake_time_now_secs);
39 }
40
41 void AdvanceTimeNow(const base::TimeDelta& delta) {
42   g_fake_time_now_secs += delta.InSecondsF();
43 }
44
45 void SetPositionFix(MockLocationProvider* provider,
46                     double latitude,
47                     double longitude,
48                     double accuracy) {
49   Geoposition position;
50   position.error_code = Geoposition::ERROR_CODE_NONE;
51   position.latitude = latitude;
52   position.longitude = longitude;
53   position.accuracy = accuracy;
54   position.timestamp = GetTimeNowForTest();
55   ASSERT_TRUE(position.Validate());
56   provider->HandlePositionChanged(position);
57 }
58
59 void SetReferencePosition(MockLocationProvider* provider) {
60   SetPositionFix(provider, 51.0, -0.1, 400);
61 }
62
63 namespace {
64
65 class TestingLocationArbitrator : public LocationArbitratorImpl {
66  public:
67   TestingLocationArbitrator(
68       const LocationArbitratorImpl::LocationUpdateCallback& callback,
69       AccessTokenStore* access_token_store)
70       : LocationArbitratorImpl(callback),
71         cell_(NULL),
72         gps_(NULL),
73         access_token_store_(access_token_store) {
74   }
75
76   base::Time GetTimeNow() const override { return GetTimeNowForTest(); }
77
78   AccessTokenStore* NewAccessTokenStore() override {
79     return access_token_store_.get();
80   }
81
82   LocationProvider* NewNetworkLocationProvider(
83       AccessTokenStore* access_token_store,
84       net::URLRequestContextGetter* context,
85       const GURL& url,
86       const base::string16& access_token) override {
87     return new MockLocationProvider(&cell_);
88   }
89
90   LocationProvider* NewSystemLocationProvider() override {
91     return new MockLocationProvider(&gps_);
92   }
93
94   // Two location providers, with nice short names to make the tests more
95   // readable. Note |gps_| will only be set when there is a high accuracy
96   // observer registered (and |cell_| when there's at least one observer of any
97   // type).
98   MockLocationProvider* cell_;
99   MockLocationProvider* gps_;
100   scoped_refptr<AccessTokenStore> access_token_store_;
101 };
102
103 }  // namespace
104
105 class GeolocationLocationArbitratorTest : public testing::Test {
106  protected:
107   // testing::Test
108   void SetUp() override {
109     access_token_store_ = new NiceMock<FakeAccessTokenStore>;
110     observer_.reset(new MockLocationObserver);
111     LocationArbitratorImpl::LocationUpdateCallback callback =
112         base::Bind(&MockLocationObserver::OnLocationUpdate,
113                    base::Unretained(observer_.get()));
114     arbitrator_.reset(new TestingLocationArbitrator(
115         callback, access_token_store_.get()));
116   }
117
118   // testing::Test
119   void TearDown() override {}
120
121   void CheckLastPositionInfo(double latitude,
122                              double longitude,
123                              double accuracy) {
124     Geoposition geoposition = observer_->last_position_;
125     EXPECT_TRUE(geoposition.Validate());
126     EXPECT_DOUBLE_EQ(latitude, geoposition.latitude);
127     EXPECT_DOUBLE_EQ(longitude, geoposition.longitude);
128     EXPECT_DOUBLE_EQ(accuracy, geoposition.accuracy);
129   }
130
131   base::TimeDelta SwitchOnFreshnessCliff() {
132     // Add 1, to ensure it meets any greater-than test.
133     return base::TimeDelta::FromMilliseconds(
134         LocationArbitratorImpl::kFixStaleTimeoutMilliseconds + 1);
135   }
136
137   MockLocationProvider* cell() {
138     return arbitrator_->cell_;
139   }
140
141   MockLocationProvider* gps() {
142     return arbitrator_->gps_;
143   }
144
145   scoped_refptr<FakeAccessTokenStore> access_token_store_;
146   scoped_ptr<MockLocationObserver> observer_;
147   scoped_ptr<TestingLocationArbitrator> arbitrator_;
148   base::MessageLoop loop_;
149 };
150
151 TEST_F(GeolocationLocationArbitratorTest, CreateDestroy) {
152   EXPECT_TRUE(access_token_store_.get());
153   EXPECT_TRUE(arbitrator_ != NULL);
154   arbitrator_.reset();
155   SUCCEED();
156 }
157
158 TEST_F(GeolocationLocationArbitratorTest, OnPermissionGranted) {
159   EXPECT_FALSE(arbitrator_->HasPermissionBeenGranted());
160   arbitrator_->OnPermissionGranted();
161   EXPECT_TRUE(arbitrator_->HasPermissionBeenGranted());
162   // Can't check the provider has been notified without going through the
163   // motions to create the provider (see next test).
164   EXPECT_FALSE(cell());
165   EXPECT_FALSE(gps());
166 }
167
168 TEST_F(GeolocationLocationArbitratorTest, NormalUsage) {
169   ASSERT_TRUE(access_token_store_.get());
170   ASSERT_TRUE(arbitrator_ != NULL);
171
172   EXPECT_FALSE(cell());
173   EXPECT_FALSE(gps());
174   arbitrator_->StartProviders(false);
175
176   EXPECT_TRUE(access_token_store_->access_token_set_.empty());
177   EXPECT_TRUE(access_token_store_->access_token_set_.empty());
178
179   access_token_store_->NotifyDelegateTokensLoaded();
180   ASSERT_TRUE(cell());
181   EXPECT_TRUE(gps());
182   EXPECT_EQ(MockLocationProvider::LOW_ACCURACY, cell()->state_);
183   EXPECT_EQ(MockLocationProvider::LOW_ACCURACY, gps()->state_);
184   EXPECT_FALSE(observer_->last_position_.Validate());
185   EXPECT_EQ(Geoposition::ERROR_CODE_NONE,
186             observer_->last_position_.error_code);
187
188   SetReferencePosition(cell());
189
190   EXPECT_TRUE(observer_->last_position_.Validate() ||
191               observer_->last_position_.error_code !=
192                   Geoposition::ERROR_CODE_NONE);
193   EXPECT_EQ(cell()->position_.latitude,
194             observer_->last_position_.latitude);
195
196   EXPECT_FALSE(cell()->is_permission_granted_);
197   EXPECT_FALSE(arbitrator_->HasPermissionBeenGranted());
198   arbitrator_->OnPermissionGranted();
199   EXPECT_TRUE(arbitrator_->HasPermissionBeenGranted());
200   EXPECT_TRUE(cell()->is_permission_granted_);
201 }
202
203 TEST_F(GeolocationLocationArbitratorTest, SetObserverOptions) {
204   arbitrator_->StartProviders(false);
205   access_token_store_->NotifyDelegateTokensLoaded();
206   ASSERT_TRUE(cell());
207   ASSERT_TRUE(gps());
208   EXPECT_EQ(MockLocationProvider::LOW_ACCURACY, cell()->state_);
209   EXPECT_EQ(MockLocationProvider::LOW_ACCURACY, gps()->state_);
210   SetReferencePosition(cell());
211   EXPECT_EQ(MockLocationProvider::LOW_ACCURACY, cell()->state_);
212   EXPECT_EQ(MockLocationProvider::LOW_ACCURACY, gps()->state_);
213   arbitrator_->StartProviders(true);
214   EXPECT_EQ(MockLocationProvider::HIGH_ACCURACY, cell()->state_);
215   EXPECT_EQ(MockLocationProvider::HIGH_ACCURACY, gps()->state_);
216 }
217
218 TEST_F(GeolocationLocationArbitratorTest, Arbitration) {
219   arbitrator_->StartProviders(false);
220   access_token_store_->NotifyDelegateTokensLoaded();
221   ASSERT_TRUE(cell());
222   ASSERT_TRUE(gps());
223
224   SetPositionFix(cell(), 1, 2, 150);
225
226   // First position available
227   EXPECT_TRUE(observer_->last_position_.Validate());
228   CheckLastPositionInfo(1, 2, 150);
229
230   SetPositionFix(gps(), 3, 4, 50);
231
232   // More accurate fix available
233   CheckLastPositionInfo(3, 4, 50);
234
235   SetPositionFix(cell(), 5, 6, 150);
236
237   // New fix is available but it's less accurate, older fix should be kept.
238   CheckLastPositionInfo(3, 4, 50);
239
240   // Advance time, and notify once again
241   AdvanceTimeNow(SwitchOnFreshnessCliff());
242   cell()->HandlePositionChanged(cell()->position_);
243
244   // New fix is available, less accurate but fresher
245   CheckLastPositionInfo(5, 6, 150);
246
247   // Advance time, and set a low accuracy position
248   AdvanceTimeNow(SwitchOnFreshnessCliff());
249   SetPositionFix(cell(), 5.676731, 139.629385, 1000);
250   CheckLastPositionInfo(5.676731, 139.629385, 1000);
251
252   // 15 secs later, step outside. Switches to gps signal.
253   AdvanceTimeNow(base::TimeDelta::FromSeconds(15));
254   SetPositionFix(gps(), 3.5676457, 139.629198, 50);
255   CheckLastPositionInfo(3.5676457, 139.629198, 50);
256
257   // 5 mins later switch cells while walking. Stay on gps.
258   AdvanceTimeNow(base::TimeDelta::FromMinutes(5));
259   SetPositionFix(cell(), 3.567832, 139.634648, 300);
260   SetPositionFix(gps(), 3.5677675, 139.632314, 50);
261   CheckLastPositionInfo(3.5677675, 139.632314, 50);
262
263   // Ride train and gps signal degrades slightly. Stay on fresher gps
264   AdvanceTimeNow(base::TimeDelta::FromMinutes(5));
265   SetPositionFix(gps(), 3.5679026, 139.634777, 300);
266   CheckLastPositionInfo(3.5679026, 139.634777, 300);
267
268   // 14 minutes later
269   AdvanceTimeNow(base::TimeDelta::FromMinutes(14));
270
271   // GPS reading misses a beat, but don't switch to cell yet to avoid
272   // oscillating.
273   SetPositionFix(gps(), 3.5659005, 139.682579, 300);
274
275   AdvanceTimeNow(base::TimeDelta::FromSeconds(7));
276   SetPositionFix(cell(), 3.5689579, 139.691420, 1000);
277   CheckLastPositionInfo(3.5659005, 139.682579, 300);
278
279   // 1 minute later
280   AdvanceTimeNow(base::TimeDelta::FromMinutes(1));
281
282   // Enter tunnel. Stay on fresher gps for a moment.
283   SetPositionFix(cell(), 3.5657078, 139.68922, 300);
284   SetPositionFix(gps(), 3.5657104, 139.690341, 300);
285   CheckLastPositionInfo(3.5657104, 139.690341, 300);
286
287   // 2 minutes later
288   AdvanceTimeNow(base::TimeDelta::FromMinutes(2));
289   // Arrive in station. Cell moves but GPS is stale. Switch to fresher cell.
290   SetPositionFix(cell(), 3.5658700, 139.069979, 1000);
291   CheckLastPositionInfo(3.5658700, 139.069979, 1000);
292 }
293
294 TEST_F(GeolocationLocationArbitratorTest, TwoOneShotsIsNewPositionBetter) {
295   arbitrator_->StartProviders(false);
296   access_token_store_->NotifyDelegateTokensLoaded();
297   ASSERT_TRUE(cell());
298   ASSERT_TRUE(gps());
299
300   // Set the initial position.
301   SetPositionFix(cell(), 3, 139, 100);
302   CheckLastPositionInfo(3, 139, 100);
303
304   // Restart providers to simulate a one-shot request.
305   arbitrator_->StopProviders();
306
307   // To test 240956, perform a throwaway alloc.
308   // This convinces the allocator to put the providers in a new memory location.
309   MockLocationProvider* fakeMockProvider = NULL;
310   LocationProvider* fakeProvider =
311       new MockLocationProvider(&fakeMockProvider);
312
313   arbitrator_->StartProviders(false);
314   access_token_store_->NotifyDelegateTokensLoaded();
315
316   // Advance the time a short while to simulate successive calls.
317   AdvanceTimeNow(base::TimeDelta::FromMilliseconds(5));
318
319   // Update with a less accurate position to verify 240956.
320   SetPositionFix(cell(), 3, 139, 150);
321   CheckLastPositionInfo(3, 139, 150);
322
323   // No delete required for fakeMockProvider. It points to fakeProvider.
324   delete fakeProvider;
325 }
326
327 }  // namespace content