1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/sync_file_system/drive_backend/fake_api_util.h"
6
7#include <algorithm>
8
9#include "base/bind.h"
10#include "base/location.h"
11#include "base/message_loop/message_loop_proxy.h"
12#include "chrome/browser/google_apis/drive_entry_kinds.h"
13#include "webkit/common/blob/scoped_file.h"
14
15namespace sync_file_system {
16namespace drive_backend {
17
18bool FakeAPIUtil::RemoteResourceComparator::operator()(
19    const RemoteResource& left,
20    const RemoteResource& right) {
21  if (left.parent_resource_id != right.parent_resource_id)
22    return left.parent_resource_id < right.parent_resource_id;
23  if (left.parent_title != right.parent_title)
24    return left.parent_title < right.parent_title;
25  if (left.title != right.title)
26    return left.title < right.title;
27  if (left.resource_id != right.resource_id)
28    return left.resource_id < right.resource_id;
29  if (left.md5_checksum != right.md5_checksum)
30    return left.md5_checksum < right.md5_checksum;
31  if (left.deleted != right.deleted)
32    return left.deleted < right.deleted;
33  return left.changestamp < right.changestamp;
34}
35
36struct FakeAPIUtil::ChangeStampComparator {
37  bool operator()(const google_apis::ResourceEntry* left,
38                  const google_apis::ResourceEntry* right) {
39    return left->changestamp() < right->changestamp();
40  }
41};
42
43FakeAPIUtil::RemoteResource::RemoteResource()
44    : type(SYNC_FILE_TYPE_UNKNOWN), deleted(false), changestamp(0) {}
45
46FakeAPIUtil::RemoteResource::RemoteResource(
47    const std::string& parent_resource_id,
48    const std::string& parent_title,
49    const std::string& title,
50    const std::string& resource_id,
51    const std::string& md5_checksum,
52    SyncFileType type,
53    bool deleted,
54    int64 changestamp)
55    : parent_resource_id(parent_resource_id),
56      parent_title(parent_title),
57      title(title),
58      resource_id(resource_id),
59      md5_checksum(md5_checksum),
60      type(type),
61      deleted(deleted),
62      changestamp(changestamp) {}
63
64FakeAPIUtil::RemoteResource::~RemoteResource() {}
65
66FakeAPIUtil::FakeAPIUtil()
67    : largest_changestamp_(0),
68      url_generator_(
69          GURL(google_apis::GDataWapiUrlGenerator::kBaseUrlForProduction),
70          GURL(google_apis::GDataWapiUrlGenerator::
71               kBaseDownloadUrlForProduction)) {}
72
73FakeAPIUtil::~FakeAPIUtil() {}
74
75void FakeAPIUtil::AddObserver(APIUtilObserver* observer) {}
76
77void FakeAPIUtil::RemoveObserver(APIUtilObserver* observer) {}
78
79void FakeAPIUtil::GetDriveDirectoryForSyncRoot(
80    const ResourceIdCallback& callback) {
81  base::MessageLoopProxy::current()->PostTask(
82      FROM_HERE,
83      base::Bind(callback,
84                 google_apis::HTTP_SUCCESS,
85                 "folder: sync_root_resource_id"));
86}
87
88void FakeAPIUtil::GetDriveDirectoryForOrigin(
89    const std::string& sync_root_resource_id,
90    const GURL& origin,
91    const ResourceIdCallback& callback) {
92  base::MessageLoopProxy::current()->PostTask(
93      FROM_HERE,
94      base::Bind(callback,
95                 google_apis::HTTP_SUCCESS,
96                 "folder resource_id for " + origin.host()));
97}
98
99void FakeAPIUtil::GetLargestChangeStamp(const ChangeStampCallback& callback) {
100  base::MessageLoopProxy::current()->PostTask(
101      FROM_HERE,
102      base::Bind(callback, google_apis::HTTP_SUCCESS, largest_changestamp_));
103}
104
105void FakeAPIUtil::GetResourceEntry(const std::string& resource_id,
106                                   const ResourceEntryCallback& callback) {
107  NOTREACHED();
108}
109
110void FakeAPIUtil::ListFiles(const std::string& directory_resource_id,
111                            const ResourceListCallback& callback) {
112  ListChanges(0, callback);
113}
114
115void FakeAPIUtil::ListChanges(int64 start_changestamp,
116                              const ResourceListCallback& callback) {
117  scoped_ptr<google_apis::ResourceList> change_feed(
118      new google_apis::ResourceList());
119
120  ScopedVector<google_apis::ResourceEntry> entries;
121  typedef RemoteResourceByResourceId::const_iterator iterator;
122  for (iterator itr = remote_resources_.begin();
123       itr != remote_resources_.end(); ++itr) {
124    if (itr->second.changestamp < start_changestamp)
125      continue;
126    scoped_ptr<google_apis::ResourceEntry> entry(
127        CreateResourceEntry(itr->second));
128    entries.push_back(entry.release());
129  }
130
131  std::sort(entries.begin(), entries.end(), ChangeStampComparator());
132
133  change_feed->set_entries(&entries);
134  change_feed->set_largest_changestamp(largest_changestamp_);
135
136  base::MessageLoopProxy::current()->PostTask(
137      FROM_HERE,
138      base::Bind(
139          callback, google_apis::HTTP_SUCCESS, base::Passed(&change_feed)));
140}
141
142void FakeAPIUtil::ContinueListing(const GURL& feed_url,
143                                  const ResourceListCallback& callback) {
144  NOTREACHED();
145}
146
147void FakeAPIUtil::DownloadFile(const std::string& resource_id,
148                               const std::string& local_file_md5,
149                               const DownloadFileCallback& callback) {
150  RemoteResourceByResourceId::iterator found =
151      remote_resources_.find(resource_id);
152  std::string file_md5;
153  int64 file_size = 0;
154  base::Time updated_time;
155  google_apis::GDataErrorCode error = google_apis::HTTP_NOT_FOUND;
156
157  if (found != remote_resources_.end() && !found->second.deleted) {
158    scoped_ptr<google_apis::ResourceEntry> entry(
159        CreateResourceEntry(found->second));
160    file_md5 = entry->file_md5();
161    file_size = entry->file_size();
162    updated_time = entry->updated_time();
163    error = google_apis::HTTP_SUCCESS;
164  }
165
166  scoped_ptr<webkit_blob::ScopedFile> dummy_local_file(
167      new webkit_blob::ScopedFile);
168  base::MessageLoopProxy::current()->PostTask(
169      FROM_HERE,
170      base::Bind(callback, error, file_md5, file_size, updated_time,
171                 base::Passed(&dummy_local_file)));
172}
173
174void FakeAPIUtil::UploadNewFile(const std::string& directory_resource_id,
175                                const base::FilePath& local_file_path,
176                                const std::string& title,
177                                const UploadFileCallback& callback) {
178  NOTREACHED();
179}
180
181void FakeAPIUtil::UploadExistingFile(const std::string& resource_id,
182                                     const std::string& remote_file_md5,
183                                     const base::FilePath& local_file_path,
184                                     const UploadFileCallback& callback) {
185  NOTREACHED();
186}
187
188void FakeAPIUtil::CreateDirectory(const std::string& parent_resource_id,
189                                  const std::string& title,
190                                  const ResourceIdCallback& callback) {
191  NOTREACHED();
192}
193
194bool FakeAPIUtil::IsAuthenticated() const { return true; }
195
196void FakeAPIUtil::DeleteFile(const std::string& resource_id,
197                             const std::string& remote_file_md5,
198                             const GDataErrorCallback& callback) {
199  if (!ContainsKey(remote_resources_, resource_id)) {
200    base::MessageLoopProxy::current()->PostTask(
201        FROM_HERE,
202        base::Bind(callback, google_apis::HTTP_NOT_FOUND));
203    return;
204  }
205
206  const RemoteResource& deleted_directory = remote_resources_[resource_id];
207  PushRemoteChange(deleted_directory.parent_resource_id,
208                   deleted_directory.parent_title,
209                   deleted_directory.title,
210                   deleted_directory.resource_id,
211                   deleted_directory.md5_checksum,
212                   SYNC_FILE_TYPE_UNKNOWN,
213                   true /* deleted */);
214
215  base::MessageLoopProxy::current()->PostTask(
216      FROM_HERE,
217      base::Bind(callback, google_apis::HTTP_SUCCESS));
218}
219
220GURL FakeAPIUtil::ResourceIdToResourceLink(
221    const std::string& resource_id) const {
222  return url_generator_.GenerateEditUrl(resource_id);
223}
224
225void FakeAPIUtil::EnsureSyncRootIsNotInMyDrive(
226    const std::string& sync_root_resource_id) {
227  // Nothing to do.
228}
229
230void FakeAPIUtil::PushRemoteChange(const std::string& parent_resource_id,
231                                   const std::string& parent_title,
232                                   const std::string& title,
233                                   const std::string& resource_id,
234                                   const std::string& md5,
235                                   SyncFileType type,
236                                   bool deleted) {
237  remote_resources_[resource_id] = RemoteResource(
238      parent_resource_id, parent_title, title, resource_id,
239      md5, type, deleted, ++largest_changestamp_);
240}
241
242scoped_ptr<google_apis::ResourceEntry> FakeAPIUtil::CreateResourceEntry(
243    const RemoteResource& resource) const {
244  scoped_ptr<google_apis::ResourceEntry> entry(
245      new google_apis::ResourceEntry());
246  ScopedVector<google_apis::Link> parent_links;
247  scoped_ptr<google_apis::Link> link(new google_apis::Link());
248
249  link->set_type(google_apis::Link::LINK_PARENT);
250  link->set_href(ResourceIdToResourceLink(resource.parent_resource_id));
251  link->set_title(resource.parent_title);
252  parent_links.push_back(link.release());
253
254  entry->set_links(&parent_links);
255  entry->set_title(resource.title);
256  entry->set_resource_id(resource.resource_id);
257  entry->set_file_md5(resource.md5_checksum);
258  entry->set_deleted(resource.deleted);
259  entry->set_changestamp(resource.changestamp);
260
261  switch (resource.type) {
262    case SYNC_FILE_TYPE_FILE:
263      entry->set_kind(google_apis::ENTRY_KIND_FILE);
264      break;
265    case SYNC_FILE_TYPE_DIRECTORY:
266      entry->set_kind(google_apis::ENTRY_KIND_FOLDER);
267      break;
268    case SYNC_FILE_TYPE_UNKNOWN:
269      entry->set_kind(google_apis::ENTRY_KIND_UNKNOWN);
270      break;
271  }
272
273  return entry.Pass();
274}
275
276}  // namespace drive_backend
277}  // namespace sync_file_system
278