- add sources.
[platform/framework/web/crosswalk.git] / src / content / browser / geolocation / network_location_provider_unittest.cc
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.
4
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"
19
20 namespace content {
21
22 // Constants used in multiple tests.
23 const char kTestServerUrl[] = "https://www.geolocation.test/service";
24 const char kAccessTokenString[] = "accessToken";
25
26 // Using #define so we can easily paste this into various other strings.
27 #define REFERENCE_ACCESS_TOKEN "2:k7j3G6LaL6u_lafw:4iXOeOpTh1glSXe"
28
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_);
36   }
37
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();
43   }
44
45   base::MessageLoop* client_message_loop_;
46   const LocationProvider* updated_provider_;
47 };
48
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_;
57   }
58
59   static MockWifiDataProviderImpl* CreateInstance() {
60     CHECK(!instance_);
61     instance_ = new MockWifiDataProviderImpl;
62     return instance_;
63   }
64
65   MockWifiDataProviderImpl()
66       : start_calls_(0),
67         stop_calls_(0),
68         got_data_(true) {
69   }
70
71   // WifiDataProviderImplBase implementation.
72   virtual void StartDataProvider() OVERRIDE {
73     ++start_calls_;
74   }
75
76   virtual void StopDataProvider() OVERRIDE {
77     ++stop_calls_;
78   }
79
80   virtual bool GetData(WifiData* data_out) OVERRIDE {
81     CHECK(data_out);
82     *data_out = data_;
83     return got_data_;
84   }
85
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();
92   }
93
94   void set_got_data(bool got_data) { got_data_ = got_data; }
95   int start_calls_;
96   int stop_calls_;
97
98  private:
99   virtual ~MockWifiDataProviderImpl() {
100     CHECK(this == instance_);
101     instance_ = NULL;
102   }
103
104   static MockWifiDataProviderImpl* instance_;
105
106   WifiData data_;
107   bool got_data_;
108
109   DISALLOW_COPY_AND_ASSIGN(MockWifiDataProviderImpl);
110 };
111
112 MockWifiDataProviderImpl* MockWifiDataProviderImpl::instance_ = NULL;
113
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();
122   }
123
124   virtual void TearDown() {
125     WifiDataProvider::ResetFactory();
126   }
127
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;
137   }
138
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);
144   }
145
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;
154   }
155
156   static int IndexToChannel(int index) { return index + 4; }
157
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           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 = ASCIIToUTF16("Some nice+network|name\\");
170       data.access_point_data.insert(ap);
171     }
172     return data;
173   }
174
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);
186     }
187   }
188
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;
196   }
197
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;
203   }
204
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();
213   }
214
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();
234   }
235
236   static GURL UrlWithoutQuery(const GURL& url) {
237     url_canon::Replacements<char> replacements;
238     replacements.ClearQuery();
239     return url.ReplaceComponents(replacements);
240   }
241
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;
248   }
249
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();
256
257     EXPECT_TRUE(IsTestServerUrl(request_url));
258
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());
264
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);
276
277     const base::DictionaryValue* request_json;
278     ASSERT_TRUE(parsed_json->GetAsDictionary(&request_json));
279
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);
287       }
288     }
289
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());
297
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));
313       }
314     } else {
315       ASSERT_FALSE(request_json->HasKey("wifiAccessPoints"));
316     }
317     EXPECT_TRUE(request_url.is_valid());
318   }
319
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_;
325 };
326
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();
334 }
335
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());
342 }
343
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());
351 }
352
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());
366 }
367
368 TEST_F(GeolocationNetworkProviderTest, MultipleWifiScansComplete) {
369   scoped_ptr<LocationProvider> provider(CreateProvider(true));
370   EXPECT_TRUE(provider->StartProvider(false));
371
372   net::TestURLFetcher* fetcher = get_url_fetcher_and_advance_id();
373   ASSERT_TRUE(fetcher != NULL);
374   EXPECT_TRUE(IsTestServerUrl(fetcher->GetOriginalURL()));
375
376   // Complete the network request with bad position fix.
377   const char* kNoFixNetworkResponse =
378       "{"
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);
386
387   Geoposition position;
388   provider->GetPosition(&position);
389   EXPECT_FALSE(position.Validate());
390
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());
399
400   // Send a reply with good position fix.
401   const char* kReferenceNetworkResponse =
402       "{"
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);
415
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());
422
423   // Token should be in the store.
424   EXPECT_EQ(UTF8ToUTF16(REFERENCE_ACCESS_TOKEN),
425             access_token_store_->access_token_set_[test_server_url_]);
426
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);
434
435   provider->GetPosition(&position);
436   EXPECT_EQ(51.0, position.latitude);
437   EXPECT_EQ(-0.1, position.longitude);
438   EXPECT_TRUE(position.Validate());
439
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.
448
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);
454
455   // Error means we now no longer have a fix.
456   provider->GetPosition(&position);
457   EXPECT_FALSE(position.Validate());
458
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.
463
464   provider->GetPosition(&position);
465   EXPECT_EQ(51.0, position.latitude);
466   EXPECT_EQ(-0.1, position.longitude);
467   EXPECT_TRUE(position.Validate());
468 }
469
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));
475
476   provider->SetUpdateCallback(
477       base::Bind(&MessageLoopQuitListener::LocationUpdateAvailable,
478                  base::Unretained(&listener)));
479
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";
484
485   wifi_data_provider_->SetData(CreateReferenceWifiScanData(1));
486   main_message_loop_.RunUntilIdle();
487   EXPECT_TRUE(get_url_fetcher_and_advance_id());
488 }
489
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);
496
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);
502 }
503
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();
510
511   fetcher = get_url_fetcher_and_advance_id();
512   ASSERT_TRUE(fetcher != NULL);
513
514   EXPECT_TRUE(IsTestServerUrl(fetcher->GetOriginalURL()));
515 }
516
517 TEST_F(GeolocationNetworkProviderTest,
518        NetworkRequestWithWifiDataDeferredForPermission) {
519   access_token_store_->access_token_set_[test_server_url_] =
520       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);
525
526   static const int kScanCount = 4;
527   wifi_data_provider_->SetData(CreateReferenceWifiScanData(kScanCount));
528   main_message_loop_.RunUntilIdle();
529
530   fetcher = get_url_fetcher_and_advance_id();
531   EXPECT_FALSE(fetcher);
532
533   provider->OnPermissionGranted();
534
535   fetcher = get_url_fetcher_and_advance_id();
536   ASSERT_TRUE(fetcher != NULL);
537
538   CheckRequestIsValid(*fetcher, 0, kScanCount, 0, REFERENCE_ACCESS_TOKEN);
539 }
540
541 TEST_F(GeolocationNetworkProviderTest, NetworkPositionCache) {
542   NetworkLocationProvider::PositionCache cache;
543
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)));
561     }
562   }
563 }
564
565 }  // namespace content