geolocation_provider_impl_unittest.cc 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  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. #include "services/device/geolocation/geolocation_provider_impl.h"
  5. #include <memory>
  6. #include <string>
  7. #include "base/at_exit.h"
  8. #include "base/bind.h"
  9. #include "base/callback_helpers.h"
  10. #include "base/location.h"
  11. #include "base/memory/ptr_util.h"
  12. #include "base/memory/raw_ptr.h"
  13. #include "base/memory/ref_counted.h"
  14. #include "base/run_loop.h"
  15. #include "base/task/single_thread_task_runner.h"
  16. #include "base/test/task_environment.h"
  17. #include "base/threading/thread_checker.h"
  18. #include "base/time/time.h"
  19. #include "services/device/geolocation/fake_location_provider.h"
  20. #include "testing/gmock/include/gmock/gmock.h"
  21. #include "testing/gtest/include/gtest/gtest.h"
  22. using testing::MakeMatcher;
  23. using testing::Matcher;
  24. using testing::MatcherInterface;
  25. using testing::MatchResultListener;
  26. namespace device {
  27. namespace {
  28. class GeolocationObserver {
  29. public:
  30. virtual ~GeolocationObserver() = default;
  31. virtual void OnLocationUpdate(const mojom::Geoposition& position) = 0;
  32. };
  33. class MockGeolocationObserver : public GeolocationObserver {
  34. public:
  35. MOCK_METHOD1(OnLocationUpdate, void(const mojom::Geoposition& position));
  36. };
  37. class AsyncMockGeolocationObserver : public MockGeolocationObserver {
  38. public:
  39. void OnLocationUpdate(const mojom::Geoposition& position) override {
  40. MockGeolocationObserver::OnLocationUpdate(position);
  41. base::RunLoop::QuitCurrentWhenIdleDeprecated();
  42. }
  43. };
  44. class MockGeolocationCallbackWrapper {
  45. public:
  46. MOCK_METHOD1(Callback, void(const mojom::Geoposition& position));
  47. };
  48. class GeopositionEqMatcher
  49. : public MatcherInterface<const mojom::Geoposition&> {
  50. public:
  51. explicit GeopositionEqMatcher(const mojom::Geoposition& expected)
  52. : expected_(expected) {}
  53. GeopositionEqMatcher(const GeopositionEqMatcher&) = delete;
  54. GeopositionEqMatcher& operator=(const GeopositionEqMatcher&) = delete;
  55. bool MatchAndExplain(const mojom::Geoposition& actual,
  56. MatchResultListener* listener) const override {
  57. return actual.latitude == expected_.latitude &&
  58. actual.longitude == expected_.longitude &&
  59. actual.altitude == expected_.altitude &&
  60. actual.accuracy == expected_.accuracy &&
  61. actual.altitude_accuracy == expected_.altitude_accuracy &&
  62. actual.heading == expected_.heading &&
  63. actual.speed == expected_.speed &&
  64. actual.timestamp == expected_.timestamp &&
  65. actual.error_code == expected_.error_code &&
  66. actual.error_message == expected_.error_message;
  67. }
  68. void DescribeTo(::std::ostream* os) const override {
  69. *os << "which matches the expected position";
  70. }
  71. void DescribeNegationTo(::std::ostream* os) const override {
  72. *os << "which does not match the expected position";
  73. }
  74. private:
  75. mojom::Geoposition expected_;
  76. };
  77. Matcher<const mojom::Geoposition&> GeopositionEq(
  78. const mojom::Geoposition& expected) {
  79. return MakeMatcher(new GeopositionEqMatcher(expected));
  80. }
  81. void DummyFunction(const LocationProvider* provider,
  82. const mojom::Geoposition& position) {}
  83. } // namespace
  84. class GeolocationProviderTest : public testing::Test {
  85. protected:
  86. GeolocationProviderTest()
  87. : task_environment_(
  88. base::test::SingleThreadTaskEnvironment::MainThreadType::UI),
  89. arbitrator_(new FakeLocationProvider) {
  90. provider()->SetArbitratorForTesting(base::WrapUnique(arbitrator_.get()));
  91. }
  92. GeolocationProviderTest(const GeolocationProviderTest&) = delete;
  93. GeolocationProviderTest& operator=(const GeolocationProviderTest&) = delete;
  94. ~GeolocationProviderTest() override = default;
  95. GeolocationProviderImpl* provider() {
  96. return GeolocationProviderImpl::GetInstance();
  97. }
  98. FakeLocationProvider* arbitrator() { return arbitrator_; }
  99. // Called on test thread.
  100. bool ProvidersStarted();
  101. void SendMockLocation(const mojom::Geoposition& position);
  102. private:
  103. // Called on provider thread.
  104. void GetProvidersStarted();
  105. // |at_exit| must be initialized before all other variables so that it is
  106. // available to register with Singletons and can handle tear down when the
  107. // test completes.
  108. base::ShadowingAtExitManager at_exit_;
  109. base::test::SingleThreadTaskEnvironment task_environment_;
  110. base::ThreadChecker thread_checker_;
  111. // Owned by the GeolocationProviderImpl class.
  112. raw_ptr<FakeLocationProvider> arbitrator_;
  113. // True if |arbitrator_| is started.
  114. bool is_started_;
  115. };
  116. bool GeolocationProviderTest::ProvidersStarted() {
  117. DCHECK(provider()->IsRunning());
  118. DCHECK(thread_checker_.CalledOnValidThread());
  119. base::RunLoop run_loop;
  120. provider()->task_runner()->PostTaskAndReply(
  121. FROM_HERE,
  122. base::BindOnce(&GeolocationProviderTest::GetProvidersStarted,
  123. base::Unretained(this)),
  124. run_loop.QuitClosure());
  125. run_loop.Run();
  126. return is_started_;
  127. }
  128. void GeolocationProviderTest::GetProvidersStarted() {
  129. DCHECK(provider()->task_runner()->BelongsToCurrentThread());
  130. is_started_ = arbitrator()->state() != FakeLocationProvider::STOPPED;
  131. }
  132. void GeolocationProviderTest::SendMockLocation(
  133. const mojom::Geoposition& position) {
  134. DCHECK(provider()->IsRunning());
  135. DCHECK(thread_checker_.CalledOnValidThread());
  136. provider()->task_runner()->PostTask(
  137. FROM_HERE,
  138. base::BindOnce(&GeolocationProviderImpl::OnLocationUpdate,
  139. base::Unretained(provider()), arbitrator_, position));
  140. }
  141. // Regression test for http://crbug.com/59377
  142. TEST_F(GeolocationProviderTest, OnPermissionGrantedWithoutObservers) {
  143. // Clear |provider|'s arbitrator so the default arbitrator can be used.
  144. provider()->SetArbitratorForTesting(nullptr);
  145. EXPECT_FALSE(provider()->user_did_opt_into_location_services_for_testing());
  146. provider()->UserDidOptIntoLocationServices();
  147. EXPECT_TRUE(provider()->user_did_opt_into_location_services_for_testing());
  148. provider()->clear_user_did_opt_into_location_services_for_testing();
  149. }
  150. TEST_F(GeolocationProviderTest, StartStop) {
  151. EXPECT_FALSE(provider()->IsRunning());
  152. base::CallbackListSubscription subscription =
  153. provider()->AddLocationUpdateCallback(
  154. base::BindRepeating(&DummyFunction, arbitrator()), false);
  155. EXPECT_TRUE(provider()->IsRunning());
  156. EXPECT_TRUE(ProvidersStarted());
  157. subscription = {};
  158. EXPECT_FALSE(ProvidersStarted());
  159. EXPECT_TRUE(provider()->IsRunning());
  160. }
  161. TEST_F(GeolocationProviderTest, StalePositionNotSent) {
  162. mojom::Geoposition first_position;
  163. first_position.latitude = 12;
  164. first_position.longitude = 34;
  165. first_position.accuracy = 56;
  166. first_position.timestamp = base::Time::Now();
  167. AsyncMockGeolocationObserver first_observer;
  168. GeolocationProviderImpl::LocationUpdateCallback first_callback =
  169. base::BindRepeating(&MockGeolocationObserver::OnLocationUpdate,
  170. base::Unretained(&first_observer));
  171. EXPECT_CALL(first_observer, OnLocationUpdate(GeopositionEq(first_position)));
  172. base::CallbackListSubscription subscription =
  173. provider()->AddLocationUpdateCallback(first_callback, false);
  174. SendMockLocation(first_position);
  175. base::RunLoop().Run();
  176. subscription = {};
  177. mojom::Geoposition second_position;
  178. second_position.latitude = 13;
  179. second_position.longitude = 34;
  180. second_position.accuracy = 56;
  181. second_position.timestamp = base::Time::Now();
  182. AsyncMockGeolocationObserver second_observer;
  183. // After adding a second observer, check that no unexpected position update
  184. // is sent.
  185. EXPECT_CALL(second_observer, OnLocationUpdate(testing::_)).Times(0);
  186. GeolocationProviderImpl::LocationUpdateCallback second_callback =
  187. base::BindRepeating(&MockGeolocationObserver::OnLocationUpdate,
  188. base::Unretained(&second_observer));
  189. base::CallbackListSubscription subscription2 =
  190. provider()->AddLocationUpdateCallback(second_callback, false);
  191. base::RunLoop().RunUntilIdle();
  192. // The second observer should receive the new position now.
  193. EXPECT_CALL(second_observer,
  194. OnLocationUpdate(GeopositionEq(second_position)));
  195. SendMockLocation(second_position);
  196. base::RunLoop().Run();
  197. subscription2 = {};
  198. EXPECT_FALSE(ProvidersStarted());
  199. }
  200. TEST_F(GeolocationProviderTest, OverrideLocationForTesting) {
  201. mojom::Geoposition position;
  202. position.error_code = mojom::Geoposition::ErrorCode::POSITION_UNAVAILABLE;
  203. provider()->OverrideLocationForTesting(position);
  204. // Adding an observer when the location is overridden should synchronously
  205. // update the observer with our overridden position.
  206. MockGeolocationObserver mock_observer;
  207. EXPECT_CALL(mock_observer, OnLocationUpdate(GeopositionEq(position)));
  208. GeolocationProviderImpl::LocationUpdateCallback callback =
  209. base::BindRepeating(&MockGeolocationObserver::OnLocationUpdate,
  210. base::Unretained(&mock_observer));
  211. base::CallbackListSubscription subscription =
  212. provider()->AddLocationUpdateCallback(callback, false);
  213. subscription = {};
  214. // Wait for the providers to be stopped now that all clients are gone.
  215. EXPECT_FALSE(ProvidersStarted());
  216. }
  217. } // namespace device