Home | History | Annotate | Download | only in file_manager
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/chromeos/file_manager/file_watcher.h"
      6 
      7 #include "base/file_util.h"
      8 #include "base/files/scoped_temp_dir.h"
      9 #include "base/message_loop/message_loop.h"
     10 #include "base/run_loop.h"
     11 #include "content/public/test/test_browser_thread_bundle.h"
     12 #include "google_apis/drive/test_util.h"
     13 #include "testing/gtest/include/gtest/gtest.h"
     14 
     15 namespace file_manager {
     16 namespace {
     17 
     18 using google_apis::test_util::CreateQuitCallback;
     19 using google_apis::test_util::CreateCopyResultCallback;
     20 
     21 class FileManagerFileWatcherTest : public testing::Test {
     22  public:
     23   // Use IO_MAINLOOP so FilePathWatcher works in the fake FILE thread, which
     24   // is actually shared with the main thread.
     25   FileManagerFileWatcherTest()
     26       : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {
     27   }
     28 
     29  private:
     30   content::TestBrowserThreadBundle thread_bundle_;
     31 };
     32 
     33 TEST_F(FileManagerFileWatcherTest, AddAndRemoveOneExtensionId) {
     34   const base::FilePath kVirtualPath =
     35       base::FilePath::FromUTF8Unsafe("foo/bar.txt");
     36   const char kExtensionId[] = "extension-id";
     37 
     38   FileWatcher file_watcher(kVirtualPath);
     39   file_watcher.AddExtension(kExtensionId);
     40   std::vector<std::string> extension_ids = file_watcher.GetExtensionIds();
     41 
     42   ASSERT_EQ(1U, extension_ids.size());
     43   ASSERT_EQ(kExtensionId, extension_ids[0]);
     44 
     45   file_watcher.RemoveExtension(kExtensionId);
     46   extension_ids = file_watcher.GetExtensionIds();
     47   ASSERT_EQ(0U, extension_ids.size());
     48 }
     49 
     50 TEST_F(FileManagerFileWatcherTest, AddAndRemoveMultipleExtensionIds) {
     51   const base::FilePath kVirtualPath =
     52       base::FilePath::FromUTF8Unsafe("foo/bar.txt");
     53   const char kExtensionFooId[] = "extension-foo-id";
     54   const char kExtensionBarId[] = "extension-bar-id";
     55 
     56   FileWatcher file_watcher(kVirtualPath);
     57   file_watcher.AddExtension(kExtensionFooId);
     58   file_watcher.AddExtension(kExtensionBarId);
     59   std::vector<std::string> extension_ids = file_watcher.GetExtensionIds();
     60 
     61   // The list should be sorted.
     62   ASSERT_EQ(2U, extension_ids.size());
     63   ASSERT_EQ(kExtensionBarId, extension_ids[0]);
     64   ASSERT_EQ(kExtensionFooId, extension_ids[1]);
     65 
     66   // Remove Foo. Bar should remain.
     67   file_watcher.RemoveExtension(kExtensionFooId);
     68   extension_ids = file_watcher.GetExtensionIds();
     69   ASSERT_EQ(1U, extension_ids.size());
     70   ASSERT_EQ(kExtensionBarId, extension_ids[0]);
     71 
     72   // Remove Bar. Nothing should remain.
     73   file_watcher.RemoveExtension(kExtensionBarId);
     74   extension_ids = file_watcher.GetExtensionIds();
     75   ASSERT_EQ(0U, extension_ids.size());
     76 }
     77 
     78 TEST_F(FileManagerFileWatcherTest, AddSameExtensionMultipleTimes) {
     79   const base::FilePath kVirtualPath =
     80       base::FilePath::FromUTF8Unsafe("foo/bar.txt");
     81   const char kExtensionId[] = "extension-id";
     82 
     83   FileWatcher file_watcher(kVirtualPath);
     84   // Add three times.
     85   file_watcher.AddExtension(kExtensionId);
     86   file_watcher.AddExtension(kExtensionId);
     87   file_watcher.AddExtension(kExtensionId);
     88 
     89   std::vector<std::string> extension_ids = file_watcher.GetExtensionIds();
     90   ASSERT_EQ(1U, extension_ids.size());
     91   ASSERT_EQ(kExtensionId, extension_ids[0]);
     92 
     93   // Remove 1st time.
     94   file_watcher.RemoveExtension(kExtensionId);
     95   extension_ids = file_watcher.GetExtensionIds();
     96   ASSERT_EQ(1U, extension_ids.size());
     97 
     98   // Remove 2nd time.
     99   file_watcher.RemoveExtension(kExtensionId);
    100   extension_ids = file_watcher.GetExtensionIds();
    101   ASSERT_EQ(1U, extension_ids.size());
    102 
    103   // Remove 3rd time. The extension ID should be gone now.
    104   file_watcher.RemoveExtension(kExtensionId);
    105   extension_ids = file_watcher.GetExtensionIds();
    106   ASSERT_EQ(0U, extension_ids.size());
    107 }
    108 
    109 TEST_F(FileManagerFileWatcherTest, WatchLocalFile) {
    110   const base::FilePath kVirtualPath =
    111       base::FilePath::FromUTF8Unsafe("foo/bar.txt");
    112   const char kExtensionId[] = "extension-id";
    113 
    114   // Create a temporary directory.
    115   base::ScopedTempDir temp_dir;
    116   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
    117 
    118   // See the comment at the end of this function for why scoped_ptr is used.
    119   scoped_ptr<FileWatcher> file_watcher(
    120       new FileWatcher(kVirtualPath));
    121   file_watcher->AddExtension(kExtensionId);
    122 
    123   // Start watching changes in the temporary directory.
    124   base::FilePath changed_path;
    125   bool watcher_created = false;
    126   bool on_change_error = false;
    127   base::RunLoop run_loop;
    128   file_watcher->WatchLocalFile(
    129       temp_dir.path(),
    130       CreateQuitCallback(
    131           &run_loop,
    132           CreateCopyResultCallback(&changed_path, &on_change_error)),
    133       CreateCopyResultCallback(&watcher_created));
    134   // Spin the message loop so the base::FilePathWatcher is created.
    135   base::RunLoop().RunUntilIdle();
    136   ASSERT_TRUE(watcher_created);
    137 
    138   // Create a temporary file in the temporary directory. The file watcher
    139   // should detect the change in the directory.
    140   base::FilePath temp_file_path;
    141   ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir.path(), &temp_file_path));
    142   // Wait until the directory change is notified.
    143   run_loop.Run();
    144   ASSERT_FALSE(on_change_error);
    145   ASSERT_EQ(temp_dir.path().value(), changed_path.value());
    146 
    147   // This is ugly, but FileWatcher should be deleted explicitly here, and
    148   // spin the message loop so the base::FilePathWatcher is deleted.
    149   // Otherwise, base::FilePathWatcher may detect a change when the temporary
    150   // directory is deleted, which may result in crash.
    151   file_watcher.reset();
    152   base::RunLoop().RunUntilIdle();
    153 }
    154 
    155 }  // namespace
    156 }  // namespace file_manager.
    157