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

Side by Side Diff: chrome/browser/google_apis/gdata_wapi_requests_unittest.cc

Issue 96413002: Move c/b/google_apis to google_apis/drive. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase Created 7 years 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) 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 <algorithm>
6 #include <map>
7
8 #include "base/bind.h"
9 #include "base/file_util.h"
10 #include "base/files/file_path.h"
11 #include "base/files/scoped_temp_dir.h"
12 #include "base/json/json_reader.h"
13 #include "base/json/json_writer.h"
14 #include "base/message_loop/message_loop.h"
15 #include "base/run_loop.h"
16 #include "base/strings/string_number_conversions.h"
17 #include "base/strings/stringprintf.h"
18 #include "base/values.h"
19 #include "chrome/browser/google_apis/dummy_auth_service.h"
20 #include "chrome/browser/google_apis/gdata_wapi_parser.h"
21 #include "chrome/browser/google_apis/gdata_wapi_requests.h"
22 #include "chrome/browser/google_apis/gdata_wapi_url_generator.h"
23 #include "chrome/browser/google_apis/request_sender.h"
24 #include "chrome/browser/google_apis/test_util.h"
25 #include "net/base/escape.h"
26 #include "net/test/embedded_test_server/embedded_test_server.h"
27 #include "net/test/embedded_test_server/http_request.h"
28 #include "net/test/embedded_test_server/http_response.h"
29 #include "net/url_request/url_request_test_util.h"
30 #include "testing/gtest/include/gtest/gtest.h"
31
32 namespace google_apis {
33
34 namespace {
35
36 const char kTestUserAgent[] = "test-user-agent";
37 const char kTestETag[] = "test_etag";
38 const char kTestDownloadPathPrefix[] = "/download/";
39
40 class GDataWapiRequestsTest : public testing::Test {
41 public:
42 GDataWapiRequestsTest() {
43 }
44
45 virtual void SetUp() OVERRIDE {
46 request_context_getter_ = new net::TestURLRequestContextGetter(
47 message_loop_.message_loop_proxy());
48
49 request_sender_.reset(new RequestSender(new DummyAuthService,
50 request_context_getter_.get(),
51 message_loop_.message_loop_proxy(),
52 kTestUserAgent));
53
54 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
55
56 ASSERT_TRUE(test_server_.InitializeAndWaitUntilReady());
57 test_server_.RegisterRequestHandler(
58 base::Bind(&test_util::HandleDownloadFileRequest,
59 test_server_.base_url(),
60 base::Unretained(&http_request_)));
61 test_server_.RegisterRequestHandler(
62 base::Bind(&GDataWapiRequestsTest::HandleResourceFeedRequest,
63 base::Unretained(this)));
64 test_server_.RegisterRequestHandler(
65 base::Bind(&GDataWapiRequestsTest::HandleMetadataRequest,
66 base::Unretained(this)));
67 test_server_.RegisterRequestHandler(
68 base::Bind(&GDataWapiRequestsTest::HandleCreateSessionRequest,
69 base::Unretained(this)));
70 test_server_.RegisterRequestHandler(
71 base::Bind(&GDataWapiRequestsTest::HandleUploadRequest,
72 base::Unretained(this)));
73 test_server_.RegisterRequestHandler(
74 base::Bind(&GDataWapiRequestsTest::HandleDownloadRequest,
75 base::Unretained(this)));
76
77 GURL test_base_url = test_util::GetBaseUrlForTesting(test_server_.port());
78 url_generator_.reset(new GDataWapiUrlGenerator(
79 test_base_url, test_base_url.Resolve(kTestDownloadPathPrefix)));
80
81 received_bytes_ = 0;
82 content_length_ = 0;
83 }
84
85 protected:
86 // Handles a request for fetching a resource feed.
87 scoped_ptr<net::test_server::HttpResponse> HandleResourceFeedRequest(
88 const net::test_server::HttpRequest& request) {
89 http_request_ = request;
90
91 const GURL absolute_url = test_server_.GetURL(request.relative_url);
92 std::string remaining_path;
93 if (absolute_url.path() == "/feeds/default/private/full" &&
94 request.method == net::test_server::METHOD_POST) {
95 // This is a request for copying a document.
96 // TODO(satorux): we should generate valid JSON data for the newly
97 // copied document but for now, just return "file_entry.json"
98 scoped_ptr<net::test_server::BasicHttpResponse> result(
99 test_util::CreateHttpResponseFromFile(
100 test_util::GetTestFilePath("gdata/file_entry.json")));
101 return result.PassAs<net::test_server::HttpResponse>();
102 }
103
104 if (!test_util::RemovePrefix(absolute_url.path(),
105 "/feeds/default/private/full",
106 &remaining_path)) {
107 return scoped_ptr<net::test_server::HttpResponse>();
108 }
109
110 if (remaining_path.empty()) {
111 // Process the default feed.
112 scoped_ptr<net::test_server::BasicHttpResponse> result(
113 test_util::CreateHttpResponseFromFile(
114 test_util::GetTestFilePath("gdata/root_feed.json")));
115 return result.PassAs<net::test_server::HttpResponse>();
116 } else {
117 // Process a feed for a single resource ID.
118 const std::string resource_id = net::UnescapeURLComponent(
119 remaining_path.substr(1), net::UnescapeRule::URL_SPECIAL_CHARS);
120 if (resource_id == "file:2_file_resource_id") {
121 scoped_ptr<net::test_server::BasicHttpResponse> result(
122 test_util::CreateHttpResponseFromFile(
123 test_util::GetTestFilePath("gdata/file_entry.json")));
124 return result.PassAs<net::test_server::HttpResponse>();
125 } else if (resource_id == "folder:root/contents" &&
126 request.method == net::test_server::METHOD_POST) {
127 // This is a request for creating a directory in the root directory.
128 // TODO(satorux): we should generate valid JSON data for the newly
129 // created directory but for now, just return "directory_entry.json"
130 scoped_ptr<net::test_server::BasicHttpResponse> result(
131 test_util::CreateHttpResponseFromFile(
132 test_util::GetTestFilePath(
133 "gdata/directory_entry.json")));
134 return result.PassAs<net::test_server::HttpResponse>();
135 } else if (resource_id ==
136 "folder:root/contents/file:2_file_resource_id" &&
137 request.method == net::test_server::METHOD_DELETE) {
138 // This is a request for deleting a file from the root directory.
139 // TODO(satorux): Investigate what's returned from the server, and
140 // copy it. For now, just return a random file, as the contents don't
141 // matter.
142 scoped_ptr<net::test_server::BasicHttpResponse> result(
143 test_util::CreateHttpResponseFromFile(
144 test_util::GetTestFilePath("gdata/testfile.txt")));
145 return result.PassAs<net::test_server::HttpResponse>();
146 } else if (resource_id == "invalid_resource_id") {
147 // Check if this is an authorization request for an app.
148 // This emulates to return invalid formatted result from the server.
149 if (request.method == net::test_server::METHOD_PUT &&
150 request.content.find("<docs:authorizedApp>") != std::string::npos) {
151 scoped_ptr<net::test_server::BasicHttpResponse> result(
152 test_util::CreateHttpResponseFromFile(
153 test_util::GetTestFilePath("gdata/testfile.txt")));
154 return result.PassAs<net::test_server::HttpResponse>();
155 }
156 }
157 }
158
159 return scoped_ptr<net::test_server::HttpResponse>();
160 }
161
162 // Handles a request for fetching a metadata feed.
163 scoped_ptr<net::test_server::HttpResponse> HandleMetadataRequest(
164 const net::test_server::HttpRequest& request) {
165 http_request_ = request;
166
167 const GURL absolute_url = test_server_.GetURL(request.relative_url);
168 if (absolute_url.path() != "/feeds/metadata/default")
169 return scoped_ptr<net::test_server::HttpResponse>();
170
171 scoped_ptr<net::test_server::BasicHttpResponse> result(
172 test_util::CreateHttpResponseFromFile(
173 test_util::GetTestFilePath(
174 "gdata/account_metadata.json")));
175 if (absolute_url.query().find("include-installed-apps=true") ==
176 string::npos) {
177 // Exclude the list of installed apps.
178 scoped_ptr<base::Value> parsed_content(
179 base::JSONReader::Read(result->content(), base::JSON_PARSE_RFC));
180 CHECK(parsed_content);
181
182 // Remove the install apps node.
183 base::DictionaryValue* dictionary_value;
184 CHECK(parsed_content->GetAsDictionary(&dictionary_value));
185 dictionary_value->Remove("entry.docs$installedApp", NULL);
186
187 // Write back it as the content of the result.
188 std::string content;
189 base::JSONWriter::Write(parsed_content.get(), &content);
190 result->set_content(content);
191 }
192
193 return result.PassAs<net::test_server::HttpResponse>();
194 }
195
196 // Handles a request for creating a session for uploading.
197 scoped_ptr<net::test_server::HttpResponse> HandleCreateSessionRequest(
198 const net::test_server::HttpRequest& request) {
199 http_request_ = request;
200
201 const GURL absolute_url = test_server_.GetURL(request.relative_url);
202 if (StartsWithASCII(absolute_url.path(),
203 "/feeds/upload/create-session/default/private/full",
204 true)) { // case sensitive
205 // This is an initiating upload URL.
206 scoped_ptr<net::test_server::BasicHttpResponse> http_response(
207 new net::test_server::BasicHttpResponse);
208
209 // Check an ETag.
210 std::map<std::string, std::string>::const_iterator found =
211 request.headers.find("If-Match");
212 if (found != request.headers.end() &&
213 found->second != "*" &&
214 found->second != kTestETag) {
215 http_response->set_code(net::HTTP_PRECONDITION_FAILED);
216 return http_response.PassAs<net::test_server::HttpResponse>();
217 }
218
219 // Check if the X-Upload-Content-Length is present. If yes, store the
220 // length of the file.
221 found = request.headers.find("X-Upload-Content-Length");
222 if (found == request.headers.end() ||
223 !base::StringToInt64(found->second, &content_length_)) {
224 return scoped_ptr<net::test_server::HttpResponse>();
225 }
226 received_bytes_ = 0;
227
228 http_response->set_code(net::HTTP_OK);
229 GURL upload_url;
230 // POST is used for a new file, and PUT is used for an existing file.
231 if (request.method == net::test_server::METHOD_POST) {
232 upload_url = test_server_.GetURL("/upload_new_file");
233 } else if (request.method == net::test_server::METHOD_PUT) {
234 upload_url = test_server_.GetURL("/upload_existing_file");
235 } else {
236 return scoped_ptr<net::test_server::HttpResponse>();
237 }
238 http_response->AddCustomHeader("Location", upload_url.spec());
239 return http_response.PassAs<net::test_server::HttpResponse>();
240 }
241
242 return scoped_ptr<net::test_server::HttpResponse>();
243 }
244
245 // Handles a request for uploading content.
246 scoped_ptr<net::test_server::HttpResponse> HandleUploadRequest(
247 const net::test_server::HttpRequest& request) {
248 http_request_ = request;
249
250 const GURL absolute_url = test_server_.GetURL(request.relative_url);
251 if (absolute_url.path() != "/upload_new_file" &&
252 absolute_url.path() != "/upload_existing_file") {
253 return scoped_ptr<net::test_server::HttpResponse>();
254 }
255
256 // TODO(satorux): We should create a correct JSON data for the uploaded
257 // file, but for now, just return file_entry.json.
258 scoped_ptr<net::test_server::BasicHttpResponse> response =
259 test_util::CreateHttpResponseFromFile(
260 test_util::GetTestFilePath("gdata/file_entry.json"));
261 // response.code() is set to SUCCESS. Change it to CREATED if it's a new
262 // file.
263 if (absolute_url.path() == "/upload_new_file")
264 response->set_code(net::HTTP_CREATED);
265
266 // Check if the Content-Range header is present. This must be present if
267 // the request body is not empty.
268 if (!request.content.empty()) {
269 std::map<std::string, std::string>::const_iterator iter =
270 request.headers.find("Content-Range");
271 if (iter == request.headers.end())
272 return scoped_ptr<net::test_server::HttpResponse>();
273 int64 length = 0;
274 int64 start_position = 0;
275 int64 end_position = 0;
276 if (!test_util::ParseContentRangeHeader(iter->second,
277 &start_position,
278 &end_position,
279 &length)) {
280 return scoped_ptr<net::test_server::HttpResponse>();
281 }
282 EXPECT_EQ(start_position, received_bytes_);
283 EXPECT_EQ(length, content_length_);
284 // end_position is inclusive, but so +1 to change the range to byte size.
285 received_bytes_ = end_position + 1;
286 }
287
288 // Add Range header to the response, based on the values of
289 // Content-Range header in the request.
290 // The header is annotated only when at least one byte is received.
291 if (received_bytes_ > 0) {
292 response->AddCustomHeader(
293 "Range",
294 "bytes=0-" + base::Int64ToString(received_bytes_ - 1));
295 }
296
297 // Change the code to RESUME_INCOMPLETE if upload is not complete.
298 if (received_bytes_ < content_length_)
299 response->set_code(static_cast<net::HttpStatusCode>(308));
300
301 return response.PassAs<net::test_server::HttpResponse>();
302 }
303
304 // Handles a request for downloading a file.
305 scoped_ptr<net::test_server::HttpResponse> HandleDownloadRequest(
306 const net::test_server::HttpRequest& request) {
307 http_request_ = request;
308
309 const GURL absolute_url = test_server_.GetURL(request.relative_url);
310 std::string id;
311 if (!test_util::RemovePrefix(absolute_url.path(),
312 kTestDownloadPathPrefix,
313 &id)) {
314 return scoped_ptr<net::test_server::HttpResponse>();
315 }
316
317 // For testing, returns a text with |id| repeated 3 times.
318 scoped_ptr<net::test_server::BasicHttpResponse> response(
319 new net::test_server::BasicHttpResponse);
320 response->set_code(net::HTTP_OK);
321 response->set_content(id + id + id);
322 response->set_content_type("text/plain");
323 return response.PassAs<net::test_server::HttpResponse>();
324 }
325
326 base::MessageLoopForIO message_loop_; // Test server needs IO thread.
327 net::test_server::EmbeddedTestServer test_server_;
328 scoped_ptr<RequestSender> request_sender_;
329 scoped_ptr<GDataWapiUrlGenerator> url_generator_;
330 scoped_refptr<net::TestURLRequestContextGetter> request_context_getter_;
331 base::ScopedTempDir temp_dir_;
332
333 // These fields are used to keep the current upload state during a
334 // test case. These values are updated by the request from
335 // ResumeUploadRequest, and used to construct the response for
336 // both ResumeUploadRequest and GetUploadStatusRequest, to emulate
337 // the WAPI server.
338 int64 received_bytes_;
339 int64 content_length_;
340
341 // The incoming HTTP request is saved so tests can verify the request
342 // parameters like HTTP method (ex. some requests should use DELETE
343 // instead of GET).
344 net::test_server::HttpRequest http_request_;
345 };
346
347 } // namespace
348
349 TEST_F(GDataWapiRequestsTest, GetResourceListRequest_DefaultFeed) {
350 GDataErrorCode result_code = GDATA_OTHER_ERROR;
351 scoped_ptr<ResourceList> result_data;
352
353 {
354 base::RunLoop run_loop;
355 GetResourceListRequest* request = new GetResourceListRequest(
356 request_sender_.get(),
357 *url_generator_,
358 GURL(), // Pass an empty URL to use the default feed
359 0, // start changestamp
360 std::string(), // search string
361 std::string(), // directory resource ID
362 test_util::CreateQuitCallback(
363 &run_loop,
364 test_util::CreateCopyResultCallback(&result_code, &result_data)));
365 request_sender_->StartRequestWithRetry(request);
366 run_loop.Run();
367 }
368
369 EXPECT_EQ(HTTP_SUCCESS, result_code);
370 EXPECT_EQ(net::test_server::METHOD_GET, http_request_.method);
371 EXPECT_EQ("/feeds/default/private/full?v=3&alt=json&showroot=true&"
372 "showfolders=true&include-shared=true&max-results=500",
373 http_request_.relative_url);
374
375 // Sanity check of the result.
376 scoped_ptr<ResourceList> expected(
377 ResourceList::ExtractAndParse(
378 *test_util::LoadJSONFile("gdata/root_feed.json")));
379 ASSERT_TRUE(result_data);
380 EXPECT_EQ(expected->title(), result_data->title());
381 }
382
383 TEST_F(GDataWapiRequestsTest, GetResourceListRequest_ValidFeed) {
384 GDataErrorCode result_code = GDATA_OTHER_ERROR;
385 scoped_ptr<ResourceList> result_data;
386
387 {
388 base::RunLoop run_loop;
389 GetResourceListRequest* request = new GetResourceListRequest(
390 request_sender_.get(),
391 *url_generator_,
392 test_server_.GetURL("/files/gdata/root_feed.json"),
393 0, // start changestamp
394 std::string(), // search string
395 std::string(), // directory resource ID
396 test_util::CreateQuitCallback(
397 &run_loop,
398 test_util::CreateCopyResultCallback(&result_code, &result_data)));
399 request_sender_->StartRequestWithRetry(request);
400 run_loop.Run();
401 }
402
403 EXPECT_EQ(HTTP_SUCCESS, result_code);
404 EXPECT_EQ(net::test_server::METHOD_GET, http_request_.method);
405 EXPECT_EQ("/files/gdata/root_feed.json?v=3&alt=json&showroot=true&"
406 "showfolders=true&include-shared=true&max-results=500",
407 http_request_.relative_url);
408
409 scoped_ptr<ResourceList> expected(
410 ResourceList::ExtractAndParse(
411 *test_util::LoadJSONFile("gdata/root_feed.json")));
412 ASSERT_TRUE(result_data);
413 EXPECT_EQ(expected->title(), result_data->title());
414 }
415
416 TEST_F(GDataWapiRequestsTest, GetResourceListRequest_InvalidFeed) {
417 // testfile.txt exists but the response is not JSON, so it should
418 // emit a parse error instead.
419 GDataErrorCode result_code = GDATA_OTHER_ERROR;
420 scoped_ptr<ResourceList> result_data;
421
422 {
423 base::RunLoop run_loop;
424 GetResourceListRequest* request = new GetResourceListRequest(
425 request_sender_.get(),
426 *url_generator_,
427 test_server_.GetURL("/files/gdata/testfile.txt"),
428 0, // start changestamp
429 std::string(), // search string
430 std::string(), // directory resource ID
431 test_util::CreateQuitCallback(
432 &run_loop,
433 test_util::CreateCopyResultCallback(&result_code, &result_data)));
434 request_sender_->StartRequestWithRetry(request);
435 run_loop.Run();
436 }
437
438 EXPECT_EQ(GDATA_PARSE_ERROR, result_code);
439 EXPECT_EQ(net::test_server::METHOD_GET, http_request_.method);
440 EXPECT_EQ("/files/gdata/testfile.txt?v=3&alt=json&showroot=true&"
441 "showfolders=true&include-shared=true&max-results=500",
442 http_request_.relative_url);
443 EXPECT_FALSE(result_data);
444 }
445
446 TEST_F(GDataWapiRequestsTest, SearchByTitleRequest) {
447 GDataErrorCode result_code = GDATA_OTHER_ERROR;
448 scoped_ptr<ResourceList> result_data;
449
450 {
451 base::RunLoop run_loop;
452 SearchByTitleRequest* request = new SearchByTitleRequest(
453 request_sender_.get(),
454 *url_generator_,
455 "search-title",
456 std::string(), // directory resource id
457 test_util::CreateQuitCallback(
458 &run_loop,
459 test_util::CreateCopyResultCallback(&result_code, &result_data)));
460 request_sender_->StartRequestWithRetry(request);
461 run_loop.Run();
462 }
463
464 EXPECT_EQ(HTTP_SUCCESS, result_code);
465 EXPECT_EQ(net::test_server::METHOD_GET, http_request_.method);
466 EXPECT_EQ("/feeds/default/private/full?v=3&alt=json&showroot=true&"
467 "showfolders=true&include-shared=true&max-results=500"
468 "&title=search-title&title-exact=true",
469 http_request_.relative_url);
470 EXPECT_TRUE(result_data);
471 }
472
473 TEST_F(GDataWapiRequestsTest, GetResourceEntryRequest_ValidResourceId) {
474 GDataErrorCode result_code = GDATA_OTHER_ERROR;
475 scoped_ptr<base::Value> result_data;
476
477 {
478 base::RunLoop run_loop;
479 GetResourceEntryRequest* request = new GetResourceEntryRequest(
480 request_sender_.get(),
481 *url_generator_,
482 "file:2_file_resource_id", // resource ID
483 GURL(), // embed origin
484 test_util::CreateQuitCallback(
485 &run_loop,
486 test_util::CreateCopyResultCallback(&result_code, &result_data)));
487 request_sender_->StartRequestWithRetry(request);
488 run_loop.Run();
489 }
490
491 EXPECT_EQ(HTTP_SUCCESS, result_code);
492 EXPECT_EQ(net::test_server::METHOD_GET, http_request_.method);
493 EXPECT_EQ("/feeds/default/private/full/file%3A2_file_resource_id"
494 "?v=3&alt=json&showroot=true",
495 http_request_.relative_url);
496 scoped_ptr<base::Value> expected_json =
497 test_util::LoadJSONFile("gdata/file_entry.json");
498 ASSERT_TRUE(expected_json);
499 EXPECT_TRUE(result_data);
500 EXPECT_TRUE(base::Value::Equals(expected_json.get(), result_data.get()));
501 }
502
503 TEST_F(GDataWapiRequestsTest, GetResourceEntryRequest_InvalidResourceId) {
504 GDataErrorCode result_code = GDATA_OTHER_ERROR;
505 scoped_ptr<base::Value> result_data;
506
507 {
508 base::RunLoop run_loop;
509 GetResourceEntryRequest* request = new GetResourceEntryRequest(
510 request_sender_.get(),
511 *url_generator_,
512 "<invalid>", // resource ID
513 GURL(), // embed origin
514 test_util::CreateQuitCallback(
515 &run_loop,
516 test_util::CreateCopyResultCallback(&result_code, &result_data)));
517 request_sender_->StartRequestWithRetry(request);
518 run_loop.Run();
519 }
520
521 EXPECT_EQ(HTTP_NOT_FOUND, result_code);
522 EXPECT_EQ(net::test_server::METHOD_GET, http_request_.method);
523 EXPECT_EQ("/feeds/default/private/full/%3Cinvalid%3E?v=3&alt=json"
524 "&showroot=true",
525 http_request_.relative_url);
526 ASSERT_FALSE(result_data);
527 }
528
529 TEST_F(GDataWapiRequestsTest, GetAccountMetadataRequest) {
530 GDataErrorCode result_code = GDATA_OTHER_ERROR;
531 scoped_ptr<AccountMetadata> result_data;
532
533 {
534 base::RunLoop run_loop;
535 GetAccountMetadataRequest* request = new GetAccountMetadataRequest(
536 request_sender_.get(),
537 *url_generator_,
538 test_util::CreateQuitCallback(
539 &run_loop,
540 test_util::CreateCopyResultCallback(&result_code, &result_data)),
541 true); // Include installed apps.
542 request_sender_->StartRequestWithRetry(request);
543 run_loop.Run();
544 }
545
546 EXPECT_EQ(HTTP_SUCCESS, result_code);
547 EXPECT_EQ(net::test_server::METHOD_GET, http_request_.method);
548 EXPECT_EQ("/feeds/metadata/default?v=3&alt=json&showroot=true"
549 "&include-installed-apps=true",
550 http_request_.relative_url);
551
552 scoped_ptr<AccountMetadata> expected(
553 AccountMetadata::CreateFrom(
554 *test_util::LoadJSONFile("gdata/account_metadata.json")));
555
556 ASSERT_TRUE(result_data.get());
557 EXPECT_EQ(expected->largest_changestamp(),
558 result_data->largest_changestamp());
559 EXPECT_EQ(expected->quota_bytes_total(),
560 result_data->quota_bytes_total());
561 EXPECT_EQ(expected->quota_bytes_used(),
562 result_data->quota_bytes_used());
563
564 // Sanity check for installed apps.
565 EXPECT_EQ(expected->installed_apps().size(),
566 result_data->installed_apps().size());
567 }
568
569 TEST_F(GDataWapiRequestsTest,
570 GetAccountMetadataRequestWithoutInstalledApps) {
571 GDataErrorCode result_code = GDATA_OTHER_ERROR;
572 scoped_ptr<AccountMetadata> result_data;
573
574 {
575 base::RunLoop run_loop;
576 GetAccountMetadataRequest* request = new GetAccountMetadataRequest(
577 request_sender_.get(),
578 *url_generator_,
579 test_util::CreateQuitCallback(
580 &run_loop,
581 test_util::CreateCopyResultCallback(&result_code, &result_data)),
582 false); // Exclude installed apps.
583 request_sender_->StartRequestWithRetry(request);
584 run_loop.Run();
585 }
586
587 EXPECT_EQ(HTTP_SUCCESS, result_code);
588 EXPECT_EQ(net::test_server::METHOD_GET, http_request_.method);
589 EXPECT_EQ("/feeds/metadata/default?v=3&alt=json&showroot=true",
590 http_request_.relative_url);
591
592 scoped_ptr<AccountMetadata> expected(
593 AccountMetadata::CreateFrom(
594 *test_util::LoadJSONFile("gdata/account_metadata.json")));
595
596 ASSERT_TRUE(result_data.get());
597 EXPECT_EQ(expected->largest_changestamp(),
598 result_data->largest_changestamp());
599 EXPECT_EQ(expected->quota_bytes_total(),
600 result_data->quota_bytes_total());
601 EXPECT_EQ(expected->quota_bytes_used(),
602 result_data->quota_bytes_used());
603
604 // Installed apps shouldn't be included.
605 EXPECT_EQ(0U, result_data->installed_apps().size());
606 }
607
608 TEST_F(GDataWapiRequestsTest, DeleteResourceRequest) {
609 GDataErrorCode result_code = GDATA_OTHER_ERROR;
610
611 {
612 base::RunLoop run_loop;
613 DeleteResourceRequest* request = new DeleteResourceRequest(
614 request_sender_.get(),
615 *url_generator_,
616 test_util::CreateQuitCallback(
617 &run_loop,
618 test_util::CreateCopyResultCallback(&result_code)),
619 "file:2_file_resource_id",
620 std::string());
621
622 request_sender_->StartRequestWithRetry(request);
623 run_loop.Run();
624 }
625
626 EXPECT_EQ(HTTP_SUCCESS, result_code);
627 EXPECT_EQ(net::test_server::METHOD_DELETE, http_request_.method);
628 EXPECT_EQ(
629 "/feeds/default/private/full/file%3A2_file_resource_id?v=3&alt=json"
630 "&showroot=true",
631 http_request_.relative_url);
632 EXPECT_EQ("*", http_request_.headers["If-Match"]);
633 }
634
635 TEST_F(GDataWapiRequestsTest, DeleteResourceRequestWithETag) {
636 GDataErrorCode result_code = GDATA_OTHER_ERROR;
637
638 {
639 base::RunLoop run_loop;
640 DeleteResourceRequest* request = new DeleteResourceRequest(
641 request_sender_.get(),
642 *url_generator_,
643 test_util::CreateQuitCallback(
644 &run_loop,
645 test_util::CreateCopyResultCallback(&result_code)),
646 "file:2_file_resource_id",
647 "etag");
648
649 request_sender_->StartRequestWithRetry(request);
650 run_loop.Run();
651 }
652
653 EXPECT_EQ(HTTP_SUCCESS, result_code);
654 EXPECT_EQ(net::test_server::METHOD_DELETE, http_request_.method);
655 EXPECT_EQ(
656 "/feeds/default/private/full/file%3A2_file_resource_id?v=3&alt=json"
657 "&showroot=true",
658 http_request_.relative_url);
659 EXPECT_EQ("etag", http_request_.headers["If-Match"]);
660 }
661
662 TEST_F(GDataWapiRequestsTest, CreateDirectoryRequest) {
663 GDataErrorCode result_code = GDATA_OTHER_ERROR;
664 scoped_ptr<base::Value> result_data;
665
666 // Create "new directory" in the root directory.
667 {
668 base::RunLoop run_loop;
669 CreateDirectoryRequest* request = new CreateDirectoryRequest(
670 request_sender_.get(),
671 *url_generator_,
672 test_util::CreateQuitCallback(
673 &run_loop,
674 test_util::CreateCopyResultCallback(&result_code, &result_data)),
675 "folder:root",
676 "new directory");
677
678 request_sender_->StartRequestWithRetry(request);
679 run_loop.Run();
680 }
681
682 EXPECT_EQ(HTTP_SUCCESS, result_code);
683 EXPECT_EQ(net::test_server::METHOD_POST, http_request_.method);
684 EXPECT_EQ("/feeds/default/private/full/folder%3Aroot/contents?v=3&alt=json"
685 "&showroot=true",
686 http_request_.relative_url);
687 EXPECT_EQ("application/atom+xml", http_request_.headers["Content-Type"]);
688
689 EXPECT_TRUE(http_request_.has_content);
690 EXPECT_EQ("<?xml version=\"1.0\"?>\n"
691 "<entry xmlns=\"http://www.w3.org/2005/Atom\">\n"
692 " <category scheme=\"http://schemas.google.com/g/2005#kind\" "
693 "term=\"http://schemas.google.com/docs/2007#folder\"/>\n"
694 " <title>new directory</title>\n"
695 "</entry>\n",
696 http_request_.content);
697 }
698
699 TEST_F(GDataWapiRequestsTest, CopyHostedDocumentRequest) {
700 GDataErrorCode result_code = GDATA_OTHER_ERROR;
701 scoped_ptr<base::Value> result_data;
702
703 // Copy a document with a new name "New Document".
704 {
705 base::RunLoop run_loop;
706 CopyHostedDocumentRequest* request = new CopyHostedDocumentRequest(
707 request_sender_.get(),
708 *url_generator_,
709 test_util::CreateQuitCallback(
710 &run_loop,
711 test_util::CreateCopyResultCallback(&result_code, &result_data)),
712 "document:5_document_resource_id", // source resource ID
713 "New Document");
714
715 request_sender_->StartRequestWithRetry(request);
716 run_loop.Run();
717 }
718
719 EXPECT_EQ(HTTP_SUCCESS, result_code);
720 EXPECT_EQ(net::test_server::METHOD_POST, http_request_.method);
721 EXPECT_EQ("/feeds/default/private/full?v=3&alt=json&showroot=true",
722 http_request_.relative_url);
723 EXPECT_EQ("application/atom+xml", http_request_.headers["Content-Type"]);
724
725 EXPECT_TRUE(http_request_.has_content);
726 EXPECT_EQ("<?xml version=\"1.0\"?>\n"
727 "<entry xmlns=\"http://www.w3.org/2005/Atom\">\n"
728 " <id>document:5_document_resource_id</id>\n"
729 " <title>New Document</title>\n"
730 "</entry>\n",
731 http_request_.content);
732 }
733
734 TEST_F(GDataWapiRequestsTest, RenameResourceRequest) {
735 GDataErrorCode result_code = GDATA_OTHER_ERROR;
736
737 // Rename a file with a new name "New File".
738 {
739 base::RunLoop run_loop;
740 RenameResourceRequest* request = new RenameResourceRequest(
741 request_sender_.get(),
742 *url_generator_,
743 test_util::CreateQuitCallback(
744 &run_loop,
745 test_util::CreateCopyResultCallback(&result_code)),
746 "file:2_file_resource_id",
747 "New File");
748
749 request_sender_->StartRequestWithRetry(request);
750 run_loop.Run();
751 }
752
753 EXPECT_EQ(HTTP_SUCCESS, result_code);
754 EXPECT_EQ(net::test_server::METHOD_PUT, http_request_.method);
755 EXPECT_EQ(
756 "/feeds/default/private/full/file%3A2_file_resource_id?v=3&alt=json"
757 "&showroot=true",
758 http_request_.relative_url);
759 EXPECT_EQ("application/atom+xml", http_request_.headers["Content-Type"]);
760 EXPECT_EQ("*", http_request_.headers["If-Match"]);
761
762 EXPECT_TRUE(http_request_.has_content);
763 EXPECT_EQ("<?xml version=\"1.0\"?>\n"
764 "<entry xmlns=\"http://www.w3.org/2005/Atom\">\n"
765 " <title>New File</title>\n"
766 "</entry>\n",
767 http_request_.content);
768 }
769
770 TEST_F(GDataWapiRequestsTest, AuthorizeAppRequest_ValidFeed) {
771 GDataErrorCode result_code = GDATA_OTHER_ERROR;
772 GURL result_data;
773
774 // Authorize an app with APP_ID to access to a document.
775 {
776 base::RunLoop run_loop;
777 AuthorizeAppRequest* request = new AuthorizeAppRequest(
778 request_sender_.get(),
779 *url_generator_,
780 test_util::CreateQuitCallback(
781 &run_loop,
782 test_util::CreateCopyResultCallback(&result_code, &result_data)),
783 "file:2_file_resource_id",
784 "the_app_id");
785
786 request_sender_->StartRequestWithRetry(request);
787 run_loop.Run();
788 }
789
790 EXPECT_EQ(HTTP_SUCCESS, result_code);
791 EXPECT_EQ(GURL("https://entry1_open_with_link/"), result_data);
792
793 EXPECT_EQ(net::test_server::METHOD_PUT, http_request_.method);
794 EXPECT_EQ("/feeds/default/private/full/file%3A2_file_resource_id"
795 "?v=3&alt=json&showroot=true",
796 http_request_.relative_url);
797 EXPECT_EQ("application/atom+xml", http_request_.headers["Content-Type"]);
798 EXPECT_EQ("*", http_request_.headers["If-Match"]);
799
800 EXPECT_TRUE(http_request_.has_content);
801 EXPECT_EQ("<?xml version=\"1.0\"?>\n"
802 "<entry xmlns=\"http://www.w3.org/2005/Atom\" "
803 "xmlns:docs=\"http://schemas.google.com/docs/2007\">\n"
804 " <docs:authorizedApp>the_app_id</docs:authorizedApp>\n"
805 "</entry>\n",
806 http_request_.content);
807 }
808
809 TEST_F(GDataWapiRequestsTest, AuthorizeAppRequest_NotFound) {
810 GDataErrorCode result_code = GDATA_OTHER_ERROR;
811 GURL result_data;
812
813 // Authorize an app with APP_ID to access to a document.
814 {
815 base::RunLoop run_loop;
816 AuthorizeAppRequest* request = new AuthorizeAppRequest(
817 request_sender_.get(),
818 *url_generator_,
819 test_util::CreateQuitCallback(
820 &run_loop,
821 test_util::CreateCopyResultCallback(&result_code, &result_data)),
822 "file:2_file_resource_id",
823 "unauthorized_app_id");
824
825 request_sender_->StartRequestWithRetry(request);
826 run_loop.Run();
827 }
828
829 EXPECT_EQ(GDATA_OTHER_ERROR, result_code);
830 EXPECT_EQ(net::test_server::METHOD_PUT, http_request_.method);
831 EXPECT_EQ("/feeds/default/private/full/file%3A2_file_resource_id"
832 "?v=3&alt=json&showroot=true",
833 http_request_.relative_url);
834 EXPECT_EQ("application/atom+xml", http_request_.headers["Content-Type"]);
835 EXPECT_EQ("*", http_request_.headers["If-Match"]);
836
837 EXPECT_TRUE(http_request_.has_content);
838 EXPECT_EQ("<?xml version=\"1.0\"?>\n"
839 "<entry xmlns=\"http://www.w3.org/2005/Atom\" "
840 "xmlns:docs=\"http://schemas.google.com/docs/2007\">\n"
841 " <docs:authorizedApp>unauthorized_app_id</docs:authorizedApp>\n"
842 "</entry>\n",
843 http_request_.content);
844 }
845
846 TEST_F(GDataWapiRequestsTest, AuthorizeAppRequest_InvalidFeed) {
847 GDataErrorCode result_code = GDATA_OTHER_ERROR;
848 GURL result_data;
849
850 // Authorize an app with APP_ID to access to a document but an invalid feed.
851 {
852 base::RunLoop run_loop;
853 AuthorizeAppRequest* request = new AuthorizeAppRequest(
854 request_sender_.get(),
855 *url_generator_,
856 test_util::CreateQuitCallback(
857 &run_loop,
858 test_util::CreateCopyResultCallback(&result_code, &result_data)),
859 "invalid_resource_id",
860 "APP_ID");
861
862 request_sender_->StartRequestWithRetry(request);
863 run_loop.Run();
864 }
865
866 EXPECT_EQ(GDATA_PARSE_ERROR, result_code);
867 EXPECT_EQ(net::test_server::METHOD_PUT, http_request_.method);
868 EXPECT_EQ("/feeds/default/private/full/invalid_resource_id"
869 "?v=3&alt=json&showroot=true",
870 http_request_.relative_url);
871 EXPECT_EQ("application/atom+xml", http_request_.headers["Content-Type"]);
872 EXPECT_EQ("*", http_request_.headers["If-Match"]);
873
874 EXPECT_TRUE(http_request_.has_content);
875 EXPECT_EQ("<?xml version=\"1.0\"?>\n"
876 "<entry xmlns=\"http://www.w3.org/2005/Atom\" "
877 "xmlns:docs=\"http://schemas.google.com/docs/2007\">\n"
878 " <docs:authorizedApp>APP_ID</docs:authorizedApp>\n"
879 "</entry>\n",
880 http_request_.content);
881 }
882
883 TEST_F(GDataWapiRequestsTest, AddResourceToDirectoryRequest) {
884 GDataErrorCode result_code = GDATA_OTHER_ERROR;
885
886 // Add a file to the root directory.
887 {
888 base::RunLoop run_loop;
889 AddResourceToDirectoryRequest* request =
890 new AddResourceToDirectoryRequest(
891 request_sender_.get(),
892 *url_generator_,
893 test_util::CreateQuitCallback(
894 &run_loop,
895 test_util::CreateCopyResultCallback(&result_code)),
896 "folder:root",
897 "file:2_file_resource_id");
898
899 request_sender_->StartRequestWithRetry(request);
900 run_loop.Run();
901 }
902
903 EXPECT_EQ(HTTP_SUCCESS, result_code);
904 EXPECT_EQ(net::test_server::METHOD_POST, http_request_.method);
905 EXPECT_EQ("/feeds/default/private/full/folder%3Aroot/contents?v=3&alt=json"
906 "&showroot=true",
907 http_request_.relative_url);
908 EXPECT_EQ("application/atom+xml", http_request_.headers["Content-Type"]);
909
910 EXPECT_TRUE(http_request_.has_content);
911 EXPECT_EQ(base::StringPrintf("<?xml version=\"1.0\"?>\n"
912 "<entry xmlns=\"http://www.w3.org/2005/Atom\">\n"
913 " <id>%sfeeds/default/private/full/"
914 "file%%3A2_file_resource_id</id>\n"
915 "</entry>\n",
916 test_server_.base_url().spec().c_str()),
917 http_request_.content);
918 }
919
920 TEST_F(GDataWapiRequestsTest, RemoveResourceFromDirectoryRequest) {
921 GDataErrorCode result_code = GDATA_OTHER_ERROR;
922
923 // Remove a file from the root directory.
924 {
925 base::RunLoop run_loop;
926 RemoveResourceFromDirectoryRequest* request =
927 new RemoveResourceFromDirectoryRequest(
928 request_sender_.get(),
929 *url_generator_,
930 test_util::CreateQuitCallback(
931 &run_loop,
932 test_util::CreateCopyResultCallback(&result_code)),
933 "folder:root",
934 "file:2_file_resource_id");
935
936 request_sender_->StartRequestWithRetry(request);
937 run_loop.Run();
938 }
939
940 EXPECT_EQ(HTTP_SUCCESS, result_code);
941 // DELETE method should be used, without the body content.
942 EXPECT_EQ(net::test_server::METHOD_DELETE, http_request_.method);
943 EXPECT_EQ("/feeds/default/private/full/folder%3Aroot/contents/"
944 "file%3A2_file_resource_id?v=3&alt=json&showroot=true",
945 http_request_.relative_url);
946 EXPECT_EQ("*", http_request_.headers["If-Match"]);
947 EXPECT_FALSE(http_request_.has_content);
948 }
949
950 // This test exercises InitiateUploadNewFileRequest and
951 // ResumeUploadRequest for a scenario of uploading a new file.
952 TEST_F(GDataWapiRequestsTest, UploadNewFile) {
953 const std::string kUploadContent = "hello";
954 const base::FilePath kTestFilePath =
955 temp_dir_.path().AppendASCII("upload_file.txt");
956 ASSERT_TRUE(test_util::WriteStringToFile(kTestFilePath, kUploadContent));
957
958 GDataErrorCode result_code = GDATA_OTHER_ERROR;
959 GURL upload_url;
960
961 // 1) Get the upload URL for uploading a new file.
962 {
963 base::RunLoop run_loop;
964 InitiateUploadNewFileRequest* initiate_request =
965 new InitiateUploadNewFileRequest(
966 request_sender_.get(),
967 *url_generator_,
968 test_util::CreateQuitCallback(
969 &run_loop,
970 test_util::CreateCopyResultCallback(&result_code, &upload_url)),
971 "text/plain",
972 kUploadContent.size(),
973 "folder:id",
974 "New file");
975 request_sender_->StartRequestWithRetry(initiate_request);
976 run_loop.Run();
977 }
978
979 EXPECT_EQ(HTTP_SUCCESS, result_code);
980 EXPECT_EQ(test_server_.GetURL("/upload_new_file"), upload_url);
981 EXPECT_EQ(net::test_server::METHOD_POST, http_request_.method);
982 // convert=false should be passed as files should be uploaded as-is.
983 EXPECT_EQ(
984 "/feeds/upload/create-session/default/private/full/folder%3Aid/contents"
985 "?convert=false&v=3&alt=json&showroot=true",
986 http_request_.relative_url);
987 EXPECT_EQ("text/plain", http_request_.headers["X-Upload-Content-Type"]);
988 EXPECT_EQ("application/atom+xml", http_request_.headers["Content-Type"]);
989 EXPECT_EQ(base::Int64ToString(kUploadContent.size()),
990 http_request_.headers["X-Upload-Content-Length"]);
991
992 EXPECT_TRUE(http_request_.has_content);
993 EXPECT_EQ("<?xml version=\"1.0\"?>\n"
994 "<entry xmlns=\"http://www.w3.org/2005/Atom\" "
995 "xmlns:docs=\"http://schemas.google.com/docs/2007\">\n"
996 " <title>New file</title>\n"
997 "</entry>\n",
998 http_request_.content);
999
1000 // 2) Upload the content to the upload URL.
1001 UploadRangeResponse response;
1002 scoped_ptr<ResourceEntry> new_entry;
1003
1004 {
1005 base::RunLoop run_loop;
1006 ResumeUploadRequest* resume_request = new ResumeUploadRequest(
1007 request_sender_.get(),
1008 test_util::CreateQuitCallback(
1009 &run_loop,
1010 test_util::CreateCopyResultCallback(&response, &new_entry)),
1011 ProgressCallback(),
1012 upload_url,
1013 0, // start_position
1014 kUploadContent.size(), // end_position (exclusive)
1015 kUploadContent.size(), // content_length,
1016 "text/plain", // content_type
1017 kTestFilePath);
1018
1019 request_sender_->StartRequestWithRetry(resume_request);
1020 run_loop.Run();
1021 }
1022
1023 // METHOD_PUT should be used to upload data.
1024 EXPECT_EQ(net::test_server::METHOD_PUT, http_request_.method);
1025 // Request should go to the upload URL.
1026 EXPECT_EQ(upload_url.path(), http_request_.relative_url);
1027 // Content-Range header should be added.
1028 EXPECT_EQ("bytes 0-" +
1029 base::Int64ToString(kUploadContent.size() -1) + "/" +
1030 base::Int64ToString(kUploadContent.size()),
1031 http_request_.headers["Content-Range"]);
1032 // The upload content should be set in the HTTP request.
1033 EXPECT_TRUE(http_request_.has_content);
1034 EXPECT_EQ(kUploadContent, http_request_.content);
1035
1036 // Check the response.
1037 EXPECT_EQ(HTTP_CREATED, response.code); // Because it's a new file
1038 // The start and end positions should be set to -1, if an upload is complete.
1039 EXPECT_EQ(-1, response.start_position_received);
1040 EXPECT_EQ(-1, response.end_position_received);
1041 }
1042
1043 // This test exercises InitiateUploadNewFileRequest and ResumeUploadRequest
1044 // for a scenario of uploading a new *large* file, which requires multiple
1045 // requests of ResumeUploadRequest. GetUploadRequest is also tested in this
1046 // test case.
1047 TEST_F(GDataWapiRequestsTest, UploadNewLargeFile) {
1048 const size_t kMaxNumBytes = 10;
1049 // This is big enough to cause multiple requests of ResumeUploadRequest
1050 // as we are going to send at most kMaxNumBytes at a time.
1051 // So, sending "kMaxNumBytes * 2 + 1" bytes ensures three
1052 // ResumeUploadRequests, which are start, middle and last requests.
1053 const std::string kUploadContent(kMaxNumBytes * 2 + 1, 'a');
1054 const base::FilePath kTestFilePath =
1055 temp_dir_.path().AppendASCII("upload_file.txt");
1056 ASSERT_TRUE(test_util::WriteStringToFile(kTestFilePath, kUploadContent));
1057
1058 GDataErrorCode result_code = GDATA_OTHER_ERROR;
1059 GURL upload_url;
1060
1061 // 1) Get the upload URL for uploading a new file.
1062 {
1063 base::RunLoop run_loop;
1064 InitiateUploadNewFileRequest* initiate_request =
1065 new InitiateUploadNewFileRequest(
1066 request_sender_.get(),
1067 *url_generator_,
1068 test_util::CreateQuitCallback(
1069 &run_loop,
1070 test_util::CreateCopyResultCallback(&result_code, &upload_url)),
1071 "text/plain",
1072 kUploadContent.size(),
1073 "folder:id",
1074 "New file");
1075 request_sender_->StartRequestWithRetry(initiate_request);
1076 run_loop.Run();
1077 }
1078
1079 EXPECT_EQ(HTTP_SUCCESS, result_code);
1080 EXPECT_EQ(test_server_.GetURL("/upload_new_file"), upload_url);
1081 EXPECT_EQ(net::test_server::METHOD_POST, http_request_.method);
1082 // convert=false should be passed as files should be uploaded as-is.
1083 EXPECT_EQ(
1084 "/feeds/upload/create-session/default/private/full/folder%3Aid/contents"
1085 "?convert=false&v=3&alt=json&showroot=true",
1086 http_request_.relative_url);
1087 EXPECT_EQ("text/plain", http_request_.headers["X-Upload-Content-Type"]);
1088 EXPECT_EQ("application/atom+xml", http_request_.headers["Content-Type"]);
1089 EXPECT_EQ(base::Int64ToString(kUploadContent.size()),
1090 http_request_.headers["X-Upload-Content-Length"]);
1091
1092 EXPECT_TRUE(http_request_.has_content);
1093 EXPECT_EQ("<?xml version=\"1.0\"?>\n"
1094 "<entry xmlns=\"http://www.w3.org/2005/Atom\" "
1095 "xmlns:docs=\"http://schemas.google.com/docs/2007\">\n"
1096 " <title>New file</title>\n"
1097 "</entry>\n",
1098 http_request_.content);
1099
1100 // 2) Before sending any data, check the current status.
1101 // This is an edge case test for GetUploadStatusRequest
1102 // (UploadRangeRequestBase).
1103 {
1104 UploadRangeResponse response;
1105 scoped_ptr<ResourceEntry> new_entry;
1106
1107 // Check the response by GetUploadStatusRequest.
1108 {
1109 base::RunLoop run_loop;
1110 GetUploadStatusRequest* get_upload_status_request =
1111 new GetUploadStatusRequest(
1112 request_sender_.get(),
1113 test_util::CreateQuitCallback(
1114 &run_loop,
1115 test_util::CreateCopyResultCallback(&response, &new_entry)),
1116 upload_url,
1117 kUploadContent.size());
1118 request_sender_->StartRequestWithRetry(get_upload_status_request);
1119 run_loop.Run();
1120 }
1121
1122 // METHOD_PUT should be used to upload data.
1123 EXPECT_EQ(net::test_server::METHOD_PUT, http_request_.method);
1124 // Request should go to the upload URL.
1125 EXPECT_EQ(upload_url.path(), http_request_.relative_url);
1126 // Content-Range header should be added.
1127 EXPECT_EQ("bytes */" + base::Int64ToString(kUploadContent.size()),
1128 http_request_.headers["Content-Range"]);
1129 EXPECT_TRUE(http_request_.has_content);
1130 EXPECT_TRUE(http_request_.content.empty());
1131
1132 // Check the response.
1133 EXPECT_EQ(HTTP_RESUME_INCOMPLETE, response.code);
1134 EXPECT_EQ(0, response.start_position_received);
1135 EXPECT_EQ(0, response.end_position_received);
1136 }
1137
1138 // 3) Upload the content to the upload URL with multiple requests.
1139 size_t num_bytes_consumed = 0;
1140 for (size_t start_position = 0; start_position < kUploadContent.size();
1141 start_position += kMaxNumBytes) {
1142 SCOPED_TRACE(testing::Message("start_position: ") << start_position);
1143
1144 // The payload is at most kMaxNumBytes.
1145 const size_t remaining_size = kUploadContent.size() - start_position;
1146 const std::string payload = kUploadContent.substr(
1147 start_position, std::min(kMaxNumBytes, remaining_size));
1148 num_bytes_consumed += payload.size();
1149 // The end position is exclusive.
1150 const size_t end_position = start_position + payload.size();
1151
1152 UploadRangeResponse response;
1153 scoped_ptr<ResourceEntry> new_entry;
1154
1155 {
1156 base::RunLoop run_loop;
1157 ResumeUploadRequest* resume_request = new ResumeUploadRequest(
1158 request_sender_.get(),
1159 test_util::CreateQuitCallback(
1160 &run_loop,
1161 test_util::CreateCopyResultCallback(&response, &new_entry)),
1162 ProgressCallback(),
1163 upload_url,
1164 start_position,
1165 end_position,
1166 kUploadContent.size(), // content_length,
1167 "text/plain", // content_type
1168 kTestFilePath);
1169 request_sender_->StartRequestWithRetry(resume_request);
1170 run_loop.Run();
1171 }
1172
1173 // METHOD_PUT should be used to upload data.
1174 EXPECT_EQ(net::test_server::METHOD_PUT, http_request_.method);
1175 // Request should go to the upload URL.
1176 EXPECT_EQ(upload_url.path(), http_request_.relative_url);
1177 // Content-Range header should be added.
1178 EXPECT_EQ("bytes " +
1179 base::Int64ToString(start_position) + "-" +
1180 base::Int64ToString(end_position - 1) + "/" +
1181 base::Int64ToString(kUploadContent.size()),
1182 http_request_.headers["Content-Range"]);
1183 // The upload content should be set in the HTTP request.
1184 EXPECT_TRUE(http_request_.has_content);
1185 EXPECT_EQ(payload, http_request_.content);
1186
1187 // Check the response.
1188 if (payload.size() == remaining_size) {
1189 EXPECT_EQ(HTTP_CREATED, response.code); // Because it's a new file.
1190 // The start and end positions should be set to -1, if an upload is
1191 // complete.
1192 EXPECT_EQ(-1, response.start_position_received);
1193 EXPECT_EQ(-1, response.end_position_received);
1194 // The upload process is completed, so exit from the loop.
1195 break;
1196 }
1197
1198 EXPECT_EQ(HTTP_RESUME_INCOMPLETE, response.code);
1199 EXPECT_EQ(0, response.start_position_received);
1200 EXPECT_EQ(static_cast<int64>(end_position),
1201 response.end_position_received);
1202
1203 // Check the response by GetUploadStatusRequest.
1204 {
1205 base::RunLoop run_loop;
1206 GetUploadStatusRequest* get_upload_status_request =
1207 new GetUploadStatusRequest(
1208 request_sender_.get(),
1209 test_util::CreateQuitCallback(
1210 &run_loop,
1211 test_util::CreateCopyResultCallback(&response, &new_entry)),
1212 upload_url,
1213 kUploadContent.size());
1214 request_sender_->StartRequestWithRetry(get_upload_status_request);
1215 run_loop.Run();
1216 }
1217
1218 // METHOD_PUT should be used to upload data.
1219 EXPECT_EQ(net::test_server::METHOD_PUT, http_request_.method);
1220 // Request should go to the upload URL.
1221 EXPECT_EQ(upload_url.path(), http_request_.relative_url);
1222 // Content-Range header should be added.
1223 EXPECT_EQ("bytes */" + base::Int64ToString(kUploadContent.size()),
1224 http_request_.headers["Content-Range"]);
1225 EXPECT_TRUE(http_request_.has_content);
1226 EXPECT_TRUE(http_request_.content.empty());
1227
1228 // Check the response.
1229 EXPECT_EQ(HTTP_RESUME_INCOMPLETE, response.code);
1230 EXPECT_EQ(0, response.start_position_received);
1231 EXPECT_EQ(static_cast<int64>(end_position),
1232 response.end_position_received);
1233 }
1234
1235 EXPECT_EQ(kUploadContent.size(), num_bytes_consumed);
1236 }
1237
1238 // This test exercises InitiateUploadNewFileRequest and ResumeUploadRequest
1239 // for a scenario of uploading a new *empty* file.
1240 //
1241 // The test is almost identical to UploadNewFile. The only difference is the
1242 // expectation for the Content-Range header.
1243 TEST_F(GDataWapiRequestsTest, UploadNewEmptyFile) {
1244 const std::string kUploadContent;
1245 const base::FilePath kTestFilePath =
1246 temp_dir_.path().AppendASCII("empty_file.txt");
1247 ASSERT_TRUE(test_util::WriteStringToFile(kTestFilePath, kUploadContent));
1248
1249 GDataErrorCode result_code = GDATA_OTHER_ERROR;
1250 GURL upload_url;
1251
1252 // 1) Get the upload URL for uploading a new file.
1253 {
1254 base::RunLoop run_loop;
1255 InitiateUploadNewFileRequest* initiate_request =
1256 new InitiateUploadNewFileRequest(
1257 request_sender_.get(),
1258 *url_generator_,
1259 test_util::CreateQuitCallback(
1260 &run_loop,
1261 test_util::CreateCopyResultCallback(&result_code, &upload_url)),
1262 "text/plain",
1263 kUploadContent.size(),
1264 "folder:id",
1265 "New file");
1266 request_sender_->StartRequestWithRetry(initiate_request);
1267 run_loop.Run();
1268 }
1269
1270 EXPECT_EQ(HTTP_SUCCESS, result_code);
1271 EXPECT_EQ(test_server_.GetURL("/upload_new_file"), upload_url);
1272 EXPECT_EQ(net::test_server::METHOD_POST, http_request_.method);
1273 // convert=false should be passed as files should be uploaded as-is.
1274 EXPECT_EQ(
1275 "/feeds/upload/create-session/default/private/full/folder%3Aid/contents"
1276 "?convert=false&v=3&alt=json&showroot=true",
1277 http_request_.relative_url);
1278 EXPECT_EQ("text/plain", http_request_.headers["X-Upload-Content-Type"]);
1279 EXPECT_EQ("application/atom+xml", http_request_.headers["Content-Type"]);
1280 EXPECT_EQ(base::Int64ToString(kUploadContent.size()),
1281 http_request_.headers["X-Upload-Content-Length"]);
1282
1283 EXPECT_TRUE(http_request_.has_content);
1284 EXPECT_EQ("<?xml version=\"1.0\"?>\n"
1285 "<entry xmlns=\"http://www.w3.org/2005/Atom\" "
1286 "xmlns:docs=\"http://schemas.google.com/docs/2007\">\n"
1287 " <title>New file</title>\n"
1288 "</entry>\n",
1289 http_request_.content);
1290
1291 // 2) Upload the content to the upload URL.
1292 UploadRangeResponse response;
1293 scoped_ptr<ResourceEntry> new_entry;
1294
1295 {
1296 base::RunLoop run_loop;
1297 ResumeUploadRequest* resume_request = new ResumeUploadRequest(
1298 request_sender_.get(),
1299 test_util::CreateQuitCallback(
1300 &run_loop,
1301 test_util::CreateCopyResultCallback(&response, &new_entry)),
1302 ProgressCallback(),
1303 upload_url,
1304 0, // start_position
1305 kUploadContent.size(), // end_position (exclusive)
1306 kUploadContent.size(), // content_length,
1307 "text/plain", // content_type
1308 kTestFilePath);
1309 request_sender_->StartRequestWithRetry(resume_request);
1310 run_loop.Run();
1311 }
1312
1313 // METHOD_PUT should be used to upload data.
1314 EXPECT_EQ(net::test_server::METHOD_PUT, http_request_.method);
1315 // Request should go to the upload URL.
1316 EXPECT_EQ(upload_url.path(), http_request_.relative_url);
1317 // Content-Range header should not exit if the content is empty.
1318 // We should not generate the header with an invalid value "bytes 0--1/0".
1319 EXPECT_EQ(0U, http_request_.headers.count("Content-Range"));
1320 // The upload content should be set in the HTTP request.
1321 EXPECT_TRUE(http_request_.has_content);
1322 EXPECT_EQ(kUploadContent, http_request_.content);
1323
1324 // Check the response.
1325 EXPECT_EQ(HTTP_CREATED, response.code); // Because it's a new file.
1326 // The start and end positions should be set to -1, if an upload is complete.
1327 EXPECT_EQ(-1, response.start_position_received);
1328 EXPECT_EQ(-1, response.end_position_received);
1329 }
1330
1331 // This test exercises InitiateUploadExistingFileRequest and
1332 // ResumeUploadRequest for a scenario of updating an existing file.
1333 TEST_F(GDataWapiRequestsTest, UploadExistingFile) {
1334 const std::string kUploadContent = "hello";
1335 const base::FilePath kTestFilePath =
1336 temp_dir_.path().AppendASCII("upload_file.txt");
1337 ASSERT_TRUE(test_util::WriteStringToFile(kTestFilePath, kUploadContent));
1338
1339 GDataErrorCode result_code = GDATA_OTHER_ERROR;
1340 GURL upload_url;
1341
1342 // 1) Get the upload URL for uploading an existing file.
1343 {
1344 base::RunLoop run_loop;
1345 InitiateUploadExistingFileRequest* initiate_request =
1346 new InitiateUploadExistingFileRequest(
1347 request_sender_.get(),
1348 *url_generator_,
1349 test_util::CreateQuitCallback(
1350 &run_loop,
1351 test_util::CreateCopyResultCallback(&result_code, &upload_url)),
1352 "text/plain",
1353 kUploadContent.size(),
1354 "file:foo",
1355 std::string() /* etag */);
1356 request_sender_->StartRequestWithRetry(initiate_request);
1357 run_loop.Run();
1358 }
1359
1360 EXPECT_EQ(HTTP_SUCCESS, result_code);
1361 EXPECT_EQ(test_server_.GetURL("/upload_existing_file"), upload_url);
1362 // For updating an existing file, METHOD_PUT should be used.
1363 EXPECT_EQ(net::test_server::METHOD_PUT, http_request_.method);
1364 // convert=false should be passed as files should be uploaded as-is.
1365 EXPECT_EQ("/feeds/upload/create-session/default/private/full/file%3Afoo"
1366 "?convert=false&v=3&alt=json&showroot=true",
1367 http_request_.relative_url);
1368 // Even though the body is empty, the content type should be set to
1369 // "text/plain".
1370 EXPECT_EQ("text/plain", http_request_.headers["Content-Type"]);
1371 EXPECT_EQ("text/plain", http_request_.headers["X-Upload-Content-Type"]);
1372 EXPECT_EQ(base::Int64ToString(kUploadContent.size()),
1373 http_request_.headers["X-Upload-Content-Length"]);
1374 // For updating an existing file, an empty body should be attached (PUT
1375 // requires a body)
1376 EXPECT_TRUE(http_request_.has_content);
1377 EXPECT_EQ("", http_request_.content);
1378 EXPECT_EQ("*", http_request_.headers["If-Match"]);
1379
1380 // 2) Upload the content to the upload URL.
1381 UploadRangeResponse response;
1382 scoped_ptr<ResourceEntry> new_entry;
1383
1384 {
1385 base::RunLoop run_loop;
1386 ResumeUploadRequest* resume_request = new ResumeUploadRequest(
1387 request_sender_.get(),
1388 test_util::CreateQuitCallback(
1389 &run_loop,
1390 test_util::CreateCopyResultCallback(&response, &new_entry)),
1391 ProgressCallback(),
1392 upload_url,
1393 0, // start_position
1394 kUploadContent.size(), // end_position (exclusive)
1395 kUploadContent.size(), // content_length,
1396 "text/plain", // content_type
1397 kTestFilePath);
1398
1399 request_sender_->StartRequestWithRetry(resume_request);
1400 run_loop.Run();
1401 }
1402
1403 // METHOD_PUT should be used to upload data.
1404 EXPECT_EQ(net::test_server::METHOD_PUT, http_request_.method);
1405 // Request should go to the upload URL.
1406 EXPECT_EQ(upload_url.path(), http_request_.relative_url);
1407 // Content-Range header should be added.
1408 EXPECT_EQ("bytes 0-" +
1409 base::Int64ToString(kUploadContent.size() -1) + "/" +
1410 base::Int64ToString(kUploadContent.size()),
1411 http_request_.headers["Content-Range"]);
1412 // The upload content should be set in the HTTP request.
1413 EXPECT_TRUE(http_request_.has_content);
1414 EXPECT_EQ(kUploadContent, http_request_.content);
1415
1416 // Check the response.
1417 EXPECT_EQ(HTTP_SUCCESS, response.code); // Because it's an existing file.
1418 // The start and end positions should be set to -1, if an upload is complete.
1419 EXPECT_EQ(-1, response.start_position_received);
1420 EXPECT_EQ(-1, response.end_position_received);
1421 }
1422
1423 // This test exercises InitiateUploadExistingFileRequest and
1424 // ResumeUploadRequest for a scenario of updating an existing file.
1425 TEST_F(GDataWapiRequestsTest, UploadExistingFileWithETag) {
1426 const std::string kUploadContent = "hello";
1427 const base::FilePath kTestFilePath =
1428 temp_dir_.path().AppendASCII("upload_file.txt");
1429 ASSERT_TRUE(test_util::WriteStringToFile(kTestFilePath, kUploadContent));
1430
1431 GDataErrorCode result_code = GDATA_OTHER_ERROR;
1432 GURL upload_url;
1433
1434 // 1) Get the upload URL for uploading an existing file.
1435 {
1436 base::RunLoop run_loop;
1437 InitiateUploadExistingFileRequest* initiate_request =
1438 new InitiateUploadExistingFileRequest(
1439 request_sender_.get(),
1440 *url_generator_,
1441 test_util::CreateQuitCallback(
1442 &run_loop,
1443 test_util::CreateCopyResultCallback(&result_code, &upload_url)),
1444 "text/plain",
1445 kUploadContent.size(),
1446 "file:foo",
1447 kTestETag);
1448 request_sender_->StartRequestWithRetry(initiate_request);
1449 run_loop.Run();
1450 }
1451
1452 EXPECT_EQ(HTTP_SUCCESS, result_code);
1453 EXPECT_EQ(test_server_.GetURL("/upload_existing_file"), upload_url);
1454 // For updating an existing file, METHOD_PUT should be used.
1455 EXPECT_EQ(net::test_server::METHOD_PUT, http_request_.method);
1456 // convert=false should be passed as files should be uploaded as-is.
1457 EXPECT_EQ("/feeds/upload/create-session/default/private/full/file%3Afoo"
1458 "?convert=false&v=3&alt=json&showroot=true",
1459 http_request_.relative_url);
1460 // Even though the body is empty, the content type should be set to
1461 // "text/plain".
1462 EXPECT_EQ("text/plain", http_request_.headers["Content-Type"]);
1463 EXPECT_EQ("text/plain", http_request_.headers["X-Upload-Content-Type"]);
1464 EXPECT_EQ(base::Int64ToString(kUploadContent.size()),
1465 http_request_.headers["X-Upload-Content-Length"]);
1466 // For updating an existing file, an empty body should be attached (PUT
1467 // requires a body)
1468 EXPECT_TRUE(http_request_.has_content);
1469 EXPECT_EQ("", http_request_.content);
1470 EXPECT_EQ(kTestETag, http_request_.headers["If-Match"]);
1471
1472 // 2) Upload the content to the upload URL.
1473 UploadRangeResponse response;
1474 scoped_ptr<ResourceEntry> new_entry;
1475
1476 {
1477 base::RunLoop run_loop;
1478 ResumeUploadRequest* resume_request = new ResumeUploadRequest(
1479 request_sender_.get(),
1480 test_util::CreateQuitCallback(
1481 &run_loop,
1482 test_util::CreateCopyResultCallback(&response, &new_entry)),
1483 ProgressCallback(),
1484 upload_url,
1485 0, // start_position
1486 kUploadContent.size(), // end_position (exclusive)
1487 kUploadContent.size(), // content_length,
1488 "text/plain", // content_type
1489 kTestFilePath);
1490 request_sender_->StartRequestWithRetry(resume_request);
1491 run_loop.Run();
1492 }
1493
1494 // METHOD_PUT should be used to upload data.
1495 EXPECT_EQ(net::test_server::METHOD_PUT, http_request_.method);
1496 // Request should go to the upload URL.
1497 EXPECT_EQ(upload_url.path(), http_request_.relative_url);
1498 // Content-Range header should be added.
1499 EXPECT_EQ("bytes 0-" +
1500 base::Int64ToString(kUploadContent.size() -1) + "/" +
1501 base::Int64ToString(kUploadContent.size()),
1502 http_request_.headers["Content-Range"]);
1503 // The upload content should be set in the HTTP request.
1504 EXPECT_TRUE(http_request_.has_content);
1505 EXPECT_EQ(kUploadContent, http_request_.content);
1506
1507 // Check the response.
1508 EXPECT_EQ(HTTP_SUCCESS, response.code); // Because it's an existing file.
1509 // The start and end positions should be set to -1, if an upload is complete.
1510 EXPECT_EQ(-1, response.start_position_received);
1511 EXPECT_EQ(-1, response.end_position_received);
1512 }
1513
1514 // This test exercises InitiateUploadExistingFileRequest for a scenario of
1515 // confliction on updating an existing file.
1516 TEST_F(GDataWapiRequestsTest, UploadExistingFileWithETagConflict) {
1517 const std::string kUploadContent = "hello";
1518 const std::string kWrongETag = "wrong_etag";
1519 GDataErrorCode result_code = GDATA_OTHER_ERROR;
1520 GURL upload_url;
1521
1522 {
1523 base::RunLoop run_loop;
1524 InitiateUploadExistingFileRequest* initiate_request =
1525 new InitiateUploadExistingFileRequest(
1526 request_sender_.get(),
1527 *url_generator_,
1528 test_util::CreateQuitCallback(
1529 &run_loop,
1530 test_util::CreateCopyResultCallback(&result_code, &upload_url)),
1531 "text/plain",
1532 kUploadContent.size(),
1533 "file:foo",
1534 kWrongETag);
1535 request_sender_->StartRequestWithRetry(initiate_request);
1536 run_loop.Run();
1537 }
1538
1539 EXPECT_EQ(HTTP_PRECONDITION, result_code);
1540 // For updating an existing file, METHOD_PUT should be used.
1541 EXPECT_EQ(net::test_server::METHOD_PUT, http_request_.method);
1542 // convert=false should be passed as files should be uploaded as-is.
1543 EXPECT_EQ("/feeds/upload/create-session/default/private/full/file%3Afoo"
1544 "?convert=false&v=3&alt=json&showroot=true",
1545 http_request_.relative_url);
1546 // Even though the body is empty, the content type should be set to
1547 // "text/plain".
1548 EXPECT_EQ("text/plain", http_request_.headers["Content-Type"]);
1549 EXPECT_EQ("text/plain", http_request_.headers["X-Upload-Content-Type"]);
1550 EXPECT_EQ(base::Int64ToString(kUploadContent.size()),
1551 http_request_.headers["X-Upload-Content-Length"]);
1552 // For updating an existing file, an empty body should be attached (PUT
1553 // requires a body)
1554 EXPECT_TRUE(http_request_.has_content);
1555 EXPECT_EQ("", http_request_.content);
1556 EXPECT_EQ(kWrongETag, http_request_.headers["If-Match"]);
1557 }
1558
1559 TEST_F(GDataWapiRequestsTest, DownloadFileRequest) {
1560 const base::FilePath kDownloadedFilePath =
1561 temp_dir_.path().AppendASCII("cache_file");
1562 const std::string kTestIdWithTypeLabel("file:dummyId");
1563 const std::string kTestId("dummyId");
1564
1565 GDataErrorCode result_code = GDATA_OTHER_ERROR;
1566 base::FilePath temp_file;
1567 {
1568 base::RunLoop run_loop;
1569 DownloadFileRequest* request = new DownloadFileRequest(
1570 request_sender_.get(),
1571 *url_generator_,
1572 test_util::CreateQuitCallback(
1573 &run_loop,
1574 test_util::CreateCopyResultCallback(&result_code, &temp_file)),
1575 GetContentCallback(),
1576 ProgressCallback(),
1577 kTestIdWithTypeLabel,
1578 kDownloadedFilePath);
1579 request_sender_->StartRequestWithRetry(request);
1580 run_loop.Run();
1581 }
1582
1583 std::string contents;
1584 base::ReadFileToString(temp_file, &contents);
1585 base::DeleteFile(temp_file, false);
1586
1587 EXPECT_EQ(HTTP_SUCCESS, result_code);
1588 EXPECT_EQ(net::test_server::METHOD_GET, http_request_.method);
1589 EXPECT_EQ(kTestDownloadPathPrefix + kTestId, http_request_.relative_url);
1590 EXPECT_EQ(kDownloadedFilePath, temp_file);
1591
1592 const std::string expected_contents = kTestId + kTestId + kTestId;
1593 EXPECT_EQ(expected_contents, contents);
1594 }
1595
1596 } // namespace google_apis
OLDNEW
« no previous file with comments | « chrome/browser/google_apis/gdata_wapi_requests.cc ('k') | chrome/browser/google_apis/gdata_wapi_url_generator.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698