simple_geolocation_unittest.cc 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516
  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 <stddef.h>
  5. #include <memory>
  6. #include "ash/components/geolocation/simple_geolocation_provider.h"
  7. #include "ash/components/geolocation/simple_geolocation_request_test_monitor.h"
  8. #include "base/bind.h"
  9. #include "base/run_loop.h"
  10. #include "base/strings/string_number_conversions.h"
  11. #include "base/strings/stringprintf.h"
  12. #include "base/test/task_environment.h"
  13. #include "base/time/time.h"
  14. #include "chromeos/ash/components/dbus/shill/shill_manager_client.h"
  15. #include "chromeos/ash/components/network/geolocation_handler.h"
  16. #include "chromeos/ash/components/network/network_handler_test_helper.h"
  17. #include "net/http/http_response_headers.h"
  18. #include "net/http/http_status_code.h"
  19. #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
  20. #include "services/network/public/mojom/url_response_head.mojom.h"
  21. #include "services/network/test/test_url_loader_factory.h"
  22. #include "testing/gtest/include/gtest/gtest.h"
  23. #include "third_party/cros_system_api/dbus/service_constants.h"
  24. namespace {
  25. constexpr int kRequestRetryIntervalMilliSeconds = 200;
  26. // This should be different from default to prevent SimpleGeolocationRequest
  27. // from modifying it.
  28. constexpr char kTestGeolocationProviderUrl[] =
  29. "https://localhost/geolocation/v1/geolocate?";
  30. constexpr char kSimpleResponseBody[] =
  31. "{\n"
  32. " \"location\": {\n"
  33. " \"lat\": 51.0,\n"
  34. " \"lng\": -0.1\n"
  35. " },\n"
  36. " \"accuracy\": 1200.4\n"
  37. "}";
  38. constexpr char kIPOnlyRequestBody[] = "{\"considerIp\": \"true\"}";
  39. constexpr char kOneWiFiAPRequestBody[] =
  40. "{"
  41. "\"considerIp\":true,"
  42. "\"wifiAccessPoints\":["
  43. "{"
  44. "\"channel\":1,"
  45. "\"macAddress\":\"01:00:00:00:00:00\","
  46. "\"signalStrength\":10,"
  47. "\"signalToNoiseRatio\":0"
  48. "}"
  49. "]"
  50. "}";
  51. constexpr char kOneCellTowerRequestBody[] =
  52. "{"
  53. "\"cellTowers\":["
  54. "{"
  55. "\"cellId\":\"1\","
  56. "\"locationAreaCode\":\"3\","
  57. "\"mobileCountryCode\":\"100\","
  58. "\"mobileNetworkCode\":\"101\""
  59. "}"
  60. "],"
  61. "\"considerIp\":true"
  62. "}";
  63. constexpr char kExpectedPosition[] =
  64. "latitude=51.000000, longitude=-0.100000, accuracy=1200.400000, "
  65. "error_code=0, error_message='', status=1 (OK)";
  66. constexpr char kWiFiAP1MacAddress[] = "01:00:00:00:00:00";
  67. constexpr char kCellTower1MNC[] = "101";
  68. } // anonymous namespace
  69. namespace ash {
  70. // This implements fake Google MAPS Geolocation API remote endpoint.
  71. class TestGeolocationAPILoaderFactory : public network::TestURLLoaderFactory {
  72. public:
  73. TestGeolocationAPILoaderFactory(const GURL& url,
  74. const std::string& response,
  75. const size_t require_retries)
  76. : url_(url), response_(response), require_retries_(require_retries) {
  77. SetInterceptor(base::BindRepeating(
  78. &TestGeolocationAPILoaderFactory::Intercept, base::Unretained(this)));
  79. AddResponseWithCode(net::HTTP_INTERNAL_SERVER_ERROR);
  80. }
  81. TestGeolocationAPILoaderFactory(const TestGeolocationAPILoaderFactory&) =
  82. delete;
  83. TestGeolocationAPILoaderFactory& operator=(
  84. const TestGeolocationAPILoaderFactory&) = delete;
  85. void Intercept(const network::ResourceRequest& request) {
  86. EXPECT_EQ(url_, request.url);
  87. EXPECT_NE(nullptr, provider_);
  88. EXPECT_EQ(provider_->requests_.size(), 1U);
  89. SimpleGeolocationRequest* geolocation_request =
  90. provider_->requests_[0].get();
  91. const base::TimeDelta base_retry_interval =
  92. base::Milliseconds(kRequestRetryIntervalMilliSeconds);
  93. geolocation_request->set_retry_sleep_on_server_error_for_testing(
  94. base_retry_interval);
  95. geolocation_request->set_retry_sleep_on_bad_response_for_testing(
  96. base_retry_interval);
  97. if (++attempts_ > require_retries_)
  98. AddResponseWithCode(net::OK);
  99. }
  100. void SetSimpleGeolocationProvider(SimpleGeolocationProvider* provider) {
  101. provider_ = provider;
  102. }
  103. size_t attempts() const { return attempts_; }
  104. private:
  105. void AddResponseWithCode(int error_code) {
  106. auto response_head = network::mojom::URLResponseHead::New();
  107. response_head->headers = base::MakeRefCounted<net::HttpResponseHeaders>("");
  108. response_head->headers->SetHeader("Content-Type", "application/json");
  109. // If AddResponse() is called multiple times for the same URL, the last
  110. // one is the one used so there is no need for ClearResponses().
  111. AddResponse(url_, std::move(response_head), response_,
  112. network::URLLoaderCompletionStatus(error_code));
  113. }
  114. GURL url_;
  115. std::string response_;
  116. const size_t require_retries_;
  117. size_t attempts_ = 0;
  118. SimpleGeolocationProvider* provider_;
  119. };
  120. class GeolocationReceiver {
  121. public:
  122. GeolocationReceiver() : server_error_(false) {}
  123. void OnRequestDone(const Geoposition& position,
  124. bool server_error,
  125. const base::TimeDelta elapsed) {
  126. position_ = position;
  127. server_error_ = server_error;
  128. elapsed_ = elapsed;
  129. message_loop_runner_->Quit();
  130. }
  131. void WaitUntilRequestDone() {
  132. message_loop_runner_ = std::make_unique<base::RunLoop>();
  133. message_loop_runner_->Run();
  134. }
  135. const Geoposition& position() const { return position_; }
  136. bool server_error() const { return server_error_; }
  137. base::TimeDelta elapsed() const { return elapsed_; }
  138. private:
  139. Geoposition position_;
  140. bool server_error_;
  141. base::TimeDelta elapsed_;
  142. std::unique_ptr<base::RunLoop> message_loop_runner_;
  143. };
  144. class WirelessTestMonitor : public SimpleGeolocationRequestTestMonitor {
  145. public:
  146. WirelessTestMonitor() = default;
  147. WirelessTestMonitor(const WirelessTestMonitor&) = delete;
  148. WirelessTestMonitor& operator=(const WirelessTestMonitor&) = delete;
  149. void OnRequestCreated(SimpleGeolocationRequest* request) override {}
  150. void OnStart(SimpleGeolocationRequest* request) override {
  151. last_request_body_ = request->FormatRequestBodyForTesting();
  152. }
  153. const std::string& last_request_body() const { return last_request_body_; }
  154. private:
  155. std::string last_request_body_;
  156. };
  157. class SimpleGeolocationTest : public testing::Test {
  158. private:
  159. base::test::SingleThreadTaskEnvironment task_environment_;
  160. };
  161. TEST_F(SimpleGeolocationTest, ResponseOK) {
  162. TestGeolocationAPILoaderFactory url_factory(GURL(kTestGeolocationProviderUrl),
  163. kSimpleResponseBody,
  164. 0 /* require_retries */);
  165. SimpleGeolocationProvider provider(
  166. base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
  167. &url_factory),
  168. GURL(kTestGeolocationProviderUrl));
  169. url_factory.SetSimpleGeolocationProvider(&provider);
  170. GeolocationReceiver receiver;
  171. provider.RequestGeolocation(
  172. base::Seconds(1), false, false,
  173. base::BindOnce(&GeolocationReceiver::OnRequestDone,
  174. base::Unretained(&receiver)));
  175. receiver.WaitUntilRequestDone();
  176. EXPECT_EQ(kExpectedPosition, receiver.position().ToString());
  177. EXPECT_FALSE(receiver.server_error());
  178. EXPECT_EQ(1U, url_factory.attempts());
  179. }
  180. TEST_F(SimpleGeolocationTest, ResponseOKWithRetries) {
  181. TestGeolocationAPILoaderFactory url_factory(GURL(kTestGeolocationProviderUrl),
  182. kSimpleResponseBody,
  183. 3 /* require_retries */);
  184. SimpleGeolocationProvider provider(
  185. base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
  186. &url_factory),
  187. GURL(kTestGeolocationProviderUrl));
  188. url_factory.SetSimpleGeolocationProvider(&provider);
  189. GeolocationReceiver receiver;
  190. provider.RequestGeolocation(
  191. base::Seconds(1), false, false,
  192. base::BindOnce(&GeolocationReceiver::OnRequestDone,
  193. base::Unretained(&receiver)));
  194. receiver.WaitUntilRequestDone();
  195. EXPECT_EQ(kExpectedPosition, receiver.position().ToString());
  196. EXPECT_FALSE(receiver.server_error());
  197. EXPECT_EQ(4U, url_factory.attempts());
  198. }
  199. TEST_F(SimpleGeolocationTest, InvalidResponse) {
  200. TestGeolocationAPILoaderFactory url_factory(GURL(kTestGeolocationProviderUrl),
  201. "invalid JSON string",
  202. 0 /* require_retries */);
  203. SimpleGeolocationProvider provider(
  204. base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
  205. &url_factory),
  206. GURL(kTestGeolocationProviderUrl));
  207. url_factory.SetSimpleGeolocationProvider(&provider);
  208. GeolocationReceiver receiver;
  209. const int timeout_seconds = 1;
  210. size_t expected_retries = static_cast<size_t>(
  211. timeout_seconds * 1000 / kRequestRetryIntervalMilliSeconds);
  212. ASSERT_GE(expected_retries, 2U);
  213. provider.RequestGeolocation(
  214. base::Seconds(timeout_seconds), false, false,
  215. base::BindOnce(&GeolocationReceiver::OnRequestDone,
  216. base::Unretained(&receiver)));
  217. receiver.WaitUntilRequestDone();
  218. std::string receiver_position = receiver.position().ToString();
  219. EXPECT_NE(
  220. std::string::npos,
  221. receiver_position.find(
  222. "latitude=200.000000, longitude=200.000000, accuracy=-1.000000, "
  223. "error_code=0, error_message='SimpleGeolocation provider at "
  224. "'https://localhost/' : JSONReader failed:"));
  225. EXPECT_NE(std::string::npos, receiver_position.find("status=4 (TIMEOUT)"));
  226. EXPECT_TRUE(receiver.server_error());
  227. EXPECT_GE(url_factory.attempts(), 2U);
  228. if (url_factory.attempts() > expected_retries + 1) {
  229. LOG(WARNING)
  230. << "SimpleGeolocationTest::InvalidResponse: Too many attempts ("
  231. << url_factory.attempts() << "), no more than " << expected_retries + 1
  232. << " expected.";
  233. }
  234. if (url_factory.attempts() < expected_retries - 1) {
  235. LOG(WARNING)
  236. << "SimpleGeolocationTest::InvalidResponse: Too little attempts ("
  237. << url_factory.attempts() << "), greater than " << expected_retries - 1
  238. << " expected.";
  239. }
  240. }
  241. TEST_F(SimpleGeolocationTest, NoWiFi) {
  242. NetworkHandlerTestHelper network_handler_test_helper;
  243. WirelessTestMonitor requests_monitor;
  244. SimpleGeolocationRequest::SetTestMonitor(&requests_monitor);
  245. TestGeolocationAPILoaderFactory url_factory(GURL(kTestGeolocationProviderUrl),
  246. kSimpleResponseBody,
  247. 0 /* require_retries */);
  248. SimpleGeolocationProvider provider(
  249. base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
  250. &url_factory),
  251. GURL(kTestGeolocationProviderUrl));
  252. url_factory.SetSimpleGeolocationProvider(&provider);
  253. GeolocationReceiver receiver;
  254. provider.RequestGeolocation(
  255. base::Seconds(1), true, false,
  256. base::BindOnce(&GeolocationReceiver::OnRequestDone,
  257. base::Unretained(&receiver)));
  258. receiver.WaitUntilRequestDone();
  259. EXPECT_EQ(kIPOnlyRequestBody, requests_monitor.last_request_body());
  260. EXPECT_EQ(kExpectedPosition, receiver.position().ToString());
  261. EXPECT_FALSE(receiver.server_error());
  262. EXPECT_EQ(1U, url_factory.attempts());
  263. }
  264. // Test sending of WiFi Access points and Cell Towers.
  265. // (This is mostly derived from GeolocationHandlerTest.)
  266. class SimpleGeolocationWirelessTest : public ::testing::TestWithParam<bool> {
  267. public:
  268. SimpleGeolocationWirelessTest() : manager_test_(nullptr) {}
  269. SimpleGeolocationWirelessTest(const SimpleGeolocationWirelessTest&) = delete;
  270. SimpleGeolocationWirelessTest& operator=(
  271. const SimpleGeolocationWirelessTest&) = delete;
  272. ~SimpleGeolocationWirelessTest() override = default;
  273. void SetUp() override {
  274. // Get the test interface for manager / device.
  275. manager_test_ = ShillManagerClient::Get()->GetTestInterface();
  276. ASSERT_TRUE(manager_test_);
  277. geolocation_handler_.reset(new GeolocationHandler());
  278. geolocation_handler_->Init();
  279. base::RunLoop().RunUntilIdle();
  280. }
  281. void TearDown() override {
  282. geolocation_handler_.reset();
  283. }
  284. bool GetWifiAccessPoints() {
  285. return geolocation_handler_->GetWifiAccessPoints(&wifi_access_points_,
  286. nullptr);
  287. }
  288. bool GetCellTowers() {
  289. return geolocation_handler_->GetNetworkInformation(nullptr, &cell_towers_);
  290. }
  291. // This should remain in sync with the format of shill (chromeos) dict entries
  292. void AddAccessPoint(int idx) {
  293. base::DictionaryValue properties;
  294. std::string mac_address =
  295. base::StringPrintf("%02X:%02X:%02X:%02X:%02X:%02X", idx, 0, 0, 0, 0, 0);
  296. std::string channel = base::NumberToString(idx);
  297. std::string strength = base::NumberToString(idx * 10);
  298. properties.SetKey(shill::kGeoMacAddressProperty, base::Value(mac_address));
  299. properties.SetKey(shill::kGeoChannelProperty, base::Value(channel));
  300. properties.SetKey(shill::kGeoSignalStrengthProperty, base::Value(strength));
  301. manager_test_->AddGeoNetwork(shill::kGeoWifiAccessPointsProperty,
  302. properties);
  303. base::RunLoop().RunUntilIdle();
  304. }
  305. // This should remain in sync with the format of shill (chromeos) dict entries
  306. void AddCellTower(int idx) {
  307. base::DictionaryValue properties;
  308. std::string ci = base::NumberToString(idx);
  309. std::string lac = base::NumberToString(idx * 3);
  310. std::string mcc = base::NumberToString(idx * 100);
  311. std::string mnc = base::NumberToString(idx * 100 + 1);
  312. properties.SetKey(shill::kGeoCellIdProperty, base::Value(ci));
  313. properties.SetKey(shill::kGeoLocationAreaCodeProperty, base::Value(lac));
  314. properties.SetKey(shill::kGeoMobileCountryCodeProperty, base::Value(mcc));
  315. properties.SetKey(shill::kGeoMobileNetworkCodeProperty, base::Value(mnc));
  316. manager_test_->AddGeoNetwork(shill::kGeoCellTowersProperty, properties);
  317. base::RunLoop().RunUntilIdle();
  318. }
  319. protected:
  320. base::test::SingleThreadTaskEnvironment task_environment_{
  321. base::test::SingleThreadTaskEnvironment::MainThreadType::UI};
  322. NetworkHandlerTestHelper network_handler_test_helper_;
  323. std::unique_ptr<GeolocationHandler> geolocation_handler_;
  324. ShillManagerClient::TestInterface* manager_test_;
  325. WifiAccessPointVector wifi_access_points_;
  326. CellTowerVector cell_towers_;
  327. };
  328. // Parameter is enable/disable sending of WiFi data.
  329. TEST_P(SimpleGeolocationWirelessTest, WiFiExists) {
  330. WirelessTestMonitor requests_monitor;
  331. SimpleGeolocationRequest::SetTestMonitor(&requests_monitor);
  332. TestGeolocationAPILoaderFactory url_factory(GURL(kTestGeolocationProviderUrl),
  333. kSimpleResponseBody,
  334. 0 /* require_retries */);
  335. SimpleGeolocationProvider provider(
  336. base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
  337. &url_factory),
  338. GURL(kTestGeolocationProviderUrl));
  339. url_factory.SetSimpleGeolocationProvider(&provider);
  340. provider.set_geolocation_handler(geolocation_handler_.get());
  341. {
  342. GeolocationReceiver receiver;
  343. provider.RequestGeolocation(
  344. base::Seconds(1), GetParam(), false,
  345. base::BindOnce(&GeolocationReceiver::OnRequestDone,
  346. base::Unretained(&receiver)));
  347. receiver.WaitUntilRequestDone();
  348. EXPECT_EQ(kIPOnlyRequestBody, requests_monitor.last_request_body());
  349. EXPECT_EQ(kExpectedPosition, receiver.position().ToString());
  350. EXPECT_FALSE(receiver.server_error());
  351. EXPECT_EQ(1U, url_factory.attempts());
  352. }
  353. // Add cell and wifi to ensure only wifi is sent when cellular disabled.
  354. AddAccessPoint(1);
  355. AddCellTower(1);
  356. base::RunLoop().RunUntilIdle();
  357. // Initial call should return false and request access points.
  358. EXPECT_FALSE(GetWifiAccessPoints());
  359. base::RunLoop().RunUntilIdle();
  360. // Second call should return true since we have an access point.
  361. EXPECT_TRUE(GetWifiAccessPoints());
  362. ASSERT_EQ(1u, wifi_access_points_.size());
  363. EXPECT_EQ(kWiFiAP1MacAddress, wifi_access_points_[0].mac_address);
  364. EXPECT_EQ(1, wifi_access_points_[0].channel);
  365. {
  366. GeolocationReceiver receiver;
  367. provider.RequestGeolocation(
  368. base::Seconds(1), GetParam(), false,
  369. base::BindOnce(&GeolocationReceiver::OnRequestDone,
  370. base::Unretained(&receiver)));
  371. receiver.WaitUntilRequestDone();
  372. if (GetParam()) {
  373. // Sending WiFi data is enabled.
  374. EXPECT_EQ(kOneWiFiAPRequestBody, requests_monitor.last_request_body());
  375. } else {
  376. // Sending WiFi data is disabled.
  377. EXPECT_EQ(kIPOnlyRequestBody, requests_monitor.last_request_body());
  378. }
  379. EXPECT_EQ(kExpectedPosition, receiver.position().ToString());
  380. EXPECT_FALSE(receiver.server_error());
  381. // This is total.
  382. EXPECT_EQ(2U, url_factory.attempts());
  383. }
  384. }
  385. // This test verifies that WiFi data is sent only if sending was requested.
  386. INSTANTIATE_TEST_SUITE_P(EnableDisableSendingWifiData,
  387. SimpleGeolocationWirelessTest,
  388. testing::Bool());
  389. TEST_P(SimpleGeolocationWirelessTest, CellularExists) {
  390. WirelessTestMonitor requests_monitor;
  391. SimpleGeolocationRequest::SetTestMonitor(&requests_monitor);
  392. TestGeolocationAPILoaderFactory url_factory(GURL(kTestGeolocationProviderUrl),
  393. kSimpleResponseBody,
  394. 0 /* require_retries */);
  395. SimpleGeolocationProvider provider(
  396. base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
  397. &url_factory),
  398. GURL(kTestGeolocationProviderUrl));
  399. url_factory.SetSimpleGeolocationProvider(&provider);
  400. provider.set_geolocation_handler(geolocation_handler_.get());
  401. {
  402. GeolocationReceiver receiver;
  403. provider.RequestGeolocation(
  404. base::Seconds(1), false, GetParam(),
  405. base::BindOnce(&GeolocationReceiver::OnRequestDone,
  406. base::Unretained(&receiver)));
  407. receiver.WaitUntilRequestDone();
  408. EXPECT_EQ(kIPOnlyRequestBody, requests_monitor.last_request_body());
  409. EXPECT_EQ(kExpectedPosition, receiver.position().ToString());
  410. EXPECT_FALSE(receiver.server_error());
  411. EXPECT_EQ(1U, url_factory.attempts());
  412. }
  413. AddCellTower(1);
  414. base::RunLoop().RunUntilIdle();
  415. // Initial call should return false and request cell towers.
  416. EXPECT_FALSE(GetCellTowers());
  417. base::RunLoop().RunUntilIdle();
  418. // Second call should return true since we have a tower.
  419. EXPECT_TRUE(GetCellTowers());
  420. ASSERT_EQ(1u, cell_towers_.size());
  421. EXPECT_EQ(kCellTower1MNC, cell_towers_[0].mnc);
  422. EXPECT_EQ(base::NumberToString(1), cell_towers_[0].ci);
  423. {
  424. GeolocationReceiver receiver;
  425. provider.RequestGeolocation(
  426. base::Seconds(1), false, GetParam(),
  427. base::BindOnce(&GeolocationReceiver::OnRequestDone,
  428. base::Unretained(&receiver)));
  429. receiver.WaitUntilRequestDone();
  430. if (GetParam()) {
  431. // Sending Cellular data is enabled.
  432. EXPECT_EQ(kOneCellTowerRequestBody, requests_monitor.last_request_body());
  433. } else {
  434. // Sending Cellular data is disabled.
  435. EXPECT_EQ(kIPOnlyRequestBody, requests_monitor.last_request_body());
  436. }
  437. EXPECT_EQ(kExpectedPosition, receiver.position().ToString());
  438. EXPECT_FALSE(receiver.server_error());
  439. // This is total.
  440. EXPECT_EQ(2U, url_factory.attempts());
  441. }
  442. }
  443. } // namespace ash