OLD | NEW |
| (Empty) |
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 "content/browser/geolocation/location_arbitrator_impl.h" | |
6 | |
7 #include <memory> | |
8 | |
9 #include "base/bind.h" | |
10 #include "base/memory/ptr_util.h" | |
11 #include "content/browser/geolocation/fake_access_token_store.h" | |
12 #include "content/browser/geolocation/mock_location_provider.h" | |
13 #include "content/public/browser/geolocation_delegate.h" | |
14 #include "content/public/common/geoposition.h" | |
15 #include "content/test/test_content_browser_client.h" | |
16 #include "testing/gmock/include/gmock/gmock.h" | |
17 #include "testing/gtest/include/gtest/gtest.h" | |
18 | |
19 using ::testing::NiceMock; | |
20 | |
21 namespace content { | |
22 | |
23 class MockLocationObserver { | |
24 public: | |
25 // Need a vtable for GMock. | |
26 virtual ~MockLocationObserver() {} | |
27 void InvalidateLastPosition() { | |
28 last_position_.latitude = 100; | |
29 last_position_.error_code = Geoposition::ERROR_CODE_NONE; | |
30 ASSERT_FALSE(last_position_.Validate()); | |
31 } | |
32 // Delegate | |
33 void OnLocationUpdate(const Geoposition& position) { | |
34 last_position_ = position; | |
35 } | |
36 | |
37 Geoposition last_position_; | |
38 }; | |
39 | |
40 double g_fake_time_now_secs = 1; | |
41 | |
42 base::Time GetTimeNowForTest() { | |
43 return base::Time::FromDoubleT(g_fake_time_now_secs); | |
44 } | |
45 | |
46 void AdvanceTimeNow(const base::TimeDelta& delta) { | |
47 g_fake_time_now_secs += delta.InSecondsF(); | |
48 } | |
49 | |
50 void SetPositionFix(MockLocationProvider* provider, | |
51 double latitude, | |
52 double longitude, | |
53 double accuracy) { | |
54 Geoposition position; | |
55 position.error_code = Geoposition::ERROR_CODE_NONE; | |
56 position.latitude = latitude; | |
57 position.longitude = longitude; | |
58 position.accuracy = accuracy; | |
59 position.timestamp = GetTimeNowForTest(); | |
60 ASSERT_TRUE(position.Validate()); | |
61 provider->HandlePositionChanged(position); | |
62 } | |
63 | |
64 void SetReferencePosition(MockLocationProvider* provider) { | |
65 SetPositionFix(provider, 51.0, -0.1, 400); | |
66 } | |
67 | |
68 namespace { | |
69 | |
70 class FakeGeolocationDelegate : public GeolocationDelegate { | |
71 public: | |
72 FakeGeolocationDelegate() = default; | |
73 | |
74 bool UseNetworkLocationProviders() override { return use_network_; } | |
75 void set_use_network(bool use_network) { use_network_ = use_network; } | |
76 | |
77 std::unique_ptr<LocationProvider> OverrideSystemLocationProvider() override { | |
78 DCHECK(!mock_location_provider_); | |
79 mock_location_provider_ = new MockLocationProvider; | |
80 return base::WrapUnique(mock_location_provider_); | |
81 } | |
82 | |
83 MockLocationProvider* mock_location_provider() const { | |
84 return mock_location_provider_; | |
85 } | |
86 | |
87 private: | |
88 bool use_network_ = true; | |
89 MockLocationProvider* mock_location_provider_ = nullptr; | |
90 | |
91 DISALLOW_COPY_AND_ASSIGN(FakeGeolocationDelegate); | |
92 }; | |
93 | |
94 } // namespace | |
95 | |
96 class TestingLocationArbitrator : public LocationArbitratorImpl { | |
97 public: | |
98 TestingLocationArbitrator( | |
99 const LocationArbitratorImpl::LocationUpdateCallback& callback, | |
100 const scoped_refptr<AccessTokenStore>& access_token_store, | |
101 GeolocationDelegate* delegate) | |
102 : LocationArbitratorImpl(callback, delegate), | |
103 cell_(nullptr), | |
104 gps_(nullptr), | |
105 access_token_store_(access_token_store) {} | |
106 | |
107 base::Time GetTimeNow() const override { return GetTimeNowForTest(); } | |
108 | |
109 scoped_refptr<AccessTokenStore> NewAccessTokenStore() override { | |
110 return access_token_store_; | |
111 } | |
112 | |
113 std::unique_ptr<LocationProvider> NewNetworkLocationProvider( | |
114 const scoped_refptr<AccessTokenStore>& access_token_store, | |
115 const scoped_refptr<net::URLRequestContextGetter>& context, | |
116 const GURL& url, | |
117 const base::string16& access_token) override { | |
118 cell_ = new MockLocationProvider; | |
119 return base::WrapUnique(cell_); | |
120 } | |
121 | |
122 std::unique_ptr<LocationProvider> NewSystemLocationProvider() override { | |
123 gps_ = new MockLocationProvider; | |
124 return base::WrapUnique(gps_); | |
125 } | |
126 | |
127 // Two location providers, with nice short names to make the tests more | |
128 // readable. Note |gps_| will only be set when there is a high accuracy | |
129 // observer registered (and |cell_| when there's at least one observer of any | |
130 // type). | |
131 // TODO(mvanouwerkerk): rename |cell_| to |network_location_provider_| and | |
132 // |gps_| to |gps_location_provider_| | |
133 MockLocationProvider* cell_; | |
134 MockLocationProvider* gps_; | |
135 const scoped_refptr<AccessTokenStore> access_token_store_; | |
136 }; | |
137 | |
138 class GeolocationLocationArbitratorTest : public testing::Test { | |
139 protected: | |
140 GeolocationLocationArbitratorTest() | |
141 : access_token_store_(new NiceMock<FakeAccessTokenStore>), | |
142 observer_(new MockLocationObserver), | |
143 delegate_(new GeolocationDelegate) {} | |
144 | |
145 // Initializes |arbitrator_|, with the possibility of injecting a specific | |
146 // |delegate|, otherwise a default, no-op GeolocationDelegate is used. | |
147 void InitializeArbitrator(std::unique_ptr<GeolocationDelegate> delegate) { | |
148 if (delegate) | |
149 delegate_ = std::move(delegate); | |
150 const LocationArbitratorImpl::LocationUpdateCallback callback = | |
151 base::Bind(&MockLocationObserver::OnLocationUpdate, | |
152 base::Unretained(observer_.get())); | |
153 arbitrator_.reset(new TestingLocationArbitrator( | |
154 callback, access_token_store_, delegate_.get())); | |
155 } | |
156 | |
157 // testing::Test | |
158 void TearDown() override {} | |
159 | |
160 void CheckLastPositionInfo(double latitude, | |
161 double longitude, | |
162 double accuracy) { | |
163 Geoposition geoposition = observer_->last_position_; | |
164 EXPECT_TRUE(geoposition.Validate()); | |
165 EXPECT_DOUBLE_EQ(latitude, geoposition.latitude); | |
166 EXPECT_DOUBLE_EQ(longitude, geoposition.longitude); | |
167 EXPECT_DOUBLE_EQ(accuracy, geoposition.accuracy); | |
168 } | |
169 | |
170 base::TimeDelta SwitchOnFreshnessCliff() { | |
171 // Add 1, to ensure it meets any greater-than test. | |
172 return base::TimeDelta::FromMilliseconds( | |
173 LocationArbitratorImpl::kFixStaleTimeoutMilliseconds + 1); | |
174 } | |
175 | |
176 MockLocationProvider* cell() { | |
177 return arbitrator_->cell_; | |
178 } | |
179 | |
180 MockLocationProvider* gps() { | |
181 return arbitrator_->gps_; | |
182 } | |
183 | |
184 const scoped_refptr<FakeAccessTokenStore> access_token_store_; | |
185 const std::unique_ptr<MockLocationObserver> observer_; | |
186 std::unique_ptr<TestingLocationArbitrator> arbitrator_; | |
187 std::unique_ptr<GeolocationDelegate> delegate_; | |
188 const base::MessageLoop loop_; | |
189 }; | |
190 | |
191 TEST_F(GeolocationLocationArbitratorTest, CreateDestroy) { | |
192 EXPECT_TRUE(access_token_store_.get()); | |
193 InitializeArbitrator(nullptr); | |
194 EXPECT_TRUE(arbitrator_); | |
195 arbitrator_.reset(); | |
196 SUCCEED(); | |
197 } | |
198 | |
199 TEST_F(GeolocationLocationArbitratorTest, OnPermissionGranted) { | |
200 InitializeArbitrator(nullptr); | |
201 EXPECT_FALSE(arbitrator_->HasPermissionBeenGranted()); | |
202 arbitrator_->OnPermissionGranted(); | |
203 EXPECT_TRUE(arbitrator_->HasPermissionBeenGranted()); | |
204 // Can't check the provider has been notified without going through the | |
205 // motions to create the provider (see next test). | |
206 EXPECT_FALSE(cell()); | |
207 EXPECT_FALSE(gps()); | |
208 } | |
209 | |
210 TEST_F(GeolocationLocationArbitratorTest, NormalUsage) { | |
211 InitializeArbitrator(nullptr); | |
212 ASSERT_TRUE(access_token_store_.get()); | |
213 ASSERT_TRUE(arbitrator_); | |
214 | |
215 EXPECT_FALSE(cell()); | |
216 EXPECT_FALSE(gps()); | |
217 arbitrator_->StartProviders(false); | |
218 | |
219 EXPECT_TRUE(access_token_store_->access_token_map_.empty()); | |
220 | |
221 access_token_store_->NotifyDelegateTokensLoaded(); | |
222 ASSERT_TRUE(cell()); | |
223 EXPECT_TRUE(gps()); | |
224 EXPECT_EQ(MockLocationProvider::LOW_ACCURACY, cell()->state_); | |
225 EXPECT_EQ(MockLocationProvider::LOW_ACCURACY, gps()->state_); | |
226 EXPECT_FALSE(observer_->last_position_.Validate()); | |
227 EXPECT_EQ(Geoposition::ERROR_CODE_NONE, | |
228 observer_->last_position_.error_code); | |
229 | |
230 SetReferencePosition(cell()); | |
231 | |
232 EXPECT_TRUE(observer_->last_position_.Validate() || | |
233 observer_->last_position_.error_code != | |
234 Geoposition::ERROR_CODE_NONE); | |
235 EXPECT_EQ(cell()->position_.latitude, | |
236 observer_->last_position_.latitude); | |
237 | |
238 EXPECT_FALSE(cell()->is_permission_granted_); | |
239 EXPECT_FALSE(arbitrator_->HasPermissionBeenGranted()); | |
240 arbitrator_->OnPermissionGranted(); | |
241 EXPECT_TRUE(arbitrator_->HasPermissionBeenGranted()); | |
242 EXPECT_TRUE(cell()->is_permission_granted_); | |
243 } | |
244 | |
245 TEST_F(GeolocationLocationArbitratorTest, CustomSystemProviderOnly) { | |
246 FakeGeolocationDelegate* fake_delegate = new FakeGeolocationDelegate; | |
247 fake_delegate->set_use_network(false); | |
248 | |
249 std::unique_ptr<GeolocationDelegate> delegate(fake_delegate); | |
250 InitializeArbitrator(std::move(delegate)); | |
251 ASSERT_TRUE(arbitrator_); | |
252 | |
253 EXPECT_FALSE(cell()); | |
254 EXPECT_FALSE(gps()); | |
255 arbitrator_->StartProviders(false); | |
256 | |
257 ASSERT_FALSE(cell()); | |
258 EXPECT_FALSE(gps()); | |
259 ASSERT_TRUE(fake_delegate->mock_location_provider()); | |
260 EXPECT_EQ(MockLocationProvider::LOW_ACCURACY, | |
261 fake_delegate->mock_location_provider()->state_); | |
262 EXPECT_FALSE(observer_->last_position_.Validate()); | |
263 EXPECT_EQ(Geoposition::ERROR_CODE_NONE, observer_->last_position_.error_code); | |
264 | |
265 SetReferencePosition(fake_delegate->mock_location_provider()); | |
266 | |
267 EXPECT_TRUE(observer_->last_position_.Validate() || | |
268 observer_->last_position_.error_code != | |
269 Geoposition::ERROR_CODE_NONE); | |
270 EXPECT_EQ(fake_delegate->mock_location_provider()->position_.latitude, | |
271 observer_->last_position_.latitude); | |
272 | |
273 EXPECT_FALSE(fake_delegate->mock_location_provider()->is_permission_granted_); | |
274 EXPECT_FALSE(arbitrator_->HasPermissionBeenGranted()); | |
275 arbitrator_->OnPermissionGranted(); | |
276 EXPECT_TRUE(arbitrator_->HasPermissionBeenGranted()); | |
277 EXPECT_TRUE(fake_delegate->mock_location_provider()->is_permission_granted_); | |
278 } | |
279 | |
280 TEST_F(GeolocationLocationArbitratorTest, | |
281 CustomSystemAndDefaultNetworkProviders) { | |
282 FakeGeolocationDelegate* fake_delegate = new FakeGeolocationDelegate; | |
283 fake_delegate->set_use_network(true); | |
284 | |
285 std::unique_ptr<GeolocationDelegate> delegate(fake_delegate); | |
286 InitializeArbitrator(std::move(delegate)); | |
287 ASSERT_TRUE(arbitrator_); | |
288 | |
289 EXPECT_FALSE(cell()); | |
290 EXPECT_FALSE(gps()); | |
291 arbitrator_->StartProviders(false); | |
292 | |
293 EXPECT_TRUE(access_token_store_->access_token_map_.empty()); | |
294 | |
295 access_token_store_->NotifyDelegateTokensLoaded(); | |
296 | |
297 ASSERT_TRUE(cell()); | |
298 EXPECT_FALSE(gps()); | |
299 ASSERT_TRUE(fake_delegate->mock_location_provider()); | |
300 EXPECT_EQ(MockLocationProvider::LOW_ACCURACY, | |
301 fake_delegate->mock_location_provider()->state_); | |
302 EXPECT_EQ(MockLocationProvider::LOW_ACCURACY, cell()->state_); | |
303 EXPECT_FALSE(observer_->last_position_.Validate()); | |
304 EXPECT_EQ(Geoposition::ERROR_CODE_NONE, observer_->last_position_.error_code); | |
305 | |
306 SetReferencePosition(cell()); | |
307 | |
308 EXPECT_TRUE(observer_->last_position_.Validate() || | |
309 observer_->last_position_.error_code != | |
310 Geoposition::ERROR_CODE_NONE); | |
311 EXPECT_EQ(cell()->position_.latitude, observer_->last_position_.latitude); | |
312 | |
313 EXPECT_FALSE(cell()->is_permission_granted_); | |
314 EXPECT_FALSE(arbitrator_->HasPermissionBeenGranted()); | |
315 arbitrator_->OnPermissionGranted(); | |
316 EXPECT_TRUE(arbitrator_->HasPermissionBeenGranted()); | |
317 EXPECT_TRUE(cell()->is_permission_granted_); | |
318 } | |
319 | |
320 TEST_F(GeolocationLocationArbitratorTest, SetObserverOptions) { | |
321 InitializeArbitrator(nullptr); | |
322 arbitrator_->StartProviders(false); | |
323 access_token_store_->NotifyDelegateTokensLoaded(); | |
324 ASSERT_TRUE(cell()); | |
325 ASSERT_TRUE(gps()); | |
326 EXPECT_EQ(MockLocationProvider::LOW_ACCURACY, cell()->state_); | |
327 EXPECT_EQ(MockLocationProvider::LOW_ACCURACY, gps()->state_); | |
328 SetReferencePosition(cell()); | |
329 EXPECT_EQ(MockLocationProvider::LOW_ACCURACY, cell()->state_); | |
330 EXPECT_EQ(MockLocationProvider::LOW_ACCURACY, gps()->state_); | |
331 arbitrator_->StartProviders(true); | |
332 EXPECT_EQ(MockLocationProvider::HIGH_ACCURACY, cell()->state_); | |
333 EXPECT_EQ(MockLocationProvider::HIGH_ACCURACY, gps()->state_); | |
334 } | |
335 | |
336 TEST_F(GeolocationLocationArbitratorTest, Arbitration) { | |
337 InitializeArbitrator(nullptr); | |
338 arbitrator_->StartProviders(false); | |
339 access_token_store_->NotifyDelegateTokensLoaded(); | |
340 ASSERT_TRUE(cell()); | |
341 ASSERT_TRUE(gps()); | |
342 | |
343 SetPositionFix(cell(), 1, 2, 150); | |
344 | |
345 // First position available | |
346 EXPECT_TRUE(observer_->last_position_.Validate()); | |
347 CheckLastPositionInfo(1, 2, 150); | |
348 | |
349 SetPositionFix(gps(), 3, 4, 50); | |
350 | |
351 // More accurate fix available | |
352 CheckLastPositionInfo(3, 4, 50); | |
353 | |
354 SetPositionFix(cell(), 5, 6, 150); | |
355 | |
356 // New fix is available but it's less accurate, older fix should be kept. | |
357 CheckLastPositionInfo(3, 4, 50); | |
358 | |
359 // Advance time, and notify once again | |
360 AdvanceTimeNow(SwitchOnFreshnessCliff()); | |
361 cell()->HandlePositionChanged(cell()->position_); | |
362 | |
363 // New fix is available, less accurate but fresher | |
364 CheckLastPositionInfo(5, 6, 150); | |
365 | |
366 // Advance time, and set a low accuracy position | |
367 AdvanceTimeNow(SwitchOnFreshnessCliff()); | |
368 SetPositionFix(cell(), 5.676731, 139.629385, 1000); | |
369 CheckLastPositionInfo(5.676731, 139.629385, 1000); | |
370 | |
371 // 15 secs later, step outside. Switches to gps signal. | |
372 AdvanceTimeNow(base::TimeDelta::FromSeconds(15)); | |
373 SetPositionFix(gps(), 3.5676457, 139.629198, 50); | |
374 CheckLastPositionInfo(3.5676457, 139.629198, 50); | |
375 | |
376 // 5 mins later switch cells while walking. Stay on gps. | |
377 AdvanceTimeNow(base::TimeDelta::FromMinutes(5)); | |
378 SetPositionFix(cell(), 3.567832, 139.634648, 300); | |
379 SetPositionFix(gps(), 3.5677675, 139.632314, 50); | |
380 CheckLastPositionInfo(3.5677675, 139.632314, 50); | |
381 | |
382 // Ride train and gps signal degrades slightly. Stay on fresher gps | |
383 AdvanceTimeNow(base::TimeDelta::FromMinutes(5)); | |
384 SetPositionFix(gps(), 3.5679026, 139.634777, 300); | |
385 CheckLastPositionInfo(3.5679026, 139.634777, 300); | |
386 | |
387 // 14 minutes later | |
388 AdvanceTimeNow(base::TimeDelta::FromMinutes(14)); | |
389 | |
390 // GPS reading misses a beat, but don't switch to cell yet to avoid | |
391 // oscillating. | |
392 SetPositionFix(gps(), 3.5659005, 139.682579, 300); | |
393 | |
394 AdvanceTimeNow(base::TimeDelta::FromSeconds(7)); | |
395 SetPositionFix(cell(), 3.5689579, 139.691420, 1000); | |
396 CheckLastPositionInfo(3.5659005, 139.682579, 300); | |
397 | |
398 // 1 minute later | |
399 AdvanceTimeNow(base::TimeDelta::FromMinutes(1)); | |
400 | |
401 // Enter tunnel. Stay on fresher gps for a moment. | |
402 SetPositionFix(cell(), 3.5657078, 139.68922, 300); | |
403 SetPositionFix(gps(), 3.5657104, 139.690341, 300); | |
404 CheckLastPositionInfo(3.5657104, 139.690341, 300); | |
405 | |
406 // 2 minutes later | |
407 AdvanceTimeNow(base::TimeDelta::FromMinutes(2)); | |
408 // Arrive in station. Cell moves but GPS is stale. Switch to fresher cell. | |
409 SetPositionFix(cell(), 3.5658700, 139.069979, 1000); | |
410 CheckLastPositionInfo(3.5658700, 139.069979, 1000); | |
411 } | |
412 | |
413 TEST_F(GeolocationLocationArbitratorTest, TwoOneShotsIsNewPositionBetter) { | |
414 InitializeArbitrator(nullptr); | |
415 arbitrator_->StartProviders(false); | |
416 access_token_store_->NotifyDelegateTokensLoaded(); | |
417 ASSERT_TRUE(cell()); | |
418 ASSERT_TRUE(gps()); | |
419 | |
420 // Set the initial position. | |
421 SetPositionFix(cell(), 3, 139, 100); | |
422 CheckLastPositionInfo(3, 139, 100); | |
423 | |
424 // Restart providers to simulate a one-shot request. | |
425 arbitrator_->StopProviders(); | |
426 | |
427 // To test 240956, perform a throwaway alloc. | |
428 // This convinces the allocator to put the providers in a new memory location. | |
429 std::unique_ptr<MockLocationProvider> dummy_provider( | |
430 new MockLocationProvider); | |
431 | |
432 arbitrator_->StartProviders(false); | |
433 access_token_store_->NotifyDelegateTokensLoaded(); | |
434 | |
435 // Advance the time a short while to simulate successive calls. | |
436 AdvanceTimeNow(base::TimeDelta::FromMilliseconds(5)); | |
437 | |
438 // Update with a less accurate position to verify 240956. | |
439 SetPositionFix(cell(), 3, 139, 150); | |
440 CheckLastPositionInfo(3, 139, 150); | |
441 } | |
442 | |
443 } // namespace content | |
OLD | NEW |