- add sources.
[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/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
23 namespace drive {
24 namespace internal {
25 namespace {
26
27 const char kTestRootResourceId[] = "test_root";
28
29 // The changestamp of the resource metadata used in
30 // ResourceMetadataTest.
31 const int64 kTestChangestamp = 100;
32
33 // Returns the sorted base names from |entries|.
34 std::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.
45 ResourceEntry 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.
59 ResourceEntry 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.
66 ResourceEntry 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.
81 ResourceEntry 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
97 void 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.
140 class 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
198 TEST_F(ResourceMetadataTestOnUIThread, GetResourceEntryByPath) {
199   // Confirm that an existing file is found.
200   FileError error = FILE_ERROR_FAILED;
201   scoped_ptr<ResourceEntry> entry;
202   resource_metadata_->GetResourceEntryByPathOnUIThread(
203       base::FilePath::FromUTF8Unsafe("drive/root/dir1/file4"),
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("file4", entry->base_name());
209
210   // Confirm that a non existing file is not found.
211   error = FILE_ERROR_FAILED;
212   entry.reset();
213   resource_metadata_->GetResourceEntryByPathOnUIThread(
214       base::FilePath::FromUTF8Unsafe("drive/root/dir1/non_existing"),
215       google_apis::test_util::CreateCopyResultCallback(&error, &entry));
216   test_util::RunBlockingPoolTask();
217   EXPECT_EQ(FILE_ERROR_NOT_FOUND, error);
218   EXPECT_FALSE(entry.get());
219
220   // Confirm that the root is found.
221   error = FILE_ERROR_FAILED;
222   entry.reset();
223   resource_metadata_->GetResourceEntryByPathOnUIThread(
224       base::FilePath::FromUTF8Unsafe("drive"),
225       google_apis::test_util::CreateCopyResultCallback(&error, &entry));
226   test_util::RunBlockingPoolTask();
227   EXPECT_EQ(FILE_ERROR_OK, error);
228   EXPECT_TRUE(entry.get());
229
230   // Confirm that a non existing file is not found at the root level.
231   error = FILE_ERROR_FAILED;
232   entry.reset();
233   resource_metadata_->GetResourceEntryByPathOnUIThread(
234       base::FilePath::FromUTF8Unsafe("non_existing"),
235       google_apis::test_util::CreateCopyResultCallback(&error, &entry));
236   test_util::RunBlockingPoolTask();
237   EXPECT_EQ(FILE_ERROR_NOT_FOUND, error);
238   EXPECT_FALSE(entry.get());
239
240   // Confirm that an entry is not found with a wrong root.
241   error = FILE_ERROR_FAILED;
242   entry.reset();
243   resource_metadata_->GetResourceEntryByPathOnUIThread(
244       base::FilePath::FromUTF8Unsafe("non_existing/root"),
245       google_apis::test_util::CreateCopyResultCallback(&error, &entry));
246   test_util::RunBlockingPoolTask();
247   EXPECT_EQ(FILE_ERROR_NOT_FOUND, error);
248   EXPECT_FALSE(entry.get());
249 }
250
251 TEST_F(ResourceMetadataTestOnUIThread, ReadDirectoryByPath) {
252   // Confirm that an existing directory is found.
253   FileError error = FILE_ERROR_FAILED;
254   scoped_ptr<ResourceEntryVector> entries;
255   resource_metadata_->ReadDirectoryByPathOnUIThread(
256       base::FilePath::FromUTF8Unsafe("drive/root/dir1"),
257       google_apis::test_util::CreateCopyResultCallback(&error, &entries));
258   test_util::RunBlockingPoolTask();
259   EXPECT_EQ(FILE_ERROR_OK, error);
260   ASSERT_TRUE(entries.get());
261   ASSERT_EQ(3U, entries->size());
262   // The order is not guaranteed so we should sort the base names.
263   std::vector<std::string> base_names = GetSortedBaseNames(*entries);
264   EXPECT_EQ("dir3", base_names[0]);
265   EXPECT_EQ("file4", base_names[1]);
266   EXPECT_EQ("file5", base_names[2]);
267
268   // Confirm that a non existing directory is not found.
269   error = FILE_ERROR_FAILED;
270   entries.reset();
271   resource_metadata_->ReadDirectoryByPathOnUIThread(
272       base::FilePath::FromUTF8Unsafe("drive/root/non_existing"),
273       google_apis::test_util::CreateCopyResultCallback(&error, &entries));
274   test_util::RunBlockingPoolTask();
275   EXPECT_EQ(FILE_ERROR_NOT_FOUND, error);
276   EXPECT_FALSE(entries.get());
277
278   // Confirm that reading a file results in FILE_ERROR_NOT_A_DIRECTORY.
279   error = FILE_ERROR_FAILED;
280   entries.reset();
281   resource_metadata_->ReadDirectoryByPathOnUIThread(
282       base::FilePath::FromUTF8Unsafe("drive/root/dir1/file4"),
283       google_apis::test_util::CreateCopyResultCallback(&error, &entries));
284   test_util::RunBlockingPoolTask();
285   EXPECT_EQ(FILE_ERROR_NOT_A_DIRECTORY, error);
286   EXPECT_FALSE(entries.get());
287 }
288
289 // Tests for methods running on the blocking task runner.
290 class ResourceMetadataTest : public testing::Test {
291  protected:
292   virtual void SetUp() OVERRIDE {
293     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
294
295     metadata_storage_.reset(new ResourceMetadataStorage(
296         temp_dir_.path(), base::MessageLoopProxy::current().get()));
297     ASSERT_TRUE(metadata_storage_->Initialize());
298
299     resource_metadata_.reset(new ResourceMetadata(
300         metadata_storage_.get(), base::MessageLoopProxy::current()));
301
302     ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->Initialize());
303
304     SetUpEntries(resource_metadata_.get());
305   }
306
307   base::ScopedTempDir temp_dir_;
308   content::TestBrowserThreadBundle thread_bundle_;
309   scoped_ptr<ResourceMetadataStorage, test_util::DestroyHelperForTests>
310       metadata_storage_;
311   scoped_ptr<ResourceMetadata, test_util::DestroyHelperForTests>
312       resource_metadata_;
313 };
314
315 TEST_F(ResourceMetadataTest, LargestChangestamp) {
316   const int64 kChangestamp = 123456;
317   EXPECT_EQ(FILE_ERROR_OK,
318             resource_metadata_->SetLargestChangestamp(kChangestamp));
319   EXPECT_EQ(kChangestamp, resource_metadata_->GetLargestChangestamp());
320 }
321
322 TEST_F(ResourceMetadataTest, RefreshEntry) {
323   base::FilePath drive_file_path;
324   ResourceEntry entry;
325
326   // Get file9.
327   std::string file_id;
328   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath(
329       base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3/file9"), &file_id));
330   EXPECT_EQ(FILE_ERROR_OK,
331             resource_metadata_->GetResourceEntryById(file_id, &entry));
332   EXPECT_EQ("file9", entry.base_name());
333   EXPECT_TRUE(!entry.file_info().is_directory());
334   EXPECT_EQ("md5:file9", entry.file_specific_info().md5());
335
336   // Rename it.
337   ResourceEntry file_entry(entry);
338   file_entry.set_title("file100");
339   EXPECT_EQ(FILE_ERROR_OK,
340             resource_metadata_->RefreshEntry(file_entry));
341
342   EXPECT_EQ("drive/root/dir1/dir3/file100",
343             resource_metadata_->GetFilePath(file_id).AsUTF8Unsafe());
344   entry.Clear();
345   EXPECT_EQ(FILE_ERROR_OK,
346             resource_metadata_->GetResourceEntryById(file_id, &entry));
347   EXPECT_EQ("file100", entry.base_name());
348   EXPECT_TRUE(!entry.file_info().is_directory());
349   EXPECT_EQ("md5:file9", entry.file_specific_info().md5());
350
351   // Update the file md5.
352   const std::string updated_md5("md5:updated");
353   file_entry = entry;
354   file_entry.mutable_file_specific_info()->set_md5(updated_md5);
355   EXPECT_EQ(FILE_ERROR_OK,
356             resource_metadata_->RefreshEntry(file_entry));
357
358   EXPECT_EQ("drive/root/dir1/dir3/file100",
359             resource_metadata_->GetFilePath(file_id).AsUTF8Unsafe());
360   entry.Clear();
361   EXPECT_EQ(FILE_ERROR_OK,
362             resource_metadata_->GetResourceEntryById(file_id, &entry));
363   EXPECT_EQ("file100", entry.base_name());
364   EXPECT_TRUE(!entry.file_info().is_directory());
365   EXPECT_EQ(updated_md5, entry.file_specific_info().md5());
366
367   // Make sure we get the same thing from GetResourceEntryByPath.
368   entry.Clear();
369   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryByPath(
370       base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3/file100"), &entry));
371   EXPECT_EQ("file100", entry.base_name());
372   ASSERT_TRUE(!entry.file_info().is_directory());
373   EXPECT_EQ(updated_md5, entry.file_specific_info().md5());
374
375   // Get dir2.
376   entry.Clear();
377   std::string dir_id;
378   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath(
379       base::FilePath::FromUTF8Unsafe("drive/root/dir2"), &dir_id));
380   EXPECT_EQ(FILE_ERROR_OK,
381             resource_metadata_->GetResourceEntryById(dir_id, &entry));
382   EXPECT_EQ("dir2", entry.base_name());
383   ASSERT_TRUE(entry.file_info().is_directory());
384
385   // Get dir3's ID.
386   std::string dir3_id;
387   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath(
388       base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3"), &dir3_id));
389
390   // Change the name to dir100 and change the parent to drive/dir1/dir3.
391   ResourceEntry dir_entry(entry);
392   dir_entry.set_title("dir100");
393   dir_entry.set_parent_local_id(dir3_id);
394   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->RefreshEntry(dir_entry));
395
396   EXPECT_EQ("drive/root/dir1/dir3/dir100",
397             resource_metadata_->GetFilePath(dir_id).AsUTF8Unsafe());
398   entry.Clear();
399   EXPECT_EQ(FILE_ERROR_OK,
400             resource_metadata_->GetResourceEntryById(dir_id, &entry));
401   EXPECT_EQ("dir100", entry.base_name());
402   EXPECT_TRUE(entry.file_info().is_directory());
403   EXPECT_EQ("id:dir2", entry.resource_id());
404
405   // Make sure the children have moved over. Test file6.
406   entry.Clear();
407   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryByPath(
408       base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3/dir100/file6"),
409       &entry));
410   EXPECT_EQ("file6", entry.base_name());
411
412   // Make sure dir2 no longer exists.
413   EXPECT_EQ(FILE_ERROR_NOT_FOUND, resource_metadata_->GetResourceEntryByPath(
414       base::FilePath::FromUTF8Unsafe("drive/root/dir2"), &entry));
415
416   // Make sure that directory cannot move under a file.
417   dir_entry.set_parent_local_id(file_id);
418   EXPECT_EQ(FILE_ERROR_NOT_A_DIRECTORY,
419             resource_metadata_->RefreshEntry(dir_entry));
420
421   // Cannot refresh root.
422   dir_entry.Clear();
423   dir_entry.set_resource_id(util::kDriveGrandRootSpecialResourceId);
424   dir_entry.set_local_id(util::kDriveGrandRootSpecialResourceId);
425   dir_entry.set_title("new-root-name");
426   dir_entry.set_parent_local_id(dir3_id);
427   EXPECT_EQ(FILE_ERROR_INVALID_OPERATION,
428             resource_metadata_->RefreshEntry(dir_entry));
429 }
430
431 TEST_F(ResourceMetadataTest, GetSubDirectoriesRecursively) {
432   std::set<base::FilePath> sub_directories;
433
434   // file9: not a directory, so no children.
435   std::string local_id;
436   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath(
437       base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3/file9"), &local_id));
438   resource_metadata_->GetSubDirectoriesRecursively(local_id, &sub_directories);
439   EXPECT_TRUE(sub_directories.empty());
440
441   // dir2: no child directories.
442   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath(
443       base::FilePath::FromUTF8Unsafe("drive/root/dir2"), &local_id));
444   resource_metadata_->GetSubDirectoriesRecursively(local_id, &sub_directories);
445   EXPECT_TRUE(sub_directories.empty());
446   const std::string dir2_id = local_id;
447
448   // dir1: dir3 is the only child
449   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath(
450       base::FilePath::FromUTF8Unsafe("drive/root/dir1"), &local_id));
451   resource_metadata_->GetSubDirectoriesRecursively(local_id, &sub_directories);
452   EXPECT_EQ(1u, sub_directories.size());
453   EXPECT_EQ(1u, sub_directories.count(
454       base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3")));
455   sub_directories.clear();
456
457   // Add a few more directories to make sure deeper nesting works.
458   // dir2/dir100
459   // dir2/dir101
460   // dir2/dir101/dir102
461   // dir2/dir101/dir103
462   // dir2/dir101/dir104
463   // dir2/dir101/dir104/dir105
464   // dir2/dir101/dir104/dir105/dir106
465   // dir2/dir101/dir104/dir105/dir106/dir107
466   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(
467       CreateDirectoryEntry("dir100", dir2_id), &local_id));
468   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(
469       CreateDirectoryEntry("dir101", dir2_id), &local_id));
470   const std::string dir101_id = local_id;
471   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(
472       CreateDirectoryEntry("dir102", dir101_id), &local_id));
473   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(
474       CreateDirectoryEntry("dir103", dir101_id), &local_id));
475   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(
476       CreateDirectoryEntry("dir104", dir101_id), &local_id));
477   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(
478       CreateDirectoryEntry("dir105", local_id), &local_id));
479   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(
480       CreateDirectoryEntry("dir106", local_id), &local_id));
481   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(
482       CreateDirectoryEntry("dir107", local_id), &local_id));
483
484   resource_metadata_->GetSubDirectoriesRecursively(dir2_id, &sub_directories);
485   EXPECT_EQ(8u, sub_directories.size());
486   EXPECT_EQ(1u, sub_directories.count(base::FilePath::FromUTF8Unsafe(
487       "drive/root/dir2/dir101")));
488   EXPECT_EQ(1u, sub_directories.count(base::FilePath::FromUTF8Unsafe(
489       "drive/root/dir2/dir101/dir104")));
490   EXPECT_EQ(1u, sub_directories.count(base::FilePath::FromUTF8Unsafe(
491       "drive/root/dir2/dir101/dir104/dir105/dir106/dir107")));
492 }
493
494 TEST_F(ResourceMetadataTest, AddEntry) {
495   base::FilePath drive_file_path;
496
497   // Add a file to dir3.
498   std::string local_id;
499   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath(
500       base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3"), &local_id));
501   ResourceEntry file_entry = CreateFileEntry("file100", local_id);
502   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(file_entry, &local_id));
503   EXPECT_EQ("drive/root/dir1/dir3/file100",
504             resource_metadata_->GetFilePath(local_id).AsUTF8Unsafe());
505
506   // Add a directory.
507   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath(
508       base::FilePath::FromUTF8Unsafe("drive/root/dir1"), &local_id));
509   ResourceEntry dir_entry = CreateDirectoryEntry("dir101", local_id);
510   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(dir_entry, &local_id));
511   EXPECT_EQ("drive/root/dir1/dir101",
512             resource_metadata_->GetFilePath(local_id).AsUTF8Unsafe());
513
514   // Add to an invalid parent.
515   ResourceEntry file_entry3 = CreateFileEntry("file103", "id:invalid");
516   EXPECT_EQ(FILE_ERROR_NOT_FOUND,
517             resource_metadata_->AddEntry(file_entry3, &local_id));
518
519   // Add an existing file.
520   EXPECT_EQ(FILE_ERROR_EXISTS,
521             resource_metadata_->AddEntry(file_entry, &local_id));
522 }
523
524 TEST_F(ResourceMetadataTest, RemoveEntry) {
525   // Make sure file9 is found.
526   std::string file9_local_id;
527   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath(
528       base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3/file9"),
529       &file9_local_id));
530   ResourceEntry entry;
531   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById(
532       file9_local_id, &entry));
533   EXPECT_EQ("file9", entry.base_name());
534
535   // Remove file9.
536   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->RemoveEntry(file9_local_id));
537
538   // file9 should no longer exist.
539   EXPECT_EQ(FILE_ERROR_NOT_FOUND, resource_metadata_->GetResourceEntryById(
540       file9_local_id, &entry));
541
542   // Look for dir3.
543   std::string dir3_local_id;
544   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath(
545       base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3"), &dir3_local_id));
546   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById(
547       dir3_local_id, &entry));
548   EXPECT_EQ("dir3", entry.base_name());
549
550   // Remove dir3.
551   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->RemoveEntry(dir3_local_id));
552
553   // dir3 should no longer exist.
554   EXPECT_EQ(FILE_ERROR_NOT_FOUND, resource_metadata_->GetResourceEntryById(
555       dir3_local_id, &entry));
556
557   // Remove unknown local_id using RemoveEntry.
558   EXPECT_EQ(FILE_ERROR_NOT_FOUND, resource_metadata_->RemoveEntry("foo"));
559
560   // Try removing root. This should fail.
561   EXPECT_EQ(FILE_ERROR_ACCESS_DENIED, resource_metadata_->RemoveEntry(
562       util::kDriveGrandRootSpecialResourceId));
563 }
564
565 TEST_F(ResourceMetadataTest, GetResourceEntryById_RootDirectory) {
566   // Look up the root directory by its ID.
567   ResourceEntry entry;
568   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById(
569       util::kDriveGrandRootSpecialResourceId, &entry));
570   EXPECT_EQ("drive", entry.base_name());
571 }
572
573 TEST_F(ResourceMetadataTest, GetResourceEntryById) {
574   // Get file4 by path.
575   std::string local_id;
576   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath(
577       base::FilePath::FromUTF8Unsafe("drive/root/dir1/file4"), &local_id));
578
579   // Confirm that an existing file is found.
580   ResourceEntry entry;
581   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById(
582       local_id, &entry));
583   EXPECT_EQ("file4", entry.base_name());
584
585   // Confirm that a non existing file is not found.
586   EXPECT_EQ(FILE_ERROR_NOT_FOUND, resource_metadata_->GetResourceEntryById(
587       "file:non_existing", &entry));
588 }
589
590 TEST_F(ResourceMetadataTest, Iterate) {
591   scoped_ptr<ResourceMetadata::Iterator> it = resource_metadata_->GetIterator();
592   ASSERT_TRUE(it);
593
594   int file_count = 0, directory_count = 0;
595   for (; !it->IsAtEnd(); it->Advance()) {
596     if (!it->GetValue().file_info().is_directory())
597       ++file_count;
598     else
599       ++directory_count;
600   }
601
602   EXPECT_EQ(7, file_count);
603   EXPECT_EQ(6, directory_count);
604 }
605
606 TEST_F(ResourceMetadataTest, DuplicatedNames) {
607   std::string root_local_id;
608   ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath(
609       base::FilePath::FromUTF8Unsafe("drive/root"), &root_local_id));
610
611   ResourceEntry entry;
612
613   // When multiple entries with the same title are added in a single directory,
614   // their base_names are de-duped.
615   // - drive/root/foo
616   // - drive/root/foo (1)
617   std::string dir_id_0;
618   ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(
619       CreateDirectoryEntryWithResourceId(
620           "foo", "foo0", root_local_id), &dir_id_0));
621   std::string dir_id_1;
622   ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(
623       CreateDirectoryEntryWithResourceId(
624           "foo", "foo1", root_local_id), &dir_id_1));
625
626   ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById(
627       dir_id_0, &entry));
628   EXPECT_EQ("foo", entry.base_name());
629   ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById(
630       dir_id_1, &entry));
631   EXPECT_EQ("foo (1)", entry.base_name());
632
633   // - drive/root/foo/bar.txt
634   // - drive/root/foo/bar (1).txt
635   // - drive/root/foo/bar (2).txt
636   std::string file_id_0;
637   ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(
638       CreateFileEntryWithResourceId(
639           "bar.txt", "bar0", dir_id_0), &file_id_0));
640   std::string file_id_1;
641   ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(
642       CreateFileEntryWithResourceId(
643           "bar.txt", "bar1", dir_id_0), &file_id_1));
644   std::string file_id_2;
645   ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(
646       CreateFileEntryWithResourceId(
647           "bar.txt", "bar2", dir_id_0), &file_id_2));
648
649   ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById(
650       file_id_0, &entry));
651   EXPECT_EQ("bar.txt", entry.base_name());
652   ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById(
653       file_id_1, &entry));
654   EXPECT_EQ("bar (1).txt", entry.base_name());
655   ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById(
656       file_id_2, &entry));
657   EXPECT_EQ("bar (2).txt", entry.base_name());
658
659   // Same name but different parent. No renaming.
660   // - drive/root/foo (1)/bar.txt
661   std::string file_id_3;
662   ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(
663       CreateFileEntryWithResourceId(
664           "bar.txt", "bar3", dir_id_1), &file_id_3));
665
666   ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById(
667       file_id_3, &entry));
668   EXPECT_EQ("bar.txt", entry.base_name());
669
670   // Checks that the entries can be looked up by the de-duped paths.
671   ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryByPath(
672       base::FilePath::FromUTF8Unsafe("drive/root/foo/bar (2).txt"), &entry));
673   EXPECT_EQ("bar2", entry.resource_id());
674   ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryByPath(
675       base::FilePath::FromUTF8Unsafe("drive/root/foo (1)/bar.txt"), &entry));
676   EXPECT_EQ("bar3", entry.resource_id());
677 }
678
679 TEST_F(ResourceMetadataTest, EncodedNames) {
680   std::string root_local_id;
681   ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath(
682       base::FilePath::FromUTF8Unsafe("drive/root"), &root_local_id));
683
684   ResourceEntry entry;
685
686   std::string dir_id;
687   ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(
688       CreateDirectoryEntry("\\(^o^)/", root_local_id), &dir_id));
689   ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById(
690       dir_id, &entry));
691   EXPECT_EQ("\\(^o^)\xE2\x88\x95", entry.base_name());
692
693   std::string file_id;
694   ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(
695       CreateFileEntryWithResourceId("Slash /.txt", "myfile", dir_id),
696       &file_id));
697   ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById(
698       file_id, &entry));
699   EXPECT_EQ("Slash \xE2\x88\x95.txt", entry.base_name());
700
701   ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryByPath(
702       base::FilePath::FromUTF8Unsafe(
703           "drive/root/\\(^o^)\xE2\x88\x95/Slash \xE2\x88\x95.txt"),
704       &entry));
705   EXPECT_EQ("myfile", entry.resource_id());
706 }
707
708 TEST_F(ResourceMetadataTest, Reset) {
709   // The grand root has "root" which is not empty.
710   std::vector<ResourceEntry> entries;
711   ASSERT_EQ(FILE_ERROR_OK,
712             resource_metadata_->ReadDirectoryByPath(
713                 base::FilePath::FromUTF8Unsafe("drive/root"), &entries));
714   ASSERT_FALSE(entries.empty());
715
716   // Reset.
717   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->Reset());
718
719   // change stamp should be reset.
720   EXPECT_EQ(0, resource_metadata_->GetLargestChangestamp());
721
722   // root should continue to exist.
723   ResourceEntry entry;
724   ASSERT_EQ(FILE_ERROR_OK,
725             resource_metadata_->GetResourceEntryByPath(
726                 base::FilePath::FromUTF8Unsafe("drive"), &entry));
727   EXPECT_EQ("drive", entry.base_name());
728   ASSERT_TRUE(entry.file_info().is_directory());
729   EXPECT_EQ(util::kDriveGrandRootSpecialResourceId, entry.resource_id());
730
731   // There is "other" under "drive".
732   ASSERT_EQ(FILE_ERROR_OK,
733             resource_metadata_->ReadDirectoryByPath(
734                 base::FilePath::FromUTF8Unsafe("drive"), &entries));
735   EXPECT_EQ(1U, entries.size());
736
737   // The "other" directory should be empty.
738   ASSERT_EQ(FILE_ERROR_OK,
739             resource_metadata_->ReadDirectoryByPath(
740                 base::FilePath::FromUTF8Unsafe("drive/other"), &entries));
741   EXPECT_TRUE(entries.empty());
742 }
743
744 }  // namespace internal
745 }  // namespace drive