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

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

Issue 17140009: Support contents upload on FakeDriveService (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: drop unused line Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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/logging.h" 10 #include "base/logging.h"
11 #include "base/md5.h"
10 #include "base/message_loop.h" 12 #include "base/message_loop.h"
11 #include "base/strings/string_number_conversions.h" 13 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/string_split.h" 14 #include "base/strings/string_split.h"
13 #include "base/strings/string_tokenizer.h" 15 #include "base/strings/string_tokenizer.h"
14 #include "base/strings/string_util.h" 16 #include "base/strings/string_util.h"
15 #include "base/strings/stringprintf.h" 17 #include "base/strings/stringprintf.h"
16 #include "base/strings/utf_string_conversions.h" 18 #include "base/strings/utf_string_conversions.h"
17 #include "chrome/browser/google_apis/drive_api_parser.h" 19 #include "chrome/browser/google_apis/drive_api_parser.h"
18 #include "chrome/browser/google_apis/gdata_wapi_parser.h" 20 #include "chrome/browser/google_apis/gdata_wapi_parser.h"
19 #include "chrome/browser/google_apis/test_util.h" 21 #include "chrome/browser/google_apis/test_util.h"
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
89 // TODO(peria): Deal with other attributes than title. 91 // TODO(peria): Deal with other attributes than title.
90 if (!key.empty() && key != "title") 92 if (!key.empty() && key != "title")
91 return false; 93 return false;
92 // Search query in the title. 94 // Search query in the title.
93 if (entry.title().find(value) == std::string::npos) 95 if (entry.title().find(value) == std::string::npos)
94 return false; 96 return false;
95 } 97 }
96 return true; 98 return true;
97 } 99 }
98 100
99 // Gets the upload URL from the given entry. Returns an empty URL if not
100 // found.
101 GURL GetUploadUrl(const base::DictionaryValue& entry) {
102 std::string upload_url;
103 const base::ListValue* links = NULL;
104 if (entry.GetList("link", &links) && links) {
105 for (size_t link_index = 0;
106 link_index < links->GetSize();
107 ++link_index) {
108 const base::DictionaryValue* link = NULL;
109 std::string rel;
110 if (links->GetDictionary(link_index, &link) &&
111 link && link->GetString("rel", &rel) &&
112 rel == kUploadUrlRel &&
113 link->GetString("href", &upload_url)) {
114 break;
115 }
116 }
117 }
118 return GURL(upload_url);
119 }
120
121 // Returns |url| without query parameter. 101 // Returns |url| without query parameter.
122 GURL RemoveQueryParameter(const GURL& url) { 102 GURL RemoveQueryParameter(const GURL& url) {
123 GURL::Replacements replacements; 103 GURL::Replacements replacements;
124 replacements.ClearQuery(); 104 replacements.ClearQuery();
125 return url.ReplaceComponents(replacements); 105 return url.ReplaceComponents(replacements);
126 } 106 }
127 107
108 void ScheduleUploadRangeCallback(const UploadRangeCallback& callback,
109 int64 start_position,
110 int64 end_position,
111 GDataErrorCode error,
112 scoped_ptr<ResourceEntry> entry) {
113 base::MessageLoop::current()->PostTask(
114 FROM_HERE,
115 base::Bind(callback,
116 UploadRangeResponse(error,
117 start_position,
118 end_position),
119 base::Passed(&entry)));
120 }
121
128 } // namespace 122 } // namespace
129 123
124 struct FakeDriveService::UploadSession {
125 std::string content_type;
126 int64 content_length;
127 std::string parent_resource_id;
128 std::string resource_id;
129 std::string etag;
130 std::string title;
131
132 int64 uploaded_size;
133
134 UploadSession()
135 : content_length(0),
136 uploaded_size(0) {}
137
138 UploadSession(
139 std::string content_type,
140 int64 content_length,
141 std::string parent_resource_id,
142 std::string resource_id,
143 std::string etag,
144 std::string title)
145 : content_type(content_type),
146 content_length(content_length),
147 parent_resource_id(parent_resource_id),
148 resource_id(resource_id),
149 etag(etag),
150 title(title),
151 uploaded_size(0) {
152 }
153 };
154
130 FakeDriveService::FakeDriveService() 155 FakeDriveService::FakeDriveService()
131 : largest_changestamp_(0), 156 : largest_changestamp_(0),
132 published_date_seq_(0), 157 published_date_seq_(0),
158 next_upload_sequence_number_(0),
133 default_max_results_(0), 159 default_max_results_(0),
134 resource_id_count_(0), 160 resource_id_count_(0),
135 resource_list_load_count_(0), 161 resource_list_load_count_(0),
136 change_list_load_count_(0), 162 change_list_load_count_(0),
137 directory_load_count_(0), 163 directory_load_count_(0),
138 about_resource_load_count_(0), 164 about_resource_load_count_(0),
139 offline_(false) { 165 offline_(false) {
140 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 166 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
141 } 167 }
142 168
(...skipping 397 matching lines...) Expand 10 before | Expand all | Expand 10 after
540 if (!entry) { 566 if (!entry) {
541 base::MessageLoopProxy::current()->PostTask( 567 base::MessageLoopProxy::current()->PostTask(
542 FROM_HERE, 568 FROM_HERE,
543 base::Bind(download_action_callback, HTTP_NOT_FOUND, base::FilePath())); 569 base::Bind(download_action_callback, HTTP_NOT_FOUND, base::FilePath()));
544 return CancelCallback(); 570 return CancelCallback();
545 } 571 }
546 572
547 // Write "x"s of the file size specified in the entry. 573 // Write "x"s of the file size specified in the entry.
548 std::string file_size_string; 574 std::string file_size_string;
549 entry->GetString("docs$size.$t", &file_size_string); 575 entry->GetString("docs$size.$t", &file_size_string);
550 // TODO(satorux): To be correct, we should update docs$md5Checksum.$t here.
551 int64 file_size = 0; 576 int64 file_size = 0;
552 if (base::StringToInt64(file_size_string, &file_size)) { 577 if (base::StringToInt64(file_size_string, &file_size)) {
553 base::BinaryValue* content_binary_data; 578 base::BinaryValue* content_binary_data;
554 std::string content_data; 579 std::string content_data;
555 if (entry->GetBinary("test$data", &content_binary_data)) { 580 if (entry->GetBinary("test$data", &content_binary_data)) {
556 content_data = std::string(content_binary_data->GetBuffer(), 581 content_data = std::string(content_binary_data->GetBuffer(),
557 content_binary_data->GetSize()); 582 content_binary_data->GetSize());
558 } 583 }
559 DCHECK_EQ(static_cast<size_t>(file_size), content_data.size()); 584 DCHECK_EQ(static_cast<size_t>(file_size), content_data.size());
560 585
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
642 entry->Set("link", links); 667 entry->Set("link", links);
643 } 668 }
644 links->Clear(); 669 links->Clear();
645 670
646 base::DictionaryValue* link = new base::DictionaryValue; 671 base::DictionaryValue* link = new base::DictionaryValue;
647 link->SetString( 672 link->SetString(
648 "rel", "http://schemas.google.com/docs/2007#parent"); 673 "rel", "http://schemas.google.com/docs/2007#parent");
649 link->SetString("href", GetFakeLinkUrl(parent_resource_id).spec()); 674 link->SetString("href", GetFakeLinkUrl(parent_resource_id).spec());
650 links->Append(link); 675 links->Append(link);
651 676
652 AddNewChangestamp(copied_entry.get()); 677 AddNewChangestampAndETag(copied_entry.get());
653 678
654 // Parse the new entry. 679 // Parse the new entry.
655 scoped_ptr<ResourceEntry> resource_entry = 680 scoped_ptr<ResourceEntry> resource_entry =
656 ResourceEntry::CreateFrom(*copied_entry); 681 ResourceEntry::CreateFrom(*copied_entry);
657 // Add it to the resource list. 682 // Add it to the resource list.
658 entries->Append(copied_entry.release()); 683 entries->Append(copied_entry.release());
659 684
660 base::MessageLoop::current()->PostTask( 685 base::MessageLoop::current()->PostTask(
661 FROM_HERE, 686 FROM_HERE,
662 base::Bind(callback, 687 base::Bind(callback,
(...skipping 30 matching lines...) Expand all
693 718
694 if (offline_) { 719 if (offline_) {
695 base::MessageLoop::current()->PostTask( 720 base::MessageLoop::current()->PostTask(
696 FROM_HERE, base::Bind(callback, GDATA_NO_CONNECTION)); 721 FROM_HERE, base::Bind(callback, GDATA_NO_CONNECTION));
697 return CancelCallback(); 722 return CancelCallback();
698 } 723 }
699 724
700 base::DictionaryValue* entry = FindEntryByResourceId(resource_id); 725 base::DictionaryValue* entry = FindEntryByResourceId(resource_id);
701 if (entry) { 726 if (entry) {
702 entry->SetString("title.$t", new_name); 727 entry->SetString("title.$t", new_name);
703 AddNewChangestamp(entry); 728 AddNewChangestampAndETag(entry);
704 base::MessageLoop::current()->PostTask( 729 base::MessageLoop::current()->PostTask(
705 FROM_HERE, base::Bind(callback, HTTP_SUCCESS)); 730 FROM_HERE, base::Bind(callback, HTTP_SUCCESS));
706 return CancelCallback(); 731 return CancelCallback();
707 } 732 }
708 733
709 base::MessageLoop::current()->PostTask( 734 base::MessageLoop::current()->PostTask(
710 FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND)); 735 FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND));
711 return CancelCallback(); 736 return CancelCallback();
712 } 737 }
713 738
(...skipping 21 matching lines...) Expand all
735 FROM_HERE, 760 FROM_HERE,
736 base::Bind(callback, HTTP_NOT_FOUND, 761 base::Bind(callback, HTTP_NOT_FOUND,
737 base::Passed(scoped_ptr<ResourceEntry>()))); 762 base::Passed(scoped_ptr<ResourceEntry>())));
738 return CancelCallback(); 763 return CancelCallback();
739 } 764 }
740 765
741 entry->SetString("updated.$t", 766 entry->SetString("updated.$t",
742 util::FormatTimeAsString(modified_date)); 767 util::FormatTimeAsString(modified_date));
743 entry->SetString("gd$lastViewed.$t", 768 entry->SetString("gd$lastViewed.$t",
744 util::FormatTimeAsString(last_viewed_by_me_date)); 769 util::FormatTimeAsString(last_viewed_by_me_date));
745 AddNewChangestamp(entry); 770 AddNewChangestampAndETag(entry);
746 771
747 scoped_ptr<ResourceEntry> parsed_entry(ResourceEntry::CreateFrom(*entry)); 772 scoped_ptr<ResourceEntry> parsed_entry(ResourceEntry::CreateFrom(*entry));
748 base::MessageLoop::current()->PostTask( 773 base::MessageLoop::current()->PostTask(
749 FROM_HERE, 774 FROM_HERE,
750 base::Bind(callback, HTTP_SUCCESS, base::Passed(&parsed_entry))); 775 base::Bind(callback, HTTP_SUCCESS, base::Passed(&parsed_entry)));
751 return CancelCallback(); 776 return CancelCallback();
752 } 777 }
753 778
754 CancelCallback FakeDriveService::AddResourceToDirectory( 779 CancelCallback FakeDriveService::AddResourceToDirectory(
755 const std::string& parent_resource_id, 780 const std::string& parent_resource_id,
(...skipping 19 matching lines...) Expand all
775 // On the real Drive server, resources do not necessary shape a tree 800 // On the real Drive server, resources do not necessary shape a tree
776 // structure. That is, each resource can have multiple parent. 801 // structure. That is, each resource can have multiple parent.
777 // We mimic the behavior here; AddResourceToDirectoy just adds 802 // We mimic the behavior here; AddResourceToDirectoy just adds
778 // one more parent link, not overwriting old links. 803 // one more parent link, not overwriting old links.
779 base::DictionaryValue* link = new base::DictionaryValue; 804 base::DictionaryValue* link = new base::DictionaryValue;
780 link->SetString("rel", "http://schemas.google.com/docs/2007#parent"); 805 link->SetString("rel", "http://schemas.google.com/docs/2007#parent");
781 link->SetString( 806 link->SetString(
782 "href", GetFakeLinkUrl(parent_resource_id).spec()); 807 "href", GetFakeLinkUrl(parent_resource_id).spec());
783 links->Append(link); 808 links->Append(link);
784 809
785 AddNewChangestamp(entry); 810 AddNewChangestampAndETag(entry);
786 base::MessageLoop::current()->PostTask( 811 base::MessageLoop::current()->PostTask(
787 FROM_HERE, base::Bind(callback, HTTP_SUCCESS)); 812 FROM_HERE, base::Bind(callback, HTTP_SUCCESS));
788 return CancelCallback(); 813 return CancelCallback();
789 } 814 }
790 815
791 base::MessageLoop::current()->PostTask( 816 base::MessageLoop::current()->PostTask(
792 FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND)); 817 FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND));
793 return CancelCallback(); 818 return CancelCallback();
794 } 819 }
795 820
(...skipping 18 matching lines...) Expand all
814 for (size_t i = 0; i < links->GetSize(); ++i) { 839 for (size_t i = 0; i < links->GetSize(); ++i) {
815 base::DictionaryValue* link = NULL; 840 base::DictionaryValue* link = NULL;
816 std::string rel; 841 std::string rel;
817 std::string href; 842 std::string href;
818 if (links->GetDictionary(i, &link) && 843 if (links->GetDictionary(i, &link) &&
819 link->GetString("rel", &rel) && 844 link->GetString("rel", &rel) &&
820 link->GetString("href", &href) && 845 link->GetString("href", &href) &&
821 rel == "http://schemas.google.com/docs/2007#parent" && 846 rel == "http://schemas.google.com/docs/2007#parent" &&
822 GURL(href) == parent_content_url) { 847 GURL(href) == parent_content_url) {
823 links->Remove(i, NULL); 848 links->Remove(i, NULL);
824 AddNewChangestamp(entry); 849 AddNewChangestampAndETag(entry);
825 base::MessageLoop::current()->PostTask( 850 base::MessageLoop::current()->PostTask(
826 FROM_HERE, base::Bind(callback, HTTP_SUCCESS)); 851 FROM_HERE, base::Bind(callback, HTTP_SUCCESS));
827 return CancelCallback(); 852 return CancelCallback();
828 } 853 }
829 } 854 }
830 } 855 }
831 } 856 }
832 857
833 base::MessageLoop::current()->PostTask( 858 base::MessageLoop::current()->PostTask(
834 FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND)); 859 FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND));
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
883 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 908 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
884 DCHECK(!callback.is_null()); 909 DCHECK(!callback.is_null());
885 910
886 if (offline_) { 911 if (offline_) {
887 base::MessageLoop::current()->PostTask( 912 base::MessageLoop::current()->PostTask(
888 FROM_HERE, 913 FROM_HERE,
889 base::Bind(callback, GDATA_NO_CONNECTION, GURL())); 914 base::Bind(callback, GDATA_NO_CONNECTION, GURL()));
890 return CancelCallback(); 915 return CancelCallback();
891 } 916 }
892 917
893 // Content length should be zero, as we'll create an empty file first. The 918 if (parent_resource_id != GetRootResourceId() &&
894 // content will be added in ResumeUpload(). 919 !FindEntryByResourceId(parent_resource_id)) {
895 const base::DictionaryValue* new_entry = AddNewEntry(content_type,
896 "", // content_data
897 parent_resource_id,
898 title,
899 false, // shared_with_me
900 "file");
901 if (!new_entry) {
902 base::MessageLoop::current()->PostTask( 920 base::MessageLoop::current()->PostTask(
903 FROM_HERE, 921 FROM_HERE,
904 base::Bind(callback, HTTP_NOT_FOUND, GURL())); 922 base::Bind(callback, HTTP_NOT_FOUND, GURL()));
905 return CancelCallback(); 923 return CancelCallback();
906 } 924 }
907 const GURL upload_url = GetUploadUrl(*new_entry); 925
908 DCHECK(upload_url.is_valid()); 926 GURL session_url = GetNewUploadSessionUrl();
927 upload_sessions_[session_url] =
928 UploadSession(content_type, content_length,
929 parent_resource_id,
930 "", // resource_id
931 "", // etag
932 title);
909 933
910 base::MessageLoop::current()->PostTask( 934 base::MessageLoop::current()->PostTask(
911 FROM_HERE, 935 FROM_HERE,
912 base::Bind(callback, HTTP_SUCCESS, 936 base::Bind(callback, HTTP_SUCCESS, session_url));
913 net::AppendQueryParameter(upload_url, "mode", "newfile")));
914 return CancelCallback(); 937 return CancelCallback();
915 } 938 }
916 939
917 CancelCallback FakeDriveService::InitiateUploadExistingFile( 940 CancelCallback FakeDriveService::InitiateUploadExistingFile(
918 const std::string& content_type, 941 const std::string& content_type,
919 int64 content_length, 942 int64 content_length,
920 const std::string& resource_id, 943 const std::string& resource_id,
921 const std::string& etag, 944 const std::string& etag,
922 const InitiateUploadCallback& callback) { 945 const InitiateUploadCallback& callback) {
923 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 946 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
(...skipping 15 matching lines...) Expand all
939 } 962 }
940 963
941 std::string entry_etag; 964 std::string entry_etag;
942 entry->GetString("gd$etag", &entry_etag); 965 entry->GetString("gd$etag", &entry_etag);
943 if (!etag.empty() && etag != entry_etag) { 966 if (!etag.empty() && etag != entry_etag) {
944 base::MessageLoop::current()->PostTask( 967 base::MessageLoop::current()->PostTask(
945 FROM_HERE, 968 FROM_HERE,
946 base::Bind(callback, HTTP_PRECONDITION, GURL())); 969 base::Bind(callback, HTTP_PRECONDITION, GURL()));
947 return CancelCallback(); 970 return CancelCallback();
948 } 971 }
949 entry->SetString("docs$size.$t", "0");
950 972
951 const GURL upload_url = GetUploadUrl(*entry); 973 GURL session_url = GetNewUploadSessionUrl();
952 DCHECK(upload_url.is_valid()); 974 upload_sessions_[session_url] =
975 UploadSession(content_type, content_length,
976 "", // parent_resource_id
977 resource_id,
978 entry_etag,
979 "" /* title */);
953 980
954 base::MessageLoop::current()->PostTask( 981 base::MessageLoop::current()->PostTask(
955 FROM_HERE, 982 FROM_HERE,
956 base::Bind(callback, HTTP_SUCCESS, 983 base::Bind(callback, HTTP_SUCCESS, session_url));
957 net::AppendQueryParameter(upload_url, "mode", "existing")));
958 return CancelCallback(); 984 return CancelCallback();
959 } 985 }
960 986
961 CancelCallback FakeDriveService::GetUploadStatus( 987 CancelCallback FakeDriveService::GetUploadStatus(
962 const GURL& upload_url, 988 const GURL& upload_url,
963 int64 content_length, 989 int64 content_length,
964 const UploadRangeCallback& callback) { 990 const UploadRangeCallback& callback) {
965 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 991 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
966 DCHECK(!callback.is_null()); 992 DCHECK(!callback.is_null());
967 return CancelCallback(); 993 return CancelCallback();
968 } 994 }
969 995
970 CancelCallback FakeDriveService::ResumeUpload( 996 CancelCallback FakeDriveService::ResumeUpload(
971 const GURL& upload_url, 997 const GURL& upload_url,
972 int64 start_position, 998 int64 start_position,
973 int64 end_position, 999 int64 end_position,
974 int64 content_length, 1000 int64 content_length,
975 const std::string& content_type, 1001 const std::string& content_type,
976 const base::FilePath& local_file_path, 1002 const base::FilePath& local_file_path,
977 const UploadRangeCallback& callback, 1003 const UploadRangeCallback& callback,
978 const ProgressCallback& progress_callback) { 1004 const ProgressCallback& progress_callback) {
979 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1005 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
980 DCHECK(!callback.is_null()); 1006 DCHECK(!callback.is_null());
981 1007
982 scoped_ptr<ResourceEntry> result_entry; 1008 GetResourceEntryCallback completion_callback
1009 = base::Bind(&ScheduleUploadRangeCallback,
1010 callback, start_position, end_position);
983 1011
984 if (offline_) { 1012 if (offline_) {
985 base::MessageLoop::current()->PostTask( 1013 completion_callback.Run(GDATA_NO_CONNECTION, scoped_ptr<ResourceEntry>());
986 FROM_HERE,
987 base::Bind(callback,
988 UploadRangeResponse(GDATA_NO_CONNECTION,
989 start_position,
990 end_position),
991 base::Passed(&result_entry)));
992 return CancelCallback(); 1014 return CancelCallback();
993 } 1015 }
994 1016
995 DictionaryValue* entry = NULL; 1017 if (!upload_sessions_.count(upload_url)) {
996 entry = FindEntryByUploadUrl(RemoveQueryParameter(upload_url)); 1018 completion_callback.Run(HTTP_NOT_FOUND, scoped_ptr<ResourceEntry>());
997 if (!entry) {
998 base::MessageLoop::current()->PostTask(
999 FROM_HERE,
1000 base::Bind(callback,
1001 UploadRangeResponse(HTTP_NOT_FOUND,
1002 start_position,
1003 end_position),
1004 base::Passed(&result_entry)));
1005 return CancelCallback(); 1019 return CancelCallback();
1006 } 1020 }
1007 1021
1022 UploadSession* session = &upload_sessions_[upload_url];
1023
1008 // Chunks are required to be sent in such a ways that they fill from the start 1024 // Chunks are required to be sent in such a ways that they fill from the start
1009 // of the not-yet-uploaded part with no gaps nor overlaps. 1025 // of the not-yet-uploaded part with no gaps nor overlaps.
1010 std::string current_size_string; 1026 if (session->uploaded_size != start_position) {
1011 int64 current_size; 1027 completion_callback.Run(HTTP_BAD_REQUEST, scoped_ptr<ResourceEntry>());
1012 if (!entry->GetString("docs$size.$t", &current_size_string) ||
1013 !base::StringToInt64(current_size_string, &current_size) ||
1014 current_size != start_position) {
1015 base::MessageLoop::current()->PostTask(
1016 FROM_HERE,
1017 base::Bind(callback,
1018 UploadRangeResponse(HTTP_BAD_REQUEST,
1019 start_position,
1020 end_position),
1021 base::Passed(&result_entry)));
1022 return CancelCallback(); 1028 return CancelCallback();
1023 } 1029 }
1024 1030
1025 entry->SetString("docs$size.$t", base::Int64ToString(end_position));
1026
1027 if (!progress_callback.is_null()) { 1031 if (!progress_callback.is_null()) {
1028 // In the real GDataWapi/Drive DriveService, progress is reported in 1032 // In the real GDataWapi/Drive DriveService, progress is reported in
1029 // nondeterministic timing. In this fake implementation, we choose to call 1033 // nondeterministic timing. In this fake implementation, we choose to call
1030 // it twice per one ResumeUpload. This is for making sure that client code 1034 // it twice per one ResumeUpload. This is for making sure that client code
1031 // works fine even if the callback is invoked more than once; it is the 1035 // works fine even if the callback is invoked more than once; it is the
1032 // crucial difference of the progress callback from others. 1036 // crucial difference of the progress callback from others.
1033 // Note that progress is notified in the relative offset in each chunk. 1037 // Note that progress is notified in the relative offset in each chunk.
1034 const int64 chunk_size = end_position - start_position; 1038 const int64 chunk_size = end_position - start_position;
1035 base::MessageLoop::current()->PostTask( 1039 base::MessageLoop::current()->PostTask(
1036 FROM_HERE, base::Bind(progress_callback, chunk_size / 2, chunk_size)); 1040 FROM_HERE, base::Bind(progress_callback, chunk_size / 2, chunk_size));
1037 base::MessageLoop::current()->PostTask( 1041 base::MessageLoop::current()->PostTask(
1038 FROM_HERE, base::Bind(progress_callback, chunk_size, chunk_size)); 1042 FROM_HERE, base::Bind(progress_callback, chunk_size, chunk_size));
1039 } 1043 }
1040 1044
1041 if (content_length != end_position) { 1045 if (content_length != end_position) {
1042 base::MessageLoop::current()->PostTask( 1046 session->uploaded_size = end_position;
1043 FROM_HERE, 1047 completion_callback.Run(HTTP_RESUME_INCOMPLETE,
1044 base::Bind(callback, 1048 scoped_ptr<ResourceEntry>());
1045 UploadRangeResponse(HTTP_RESUME_INCOMPLETE,
1046 start_position,
1047 end_position),
1048 base::Passed(&result_entry)));
1049 return CancelCallback(); 1049 return CancelCallback();
1050 } 1050 }
1051 1051
1052 AddNewChangestamp(entry); 1052 std::string content_data;
1053 result_entry = ResourceEntry::CreateFrom(*entry).Pass(); 1053 if (!file_util::ReadFileToString(local_file_path, &content_data)) {
1054 session->uploaded_size = end_position;
1055 completion_callback.Run(GDATA_FILE_ERROR, scoped_ptr<ResourceEntry>());
1056 return CancelCallback();
1057 }
1058 session->uploaded_size = end_position;
1054 1059
1055 std::string upload_mode; 1060 // |resource_id| is empty if the upload is for new file.
1056 bool upload_mode_found = 1061 if (session->resource_id.empty()) {
1057 net::GetValueForKeyInQuery(upload_url, "mode", &upload_mode); 1062 DCHECK(!session->parent_resource_id.empty());
1058 DCHECK(upload_mode_found && 1063 DCHECK(!session->title.empty());
1059 (upload_mode == "newfile" || upload_mode == "existing")); 1064 const DictionaryValue* new_entry = AddNewEntry(
1065 session->content_type,
1066 content_data,
1067 session->parent_resource_id,
1068 session->title,
1069 false, // shared_with_me
1070 "file");
1071 if (!new_entry) {
1072 completion_callback.Run(HTTP_NOT_FOUND, scoped_ptr<ResourceEntry>());
1073 return CancelCallback();
1074 }
1060 1075
1061 GDataErrorCode return_code = 1076 completion_callback.Run(HTTP_CREATED,
1062 upload_mode == "newfile" ? HTTP_CREATED : HTTP_SUCCESS; 1077 ResourceEntry::CreateFrom(*new_entry));
1078 return CancelCallback();
1079 }
1063 1080
1064 base::MessageLoop::current()->PostTask( 1081 DictionaryValue* entry = FindEntryByResourceId(session->resource_id);
1065 FROM_HERE, 1082 if (!entry) {
1066 base::Bind(callback, 1083 completion_callback.Run(HTTP_NOT_FOUND, scoped_ptr<ResourceEntry>());
1067 UploadRangeResponse(return_code, 1084 return CancelCallback();
1068 start_position, 1085 }
1069 end_position), 1086
1070 base::Passed(&result_entry))); 1087 std::string entry_etag;
1088 entry->GetString("gd$etag", &entry_etag);
1089 if (entry_etag.empty() || session->etag != entry_etag) {
1090 completion_callback.Run(HTTP_PRECONDITION, scoped_ptr<ResourceEntry>());
1091 return CancelCallback();
1092 }
1093
1094 entry->SetString("docs$md5Checksum.$t", base::MD5String(content_data));
1095 entry->Set("test$data",
1096 base::BinaryValue::CreateWithCopiedBuffer(
1097 content_data.data(), content_data.size()));
1098 entry->SetString("docs$size.$t", base::Int64ToString(end_position));
1099 AddNewChangestampAndETag(entry);
1100
1101 completion_callback.Run(HTTP_SUCCESS, ResourceEntry::CreateFrom(*entry));
1071 return CancelCallback(); 1102 return CancelCallback();
1072 } 1103 }
1073 1104
1074 CancelCallback FakeDriveService::AuthorizeApp( 1105 CancelCallback FakeDriveService::AuthorizeApp(
1075 const std::string& resource_id, 1106 const std::string& resource_id,
1076 const std::string& app_id, 1107 const std::string& app_id,
1077 const AuthorizeAppCallback& callback) { 1108 const AuthorizeAppCallback& callback) {
1078 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1109 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1079 DCHECK(!callback.is_null()); 1110 DCHECK(!callback.is_null());
1080 return CancelCallback(); 1111 return CancelCallback();
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after
1202 entry->GetString("content.src", &current_content_url) && 1233 entry->GetString("content.src", &current_content_url) &&
1203 content_url == GURL(current_content_url)) { 1234 content_url == GURL(current_content_url)) {
1204 return entry; 1235 return entry;
1205 } 1236 }
1206 } 1237 }
1207 } 1238 }
1208 1239
1209 return NULL; 1240 return NULL;
1210 } 1241 }
1211 1242
1212 base::DictionaryValue* FakeDriveService::FindEntryByUploadUrl(
1213 const GURL& upload_url) {
1214 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1215
1216 base::ListValue* entries = NULL;
1217 // Go through entries and return the one that matches |upload_url|.
1218 if (resource_list_value_->GetList("entry", &entries)) {
1219 for (size_t i = 0; i < entries->GetSize(); ++i) {
1220 base::DictionaryValue* entry = NULL;
1221 base::ListValue* links = NULL;
1222 if (entries->GetDictionary(i, &entry) &&
1223 entry->GetList("link", &links) &&
1224 links) {
1225 for (size_t link_index = 0;
1226 link_index < links->GetSize();
1227 ++link_index) {
1228 base::DictionaryValue* link = NULL;
1229 std::string rel;
1230 std::string found_upload_url;
1231 if (links->GetDictionary(link_index, &link) &&
1232 link && link->GetString("rel", &rel) &&
1233 rel == kUploadUrlRel &&
1234 link->GetString("href", &found_upload_url) &&
1235 GURL(found_upload_url) == upload_url) {
1236 return entry;
1237 }
1238 }
1239 }
1240 }
1241 }
1242
1243 return NULL;
1244 }
1245
1246 std::string FakeDriveService::GetNewResourceId() { 1243 std::string FakeDriveService::GetNewResourceId() {
1247 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1244 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1248 1245
1249 ++resource_id_count_; 1246 ++resource_id_count_;
1250 return base::StringPrintf("resource_id_%d", resource_id_count_); 1247 return base::StringPrintf("resource_id_%d", resource_id_count_);
1251 } 1248 }
1252 1249
1253 void FakeDriveService::AddNewChangestamp(base::DictionaryValue* entry) { 1250 void FakeDriveService::AddNewChangestampAndETag(base::DictionaryValue* entry) {
1254 ++largest_changestamp_; 1251 ++largest_changestamp_;
1255 entry->SetString("docs$changestamp.value", 1252 entry->SetString("docs$changestamp.value",
1256 base::Int64ToString(largest_changestamp_)); 1253 base::Int64ToString(largest_changestamp_));
1254 entry->SetString("gd$etag",
1255 "etag_" + base::Int64ToString(largest_changestamp_));
1257 } 1256 }
1258 1257
1259 const base::DictionaryValue* FakeDriveService::AddNewEntry( 1258 const base::DictionaryValue* FakeDriveService::AddNewEntry(
1260 const std::string& content_type, 1259 const std::string& content_type,
1261 const std::string& content_data, 1260 const std::string& content_data,
1262 const std::string& parent_resource_id, 1261 const std::string& parent_resource_id,
1263 const std::string& title, 1262 const std::string& title,
1264 bool shared_with_me, 1263 bool shared_with_me,
1265 const std::string& entry_kind) { 1264 const std::string& entry_kind) {
1266 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1265 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
(...skipping 11 matching lines...) Expand all
1278 new_entry->SetString("gd$resourceId.$t", resource_id); 1277 new_entry->SetString("gd$resourceId.$t", resource_id);
1279 new_entry->SetString("title.$t", title); 1278 new_entry->SetString("title.$t", title);
1280 new_entry->SetString("docs$filename", title); 1279 new_entry->SetString("docs$filename", title);
1281 // Set the contents, size and MD5 for a file. 1280 // Set the contents, size and MD5 for a file.
1282 if (entry_kind == "file") { 1281 if (entry_kind == "file") {
1283 new_entry->Set("test$data", 1282 new_entry->Set("test$data",
1284 base::BinaryValue::CreateWithCopiedBuffer( 1283 base::BinaryValue::CreateWithCopiedBuffer(
1285 content_data.c_str(), content_data.size())); 1284 content_data.c_str(), content_data.size()));
1286 new_entry->SetString("docs$size.$t", 1285 new_entry->SetString("docs$size.$t",
1287 base::Int64ToString(content_data.size())); 1286 base::Int64ToString(content_data.size()));
1288 // TODO(satorux): Set the correct MD5 here.
1289 new_entry->SetString("docs$md5Checksum.$t", 1287 new_entry->SetString("docs$md5Checksum.$t",
1290 "3b4385ebefec6e743574c76bbd0575de"); 1288 base::MD5String(content_data));
1291 } 1289 }
1292 1290
1293 // Add "category" which sets the resource type to |entry_kind|. 1291 // Add "category" which sets the resource type to |entry_kind|.
1294 base::ListValue* categories = new base::ListValue; 1292 base::ListValue* categories = new base::ListValue;
1295 base::DictionaryValue* category = new base::DictionaryValue; 1293 base::DictionaryValue* category = new base::DictionaryValue;
1296 category->SetString("scheme", "http://schemas.google.com/g/2005#kind"); 1294 category->SetString("scheme", "http://schemas.google.com/g/2005#kind");
1297 category->SetString("term", "http://schemas.google.com/docs/2007#" + 1295 category->SetString("term", "http://schemas.google.com/docs/2007#" +
1298 entry_kind); 1296 entry_kind);
1299 categories->Append(category); 1297 categories->Append(category);
1300 new_entry->Set("category", categories); 1298 new_entry->Set("category", categories);
(...skipping 28 matching lines...) Expand all
1329 edit_link->SetString("href", "https://xxx/edit/" + escaped_resource_id); 1327 edit_link->SetString("href", "https://xxx/edit/" + escaped_resource_id);
1330 edit_link->SetString("rel", "edit"); 1328 edit_link->SetString("rel", "edit");
1331 links->Append(edit_link); 1329 links->Append(edit_link);
1332 1330
1333 base::DictionaryValue* upload_link = new base::DictionaryValue; 1331 base::DictionaryValue* upload_link = new base::DictionaryValue;
1334 upload_link->SetString("href", upload_url.spec()); 1332 upload_link->SetString("href", upload_url.spec());
1335 upload_link->SetString("rel", kUploadUrlRel); 1333 upload_link->SetString("rel", kUploadUrlRel);
1336 links->Append(upload_link); 1334 links->Append(upload_link);
1337 new_entry->Set("link", links); 1335 new_entry->Set("link", links);
1338 1336
1339 AddNewChangestamp(new_entry.get()); 1337 AddNewChangestampAndETag(new_entry.get());
1340 1338
1341 base::Time published_date = 1339 base::Time published_date =
1342 base::Time() + base::TimeDelta::FromMilliseconds(++published_date_seq_); 1340 base::Time() + base::TimeDelta::FromMilliseconds(++published_date_seq_);
1343 new_entry->SetString("published.$t", 1341 new_entry->SetString("published.$t",
1344 util::FormatTimeAsString(published_date)); 1342 util::FormatTimeAsString(published_date));
1345 1343
1346 // If there are no entries, prepare an empty entry to add. 1344 // If there are no entries, prepare an empty entry to add.
1347 if (!resource_list_value_->HasKey("entry")) 1345 if (!resource_list_value_->HasKey("entry"))
1348 resource_list_value_->Set("entry", new ListValue); 1346 resource_list_value_->Set("entry", new ListValue);
1349 1347
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
1465 1463
1466 if (load_counter) 1464 if (load_counter)
1467 *load_counter += 1; 1465 *load_counter += 1;
1468 base::MessageLoop::current()->PostTask( 1466 base::MessageLoop::current()->PostTask(
1469 FROM_HERE, 1467 FROM_HERE,
1470 base::Bind(callback, 1468 base::Bind(callback,
1471 HTTP_SUCCESS, 1469 HTTP_SUCCESS,
1472 base::Passed(&resource_list))); 1470 base::Passed(&resource_list)));
1473 } 1471 }
1474 1472
1473 GURL FakeDriveService::GetNewUploadSessionUrl() {
1474 return GURL("https://upload_session_url/" +
1475 base::Int64ToString(next_upload_sequence_number_++));
1476 }
1477
1475 } // namespace drive 1478 } // namespace drive
OLDNEW
« no previous file with comments | « chrome/browser/drive/fake_drive_service.h ('k') | chrome/browser/drive/fake_drive_service_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698