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