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

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

Issue 575021: Revert 38207 - bah. still can't work out why this passes fine on local machin... (Closed) Base URL: svn://svn.chromium.org/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
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 explicit MessageLoopQuitListener()
27 : client_message_loop_(MessageLoop::current()),
28 updated_provider_(NULL),
29 movement_provider_(NULL) {
30 DCHECK(client_message_loop_ != NULL);
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 RadioDataProvider::SetFactory(
135 MockDeviceDataProviderImpl<RadioData>::Create);
136 WifiDataProvider::SetFactory(
137 MockDeviceDataProviderImpl<WifiData>::Create);
138 }
139
140 virtual void TearDown() {
141 WifiDataProvider::ResetFactory();
142 RadioDataProvider::ResetFactory();
143 URLFetcher::set_factory(NULL);
144 base::LeakTracker<URLFetcher>::CheckForLeaks();
145 }
146
147 LocationProviderBase* CreateProvider() {
148 return NewNetworkLocationProvider(
149 &access_token_store_,
150 NULL, // No URLContextGetter needed, as using test urlfecther factory.
151 test_server_url_,
152 ASCIIToUTF16(kTestHost));
153 }
154
155 protected:
156 NetworkLocationProviderTest() : test_server_url_(kTestServerUrl) {}
157
158 static int IndexToChannal(int index) { return index + 4; }
159 static int IndexToAge(int index) { return (index * 3) + 100; }
160
161 // Creates wifi data containing the specified number of access points, with
162 // some differentiating charactistics in each.
163 static WifiData CreateReferenceWifiScanData(int ap_count) {
164 WifiData data;
165 for (int i = 0; i < ap_count; ++i) {
166 AccessPointData ap;
167 ap.mac_address = ASCIIToUTF16(StringPrintf("%02d-34-56-78-54-32", i));
168 ap.radio_signal_strength = i;
169 ap.age = IndexToAge(i);
170 ap.channel = IndexToChannal(i);
171 ap.signal_to_noise = i + 42;
172 ap.ssid = ASCIIToUTF16("Some nice network");
173 data.access_point_data.insert(ap);
174 }
175 return data;
176 }
177
178 static void ParseRequest(const std::string& request_data,
179 WifiData* wifi_data_out,
180 std::string* access_token_out) {
181 CHECK(wifi_data_out && access_token_out);
182 scoped_ptr<Value> value(base::JSONReader::Read(request_data, false));
183 EXPECT_TRUE(value != NULL);
184 EXPECT_EQ(Value::TYPE_DICTIONARY, value->GetType());
185 DictionaryValue* dictionary = static_cast<DictionaryValue*>(value.get());
186 std::string attr_value;
187 EXPECT_TRUE(dictionary->GetString(L"version", &attr_value));
188 EXPECT_EQ(attr_value, "1.1.0");
189 EXPECT_TRUE(dictionary->GetString(L"host", &attr_value));
190 EXPECT_EQ(attr_value, kTestHost);
191 // Everything else is optional.
192 ListValue* wifi_aps;
193 if (dictionary->GetList(L"wifi_towers", &wifi_aps)) {
194 int i = 0;
195 for (ListValue::const_iterator it = wifi_aps->begin();
196 it < wifi_aps->end(); ++it, ++i) {
197 EXPECT_EQ(Value::TYPE_DICTIONARY, (*it)->GetType());
198 DictionaryValue* ap = static_cast<DictionaryValue*>(*it);
199 AccessPointData data;
200 ap->GetStringAsUTF16(L"mac_address", &data.mac_address);
201 ap->GetInteger(L"signal_strength", &data.radio_signal_strength);
202 ap->GetInteger(L"age", &data.age);
203 ap->GetInteger(L"channel", &data.channel);
204 ap->GetInteger(L"signal_to_noise", &data.signal_to_noise);
205 ap->GetStringAsUTF16(L"ssid", &data.ssid);
206 wifi_data_out->access_point_data.insert(data);
207 }
208 } else {
209 wifi_data_out->access_point_data.clear();
210 }
211 if (!dictionary->GetString(L"access_token", access_token_out))
212 access_token_out->clear();
213 }
214
215 static void CheckEmptyRequestIsValid(const std::string& request_data) {
216 WifiData wifi_aps;
217 std::string access_token;
218 ParseRequest(request_data, &wifi_aps, &access_token);
219 EXPECT_EQ(0, static_cast<int>(wifi_aps.access_point_data.size()));
220 EXPECT_TRUE(access_token.empty());
221 }
222
223 static void CheckRequestIsValid(const std::string& request_data,
224 int expected_wifi_aps,
225 const std::string& expected_access_token) {
226 WifiData wifi_aps;
227 std::string access_token;
228 ParseRequest(request_data, &wifi_aps, &access_token);
229 EXPECT_EQ(expected_wifi_aps,
230 static_cast<int>(wifi_aps.access_point_data.size()));
231 WifiData expected_data = CreateReferenceWifiScanData(expected_wifi_aps);
232 WifiData::AccessPointDataSet::const_iterator expected =
233 expected_data.access_point_data.begin();
234 WifiData::AccessPointDataSet::const_iterator actual =
235 wifi_aps.access_point_data.begin();
236 for (int i = 0; i < expected_wifi_aps; ++i) {
237 EXPECT_EQ(expected->mac_address, actual->mac_address) << i;
238 EXPECT_EQ(expected->radio_signal_strength, actual->radio_signal_strength)
239 << i;
240 EXPECT_EQ(expected->age, actual->age) << i;
241 EXPECT_EQ(expected->channel, actual->channel) << i;
242 EXPECT_EQ(expected->signal_to_noise, actual->signal_to_noise) << i;
243 EXPECT_EQ(expected->ssid, actual->ssid) << i;
244 ++expected;
245 ++actual;
246 }
247 EXPECT_EQ(expected_access_token, access_token);
248 }
249
250 const GURL test_server_url_;
251 MessageLoop main_message_loop_;
252 FakeAccessTokenStore access_token_store_;
253 TestURLFetcherFactory url_fetcher_factory_;
254 };
255
256
257 TEST_F(NetworkLocationProviderTest, CreateDestroy) {
258 // Test fixture members were SetUp correctly.
259 EXPECT_EQ(&main_message_loop_, MessageLoop::current());
260 scoped_refptr<LocationProviderBase> provider(CreateProvider());
261 EXPECT_TRUE(NULL != provider.get());
262 provider = NULL;
263 SUCCEED();
264 }
265
266 TEST_F(NetworkLocationProviderTest, StartProvider) {
267 scoped_refptr<LocationProviderBase> provider(CreateProvider());
268 EXPECT_TRUE(provider->StartProvider());
269 TestURLFetcher* fetcher = url_fetcher_factory_.GetFetcherByID(0);
270 ASSERT_TRUE(fetcher != NULL);
271
272 EXPECT_EQ(test_server_url_, fetcher->original_url());
273
274 // No wifi data so expect an empty request.
275 CheckEmptyRequestIsValid(fetcher->upload_data());
276 }
277
278 TEST_F(NetworkLocationProviderTest, MultipleWifiScansComplete) {
279 scoped_refptr<LocationProviderBase> provider(CreateProvider());
280 EXPECT_TRUE(provider->StartProvider());
281 TestURLFetcher* fetcher = url_fetcher_factory_.GetFetcherByID(0);
282 ASSERT_TRUE(fetcher != NULL);
283 CheckEmptyRequestIsValid(fetcher->upload_data());
284 // Complete the network request with bad position fix (using #define so we
285 // can paste this into various other strings below)
286 #define REFERENCE_ACCESS_TOKEN "2:k7j3G6LaL6u_lafw:4iXOeOpTh1glSXe"
287 const char* kNoFixNetworkResponse =
288 "{"
289 " \"location\": null,"
290 " \"access_token\": \"" REFERENCE_ACCESS_TOKEN "\""
291 "}";
292 fetcher->delegate()->OnURLFetchComplete(
293 fetcher, test_server_url_, URLRequestStatus(), 200, // OK
294 ResponseCookies(), kNoFixNetworkResponse);
295
296 // This should have set the access token anyhow
297 EXPECT_EQ(1, static_cast<int>(access_token_store_.token_map_.size()));
298 string16 token;
299 EXPECT_TRUE(access_token_store_.GetAccessToken(test_server_url_, &token));
300 EXPECT_EQ(REFERENCE_ACCESS_TOKEN, UTF16ToUTF8(token));
301
302 Position position;
303 provider->GetPosition(&position);
304 EXPECT_FALSE(position.IsValidFix());
305
306 // Now wifi data arrives
307 const int kFirstScanAps = 6;
308 MockDeviceDataProviderImpl<WifiData>::instance()->SetData(
309 CreateReferenceWifiScanData(kFirstScanAps)); // Will notify listeners
310 fetcher = url_fetcher_factory_.GetFetcherByID(kFirstScanAps);
311 ASSERT_TRUE(fetcher != NULL);
312 // The request should have access token (set previously) and the wifi data.
313 CheckRequestIsValid(fetcher->upload_data(),
314 kFirstScanAps,
315 REFERENCE_ACCESS_TOKEN);
316
317 // Send a reply with good position fix.
318 const char* kReferenceNetworkResponse =
319 "{"
320 " \"location\": {"
321 " \"latitude\": 51.0,"
322 " \"longitude\": -0.1,"
323 " \"altitude\": 30.1,"
324 " \"accuracy\": 1200.4,"
325 " \"altitude_accuracy\": 10.6"
326 " }"
327 "}";
328 fetcher->delegate()->OnURLFetchComplete(
329 fetcher, test_server_url_, URLRequestStatus(), 200, // OK
330 ResponseCookies(), kReferenceNetworkResponse);
331
332 provider->GetPosition(&position);
333 EXPECT_EQ(51.0, position.latitude);
334 EXPECT_EQ(-0.1, position.longitude);
335 EXPECT_EQ(30.1, position.altitude);
336 EXPECT_EQ(1200.4, position.accuracy);
337 EXPECT_EQ(10.6, position.altitude_accuracy);
338 EXPECT_TRUE(position.is_valid_timestamp());
339 EXPECT_TRUE(position.IsValidFix());
340
341 // Token should still be in the store.
342 EXPECT_EQ(1, static_cast<int>(access_token_store_.token_map_.size()));
343 EXPECT_TRUE(access_token_store_.GetAccessToken(test_server_url_, &token));
344 EXPECT_EQ(REFERENCE_ACCESS_TOKEN, UTF16ToUTF8(token));
345
346 // Wifi updated again, with one less AP. This is 'close enough' to the
347 // previous scan, so no new request made.
348 const int kSecondScanAps = kFirstScanAps - 1;
349 MockDeviceDataProviderImpl<WifiData>::instance()->SetData(
350 CreateReferenceWifiScanData(kSecondScanAps));
351 fetcher = url_fetcher_factory_.GetFetcherByID(kSecondScanAps);
352 EXPECT_FALSE(fetcher);
353
354 provider->GetPosition(&position);
355 EXPECT_EQ(51.0, position.latitude);
356 EXPECT_EQ(-0.1, position.longitude);
357 EXPECT_TRUE(position.IsValidFix());
358
359 // Now a third scan with more than twice the original amount -> new request.
360 const int kThirdScanAps = kFirstScanAps * 2 + 1;
361 MockDeviceDataProviderImpl<WifiData>::instance()->SetData(
362 CreateReferenceWifiScanData(kThirdScanAps));
363 fetcher = url_fetcher_factory_.GetFetcherByID(kThirdScanAps);
364 EXPECT_TRUE(fetcher);
365 // ...reply with a network error.
366 fetcher->delegate()->OnURLFetchComplete(
367 fetcher, test_server_url_,
368 URLRequestStatus(URLRequestStatus::FAILED, -1),
369 200, // should be ignored
370 ResponseCookies(), "");
371
372 // Error means we now no longer have a fix.
373 provider->GetPosition(&position);
374 EXPECT_FALSE(position.is_valid_latlong());
375 EXPECT_FALSE(position.IsValidFix());
376
377 // wifi scan returns to original set: should be serviced from cache
378 const TestURLFetcher* orig_fetcher =
379 url_fetcher_factory_.GetFetcherByID(kFirstScanAps);
380 MockDeviceDataProviderImpl<WifiData>::instance()->SetData(
381 CreateReferenceWifiScanData(kFirstScanAps));
382 fetcher = url_fetcher_factory_.GetFetcherByID(kFirstScanAps);
383 EXPECT_EQ(orig_fetcher, fetcher); // No new request created.
384
385 provider->GetPosition(&position);
386 EXPECT_EQ(51.0, position.latitude);
387 EXPECT_EQ(-0.1, position.longitude);
388 EXPECT_TRUE(position.IsValidFix());
389 }
390
391 // TODO(joth): Add tests for corner cases around the 2 second startup delay
392 // (e.g. timer firing, or being pre-empted by data arriving)
OLDNEW
« no previous file with comments | « chrome/browser/geolocation/network_location_provider.cc ('k') | chrome/browser/geolocation/network_location_request.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698