Remove PlatformFile from profile_browsertest
[chromium-blink-merge.git] / content / browser / geolocation / network_location_provider_unittest.cc
blob4bd9348d970fe9b01c2350444c28c0f89bcdbd6f
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.
5 #include "base/json/json_reader.h"
6 #include "base/json/json_writer.h"
7 #include "base/memory/scoped_ptr.h"
8 #include "base/strings/string_number_conversions.h"
9 #include "base/strings/string_util.h"
10 #include "base/strings/stringprintf.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "base/values.h"
13 #include "content/browser/geolocation/fake_access_token_store.h"
14 #include "content/browser/geolocation/location_arbitrator_impl.h"
15 #include "content/browser/geolocation/network_location_provider.h"
16 #include "net/url_request/test_url_fetcher_factory.h"
17 #include "net/url_request/url_request_status.h"
18 #include "testing/gtest/include/gtest/gtest.h"
20 namespace content {
22 // Constants used in multiple tests.
23 const char kTestServerUrl[] = "https://www.geolocation.test/service";
24 const char kAccessTokenString[] = "accessToken";
26 // Using #define so we can easily paste this into various other strings.
27 #define REFERENCE_ACCESS_TOKEN "2:k7j3G6LaL6u_lafw:4iXOeOpTh1glSXe"
29 // Stops the specified (nested) message loop when the listener is called back.
30 class MessageLoopQuitListener {
31 public:
32 MessageLoopQuitListener()
33 : client_message_loop_(base::MessageLoop::current()),
34 updated_provider_(NULL) {
35 CHECK(client_message_loop_);
38 void LocationUpdateAvailable(const LocationProvider* provider,
39 const Geoposition& position) {
40 EXPECT_EQ(client_message_loop_, base::MessageLoop::current());
41 updated_provider_ = provider;
42 client_message_loop_->Quit();
45 base::MessageLoop* client_message_loop_;
46 const LocationProvider* updated_provider_;
49 // A mock implementation of WifiDataProviderImplBase for testing. Adapted from
50 // http://gears.googlecode.com/svn/trunk/gears/geolocation/geolocation_test.cc
51 class MockWifiDataProviderImpl : public WifiDataProviderImplBase {
52 public:
53 // Factory method for use with WifiDataProvider::SetFactory.
54 static WifiDataProviderImplBase* GetInstance() {
55 CHECK(instance_);
56 return instance_;
59 static MockWifiDataProviderImpl* CreateInstance() {
60 CHECK(!instance_);
61 instance_ = new MockWifiDataProviderImpl;
62 return instance_;
65 MockWifiDataProviderImpl()
66 : start_calls_(0),
67 stop_calls_(0),
68 got_data_(true) {
71 // WifiDataProviderImplBase implementation.
72 virtual void StartDataProvider() OVERRIDE {
73 ++start_calls_;
76 virtual void StopDataProvider() OVERRIDE {
77 ++stop_calls_;
80 virtual bool GetData(WifiData* data_out) OVERRIDE {
81 CHECK(data_out);
82 *data_out = data_;
83 return got_data_;
86 void SetData(const WifiData& new_data) {
87 got_data_ = true;
88 const bool differs = data_.DiffersSignificantly(new_data);
89 data_ = new_data;
90 if (differs)
91 this->RunCallbacks();
94 void set_got_data(bool got_data) { got_data_ = got_data; }
95 int start_calls_;
96 int stop_calls_;
98 private:
99 virtual ~MockWifiDataProviderImpl() {
100 CHECK(this == instance_);
101 instance_ = NULL;
104 static MockWifiDataProviderImpl* instance_;
106 WifiData data_;
107 bool got_data_;
109 DISALLOW_COPY_AND_ASSIGN(MockWifiDataProviderImpl);
112 MockWifiDataProviderImpl* MockWifiDataProviderImpl::instance_ = NULL;
114 // Main test fixture
115 class GeolocationNetworkProviderTest : public testing::Test {
116 public:
117 virtual void SetUp() {
118 test_server_url_ = GURL(kTestServerUrl);
119 access_token_store_ = new FakeAccessTokenStore;
120 wifi_data_provider_ =
121 MockWifiDataProviderImpl::CreateInstance();
124 virtual void TearDown() {
125 WifiDataProvider::ResetFactory();
128 LocationProvider* CreateProvider(bool set_permission_granted) {
129 LocationProvider* provider = NewNetworkLocationProvider(
130 access_token_store_.get(),
131 NULL, // No URLContextGetter needed, as using test urlfecther factory.
132 test_server_url_,
133 access_token_store_->access_token_set_[test_server_url_]);
134 if (set_permission_granted)
135 provider->OnPermissionGranted();
136 return provider;
139 protected:
140 GeolocationNetworkProviderTest() {
141 // TODO(joth): Really these should be in SetUp, not here, but they take no
142 // effect on Mac OS Release builds if done there. I kid not. Figure out why.
143 WifiDataProvider::SetFactory(MockWifiDataProviderImpl::GetInstance);
146 // Returns the current url fetcher (if any) and advances the id ready for the
147 // next test step.
148 net::TestURLFetcher* get_url_fetcher_and_advance_id() {
149 net::TestURLFetcher* fetcher = url_fetcher_factory_.GetFetcherByID(
150 NetworkLocationRequest::url_fetcher_id_for_tests);
151 if (fetcher)
152 ++NetworkLocationRequest::url_fetcher_id_for_tests;
153 return fetcher;
156 static int IndexToChannel(int index) { return index + 4; }
158 // Creates wifi data containing the specified number of access points, with
159 // some differentiating charactistics in each.
160 static WifiData CreateReferenceWifiScanData(int ap_count) {
161 WifiData data;
162 for (int i = 0; i < ap_count; ++i) {
163 AccessPointData ap;
164 ap.mac_address =
165 base::ASCIIToUTF16(base::StringPrintf("%02d-34-56-78-54-32", i));
166 ap.radio_signal_strength = ap_count - i;
167 ap.channel = IndexToChannel(i);
168 ap.signal_to_noise = i + 42;
169 ap.ssid = base::ASCIIToUTF16("Some nice+network|name\\");
170 data.access_point_data.insert(ap);
172 return data;
175 static void CreateReferenceWifiScanDataJson(
176 int ap_count, int start_index, base::ListValue* wifi_access_point_list) {
177 std::vector<std::string> wifi_data;
178 for (int i = 0; i < ap_count; ++i) {
179 base::DictionaryValue* ap = new base::DictionaryValue();
180 ap->SetString("macAddress", base::StringPrintf("%02d-34-56-78-54-32", i));
181 ap->SetInteger("signalStrength", start_index + ap_count - i);
182 ap->SetInteger("age", 0);
183 ap->SetInteger("channel", IndexToChannel(i));
184 ap->SetInteger("signalToNoiseRatio", i + 42);
185 wifi_access_point_list->Append(ap);
189 static Geoposition CreateReferencePosition(int id) {
190 Geoposition pos;
191 pos.latitude = id;
192 pos.longitude = -(id + 1);
193 pos.altitude = 2 * id;
194 pos.timestamp = base::Time::Now();
195 return pos;
198 static std::string PrettyJson(const base::Value& value) {
199 std::string pretty;
200 base::JSONWriter::WriteWithOptions(
201 &value, base::JSONWriter::OPTIONS_PRETTY_PRINT, &pretty);
202 return pretty;
205 static testing::AssertionResult JsonGetList(
206 const std::string& field,
207 const base::DictionaryValue& dict,
208 const base::ListValue** output_list) {
209 if (!dict.GetList(field, output_list))
210 return testing::AssertionFailure() << "Dictionary " << PrettyJson(dict)
211 << " is missing list field " << field;
212 return testing::AssertionSuccess();
215 static testing::AssertionResult JsonFieldEquals(
216 const std::string& field,
217 const base::DictionaryValue& expected,
218 const base::DictionaryValue& actual) {
219 const base::Value* expected_value;
220 const base::Value* actual_value;
221 if (!expected.Get(field, &expected_value))
222 return testing::AssertionFailure()
223 << "Expected dictionary " << PrettyJson(expected)
224 << " is missing field " << field;
225 if (!expected.Get(field, &actual_value))
226 return testing::AssertionFailure()
227 << "Actual dictionary " << PrettyJson(actual)
228 << " is missing field " << field;
229 if (!expected_value->Equals(actual_value))
230 return testing::AssertionFailure()
231 << "Field " << field << " mismatch: " << PrettyJson(*expected_value)
232 << " != " << PrettyJson(*actual_value);
233 return testing::AssertionSuccess();
236 static GURL UrlWithoutQuery(const GURL& url) {
237 url_canon::Replacements<char> replacements;
238 replacements.ClearQuery();
239 return url.ReplaceComponents(replacements);
242 testing::AssertionResult IsTestServerUrl(const GURL& request_url) {
243 const GURL a(UrlWithoutQuery(test_server_url_));
244 const GURL b(UrlWithoutQuery(request_url));
245 if (a == b)
246 return testing::AssertionSuccess();
247 return testing::AssertionFailure() << a << " != " << b;
250 void CheckRequestIsValid(const net::TestURLFetcher& request,
251 int expected_routers,
252 int expected_wifi_aps,
253 int wifi_start_index,
254 const std::string& expected_access_token) {
255 const GURL& request_url = request.GetOriginalURL();
257 EXPECT_TRUE(IsTestServerUrl(request_url));
259 // Check to see that the api key is being appended for the default
260 // network provider url.
261 bool is_default_url = UrlWithoutQuery(request_url) ==
262 UrlWithoutQuery(LocationArbitratorImpl::DefaultNetworkProviderURL());
263 EXPECT_EQ(is_default_url, !request_url.query().empty());
265 const std::string& upload_data = request.upload_data();
266 ASSERT_FALSE(upload_data.empty());
267 std::string json_parse_error_msg;
268 scoped_ptr<base::Value> parsed_json(
269 base::JSONReader::ReadAndReturnError(
270 upload_data,
271 base::JSON_PARSE_RFC,
272 NULL,
273 &json_parse_error_msg));
274 EXPECT_TRUE(json_parse_error_msg.empty());
275 ASSERT_TRUE(parsed_json.get() != NULL);
277 const base::DictionaryValue* request_json;
278 ASSERT_TRUE(parsed_json->GetAsDictionary(&request_json));
280 if (!is_default_url) {
281 if (expected_access_token.empty())
282 ASSERT_FALSE(request_json->HasKey(kAccessTokenString));
283 else {
284 std::string access_token;
285 EXPECT_TRUE(request_json->GetString(kAccessTokenString, &access_token));
286 EXPECT_EQ(expected_access_token, access_token);
290 if (expected_wifi_aps) {
291 base::ListValue expected_wifi_aps_json;
292 CreateReferenceWifiScanDataJson(
293 expected_wifi_aps,
294 wifi_start_index,
295 &expected_wifi_aps_json);
296 EXPECT_EQ(size_t(expected_wifi_aps), expected_wifi_aps_json.GetSize());
298 const base::ListValue* wifi_aps_json;
299 ASSERT_TRUE(JsonGetList("wifiAccessPoints", *request_json,
300 &wifi_aps_json));
301 for (size_t i = 0; i < expected_wifi_aps_json.GetSize(); ++i ) {
302 const base::DictionaryValue* expected_json;
303 ASSERT_TRUE(expected_wifi_aps_json.GetDictionary(i, &expected_json));
304 const base::DictionaryValue* actual_json;
305 ASSERT_TRUE(wifi_aps_json->GetDictionary(i, &actual_json));
306 ASSERT_TRUE(JsonFieldEquals("macAddress", *expected_json,
307 *actual_json));
308 ASSERT_TRUE(JsonFieldEquals("signalStrength", *expected_json,
309 *actual_json));
310 ASSERT_TRUE(JsonFieldEquals("channel", *expected_json, *actual_json));
311 ASSERT_TRUE(JsonFieldEquals("signalToNoiseRatio", *expected_json,
312 *actual_json));
314 } else {
315 ASSERT_FALSE(request_json->HasKey("wifiAccessPoints"));
317 EXPECT_TRUE(request_url.is_valid());
320 GURL test_server_url_;
321 base::MessageLoop main_message_loop_;
322 scoped_refptr<FakeAccessTokenStore> access_token_store_;
323 net::TestURLFetcherFactory url_fetcher_factory_;
324 scoped_refptr<MockWifiDataProviderImpl> wifi_data_provider_;
327 TEST_F(GeolocationNetworkProviderTest, CreateDestroy) {
328 // Test fixture members were SetUp correctly.
329 EXPECT_EQ(&main_message_loop_, base::MessageLoop::current());
330 scoped_ptr<LocationProvider> provider(CreateProvider(true));
331 EXPECT_TRUE(NULL != provider.get());
332 provider.reset();
333 SUCCEED();
336 TEST_F(GeolocationNetworkProviderTest, StartProvider) {
337 scoped_ptr<LocationProvider> provider(CreateProvider(true));
338 EXPECT_TRUE(provider->StartProvider(false));
339 net::TestURLFetcher* fetcher = get_url_fetcher_and_advance_id();
340 ASSERT_TRUE(fetcher != NULL);
341 CheckRequestIsValid(*fetcher, 0, 0, 0, std::string());
344 TEST_F(GeolocationNetworkProviderTest, StartProviderDefaultUrl) {
345 test_server_url_ = LocationArbitratorImpl::DefaultNetworkProviderURL();
346 scoped_ptr<LocationProvider> provider(CreateProvider(true));
347 EXPECT_TRUE(provider->StartProvider(false));
348 net::TestURLFetcher* fetcher = get_url_fetcher_and_advance_id();
349 ASSERT_TRUE(fetcher != NULL);
350 CheckRequestIsValid(*fetcher, 0, 0, 0, std::string());
353 TEST_F(GeolocationNetworkProviderTest, StartProviderLongRequest) {
354 scoped_ptr<LocationProvider> provider(CreateProvider(true));
355 EXPECT_TRUE(provider->StartProvider(false));
356 const int kFirstScanAps = 20;
357 wifi_data_provider_->SetData(CreateReferenceWifiScanData(kFirstScanAps));
358 main_message_loop_.RunUntilIdle();
359 net::TestURLFetcher* fetcher = get_url_fetcher_and_advance_id();
360 ASSERT_TRUE(fetcher != NULL);
361 // The request url should have been shortened to less than 2048 characters
362 // in length by not including access points with the lowest signal strength
363 // in the request.
364 EXPECT_LT(fetcher->GetOriginalURL().spec().size(), size_t(2048));
365 CheckRequestIsValid(*fetcher, 0, 16, 4, std::string());
368 TEST_F(GeolocationNetworkProviderTest, MultipleWifiScansComplete) {
369 scoped_ptr<LocationProvider> provider(CreateProvider(true));
370 EXPECT_TRUE(provider->StartProvider(false));
372 net::TestURLFetcher* fetcher = get_url_fetcher_and_advance_id();
373 ASSERT_TRUE(fetcher != NULL);
374 EXPECT_TRUE(IsTestServerUrl(fetcher->GetOriginalURL()));
376 // Complete the network request with bad position fix.
377 const char* kNoFixNetworkResponse =
379 " \"status\": \"ZERO_RESULTS\""
380 "}";
381 fetcher->set_url(test_server_url_);
382 fetcher->set_status(net::URLRequestStatus());
383 fetcher->set_response_code(200); // OK
384 fetcher->SetResponseString(kNoFixNetworkResponse);
385 fetcher->delegate()->OnURLFetchComplete(fetcher);
387 Geoposition position;
388 provider->GetPosition(&position);
389 EXPECT_FALSE(position.Validate());
391 // Now wifi data arrives -- SetData will notify listeners.
392 const int kFirstScanAps = 6;
393 wifi_data_provider_->SetData(CreateReferenceWifiScanData(kFirstScanAps));
394 main_message_loop_.RunUntilIdle();
395 fetcher = get_url_fetcher_and_advance_id();
396 ASSERT_TRUE(fetcher != NULL);
397 // The request should have the wifi data.
398 CheckRequestIsValid(*fetcher, 0, kFirstScanAps, 0, std::string());
400 // Send a reply with good position fix.
401 const char* kReferenceNetworkResponse =
403 " \"accessToken\": \"" REFERENCE_ACCESS_TOKEN "\","
404 " \"accuracy\": 1200.4,"
405 " \"location\": {"
406 " \"lat\": 51.0,"
407 " \"lng\": -0.1"
408 " }"
409 "}";
410 fetcher->set_url(test_server_url_);
411 fetcher->set_status(net::URLRequestStatus());
412 fetcher->set_response_code(200); // OK
413 fetcher->SetResponseString(kReferenceNetworkResponse);
414 fetcher->delegate()->OnURLFetchComplete(fetcher);
416 provider->GetPosition(&position);
417 EXPECT_EQ(51.0, position.latitude);
418 EXPECT_EQ(-0.1, position.longitude);
419 EXPECT_EQ(1200.4, position.accuracy);
420 EXPECT_FALSE(position.timestamp.is_null());
421 EXPECT_TRUE(position.Validate());
423 // Token should be in the store.
424 EXPECT_EQ(base::UTF8ToUTF16(REFERENCE_ACCESS_TOKEN),
425 access_token_store_->access_token_set_[test_server_url_]);
427 // Wifi updated again, with one less AP. This is 'close enough' to the
428 // previous scan, so no new request made.
429 const int kSecondScanAps = kFirstScanAps - 1;
430 wifi_data_provider_->SetData(CreateReferenceWifiScanData(kSecondScanAps));
431 main_message_loop_.RunUntilIdle();
432 fetcher = get_url_fetcher_and_advance_id();
433 EXPECT_FALSE(fetcher);
435 provider->GetPosition(&position);
436 EXPECT_EQ(51.0, position.latitude);
437 EXPECT_EQ(-0.1, position.longitude);
438 EXPECT_TRUE(position.Validate());
440 // Now a third scan with more than twice the original amount -> new request.
441 const int kThirdScanAps = kFirstScanAps * 2 + 1;
442 wifi_data_provider_->SetData(CreateReferenceWifiScanData(kThirdScanAps));
443 main_message_loop_.RunUntilIdle();
444 fetcher = get_url_fetcher_and_advance_id();
445 EXPECT_TRUE(fetcher);
446 CheckRequestIsValid(*fetcher, 0, kThirdScanAps, 0, REFERENCE_ACCESS_TOKEN);
447 // ...reply with a network error.
449 fetcher->set_url(test_server_url_);
450 fetcher->set_status(net::URLRequestStatus(net::URLRequestStatus::FAILED, -1));
451 fetcher->set_response_code(200); // should be ignored
452 fetcher->SetResponseString(std::string());
453 fetcher->delegate()->OnURLFetchComplete(fetcher);
455 // Error means we now no longer have a fix.
456 provider->GetPosition(&position);
457 EXPECT_FALSE(position.Validate());
459 // Wifi scan returns to original set: should be serviced from cache.
460 wifi_data_provider_->SetData(CreateReferenceWifiScanData(kFirstScanAps));
461 main_message_loop_.RunUntilIdle();
462 EXPECT_FALSE(get_url_fetcher_and_advance_id()); // No new request created.
464 provider->GetPosition(&position);
465 EXPECT_EQ(51.0, position.latitude);
466 EXPECT_EQ(-0.1, position.longitude);
467 EXPECT_TRUE(position.Validate());
470 TEST_F(GeolocationNetworkProviderTest, NoRequestOnStartupUntilWifiData) {
471 MessageLoopQuitListener listener;
472 wifi_data_provider_->set_got_data(false);
473 scoped_ptr<LocationProvider> provider(CreateProvider(true));
474 EXPECT_TRUE(provider->StartProvider(false));
476 provider->SetUpdateCallback(
477 base::Bind(&MessageLoopQuitListener::LocationUpdateAvailable,
478 base::Unretained(&listener)));
480 main_message_loop_.RunUntilIdle();
481 EXPECT_FALSE(get_url_fetcher_and_advance_id())
482 << "Network request should not be created right away on startup when "
483 "wifi data has not yet arrived";
485 wifi_data_provider_->SetData(CreateReferenceWifiScanData(1));
486 main_message_loop_.RunUntilIdle();
487 EXPECT_TRUE(get_url_fetcher_and_advance_id());
490 TEST_F(GeolocationNetworkProviderTest, NewDataReplacesExistingNetworkRequest) {
491 // Send initial request with empty data
492 scoped_ptr<LocationProvider> provider(CreateProvider(true));
493 EXPECT_TRUE(provider->StartProvider(false));
494 net::TestURLFetcher* fetcher = get_url_fetcher_and_advance_id();
495 EXPECT_TRUE(fetcher);
497 // Now wifi data arrives; new request should be sent.
498 wifi_data_provider_->SetData(CreateReferenceWifiScanData(4));
499 main_message_loop_.RunUntilIdle();
500 fetcher = get_url_fetcher_and_advance_id();
501 EXPECT_TRUE(fetcher);
504 TEST_F(GeolocationNetworkProviderTest, NetworkRequestDeferredForPermission) {
505 scoped_ptr<LocationProvider> provider(CreateProvider(false));
506 EXPECT_TRUE(provider->StartProvider(false));
507 net::TestURLFetcher* fetcher = get_url_fetcher_and_advance_id();
508 EXPECT_FALSE(fetcher);
509 provider->OnPermissionGranted();
511 fetcher = get_url_fetcher_and_advance_id();
512 ASSERT_TRUE(fetcher != NULL);
514 EXPECT_TRUE(IsTestServerUrl(fetcher->GetOriginalURL()));
517 TEST_F(GeolocationNetworkProviderTest,
518 NetworkRequestWithWifiDataDeferredForPermission) {
519 access_token_store_->access_token_set_[test_server_url_] =
520 base::UTF8ToUTF16(REFERENCE_ACCESS_TOKEN);
521 scoped_ptr<LocationProvider> provider(CreateProvider(false));
522 EXPECT_TRUE(provider->StartProvider(false));
523 net::TestURLFetcher* fetcher = get_url_fetcher_and_advance_id();
524 EXPECT_FALSE(fetcher);
526 static const int kScanCount = 4;
527 wifi_data_provider_->SetData(CreateReferenceWifiScanData(kScanCount));
528 main_message_loop_.RunUntilIdle();
530 fetcher = get_url_fetcher_and_advance_id();
531 EXPECT_FALSE(fetcher);
533 provider->OnPermissionGranted();
535 fetcher = get_url_fetcher_and_advance_id();
536 ASSERT_TRUE(fetcher != NULL);
538 CheckRequestIsValid(*fetcher, 0, kScanCount, 0, REFERENCE_ACCESS_TOKEN);
541 TEST_F(GeolocationNetworkProviderTest, NetworkPositionCache) {
542 NetworkLocationProvider::PositionCache cache;
544 const int kCacheSize = NetworkLocationProvider::PositionCache::kMaximumSize;
545 for (int i = 1; i < kCacheSize * 2 + 1; ++i) {
546 Geoposition pos = CreateReferencePosition(i);
547 bool ret = cache.CachePosition(CreateReferenceWifiScanData(i), pos);
548 EXPECT_TRUE(ret) << i;
549 const Geoposition* item =
550 cache.FindPosition(CreateReferenceWifiScanData(i));
551 ASSERT_TRUE(item) << i;
552 EXPECT_EQ(pos.latitude, item->latitude) << i;
553 EXPECT_EQ(pos.longitude, item->longitude) << i;
554 if (i <= kCacheSize) {
555 // Nothing should have spilled yet; check oldest item is still there.
556 EXPECT_TRUE(cache.FindPosition(CreateReferenceWifiScanData(1)));
557 } else {
558 const int evicted = i - kCacheSize;
559 EXPECT_FALSE(cache.FindPosition(CreateReferenceWifiScanData(evicted)));
560 EXPECT_TRUE(cache.FindPosition(CreateReferenceWifiScanData(evicted + 1)));
565 } // namespace content