Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4)

Side by Side Diff: chrome/browser/geolocation/network_location_provider_unittest.cc

Issue 578017: Hopefully final attempt at landing http://src.chromium.org/viewvc/chrome?view... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 10 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | chrome/chrome_tests.gypi » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Property Changes:
Name: svn:eol-style
+ LF
OLDNEW
(Empty)
1 // Copyright (c) 2010 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 "chrome/browser/geolocation/network_location_provider.h"
6
7 #include <map>
8
9 #include "base/json/json_reader.h"
10 #include "base/scoped_ptr.h"
11 #include "base/string_util.h"
12 #include "base/values.h"
13 #include "chrome/browser/net/test_url_fetcher_factory.h"
14 #include "net/url_request/url_request_status.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16
17 namespace {
18 const char kTestServerUrl[] = "https://www.geolocation.test/service";
19 const char kTestHost[] = "myclienthost.test";
20 } // namespace
21
22 // Stops the specified (nested) message loop when the listener is called back.
23 class MessageLoopQuitListener
24 : public LocationProviderBase::ListenerInterface {
25 public:
26 MessageLoopQuitListener()
27 : client_message_loop_(MessageLoop::current()),
28 updated_provider_(NULL),
29 movement_provider_(NULL) {
30 DCHECK(client_message_loop_);
31 }
32 // ListenerInterface
33 virtual void LocationUpdateAvailable(LocationProviderBase* provider) {
34 EXPECT_EQ(client_message_loop_, MessageLoop::current());
35 updated_provider_ = provider;
36 client_message_loop_->Quit();
37 }
38 virtual void MovementDetected(LocationProviderBase* provider) {
39 EXPECT_EQ(client_message_loop_, MessageLoop::current());
40 movement_provider_ = provider;
41 client_message_loop_->Quit();
42 }
43 MessageLoop* client_message_loop_;
44 LocationProviderBase* updated_provider_;
45 LocationProviderBase* movement_provider_;
46 };
47
48 class FakeAccessTokenStore : public LocationProviderBase::AccessTokenStore {
49 public:
50 FakeAccessTokenStore() : allow_set_(true) {}
51
52 virtual bool SetAccessToken(const GURL& url,
53 const string16& access_token) {
54 if (!allow_set_)
55 return false;
56 token_map_[url] = access_token;
57 return true;
58 }
59 virtual bool GetAccessToken(const GURL& url, string16* access_token) {
60 std::map<GURL, string16>::iterator item = token_map_.find(url);
61 if (item == token_map_.end())
62 return false;
63 *access_token = item->second;
64 return true;
65 }
66 bool allow_set_;
67 std::map<GURL, string16> token_map_;
68 };
69
70
71 // A mock implementation of DeviceDataProviderImplBase for testing. Adapted from
72 // http://gears.googlecode.com/svn/trunk/gears/geolocation/geolocation_test.cc
73 template<typename DataType>
74 class MockDeviceDataProviderImpl
75 : public DeviceDataProviderImplBase<DataType> {
76 public:
77 // Factory method for use with DeviceDataProvider::SetFactory.
78 static DeviceDataProviderImplBase<DataType>* Create() {
79 return new MockDeviceDataProviderImpl<DataType>();
80 }
81 static MockDeviceDataProviderImpl<DataType>* instance() {
82 CHECK(instance_ != NULL);
83 return instance_;
84 }
85
86 MockDeviceDataProviderImpl() {
87 CHECK(instance_ == NULL);
88 instance_ = this;
89 }
90 virtual ~MockDeviceDataProviderImpl() {
91 CHECK(this == instance_);
92 instance_ = NULL;
93 }
94
95 // DeviceDataProviderImplBase implementation.
96 virtual bool StartDataProvider() {
97 return true;
98 }
99 virtual bool GetData(DataType* data_out) {
100 CHECK(data_out);
101 AutoLock lock(data_mutex_);
102 *data_out = data_;
103 // We always have all the data we can get, so return true.
104 return true;
105 }
106
107 void SetData(const DataType& new_data) {
108 data_mutex_.Acquire();
109 const bool differs = data_.DiffersSignificantly(new_data);
110 data_ = new_data;
111 data_mutex_.Release();
112 if (differs)
113 this->NotifyListeners();
114 }
115
116 private:
117 static MockDeviceDataProviderImpl<DataType>* instance_;
118
119 DataType data_;
120 Lock data_mutex_;
121
122 DISALLOW_COPY_AND_ASSIGN(MockDeviceDataProviderImpl);
123 };
124
125 template<typename DataType>
126 MockDeviceDataProviderImpl<DataType>*
127 MockDeviceDataProviderImpl<DataType>::instance_ = NULL;
128
129 // Main test fixture
130 class NetworkLocationProviderTest : public testing::Test {
131 public:
132 virtual void SetUp() {
133 URLFetcher::set_factory(&url_fetcher_factory_);
134 }
135
136 virtual void TearDown() {
137 WifiDataProvider::ResetFactory();
138 RadioDataProvider::ResetFactory();
139 URLFetcher::set_factory(NULL);
140 base::LeakTracker<URLFetcher>::CheckForLeaks();
141 }
142
143 LocationProviderBase* CreateProvider() {
144 return NewNetworkLocationProvider(
145 &access_token_store_,
146 NULL, // No URLContextGetter needed, as using test urlfecther factory.
147 test_server_url_,
148 ASCIIToUTF16(kTestHost));
149 }
150
151 protected:
152 NetworkLocationProviderTest() : test_server_url_(kTestServerUrl) {
153 // TODO(joth): Really these should be in SetUp, not here, but they take no
154 // effect on Mac OS Release builds if done there. I kid not. Figure out why.
155 RadioDataProvider::SetFactory(
156 MockDeviceDataProviderImpl<RadioData>::Create);
157 WifiDataProvider::SetFactory(
158 MockDeviceDataProviderImpl<WifiData>::Create);
159 }
160
161 static int IndexToChannal(int index) { return index + 4; }
162 static int IndexToAge(int index) { return (index * 3) + 100; }
163
164 // Creates wifi data containing the specified number of access points, with
165 // some differentiating charactistics in each.
166 static WifiData CreateReferenceWifiScanData(int ap_count) {
167 WifiData data;
168 for (int i = 0; i < ap_count; ++i) {
169 AccessPointData ap;
170 ap.mac_address = ASCIIToUTF16(StringPrintf("%02d-34-56-78-54-32", i));
171 ap.radio_signal_strength = i;
172 ap.age = IndexToAge(i);
173 ap.channel = IndexToChannal(i);
174 ap.signal_to_noise = i + 42;
175 ap.ssid = ASCIIToUTF16("Some nice network");
176 data.access_point_data.insert(ap);
177 }
178 return data;
179 }
180
181 static void ParseRequest(const std::string& request_data,
182 WifiData* wifi_data_out,
183 std::string* access_token_out) {
184 CHECK(wifi_data_out && access_token_out);
185 scoped_ptr<Value> value(base::JSONReader::Read(request_data, false));
186 EXPECT_TRUE(value != NULL);
187 EXPECT_EQ(Value::TYPE_DICTIONARY, value->GetType());
188 DictionaryValue* dictionary = static_cast<DictionaryValue*>(value.get());
189 std::string attr_value;
190 EXPECT_TRUE(dictionary->GetString(L"version", &attr_value));
191 EXPECT_EQ(attr_value, "1.1.0");
192 EXPECT_TRUE(dictionary->GetString(L"host", &attr_value));
193 EXPECT_EQ(attr_value, kTestHost);
194 // Everything else is optional.
195 ListValue* wifi_aps;
196 if (dictionary->GetList(L"wifi_towers", &wifi_aps)) {
197 int i = 0;
198 for (ListValue::const_iterator it = wifi_aps->begin();
199 it < wifi_aps->end(); ++it, ++i) {
200 EXPECT_EQ(Value::TYPE_DICTIONARY, (*it)->GetType());
201 DictionaryValue* ap = static_cast<DictionaryValue*>(*it);
202 AccessPointData data;
203 ap->GetStringAsUTF16(L"mac_address", &data.mac_address);
204 ap->GetInteger(L"signal_strength", &data.radio_signal_strength);
205 ap->GetInteger(L"age", &data.age);
206 ap->GetInteger(L"channel", &data.channel);
207 ap->GetInteger(L"signal_to_noise", &data.signal_to_noise);
208 ap->GetStringAsUTF16(L"ssid", &data.ssid);
209 wifi_data_out->access_point_data.insert(data);
210 }
211 } else {
212 wifi_data_out->access_point_data.clear();
213 }
214 if (!dictionary->GetString(L"access_token", access_token_out))
215 access_token_out->clear();
216 }
217
218 static void CheckEmptyRequestIsValid(const std::string& request_data) {
219 WifiData wifi_aps;
220 std::string access_token;
221 ParseRequest(request_data, &wifi_aps, &access_token);
222 EXPECT_EQ(0, static_cast<int>(wifi_aps.access_point_data.size()));
223 EXPECT_TRUE(access_token.empty());
224 }
225
226 static void CheckRequestIsValid(const std::string& request_data,
227 int expected_wifi_aps,
228 const std::string& expected_access_token) {
229 WifiData wifi_aps;
230 std::string access_token;
231 ParseRequest(request_data, &wifi_aps, &access_token);
232 EXPECT_EQ(expected_wifi_aps,
233 static_cast<int>(wifi_aps.access_point_data.size()));
234 WifiData expected_data = CreateReferenceWifiScanData(expected_wifi_aps);
235 WifiData::AccessPointDataSet::const_iterator expected =
236 expected_data.access_point_data.begin();
237 WifiData::AccessPointDataSet::const_iterator actual =
238 wifi_aps.access_point_data.begin();
239 for (int i = 0; i < expected_wifi_aps; ++i) {
240 EXPECT_EQ(expected->mac_address, actual->mac_address) << i;
241 EXPECT_EQ(expected->radio_signal_strength, actual->radio_signal_strength)
242 << i;
243 EXPECT_EQ(expected->age, actual->age) << i;
244 EXPECT_EQ(expected->channel, actual->channel) << i;
245 EXPECT_EQ(expected->signal_to_noise, actual->signal_to_noise) << i;
246 EXPECT_EQ(expected->ssid, actual->ssid) << i;
247 ++expected;
248 ++actual;
249 }
250 EXPECT_EQ(expected_access_token, access_token);
251 }
252
253 const GURL test_server_url_;
254 MessageLoop main_message_loop_;
255 FakeAccessTokenStore access_token_store_;
256 TestURLFetcherFactory url_fetcher_factory_;
257 };
258
259
260 TEST_F(NetworkLocationProviderTest, CreateDestroy) {
261 // Test fixture members were SetUp correctly.
262 EXPECT_EQ(&main_message_loop_, MessageLoop::current());
263 scoped_refptr<LocationProviderBase> provider(CreateProvider());
264 EXPECT_TRUE(NULL != provider.get());
265 provider = NULL;
266 SUCCEED();
267 }
268
269 TEST_F(NetworkLocationProviderTest, StartProvider) {
270 scoped_refptr<LocationProviderBase> provider(CreateProvider());
271 EXPECT_TRUE(provider->StartProvider());
272 TestURLFetcher* fetcher = url_fetcher_factory_.GetFetcherByID(0);
273 ASSERT_TRUE(fetcher != NULL);
274
275 EXPECT_EQ(test_server_url_, fetcher->original_url());
276
277 // No wifi data so expect an empty request.
278 CheckEmptyRequestIsValid(fetcher->upload_data());
279 }
280
281 TEST_F(NetworkLocationProviderTest, MultipleWifiScansComplete) {
282 scoped_refptr<LocationProviderBase> provider(CreateProvider());
283 EXPECT_TRUE(provider->StartProvider());
284
285 TestURLFetcher* fetcher = url_fetcher_factory_.GetFetcherByID(0);
286 ASSERT_TRUE(fetcher != NULL);
287 CheckEmptyRequestIsValid(fetcher->upload_data());
288 // Complete the network request with bad position fix (using #define so we
289 // can paste this into various other strings below)
290 #define REFERENCE_ACCESS_TOKEN "2:k7j3G6LaL6u_lafw:4iXOeOpTh1glSXe"
291 const char* kNoFixNetworkResponse =
292 "{"
293 " \"location\": null,"
294 " \"access_token\": \"" REFERENCE_ACCESS_TOKEN "\""
295 "}";
296 fetcher->delegate()->OnURLFetchComplete(
297 fetcher, test_server_url_, URLRequestStatus(), 200, // OK
298 ResponseCookies(), kNoFixNetworkResponse);
299
300 // This should have set the access token anyhow
301 EXPECT_EQ(1, static_cast<int>(access_token_store_.token_map_.size()));
302 string16 token;
303 EXPECT_TRUE(access_token_store_.GetAccessToken(test_server_url_, &token));
304 EXPECT_EQ(REFERENCE_ACCESS_TOKEN, UTF16ToUTF8(token));
305
306 Position position;
307 provider->GetPosition(&position);
308 EXPECT_FALSE(position.IsValidFix());
309
310 // Now wifi data arrives
311 const int kFirstScanAps = 6;
312 MockDeviceDataProviderImpl<WifiData>::instance()->SetData(
313 CreateReferenceWifiScanData(kFirstScanAps)); // Will notify listeners
314 fetcher = url_fetcher_factory_.GetFetcherByID(kFirstScanAps);
315 ASSERT_TRUE(fetcher != NULL);
316 // The request should have access token (set previously) and the wifi data.
317 CheckRequestIsValid(fetcher->upload_data(),
318 kFirstScanAps,
319 REFERENCE_ACCESS_TOKEN);
320
321 // Send a reply with good position fix.
322 const char* kReferenceNetworkResponse =
323 "{"
324 " \"location\": {"
325 " \"latitude\": 51.0,"
326 " \"longitude\": -0.1,"
327 " \"altitude\": 30.1,"
328 " \"accuracy\": 1200.4,"
329 " \"altitude_accuracy\": 10.6"
330 " }"
331 "}";
332 fetcher->delegate()->OnURLFetchComplete(
333 fetcher, test_server_url_, URLRequestStatus(), 200, // OK
334 ResponseCookies(), kReferenceNetworkResponse);
335
336 provider->GetPosition(&position);
337 EXPECT_EQ(51.0, position.latitude);
338 EXPECT_EQ(-0.1, position.longitude);
339 EXPECT_EQ(30.1, position.altitude);
340 EXPECT_EQ(1200.4, position.accuracy);
341 EXPECT_EQ(10.6, position.altitude_accuracy);
342 EXPECT_TRUE(position.is_valid_timestamp());
343 EXPECT_TRUE(position.IsValidFix());
344
345 // Token should still be in the store.
346 EXPECT_EQ(1, static_cast<int>(access_token_store_.token_map_.size()));
347 EXPECT_TRUE(access_token_store_.GetAccessToken(test_server_url_, &token));
348 EXPECT_EQ(REFERENCE_ACCESS_TOKEN, UTF16ToUTF8(token));
349
350 // Wifi updated again, with one less AP. This is 'close enough' to the
351 // previous scan, so no new request made.
352 const int kSecondScanAps = kFirstScanAps - 1;
353 MockDeviceDataProviderImpl<WifiData>::instance()->SetData(
354 CreateReferenceWifiScanData(kSecondScanAps));
355 fetcher = url_fetcher_factory_.GetFetcherByID(kSecondScanAps);
356 EXPECT_FALSE(fetcher);
357
358 provider->GetPosition(&position);
359 EXPECT_EQ(51.0, position.latitude);
360 EXPECT_EQ(-0.1, position.longitude);
361 EXPECT_TRUE(position.IsValidFix());
362
363 // Now a third scan with more than twice the original amount -> new request.
364 const int kThirdScanAps = kFirstScanAps * 2 + 1;
365 MockDeviceDataProviderImpl<WifiData>::instance()->SetData(
366 CreateReferenceWifiScanData(kThirdScanAps));
367 fetcher = url_fetcher_factory_.GetFetcherByID(kThirdScanAps);
368 EXPECT_TRUE(fetcher);
369 // ...reply with a network error.
370 fetcher->delegate()->OnURLFetchComplete(
371 fetcher, test_server_url_,
372 URLRequestStatus(URLRequestStatus::FAILED, -1),
373 200, // should be ignored
374 ResponseCookies(), "");
375
376 // Error means we now no longer have a fix.
377 provider->GetPosition(&position);
378 EXPECT_FALSE(position.is_valid_latlong());
379 EXPECT_FALSE(position.IsValidFix());
380
381 // Wifi scan returns to original set: should be serviced from cache.
382 const TestURLFetcher* orig_fetcher =
383 url_fetcher_factory_.GetFetcherByID(kFirstScanAps);
384 MockDeviceDataProviderImpl<WifiData>::instance()->SetData(
385 CreateReferenceWifiScanData(kFirstScanAps));
386 fetcher = url_fetcher_factory_.GetFetcherByID(kFirstScanAps);
387 EXPECT_EQ(orig_fetcher, fetcher); // No new request created.
388
389 provider->GetPosition(&position);
390 EXPECT_EQ(51.0, position.latitude);
391 EXPECT_EQ(-0.1, position.longitude);
392 EXPECT_TRUE(position.IsValidFix());
393 }
394
395 // TODO(joth): Add tests for corner cases around the 2 second startup delay
396 // (e.g. timer firing, or being pre-empted by data arriving)
OLDNEW
« no previous file with comments | « no previous file | chrome/chrome_tests.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698