OLD | NEW |
| (Empty) |
1 // Copyright 2014 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/geolocation_provider_impl.h" | |
6 | |
7 #include <memory> | |
8 | |
9 #include "base/bind.h" | |
10 #include "base/bind_helpers.h" | |
11 #include "base/location.h" | |
12 #include "base/macros.h" | |
13 #include "base/memory/ptr_util.h" | |
14 #include "base/memory/ref_counted.h" | |
15 #include "base/run_loop.h" | |
16 #include "base/single_thread_task_runner.h" | |
17 #include "base/strings/string16.h" | |
18 #include "base/time/time.h" | |
19 #include "content/browser/geolocation/mock_location_arbitrator.h" | |
20 #include "content/public/browser/access_token_store.h" | |
21 #include "content/public/browser/browser_thread.h" | |
22 #include "content/public/test/test_browser_thread.h" | |
23 #include "testing/gmock/include/gmock/gmock.h" | |
24 #include "testing/gtest/include/gtest/gtest.h" | |
25 | |
26 using testing::MakeMatcher; | |
27 using testing::Matcher; | |
28 using testing::MatcherInterface; | |
29 using testing::MatchResultListener; | |
30 | |
31 namespace content { | |
32 | |
33 class LocationProviderForTestArbitrator : public GeolocationProviderImpl { | |
34 public: | |
35 LocationProviderForTestArbitrator() : mock_arbitrator_(NULL) {} | |
36 ~LocationProviderForTestArbitrator() override {} | |
37 | |
38 // Only valid for use on the geolocation thread. | |
39 MockLocationArbitrator* mock_arbitrator() const { | |
40 return mock_arbitrator_; | |
41 } | |
42 | |
43 protected: | |
44 // GeolocationProviderImpl implementation: | |
45 std::unique_ptr<LocationArbitrator> CreateArbitrator() override; | |
46 | |
47 private: | |
48 // An alias to the arbitrator stored in the super class, where it is owned. | |
49 MockLocationArbitrator* mock_arbitrator_; | |
50 }; | |
51 | |
52 std::unique_ptr<LocationArbitrator> | |
53 LocationProviderForTestArbitrator::CreateArbitrator() { | |
54 DCHECK(mock_arbitrator_ == NULL); | |
55 mock_arbitrator_ = new MockLocationArbitrator; | |
56 return base::WrapUnique(mock_arbitrator_); | |
57 } | |
58 | |
59 class GeolocationObserver { | |
60 public: | |
61 virtual ~GeolocationObserver() {} | |
62 virtual void OnLocationUpdate(const Geoposition& position) = 0; | |
63 }; | |
64 | |
65 class MockGeolocationObserver : public GeolocationObserver { | |
66 public: | |
67 MOCK_METHOD1(OnLocationUpdate, void(const Geoposition& position)); | |
68 }; | |
69 | |
70 class AsyncMockGeolocationObserver : public MockGeolocationObserver { | |
71 public: | |
72 void OnLocationUpdate(const Geoposition& position) override { | |
73 MockGeolocationObserver::OnLocationUpdate(position); | |
74 base::MessageLoop::current()->QuitWhenIdle(); | |
75 } | |
76 }; | |
77 | |
78 class MockGeolocationCallbackWrapper { | |
79 public: | |
80 MOCK_METHOD1(Callback, void(const Geoposition& position)); | |
81 }; | |
82 | |
83 class GeopositionEqMatcher | |
84 : public MatcherInterface<const Geoposition&> { | |
85 public: | |
86 explicit GeopositionEqMatcher(const Geoposition& expected) | |
87 : expected_(expected) {} | |
88 | |
89 bool MatchAndExplain(const Geoposition& actual, | |
90 MatchResultListener* listener) const override { | |
91 return actual.latitude == expected_.latitude && | |
92 actual.longitude == expected_.longitude && | |
93 actual.altitude == expected_.altitude && | |
94 actual.accuracy == expected_.accuracy && | |
95 actual.altitude_accuracy == expected_.altitude_accuracy && | |
96 actual.heading == expected_.heading && | |
97 actual.speed == expected_.speed && | |
98 actual.timestamp == expected_.timestamp && | |
99 actual.error_code == expected_.error_code && | |
100 actual.error_message == expected_.error_message; | |
101 } | |
102 | |
103 void DescribeTo(::std::ostream* os) const override { | |
104 *os << "which matches the expected position"; | |
105 } | |
106 | |
107 void DescribeNegationTo(::std::ostream* os) const override { | |
108 *os << "which does not match the expected position"; | |
109 } | |
110 | |
111 private: | |
112 Geoposition expected_; | |
113 | |
114 DISALLOW_COPY_AND_ASSIGN(GeopositionEqMatcher); | |
115 }; | |
116 | |
117 Matcher<const Geoposition&> GeopositionEq(const Geoposition& expected) { | |
118 return MakeMatcher(new GeopositionEqMatcher(expected)); | |
119 } | |
120 | |
121 class GeolocationProviderTest : public testing::Test { | |
122 protected: | |
123 GeolocationProviderTest() | |
124 : message_loop_(), | |
125 ui_thread_(BrowserThread::UI, &message_loop_), | |
126 provider_(new LocationProviderForTestArbitrator) { | |
127 } | |
128 | |
129 ~GeolocationProviderTest() override {} | |
130 | |
131 LocationProviderForTestArbitrator* provider() { return provider_.get(); } | |
132 | |
133 // Called on test thread. | |
134 bool ProvidersStarted(); | |
135 void SendMockLocation(const Geoposition& position); | |
136 | |
137 private: | |
138 // Called on provider thread. | |
139 void GetProvidersStarted(bool* started); | |
140 | |
141 base::MessageLoop message_loop_; | |
142 TestBrowserThread ui_thread_; | |
143 std::unique_ptr<LocationProviderForTestArbitrator> provider_; | |
144 }; | |
145 | |
146 | |
147 bool GeolocationProviderTest::ProvidersStarted() { | |
148 DCHECK(provider_->IsRunning()); | |
149 DCHECK(base::MessageLoop::current() == &message_loop_); | |
150 bool started; | |
151 provider_->task_runner()->PostTaskAndReply( | |
152 FROM_HERE, base::Bind(&GeolocationProviderTest::GetProvidersStarted, | |
153 base::Unretained(this), &started), | |
154 base::MessageLoop::QuitWhenIdleClosure()); | |
155 base::RunLoop().Run(); | |
156 return started; | |
157 } | |
158 | |
159 void GeolocationProviderTest::GetProvidersStarted(bool* started) { | |
160 DCHECK(provider_->task_runner()->BelongsToCurrentThread()); | |
161 *started = provider_->mock_arbitrator()->providers_started(); | |
162 } | |
163 | |
164 void GeolocationProviderTest::SendMockLocation(const Geoposition& position) { | |
165 DCHECK(provider_->IsRunning()); | |
166 DCHECK(base::MessageLoop::current() == &message_loop_); | |
167 provider_->task_runner()->PostTask( | |
168 FROM_HERE, base::Bind(&GeolocationProviderImpl::OnLocationUpdate, | |
169 base::Unretained(provider_.get()), position)); | |
170 } | |
171 | |
172 // Regression test for http://crbug.com/59377 | |
173 TEST_F(GeolocationProviderTest, OnPermissionGrantedWithoutObservers) { | |
174 EXPECT_FALSE(provider()->user_did_opt_into_location_services_for_testing()); | |
175 provider()->UserDidOptIntoLocationServices(); | |
176 EXPECT_TRUE(provider()->user_did_opt_into_location_services_for_testing()); | |
177 } | |
178 | |
179 void DummyFunction(const Geoposition& position) { | |
180 } | |
181 | |
182 TEST_F(GeolocationProviderTest, StartStop) { | |
183 EXPECT_FALSE(provider()->IsRunning()); | |
184 GeolocationProviderImpl::LocationUpdateCallback callback = | |
185 base::Bind(&DummyFunction); | |
186 std::unique_ptr<content::GeolocationProvider::Subscription> subscription = | |
187 provider()->AddLocationUpdateCallback(callback, false); | |
188 EXPECT_TRUE(provider()->IsRunning()); | |
189 EXPECT_TRUE(ProvidersStarted()); | |
190 | |
191 subscription.reset(); | |
192 | |
193 EXPECT_FALSE(ProvidersStarted()); | |
194 EXPECT_TRUE(provider()->IsRunning()); | |
195 } | |
196 | |
197 TEST_F(GeolocationProviderTest, StalePositionNotSent) { | |
198 Geoposition first_position; | |
199 first_position.latitude = 12; | |
200 first_position.longitude = 34; | |
201 first_position.accuracy = 56; | |
202 first_position.timestamp = base::Time::Now(); | |
203 | |
204 AsyncMockGeolocationObserver first_observer; | |
205 GeolocationProviderImpl::LocationUpdateCallback first_callback = base::Bind( | |
206 &MockGeolocationObserver::OnLocationUpdate, | |
207 base::Unretained(&first_observer)); | |
208 EXPECT_CALL(first_observer, OnLocationUpdate(GeopositionEq(first_position))); | |
209 std::unique_ptr<content::GeolocationProvider::Subscription> subscription = | |
210 provider()->AddLocationUpdateCallback(first_callback, false); | |
211 SendMockLocation(first_position); | |
212 base::RunLoop().Run(); | |
213 | |
214 subscription.reset(); | |
215 | |
216 Geoposition second_position; | |
217 second_position.latitude = 13; | |
218 second_position.longitude = 34; | |
219 second_position.accuracy = 56; | |
220 second_position.timestamp = base::Time::Now(); | |
221 | |
222 AsyncMockGeolocationObserver second_observer; | |
223 | |
224 // After adding a second observer, check that no unexpected position update | |
225 // is sent. | |
226 EXPECT_CALL(second_observer, OnLocationUpdate(testing::_)).Times(0); | |
227 GeolocationProviderImpl::LocationUpdateCallback second_callback = base::Bind( | |
228 &MockGeolocationObserver::OnLocationUpdate, | |
229 base::Unretained(&second_observer)); | |
230 std::unique_ptr<content::GeolocationProvider::Subscription> subscription2 = | |
231 provider()->AddLocationUpdateCallback(second_callback, false); | |
232 base::RunLoop().RunUntilIdle(); | |
233 | |
234 // The second observer should receive the new position now. | |
235 EXPECT_CALL(second_observer, | |
236 OnLocationUpdate(GeopositionEq(second_position))); | |
237 SendMockLocation(second_position); | |
238 base::RunLoop().Run(); | |
239 | |
240 subscription2.reset(); | |
241 EXPECT_FALSE(ProvidersStarted()); | |
242 } | |
243 | |
244 TEST_F(GeolocationProviderTest, OverrideLocationForTesting) { | |
245 Geoposition position; | |
246 position.error_code = Geoposition::ERROR_CODE_POSITION_UNAVAILABLE; | |
247 provider()->OverrideLocationForTesting(position); | |
248 // Adding an observer when the location is overridden should synchronously | |
249 // update the observer with our overridden position. | |
250 MockGeolocationObserver mock_observer; | |
251 EXPECT_CALL(mock_observer, OnLocationUpdate(GeopositionEq(position))); | |
252 GeolocationProviderImpl::LocationUpdateCallback callback = base::Bind( | |
253 &MockGeolocationObserver::OnLocationUpdate, | |
254 base::Unretained(&mock_observer)); | |
255 std::unique_ptr<content::GeolocationProvider::Subscription> subscription = | |
256 provider()->AddLocationUpdateCallback(callback, false); | |
257 subscription.reset(); | |
258 // Wait for the providers to be stopped now that all clients are gone. | |
259 EXPECT_FALSE(ProvidersStarted()); | |
260 } | |
261 | |
262 } // namespace content | |
OLD | NEW |