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 "content/browser/browser_thread_impl.h" 6 #include "content/browser/geolocation/gps_location_provider_linux.h" 7 #include "testing/gtest/include/gtest/gtest.h" 8 9 #include "base/bind.h" 10 11 namespace content { 12 13 class MockLibGps : public LibGps { 14 public: 15 MockLibGps(); 16 virtual ~MockLibGps(); 17 18 virtual bool GetPositionIfFixed(Geoposition* position) OVERRIDE { 19 CHECK(position); 20 ++get_position_calls_; 21 *position = get_position_; 22 return get_position_ret_; 23 } 24 25 static int gps_open_stub(const char*, const char*, struct gps_data_t*) { 26 CHECK(g_instance_); 27 g_instance_->gps_open_calls_++; 28 return g_instance_->gps_open_ret_; 29 } 30 31 static int gps_close_stub(struct gps_data_t*) { 32 return 0; 33 } 34 35 static int gps_read_stub(struct gps_data_t*) { 36 CHECK(g_instance_); 37 g_instance_->gps_read_calls_++; 38 return g_instance_->gps_read_ret_; 39 } 40 41 int get_position_calls_; 42 bool get_position_ret_; 43 int gps_open_calls_; 44 int gps_open_ret_; 45 int gps_read_calls_; 46 int gps_read_ret_; 47 Geoposition get_position_; 48 static MockLibGps* g_instance_; 49 }; 50 51 class GeolocationGpsProviderLinuxTests : public testing::Test { 52 public: 53 GeolocationGpsProviderLinuxTests(); 54 virtual ~GeolocationGpsProviderLinuxTests(); 55 56 static LibGps* NewMockLibGps() { 57 return new MockLibGps(); 58 } 59 static LibGps* NoLibGpsFactory() { 60 return NULL; 61 } 62 63 protected: 64 base::MessageLoop message_loop_; 65 BrowserThreadImpl ui_thread_; 66 scoped_ptr<LocationProvider> provider_; 67 }; 68 69 void CheckValidPosition(const Geoposition& expected, 70 const Geoposition& actual) { 71 EXPECT_TRUE(actual.Validate()); 72 EXPECT_DOUBLE_EQ(expected.latitude, actual.latitude); 73 EXPECT_DOUBLE_EQ(expected.longitude, actual.longitude); 74 EXPECT_DOUBLE_EQ(expected.accuracy, actual.accuracy); 75 } 76 77 void QuitMessageLoopAfterUpdate(const LocationProvider* provider, 78 const Geoposition& position) { 79 base::MessageLoop::current()->Quit(); 80 } 81 82 MockLibGps* MockLibGps::g_instance_ = NULL; 83 84 MockLibGps::MockLibGps() 85 : get_position_calls_(0), 86 get_position_ret_(true), 87 gps_open_calls_(0), 88 gps_open_ret_(0), 89 gps_read_calls_(0), 90 gps_read_ret_(0) { 91 get_position_.error_code = Geoposition::ERROR_CODE_POSITION_UNAVAILABLE; 92 EXPECT_FALSE(g_instance_); 93 g_instance_ = this; 94 #if defined(USE_LIBGPS) 95 libgps_loader_.gps_open = gps_open_stub; 96 libgps_loader_.gps_close = gps_close_stub; 97 libgps_loader_.gps_read = gps_read_stub; 98 #endif // defined(USE_LIBGPS) 99 } 100 101 MockLibGps::~MockLibGps() { 102 EXPECT_EQ(this, g_instance_); 103 g_instance_ = NULL; 104 } 105 106 GeolocationGpsProviderLinuxTests::GeolocationGpsProviderLinuxTests() 107 : ui_thread_(BrowserThread::IO, &message_loop_), 108 provider_(new GpsLocationProviderLinux(NewMockLibGps)) { 109 provider_->SetUpdateCallback(base::Bind(&QuitMessageLoopAfterUpdate)); 110 } 111 112 GeolocationGpsProviderLinuxTests::~GeolocationGpsProviderLinuxTests() { 113 } 114 115 TEST_F(GeolocationGpsProviderLinuxTests, NoLibGpsInstalled) { 116 provider_.reset(new GpsLocationProviderLinux(NoLibGpsFactory)); 117 ASSERT_TRUE(provider_.get()); 118 const bool ok = provider_->StartProvider(true); 119 EXPECT_FALSE(ok); 120 Geoposition position; 121 provider_->GetPosition(&position); 122 EXPECT_FALSE(position.Validate()); 123 EXPECT_EQ(Geoposition::ERROR_CODE_POSITION_UNAVAILABLE, position.error_code); 124 } 125 126 #if defined(OS_CHROMEOS) 127 128 TEST_F(GeolocationGpsProviderLinuxTests, GetPosition) { 129 ASSERT_TRUE(provider_.get()); 130 const bool ok = provider_->StartProvider(true); 131 EXPECT_TRUE(ok); 132 ASSERT_TRUE(MockLibGps::g_instance_); 133 EXPECT_EQ(0, MockLibGps::g_instance_->get_position_calls_); 134 EXPECT_EQ(0, MockLibGps::g_instance_->gps_open_calls_); 135 EXPECT_EQ(0, MockLibGps::g_instance_->gps_read_calls_); 136 Geoposition position; 137 provider_->GetPosition(&position); 138 EXPECT_FALSE(position.Validate()); 139 EXPECT_EQ(Geoposition::ERROR_CODE_POSITION_UNAVAILABLE, position.error_code); 140 MockLibGps::g_instance_->get_position_.error_code = 141 Geoposition::ERROR_CODE_NONE; 142 MockLibGps::g_instance_->get_position_.latitude = 4.5; 143 MockLibGps::g_instance_->get_position_.longitude = -34.1; 144 MockLibGps::g_instance_->get_position_.accuracy = 345; 145 MockLibGps::g_instance_->get_position_.timestamp = 146 base::Time::FromDoubleT(200); 147 EXPECT_TRUE(MockLibGps::g_instance_->get_position_.Validate()); 148 base::MessageLoop::current()->Run(); 149 EXPECT_EQ(1, MockLibGps::g_instance_->get_position_calls_); 150 EXPECT_EQ(1, MockLibGps::g_instance_->gps_open_calls_); 151 EXPECT_EQ(1, MockLibGps::g_instance_->gps_read_calls_); 152 provider_->GetPosition(&position); 153 CheckValidPosition(MockLibGps::g_instance_->get_position_, position); 154 155 // Movement. This will block for up to half a second. 156 MockLibGps::g_instance_->get_position_.latitude += 0.01; 157 base::MessageLoop::current()->Run(); 158 provider_->GetPosition(&position); 159 EXPECT_EQ(2, MockLibGps::g_instance_->get_position_calls_); 160 EXPECT_EQ(1, MockLibGps::g_instance_->gps_open_calls_); 161 EXPECT_EQ(2, MockLibGps::g_instance_->gps_read_calls_); 162 CheckValidPosition(MockLibGps::g_instance_->get_position_, position); 163 } 164 165 void EnableGpsOpenCallback() { 166 CHECK(MockLibGps::g_instance_); 167 MockLibGps::g_instance_->gps_open_ret_ = 0; 168 } 169 170 TEST_F(GeolocationGpsProviderLinuxTests, LibGpsReconnect) { 171 // Setup gpsd reconnect interval to be 1000ms to speed up test. 172 GpsLocationProviderLinux* gps_provider = 173 static_cast<GpsLocationProviderLinux*>(provider_.get()); 174 gps_provider->SetGpsdReconnectIntervalMillis(1000); 175 gps_provider->SetPollPeriodMovingMillis(200); 176 const bool ok = provider_->StartProvider(true); 177 EXPECT_TRUE(ok); 178 ASSERT_TRUE(MockLibGps::g_instance_); 179 // Let gps_open() fails, and so will LibGps::Start(). 180 // Reconnect will happen in 1000ms. 181 MockLibGps::g_instance_->gps_open_ret_ = 1; 182 Geoposition position; 183 MockLibGps::g_instance_->get_position_.error_code = 184 Geoposition::ERROR_CODE_NONE; 185 MockLibGps::g_instance_->get_position_.latitude = 4.5; 186 MockLibGps::g_instance_->get_position_.longitude = -34.1; 187 MockLibGps::g_instance_->get_position_.accuracy = 345; 188 MockLibGps::g_instance_->get_position_.timestamp = 189 base::Time::FromDoubleT(200); 190 EXPECT_TRUE(MockLibGps::g_instance_->get_position_.Validate()); 191 // This task makes gps_open() and LibGps::Start() to succeed after 192 // 1500ms. 193 base::MessageLoop::current()->PostDelayedTask( 194 FROM_HERE, 195 base::Bind(&EnableGpsOpenCallback), 196 base::TimeDelta::FromMilliseconds(1500)); 197 base::MessageLoop::current()->Run(); 198 provider_->GetPosition(&position); 199 EXPECT_TRUE(position.Validate()); 200 // 3 gps_open() calls are expected (2 failures and 1 success) 201 EXPECT_EQ(1, MockLibGps::g_instance_->get_position_calls_); 202 EXPECT_EQ(3, MockLibGps::g_instance_->gps_open_calls_); 203 EXPECT_EQ(1, MockLibGps::g_instance_->gps_read_calls_); 204 } 205 206 #endif // #if defined(OS_CHROMEOS) 207 208 } // namespace content 209