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