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/memory/ref_counted.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/strings/string16.h"
11 #include "base/time/time.h"
12 #include "content/browser/geolocation/geolocation_provider_impl.h"
13 #include "content/browser/geolocation/mock_location_arbitrator.h"
14 #include "content/public/browser/access_token_store.h"
15 #include "content/public/browser/browser_thread.h"
16 #include "content/public/test/test_browser_thread.h"
17 #include "testing/gmock/include/gmock/gmock.h"
18 #include "testing/gtest/include/gtest/gtest.h"
20 using testing::MakeMatcher
;
21 using testing::Matcher
;
22 using testing::MatcherInterface
;
23 using testing::MatchResultListener
;
27 class LocationProviderForTestArbitrator
: public GeolocationProviderImpl
{
29 LocationProviderForTestArbitrator() : mock_arbitrator_(NULL
) {}
30 ~LocationProviderForTestArbitrator() override
{}
32 // Only valid for use on the geolocation thread.
33 MockLocationArbitrator
* mock_arbitrator() const {
34 return mock_arbitrator_
;
38 // GeolocationProviderImpl implementation:
39 LocationArbitrator
* CreateArbitrator() override
;
42 MockLocationArbitrator
* mock_arbitrator_
;
45 LocationArbitrator
* LocationProviderForTestArbitrator::CreateArbitrator() {
46 DCHECK(mock_arbitrator_
== NULL
);
47 mock_arbitrator_
= new MockLocationArbitrator
;
48 return mock_arbitrator_
;
51 class GeolocationObserver
{
53 virtual ~GeolocationObserver() {}
54 virtual void OnLocationUpdate(const Geoposition
& position
) = 0;
57 class MockGeolocationObserver
: public GeolocationObserver
{
59 MOCK_METHOD1(OnLocationUpdate
, void(const Geoposition
& position
));
62 class AsyncMockGeolocationObserver
: public MockGeolocationObserver
{
64 void OnLocationUpdate(const Geoposition
& position
) override
{
65 MockGeolocationObserver::OnLocationUpdate(position
);
66 base::MessageLoop::current()->Quit();
70 class MockGeolocationCallbackWrapper
{
72 MOCK_METHOD1(Callback
, void(const Geoposition
& position
));
75 class GeopositionEqMatcher
76 : public MatcherInterface
<const Geoposition
&> {
78 explicit GeopositionEqMatcher(const Geoposition
& expected
)
79 : expected_(expected
) {}
81 virtual bool MatchAndExplain(const Geoposition
& actual
,
82 MatchResultListener
* listener
) const override
{
83 return actual
.latitude
== expected_
.latitude
&&
84 actual
.longitude
== expected_
.longitude
&&
85 actual
.altitude
== expected_
.altitude
&&
86 actual
.accuracy
== expected_
.accuracy
&&
87 actual
.altitude_accuracy
== expected_
.altitude_accuracy
&&
88 actual
.heading
== expected_
.heading
&&
89 actual
.speed
== expected_
.speed
&&
90 actual
.timestamp
== expected_
.timestamp
&&
91 actual
.error_code
== expected_
.error_code
&&
92 actual
.error_message
== expected_
.error_message
;
95 virtual void DescribeTo(::std::ostream
* os
) const override
{
96 *os
<< "which matches the expected position";
99 virtual void DescribeNegationTo(::std::ostream
* os
) const override
{
100 *os
<< "which does not match the expected position";
104 Geoposition expected_
;
106 DISALLOW_COPY_AND_ASSIGN(GeopositionEqMatcher
);
109 Matcher
<const Geoposition
&> GeopositionEq(const Geoposition
& expected
) {
110 return MakeMatcher(new GeopositionEqMatcher(expected
));
113 class GeolocationProviderTest
: public testing::Test
{
115 GeolocationProviderTest()
117 ui_thread_(BrowserThread::UI
, &message_loop_
),
118 provider_(new LocationProviderForTestArbitrator
) {
121 ~GeolocationProviderTest() override
{}
123 LocationProviderForTestArbitrator
* provider() { return provider_
.get(); }
125 // Called on test thread.
126 bool ProvidersStarted();
127 void SendMockLocation(const Geoposition
& position
);
130 // Called on provider thread.
131 void GetProvidersStarted(bool* started
);
133 base::MessageLoop message_loop_
;
134 TestBrowserThread ui_thread_
;
135 scoped_ptr
<LocationProviderForTestArbitrator
> provider_
;
139 bool GeolocationProviderTest::ProvidersStarted() {
140 DCHECK(provider_
->IsRunning());
141 DCHECK(base::MessageLoop::current() == &message_loop_
);
143 provider_
->message_loop_proxy()->PostTaskAndReply(
145 base::Bind(&GeolocationProviderTest::GetProvidersStarted
,
146 base::Unretained(this),
148 base::MessageLoop::QuitClosure());
153 void GeolocationProviderTest::GetProvidersStarted(bool* started
) {
154 DCHECK(base::MessageLoop::current() == provider_
->message_loop());
155 *started
= provider_
->mock_arbitrator()->providers_started();
158 void GeolocationProviderTest::SendMockLocation(const Geoposition
& position
) {
159 DCHECK(provider_
->IsRunning());
160 DCHECK(base::MessageLoop::current() == &message_loop_
);
161 provider_
->message_loop()
162 ->PostTask(FROM_HERE
,
163 base::Bind(&GeolocationProviderImpl::OnLocationUpdate
,
164 base::Unretained(provider_
.get()),
168 // Regression test for http://crbug.com/59377
169 TEST_F(GeolocationProviderTest
, OnPermissionGrantedWithoutObservers
) {
170 EXPECT_FALSE(provider()->user_did_opt_into_location_services_for_testing());
171 provider()->UserDidOptIntoLocationServices();
172 EXPECT_TRUE(provider()->user_did_opt_into_location_services_for_testing());
175 void DummyFunction(const Geoposition
& position
) {
178 TEST_F(GeolocationProviderTest
, StartStop
) {
179 EXPECT_FALSE(provider()->IsRunning());
180 GeolocationProviderImpl::LocationUpdateCallback callback
=
181 base::Bind(&DummyFunction
);
182 scoped_ptr
<content::GeolocationProvider::Subscription
> subscription
=
183 provider()->AddLocationUpdateCallback(callback
, false);
184 EXPECT_TRUE(provider()->IsRunning());
185 EXPECT_TRUE(ProvidersStarted());
187 subscription
.reset();
189 EXPECT_FALSE(ProvidersStarted());
190 EXPECT_TRUE(provider()->IsRunning());
193 TEST_F(GeolocationProviderTest
, StalePositionNotSent
) {
194 Geoposition first_position
;
195 first_position
.latitude
= 12;
196 first_position
.longitude
= 34;
197 first_position
.accuracy
= 56;
198 first_position
.timestamp
= base::Time::Now();
200 AsyncMockGeolocationObserver first_observer
;
201 GeolocationProviderImpl::LocationUpdateCallback first_callback
= base::Bind(
202 &MockGeolocationObserver::OnLocationUpdate
,
203 base::Unretained(&first_observer
));
204 EXPECT_CALL(first_observer
, OnLocationUpdate(GeopositionEq(first_position
)));
205 scoped_ptr
<content::GeolocationProvider::Subscription
> subscription
=
206 provider()->AddLocationUpdateCallback(first_callback
, false);
207 SendMockLocation(first_position
);
208 base::MessageLoop::current()->Run();
210 subscription
.reset();
212 Geoposition second_position
;
213 second_position
.latitude
= 13;
214 second_position
.longitude
= 34;
215 second_position
.accuracy
= 56;
216 second_position
.timestamp
= base::Time::Now();
218 AsyncMockGeolocationObserver second_observer
;
220 // After adding a second observer, check that no unexpected position update
222 EXPECT_CALL(second_observer
, OnLocationUpdate(testing::_
)).Times(0);
223 GeolocationProviderImpl::LocationUpdateCallback second_callback
= base::Bind(
224 &MockGeolocationObserver::OnLocationUpdate
,
225 base::Unretained(&second_observer
));
226 scoped_ptr
<content::GeolocationProvider::Subscription
> subscription2
=
227 provider()->AddLocationUpdateCallback(second_callback
, false);
228 base::MessageLoop::current()->RunUntilIdle();
230 // The second observer should receive the new position now.
231 EXPECT_CALL(second_observer
,
232 OnLocationUpdate(GeopositionEq(second_position
)));
233 SendMockLocation(second_position
);
234 base::MessageLoop::current()->Run();
236 subscription2
.reset();
237 EXPECT_FALSE(ProvidersStarted());
240 TEST_F(GeolocationProviderTest
, OverrideLocationForTesting
) {
241 Geoposition position
;
242 position
.error_code
= Geoposition::ERROR_CODE_POSITION_UNAVAILABLE
;
243 provider()->OverrideLocationForTesting(position
);
244 // Adding an observer when the location is overridden should synchronously
245 // update the observer with our overridden position.
246 MockGeolocationObserver mock_observer
;
247 EXPECT_CALL(mock_observer
, OnLocationUpdate(GeopositionEq(position
)));
248 GeolocationProviderImpl::LocationUpdateCallback callback
= base::Bind(
249 &MockGeolocationObserver::OnLocationUpdate
,
250 base::Unretained(&mock_observer
));
251 scoped_ptr
<content::GeolocationProvider::Subscription
> subscription
=
252 provider()->AddLocationUpdateCallback(callback
, false);
253 subscription
.reset();
254 // Wait for the providers to be stopped now that all clients are gone.
255 EXPECT_FALSE(ProvidersStarted());
258 } // namespace content