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

Side by Side Diff: chrome/browser/drive/fake_drive_service.cc

Issue 135643005: drive: Stop using DictionaryValue to store data in FakeDriveService (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/browser/drive/fake_drive_service.h ('k') | google_apis/drive/drive_api_parser.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/drive/fake_drive_service.h" 5 #include "chrome/browser/drive/fake_drive_service.h"
6 6
7 #include <string> 7 #include <string>
8 8
9 #include "base/file_util.h" 9 #include "base/file_util.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
(...skipping 16 matching lines...) Expand all
27 27
28 using content::BrowserThread; 28 using content::BrowserThread;
29 using google_apis::AboutResource; 29 using google_apis::AboutResource;
30 using google_apis::AboutResourceCallback; 30 using google_apis::AboutResourceCallback;
31 using google_apis::AccountMetadata; 31 using google_apis::AccountMetadata;
32 using google_apis::AppList; 32 using google_apis::AppList;
33 using google_apis::AppListCallback; 33 using google_apis::AppListCallback;
34 using google_apis::AuthStatusCallback; 34 using google_apis::AuthStatusCallback;
35 using google_apis::AuthorizeAppCallback; 35 using google_apis::AuthorizeAppCallback;
36 using google_apis::CancelCallback; 36 using google_apis::CancelCallback;
37 using google_apis::ChangeResource;
37 using google_apis::DownloadActionCallback; 38 using google_apis::DownloadActionCallback;
38 using google_apis::EntryActionCallback; 39 using google_apis::EntryActionCallback;
40 using google_apis::FileResource;
39 using google_apis::GDATA_FILE_ERROR; 41 using google_apis::GDATA_FILE_ERROR;
40 using google_apis::GDATA_NO_CONNECTION; 42 using google_apis::GDATA_NO_CONNECTION;
41 using google_apis::GDATA_OTHER_ERROR; 43 using google_apis::GDATA_OTHER_ERROR;
42 using google_apis::GDataErrorCode; 44 using google_apis::GDataErrorCode;
43 using google_apis::GetContentCallback; 45 using google_apis::GetContentCallback;
44 using google_apis::GetResourceEntryCallback; 46 using google_apis::GetResourceEntryCallback;
45 using google_apis::GetResourceListCallback; 47 using google_apis::GetResourceListCallback;
46 using google_apis::GetShareUrlCallback; 48 using google_apis::GetShareUrlCallback;
47 using google_apis::HTTP_BAD_REQUEST; 49 using google_apis::HTTP_BAD_REQUEST;
48 using google_apis::HTTP_CREATED; 50 using google_apis::HTTP_CREATED;
49 using google_apis::HTTP_NOT_FOUND; 51 using google_apis::HTTP_NOT_FOUND;
50 using google_apis::HTTP_NO_CONTENT; 52 using google_apis::HTTP_NO_CONTENT;
51 using google_apis::HTTP_PRECONDITION; 53 using google_apis::HTTP_PRECONDITION;
52 using google_apis::HTTP_RESUME_INCOMPLETE; 54 using google_apis::HTTP_RESUME_INCOMPLETE;
53 using google_apis::HTTP_SUCCESS; 55 using google_apis::HTTP_SUCCESS;
54 using google_apis::InitiateUploadCallback; 56 using google_apis::InitiateUploadCallback;
55 using google_apis::Link; 57 using google_apis::Link;
58 using google_apis::ParentReference;
56 using google_apis::ProgressCallback; 59 using google_apis::ProgressCallback;
57 using google_apis::ResourceEntry; 60 using google_apis::ResourceEntry;
58 using google_apis::ResourceList; 61 using google_apis::ResourceList;
59 using google_apis::UploadRangeCallback; 62 using google_apis::UploadRangeCallback;
60 using google_apis::UploadRangeResponse; 63 using google_apis::UploadRangeResponse;
61 namespace test_util = google_apis::test_util; 64 namespace test_util = google_apis::test_util;
62 65
63 namespace drive { 66 namespace drive {
64 namespace { 67 namespace {
65 68
66 // Rel property of an upload link in the entries dictionary value. 69 // Mime type of directories.
67 const char kUploadUrlRel[] = 70 const char kDriveFolderMimeType[] = "application/vnd.google-apps.folder";
68 "http://schemas.google.com/g/2005#resumable-create-media";
69
70 // Rel property of a share link in the entries dictionary value.
71 const char kShareUrlRel[] =
72 "http://schemas.google.com/docs/2007#share";
73 71
74 // Returns true if a resource entry matches with the search query. 72 // Returns true if a resource entry matches with the search query.
75 // Supports queries consist of following format. 73 // Supports queries consist of following format.
76 // - Phrases quoted by double/single quotes 74 // - Phrases quoted by double/single quotes
77 // - AND search for multiple words/phrases segmented by space 75 // - AND search for multiple words/phrases segmented by space
78 // - Limited attribute search. Only "title:" is supported. 76 // - Limited attribute search. Only "title:" is supported.
79 bool EntryMatchWithQuery(const ResourceEntry& entry, 77 bool EntryMatchWithQuery(const ResourceEntry& entry,
80 const std::string& query) { 78 const std::string& query) {
81 base::StringTokenizer tokenizer(query, " "); 79 base::StringTokenizer tokenizer(query, " ");
82 tokenizer.set_quote_chars("\"'"); 80 tokenizer.set_quote_chars("\"'");
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
119 end_position), 117 end_position),
120 base::Passed(&entry))); 118 base::Passed(&entry)));
121 } 119 }
122 120
123 void EntryActionCallbackAdapter( 121 void EntryActionCallbackAdapter(
124 const EntryActionCallback& callback, 122 const EntryActionCallback& callback,
125 GDataErrorCode error, scoped_ptr<ResourceEntry> resource_entry) { 123 GDataErrorCode error, scoped_ptr<ResourceEntry> resource_entry) {
126 callback.Run(error); 124 callback.Run(error);
127 } 125 }
128 126
129 void ClearPropatiesForPermanentDelete(base::DictionaryValue* entry) {
130 scoped_ptr<base::DictionaryValue> new_entry(new base::DictionaryValue);
131 const char* kPreservedProperties[] = {
132 "docs$removed", "docs$changestamp", "gd$resourceId", "id", "updated"
133 };
134
135 for (size_t i = 0; i < arraysize(kPreservedProperties); ++i) {
136 const char* key = kPreservedProperties[i];
137 scoped_ptr<base::Value> value;
138 if (entry->Remove(key, &value))
139 new_entry->Set(key, value.release());
140 }
141
142 entry->Swap(new_entry.get());
143 }
144
145 } // namespace 127 } // namespace
146 128
129 struct FakeDriveService::EntryInfo {
130 google_apis::ChangeResource change_resource;
131 GURL share_url;
132 std::string content_data;
133 };
134
147 struct FakeDriveService::UploadSession { 135 struct FakeDriveService::UploadSession {
148 std::string content_type; 136 std::string content_type;
149 int64 content_length; 137 int64 content_length;
150 std::string parent_resource_id; 138 std::string parent_resource_id;
151 std::string resource_id; 139 std::string resource_id;
152 std::string etag; 140 std::string etag;
153 std::string title; 141 std::string title;
154 142
155 int64 uploaded_size; 143 int64 uploaded_size;
156 144
(...skipping 30 matching lines...) Expand all
187 about_resource_load_count_(0), 175 about_resource_load_count_(0),
188 app_list_load_count_(0), 176 app_list_load_count_(0),
189 blocked_resource_list_load_count_(0), 177 blocked_resource_list_load_count_(0),
190 offline_(false), 178 offline_(false),
191 never_return_all_resource_list_(false) { 179 never_return_all_resource_list_(false) {
192 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 180 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
193 } 181 }
194 182
195 FakeDriveService::~FakeDriveService() { 183 FakeDriveService::~FakeDriveService() {
196 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 184 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
185 STLDeleteValues(&entries_);
197 } 186 }
198 187
199 bool FakeDriveService::LoadResourceListForWapi( 188 bool FakeDriveService::LoadResourceListForWapi(
200 const std::string& relative_path) { 189 const std::string& relative_path) {
201 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 190 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
202 scoped_ptr<base::Value> raw_value = test_util::LoadJSONFile(relative_path); 191 scoped_ptr<base::Value> raw_value = test_util::LoadJSONFile(relative_path);
203 base::DictionaryValue* as_dict = NULL; 192 base::DictionaryValue* as_dict = NULL;
204 scoped_ptr<base::Value> feed; 193 scoped_ptr<base::Value> feed;
205 base::DictionaryValue* feed_as_dict = NULL; 194 base::DictionaryValue* feed_as_dict = NULL;
206 195
207 // Extract the "feed" from the raw value and take the ownership. 196 // Extract the "feed" from the raw value and take the ownership.
208 // Note that Remove() transfers the ownership to |feed|. 197 // Note that Remove() transfers the ownership to |feed|.
209 if (raw_value->GetAsDictionary(&as_dict) && 198 if (raw_value->GetAsDictionary(&as_dict) &&
210 as_dict->Remove("feed", &feed) && 199 as_dict->Remove("feed", &feed) &&
211 feed->GetAsDictionary(&feed_as_dict)) { 200 feed->GetAsDictionary(&feed_as_dict)) {
212 ignore_result(feed.release());
213 resource_list_value_.reset(feed_as_dict);
214
215 // Go through entries and convert test$data from a string to a binary blob.
216 base::ListValue* entries = NULL; 201 base::ListValue* entries = NULL;
217 if (feed_as_dict->GetList("entry", &entries)) { 202 if (feed_as_dict->GetList("entry", &entries)) {
218 for (size_t i = 0; i < entries->GetSize(); ++i) { 203 for (size_t i = 0; i < entries->GetSize(); ++i) {
219 base::DictionaryValue* entry = NULL; 204 base::DictionaryValue* entry = NULL;
220 std::string content_data; 205 if (entries->GetDictionary(i, &entry)) {
221 if (entries->GetDictionary(i, &entry) && 206 scoped_ptr<ResourceEntry> resource_entry =
222 entry->GetString("test$data", &content_data)) { 207 ResourceEntry::CreateFrom(*entry);
223 entry->Set("test$data", 208
224 base::BinaryValue::CreateWithCopiedBuffer( 209 const std::string resource_id = resource_entry->resource_id();
225 content_data.c_str(), content_data.size())); 210 EntryInfoMap::iterator it = entries_.find(resource_id);
211 if (it == entries_.end()) {
212 it = entries_.insert(
213 std::make_pair(resource_id, new EntryInfo)).first;
214 }
215 EntryInfo* new_entry = it->second;
216
217 ChangeResource* change = &new_entry->change_resource;
218 change->set_change_id(resource_entry->changestamp());
219 change->set_file_id(resource_id);
220 change->set_file(
221 util::ConvertResourceEntryToFileResource(*resource_entry));
222
223 const Link* share_url =
224 resource_entry->GetLinkByType(Link::LINK_SHARE);
225 if (share_url)
226 new_entry->share_url = share_url->href();
227
228 entry->GetString("test$data", &new_entry->content_data);
226 } 229 }
227 } 230 }
228 } 231 }
229 } 232 }
230 233
231 return resource_list_value_; 234 return feed_as_dict;
232 } 235 }
233 236
234 bool FakeDriveService::LoadAccountMetadataForWapi( 237 bool FakeDriveService::LoadAccountMetadataForWapi(
235 const std::string& relative_path) { 238 const std::string& relative_path) {
236 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 239 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
237 240
238 // Load JSON data, which must be a dictionary. 241 // Load JSON data, which must be a dictionary.
239 scoped_ptr<base::Value> value = test_util::LoadJSONFile(relative_path); 242 scoped_ptr<base::Value> value = test_util::LoadJSONFile(relative_path);
240 CHECK_EQ(base::Value::TYPE_DICTIONARY, value->GetType()); 243 CHECK_EQ(base::Value::TYPE_DICTIONARY, value->GetType());
241 account_metadata_value_.reset( 244 account_metadata_value_.reset(
242 static_cast<base::DictionaryValue*>(value.release())); 245 static_cast<base::DictionaryValue*>(value.release()));
243 246
244 // Update the largest_changestamp_. 247 // Update the largest_changestamp_.
245 scoped_ptr<AccountMetadata> account_metadata = 248 scoped_ptr<AccountMetadata> account_metadata =
246 AccountMetadata::CreateFrom(*account_metadata_value_); 249 AccountMetadata::CreateFrom(*account_metadata_value_);
247 largest_changestamp_ = account_metadata->largest_changestamp(); 250 largest_changestamp_ = account_metadata->largest_changestamp();
248 251
249 // Add the largest changestamp to the existing entries. 252 // Add the largest changestamp to the existing entries.
250 // This will be used to generate change lists in GetResourceList(). 253 // This will be used to generate change lists in GetResourceList().
251 if (resource_list_value_) { 254 for (EntryInfoMap::iterator it = entries_.begin(); it != entries_.end(); ++it)
252 base::ListValue* entries = NULL; 255 it->second->change_resource.set_change_id(largest_changestamp_);
253 if (resource_list_value_->GetList("entry", &entries)) {
254 for (size_t i = 0; i < entries->GetSize(); ++i) {
255 base::DictionaryValue* entry = NULL;
256 if (entries->GetDictionary(i, &entry)) {
257 entry->SetString("docs$changestamp.value",
258 base::Int64ToString(largest_changestamp_));
259 }
260 }
261 }
262 }
263 256
264 return account_metadata_value_; 257 return account_metadata_value_;
265 } 258 }
266 259
267 bool FakeDriveService::LoadAppListForDriveApi( 260 bool FakeDriveService::LoadAppListForDriveApi(
268 const std::string& relative_path) { 261 const std::string& relative_path) {
269 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 262 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
270 263
271 // Load JSON data, which must be a dictionary. 264 // Load JSON data, which must be a dictionary.
272 scoped_ptr<base::Value> value = test_util::LoadJSONFile(relative_path); 265 scoped_ptr<base::Value> value = test_util::LoadJSONFile(relative_path);
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after
458 if (offline_) { 451 if (offline_) {
459 scoped_ptr<ResourceEntry> null; 452 scoped_ptr<ResourceEntry> null;
460 base::MessageLoop::current()->PostTask( 453 base::MessageLoop::current()->PostTask(
461 FROM_HERE, 454 FROM_HERE,
462 base::Bind(callback, 455 base::Bind(callback,
463 GDATA_NO_CONNECTION, 456 GDATA_NO_CONNECTION,
464 base::Passed(&null))); 457 base::Passed(&null)));
465 return CancelCallback(); 458 return CancelCallback();
466 } 459 }
467 460
468 base::DictionaryValue* entry = FindEntryByResourceId(resource_id); 461 EntryInfo* entry = FindEntryByResourceId(resource_id);
469 if (entry) { 462 if (entry) {
470 scoped_ptr<ResourceEntry> resource_entry = 463 scoped_ptr<ResourceEntry> resource_entry =
471 ResourceEntry::CreateFrom(*entry); 464 util::ConvertChangeResourceToResourceEntry(entry->change_resource);
472 base::MessageLoop::current()->PostTask( 465 base::MessageLoop::current()->PostTask(
473 FROM_HERE, 466 FROM_HERE,
474 base::Bind(callback, HTTP_SUCCESS, base::Passed(&resource_entry))); 467 base::Bind(callback, HTTP_SUCCESS, base::Passed(&resource_entry)));
475 return CancelCallback(); 468 return CancelCallback();
476 } 469 }
477 470
478 scoped_ptr<ResourceEntry> null; 471 scoped_ptr<ResourceEntry> null;
479 base::MessageLoop::current()->PostTask( 472 base::MessageLoop::current()->PostTask(
480 FROM_HERE, 473 FROM_HERE,
481 base::Bind(callback, HTTP_NOT_FOUND, base::Passed(&null))); 474 base::Bind(callback, HTTP_NOT_FOUND, base::Passed(&null)));
(...skipping 10 matching lines...) Expand all
492 if (offline_) { 485 if (offline_) {
493 scoped_ptr<ResourceEntry> null; 486 scoped_ptr<ResourceEntry> null;
494 base::MessageLoop::current()->PostTask( 487 base::MessageLoop::current()->PostTask(
495 FROM_HERE, 488 FROM_HERE,
496 base::Bind(callback, 489 base::Bind(callback,
497 GDATA_NO_CONNECTION, 490 GDATA_NO_CONNECTION,
498 GURL())); 491 GURL()));
499 return CancelCallback(); 492 return CancelCallback();
500 } 493 }
501 494
502 base::DictionaryValue* entry = FindEntryByResourceId(resource_id); 495 EntryInfo* entry = FindEntryByResourceId(resource_id);
503 if (entry) { 496 if (entry) {
504 // Share urls are stored in the resource entry, and they do not rely on the 497 base::MessageLoop::current()->PostTask(
505 // embedding origin. 498 FROM_HERE,
506 scoped_ptr<ResourceEntry> resource_entry = 499 base::Bind(callback, HTTP_SUCCESS, entry->share_url));
507 ResourceEntry::CreateFrom(*entry);
508 const Link* share_url = resource_entry->GetLinkByType(Link::LINK_SHARE);
509 if (share_url) {
510 base::MessageLoop::current()->PostTask(
511 FROM_HERE,
512 base::Bind(callback, HTTP_SUCCESS, share_url->href()));
513 } else {
514 base::MessageLoop::current()->PostTask(
515 FROM_HERE,
516 base::Bind(callback, HTTP_SUCCESS, GURL()));
517 }
518 return CancelCallback(); 500 return CancelCallback();
519 } 501 }
520 502
521 scoped_ptr<ResourceEntry> null;
522 base::MessageLoop::current()->PostTask( 503 base::MessageLoop::current()->PostTask(
523 FROM_HERE, 504 FROM_HERE,
524 base::Bind(callback, HTTP_NOT_FOUND, GURL())); 505 base::Bind(callback, HTTP_NOT_FOUND, GURL()));
525 return CancelCallback(); 506 return CancelCallback();
526 } 507 }
527 508
528 CancelCallback FakeDriveService::GetAboutResource( 509 CancelCallback FakeDriveService::GetAboutResource(
529 const AboutResourceCallback& callback) { 510 const AboutResourceCallback& callback) {
530 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 511 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
531 DCHECK(!callback.is_null()); 512 DCHECK(!callback.is_null());
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
582 const EntryActionCallback& callback) { 563 const EntryActionCallback& callback) {
583 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 564 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
584 DCHECK(!callback.is_null()); 565 DCHECK(!callback.is_null());
585 566
586 if (offline_) { 567 if (offline_) {
587 base::MessageLoop::current()->PostTask( 568 base::MessageLoop::current()->PostTask(
588 FROM_HERE, base::Bind(callback, GDATA_NO_CONNECTION)); 569 FROM_HERE, base::Bind(callback, GDATA_NO_CONNECTION));
589 return CancelCallback(); 570 return CancelCallback();
590 } 571 }
591 572
592 base::ListValue* entries = NULL; 573 EntryInfo* entry = FindEntryByResourceId(resource_id);
593 if (resource_list_value_->GetList("entry", &entries)) { 574 if (entry) {
594 for (size_t i = 0; i < entries->GetSize(); ++i) { 575 ChangeResource* change = &entry->change_resource;
595 base::DictionaryValue* entry = NULL; 576 const FileResource* file = change->file();
596 std::string current_resource_id; 577 if (change->is_deleted()) {
597 if (entries->GetDictionary(i, &entry) && 578 base::MessageLoop::current()->PostTask(
598 entry->GetString("gd$resourceId.$t", &current_resource_id) && 579 FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND));
599 resource_id == current_resource_id) { 580 return CancelCallback();
600 if (entry->HasKey("docs$removed")) { 581 }
601 base::MessageLoop::current()->PostTask(
602 FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND));
603 return CancelCallback();
604 }
605 582
606 std::string entry_etag; 583 if (!etag.empty() && etag != file->etag()) {
607 entry->GetString("gd$etag", &entry_etag); 584 base::MessageLoop::current()->PostTask(
608 if (!etag.empty() && entry_etag != etag) { 585 FROM_HERE, base::Bind(callback, HTTP_PRECONDITION));
609 base::MessageLoop::current()->PostTask( 586 return CancelCallback();
610 FROM_HERE, base::Bind(callback, HTTP_PRECONDITION)); 587 }
611 return CancelCallback();
612 }
613 588
614 entry->Set("docs$removed", new base::DictionaryValue); 589 change->set_deleted(true);
615 AddNewChangestamp(entry); 590 AddNewChangestamp(change);
616 ClearPropatiesForPermanentDelete(entry); 591 change->set_file(scoped_ptr<FileResource>());
617 base::MessageLoop::current()->PostTask( 592 base::MessageLoop::current()->PostTask(
618 FROM_HERE, base::Bind(callback, HTTP_NO_CONTENT)); 593 FROM_HERE, base::Bind(callback, HTTP_NO_CONTENT));
619 return CancelCallback(); 594 return CancelCallback();
620 }
621 }
622 } 595 }
623 596
624 base::MessageLoop::current()->PostTask( 597 base::MessageLoop::current()->PostTask(
625 FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND)); 598 FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND));
626 return CancelCallback(); 599 return CancelCallback();
627 } 600 }
628 601
629 CancelCallback FakeDriveService::TrashResource( 602 CancelCallback FakeDriveService::TrashResource(
630 const std::string& resource_id, 603 const std::string& resource_id,
631 const EntryActionCallback& callback) { 604 const EntryActionCallback& callback) {
632 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 605 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
633 DCHECK(!callback.is_null()); 606 DCHECK(!callback.is_null());
634 607
635 if (offline_) { 608 if (offline_) {
636 base::MessageLoop::current()->PostTask( 609 base::MessageLoop::current()->PostTask(
637 FROM_HERE, base::Bind(callback, GDATA_NO_CONNECTION)); 610 FROM_HERE, base::Bind(callback, GDATA_NO_CONNECTION));
638 return CancelCallback(); 611 return CancelCallback();
639 } 612 }
640 613
641 base::ListValue* entries = NULL; 614 EntryInfo* entry = FindEntryByResourceId(resource_id);
642 // Go through entries and remove the one that matches |resource_id|. 615 if (entry) {
643 if (resource_list_value_->GetList("entry", &entries)) { 616 ChangeResource* change = &entry->change_resource;
644 for (size_t i = 0; i < entries->GetSize(); ++i) { 617 FileResource* file = change->mutable_file();
645 base::DictionaryValue* entry = NULL; 618 GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
646 std::string current_resource_id; 619 if (change->is_deleted() || file->labels().is_trashed()) {
647 if (entries->GetDictionary(i, &entry) && 620 error = HTTP_NOT_FOUND;
648 entry->GetString("gd$resourceId.$t", &current_resource_id) && 621 } else {
649 resource_id == current_resource_id) { 622 file->mutable_labels()->set_trashed(true);
650 GDataErrorCode error = google_apis::GDATA_OTHER_ERROR; 623 AddNewChangestamp(change);
651 if (entry->HasKey("gd$deleted") || entry->HasKey("docs$removed")) { 624 error = HTTP_SUCCESS;
652 error = HTTP_NOT_FOUND;
653 } else {
654 entry->Set("gd$deleted", new base::DictionaryValue);
655 AddNewChangestamp(entry);
656 error = HTTP_SUCCESS;
657 }
658 base::MessageLoop::current()->PostTask(
659 FROM_HERE, base::Bind(callback, error));
660 return CancelCallback();
661 }
662 } 625 }
626 base::MessageLoop::current()->PostTask(
627 FROM_HERE, base::Bind(callback, error));
628 return CancelCallback();
663 } 629 }
664 630
665 base::MessageLoop::current()->PostTask( 631 base::MessageLoop::current()->PostTask(
666 FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND)); 632 FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND));
667 return CancelCallback(); 633 return CancelCallback();
668 } 634 }
669 635
670 CancelCallback FakeDriveService::DownloadFile( 636 CancelCallback FakeDriveService::DownloadFile(
671 const base::FilePath& local_cache_path, 637 const base::FilePath& local_cache_path,
672 const std::string& resource_id, 638 const std::string& resource_id,
673 const DownloadActionCallback& download_action_callback, 639 const DownloadActionCallback& download_action_callback,
674 const GetContentCallback& get_content_callback, 640 const GetContentCallback& get_content_callback,
675 const ProgressCallback& progress_callback) { 641 const ProgressCallback& progress_callback) {
676 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 642 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
677 DCHECK(!download_action_callback.is_null()); 643 DCHECK(!download_action_callback.is_null());
678 644
679 if (offline_) { 645 if (offline_) {
680 base::MessageLoop::current()->PostTask( 646 base::MessageLoop::current()->PostTask(
681 FROM_HERE, 647 FROM_HERE,
682 base::Bind(download_action_callback, 648 base::Bind(download_action_callback,
683 GDATA_NO_CONNECTION, 649 GDATA_NO_CONNECTION,
684 base::FilePath())); 650 base::FilePath()));
685 return CancelCallback(); 651 return CancelCallback();
686 } 652 }
687 653
688 // The field content.src is the URL to download the file. 654 EntryInfo* entry = FindEntryByResourceId(resource_id);
689 base::DictionaryValue* entry = FindEntryByResourceId(resource_id);
690 if (!entry) { 655 if (!entry) {
691 base::MessageLoopProxy::current()->PostTask( 656 base::MessageLoopProxy::current()->PostTask(
692 FROM_HERE, 657 FROM_HERE,
693 base::Bind(download_action_callback, HTTP_NOT_FOUND, base::FilePath())); 658 base::Bind(download_action_callback, HTTP_NOT_FOUND, base::FilePath()));
694 return CancelCallback(); 659 return CancelCallback();
695 } 660 }
696 661
697 // Write "x"s of the file size specified in the entry. 662 const FileResource* file = entry->change_resource.file();
698 std::string file_size_string; 663 const std::string& content_data = entry->content_data;
699 entry->GetString("docs$size.$t", &file_size_string); 664 int64 file_size = file->file_size();
700 int64 file_size = 0; 665 DCHECK_EQ(static_cast<size_t>(file_size), content_data.size());
701 if (base::StringToInt64(file_size_string, &file_size)) {
702 base::BinaryValue* content_binary_data;
703 std::string content_data;
704 if (entry->GetBinary("test$data", &content_binary_data)) {
705 content_data = std::string(content_binary_data->GetBuffer(),
706 content_binary_data->GetSize());
707 }
708 DCHECK_EQ(static_cast<size_t>(file_size), content_data.size());
709 666
710 if (!get_content_callback.is_null()) { 667 if (!get_content_callback.is_null()) {
711 const int64 kBlockSize = 5; 668 const int64 kBlockSize = 5;
712 for (int64 i = 0; i < file_size; i += kBlockSize) { 669 for (int64 i = 0; i < file_size; i += kBlockSize) {
713 const int64 size = std::min(kBlockSize, file_size - i); 670 const int64 size = std::min(kBlockSize, file_size - i);
714 scoped_ptr<std::string> content_for_callback( 671 scoped_ptr<std::string> content_for_callback(
715 new std::string(content_data.substr(i, size))); 672 new std::string(content_data.substr(i, size)));
716 base::MessageLoopProxy::current()->PostTask(
717 FROM_HERE,
718 base::Bind(get_content_callback, HTTP_SUCCESS,
719 base::Passed(&content_for_callback)));
720 }
721 }
722
723 if (test_util::WriteStringToFile(local_cache_path, content_data)) {
724 if (!progress_callback.is_null()) {
725 // See also the comment in ResumeUpload(). For testing that clients
726 // can handle the case progress_callback is called multiple times,
727 // here we invoke the callback twice.
728 base::MessageLoopProxy::current()->PostTask(
729 FROM_HERE,
730 base::Bind(progress_callback, file_size / 2, file_size));
731 base::MessageLoopProxy::current()->PostTask(
732 FROM_HERE,
733 base::Bind(progress_callback, file_size, file_size));
734 }
735 base::MessageLoopProxy::current()->PostTask( 673 base::MessageLoopProxy::current()->PostTask(
736 FROM_HERE, 674 FROM_HERE,
737 base::Bind(download_action_callback, 675 base::Bind(get_content_callback, HTTP_SUCCESS,
738 HTTP_SUCCESS, 676 base::Passed(&content_for_callback)));
739 local_cache_path));
740 return CancelCallback();
741 } 677 }
742 } 678 }
743 679
680 if (test_util::WriteStringToFile(local_cache_path, content_data)) {
681 if (!progress_callback.is_null()) {
682 // See also the comment in ResumeUpload(). For testing that clients
683 // can handle the case progress_callback is called multiple times,
684 // here we invoke the callback twice.
685 base::MessageLoopProxy::current()->PostTask(
686 FROM_HERE,
687 base::Bind(progress_callback, file_size / 2, file_size));
688 base::MessageLoopProxy::current()->PostTask(
689 FROM_HERE,
690 base::Bind(progress_callback, file_size, file_size));
691 }
692 base::MessageLoopProxy::current()->PostTask(
693 FROM_HERE,
694 base::Bind(download_action_callback,
695 HTTP_SUCCESS,
696 local_cache_path));
697 return CancelCallback();
698 }
699
744 // Failed to write the content. 700 // Failed to write the content.
745 base::MessageLoopProxy::current()->PostTask( 701 base::MessageLoopProxy::current()->PostTask(
746 FROM_HERE, 702 FROM_HERE,
747 base::Bind(download_action_callback, GDATA_FILE_ERROR, base::FilePath())); 703 base::Bind(download_action_callback, GDATA_FILE_ERROR, base::FilePath()));
748 return CancelCallback(); 704 return CancelCallback();
749 } 705 }
750 706
751 CancelCallback FakeDriveService::CopyResource( 707 CancelCallback FakeDriveService::CopyResource(
752 const std::string& resource_id, 708 const std::string& resource_id,
753 const std::string& in_parent_resource_id, 709 const std::string& in_parent_resource_id,
754 const std::string& new_title, 710 const std::string& new_title,
755 const base::Time& last_modified, 711 const base::Time& last_modified,
756 const GetResourceEntryCallback& callback) { 712 const GetResourceEntryCallback& callback) {
757 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 713 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
758 DCHECK(!callback.is_null()); 714 DCHECK(!callback.is_null());
759 715
760 if (offline_) { 716 if (offline_) {
761 scoped_ptr<ResourceEntry> null; 717 scoped_ptr<ResourceEntry> null;
762 base::MessageLoop::current()->PostTask( 718 base::MessageLoop::current()->PostTask(
763 FROM_HERE, 719 FROM_HERE,
764 base::Bind(callback, 720 base::Bind(callback,
765 GDATA_NO_CONNECTION, 721 GDATA_NO_CONNECTION,
766 base::Passed(&null))); 722 base::Passed(&null)));
767 return CancelCallback(); 723 return CancelCallback();
768 } 724 }
769 725
770 const std::string& parent_resource_id = in_parent_resource_id.empty() ? 726 const std::string& parent_resource_id = in_parent_resource_id.empty() ?
771 GetRootResourceId() : in_parent_resource_id; 727 GetRootResourceId() : in_parent_resource_id;
772 728
773 base::ListValue* entries = NULL; 729 EntryInfo* entry = FindEntryByResourceId(resource_id);
774 // Go through entries and copy the one that matches |resource_id|. 730 if (entry) {
775 if (resource_list_value_->GetList("entry", &entries)) { 731 // Make a copy and set the new resource ID and the new title.
776 for (size_t i = 0; i < entries->GetSize(); ++i) { 732 scoped_ptr<EntryInfo> copied_entry(new EntryInfo);
777 base::DictionaryValue* entry = NULL; 733 copied_entry->content_data = entry->content_data;
778 std::string current_resource_id; 734 copied_entry->share_url = entry->share_url;
779 if (entries->GetDictionary(i, &entry) &&
780 entry->GetString("gd$resourceId.$t", &current_resource_id) &&
781 resource_id == current_resource_id) {
782 // Make a copy and set the new resource ID and the new title.
783 scoped_ptr<base::DictionaryValue> copied_entry(entry->DeepCopy());
784 copied_entry->SetString("gd$resourceId.$t", GetNewResourceId());
785 copied_entry->SetString("title.$t", new_title);
786 735
787 // Reset parent directory. 736 // TODO(hashimoto): Implement a proper way to copy FileResource.
788 base::ListValue* links = NULL; 737 scoped_ptr<ResourceEntry> copied_resource_entry =
789 if (!copied_entry->GetList("link", &links)) { 738 util::ConvertChangeResourceToResourceEntry(entry->change_resource);
790 links = new base::ListValue; 739 copied_entry->change_resource.set_file(
791 copied_entry->Set("link", links); 740 util::ConvertResourceEntryToFileResource(*copied_resource_entry));
792 }
793 links->Clear();
794 741
795 base::DictionaryValue* link = new base::DictionaryValue; 742 ChangeResource* new_change = &copied_entry->change_resource;
796 link->SetString( 743 FileResource* new_file = new_change->mutable_file();
797 "rel", "http://schemas.google.com/docs/2007#parent"); 744 const std::string new_resource_id = GetNewResourceId();
798 link->SetString("href", GetFakeLinkUrl(parent_resource_id).spec()); 745 new_change->set_file_id(new_resource_id);
799 links->Append(link); 746 new_file->set_file_id(new_resource_id);
747 new_file->set_title(new_title);
800 748
801 if (!last_modified.is_null()) { 749 scoped_ptr<ParentReference> parent(new ParentReference);
802 copied_entry->SetString( 750 parent->set_file_id(parent_resource_id);
803 "updated.$t", 751 parent->set_parent_link(GetFakeLinkUrl(parent_resource_id));
804 google_apis::util::FormatTimeAsString(last_modified)); 752 parent->set_is_root(parent_resource_id == GetRootResourceId());
805 } 753 ScopedVector<ParentReference> parents;
754 parents.push_back(parent.release());
755 new_file->set_parents(parents.Pass());
806 756
807 AddNewChangestamp(copied_entry.get()); 757 if (!last_modified.is_null())
808 UpdateETag(copied_entry.get()); 758 new_file->set_modified_date(last_modified);
809 759
810 // Parse the new entry. 760 AddNewChangestamp(new_change);
811 scoped_ptr<ResourceEntry> resource_entry = 761 UpdateETag(new_file);
812 ResourceEntry::CreateFrom(*copied_entry);
813 // Add it to the resource list.
814 entries->Append(copied_entry.release());
815 762
816 base::MessageLoop::current()->PostTask( 763 scoped_ptr<ResourceEntry> resource_entry =
817 FROM_HERE, 764 util::ConvertChangeResourceToResourceEntry(*new_change);
818 base::Bind(callback, 765 // Add the new entry to the map.
819 HTTP_SUCCESS, 766 entries_[new_resource_id] = copied_entry.release();
820 base::Passed(&resource_entry))); 767
821 return CancelCallback(); 768 base::MessageLoop::current()->PostTask(
822 } 769 FROM_HERE,
823 } 770 base::Bind(callback,
771 HTTP_SUCCESS,
772 base::Passed(&resource_entry)));
773 return CancelCallback();
824 } 774 }
825 775
826 scoped_ptr<ResourceEntry> null; 776 scoped_ptr<ResourceEntry> null;
827 base::MessageLoop::current()->PostTask( 777 base::MessageLoop::current()->PostTask(
828 FROM_HERE, 778 FROM_HERE,
829 base::Bind(callback, HTTP_NOT_FOUND, base::Passed(&null))); 779 base::Bind(callback, HTTP_NOT_FOUND, base::Passed(&null)));
830 return CancelCallback(); 780 return CancelCallback();
831 } 781 }
832 782
833 CancelCallback FakeDriveService::UpdateResource( 783 CancelCallback FakeDriveService::UpdateResource(
834 const std::string& resource_id, 784 const std::string& resource_id,
835 const std::string& parent_resource_id, 785 const std::string& parent_resource_id,
836 const std::string& new_title, 786 const std::string& new_title,
837 const base::Time& last_modified, 787 const base::Time& last_modified,
838 const base::Time& last_viewed_by_me, 788 const base::Time& last_viewed_by_me,
839 const google_apis::GetResourceEntryCallback& callback) { 789 const google_apis::GetResourceEntryCallback& callback) {
840 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 790 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
841 DCHECK(!callback.is_null()); 791 DCHECK(!callback.is_null());
842 792
843 if (offline_) { 793 if (offline_) {
844 base::MessageLoop::current()->PostTask( 794 base::MessageLoop::current()->PostTask(
845 FROM_HERE, base::Bind(callback, GDATA_NO_CONNECTION, 795 FROM_HERE, base::Bind(callback, GDATA_NO_CONNECTION,
846 base::Passed(scoped_ptr<ResourceEntry>()))); 796 base::Passed(scoped_ptr<ResourceEntry>())));
847 return CancelCallback(); 797 return CancelCallback();
848 } 798 }
849 799
850 base::DictionaryValue* entry = FindEntryByResourceId(resource_id); 800 EntryInfo* entry = FindEntryByResourceId(resource_id);
851 if (entry) { 801 if (entry) {
852 entry->SetString("title.$t", new_title); 802 ChangeResource* change = &entry->change_resource;
803 FileResource* file = change->mutable_file();
804 file->set_title(new_title);
853 805
854 // Set parent if necessary. 806 // Set parent if necessary.
855 if (!parent_resource_id.empty()) { 807 if (!parent_resource_id.empty()) {
856 base::ListValue* links = NULL; 808 scoped_ptr<ParentReference> parent(new ParentReference);
857 if (!entry->GetList("link", &links)) { 809 parent->set_file_id(parent_resource_id);
858 links = new base::ListValue; 810 parent->set_parent_link(GetFakeLinkUrl(parent_resource_id));
859 entry->Set("link", links); 811 parent->set_is_root(parent_resource_id == GetRootResourceId());
860 }
861 812
862 // Remove old parent(s). 813 ScopedVector<ParentReference> parents;
863 for (size_t i = 0; i < links->GetSize(); ) { 814 parents.push_back(parent.release());
864 base::DictionaryValue* link = NULL; 815 file->set_parents(parents.Pass());
865 std::string rel;
866 std::string href;
867 if (links->GetDictionary(i, &link) &&
868 link->GetString("rel", &rel) &&
869 link->GetString("href", &href) &&
870 rel == "http://schemas.google.com/docs/2007#parent") {
871 links->Remove(i, NULL);
872 } else {
873 ++i;
874 }
875 }
876
877 base::DictionaryValue* link = new base::DictionaryValue;
878 link->SetString("rel", "http://schemas.google.com/docs/2007#parent");
879 link->SetString(
880 "href", GetFakeLinkUrl(parent_resource_id).spec());
881 links->Append(link);
882 } 816 }
883 817
884 if (!last_modified.is_null()) { 818 if (!last_modified.is_null())
885 entry->SetString( 819 file->set_modified_date(last_modified);
886 "updated.$t",
887 google_apis::util::FormatTimeAsString(last_modified));
888 }
889 820
890 if (!last_viewed_by_me.is_null()) { 821 if (!last_viewed_by_me.is_null())
891 entry->SetString( 822 file->set_last_viewed_by_me_date(last_viewed_by_me);
892 "gd$lastViewed.$t",
893 google_apis::util::FormatTimeAsString(last_viewed_by_me));
894 }
895 823
896 AddNewChangestamp(entry); 824 AddNewChangestamp(change);
897 UpdateETag(entry); 825 UpdateETag(file);
898 826
899 // Parse the new entry.
900 scoped_ptr<ResourceEntry> resource_entry = 827 scoped_ptr<ResourceEntry> resource_entry =
901 ResourceEntry::CreateFrom(*entry); 828 util::ConvertChangeResourceToResourceEntry(*change);
902 base::MessageLoop::current()->PostTask( 829 base::MessageLoop::current()->PostTask(
903 FROM_HERE, 830 FROM_HERE,
904 base::Bind(callback, HTTP_SUCCESS, base::Passed(&resource_entry))); 831 base::Bind(callback, HTTP_SUCCESS, base::Passed(&resource_entry)));
905 return CancelCallback(); 832 return CancelCallback();
906 } 833 }
907 834
908 base::MessageLoop::current()->PostTask( 835 base::MessageLoop::current()->PostTask(
909 FROM_HERE, 836 FROM_HERE,
910 base::Bind(callback, HTTP_NOT_FOUND, 837 base::Bind(callback, HTTP_NOT_FOUND,
911 base::Passed(scoped_ptr<ResourceEntry>()))); 838 base::Passed(scoped_ptr<ResourceEntry>())));
(...skipping 18 matching lines...) Expand all
930 const EntryActionCallback& callback) { 857 const EntryActionCallback& callback) {
931 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 858 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
932 DCHECK(!callback.is_null()); 859 DCHECK(!callback.is_null());
933 860
934 if (offline_) { 861 if (offline_) {
935 base::MessageLoop::current()->PostTask( 862 base::MessageLoop::current()->PostTask(
936 FROM_HERE, base::Bind(callback, GDATA_NO_CONNECTION)); 863 FROM_HERE, base::Bind(callback, GDATA_NO_CONNECTION));
937 return CancelCallback(); 864 return CancelCallback();
938 } 865 }
939 866
940 base::DictionaryValue* entry = FindEntryByResourceId(resource_id); 867 EntryInfo* entry = FindEntryByResourceId(resource_id);
941 if (entry) { 868 if (entry) {
942 base::ListValue* links = NULL; 869 ChangeResource* change = &entry->change_resource;
943 if (!entry->GetList("link", &links)) {
944 links = new base::ListValue;
945 entry->Set("link", links);
946 }
947
948 // On the real Drive server, resources do not necessary shape a tree 870 // On the real Drive server, resources do not necessary shape a tree
949 // structure. That is, each resource can have multiple parent. 871 // structure. That is, each resource can have multiple parent.
950 // We mimic the behavior here; AddResourceToDirectoy just adds 872 // We mimic the behavior here; AddResourceToDirectoy just adds
951 // one more parent link, not overwriting old links. 873 // one more parent, not overwriting old ones.
952 base::DictionaryValue* link = new base::DictionaryValue; 874 scoped_ptr<ParentReference> parent(new ParentReference);
953 link->SetString("rel", "http://schemas.google.com/docs/2007#parent"); 875 parent->set_file_id(parent_resource_id);
954 link->SetString( 876 parent->set_parent_link(GetFakeLinkUrl(parent_resource_id));
955 "href", GetFakeLinkUrl(parent_resource_id).spec()); 877 parent->set_is_root(parent_resource_id == GetRootResourceId());
956 links->Append(link); 878 change->mutable_file()->mutable_parents()->push_back(parent.release());
957 879
958 AddNewChangestamp(entry); 880 AddNewChangestamp(change);
959 base::MessageLoop::current()->PostTask( 881 base::MessageLoop::current()->PostTask(
960 FROM_HERE, base::Bind(callback, HTTP_SUCCESS)); 882 FROM_HERE, base::Bind(callback, HTTP_SUCCESS));
961 return CancelCallback(); 883 return CancelCallback();
962 } 884 }
963 885
964 base::MessageLoop::current()->PostTask( 886 base::MessageLoop::current()->PostTask(
965 FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND)); 887 FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND));
966 return CancelCallback(); 888 return CancelCallback();
967 } 889 }
968 890
969 CancelCallback FakeDriveService::RemoveResourceFromDirectory( 891 CancelCallback FakeDriveService::RemoveResourceFromDirectory(
970 const std::string& parent_resource_id, 892 const std::string& parent_resource_id,
971 const std::string& resource_id, 893 const std::string& resource_id,
972 const EntryActionCallback& callback) { 894 const EntryActionCallback& callback) {
973 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 895 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
974 DCHECK(!callback.is_null()); 896 DCHECK(!callback.is_null());
975 897
976 if (offline_) { 898 if (offline_) {
977 base::MessageLoop::current()->PostTask( 899 base::MessageLoop::current()->PostTask(
978 FROM_HERE, base::Bind(callback, GDATA_NO_CONNECTION)); 900 FROM_HERE, base::Bind(callback, GDATA_NO_CONNECTION));
979 return CancelCallback(); 901 return CancelCallback();
980 } 902 }
981 903
982 base::DictionaryValue* entry = FindEntryByResourceId(resource_id); 904 EntryInfo* entry = FindEntryByResourceId(resource_id);
983 if (entry) { 905 if (entry) {
984 base::ListValue* links = NULL; 906 ChangeResource* change = &entry->change_resource;
985 if (entry->GetList("link", &links)) { 907 FileResource* file = change->mutable_file();
986 GURL parent_content_url = GetFakeLinkUrl(parent_resource_id); 908 ScopedVector<ParentReference>* parents = file->mutable_parents();
987 for (size_t i = 0; i < links->GetSize(); ++i) { 909 for (size_t i = 0; i < parents->size(); ++i) {
988 base::DictionaryValue* link = NULL; 910 if ((*parents)[i]->file_id() == parent_resource_id) {
989 std::string rel; 911 parents->erase(parents->begin() + i);
990 std::string href; 912 AddNewChangestamp(change);
991 if (links->GetDictionary(i, &link) && 913 base::MessageLoop::current()->PostTask(
992 link->GetString("rel", &rel) && 914 FROM_HERE, base::Bind(callback, HTTP_NO_CONTENT));
993 link->GetString("href", &href) && 915 return CancelCallback();
994 rel == "http://schemas.google.com/docs/2007#parent" &&
995 GURL(href) == parent_content_url) {
996 links->Remove(i, NULL);
997 AddNewChangestamp(entry);
998 base::MessageLoop::current()->PostTask(
999 FROM_HERE, base::Bind(callback, HTTP_NO_CONTENT));
1000 return CancelCallback();
1001 }
1002 } 916 }
1003 } 917 }
1004 } 918 }
1005 919
1006 base::MessageLoop::current()->PostTask( 920 base::MessageLoop::current()->PostTask(
1007 FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND)); 921 FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND));
1008 return CancelCallback(); 922 return CancelCallback();
1009 } 923 }
1010 924
1011 CancelCallback FakeDriveService::AddNewDirectory( 925 CancelCallback FakeDriveService::AddNewDirectory(
1012 const std::string& parent_resource_id, 926 const std::string& parent_resource_id,
1013 const std::string& directory_title, 927 const std::string& directory_title,
1014 const GetResourceEntryCallback& callback) { 928 const GetResourceEntryCallback& callback) {
1015 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 929 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1016 DCHECK(!callback.is_null()); 930 DCHECK(!callback.is_null());
1017 931
1018 if (offline_) { 932 if (offline_) {
1019 scoped_ptr<ResourceEntry> null; 933 scoped_ptr<ResourceEntry> null;
1020 base::MessageLoop::current()->PostTask( 934 base::MessageLoop::current()->PostTask(
1021 FROM_HERE, 935 FROM_HERE,
1022 base::Bind(callback, 936 base::Bind(callback,
1023 GDATA_NO_CONNECTION, 937 GDATA_NO_CONNECTION,
1024 base::Passed(&null))); 938 base::Passed(&null)));
1025 return CancelCallback(); 939 return CancelCallback();
1026 } 940 }
1027 941
1028 const char kContentType[] = "application/atom+xml;type=feed"; 942 const EntryInfo* new_entry = AddNewEntry(kDriveFolderMimeType,
1029 const base::DictionaryValue* new_entry = AddNewEntry(kContentType, 943 "", // content_data
1030 "", // content_data 944 parent_resource_id,
1031 parent_resource_id, 945 directory_title,
1032 directory_title, 946 false); // shared_with_me
1033 false, // shared_with_me
1034 "folder");
1035 if (!new_entry) { 947 if (!new_entry) {
1036 scoped_ptr<ResourceEntry> null; 948 scoped_ptr<ResourceEntry> null;
1037 base::MessageLoop::current()->PostTask( 949 base::MessageLoop::current()->PostTask(
1038 FROM_HERE, 950 FROM_HERE,
1039 base::Bind(callback, HTTP_NOT_FOUND, base::Passed(&null))); 951 base::Bind(callback, HTTP_NOT_FOUND, base::Passed(&null)));
1040 return CancelCallback(); 952 return CancelCallback();
1041 } 953 }
1042 954
1043 scoped_ptr<ResourceEntry> parsed_entry(ResourceEntry::CreateFrom(*new_entry)); 955 scoped_ptr<ResourceEntry> parsed_entry(
956 util::ConvertChangeResourceToResourceEntry(new_entry->change_resource));
1044 base::MessageLoop::current()->PostTask( 957 base::MessageLoop::current()->PostTask(
1045 FROM_HERE, 958 FROM_HERE,
1046 base::Bind(callback, HTTP_CREATED, base::Passed(&parsed_entry))); 959 base::Bind(callback, HTTP_CREATED, base::Passed(&parsed_entry)));
1047 return CancelCallback(); 960 return CancelCallback();
1048 } 961 }
1049 962
1050 CancelCallback FakeDriveService::InitiateUploadNewFile( 963 CancelCallback FakeDriveService::InitiateUploadNewFile(
1051 const std::string& content_type, 964 const std::string& content_type,
1052 int64 content_length, 965 int64 content_length,
1053 const std::string& parent_resource_id, 966 const std::string& parent_resource_id,
1054 const std::string& title, 967 const std::string& title,
1055 const InitiateUploadCallback& callback) { 968 const InitiateUploadCallback& callback) {
1056 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 969 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1057 DCHECK(!callback.is_null()); 970 DCHECK(!callback.is_null());
1058 971
1059 if (offline_) { 972 if (offline_) {
1060 base::MessageLoop::current()->PostTask( 973 base::MessageLoop::current()->PostTask(
1061 FROM_HERE, 974 FROM_HERE,
1062 base::Bind(callback, GDATA_NO_CONNECTION, GURL())); 975 base::Bind(callback, GDATA_NO_CONNECTION, GURL()));
1063 return CancelCallback(); 976 return CancelCallback();
1064 } 977 }
1065 978
1066 if (parent_resource_id != GetRootResourceId() && 979 if (parent_resource_id != GetRootResourceId() &&
1067 !FindEntryByResourceId(parent_resource_id)) { 980 !entries_.count(parent_resource_id)) {
1068 base::MessageLoop::current()->PostTask( 981 base::MessageLoop::current()->PostTask(
1069 FROM_HERE, 982 FROM_HERE,
1070 base::Bind(callback, HTTP_NOT_FOUND, GURL())); 983 base::Bind(callback, HTTP_NOT_FOUND, GURL()));
1071 return CancelCallback(); 984 return CancelCallback();
1072 } 985 }
1073 986
1074 GURL session_url = GetNewUploadSessionUrl(); 987 GURL session_url = GetNewUploadSessionUrl();
1075 upload_sessions_[session_url] = 988 upload_sessions_[session_url] =
1076 UploadSession(content_type, content_length, 989 UploadSession(content_type, content_length,
1077 parent_resource_id, 990 parent_resource_id,
(...skipping 16 matching lines...) Expand all
1094 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1007 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1095 DCHECK(!callback.is_null()); 1008 DCHECK(!callback.is_null());
1096 1009
1097 if (offline_) { 1010 if (offline_) {
1098 base::MessageLoop::current()->PostTask( 1011 base::MessageLoop::current()->PostTask(
1099 FROM_HERE, 1012 FROM_HERE,
1100 base::Bind(callback, GDATA_NO_CONNECTION, GURL())); 1013 base::Bind(callback, GDATA_NO_CONNECTION, GURL()));
1101 return CancelCallback(); 1014 return CancelCallback();
1102 } 1015 }
1103 1016
1104 base::DictionaryValue* entry = FindEntryByResourceId(resource_id); 1017 EntryInfo* entry = FindEntryByResourceId(resource_id);
1105 if (!entry) { 1018 if (!entry) {
1106 base::MessageLoop::current()->PostTask( 1019 base::MessageLoop::current()->PostTask(
1107 FROM_HERE, 1020 FROM_HERE,
1108 base::Bind(callback, HTTP_NOT_FOUND, GURL())); 1021 base::Bind(callback, HTTP_NOT_FOUND, GURL()));
1109 return CancelCallback(); 1022 return CancelCallback();
1110 } 1023 }
1111 1024
1112 std::string entry_etag; 1025 const FileResource* file = entry->change_resource.file();
1113 entry->GetString("gd$etag", &entry_etag); 1026 if (!etag.empty() && etag != file->etag()) {
1114 if (!etag.empty() && etag != entry_etag) {
1115 base::MessageLoop::current()->PostTask( 1027 base::MessageLoop::current()->PostTask(
1116 FROM_HERE, 1028 FROM_HERE,
1117 base::Bind(callback, HTTP_PRECONDITION, GURL())); 1029 base::Bind(callback, HTTP_PRECONDITION, GURL()));
1118 return CancelCallback(); 1030 return CancelCallback();
1119 } 1031 }
1120 1032
1121 GURL session_url = GetNewUploadSessionUrl(); 1033 GURL session_url = GetNewUploadSessionUrl();
1122 upload_sessions_[session_url] = 1034 upload_sessions_[session_url] =
1123 UploadSession(content_type, content_length, 1035 UploadSession(content_type, content_length,
1124 "", // parent_resource_id 1036 "", // parent_resource_id
1125 resource_id, 1037 resource_id,
1126 entry_etag, 1038 file->etag(),
1127 "" /* title */); 1039 "" /* title */);
1128 1040
1129 base::MessageLoop::current()->PostTask( 1041 base::MessageLoop::current()->PostTask(
1130 FROM_HERE, 1042 FROM_HERE,
1131 base::Bind(callback, HTTP_SUCCESS, session_url)); 1043 base::Bind(callback, HTTP_SUCCESS, session_url));
1132 return CancelCallback(); 1044 return CancelCallback();
1133 } 1045 }
1134 1046
1135 CancelCallback FakeDriveService::GetUploadStatus( 1047 CancelCallback FakeDriveService::GetUploadStatus(
1136 const GURL& upload_url, 1048 const GURL& upload_url,
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
1202 session->uploaded_size = end_position; 1114 session->uploaded_size = end_position;
1203 completion_callback.Run(GDATA_FILE_ERROR, scoped_ptr<ResourceEntry>()); 1115 completion_callback.Run(GDATA_FILE_ERROR, scoped_ptr<ResourceEntry>());
1204 return CancelCallback(); 1116 return CancelCallback();
1205 } 1117 }
1206 session->uploaded_size = end_position; 1118 session->uploaded_size = end_position;
1207 1119
1208 // |resource_id| is empty if the upload is for new file. 1120 // |resource_id| is empty if the upload is for new file.
1209 if (session->resource_id.empty()) { 1121 if (session->resource_id.empty()) {
1210 DCHECK(!session->parent_resource_id.empty()); 1122 DCHECK(!session->parent_resource_id.empty());
1211 DCHECK(!session->title.empty()); 1123 DCHECK(!session->title.empty());
1212 const base::DictionaryValue* new_entry = AddNewEntry( 1124 const EntryInfo* new_entry = AddNewEntry(
1213 session->content_type, 1125 session->content_type,
1214 content_data, 1126 content_data,
1215 session->parent_resource_id, 1127 session->parent_resource_id,
1216 session->title, 1128 session->title,
1217 false, // shared_with_me 1129 false); // shared_with_me
1218 "file");
1219 if (!new_entry) { 1130 if (!new_entry) {
1220 completion_callback.Run(HTTP_NOT_FOUND, scoped_ptr<ResourceEntry>()); 1131 completion_callback.Run(HTTP_NOT_FOUND, scoped_ptr<ResourceEntry>());
1221 return CancelCallback(); 1132 return CancelCallback();
1222 } 1133 }
1223 1134
1224 completion_callback.Run(HTTP_CREATED, 1135 completion_callback.Run(
1225 ResourceEntry::CreateFrom(*new_entry)); 1136 HTTP_CREATED,
1137 util::ConvertChangeResourceToResourceEntry(new_entry->change_resource));
1226 return CancelCallback(); 1138 return CancelCallback();
1227 } 1139 }
1228 1140
1229 base::DictionaryValue* entry = FindEntryByResourceId(session->resource_id); 1141 EntryInfo* entry = FindEntryByResourceId(session->resource_id);
1230 if (!entry) { 1142 if (!entry) {
1231 completion_callback.Run(HTTP_NOT_FOUND, scoped_ptr<ResourceEntry>()); 1143 completion_callback.Run(HTTP_NOT_FOUND, scoped_ptr<ResourceEntry>());
1232 return CancelCallback(); 1144 return CancelCallback();
1233 } 1145 }
1234 1146
1235 std::string entry_etag; 1147 ChangeResource* change = &entry->change_resource;
1236 entry->GetString("gd$etag", &entry_etag); 1148 FileResource* file = change->mutable_file();
1237 if (entry_etag.empty() || session->etag != entry_etag) { 1149 if (file->etag().empty() || session->etag != file->etag()) {
1238 completion_callback.Run(HTTP_PRECONDITION, scoped_ptr<ResourceEntry>()); 1150 completion_callback.Run(HTTP_PRECONDITION, scoped_ptr<ResourceEntry>());
1239 return CancelCallback(); 1151 return CancelCallback();
1240 } 1152 }
1241 1153
1242 entry->SetString("docs$md5Checksum.$t", base::MD5String(content_data)); 1154 file->set_md5_checksum(base::MD5String(content_data));
1243 entry->Set("test$data", 1155 entry->content_data = content_data;
1244 base::BinaryValue::CreateWithCopiedBuffer( 1156 file->set_file_size(end_position);
1245 content_data.data(), content_data.size())); 1157 AddNewChangestamp(change);
1246 entry->SetString("docs$size.$t", base::Int64ToString(end_position)); 1158 UpdateETag(file);
1247 AddNewChangestamp(entry);
1248 UpdateETag(entry);
1249 1159
1250 completion_callback.Run(HTTP_SUCCESS, ResourceEntry::CreateFrom(*entry)); 1160 completion_callback.Run(HTTP_SUCCESS,
1161 util::ConvertChangeResourceToResourceEntry(*change));
1251 return CancelCallback(); 1162 return CancelCallback();
1252 } 1163 }
1253 1164
1254 CancelCallback FakeDriveService::AuthorizeApp( 1165 CancelCallback FakeDriveService::AuthorizeApp(
1255 const std::string& resource_id, 1166 const std::string& resource_id,
1256 const std::string& app_id, 1167 const std::string& app_id,
1257 const AuthorizeAppCallback& callback) { 1168 const AuthorizeAppCallback& callback) {
1258 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1169 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1259 DCHECK(!callback.is_null()); 1170 DCHECK(!callback.is_null());
1260 return CancelCallback(); 1171 return CancelCallback();
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
1361 if (offline_) { 1272 if (offline_) {
1362 scoped_ptr<ResourceEntry> null; 1273 scoped_ptr<ResourceEntry> null;
1363 base::MessageLoop::current()->PostTask( 1274 base::MessageLoop::current()->PostTask(
1364 FROM_HERE, 1275 FROM_HERE,
1365 base::Bind(callback, 1276 base::Bind(callback,
1366 GDATA_NO_CONNECTION, 1277 GDATA_NO_CONNECTION,
1367 base::Passed(&null))); 1278 base::Passed(&null)));
1368 return; 1279 return;
1369 } 1280 }
1370 1281
1371 // Prepare "kind" for hosted documents. This only supports Google Document. 1282 const EntryInfo* new_entry = AddNewEntry(content_type,
1372 std::string entry_kind; 1283 content_data,
1373 if (content_type == "application/vnd.google-apps.document") 1284 parent_resource_id,
1374 entry_kind = "document"; 1285 title,
1375 else 1286 shared_with_me);
1376 entry_kind = "file";
1377
1378 const base::DictionaryValue* new_entry = AddNewEntry(content_type,
1379 content_data,
1380 parent_resource_id,
1381 title,
1382 shared_with_me,
1383 entry_kind);
1384 if (!new_entry) { 1287 if (!new_entry) {
1385 scoped_ptr<ResourceEntry> null; 1288 scoped_ptr<ResourceEntry> null;
1386 base::MessageLoop::current()->PostTask( 1289 base::MessageLoop::current()->PostTask(
1387 FROM_HERE, 1290 FROM_HERE,
1388 base::Bind(callback, HTTP_NOT_FOUND, base::Passed(&null))); 1291 base::Bind(callback, HTTP_NOT_FOUND, base::Passed(&null)));
1389 return; 1292 return;
1390 } 1293 }
1391 1294
1392 scoped_ptr<ResourceEntry> parsed_entry( 1295 scoped_ptr<ResourceEntry> parsed_entry(
1393 ResourceEntry::CreateFrom(*new_entry)); 1296 util::ConvertChangeResourceToResourceEntry(new_entry->change_resource));
1394 base::MessageLoop::current()->PostTask( 1297 base::MessageLoop::current()->PostTask(
1395 FROM_HERE, 1298 FROM_HERE,
1396 base::Bind(callback, HTTP_CREATED, base::Passed(&parsed_entry))); 1299 base::Bind(callback, HTTP_CREATED, base::Passed(&parsed_entry)));
1397 } 1300 }
1398 1301
1399 void FakeDriveService::SetLastModifiedTime( 1302 void FakeDriveService::SetLastModifiedTime(
1400 const std::string& resource_id, 1303 const std::string& resource_id,
1401 const base::Time& last_modified_time, 1304 const base::Time& last_modified_time,
1402 const GetResourceEntryCallback& callback) { 1305 const GetResourceEntryCallback& callback) {
1403 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1306 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1404 DCHECK(!callback.is_null()); 1307 DCHECK(!callback.is_null());
1405 1308
1406 if (offline_) { 1309 if (offline_) {
1407 scoped_ptr<ResourceEntry> null; 1310 scoped_ptr<ResourceEntry> null;
1408 base::MessageLoop::current()->PostTask( 1311 base::MessageLoop::current()->PostTask(
1409 FROM_HERE, 1312 FROM_HERE,
1410 base::Bind(callback, 1313 base::Bind(callback,
1411 GDATA_NO_CONNECTION, 1314 GDATA_NO_CONNECTION,
1412 base::Passed(&null))); 1315 base::Passed(&null)));
1413 return; 1316 return;
1414 } 1317 }
1415 1318
1416 base::DictionaryValue* entry = FindEntryByResourceId(resource_id); 1319 EntryInfo* entry = FindEntryByResourceId(resource_id);
1417 if (!entry) { 1320 if (!entry) {
1418 scoped_ptr<ResourceEntry> null; 1321 scoped_ptr<ResourceEntry> null;
1419 base::MessageLoop::current()->PostTask( 1322 base::MessageLoop::current()->PostTask(
1420 FROM_HERE, 1323 FROM_HERE,
1421 base::Bind(callback, HTTP_NOT_FOUND, base::Passed(&null))); 1324 base::Bind(callback, HTTP_NOT_FOUND, base::Passed(&null)));
1422 return; 1325 return;
1423 } 1326 }
1424 1327
1425 if (last_modified_time.is_null()) { 1328 ChangeResource* change = &entry->change_resource;
1426 entry->Remove("updated.$t", NULL); 1329 FileResource* file = change->mutable_file();
1427 } else { 1330 file->set_modified_date(last_modified_time);
1428 entry->SetString(
1429 "updated.$t",
1430 google_apis::util::FormatTimeAsString(last_modified_time));
1431 }
1432 1331
1433 scoped_ptr<ResourceEntry> parsed_entry( 1332 scoped_ptr<ResourceEntry> parsed_entry(
1434 ResourceEntry::CreateFrom(*entry)); 1333 util::ConvertChangeResourceToResourceEntry(*change));
1435 base::MessageLoop::current()->PostTask( 1334 base::MessageLoop::current()->PostTask(
1436 FROM_HERE, 1335 FROM_HERE,
1437 base::Bind(callback, HTTP_SUCCESS, base::Passed(&parsed_entry))); 1336 base::Bind(callback, HTTP_SUCCESS, base::Passed(&parsed_entry)));
1438 } 1337 }
1439 1338
1440 base::DictionaryValue* FakeDriveService::FindEntryByResourceId( 1339 FakeDriveService::EntryInfo* FakeDriveService::FindEntryByResourceId(
1441 const std::string& resource_id) { 1340 const std::string& resource_id) {
1442 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1341 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1443 1342
1444 base::ListValue* entries = NULL; 1343 EntryInfoMap::iterator it = entries_.find(resource_id);
1445 // Go through entries and return the one that matches |resource_id|. 1344 // Deleted entries don't have FileResource.
1446 if (resource_list_value_->GetList("entry", &entries)) { 1345 return it != entries_.end() && it->second->change_resource.file() ?
1447 for (size_t i = 0; i < entries->GetSize(); ++i) { 1346 it->second : NULL;
1448 base::DictionaryValue* entry = NULL;
1449 std::string current_resource_id;
1450 if (entries->GetDictionary(i, &entry) &&
1451 entry->GetString("gd$resourceId.$t", &current_resource_id) &&
1452 resource_id == current_resource_id &&
1453 !entry->HasKey("docs$removed")) {
1454 return entry;
1455 }
1456 }
1457 }
1458
1459 return NULL;
1460 }
1461
1462 base::DictionaryValue* FakeDriveService::FindEntryByContentUrl(
1463 const GURL& content_url) {
1464 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1465
1466 base::ListValue* entries = NULL;
1467 // Go through entries and return the one that matches |content_url|.
1468 if (resource_list_value_->GetList("entry", &entries)) {
1469 for (size_t i = 0; i < entries->GetSize(); ++i) {
1470 base::DictionaryValue* entry = NULL;
1471 std::string current_content_url;
1472 if (entries->GetDictionary(i, &entry) &&
1473 entry->GetString("content.src", &current_content_url) &&
1474 content_url == GURL(current_content_url)) {
1475 return entry;
1476 }
1477 }
1478 }
1479
1480 return NULL;
1481 } 1347 }
1482 1348
1483 std::string FakeDriveService::GetNewResourceId() { 1349 std::string FakeDriveService::GetNewResourceId() {
1484 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1350 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1485 1351
1486 ++resource_id_count_; 1352 ++resource_id_count_;
1487 return base::StringPrintf("resource_id_%d", resource_id_count_); 1353 return base::StringPrintf("resource_id_%d", resource_id_count_);
1488 } 1354 }
1489 1355
1490 void FakeDriveService::UpdateETag(base::DictionaryValue* entry) { 1356 void FakeDriveService::UpdateETag(google_apis::FileResource* file) {
1491 entry->SetString("gd$etag", 1357 file->set_etag("etag_" + base::Int64ToString(largest_changestamp_));
1492 "etag_" + base::Int64ToString(largest_changestamp_));
1493 } 1358 }
1494 1359
1495 void FakeDriveService::AddNewChangestamp(base::DictionaryValue* entry) { 1360 void FakeDriveService::AddNewChangestamp(google_apis::ChangeResource* change) {
1496 ++largest_changestamp_; 1361 ++largest_changestamp_;
1497 entry->SetString("docs$changestamp.value", 1362 change->set_change_id(largest_changestamp_);
1498 base::Int64ToString(largest_changestamp_));
1499 } 1363 }
1500 1364
1501 const base::DictionaryValue* FakeDriveService::AddNewEntry( 1365 const FakeDriveService::EntryInfo* FakeDriveService::AddNewEntry(
1502 const std::string& content_type, 1366 const std::string& content_type,
1503 const std::string& content_data, 1367 const std::string& content_data,
1504 const std::string& parent_resource_id, 1368 const std::string& parent_resource_id,
1505 const std::string& title, 1369 const std::string& title,
1506 bool shared_with_me, 1370 bool shared_with_me) {
1507 const std::string& entry_kind) {
1508 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1371 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1509 1372
1510 if (!parent_resource_id.empty() && 1373 if (!parent_resource_id.empty() &&
1511 parent_resource_id != GetRootResourceId() && 1374 parent_resource_id != GetRootResourceId() &&
1512 !FindEntryByResourceId(parent_resource_id)) { 1375 !entries_.count(parent_resource_id)) {
1513 return NULL; 1376 return NULL;
1514 } 1377 }
1515 1378
1516 std::string resource_id = GetNewResourceId(); 1379 std::string resource_id = GetNewResourceId();
1517 GURL upload_url = GURL("https://xxx/upload/" + resource_id); 1380 GURL upload_url = GURL("https://xxx/upload/" + resource_id);
1518 1381
1519 scoped_ptr<base::DictionaryValue> new_entry(new base::DictionaryValue); 1382 scoped_ptr<EntryInfo> new_entry(new EntryInfo);
1383 ChangeResource* new_change = &new_entry->change_resource;
1384 FileResource* new_file = new FileResource;
1385 new_change->set_file(make_scoped_ptr(new_file));
1386
1520 // Set the resource ID and the title 1387 // Set the resource ID and the title
1521 new_entry->SetString("gd$resourceId.$t", resource_id); 1388 new_change->set_file_id(resource_id);
1522 new_entry->SetString("title.$t", title); 1389 new_file->set_file_id(resource_id);
1523 new_entry->SetString("docs$filename", title); 1390 new_file->set_title(title);
1524 // Set the contents, size and MD5 for a file. 1391 // Set the contents, size and MD5 for a file.
1525 if (entry_kind == "file") { 1392 if (content_type != kDriveFolderMimeType) {
1526 new_entry->Set("test$data", 1393 new_entry->content_data = content_data;
1527 base::BinaryValue::CreateWithCopiedBuffer( 1394 new_file->set_file_size(content_data.size());
1528 content_data.c_str(), content_data.size())); 1395 new_file->set_md5_checksum(base::MD5String(content_data));
1529 new_entry->SetString("docs$size.$t",
1530 base::Int64ToString(content_data.size()));
1531 new_entry->SetString("docs$md5Checksum.$t",
1532 base::MD5String(content_data));
1533 } 1396 }
1534 1397
1535 // Add "category" which sets the resource type to |entry_kind|.
1536 base::ListValue* categories = new base::ListValue;
1537 base::DictionaryValue* category = new base::DictionaryValue;
1538 category->SetString("scheme", "http://schemas.google.com/g/2005#kind");
1539 category->SetString("term", "http://schemas.google.com/docs/2007#" +
1540 entry_kind);
1541 categories->Append(category);
1542 new_entry->Set("category", categories);
1543 if (shared_with_me) { 1398 if (shared_with_me) {
1544 base::DictionaryValue* shared_with_me_label = new base::DictionaryValue; 1399 // Set current time to mark the file as shared_with_me.
1545 shared_with_me_label->SetString("label", "shared-with-me"); 1400 new_file->set_shared_with_me_date(base::Time::Now());
1546 shared_with_me_label->SetString("scheme",
1547 "http://schemas.google.com/g/2005/labels");
1548 shared_with_me_label->SetString(
1549 "term", "http://schemas.google.com/g/2005/labels#shared");
1550 categories->Append(shared_with_me_label);
1551 } 1401 }
1552 1402
1553 std::string escaped_resource_id = net::EscapePath(resource_id); 1403 std::string escaped_resource_id = net::EscapePath(resource_id);
1554 1404
1555 // Add "content" which sets the content URL. 1405 // Set download URL and mime type.
1556 base::DictionaryValue* content = new base::DictionaryValue; 1406 new_file->set_download_url(
1557 content->SetString("src", "https://xxx/content/" + escaped_resource_id); 1407 GURL("https://xxx/content/" + escaped_resource_id));
1558 content->SetString("type", content_type); 1408 new_file->set_mime_type(content_type);
1559 new_entry->Set("content", content);
1560 1409
1561 // Add "link" which sets the parent URL, the edit URL and the upload URL. 1410 // Set parents.
1562 base::ListValue* links = new base::ListValue; 1411 scoped_ptr<ParentReference> parent(new ParentReference);
1412 if (parent_resource_id.empty())
1413 parent->set_file_id(GetRootResourceId());
1414 else
1415 parent->set_file_id(parent_resource_id);
1416 parent->set_parent_link(GetFakeLinkUrl(parent->file_id()));
1417 parent->set_is_root(parent->file_id() == GetRootResourceId());
1418 ScopedVector<ParentReference> parents;
1419 parents.push_back(parent.release());
1420 new_file->set_parents(parents.Pass());
1563 1421
1564 base::DictionaryValue* parent_link = new base::DictionaryValue; 1422 new_file->set_self_link(GURL("https://xxx/edit/" + escaped_resource_id));
1565 if (parent_resource_id.empty())
1566 parent_link->SetString("href", GetFakeLinkUrl(GetRootResourceId()).spec());
1567 else
1568 parent_link->SetString("href", GetFakeLinkUrl(parent_resource_id).spec());
1569 parent_link->SetString("rel",
1570 "http://schemas.google.com/docs/2007#parent");
1571 links->Append(parent_link);
1572 1423
1573 base::DictionaryValue* edit_link = new base::DictionaryValue; 1424 new_entry->share_url = net::AppendOrReplaceQueryParameter(
1574 edit_link->SetString("href", "https://xxx/edit/" + escaped_resource_id); 1425 share_url_base_, "name", title);
1575 edit_link->SetString("rel", "edit");
1576 links->Append(edit_link);
1577 1426
1578 base::DictionaryValue* upload_link = new base::DictionaryValue; 1427 AddNewChangestamp(new_change);
1579 upload_link->SetString("href", upload_url.spec()); 1428 UpdateETag(new_file);
1580 upload_link->SetString("rel", kUploadUrlRel);
1581 links->Append(upload_link);
1582
1583 const GURL share_url = net::AppendOrReplaceQueryParameter(
1584 share_url_base_, "name", title);
1585 base::DictionaryValue* share_link = new base::DictionaryValue;
1586 upload_link->SetString("href", share_url.spec());
1587 upload_link->SetString("rel", kShareUrlRel);
1588 links->Append(share_link);
1589 new_entry->Set("link", links);
1590
1591 AddNewChangestamp(new_entry.get());
1592 UpdateETag(new_entry.get());
1593 1429
1594 base::Time published_date = 1430 base::Time published_date =
1595 base::Time() + base::TimeDelta::FromMilliseconds(++published_date_seq_); 1431 base::Time() + base::TimeDelta::FromMilliseconds(++published_date_seq_);
1596 new_entry->SetString( 1432 new_file->set_created_date(published_date);
1597 "published.$t",
1598 google_apis::util::FormatTimeAsString(published_date));
1599 1433
1600 // If there are no entries, prepare an empty entry to add. 1434 EntryInfo* raw_new_entry = new_entry.release();
1601 if (!resource_list_value_->HasKey("entry")) 1435 entries_[resource_id] = raw_new_entry;
1602 resource_list_value_->Set("entry", new base::ListValue);
1603
1604 base::DictionaryValue* raw_new_entry = new_entry.release();
1605 base::ListValue* entries = NULL;
1606 if (resource_list_value_->GetList("entry", &entries))
1607 entries->Append(raw_new_entry);
1608
1609 return raw_new_entry; 1436 return raw_new_entry;
1610 } 1437 }
1611 1438
1612 void FakeDriveService::GetResourceListInternal( 1439 void FakeDriveService::GetResourceListInternal(
1613 int64 start_changestamp, 1440 int64 start_changestamp,
1614 const std::string& search_query, 1441 const std::string& search_query,
1615 const std::string& directory_resource_id, 1442 const std::string& directory_resource_id,
1616 int start_offset, 1443 int start_offset,
1617 int max_results, 1444 int max_results,
1618 int* load_counter, 1445 int* load_counter,
1619 const GetResourceListCallback& callback) { 1446 const GetResourceListCallback& callback) {
1620 if (offline_) { 1447 if (offline_) {
1621 base::MessageLoop::current()->PostTask( 1448 base::MessageLoop::current()->PostTask(
1622 FROM_HERE, 1449 FROM_HERE,
1623 base::Bind(callback, 1450 base::Bind(callback,
1624 GDATA_NO_CONNECTION, 1451 GDATA_NO_CONNECTION,
1625 base::Passed(scoped_ptr<ResourceList>()))); 1452 base::Passed(scoped_ptr<ResourceList>())));
1626 return; 1453 return;
1627 } 1454 }
1628 1455
1629 scoped_ptr<ResourceList> resource_list =
1630 ResourceList::CreateFrom(*resource_list_value_);
1631
1632 // TODO(hashimoto): Drive API always provides largest changestamp. Remove this
1633 // if-statement after API switch.
1634 if (start_changestamp > 0 && start_offset == 0)
1635 resource_list->set_largest_changestamp(largest_changestamp_);
1636
1637 // Filter out entries per parameters like |directory_resource_id| and 1456 // Filter out entries per parameters like |directory_resource_id| and
1638 // |search_query|. 1457 // |search_query|.
1639 ScopedVector<ResourceEntry>* entries = resource_list->mutable_entries(); 1458 ScopedVector<ResourceEntry> entries;
1640
1641 int num_entries_matched = 0; 1459 int num_entries_matched = 0;
1642 for (size_t i = 0; i < entries->size();) { 1460 for (EntryInfoMap::iterator it = entries_.begin(); it != entries_.end();
1643 ResourceEntry* entry = (*entries)[i]; 1461 ++it) {
1462 scoped_ptr<ResourceEntry> entry =
1463 util::ConvertChangeResourceToResourceEntry(it->second->change_resource);
1644 bool should_exclude = false; 1464 bool should_exclude = false;
1645 1465
1646 // If |directory_resource_id| is set, exclude the entry if it's not in 1466 // If |directory_resource_id| is set, exclude the entry if it's not in
1647 // the target directory. 1467 // the target directory.
1648 if (!directory_resource_id.empty()) { 1468 if (!directory_resource_id.empty()) {
1649 // Get the parent resource ID of the entry. 1469 // Get the parent resource ID of the entry.
1650 std::string parent_resource_id; 1470 std::string parent_resource_id;
1651 const google_apis::Link* parent_link = 1471 const google_apis::Link* parent_link =
1652 entry->GetLinkByType(Link::LINK_PARENT); 1472 entry->GetLinkByType(Link::LINK_PARENT);
1653 if (parent_link) { 1473 if (parent_link) {
(...skipping 27 matching lines...) Expand all
1681 // The entry matched the criteria for inclusion. 1501 // The entry matched the criteria for inclusion.
1682 if (!should_exclude) 1502 if (!should_exclude)
1683 ++num_entries_matched; 1503 ++num_entries_matched;
1684 1504
1685 // If |start_offset| is set, exclude the entry if the entry is before the 1505 // If |start_offset| is set, exclude the entry if the entry is before the
1686 // start index. <= instead of < as |num_entries_matched| was 1506 // start index. <= instead of < as |num_entries_matched| was
1687 // already incremented. 1507 // already incremented.
1688 if (start_offset > 0 && num_entries_matched <= start_offset) 1508 if (start_offset > 0 && num_entries_matched <= start_offset)
1689 should_exclude = true; 1509 should_exclude = true;
1690 1510
1691 if (should_exclude) 1511 if (!should_exclude)
1692 entries->erase(entries->begin() + i); 1512 entries.push_back(entry.release());
1693 else
1694 ++i;
1695 } 1513 }
1696 1514
1515 scoped_ptr<ResourceList> resource_list(new ResourceList);
1516 if (start_changestamp > 0 && start_offset == 0)
1517 resource_list->set_largest_changestamp(largest_changestamp_);
1518
1697 // If |max_results| is set, trim the entries if the number exceeded the max 1519 // If |max_results| is set, trim the entries if the number exceeded the max
1698 // results. 1520 // results.
1699 if (max_results > 0 && entries->size() > static_cast<size_t>(max_results)) { 1521 if (max_results > 0 && entries.size() > static_cast<size_t>(max_results)) {
1700 entries->erase(entries->begin() + max_results, entries->end()); 1522 entries.erase(entries.begin() + max_results, entries.end());
1701 // Adds the next URL. 1523 // Adds the next URL.
1702 // Here, we embed information which is needed for continuing the 1524 // Here, we embed information which is needed for continuing the
1703 // GetResourceList request in the next invocation into url query 1525 // GetResourceList request in the next invocation into url query
1704 // parameters. 1526 // parameters.
1705 GURL next_url(base::StringPrintf( 1527 GURL next_url(base::StringPrintf(
1706 "http://localhost/?start-offset=%d&max-results=%d", 1528 "http://localhost/?start-offset=%d&max-results=%d",
1707 start_offset + max_results, 1529 start_offset + max_results,
1708 max_results)); 1530 max_results));
1709 if (start_changestamp > 0) { 1531 if (start_changestamp > 0) {
1710 next_url = net::AppendOrReplaceQueryParameter( 1532 next_url = net::AppendOrReplaceQueryParameter(
1711 next_url, "changestamp", 1533 next_url, "changestamp",
1712 base::Int64ToString(start_changestamp).c_str()); 1534 base::Int64ToString(start_changestamp).c_str());
1713 } 1535 }
1714 if (!search_query.empty()) { 1536 if (!search_query.empty()) {
1715 next_url = net::AppendOrReplaceQueryParameter( 1537 next_url = net::AppendOrReplaceQueryParameter(
1716 next_url, "q", search_query); 1538 next_url, "q", search_query);
1717 } 1539 }
1718 if (!directory_resource_id.empty()) { 1540 if (!directory_resource_id.empty()) {
1719 next_url = net::AppendOrReplaceQueryParameter( 1541 next_url = net::AppendOrReplaceQueryParameter(
1720 next_url, "parent", directory_resource_id); 1542 next_url, "parent", directory_resource_id);
1721 } 1543 }
1722 1544
1723 Link* link = new Link; 1545 Link* link = new Link;
1724 link->set_type(Link::LINK_NEXT); 1546 link->set_type(Link::LINK_NEXT);
1725 link->set_href(next_url); 1547 link->set_href(next_url);
1726 resource_list->mutable_links()->push_back(link); 1548 resource_list->mutable_links()->push_back(link);
1727 } 1549 }
1550 resource_list->set_entries(entries.Pass());
1728 1551
1729 if (load_counter) 1552 if (load_counter)
1730 *load_counter += 1; 1553 *load_counter += 1;
1731 base::MessageLoop::current()->PostTask( 1554 base::MessageLoop::current()->PostTask(
1732 FROM_HERE, 1555 FROM_HERE,
1733 base::Bind(callback, HTTP_SUCCESS, base::Passed(&resource_list))); 1556 base::Bind(callback, HTTP_SUCCESS, base::Passed(&resource_list)));
1734 } 1557 }
1735 1558
1736 GURL FakeDriveService::GetNewUploadSessionUrl() { 1559 GURL FakeDriveService::GetNewUploadSessionUrl() {
1737 return GURL("https://upload_session_url/" + 1560 return GURL("https://upload_session_url/" +
1738 base::Int64ToString(next_upload_sequence_number_++)); 1561 base::Int64ToString(next_upload_sequence_number_++));
1739 } 1562 }
1740 1563
1741 } // namespace drive 1564 } // namespace drive
OLDNEW
« no previous file with comments | « chrome/browser/drive/fake_drive_service.h ('k') | google_apis/drive/drive_api_parser.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698