• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "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         io_thread_(BrowserThread::IO, &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 io_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()->LocationServicesOptedIn());
171   provider()->UserDidOptIntoLocationServices();
172   EXPECT_TRUE(provider()->LocationServicesOptedIn());
173 }
174 
TEST_F(GeolocationProviderTest,StartStop)175 TEST_F(GeolocationProviderTest, StartStop) {
176   EXPECT_FALSE(provider()->IsRunning());
177   GeolocationProviderImpl::LocationUpdateCallback null_callback;
178   provider()->AddLocationUpdateCallback(null_callback, false);
179   EXPECT_TRUE(provider()->IsRunning());
180   EXPECT_TRUE(ProvidersStarted());
181 
182   provider()->RemoveLocationUpdateCallback(null_callback);
183   EXPECT_FALSE(ProvidersStarted());
184   EXPECT_TRUE(provider()->IsRunning());
185 }
186 
TEST_F(GeolocationProviderTest,StalePositionNotSent)187 TEST_F(GeolocationProviderTest, StalePositionNotSent) {
188   Geoposition first_position;
189   first_position.latitude = 12;
190   first_position.longitude = 34;
191   first_position.accuracy = 56;
192   first_position.timestamp = base::Time::Now();
193 
194   AsyncMockGeolocationObserver first_observer;
195   GeolocationProviderImpl::LocationUpdateCallback first_callback = base::Bind(
196       &MockGeolocationObserver::OnLocationUpdate,
197       base::Unretained(&first_observer));
198   EXPECT_CALL(first_observer, OnLocationUpdate(GeopositionEq(first_position)));
199   provider()->AddLocationUpdateCallback(first_callback, false);
200   SendMockLocation(first_position);
201   base::MessageLoop::current()->Run();
202 
203   provider()->RemoveLocationUpdateCallback(first_callback);
204 
205   Geoposition second_position;
206   second_position.latitude = 13;
207   second_position.longitude = 34;
208   second_position.accuracy = 56;
209   second_position.timestamp = base::Time::Now();
210 
211   AsyncMockGeolocationObserver second_observer;
212 
213   // After adding a second observer, check that no unexpected position update
214   // is sent.
215   EXPECT_CALL(second_observer, OnLocationUpdate(testing::_)).Times(0);
216   GeolocationProviderImpl::LocationUpdateCallback second_callback = base::Bind(
217       &MockGeolocationObserver::OnLocationUpdate,
218       base::Unretained(&second_observer));
219   provider()->AddLocationUpdateCallback(second_callback, false);
220   base::MessageLoop::current()->RunUntilIdle();
221 
222   // The second observer should receive the new position now.
223   EXPECT_CALL(second_observer,
224               OnLocationUpdate(GeopositionEq(second_position)));
225   SendMockLocation(second_position);
226   base::MessageLoop::current()->Run();
227 
228   provider()->RemoveLocationUpdateCallback(second_callback);
229   EXPECT_FALSE(ProvidersStarted());
230 }
231 
TEST_F(GeolocationProviderTest,OverrideLocationForTesting)232 TEST_F(GeolocationProviderTest, OverrideLocationForTesting) {
233   Geoposition position;
234   position.error_code = Geoposition::ERROR_CODE_POSITION_UNAVAILABLE;
235   provider()->OverrideLocationForTesting(position);
236   // Adding an observer when the location is overridden should synchronously
237   // update the observer with our overridden position.
238   MockGeolocationObserver mock_observer;
239   EXPECT_CALL(mock_observer, OnLocationUpdate(GeopositionEq(position)));
240   GeolocationProviderImpl::LocationUpdateCallback callback = base::Bind(
241       &MockGeolocationObserver::OnLocationUpdate,
242       base::Unretained(&mock_observer));
243   provider()->AddLocationUpdateCallback(callback, false);
244   provider()->RemoveLocationUpdateCallback(callback);
245   // Wait for the providers to be stopped now that all clients are gone.
246   EXPECT_FALSE(ProvidersStarted());
247 }
248 
249 }  // namespace content
250