resource_metadata_unittest.cc revision 4e180b6a0b4720a9b8e9e959a882386f690f08ff
1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/chromeos/drive/resource_metadata.h"
6
7#include <algorithm>
8#include <string>
9#include <vector>
10
11#include "base/files/scoped_temp_dir.h"
12#include "base/sequenced_task_runner.h"
13#include "base/threading/sequenced_worker_pool.h"
14#include "base/threading/thread_restrictions.h"
15#include "chrome/browser/chromeos/drive/drive.pb.h"
16#include "chrome/browser/chromeos/drive/file_system_util.h"
17#include "chrome/browser/chromeos/drive/test_util.h"
18#include "chrome/browser/google_apis/test_util.h"
19#include "content/public/browser/browser_thread.h"
20#include "content/public/test/test_browser_thread_bundle.h"
21#include "testing/gtest/include/gtest/gtest.h"
22
23namespace drive {
24namespace internal {
25namespace {
26
27const char kTestRootResourceId[] = "test_root";
28
29// The changestamp of the resource metadata used in
30// ResourceMetadataTest.
31const int64 kTestChangestamp = 100;
32
33// Returns the sorted base names from |entries|.
34std::vector<std::string> GetSortedBaseNames(
35    const ResourceEntryVector& entries) {
36  std::vector<std::string> base_names;
37  for (size_t i = 0; i < entries.size(); ++i)
38    base_names.push_back(entries[i].base_name());
39  std::sort(base_names.begin(), base_names.end());
40
41  return base_names;
42}
43
44// Creates a ResourceEntry for a directory with explicitly set resource_id.
45ResourceEntry CreateDirectoryEntryWithResourceId(
46    const std::string& title,
47    const std::string& resource_id,
48    const std::string& parent_local_id) {
49  ResourceEntry entry;
50  entry.set_title(title);
51  entry.set_resource_id(resource_id);
52  entry.set_parent_local_id(parent_local_id);
53  entry.mutable_file_info()->set_is_directory(true);
54  entry.mutable_directory_specific_info()->set_changestamp(kTestChangestamp);
55  return entry;
56}
57
58// Creates a ResourceEntry for a directory.
59ResourceEntry CreateDirectoryEntry(const std::string& title,
60                                   const std::string& parent_local_id) {
61  return CreateDirectoryEntryWithResourceId(
62      title, "id:" + title, parent_local_id);
63}
64
65// Creates a ResourceEntry for a file with explicitly set resource_id.
66ResourceEntry CreateFileEntryWithResourceId(
67    const std::string& title,
68    const std::string& resource_id,
69    const std::string& parent_local_id) {
70  ResourceEntry entry;
71  entry.set_title(title);
72  entry.set_resource_id(resource_id);
73  entry.set_parent_local_id(parent_local_id);
74  entry.mutable_file_info()->set_is_directory(false);
75  entry.mutable_file_info()->set_size(1024);
76  entry.mutable_file_specific_info()->set_md5("md5:" + title);
77  return entry;
78}
79
80// Creates a ResourceEntry for a file.
81ResourceEntry CreateFileEntry(const std::string& title,
82                              const std::string& parent_local_id) {
83  return CreateFileEntryWithResourceId(title, "id:" + title, parent_local_id);
84}
85
86// Creates the following files/directories
87// drive/root/dir1/
88// drive/root/dir2/
89// drive/root/dir1/dir3/
90// drive/root/dir1/file4
91// drive/root/dir1/file5
92// drive/root/dir2/file6
93// drive/root/dir2/file7
94// drive/root/dir2/file8
95// drive/root/dir1/dir3/file9
96// drive/root/dir1/dir3/file10
97void SetUpEntries(ResourceMetadata* resource_metadata) {
98  // Create mydrive root directory.
99  std::string local_id;
100  ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(
101      util::CreateMyDriveRootEntry(kTestRootResourceId), &local_id));
102  const std::string root_local_id = local_id;
103
104  ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(
105      CreateDirectoryEntry("dir1", root_local_id), &local_id));
106  const std::string local_id_dir1 = local_id;
107
108  ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(
109      CreateDirectoryEntry("dir2", root_local_id), &local_id));
110  const std::string local_id_dir2 = local_id;
111
112  ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(
113      CreateDirectoryEntry("dir3", local_id_dir1), &local_id));
114  const std::string local_id_dir3 = local_id;
115
116  ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(
117      CreateFileEntry("file4", local_id_dir1), &local_id));
118  ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(
119      CreateFileEntry("file5", local_id_dir1), &local_id));
120
121  ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(
122      CreateFileEntry("file6", local_id_dir2), &local_id));
123  ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(
124      CreateFileEntry("file7", local_id_dir2), &local_id));
125  ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(
126      CreateFileEntry("file8", local_id_dir2), &local_id));
127
128  ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(
129      CreateFileEntry("file9", local_id_dir3), &local_id));
130  ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(
131      CreateFileEntry("file10", local_id_dir3), &local_id));
132
133  ASSERT_EQ(FILE_ERROR_OK,
134            resource_metadata->SetLargestChangestamp(kTestChangestamp));
135}
136
137}  // namespace
138
139// Tests for methods invoked from the UI thread.
140class ResourceMetadataTestOnUIThread : public testing::Test {
141 protected:
142  virtual void SetUp() OVERRIDE {
143    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
144
145    base::ThreadRestrictions::SetIOAllowed(false);  // For strict thread check.
146    scoped_refptr<base::SequencedWorkerPool> pool =
147        content::BrowserThread::GetBlockingPool();
148    blocking_task_runner_ =
149        pool->GetSequencedTaskRunner(pool->GetSequenceToken());
150
151    metadata_storage_.reset(new ResourceMetadataStorage(
152        temp_dir_.path(), blocking_task_runner_.get()));
153    bool success = false;
154    base::PostTaskAndReplyWithResult(
155        blocking_task_runner_.get(),
156        FROM_HERE,
157        base::Bind(&ResourceMetadataStorage::Initialize,
158                   base::Unretained(metadata_storage_.get())),
159        google_apis::test_util::CreateCopyResultCallback(&success));
160    test_util::RunBlockingPoolTask();
161    ASSERT_TRUE(success);
162
163    resource_metadata_.reset(new ResourceMetadata(metadata_storage_.get(),
164                                                  blocking_task_runner_));
165
166    FileError error = FILE_ERROR_FAILED;
167    base::PostTaskAndReplyWithResult(
168        blocking_task_runner_.get(),
169        FROM_HERE,
170        base::Bind(&ResourceMetadata::Initialize,
171                   base::Unretained(resource_metadata_.get())),
172        google_apis::test_util::CreateCopyResultCallback(&error));
173    test_util::RunBlockingPoolTask();
174    ASSERT_EQ(FILE_ERROR_OK, error);
175
176    blocking_task_runner_->PostTask(
177        FROM_HERE,
178        base::Bind(&SetUpEntries,
179                   base::Unretained(resource_metadata_.get())));
180    test_util::RunBlockingPoolTask();
181  }
182
183  virtual void TearDown() OVERRIDE {
184    metadata_storage_.reset();
185    resource_metadata_.reset();
186    base::ThreadRestrictions::SetIOAllowed(true);
187  }
188
189  content::TestBrowserThreadBundle thread_bundle_;
190  base::ScopedTempDir temp_dir_;
191  scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
192  scoped_ptr<ResourceMetadataStorage, test_util::DestroyHelperForTests>
193      metadata_storage_;
194  scoped_ptr<ResourceMetadata, test_util::DestroyHelperForTests>
195      resource_metadata_;
196};
197
198TEST_F(ResourceMetadataTestOnUIThread, GetResourceEntryById_RootDirectory) {
199  // Look up the root directory by its resource ID.
200  FileError error = FILE_ERROR_FAILED;
201  scoped_ptr<ResourceEntry> entry;
202  resource_metadata_->GetResourceEntryByIdOnUIThread(
203      util::kDriveGrandRootSpecialResourceId,
204      google_apis::test_util::CreateCopyResultCallback(&error, &entry));
205  test_util::RunBlockingPoolTask();
206  EXPECT_EQ(FILE_ERROR_OK, error);
207  ASSERT_TRUE(entry.get());
208  EXPECT_EQ("drive", entry->base_name());
209}
210
211TEST_F(ResourceMetadataTestOnUIThread, GetResourceEntryById) {
212  // Get file4 by path.
213  FileError error = FILE_ERROR_FAILED;
214  std::string local_id;
215  base::PostTaskAndReplyWithResult(
216      blocking_task_runner_,
217      FROM_HERE,
218      base::Bind(&ResourceMetadata::GetIdByPath,
219                 base::Unretained(resource_metadata_.get()),
220                 base::FilePath::FromUTF8Unsafe("drive/root/dir1/file4"),
221                 &local_id),
222      google_apis::test_util::CreateCopyResultCallback(&error));
223  test_util::RunBlockingPoolTask();
224  EXPECT_EQ(FILE_ERROR_OK, error);
225
226  // Confirm that an existing file is found.
227  error = FILE_ERROR_FAILED;
228  scoped_ptr<ResourceEntry> entry;
229  resource_metadata_->GetResourceEntryByIdOnUIThread(
230      local_id,
231      google_apis::test_util::CreateCopyResultCallback(&error, &entry));
232  test_util::RunBlockingPoolTask();
233  EXPECT_EQ(FILE_ERROR_OK, error);
234  ASSERT_TRUE(entry.get());
235  EXPECT_EQ("file4", entry->base_name());
236
237  // Confirm that a non existing file is not found.
238  error = FILE_ERROR_FAILED;
239  entry.reset();
240  resource_metadata_->GetResourceEntryByIdOnUIThread(
241      "file:non_existing",
242      google_apis::test_util::CreateCopyResultCallback(&error, &entry));
243  test_util::RunBlockingPoolTask();
244  EXPECT_EQ(FILE_ERROR_NOT_FOUND, error);
245  EXPECT_FALSE(entry.get());
246}
247
248TEST_F(ResourceMetadataTestOnUIThread, GetResourceEntryByPath) {
249  // Confirm that an existing file is found.
250  FileError error = FILE_ERROR_FAILED;
251  scoped_ptr<ResourceEntry> entry;
252  resource_metadata_->GetResourceEntryByPathOnUIThread(
253      base::FilePath::FromUTF8Unsafe("drive/root/dir1/file4"),
254      google_apis::test_util::CreateCopyResultCallback(&error, &entry));
255  test_util::RunBlockingPoolTask();
256  EXPECT_EQ(FILE_ERROR_OK, error);
257  ASSERT_TRUE(entry.get());
258  EXPECT_EQ("file4", entry->base_name());
259
260  // Confirm that a non existing file is not found.
261  error = FILE_ERROR_FAILED;
262  entry.reset();
263  resource_metadata_->GetResourceEntryByPathOnUIThread(
264      base::FilePath::FromUTF8Unsafe("drive/root/dir1/non_existing"),
265      google_apis::test_util::CreateCopyResultCallback(&error, &entry));
266  test_util::RunBlockingPoolTask();
267  EXPECT_EQ(FILE_ERROR_NOT_FOUND, error);
268  EXPECT_FALSE(entry.get());
269
270  // Confirm that the root is found.
271  error = FILE_ERROR_FAILED;
272  entry.reset();
273  resource_metadata_->GetResourceEntryByPathOnUIThread(
274      base::FilePath::FromUTF8Unsafe("drive"),
275      google_apis::test_util::CreateCopyResultCallback(&error, &entry));
276  test_util::RunBlockingPoolTask();
277  EXPECT_EQ(FILE_ERROR_OK, error);
278  EXPECT_TRUE(entry.get());
279
280  // Confirm that a non existing file is not found at the root level.
281  error = FILE_ERROR_FAILED;
282  entry.reset();
283  resource_metadata_->GetResourceEntryByPathOnUIThread(
284      base::FilePath::FromUTF8Unsafe("non_existing"),
285      google_apis::test_util::CreateCopyResultCallback(&error, &entry));
286  test_util::RunBlockingPoolTask();
287  EXPECT_EQ(FILE_ERROR_NOT_FOUND, error);
288  EXPECT_FALSE(entry.get());
289
290  // Confirm that an entry is not found with a wrong root.
291  error = FILE_ERROR_FAILED;
292  entry.reset();
293  resource_metadata_->GetResourceEntryByPathOnUIThread(
294      base::FilePath::FromUTF8Unsafe("non_existing/root"),
295      google_apis::test_util::CreateCopyResultCallback(&error, &entry));
296  test_util::RunBlockingPoolTask();
297  EXPECT_EQ(FILE_ERROR_NOT_FOUND, error);
298  EXPECT_FALSE(entry.get());
299}
300
301TEST_F(ResourceMetadataTestOnUIThread, ReadDirectoryByPath) {
302  // Confirm that an existing directory is found.
303  FileError error = FILE_ERROR_FAILED;
304  scoped_ptr<ResourceEntryVector> entries;
305  resource_metadata_->ReadDirectoryByPathOnUIThread(
306      base::FilePath::FromUTF8Unsafe("drive/root/dir1"),
307      google_apis::test_util::CreateCopyResultCallback(&error, &entries));
308  test_util::RunBlockingPoolTask();
309  EXPECT_EQ(FILE_ERROR_OK, error);
310  ASSERT_TRUE(entries.get());
311  ASSERT_EQ(3U, entries->size());
312  // The order is not guaranteed so we should sort the base names.
313  std::vector<std::string> base_names = GetSortedBaseNames(*entries);
314  EXPECT_EQ("dir3", base_names[0]);
315  EXPECT_EQ("file4", base_names[1]);
316  EXPECT_EQ("file5", base_names[2]);
317
318  // Confirm that a non existing directory is not found.
319  error = FILE_ERROR_FAILED;
320  entries.reset();
321  resource_metadata_->ReadDirectoryByPathOnUIThread(
322      base::FilePath::FromUTF8Unsafe("drive/root/non_existing"),
323      google_apis::test_util::CreateCopyResultCallback(&error, &entries));
324  test_util::RunBlockingPoolTask();
325  EXPECT_EQ(FILE_ERROR_NOT_FOUND, error);
326  EXPECT_FALSE(entries.get());
327
328  // Confirm that reading a file results in FILE_ERROR_NOT_A_DIRECTORY.
329  error = FILE_ERROR_FAILED;
330  entries.reset();
331  resource_metadata_->ReadDirectoryByPathOnUIThread(
332      base::FilePath::FromUTF8Unsafe("drive/root/dir1/file4"),
333      google_apis::test_util::CreateCopyResultCallback(&error, &entries));
334  test_util::RunBlockingPoolTask();
335  EXPECT_EQ(FILE_ERROR_NOT_A_DIRECTORY, error);
336  EXPECT_FALSE(entries.get());
337}
338
339// Tests for methods running on the blocking task runner.
340class ResourceMetadataTest : public testing::Test {
341 protected:
342  virtual void SetUp() OVERRIDE {
343    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
344
345    metadata_storage_.reset(new ResourceMetadataStorage(
346        temp_dir_.path(), base::MessageLoopProxy::current().get()));
347    ASSERT_TRUE(metadata_storage_->Initialize());
348
349    resource_metadata_.reset(new ResourceMetadata(
350        metadata_storage_.get(), base::MessageLoopProxy::current()));
351
352    ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->Initialize());
353
354    SetUpEntries(resource_metadata_.get());
355  }
356
357  base::ScopedTempDir temp_dir_;
358  content::TestBrowserThreadBundle thread_bundle_;
359  scoped_ptr<ResourceMetadataStorage, test_util::DestroyHelperForTests>
360      metadata_storage_;
361  scoped_ptr<ResourceMetadata, test_util::DestroyHelperForTests>
362      resource_metadata_;
363};
364
365TEST_F(ResourceMetadataTest, LargestChangestamp) {
366  const int64 kChangestamp = 123456;
367  EXPECT_EQ(FILE_ERROR_OK,
368            resource_metadata_->SetLargestChangestamp(kChangestamp));
369  EXPECT_EQ(kChangestamp, resource_metadata_->GetLargestChangestamp());
370}
371
372TEST_F(ResourceMetadataTest, RefreshEntry) {
373  base::FilePath drive_file_path;
374  ResourceEntry entry;
375
376  // Get file9.
377  std::string file_id;
378  EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath(
379      base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3/file9"), &file_id));
380  EXPECT_EQ(FILE_ERROR_OK,
381            resource_metadata_->GetResourceEntryById(file_id, &entry));
382  EXPECT_EQ("file9", entry.base_name());
383  EXPECT_TRUE(!entry.file_info().is_directory());
384  EXPECT_EQ("md5:file9", entry.file_specific_info().md5());
385
386  // Rename it.
387  ResourceEntry file_entry(entry);
388  file_entry.set_title("file100");
389  EXPECT_EQ(FILE_ERROR_OK,
390            resource_metadata_->RefreshEntry(file_entry));
391
392  EXPECT_EQ("drive/root/dir1/dir3/file100",
393            resource_metadata_->GetFilePath(file_id).AsUTF8Unsafe());
394  entry.Clear();
395  EXPECT_EQ(FILE_ERROR_OK,
396            resource_metadata_->GetResourceEntryById(file_id, &entry));
397  EXPECT_EQ("file100", entry.base_name());
398  EXPECT_TRUE(!entry.file_info().is_directory());
399  EXPECT_EQ("md5:file9", entry.file_specific_info().md5());
400
401  // Update the file md5.
402  const std::string updated_md5("md5:updated");
403  file_entry = entry;
404  file_entry.mutable_file_specific_info()->set_md5(updated_md5);
405  EXPECT_EQ(FILE_ERROR_OK,
406            resource_metadata_->RefreshEntry(file_entry));
407
408  EXPECT_EQ("drive/root/dir1/dir3/file100",
409            resource_metadata_->GetFilePath(file_id).AsUTF8Unsafe());
410  entry.Clear();
411  EXPECT_EQ(FILE_ERROR_OK,
412            resource_metadata_->GetResourceEntryById(file_id, &entry));
413  EXPECT_EQ("file100", entry.base_name());
414  EXPECT_TRUE(!entry.file_info().is_directory());
415  EXPECT_EQ(updated_md5, entry.file_specific_info().md5());
416
417  // Make sure we get the same thing from GetResourceEntryByPath.
418  entry.Clear();
419  EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryByPath(
420      base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3/file100"), &entry));
421  EXPECT_EQ("file100", entry.base_name());
422  ASSERT_TRUE(!entry.file_info().is_directory());
423  EXPECT_EQ(updated_md5, entry.file_specific_info().md5());
424
425  // Get dir2.
426  entry.Clear();
427  std::string dir_id;
428  EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath(
429      base::FilePath::FromUTF8Unsafe("drive/root/dir2"), &dir_id));
430  EXPECT_EQ(FILE_ERROR_OK,
431            resource_metadata_->GetResourceEntryById(dir_id, &entry));
432  EXPECT_EQ("dir2", entry.base_name());
433  ASSERT_TRUE(entry.file_info().is_directory());
434
435  // Get dir3's ID.
436  std::string dir3_id;
437  EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath(
438      base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3"), &dir3_id));
439
440  // Change the name to dir100 and change the parent to drive/dir1/dir3.
441  ResourceEntry dir_entry(entry);
442  dir_entry.set_title("dir100");
443  dir_entry.set_parent_local_id(dir3_id);
444  EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->RefreshEntry(dir_entry));
445
446  EXPECT_EQ("drive/root/dir1/dir3/dir100",
447            resource_metadata_->GetFilePath(dir_id).AsUTF8Unsafe());
448  entry.Clear();
449  EXPECT_EQ(FILE_ERROR_OK,
450            resource_metadata_->GetResourceEntryById(dir_id, &entry));
451  EXPECT_EQ("dir100", entry.base_name());
452  EXPECT_TRUE(entry.file_info().is_directory());
453  EXPECT_EQ("id:dir2", entry.resource_id());
454
455  // Make sure the children have moved over. Test file6.
456  entry.Clear();
457  EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryByPath(
458      base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3/dir100/file6"),
459      &entry));
460  EXPECT_EQ("file6", entry.base_name());
461
462  // Make sure dir2 no longer exists.
463  EXPECT_EQ(FILE_ERROR_NOT_FOUND, resource_metadata_->GetResourceEntryByPath(
464      base::FilePath::FromUTF8Unsafe("drive/root/dir2"), &entry));
465
466  // Make sure that directory cannot move under a file.
467  dir_entry.set_parent_local_id(file_id);
468  EXPECT_EQ(FILE_ERROR_NOT_A_DIRECTORY,
469            resource_metadata_->RefreshEntry(dir_entry));
470
471  // Cannot refresh root.
472  dir_entry.Clear();
473  dir_entry.set_resource_id(util::kDriveGrandRootSpecialResourceId);
474  dir_entry.set_local_id(util::kDriveGrandRootSpecialResourceId);
475  dir_entry.set_title("new-root-name");
476  dir_entry.set_parent_local_id(dir3_id);
477  EXPECT_EQ(FILE_ERROR_INVALID_OPERATION,
478            resource_metadata_->RefreshEntry(dir_entry));
479}
480
481TEST_F(ResourceMetadataTest, GetSubDirectoriesRecursively) {
482  std::set<base::FilePath> sub_directories;
483
484  // file9: not a directory, so no children.
485  std::string local_id;
486  EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath(
487      base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3/file9"), &local_id));
488  resource_metadata_->GetSubDirectoriesRecursively(local_id, &sub_directories);
489  EXPECT_TRUE(sub_directories.empty());
490
491  // dir2: no child directories.
492  EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath(
493      base::FilePath::FromUTF8Unsafe("drive/root/dir2"), &local_id));
494  resource_metadata_->GetSubDirectoriesRecursively(local_id, &sub_directories);
495  EXPECT_TRUE(sub_directories.empty());
496  const std::string dir2_id = local_id;
497
498  // dir1: dir3 is the only child
499  EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath(
500      base::FilePath::FromUTF8Unsafe("drive/root/dir1"), &local_id));
501  resource_metadata_->GetSubDirectoriesRecursively(local_id, &sub_directories);
502  EXPECT_EQ(1u, sub_directories.size());
503  EXPECT_EQ(1u, sub_directories.count(
504      base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3")));
505  sub_directories.clear();
506
507  // Add a few more directories to make sure deeper nesting works.
508  // dir2/dir100
509  // dir2/dir101
510  // dir2/dir101/dir102
511  // dir2/dir101/dir103
512  // dir2/dir101/dir104
513  // dir2/dir101/dir104/dir105
514  // dir2/dir101/dir104/dir105/dir106
515  // dir2/dir101/dir104/dir105/dir106/dir107
516  EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(
517      CreateDirectoryEntry("dir100", dir2_id), &local_id));
518  EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(
519      CreateDirectoryEntry("dir101", dir2_id), &local_id));
520  const std::string dir101_id = local_id;
521  EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(
522      CreateDirectoryEntry("dir102", dir101_id), &local_id));
523  EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(
524      CreateDirectoryEntry("dir103", dir101_id), &local_id));
525  EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(
526      CreateDirectoryEntry("dir104", dir101_id), &local_id));
527  EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(
528      CreateDirectoryEntry("dir105", local_id), &local_id));
529  EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(
530      CreateDirectoryEntry("dir106", local_id), &local_id));
531  EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(
532      CreateDirectoryEntry("dir107", local_id), &local_id));
533
534  resource_metadata_->GetSubDirectoriesRecursively(dir2_id, &sub_directories);
535  EXPECT_EQ(8u, sub_directories.size());
536  EXPECT_EQ(1u, sub_directories.count(base::FilePath::FromUTF8Unsafe(
537      "drive/root/dir2/dir101")));
538  EXPECT_EQ(1u, sub_directories.count(base::FilePath::FromUTF8Unsafe(
539      "drive/root/dir2/dir101/dir104")));
540  EXPECT_EQ(1u, sub_directories.count(base::FilePath::FromUTF8Unsafe(
541      "drive/root/dir2/dir101/dir104/dir105/dir106/dir107")));
542}
543
544TEST_F(ResourceMetadataTest, AddEntry) {
545  base::FilePath drive_file_path;
546
547  // Add a file to dir3.
548  std::string local_id;
549  EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath(
550      base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3"), &local_id));
551  ResourceEntry file_entry = CreateFileEntry("file100", local_id);
552  EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(file_entry, &local_id));
553  EXPECT_EQ("drive/root/dir1/dir3/file100",
554            resource_metadata_->GetFilePath(local_id).AsUTF8Unsafe());
555
556  // Add a directory.
557  EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath(
558      base::FilePath::FromUTF8Unsafe("drive/root/dir1"), &local_id));
559  ResourceEntry dir_entry = CreateDirectoryEntry("dir101", local_id);
560  EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(dir_entry, &local_id));
561  EXPECT_EQ("drive/root/dir1/dir101",
562            resource_metadata_->GetFilePath(local_id).AsUTF8Unsafe());
563
564  // Add to an invalid parent.
565  ResourceEntry file_entry3 = CreateFileEntry("file103", "id:invalid");
566  EXPECT_EQ(FILE_ERROR_NOT_FOUND,
567            resource_metadata_->AddEntry(file_entry3, &local_id));
568
569  // Add an existing file.
570  EXPECT_EQ(FILE_ERROR_EXISTS,
571            resource_metadata_->AddEntry(file_entry, &local_id));
572}
573
574TEST_F(ResourceMetadataTest, RemoveEntry) {
575  // Make sure file9 is found.
576  std::string file9_local_id;
577  EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath(
578      base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3/file9"),
579      &file9_local_id));
580  ResourceEntry entry;
581  EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById(
582      file9_local_id, &entry));
583  EXPECT_EQ("file9", entry.base_name());
584
585  // Remove file9.
586  EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->RemoveEntry(file9_local_id));
587
588  // file9 should no longer exist.
589  EXPECT_EQ(FILE_ERROR_NOT_FOUND, resource_metadata_->GetResourceEntryById(
590      file9_local_id, &entry));
591
592  // Look for dir3.
593  std::string dir3_local_id;
594  EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath(
595      base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3"), &dir3_local_id));
596  EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById(
597      dir3_local_id, &entry));
598  EXPECT_EQ("dir3", entry.base_name());
599
600  // Remove dir3.
601  EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->RemoveEntry(dir3_local_id));
602
603  // dir3 should no longer exist.
604  EXPECT_EQ(FILE_ERROR_NOT_FOUND, resource_metadata_->GetResourceEntryById(
605      dir3_local_id, &entry));
606
607  // Remove unknown local_id using RemoveEntry.
608  EXPECT_EQ(FILE_ERROR_NOT_FOUND, resource_metadata_->RemoveEntry("foo"));
609
610  // Try removing root. This should fail.
611  EXPECT_EQ(FILE_ERROR_ACCESS_DENIED, resource_metadata_->RemoveEntry(
612      util::kDriveGrandRootSpecialResourceId));
613}
614
615TEST_F(ResourceMetadataTest, Iterate) {
616  scoped_ptr<ResourceMetadata::Iterator> it = resource_metadata_->GetIterator();
617  ASSERT_TRUE(it);
618
619  int file_count = 0, directory_count = 0;
620  for (; !it->IsAtEnd(); it->Advance()) {
621    if (!it->GetValue().file_info().is_directory())
622      ++file_count;
623    else
624      ++directory_count;
625  }
626
627  EXPECT_EQ(7, file_count);
628  EXPECT_EQ(6, directory_count);
629}
630
631TEST_F(ResourceMetadataTest, DuplicatedNames) {
632  std::string root_local_id;
633  ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath(
634      base::FilePath::FromUTF8Unsafe("drive/root"), &root_local_id));
635
636  ResourceEntry entry;
637
638  // When multiple entries with the same title are added in a single directory,
639  // their base_names are de-duped.
640  // - drive/root/foo
641  // - drive/root/foo (1)
642  std::string dir_id_0;
643  ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(
644      CreateDirectoryEntryWithResourceId(
645          "foo", "foo0", root_local_id), &dir_id_0));
646  std::string dir_id_1;
647  ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(
648      CreateDirectoryEntryWithResourceId(
649          "foo", "foo1", root_local_id), &dir_id_1));
650
651  ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById(
652      dir_id_0, &entry));
653  EXPECT_EQ("foo", entry.base_name());
654  ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById(
655      dir_id_1, &entry));
656  EXPECT_EQ("foo (1)", entry.base_name());
657
658  // - drive/root/foo/bar.txt
659  // - drive/root/foo/bar (1).txt
660  // - drive/root/foo/bar (2).txt
661  std::string file_id_0;
662  ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(
663      CreateFileEntryWithResourceId(
664          "bar.txt", "bar0", dir_id_0), &file_id_0));
665  std::string file_id_1;
666  ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(
667      CreateFileEntryWithResourceId(
668          "bar.txt", "bar1", dir_id_0), &file_id_1));
669  std::string file_id_2;
670  ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(
671      CreateFileEntryWithResourceId(
672          "bar.txt", "bar2", dir_id_0), &file_id_2));
673
674  ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById(
675      file_id_0, &entry));
676  EXPECT_EQ("bar.txt", entry.base_name());
677  ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById(
678      file_id_1, &entry));
679  EXPECT_EQ("bar (1).txt", entry.base_name());
680  ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById(
681      file_id_2, &entry));
682  EXPECT_EQ("bar (2).txt", entry.base_name());
683
684  // Same name but different parent. No renaming.
685  // - drive/root/foo (1)/bar.txt
686  std::string file_id_3;
687  ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(
688      CreateFileEntryWithResourceId(
689          "bar.txt", "bar3", dir_id_1), &file_id_3));
690
691  ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById(
692      file_id_3, &entry));
693  EXPECT_EQ("bar.txt", entry.base_name());
694
695  // Checks that the entries can be looked up by the de-duped paths.
696  ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryByPath(
697      base::FilePath::FromUTF8Unsafe("drive/root/foo/bar (2).txt"), &entry));
698  EXPECT_EQ("bar2", entry.resource_id());
699  ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryByPath(
700      base::FilePath::FromUTF8Unsafe("drive/root/foo (1)/bar.txt"), &entry));
701  EXPECT_EQ("bar3", entry.resource_id());
702}
703
704TEST_F(ResourceMetadataTest, EncodedNames) {
705  std::string root_local_id;
706  ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath(
707      base::FilePath::FromUTF8Unsafe("drive/root"), &root_local_id));
708
709  ResourceEntry entry;
710
711  std::string dir_id;
712  ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(
713      CreateDirectoryEntry("\\(^o^)/", root_local_id), &dir_id));
714  ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById(
715      dir_id, &entry));
716  EXPECT_EQ("\\(^o^)\xE2\x88\x95", entry.base_name());
717
718  std::string file_id;
719  ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(
720      CreateFileEntryWithResourceId("Slash /.txt", "myfile", dir_id),
721      &file_id));
722  ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById(
723      file_id, &entry));
724  EXPECT_EQ("Slash \xE2\x88\x95.txt", entry.base_name());
725
726  ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryByPath(
727      base::FilePath::FromUTF8Unsafe(
728          "drive/root/\\(^o^)\xE2\x88\x95/Slash \xE2\x88\x95.txt"),
729      &entry));
730  EXPECT_EQ("myfile", entry.resource_id());
731}
732
733TEST_F(ResourceMetadataTest, Reset) {
734  // The grand root has "root" which is not empty.
735  std::vector<ResourceEntry> entries;
736  ASSERT_EQ(FILE_ERROR_OK,
737            resource_metadata_->ReadDirectoryByPath(
738                base::FilePath::FromUTF8Unsafe("drive/root"), &entries));
739  ASSERT_FALSE(entries.empty());
740
741  // Reset.
742  EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->Reset());
743
744  // change stamp should be reset.
745  EXPECT_EQ(0, resource_metadata_->GetLargestChangestamp());
746
747  // root should continue to exist.
748  ResourceEntry entry;
749  ASSERT_EQ(FILE_ERROR_OK,
750            resource_metadata_->GetResourceEntryByPath(
751                base::FilePath::FromUTF8Unsafe("drive"), &entry));
752  EXPECT_EQ("drive", entry.base_name());
753  ASSERT_TRUE(entry.file_info().is_directory());
754  EXPECT_EQ(util::kDriveGrandRootSpecialResourceId, entry.resource_id());
755
756  // There is "other" under "drive".
757  ASSERT_EQ(FILE_ERROR_OK,
758            resource_metadata_->ReadDirectoryByPath(
759                base::FilePath::FromUTF8Unsafe("drive"), &entries));
760  EXPECT_EQ(1U, entries.size());
761
762  // The "other" directory should be empty.
763  ASSERT_EQ(FILE_ERROR_OK,
764            resource_metadata_->ReadDirectoryByPath(
765                base::FilePath::FromUTF8Unsafe("drive/other"), &entries));
766  EXPECT_TRUE(entries.empty());
767}
768
769}  // namespace internal
770}  // namespace drive
771