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