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.
5 #include "base/message_loop/message_loop.h"
6 #include "base/run_loop.h"
7 #include "chromeos/geolocation/simple_geolocation_provider.h"
8 #include "net/http/http_response_headers.h"
9 #include "net/http/http_status_code.h"
10 #include "net/url_request/test_url_fetcher_factory.h"
11 #include "net/url_request/url_fetcher_impl.h"
12 #include "net/url_request/url_request_status.h"
13 #include "testing/gtest/include/gtest/gtest.h"
17 const int kRequestRetryIntervalMilliSeconds
= 200;
19 // This should be different from default to prevent SimpleGeolocationRequest
21 const char kTestGeolocationProviderUrl
[] =
22 "https://localhost/geolocation/v1/geolocate?";
24 const char kSimpleResponseBody
[] =
30 " \"accuracy\": 1200.4\n"
32 } // anonymous namespace
36 // This is helper class for net::FakeURLFetcherFactory.
37 class TestGeolocationAPIURLFetcherCallback
{
39 TestGeolocationAPIURLFetcherCallback(const GURL
& url
,
40 const size_t require_retries
,
41 const std::string
& response
,
42 SimpleGeolocationProvider
* provider
)
44 require_retries_(require_retries
),
48 provider_(provider
) {}
50 scoped_ptr
<net::FakeURLFetcher
> CreateURLFetcher(
52 net::URLFetcherDelegate
* delegate
,
53 const std::string
& response_data
,
54 net::HttpStatusCode response_code
,
55 net::URLRequestStatus::Status status
) {
56 EXPECT_EQ(provider_
->requests_
.size(), 1U);
58 SimpleGeolocationRequest
* geolocation_request
= provider_
->requests_
[0];
60 const base::TimeDelta base_retry_interval
=
61 base::TimeDelta::FromMilliseconds(kRequestRetryIntervalMilliSeconds
);
62 geolocation_request
->set_retry_sleep_on_server_error_for_testing(
64 geolocation_request
->set_retry_sleep_on_bad_response_for_testing(
68 if (attempts_
> require_retries_
) {
69 response_code
= net::HTTP_OK
;
70 status
= net::URLRequestStatus::SUCCESS
;
71 factory_
->SetFakeResponse(url
, response_
, response_code
, status
);
73 scoped_ptr
<net::FakeURLFetcher
> fetcher(new net::FakeURLFetcher(
74 url
, delegate
, response_
, response_code
, status
));
75 scoped_refptr
<net::HttpResponseHeaders
> download_headers
=
76 new net::HttpResponseHeaders(std::string());
77 download_headers
->AddHeader("Content-Type: application/json");
78 fetcher
->set_response_headers(download_headers
);
79 return fetcher
.Pass();
82 void Initialize(net::FakeURLFetcherFactory
* factory
) {
84 factory_
->SetFakeResponse(url_
,
86 net::HTTP_INTERNAL_SERVER_ERROR
,
87 net::URLRequestStatus::FAILED
);
90 size_t attempts() const { return attempts_
; }
94 // Respond with OK on required retry attempt.
95 const size_t require_retries_
;
96 std::string response_
;
97 net::FakeURLFetcherFactory
* factory_
;
99 SimpleGeolocationProvider
* provider_
;
101 DISALLOW_COPY_AND_ASSIGN(TestGeolocationAPIURLFetcherCallback
);
104 // This implements fake Google MAPS Geolocation API remote endpoint.
105 // Response data is served to SimpleGeolocationProvider via
106 // net::FakeURLFetcher.
107 class GeolocationAPIFetcherFactory
{
109 GeolocationAPIFetcherFactory(const GURL
& url
,
110 const std::string
& response
,
111 const size_t require_retries
,
112 SimpleGeolocationProvider
* provider
) {
113 url_callback_
.reset(new TestGeolocationAPIURLFetcherCallback(
114 url
, require_retries
, response
, provider
));
115 net::URLFetcherImpl::set_factory(NULL
);
116 fetcher_factory_
.reset(new net::FakeURLFetcherFactory(
118 base::Bind(&TestGeolocationAPIURLFetcherCallback::CreateURLFetcher
,
119 base::Unretained(url_callback_
.get()))));
120 url_callback_
->Initialize(fetcher_factory_
.get());
123 size_t attempts() const { return url_callback_
->attempts(); }
126 scoped_ptr
<TestGeolocationAPIURLFetcherCallback
> url_callback_
;
127 scoped_ptr
<net::FakeURLFetcherFactory
> fetcher_factory_
;
129 DISALLOW_COPY_AND_ASSIGN(GeolocationAPIFetcherFactory
);
132 class GeolocationReceiver
{
134 GeolocationReceiver() : server_error_(false) {}
136 void OnRequestDone(const Geoposition
& position
,
138 const base::TimeDelta elapsed
) {
139 position_
= position
;
140 server_error_
= server_error
;
143 message_loop_runner_
->Quit();
146 void WaitUntilRequestDone() {
147 message_loop_runner_
.reset(new base::RunLoop
);
148 message_loop_runner_
->Run();
151 const Geoposition
& position() const { return position_
; }
152 bool server_error() const { return server_error_
; }
153 base::TimeDelta
elapsed() const { return elapsed_
; }
156 Geoposition position_
;
158 base::TimeDelta elapsed_
;
159 scoped_ptr
<base::RunLoop
> message_loop_runner_
;
162 class SimpleGeolocationTest
: public testing::Test
{
164 base::MessageLoop message_loop_
;
167 TEST_F(SimpleGeolocationTest
, ResponseOK
) {
168 SimpleGeolocationProvider
provider(NULL
, GURL(kTestGeolocationProviderUrl
));
170 GeolocationAPIFetcherFactory
url_factory(GURL(kTestGeolocationProviderUrl
),
171 std::string(kSimpleResponseBody
),
172 0 /* require_retries */,
175 GeolocationReceiver receiver
;
176 provider
.RequestGeolocation(base::TimeDelta::FromSeconds(1),
177 base::Bind(&GeolocationReceiver::OnRequestDone
,
178 base::Unretained(&receiver
)));
179 receiver
.WaitUntilRequestDone();
182 "latitude=51.000000, longitude=-0.100000, accuracy=1200.400000, "
183 "error_code=0, error_message='', status=1 (OK)",
184 receiver
.position().ToString());
185 EXPECT_FALSE(receiver
.server_error());
186 EXPECT_EQ(1U, url_factory
.attempts());
189 TEST_F(SimpleGeolocationTest
, ResponseOKWithRetries
) {
190 SimpleGeolocationProvider
provider(NULL
, GURL(kTestGeolocationProviderUrl
));
192 GeolocationAPIFetcherFactory
url_factory(GURL(kTestGeolocationProviderUrl
),
193 std::string(kSimpleResponseBody
),
194 3 /* require_retries */,
197 GeolocationReceiver receiver
;
198 provider
.RequestGeolocation(base::TimeDelta::FromSeconds(1),
199 base::Bind(&GeolocationReceiver::OnRequestDone
,
200 base::Unretained(&receiver
)));
201 receiver
.WaitUntilRequestDone();
203 "latitude=51.000000, longitude=-0.100000, accuracy=1200.400000, "
204 "error_code=0, error_message='', status=1 (OK)",
205 receiver
.position().ToString());
206 EXPECT_FALSE(receiver
.server_error());
207 EXPECT_EQ(4U, url_factory
.attempts());
210 TEST_F(SimpleGeolocationTest
, InvalidResponse
) {
211 SimpleGeolocationProvider
provider(NULL
, GURL(kTestGeolocationProviderUrl
));
213 GeolocationAPIFetcherFactory
url_factory(GURL(kTestGeolocationProviderUrl
),
214 "invalid JSON string",
215 0 /* require_retries */,
218 GeolocationReceiver receiver
;
220 const int timeout_seconds
= 1;
221 size_t expected_retries
= static_cast<size_t>(
222 timeout_seconds
* 1000 / kRequestRetryIntervalMilliSeconds
);
223 ASSERT_GE(expected_retries
, 2U);
225 provider
.RequestGeolocation(base::TimeDelta::FromSeconds(timeout_seconds
),
226 base::Bind(&GeolocationReceiver::OnRequestDone
,
227 base::Unretained(&receiver
)));
228 receiver
.WaitUntilRequestDone();
231 "latitude=200.000000, longitude=200.000000, accuracy=-1.000000, "
232 "error_code=0, error_message='SimpleGeolocation provider at "
233 "'https://localhost/' : JSONReader failed: Line: 1, column: 1, "
234 "Unexpected token..', status=4 (TIMEOUT)",
235 receiver
.position().ToString());
236 EXPECT_TRUE(receiver
.server_error());
237 EXPECT_GE(url_factory
.attempts(), 2U);
238 if (url_factory
.attempts() > expected_retries
+ 1) {
240 << "SimpleGeolocationTest::InvalidResponse: Too many attempts ("
241 << url_factory
.attempts() << "), no more then " << expected_retries
+ 1
244 if (url_factory
.attempts() < expected_retries
- 1) {
246 << "SimpleGeolocationTest::InvalidResponse: Too little attempts ("
247 << url_factory
.attempts() << "), greater then " << expected_retries
- 1
252 } // namespace chromeos