• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "base/bind.h"
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"
19 
20 using testing::MakeMatcher;
21 using testing::Matcher;
22 using testing::MatcherInterface;
23 using testing::MatchResultListener;
24 
25 namespace content {
26 
27 class LocationProviderForTestArbitrator : public GeolocationProviderImpl {
28  public:
LocationProviderForTestArbitrator()29   LocationProviderForTestArbitrator() : mock_arbitrator_(NULL) {}
~LocationProviderForTestArbitrator()30   virtual ~LocationProviderForTestArbitrator() {}
31 
32   // Only valid for use on the geolocation thread.
mock_arbitrator() const33   MockLocationArbitrator* mock_arbitrator() const {
34     return mock_arbitrator_;
35   }
36 
37  protected:
38   // GeolocationProviderImpl implementation:
39   virtual LocationArbitrator* CreateArbitrator() OVERRIDE;
40 
41  private:
42   MockLocationArbitrator* mock_arbitrator_;
43 };
44 
CreateArbitrator()45 LocationArbitrator* LocationProviderForTestArbitrator::CreateArbitrator() {
46   DCHECK(mock_arbitrator_ == NULL);
47   mock_arbitrator_ = new MockLocationArbitrator;
48   return mock_arbitrator_;
49 }
50 
51 class GeolocationObserver {
52  public:
~GeolocationObserver()53   virtual ~GeolocationObserver() {}
54   virtual void OnLocationUpdate(const Geoposition& position) = 0;
55 };
56 
57 class MockGeolocationObserver : public GeolocationObserver {
58  public:
59   MOCK_METHOD1(OnLocationUpdate, void(const Geoposition& position));
60 };
61 
62 class AsyncMockGeolocationObserver : public MockGeolocationObserver {
63  public:
OnLocationUpdate(const Geoposition & position)64   virtual void OnLocationUpdate(const Geoposition& position) OVERRIDE {
65     MockGeolocationObserver::OnLocationUpdate(position);
66     base::MessageLoop::current()->Quit();
67   }
68 };
69 
70 class MockGeolocationCallbackWrapper {
71  public:
72   MOCK_METHOD1(Callback, void(const Geoposition& position));
73 };
74 
75 class GeopositionEqMatcher
76     : public MatcherInterface<const Geoposition&> {
77  public:
GeopositionEqMatcher(const Geoposition & expected)78   explicit GeopositionEqMatcher(const Geoposition& expected)
79       : expected_(expected) {}
80 
MatchAndExplain(const Geoposition & actual,MatchResultListener * listener) const81   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;
93   }
94 
DescribeTo(::std::ostream * os) const95   virtual void DescribeTo(::std::ostream* os) const OVERRIDE {
96     *os << "which matches the expected position";
97   }
98 
DescribeNegationTo(::std::ostream * os) const99   virtual void DescribeNegationTo(::std::ostream* os) const OVERRIDE {
100     *os << "which does not match the expected position";
101   }
102 
103  private:
104   Geoposition expected_;
105 
106   DISALLOW_COPY_AND_ASSIGN(GeopositionEqMatcher);
107 };
108 
GeopositionEq(const Geoposition & expected)109 Matcher<const Geoposition&> GeopositionEq(const Geoposition& expected) {
110   return MakeMatcher(new GeopositionEqMatcher(expected));
111 }
112 
113 class GeolocationProviderTest : public testing::Test {
114  protected:
GeolocationProviderTest()115   GeolocationProviderTest()
116       : message_loop_(),
117         ui_thread_(BrowserThread::UI, &message_loop_),
118         provider_(new LocationProviderForTestArbitrator) {
119   }
120 
~GeolocationProviderTest()121   virtual ~GeolocationProviderTest() {}
122 
provider()123   LocationProviderForTestArbitrator* provider() { return provider_.get(); }
124 
125   // Called on test thread.
126   bool ProvidersStarted();
127   void SendMockLocation(const Geoposition& position);
128 
129  private:
130   // Called on provider thread.
131   void GetProvidersStarted(bool* started);
132 
133   base::MessageLoop message_loop_;
134   TestBrowserThread ui_thread_;
135   scoped_ptr<LocationProviderForTestArbitrator> provider_;
136 };
137 
138 
ProvidersStarted()139 bool GeolocationProviderTest::ProvidersStarted() {
140   DCHECK(provider_->IsRunning());
141   DCHECK(base::MessageLoop::current() == &message_loop_);
142   bool started;
143   provider_->message_loop_proxy()->PostTaskAndReply(
144       FROM_HERE,
145       base::Bind(&GeolocationProviderTest::GetProvidersStarted,
146                  base::Unretained(this),
147                  &started),
148       base::MessageLoop::QuitClosure());
149   message_loop_.Run();
150   return started;
151 }
152 
GetProvidersStarted(bool * started)153 void GeolocationProviderTest::GetProvidersStarted(bool* started) {
154   DCHECK(base::MessageLoop::current() == provider_->message_loop());
155   *started = provider_->mock_arbitrator()->providers_started();
156 }
157 
SendMockLocation(const Geoposition & position)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()),
165                             position));
166 }
167 
168 // Regression test for http://crbug.com/59377
TEST_F(GeolocationProviderTest,OnPermissionGrantedWithoutObservers)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());
173 }
174 
DummyFunction(const Geoposition & position)175 void DummyFunction(const Geoposition& position) {
176 }
177 
TEST_F(GeolocationProviderTest,StartStop)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());
186 
187   subscription.reset();
188 
189   EXPECT_FALSE(ProvidersStarted());
190   EXPECT_TRUE(provider()->IsRunning());
191 }
192 
TEST_F(GeolocationProviderTest,StalePositionNotSent)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();
199 
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();
209 
210   subscription.reset();
211 
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();
217 
218   AsyncMockGeolocationObserver second_observer;
219 
220   // After adding a second observer, check that no unexpected position update
221   // is sent.
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();
229 
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();
235 
236   subscription2.reset();
237   EXPECT_FALSE(ProvidersStarted());
238 }
239 
TEST_F(GeolocationProviderTest,OverrideLocationForTesting)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());
256 }
257 
258 }  // namespace content
259