Home | History | Annotate | Download | only in geolocation
      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:
     29   LocationProviderForTestArbitrator() : mock_arbitrator_(NULL) {}
     30   virtual ~LocationProviderForTestArbitrator() {}
     31 
     32   // Only valid for use on the geolocation thread.
     33   MockGeolocationArbitrator* mock_arbitrator() const {
     34     return mock_arbitrator_;
     35   }
     36 
     37  protected:
     38   // GeolocationProviderImpl implementation:
     39   virtual GeolocationArbitrator* CreateArbitrator() OVERRIDE;
     40 
     41  private:
     42   MockGeolocationArbitrator* mock_arbitrator_;
     43 };
     44 
     45 GeolocationArbitrator* LocationProviderForTestArbitrator::CreateArbitrator() {
     46   DCHECK(mock_arbitrator_ == NULL);
     47   mock_arbitrator_ = new MockGeolocationArbitrator;
     48   return mock_arbitrator_;
     49 }
     50 
     51 class GeolocationObserver {
     52  public:
     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:
     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:
     78   explicit GeopositionEqMatcher(const Geoposition& expected)
     79       : expected_(expected) {}
     80 
     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;
     93   }
     94 
     95   virtual void DescribeTo(::std::ostream* os) const OVERRIDE {
     96     *os << "which matches the expected position";
     97   }
     98 
     99   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 
    109 Matcher<const Geoposition&> GeopositionEq(const Geoposition& expected) {
    110   return MakeMatcher(new GeopositionEqMatcher(expected));
    111 }
    112 
    113 class GeolocationProviderTest : public testing::Test {
    114  protected:
    115   GeolocationProviderTest()
    116       : message_loop_(),
    117         io_thread_(BrowserThread::IO, &message_loop_),
    118         provider_(new LocationProviderForTestArbitrator) {
    119   }
    120 
    121   virtual ~GeolocationProviderTest() {}
    122 
    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 
    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 
    153 void GeolocationProviderTest::GetProvidersStarted(bool* started) {
    154   DCHECK(base::MessageLoop::current() == provider_->message_loop());
    155   *started = provider_->mock_arbitrator()->providers_started();
    156 }
    157 
    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
    169 TEST_F(GeolocationProviderTest, OnPermissionGrantedWithoutObservers) {
    170   EXPECT_FALSE(provider()->LocationServicesOptedIn());
    171   provider()->UserDidOptIntoLocationServices();
    172   EXPECT_TRUE(provider()->LocationServicesOptedIn());
    173 }
    174 
    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 
    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 
    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