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.
6 #include "base/bind_helpers.h"
7 #include "base/location.h"
8 #include "base/memory/ref_counted.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/single_thread_task_runner.h"
11 #include "base/strings/string16.h"
12 #include "base/time/time.h"
13 #include "content/browser/geolocation/geolocation_provider_impl.h"
14 #include "content/browser/geolocation/mock_location_arbitrator.h"
15 #include "content/public/browser/access_token_store.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "content/public/test/test_browser_thread.h"
18 #include "testing/gmock/include/gmock/gmock.h"
19 #include "testing/gtest/include/gtest/gtest.h"
21 using testing::MakeMatcher
;
22 using testing::Matcher
;
23 using testing::MatcherInterface
;
24 using testing::MatchResultListener
;
28 class LocationProviderForTestArbitrator
: public GeolocationProviderImpl
{
30 LocationProviderForTestArbitrator() : mock_arbitrator_(NULL
) {}
31 ~LocationProviderForTestArbitrator() override
{}
33 // Only valid for use on the geolocation thread.
34 MockLocationArbitrator
* mock_arbitrator() const {
35 return mock_arbitrator_
;
39 // GeolocationProviderImpl implementation:
40 LocationArbitrator
* CreateArbitrator() override
;
43 MockLocationArbitrator
* mock_arbitrator_
;
46 LocationArbitrator
* LocationProviderForTestArbitrator::CreateArbitrator() {
47 DCHECK(mock_arbitrator_
== NULL
);
48 mock_arbitrator_
= new MockLocationArbitrator
;
49 return mock_arbitrator_
;
52 class GeolocationObserver
{
54 virtual ~GeolocationObserver() {}
55 virtual void OnLocationUpdate(const Geoposition
& position
) = 0;
58 class MockGeolocationObserver
: public GeolocationObserver
{
60 MOCK_METHOD1(OnLocationUpdate
, void(const Geoposition
& position
));
63 class AsyncMockGeolocationObserver
: public MockGeolocationObserver
{
65 void OnLocationUpdate(const Geoposition
& position
) override
{
66 MockGeolocationObserver::OnLocationUpdate(position
);
67 base::MessageLoop::current()->Quit();
71 class MockGeolocationCallbackWrapper
{
73 MOCK_METHOD1(Callback
, void(const Geoposition
& position
));
76 class GeopositionEqMatcher
77 : public MatcherInterface
<const Geoposition
&> {
79 explicit GeopositionEqMatcher(const Geoposition
& expected
)
80 : expected_(expected
) {}
82 bool MatchAndExplain(const Geoposition
& actual
,
83 MatchResultListener
* listener
) const override
{
84 return actual
.latitude
== expected_
.latitude
&&
85 actual
.longitude
== expected_
.longitude
&&
86 actual
.altitude
== expected_
.altitude
&&
87 actual
.accuracy
== expected_
.accuracy
&&
88 actual
.altitude_accuracy
== expected_
.altitude_accuracy
&&
89 actual
.heading
== expected_
.heading
&&
90 actual
.speed
== expected_
.speed
&&
91 actual
.timestamp
== expected_
.timestamp
&&
92 actual
.error_code
== expected_
.error_code
&&
93 actual
.error_message
== expected_
.error_message
;
96 void DescribeTo(::std::ostream
* os
) const override
{
97 *os
<< "which matches the expected position";
100 void DescribeNegationTo(::std::ostream
* os
) const override
{
101 *os
<< "which does not match the expected position";
105 Geoposition expected_
;
107 DISALLOW_COPY_AND_ASSIGN(GeopositionEqMatcher
);
110 Matcher
<const Geoposition
&> GeopositionEq(const Geoposition
& expected
) {
111 return MakeMatcher(new GeopositionEqMatcher(expected
));
114 class GeolocationProviderTest
: public testing::Test
{
116 GeolocationProviderTest()
118 ui_thread_(BrowserThread::UI
, &message_loop_
),
119 provider_(new LocationProviderForTestArbitrator
) {
122 ~GeolocationProviderTest() override
{}
124 LocationProviderForTestArbitrator
* provider() { return provider_
.get(); }
126 // Called on test thread.
127 bool ProvidersStarted();
128 void SendMockLocation(const Geoposition
& position
);
131 // Called on provider thread.
132 void GetProvidersStarted(bool* started
);
134 base::MessageLoop message_loop_
;
135 TestBrowserThread ui_thread_
;
136 scoped_ptr
<LocationProviderForTestArbitrator
> provider_
;
140 bool GeolocationProviderTest::ProvidersStarted() {
141 DCHECK(provider_
->IsRunning());
142 DCHECK(base::MessageLoop::current() == &message_loop_
);
144 provider_
->task_runner()->PostTaskAndReply(
145 FROM_HERE
, base::Bind(&GeolocationProviderTest::GetProvidersStarted
,
146 base::Unretained(this), &started
),
147 base::MessageLoop::QuitClosure());
152 void GeolocationProviderTest::GetProvidersStarted(bool* started
) {
153 DCHECK(base::MessageLoop::current() == provider_
->message_loop());
154 *started
= provider_
->mock_arbitrator()->providers_started();
157 void GeolocationProviderTest::SendMockLocation(const Geoposition
& position
) {
158 DCHECK(provider_
->IsRunning());
159 DCHECK(base::MessageLoop::current() == &message_loop_
);
160 provider_
->task_runner()->PostTask(
161 FROM_HERE
, base::Bind(&GeolocationProviderImpl::OnLocationUpdate
,
162 base::Unretained(provider_
.get()), position
));
165 // Regression test for http://crbug.com/59377
166 TEST_F(GeolocationProviderTest
, OnPermissionGrantedWithoutObservers
) {
167 EXPECT_FALSE(provider()->user_did_opt_into_location_services_for_testing());
168 provider()->UserDidOptIntoLocationServices();
169 EXPECT_TRUE(provider()->user_did_opt_into_location_services_for_testing());
172 void DummyFunction(const Geoposition
& position
) {
175 TEST_F(GeolocationProviderTest
, StartStop
) {
176 EXPECT_FALSE(provider()->IsRunning());
177 GeolocationProviderImpl::LocationUpdateCallback callback
=
178 base::Bind(&DummyFunction
);
179 scoped_ptr
<content::GeolocationProvider::Subscription
> subscription
=
180 provider()->AddLocationUpdateCallback(callback
, false);
181 EXPECT_TRUE(provider()->IsRunning());
182 EXPECT_TRUE(ProvidersStarted());
184 subscription
.reset();
186 EXPECT_FALSE(ProvidersStarted());
187 EXPECT_TRUE(provider()->IsRunning());
190 TEST_F(GeolocationProviderTest
, StalePositionNotSent
) {
191 Geoposition first_position
;
192 first_position
.latitude
= 12;
193 first_position
.longitude
= 34;
194 first_position
.accuracy
= 56;
195 first_position
.timestamp
= base::Time::Now();
197 AsyncMockGeolocationObserver first_observer
;
198 GeolocationProviderImpl::LocationUpdateCallback first_callback
= base::Bind(
199 &MockGeolocationObserver::OnLocationUpdate
,
200 base::Unretained(&first_observer
));
201 EXPECT_CALL(first_observer
, OnLocationUpdate(GeopositionEq(first_position
)));
202 scoped_ptr
<content::GeolocationProvider::Subscription
> subscription
=
203 provider()->AddLocationUpdateCallback(first_callback
, false);
204 SendMockLocation(first_position
);
205 base::MessageLoop::current()->Run();
207 subscription
.reset();
209 Geoposition second_position
;
210 second_position
.latitude
= 13;
211 second_position
.longitude
= 34;
212 second_position
.accuracy
= 56;
213 second_position
.timestamp
= base::Time::Now();
215 AsyncMockGeolocationObserver second_observer
;
217 // After adding a second observer, check that no unexpected position update
219 EXPECT_CALL(second_observer
, OnLocationUpdate(testing::_
)).Times(0);
220 GeolocationProviderImpl::LocationUpdateCallback second_callback
= base::Bind(
221 &MockGeolocationObserver::OnLocationUpdate
,
222 base::Unretained(&second_observer
));
223 scoped_ptr
<content::GeolocationProvider::Subscription
> subscription2
=
224 provider()->AddLocationUpdateCallback(second_callback
, false);
225 base::MessageLoop::current()->RunUntilIdle();
227 // The second observer should receive the new position now.
228 EXPECT_CALL(second_observer
,
229 OnLocationUpdate(GeopositionEq(second_position
)));
230 SendMockLocation(second_position
);
231 base::MessageLoop::current()->Run();
233 subscription2
.reset();
234 EXPECT_FALSE(ProvidersStarted());
237 TEST_F(GeolocationProviderTest
, OverrideLocationForTesting
) {
238 Geoposition position
;
239 position
.error_code
= Geoposition::ERROR_CODE_POSITION_UNAVAILABLE
;
240 provider()->OverrideLocationForTesting(position
);
241 // Adding an observer when the location is overridden should synchronously
242 // update the observer with our overridden position.
243 MockGeolocationObserver mock_observer
;
244 EXPECT_CALL(mock_observer
, OnLocationUpdate(GeopositionEq(position
)));
245 GeolocationProviderImpl::LocationUpdateCallback callback
= base::Bind(
246 &MockGeolocationObserver::OnLocationUpdate
,
247 base::Unretained(&mock_observer
));
248 scoped_ptr
<content::GeolocationProvider::Subscription
> subscription
=
249 provider()->AddLocationUpdateCallback(callback
, false);
250 subscription
.reset();
251 // Wait for the providers to be stopped now that all clients are gone.
252 EXPECT_FALSE(ProvidersStarted());
255 } // namespace content