fake_drive_service_helper.cc revision 424c4d7b64af9d0d8fd9624f381f469654d5e3d2
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_drive_service_helper.h"
6
7#include "base/bind.h"
8#include "base/file_util.h"
9#include "base/message_loop/message_loop.h"
10#include "base/threading/sequenced_worker_pool.h"
11#include "chrome/browser/sync_file_system/drive_backend/api_util.h"
12#include "chrome/browser/sync_file_system/sync_status_code.h"
13#include "content/public/test/test_browser_thread.h"
14#include "testing/gtest/include/gtest/gtest.h"
15#include "webkit/browser/fileapi/file_system_url.h"
16
17#define FPL(path) FILE_PATH_LITERAL(path)
18
19using google_apis::GDataErrorCode;
20using google_apis::ResourceEntry;
21using google_apis::ResourceList;
22
23namespace sync_file_system {
24namespace drive_backend {
25
26namespace {
27
28void ResourceEntryResultCallback(GDataErrorCode* error_out,
29                                 scoped_ptr<ResourceEntry>* entry_out,
30                                 GDataErrorCode error,
31                                 scoped_ptr<ResourceEntry> entry) {
32  ASSERT_TRUE(error_out);
33  ASSERT_TRUE(entry_out);
34  *error_out = error;
35  *entry_out = entry.Pass();
36}
37
38void UploadResultCallback(GDataErrorCode* error_out,
39                          scoped_ptr<ResourceEntry>* entry_out,
40                          GDataErrorCode error,
41                          const GURL& upload_location,
42                          scoped_ptr<ResourceEntry> entry) {
43  ASSERT_TRUE(error_out);
44  ASSERT_TRUE(entry_out);
45  *error_out = error;
46  *entry_out = entry.Pass();
47}
48
49void ResourceListResultCallback(GDataErrorCode* error_out,
50                                scoped_ptr<ResourceList>* list_out,
51                                GDataErrorCode error,
52                                scoped_ptr<ResourceList> list) {
53  ASSERT_TRUE(error_out);
54  ASSERT_TRUE(list_out);
55  *error_out = error;
56  *list_out = list.Pass();
57}
58
59void GDataErrorResultCallback(GDataErrorCode* error_out,
60                              GDataErrorCode error) {
61  ASSERT_TRUE(error_out);
62  *error_out = error;
63}
64
65void DownloadResultCallback(GDataErrorCode* error_out,
66                            GDataErrorCode error,
67                            const base::FilePath& local_file) {
68  ASSERT_TRUE(error_out);
69  *error_out = error;
70}
71
72}  // namespace
73
74FakeDriveServiceHelper::FakeDriveServiceHelper(
75    drive::FakeDriveService* fake_drive_service,
76    drive::DriveUploaderInterface* drive_uploader)
77    : fake_drive_service_(fake_drive_service),
78      drive_uploader_(drive_uploader) {
79  Initialize();
80}
81
82FakeDriveServiceHelper::~FakeDriveServiceHelper() {
83}
84
85GDataErrorCode FakeDriveServiceHelper::AddOrphanedFolder(
86    const std::string& title,
87    std::string* folder_id) {
88  EXPECT_TRUE(folder_id);
89
90  std::string root_folder_id = fake_drive_service_->GetRootResourceId();
91  GDataErrorCode error = AddFolder(root_folder_id, title, folder_id);
92  if (error != google_apis::HTTP_CREATED)
93    return error;
94
95  error = google_apis::GDATA_OTHER_ERROR;
96  fake_drive_service_->RemoveResourceFromDirectory(
97      root_folder_id, *folder_id,
98      base::Bind(&GDataErrorResultCallback, &error));
99  FlushMessageLoop();
100
101  if (error != google_apis::HTTP_SUCCESS)
102    return error;
103  return google_apis::HTTP_CREATED;
104}
105
106GDataErrorCode FakeDriveServiceHelper::AddFolder(
107    const std::string& parent_folder_id,
108    const std::string& title,
109    std::string* folder_id) {
110  EXPECT_TRUE(folder_id);
111
112  GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
113  scoped_ptr<ResourceEntry> folder;
114  fake_drive_service_->AddNewDirectory(
115      parent_folder_id, title,
116      base::Bind(&ResourceEntryResultCallback, &error, &folder));
117  FlushMessageLoop();
118
119  if (error == google_apis::HTTP_CREATED)
120    *folder_id = folder->resource_id();
121  return error;
122}
123
124GDataErrorCode FakeDriveServiceHelper::AddFile(
125    const std::string& parent_folder_id,
126    const std::string& title,
127    const std::string& content,
128    std::string* file_id) {
129  EXPECT_TRUE(file_id);
130  base::FilePath temp_file = WriteToTempFile(content);
131
132  GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
133  scoped_ptr<ResourceEntry> file;
134  drive_uploader_->UploadNewFile(
135      parent_folder_id, temp_file, title,
136      "application/octet-stream",
137      base::Bind(&UploadResultCallback, &error, &file),
138      google_apis::ProgressCallback());
139  FlushMessageLoop();
140
141  if (error == google_apis::HTTP_SUCCESS)
142    *file_id = file->resource_id();
143  return error;
144}
145
146GDataErrorCode FakeDriveServiceHelper::UpdateFile(
147    const std::string& file_id,
148    const std::string& content) {
149  base::FilePath temp_file = WriteToTempFile(content);
150  GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
151  scoped_ptr<ResourceEntry> file;
152  drive_uploader_->UploadExistingFile(
153      file_id, temp_file,
154      "application/octet-stream",
155      std::string(),  // etag
156      base::Bind(&UploadResultCallback, &error, &file),
157      google_apis::ProgressCallback());
158  FlushMessageLoop();
159  return error;
160}
161
162GDataErrorCode FakeDriveServiceHelper::RemoveResource(
163    const std::string& file_id) {
164  GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
165  fake_drive_service_->DeleteResource(
166      file_id,
167      std::string(),  // etag
168      base::Bind(&GDataErrorResultCallback, &error));
169  FlushMessageLoop();
170  return error;
171}
172
173GDataErrorCode FakeDriveServiceHelper::GetSyncRootFolderID(
174    std::string* sync_root_folder_id) {
175  GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
176  scoped_ptr<ResourceList> resource_list;
177  fake_drive_service_->SearchByTitle(
178      APIUtil::GetSyncRootDirectoryName(), std::string(),
179      base::Bind(&ResourceListResultCallback, &error, &resource_list));
180  FlushMessageLoop();
181  if (error != google_apis::HTTP_SUCCESS)
182    return error;
183
184  const ScopedVector<ResourceEntry>& entries = resource_list->entries();
185  for (ScopedVector<ResourceEntry>::const_iterator itr = entries.begin();
186       itr != entries.end(); ++itr) {
187    const ResourceEntry& entry = **itr;
188    if (!entry.GetLinkByType(google_apis::Link::LINK_PARENT)) {
189      *sync_root_folder_id = entry.resource_id();
190      return google_apis::HTTP_SUCCESS;
191    }
192  }
193  return google_apis::HTTP_NOT_FOUND;
194}
195
196GDataErrorCode FakeDriveServiceHelper::ListFilesInFolder(
197    const std::string& folder_id,
198    ScopedVector<ResourceEntry>* entries) {
199  GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
200  scoped_ptr<ResourceList> list;
201  fake_drive_service_->GetResourceListInDirectory(
202      folder_id,
203      base::Bind(&ResourceListResultCallback, &error, &list));
204  FlushMessageLoop();
205  if (error != google_apis::HTTP_SUCCESS)
206    return error;
207
208  return CompleteListing(list.Pass(), entries);
209}
210
211GDataErrorCode FakeDriveServiceHelper::SearchByTitle(
212    const std::string& folder_id,
213    const std::string& title,
214    ScopedVector<ResourceEntry>* entries) {
215  GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
216  scoped_ptr<ResourceList> list;
217  fake_drive_service_->SearchByTitle(
218      title, folder_id,
219      base::Bind(&ResourceListResultCallback, &error, &list));
220  FlushMessageLoop();
221  if (error != google_apis::HTTP_SUCCESS)
222    return error;
223
224  return CompleteListing(list.Pass(), entries);
225}
226
227GDataErrorCode FakeDriveServiceHelper::GetResourceEntry(
228    const std::string& file_id,
229    scoped_ptr<ResourceEntry>* entry) {
230  GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
231  fake_drive_service_->GetResourceEntry(
232      file_id,
233      base::Bind(&ResourceEntryResultCallback, &error, entry));
234  FlushMessageLoop();
235  return error;
236}
237
238GDataErrorCode FakeDriveServiceHelper::ReadFile(
239    const std::string& file_id,
240    std::string* file_content) {
241  scoped_ptr<google_apis::ResourceEntry> file;
242  GDataErrorCode error = GetResourceEntry(file_id, &file);
243  if (error != google_apis::HTTP_SUCCESS)
244    return error;
245  if (!file)
246    return google_apis::GDATA_PARSE_ERROR;
247
248  error = google_apis::GDATA_OTHER_ERROR;
249  base::FilePath temp_file;
250  EXPECT_TRUE(file_util::CreateTemporaryFileInDir(temp_dir_, &temp_file));
251  fake_drive_service_->DownloadFile(
252      temp_file, file->resource_id(),
253      base::Bind(&DownloadResultCallback, &error),
254      google_apis::GetContentCallback(),
255      google_apis::ProgressCallback());
256  FlushMessageLoop();
257  if (error != google_apis::HTTP_SUCCESS)
258    return error;
259
260  return file_util::ReadFileToString(temp_file, file_content)
261      ? google_apis::HTTP_SUCCESS : google_apis::GDATA_FILE_ERROR;
262}
263
264GDataErrorCode FakeDriveServiceHelper::CompleteListing(
265    scoped_ptr<ResourceList> list,
266    ScopedVector<ResourceEntry>* entries) {
267  while (true) {
268    entries->reserve(entries->size() + list->entries().size());
269    for (ScopedVector<ResourceEntry>::iterator itr =
270         list->mutable_entries()->begin();
271         itr != list->mutable_entries()->end(); ++itr) {
272      entries->push_back(*itr);
273      *itr = NULL;
274    }
275
276    // TODO(hidehiko): Use page token instead of next feed.
277    GURL next_feed;
278    if (!list->GetNextFeedURL(&next_feed))
279      return google_apis::HTTP_SUCCESS;
280
281    GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
282    list.reset();
283    fake_drive_service_->GetRemainingFileList(
284        next_feed.spec(),
285        base::Bind(&ResourceListResultCallback, &error, &list));
286    FlushMessageLoop();
287    if (error != google_apis::HTTP_SUCCESS)
288      return error;
289  }
290}
291
292void FakeDriveServiceHelper::Initialize() {
293  ASSERT_TRUE(base_dir_.CreateUniqueTempDir());
294  temp_dir_ = base_dir_.path().Append(FPL("tmp"));
295  ASSERT_TRUE(file_util::CreateDirectory(temp_dir_));
296}
297
298base::FilePath FakeDriveServiceHelper::WriteToTempFile(
299    const std::string& content) {
300  base::FilePath temp_file;
301  EXPECT_TRUE(file_util::CreateTemporaryFileInDir(temp_dir_, &temp_file));
302  EXPECT_EQ(static_cast<int>(content.size()),
303            file_util::WriteFile(temp_file, content.data(), content.size()));
304  return temp_file;
305}
306
307void FakeDriveServiceHelper::FlushMessageLoop() {
308  base::MessageLoop::current()->RunUntilIdle();
309  content::BrowserThread::GetBlockingPool()->FlushForTesting();
310  base::MessageLoop::current()->RunUntilIdle();
311}
312
313}  // namespace drive_backend
314}  // namespace sync_file_system
315