public_ip_address_location_notifier_unittest.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. // Copyright 2017 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/public_ip_address_location_notifier.h"
  5. #include "base/bind.h"
  6. #include "base/run_loop.h"
  7. #include "base/strings/stringprintf.h"
  8. #include "base/test/task_environment.h"
  9. #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
  10. #include "services/device/device_service_test_base.h"
  11. #include "services/device/public/cpp/geolocation/geoposition.h"
  12. #include "services/device/public/mojom/geoposition.mojom.h"
  13. #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
  14. #include "services/network/test/test_network_connection_tracker.h"
  15. #include "services/network/test/test_url_loader_factory.h"
  16. #include "testing/gmock/include/gmock/gmock.h"
  17. #include "testing/gtest/include/gtest/gtest.h"
  18. namespace device {
  19. class PublicIpAddressLocationNotifierTest : public testing::Test {
  20. protected:
  21. // Helps test a single call to
  22. // PublicIpAddressLocationNotifier::QueryNextPositionAfterTimestamp.
  23. class TestPositionQuery {
  24. public:
  25. // Provides a callback suitable to pass to QueryNextPositionAfterTimestamp.
  26. PublicIpAddressLocationNotifier::QueryNextPositionCallback MakeCallback() {
  27. return base::BindOnce(&TestPositionQuery::OnQueryNextPositionResponse,
  28. base::Unretained(this));
  29. }
  30. // Optional. Wait until the callback from MakeCallback() is called.
  31. void Wait() { loop_.Run(); }
  32. const absl::optional<mojom::Geoposition>& position() const {
  33. return position_;
  34. }
  35. private:
  36. void OnQueryNextPositionResponse(const mojom::Geoposition& position) {
  37. position_ = position;
  38. loop_.Quit();
  39. }
  40. base::RunLoop loop_;
  41. absl::optional<mojom::Geoposition> position_;
  42. };
  43. PublicIpAddressLocationNotifierTest()
  44. : network_connection_tracker_(
  45. network::TestNetworkConnectionTracker::CreateInstance()),
  46. notifier_(
  47. base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
  48. &test_url_loader_factory_),
  49. network::TestNetworkConnectionTracker::GetInstance(),
  50. kTestGeolocationApiKey) {}
  51. ~PublicIpAddressLocationNotifierTest() override {}
  52. // Gives a valid JSON reponse to the specified URLFetcher.
  53. // For disambiguation purposes, the specified |latitude| is included in the
  54. // response.
  55. void RespondToFetchWithLatitude(const float latitude) {
  56. ASSERT_EQ(1, test_url_loader_factory_.NumPending());
  57. const std::string& request_url =
  58. test_url_loader_factory_.pending_requests()->back().request.url.spec();
  59. std::string expected_url =
  60. "https://www.googleapis.com/geolocation/v1/"
  61. "geolocate?key=";
  62. expected_url.append(kTestGeolocationApiKey);
  63. EXPECT_EQ(expected_url, request_url);
  64. // Issue a valid response including the specified latitude.
  65. const char kNetworkResponseFormatString[] =
  66. R"({
  67. "accuracy": 100.0,
  68. "location": {
  69. "lat": %f,
  70. "lng": 90.0
  71. }
  72. })";
  73. std::string body =
  74. base::StringPrintf(kNetworkResponseFormatString, latitude);
  75. test_url_loader_factory_.AddResponse(request_url, body, net::HTTP_OK);
  76. task_environment_.RunUntilIdle();
  77. test_url_loader_factory_.ClearResponses();
  78. }
  79. void RespondToFetchWithServerError() {
  80. ASSERT_EQ(1, test_url_loader_factory_.NumPending());
  81. const std::string& request_url =
  82. test_url_loader_factory_.pending_requests()->back().request.url.spec();
  83. std::string expected_url =
  84. "https://www.googleapis.com/geolocation/v1/"
  85. "geolocate?key=";
  86. expected_url.append(kTestGeolocationApiKey);
  87. EXPECT_EQ(expected_url, request_url);
  88. test_url_loader_factory_.AddResponse(request_url, std::string(),
  89. net::HTTP_INTERNAL_SERVER_ERROR);
  90. task_environment_.RunUntilIdle();
  91. test_url_loader_factory_.ClearResponses();
  92. }
  93. // Expects a non-empty and valid Geoposition, including the specified
  94. // |latitude|.
  95. void ExpectValidPosition(const absl::optional<mojom::Geoposition>& position,
  96. const float latitude) {
  97. ASSERT_TRUE(position);
  98. EXPECT_TRUE(ValidateGeoposition(*position));
  99. EXPECT_FLOAT_EQ(position->latitude, latitude);
  100. }
  101. void ExpectError(const absl::optional<mojom::Geoposition>& position) {
  102. ASSERT_TRUE(position);
  103. EXPECT_THAT(position->error_code,
  104. mojom::Geoposition::ErrorCode::POSITION_UNAVAILABLE);
  105. }
  106. // Use a TaskRunner on which we can fast-forward time.
  107. base::test::TaskEnvironment task_environment_{
  108. base::test::TaskEnvironment::TimeSource::MOCK_TIME};
  109. // Test NetworkConnectionTracker instance.
  110. std::unique_ptr<network::TestNetworkConnectionTracker>
  111. network_connection_tracker_;
  112. // Test URLLoaderFactory for handling requests to the geolocation API.
  113. network::TestURLLoaderFactory test_url_loader_factory_;
  114. // The object under test.
  115. PublicIpAddressLocationNotifier notifier_;
  116. };
  117. // Tests that a single initial query makes a URL fetch and returns a position.
  118. TEST_F(PublicIpAddressLocationNotifierTest, SingleQueryReturns) {
  119. // Make query.
  120. TestPositionQuery query;
  121. notifier_.QueryNextPosition(base::Time::Now(),
  122. PARTIAL_TRAFFIC_ANNOTATION_FOR_TESTS,
  123. query.MakeCallback());
  124. // Expect a URL fetch & send a valid response.
  125. RespondToFetchWithLatitude(1.0f);
  126. // Expect the query to return.
  127. ExpectValidPosition(query.position(), 1.0f);
  128. }
  129. // Tests that a second query asking for an older timestamp gets a cached result.
  130. TEST_F(PublicIpAddressLocationNotifierTest, OlderQueryReturnsCached) {
  131. const auto time = base::Time::Now();
  132. // Initial query.
  133. TestPositionQuery query_1;
  134. notifier_.QueryNextPosition(time, PARTIAL_TRAFFIC_ANNOTATION_FOR_TESTS,
  135. query_1.MakeCallback());
  136. RespondToFetchWithLatitude(1.0f);
  137. ExpectValidPosition(query_1.position(), 1.0f);
  138. // Second query for an earlier time.
  139. TestPositionQuery query_2;
  140. notifier_.QueryNextPosition(time - base::Minutes(5),
  141. PARTIAL_TRAFFIC_ANNOTATION_FOR_TESTS,
  142. query_2.MakeCallback());
  143. // Expect a cached result, so no new network request.
  144. EXPECT_EQ(0, test_url_loader_factory_.NumPending());
  145. // Expect the same result as query_1.
  146. ExpectValidPosition(query_2.position(), 1.0f);
  147. }
  148. // Tests that a subsequent query seeking a newer geoposition does not return,
  149. // until a network change occurs.
  150. TEST_F(PublicIpAddressLocationNotifierTest,
  151. SubsequentQueryWaitsForNetworkChange) {
  152. // Initial query.
  153. TestPositionQuery query_1;
  154. notifier_.QueryNextPosition(base::Time::Now(),
  155. PARTIAL_TRAFFIC_ANNOTATION_FOR_TESTS,
  156. query_1.MakeCallback());
  157. RespondToFetchWithLatitude(1.0f);
  158. ExpectValidPosition(query_1.position(), 1.0f);
  159. // Second query seeking a position newer than the result of query_1.
  160. TestPositionQuery query_2;
  161. notifier_.QueryNextPosition(query_1.position()->timestamp,
  162. PARTIAL_TRAFFIC_ANNOTATION_FOR_TESTS,
  163. query_2.MakeCallback());
  164. // Expect no network request or callback.
  165. EXPECT_EQ(0, test_url_loader_factory_.NumPending());
  166. EXPECT_FALSE(query_2.position().has_value());
  167. // Fake a network change notification.
  168. network::TestNetworkConnectionTracker::GetInstance()->SetConnectionType(
  169. network::mojom::ConnectionType::CONNECTION_UNKNOWN);
  170. // Wait for the notifier to complete its delayed reaction.
  171. task_environment_.FastForwardUntilNoTasksRemain();
  172. // Now expect a network request and query_2 to return.
  173. RespondToFetchWithLatitude(2.0f);
  174. ExpectValidPosition(query_2.position(), 2.0f);
  175. }
  176. // Tests that multiple network changes in a short time result in only one
  177. // network request.
  178. TEST_F(PublicIpAddressLocationNotifierTest,
  179. ConsecutiveNetworkChangesRequestsOnlyOnce) {
  180. // Initial query.
  181. TestPositionQuery query_1;
  182. notifier_.QueryNextPosition(base::Time::Now(),
  183. PARTIAL_TRAFFIC_ANNOTATION_FOR_TESTS,
  184. query_1.MakeCallback());
  185. RespondToFetchWithLatitude(1.0f);
  186. ExpectValidPosition(query_1.position(), 1.0f);
  187. // Second query seeking a position newer than the result of query_1.
  188. TestPositionQuery query_2;
  189. notifier_.QueryNextPosition(query_1.position()->timestamp,
  190. PARTIAL_TRAFFIC_ANNOTATION_FOR_TESTS,
  191. query_2.MakeCallback());
  192. // Expect no network request or callback since network has not changed.
  193. EXPECT_EQ(0, test_url_loader_factory_.NumPending());
  194. EXPECT_FALSE(query_2.position().has_value());
  195. // Fake several consecutive network changes notification.
  196. for (int i = 0; i < 10; ++i) {
  197. network::TestNetworkConnectionTracker::GetInstance()->SetConnectionType(
  198. network::mojom::ConnectionType::CONNECTION_UNKNOWN);
  199. task_environment_.FastForwardBy(base::Seconds(5));
  200. }
  201. // Expect still no network request or callback.
  202. EXPECT_EQ(0, test_url_loader_factory_.NumPending());
  203. EXPECT_FALSE(query_2.position().has_value());
  204. // Wait longer.
  205. task_environment_.FastForwardUntilNoTasksRemain();
  206. // Now expect a network request & query_2 to return.
  207. RespondToFetchWithLatitude(2.0f);
  208. ExpectValidPosition(query_2.position(), 2.0f);
  209. }
  210. // Tests multiple waiting queries.
  211. TEST_F(PublicIpAddressLocationNotifierTest, MutipleWaitingQueries) {
  212. // Initial query.
  213. TestPositionQuery query_1;
  214. notifier_.QueryNextPosition(base::Time::Now(),
  215. PARTIAL_TRAFFIC_ANNOTATION_FOR_TESTS,
  216. query_1.MakeCallback());
  217. RespondToFetchWithLatitude(1.0f);
  218. ExpectValidPosition(query_1.position(), 1.0f);
  219. // Multiple queries seeking positions newer than the result of query_1.
  220. TestPositionQuery query_2;
  221. notifier_.QueryNextPosition(query_1.position()->timestamp,
  222. PARTIAL_TRAFFIC_ANNOTATION_FOR_TESTS,
  223. query_2.MakeCallback());
  224. TestPositionQuery query_3;
  225. notifier_.QueryNextPosition(query_1.position()->timestamp,
  226. PARTIAL_TRAFFIC_ANNOTATION_FOR_TESTS,
  227. query_3.MakeCallback());
  228. // Expect no network requests or callback since network has not changed.
  229. EXPECT_EQ(0, test_url_loader_factory_.NumPending());
  230. EXPECT_FALSE(query_2.position().has_value());
  231. EXPECT_FALSE(query_3.position().has_value());
  232. // Fake a network change notification.
  233. network::TestNetworkConnectionTracker::GetInstance()->SetConnectionType(
  234. network::mojom::ConnectionType::CONNECTION_UNKNOWN);
  235. // Wait for the notifier to complete its delayed reaction.
  236. task_environment_.FastForwardUntilNoTasksRemain();
  237. // Now expect a network request & fake a valid response.
  238. RespondToFetchWithLatitude(2.0f);
  239. // Expect all queries to now return.
  240. ExpectValidPosition(query_2.position(), 2.0f);
  241. ExpectValidPosition(query_3.position(), 2.0f);
  242. }
  243. // Tests that server error is propagated to the client.
  244. TEST_F(PublicIpAddressLocationNotifierTest, ServerError) {
  245. // Make query.
  246. TestPositionQuery query;
  247. notifier_.QueryNextPosition(base::Time::Now(),
  248. PARTIAL_TRAFFIC_ANNOTATION_FOR_TESTS,
  249. query.MakeCallback());
  250. // Expect a URL fetch & send a valid response.
  251. RespondToFetchWithServerError();
  252. // Expect the query to return.
  253. ExpectError(query.position());
  254. }
  255. } // namespace device