[email protected] | 6ca7dc1 | 2014-08-15 09:43:32 | [diff] [blame] | 1 | // Copyright 2014 The Chromium Authors. All rights reserved. |
[email protected] | fa7e91b8 | 2010-10-20 09:29:27 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
[email protected] | 439eb40 | 2012-05-04 13:04:44 | [diff] [blame] | 5 | #include "base/bind.h" |
| 6 | #include "base/bind_helpers.h" |
skyostil | 95082a6 | 2015-06-05 19:53:07 | [diff] [blame] | 7 | #include "base/location.h" |
[email protected] | 439eb40 | 2012-05-04 13:04:44 | [diff] [blame] | 8 | #include "base/memory/ref_counted.h" |
| 9 | #include "base/memory/scoped_ptr.h" |
skyostil | 95082a6 | 2015-06-05 19:53:07 | [diff] [blame] | 10 | #include "base/single_thread_task_runner.h" |
[email protected] | 10994d13 | 2013-06-11 07:16:18 | [diff] [blame] | 11 | #include "base/strings/string16.h" |
[email protected] | a43858f | 2013-06-28 15:18:37 | [diff] [blame] | 12 | #include "base/time/time.h" |
[email protected] | 6d444ddf | 2013-05-07 17:10:44 | [diff] [blame] | 13 | #include "content/browser/geolocation/geolocation_provider_impl.h" |
[email protected] | 90984b0 | 2012-11-30 13:00:40 | [diff] [blame] | 14 | #include "content/browser/geolocation/mock_location_arbitrator.h" |
[email protected] | f40000c6 | 2012-05-11 15:57:07 | [diff] [blame] | 15 | #include "content/public/browser/access_token_store.h" |
[email protected] | 439eb40 | 2012-05-04 13:04:44 | [diff] [blame] | 16 | #include "content/public/browser/browser_thread.h" |
[email protected] | e97882f | 2012-06-04 02:23:17 | [diff] [blame] | 17 | #include "content/public/test/test_browser_thread.h" |
[email protected] | 60349d9 | 2011-09-06 11:00:41 | [diff] [blame] | 18 | #include "testing/gmock/include/gmock/gmock.h" |
[email protected] | fa7e91b8 | 2010-10-20 09:29:27 | [diff] [blame] | 19 | #include "testing/gtest/include/gtest/gtest.h" |
| 20 | |
[email protected] | 439eb40 | 2012-05-04 13:04:44 | [diff] [blame] | 21 | using testing::MakeMatcher; |
| 22 | using testing::Matcher; |
| 23 | using testing::MatcherInterface; |
| 24 | using testing::MatchResultListener; |
[email protected] | 60349d9 | 2011-09-06 11:00:41 | [diff] [blame] | 25 | |
[email protected] | 6bd4083 | 2012-10-29 03:01:49 | [diff] [blame] | 26 | namespace content { |
[email protected] | 439eb40 | 2012-05-04 13:04:44 | [diff] [blame] | 27 | |
[email protected] | 6d444ddf | 2013-05-07 17:10:44 | [diff] [blame] | 28 | class LocationProviderForTestArbitrator : public GeolocationProviderImpl { |
[email protected] | b7c5c26 | 2012-11-26 13:17:18 | [diff] [blame] | 29 | public: |
[email protected] | 90984b0 | 2012-11-30 13:00:40 | [diff] [blame] | 30 | LocationProviderForTestArbitrator() : mock_arbitrator_(NULL) {} |
dcheng | c2282aa | 2014-10-21 12:07:58 | [diff] [blame] | 31 | ~LocationProviderForTestArbitrator() override {} |
[email protected] | b7c5c26 | 2012-11-26 13:17:18 | [diff] [blame] | 32 | |
[email protected] | 90984b0 | 2012-11-30 13:00:40 | [diff] [blame] | 33 | // Only valid for use on the geolocation thread. |
[email protected] | 73d8e1d8 | 2013-09-10 20:52:09 | [diff] [blame] | 34 | MockLocationArbitrator* mock_arbitrator() const { |
[email protected] | 90984b0 | 2012-11-30 13:00:40 | [diff] [blame] | 35 | return mock_arbitrator_; |
| 36 | } |
| 37 | |
[email protected] | b7c5c26 | 2012-11-26 13:17:18 | [diff] [blame] | 38 | protected: |
[email protected] | 6d444ddf | 2013-05-07 17:10:44 | [diff] [blame] | 39 | // GeolocationProviderImpl implementation: |
dcheng | c2282aa | 2014-10-21 12:07:58 | [diff] [blame] | 40 | LocationArbitrator* CreateArbitrator() override; |
[email protected] | b7c5c26 | 2012-11-26 13:17:18 | [diff] [blame] | 41 | |
| 42 | private: |
[email protected] | 73d8e1d8 | 2013-09-10 20:52:09 | [diff] [blame] | 43 | MockLocationArbitrator* mock_arbitrator_; |
[email protected] | 439eb40 | 2012-05-04 13:04:44 | [diff] [blame] | 44 | }; |
| 45 | |
[email protected] | 73d8e1d8 | 2013-09-10 20:52:09 | [diff] [blame] | 46 | LocationArbitrator* LocationProviderForTestArbitrator::CreateArbitrator() { |
[email protected] | 90984b0 | 2012-11-30 13:00:40 | [diff] [blame] | 47 | DCHECK(mock_arbitrator_ == NULL); |
[email protected] | 73d8e1d8 | 2013-09-10 20:52:09 | [diff] [blame] | 48 | mock_arbitrator_ = new MockLocationArbitrator; |
[email protected] | 90984b0 | 2012-11-30 13:00:40 | [diff] [blame] | 49 | return mock_arbitrator_; |
[email protected] | b7c5c26 | 2012-11-26 13:17:18 | [diff] [blame] | 50 | } |
| 51 | |
[email protected] | 6d444ddf | 2013-05-07 17:10:44 | [diff] [blame] | 52 | class GeolocationObserver { |
[email protected] | 439eb40 | 2012-05-04 13:04:44 | [diff] [blame] | 53 | public: |
[email protected] | 6d444ddf | 2013-05-07 17:10:44 | [diff] [blame] | 54 | virtual ~GeolocationObserver() {} |
| 55 | virtual void OnLocationUpdate(const Geoposition& position) = 0; |
[email protected] | 439eb40 | 2012-05-04 13:04:44 | [diff] [blame] | 56 | }; |
| 57 | |
| 58 | class MockGeolocationObserver : public GeolocationObserver { |
| 59 | public: |
[email protected] | 6bd4083 | 2012-10-29 03:01:49 | [diff] [blame] | 60 | MOCK_METHOD1(OnLocationUpdate, void(const Geoposition& position)); |
[email protected] | 439eb40 | 2012-05-04 13:04:44 | [diff] [blame] | 61 | }; |
| 62 | |
[email protected] | baaf184 | 2012-12-03 20:54:54 | [diff] [blame] | 63 | class AsyncMockGeolocationObserver : public MockGeolocationObserver { |
| 64 | public: |
dcheng | c2282aa | 2014-10-21 12:07:58 | [diff] [blame] | 65 | void OnLocationUpdate(const Geoposition& position) override { |
[email protected] | baaf184 | 2012-12-03 20:54:54 | [diff] [blame] | 66 | MockGeolocationObserver::OnLocationUpdate(position); |
ki.stfu | 80077924 | 2015-10-12 22:46:26 | [diff] [blame] | 67 | base::MessageLoop::current()->QuitWhenIdle(); |
[email protected] | baaf184 | 2012-12-03 20:54:54 | [diff] [blame] | 68 | } |
| 69 | }; |
| 70 | |
[email protected] | 439eb40 | 2012-05-04 13:04:44 | [diff] [blame] | 71 | class MockGeolocationCallbackWrapper { |
| 72 | public: |
[email protected] | 6bd4083 | 2012-10-29 03:01:49 | [diff] [blame] | 73 | MOCK_METHOD1(Callback, void(const Geoposition& position)); |
[email protected] | 439eb40 | 2012-05-04 13:04:44 | [diff] [blame] | 74 | }; |
| 75 | |
| 76 | class GeopositionEqMatcher |
[email protected] | 6bd4083 | 2012-10-29 03:01:49 | [diff] [blame] | 77 | : public MatcherInterface<const Geoposition&> { |
[email protected] | 439eb40 | 2012-05-04 13:04:44 | [diff] [blame] | 78 | public: |
[email protected] | 6bd4083 | 2012-10-29 03:01:49 | [diff] [blame] | 79 | explicit GeopositionEqMatcher(const Geoposition& expected) |
[email protected] | 439eb40 | 2012-05-04 13:04:44 | [diff] [blame] | 80 | : expected_(expected) {} |
| 81 | |
nick | 5120892 | 2015-04-24 21:38:37 | [diff] [blame] | 82 | bool MatchAndExplain(const Geoposition& actual, |
| 83 | MatchResultListener* listener) const override { |
[email protected] | 439eb40 | 2012-05-04 13:04:44 | [diff] [blame] | 84 | return actual.latitude == expected_.latitude && |
| 85 | actual.longitude == expected_.longitude && |
| 86 | actual.altitude == expected_.altitude && |
| 87 | actual.accuracy == expected_.accuracy && |
| 88 | actual.altitude_accuracy == expected_.altitude_accuracy && |
| 89 | actual.heading == expected_.heading && |
| 90 | actual.speed == expected_.speed && |
| 91 | actual.timestamp == expected_.timestamp && |
| 92 | actual.error_code == expected_.error_code && |
| 93 | actual.error_message == expected_.error_message; |
| 94 | } |
| 95 | |
nick | 5120892 | 2015-04-24 21:38:37 | [diff] [blame] | 96 | void DescribeTo(::std::ostream* os) const override { |
[email protected] | 439eb40 | 2012-05-04 13:04:44 | [diff] [blame] | 97 | *os << "which matches the expected position"; |
| 98 | } |
| 99 | |
nick | 5120892 | 2015-04-24 21:38:37 | [diff] [blame] | 100 | void DescribeNegationTo(::std::ostream* os) const override { |
[email protected] | 439eb40 | 2012-05-04 13:04:44 | [diff] [blame] | 101 | *os << "which does not match the expected position"; |
| 102 | } |
| 103 | |
| 104 | private: |
[email protected] | 6bd4083 | 2012-10-29 03:01:49 | [diff] [blame] | 105 | Geoposition expected_; |
[email protected] | 439eb40 | 2012-05-04 13:04:44 | [diff] [blame] | 106 | |
| 107 | DISALLOW_COPY_AND_ASSIGN(GeopositionEqMatcher); |
| 108 | }; |
| 109 | |
[email protected] | 6bd4083 | 2012-10-29 03:01:49 | [diff] [blame] | 110 | Matcher<const Geoposition&> GeopositionEq(const Geoposition& expected) { |
[email protected] | 439eb40 | 2012-05-04 13:04:44 | [diff] [blame] | 111 | return MakeMatcher(new GeopositionEqMatcher(expected)); |
| 112 | } |
[email protected] | fa7e91b8 | 2010-10-20 09:29:27 | [diff] [blame] | 113 | |
| 114 | class GeolocationProviderTest : public testing::Test { |
| 115 | protected: |
[email protected] | fa7e91b8 | 2010-10-20 09:29:27 | [diff] [blame] | 116 | GeolocationProviderTest() |
[email protected] | 439eb40 | 2012-05-04 13:04:44 | [diff] [blame] | 117 | : message_loop_(), |
[email protected] | f28ef9a3 | 2014-05-12 16:36:10 | [diff] [blame] | 118 | ui_thread_(BrowserThread::UI, &message_loop_), |
[email protected] | 90984b0 | 2012-11-30 13:00:40 | [diff] [blame] | 119 | provider_(new LocationProviderForTestArbitrator) { |
[email protected] | b7d6acc | 2011-02-03 11:01:50 | [diff] [blame] | 120 | } |
| 121 | |
dcheng | fa85b15 | 2014-10-28 01:13:42 | [diff] [blame] | 122 | ~GeolocationProviderTest() override {} |
[email protected] | b7d6acc | 2011-02-03 11:01:50 | [diff] [blame] | 123 | |
[email protected] | 90984b0 | 2012-11-30 13:00:40 | [diff] [blame] | 124 | LocationProviderForTestArbitrator* provider() { return provider_.get(); } |
| 125 | |
| 126 | // Called on test thread. |
| 127 | bool ProvidersStarted(); |
[email protected] | baaf184 | 2012-12-03 20:54:54 | [diff] [blame] | 128 | void SendMockLocation(const Geoposition& position); |
[email protected] | 90984b0 | 2012-11-30 13:00:40 | [diff] [blame] | 129 | |
| 130 | private: |
| 131 | // Called on provider thread. |
| 132 | void GetProvidersStarted(bool* started); |
[email protected] | d4cee67 | 2012-05-09 17:36:07 | [diff] [blame] | 133 | |
[email protected] | dd32b127 | 2013-05-04 14:17:11 | [diff] [blame] | 134 | base::MessageLoop message_loop_; |
[email protected] | f28ef9a3 | 2014-05-12 16:36:10 | [diff] [blame] | 135 | TestBrowserThread ui_thread_; |
[email protected] | b7c5c26 | 2012-11-26 13:17:18 | [diff] [blame] | 136 | scoped_ptr<LocationProviderForTestArbitrator> provider_; |
[email protected] | fa7e91b8 | 2010-10-20 09:29:27 | [diff] [blame] | 137 | }; |
| 138 | |
[email protected] | 90984b0 | 2012-11-30 13:00:40 | [diff] [blame] | 139 | |
| 140 | bool GeolocationProviderTest::ProvidersStarted() { |
| 141 | DCHECK(provider_->IsRunning()); |
[email protected] | dd32b127 | 2013-05-04 14:17:11 | [diff] [blame] | 142 | DCHECK(base::MessageLoop::current() == &message_loop_); |
[email protected] | 90984b0 | 2012-11-30 13:00:40 | [diff] [blame] | 143 | bool started; |
skyostil | 95082a6 | 2015-06-05 19:53:07 | [diff] [blame] | 144 | provider_->task_runner()->PostTaskAndReply( |
| 145 | FROM_HERE, base::Bind(&GeolocationProviderTest::GetProvidersStarted, |
| 146 | base::Unretained(this), &started), |
ki.stfu | 80077924 | 2015-10-12 22:46:26 | [diff] [blame] | 147 | base::MessageLoop::QuitWhenIdleClosure()); |
[email protected] | 90984b0 | 2012-11-30 13:00:40 | [diff] [blame] | 148 | message_loop_.Run(); |
| 149 | return started; |
| 150 | } |
| 151 | |
| 152 | void GeolocationProviderTest::GetProvidersStarted(bool* started) { |
[email protected] | dd32b127 | 2013-05-04 14:17:11 | [diff] [blame] | 153 | DCHECK(base::MessageLoop::current() == provider_->message_loop()); |
[email protected] | 90984b0 | 2012-11-30 13:00:40 | [diff] [blame] | 154 | *started = provider_->mock_arbitrator()->providers_started(); |
| 155 | } |
| 156 | |
[email protected] | baaf184 | 2012-12-03 20:54:54 | [diff] [blame] | 157 | void GeolocationProviderTest::SendMockLocation(const Geoposition& position) { |
| 158 | DCHECK(provider_->IsRunning()); |
[email protected] | dd32b127 | 2013-05-04 14:17:11 | [diff] [blame] | 159 | DCHECK(base::MessageLoop::current() == &message_loop_); |
skyostil | 95082a6 | 2015-06-05 19:53:07 | [diff] [blame] | 160 | provider_->task_runner()->PostTask( |
| 161 | FROM_HERE, base::Bind(&GeolocationProviderImpl::OnLocationUpdate, |
| 162 | base::Unretained(provider_.get()), position)); |
[email protected] | baaf184 | 2012-12-03 20:54:54 | [diff] [blame] | 163 | } |
[email protected] | 90984b0 | 2012-11-30 13:00:40 | [diff] [blame] | 164 | |
[email protected] | fa7e91b8 | 2010-10-20 09:29:27 | [diff] [blame] | 165 | // Regression test for http://crbug.com/59377 |
| 166 | TEST_F(GeolocationProviderTest, OnPermissionGrantedWithoutObservers) { |
[email protected] | f28ef9a3 | 2014-05-12 16:36:10 | [diff] [blame] | 167 | EXPECT_FALSE(provider()->user_did_opt_into_location_services_for_testing()); |
[email protected] | 6d444ddf | 2013-05-07 17:10:44 | [diff] [blame] | 168 | provider()->UserDidOptIntoLocationServices(); |
[email protected] | f28ef9a3 | 2014-05-12 16:36:10 | [diff] [blame] | 169 | EXPECT_TRUE(provider()->user_did_opt_into_location_services_for_testing()); |
| 170 | } |
| 171 | |
| 172 | void DummyFunction(const Geoposition& position) { |
[email protected] | fa7e91b8 | 2010-10-20 09:29:27 | [diff] [blame] | 173 | } |
| 174 | |
[email protected] | b7d6acc | 2011-02-03 11:01:50 | [diff] [blame] | 175 | TEST_F(GeolocationProviderTest, StartStop) { |
[email protected] | 90984b0 | 2012-11-30 13:00:40 | [diff] [blame] | 176 | EXPECT_FALSE(provider()->IsRunning()); |
[email protected] | f28ef9a3 | 2014-05-12 16:36:10 | [diff] [blame] | 177 | GeolocationProviderImpl::LocationUpdateCallback callback = |
| 178 | base::Bind(&DummyFunction); |
| 179 | scoped_ptr<content::GeolocationProvider::Subscription> subscription = |
| 180 | provider()->AddLocationUpdateCallback(callback, false); |
[email protected] | 90984b0 | 2012-11-30 13:00:40 | [diff] [blame] | 181 | EXPECT_TRUE(provider()->IsRunning()); |
| 182 | EXPECT_TRUE(ProvidersStarted()); |
[email protected] | 439eb40 | 2012-05-04 13:04:44 | [diff] [blame] | 183 | |
[email protected] | f28ef9a3 | 2014-05-12 16:36:10 | [diff] [blame] | 184 | subscription.reset(); |
| 185 | |
[email protected] | 90984b0 | 2012-11-30 13:00:40 | [diff] [blame] | 186 | EXPECT_FALSE(ProvidersStarted()); |
| 187 | EXPECT_TRUE(provider()->IsRunning()); |
[email protected] | b7d6acc | 2011-02-03 11:01:50 | [diff] [blame] | 188 | } |
| 189 | |
[email protected] | baaf184 | 2012-12-03 20:54:54 | [diff] [blame] | 190 | TEST_F(GeolocationProviderTest, StalePositionNotSent) { |
| 191 | Geoposition first_position; |
| 192 | first_position.latitude = 12; |
| 193 | first_position.longitude = 34; |
| 194 | first_position.accuracy = 56; |
| 195 | first_position.timestamp = base::Time::Now(); |
| 196 | |
| 197 | AsyncMockGeolocationObserver first_observer; |
[email protected] | 6d444ddf | 2013-05-07 17:10:44 | [diff] [blame] | 198 | GeolocationProviderImpl::LocationUpdateCallback first_callback = base::Bind( |
| 199 | &MockGeolocationObserver::OnLocationUpdate, |
| 200 | base::Unretained(&first_observer)); |
[email protected] | baaf184 | 2012-12-03 20:54:54 | [diff] [blame] | 201 | EXPECT_CALL(first_observer, OnLocationUpdate(GeopositionEq(first_position))); |
[email protected] | f28ef9a3 | 2014-05-12 16:36:10 | [diff] [blame] | 202 | scoped_ptr<content::GeolocationProvider::Subscription> subscription = |
| 203 | provider()->AddLocationUpdateCallback(first_callback, false); |
[email protected] | baaf184 | 2012-12-03 20:54:54 | [diff] [blame] | 204 | SendMockLocation(first_position); |
[email protected] | dd32b127 | 2013-05-04 14:17:11 | [diff] [blame] | 205 | base::MessageLoop::current()->Run(); |
[email protected] | baaf184 | 2012-12-03 20:54:54 | [diff] [blame] | 206 | |
[email protected] | f28ef9a3 | 2014-05-12 16:36:10 | [diff] [blame] | 207 | subscription.reset(); |
[email protected] | baaf184 | 2012-12-03 20:54:54 | [diff] [blame] | 208 | |
| 209 | Geoposition second_position; |
| 210 | second_position.latitude = 13; |
| 211 | second_position.longitude = 34; |
| 212 | second_position.accuracy = 56; |
| 213 | second_position.timestamp = base::Time::Now(); |
| 214 | |
| 215 | AsyncMockGeolocationObserver second_observer; |
| 216 | |
| 217 | // After adding a second observer, check that no unexpected position update |
| 218 | // is sent. |
| 219 | EXPECT_CALL(second_observer, OnLocationUpdate(testing::_)).Times(0); |
[email protected] | 6d444ddf | 2013-05-07 17:10:44 | [diff] [blame] | 220 | GeolocationProviderImpl::LocationUpdateCallback second_callback = base::Bind( |
| 221 | &MockGeolocationObserver::OnLocationUpdate, |
| 222 | base::Unretained(&second_observer)); |
[email protected] | f28ef9a3 | 2014-05-12 16:36:10 | [diff] [blame] | 223 | scoped_ptr<content::GeolocationProvider::Subscription> subscription2 = |
| 224 | provider()->AddLocationUpdateCallback(second_callback, false); |
[email protected] | dd32b127 | 2013-05-04 14:17:11 | [diff] [blame] | 225 | base::MessageLoop::current()->RunUntilIdle(); |
[email protected] | baaf184 | 2012-12-03 20:54:54 | [diff] [blame] | 226 | |
| 227 | // The second observer should receive the new position now. |
| 228 | EXPECT_CALL(second_observer, |
| 229 | OnLocationUpdate(GeopositionEq(second_position))); |
| 230 | SendMockLocation(second_position); |
[email protected] | dd32b127 | 2013-05-04 14:17:11 | [diff] [blame] | 231 | base::MessageLoop::current()->Run(); |
[email protected] | baaf184 | 2012-12-03 20:54:54 | [diff] [blame] | 232 | |
[email protected] | f28ef9a3 | 2014-05-12 16:36:10 | [diff] [blame] | 233 | subscription2.reset(); |
[email protected] | baaf184 | 2012-12-03 20:54:54 | [diff] [blame] | 234 | EXPECT_FALSE(ProvidersStarted()); |
| 235 | } |
| 236 | |
[email protected] | f40000c6 | 2012-05-11 15:57:07 | [diff] [blame] | 237 | TEST_F(GeolocationProviderTest, OverrideLocationForTesting) { |
[email protected] | 6bd4083 | 2012-10-29 03:01:49 | [diff] [blame] | 238 | Geoposition position; |
| 239 | position.error_code = Geoposition::ERROR_CODE_POSITION_UNAVAILABLE; |
[email protected] | 90984b0 | 2012-11-30 13:00:40 | [diff] [blame] | 240 | provider()->OverrideLocationForTesting(position); |
[email protected] | 439eb40 | 2012-05-04 13:04:44 | [diff] [blame] | 241 | // Adding an observer when the location is overridden should synchronously |
| 242 | // update the observer with our overridden position. |
[email protected] | 02a5fe29 | 2012-04-25 21:47:56 | [diff] [blame] | 243 | MockGeolocationObserver mock_observer; |
[email protected] | 439eb40 | 2012-05-04 13:04:44 | [diff] [blame] | 244 | EXPECT_CALL(mock_observer, OnLocationUpdate(GeopositionEq(position))); |
[email protected] | 6d444ddf | 2013-05-07 17:10:44 | [diff] [blame] | 245 | GeolocationProviderImpl::LocationUpdateCallback callback = base::Bind( |
| 246 | &MockGeolocationObserver::OnLocationUpdate, |
| 247 | base::Unretained(&mock_observer)); |
[email protected] | f28ef9a3 | 2014-05-12 16:36:10 | [diff] [blame] | 248 | scoped_ptr<content::GeolocationProvider::Subscription> subscription = |
| 249 | provider()->AddLocationUpdateCallback(callback, false); |
| 250 | subscription.reset(); |
[email protected] | d4cee67 | 2012-05-09 17:36:07 | [diff] [blame] | 251 | // Wait for the providers to be stopped now that all clients are gone. |
[email protected] | 90984b0 | 2012-11-30 13:00:40 | [diff] [blame] | 252 | EXPECT_FALSE(ProvidersStarted()); |
[email protected] | 02a5fe29 | 2012-04-25 21:47:56 | [diff] [blame] | 253 | } |
| 254 | |
[email protected] | 6bd4083 | 2012-10-29 03:01:49 | [diff] [blame] | 255 | } // namespace content |