Home | History | Annotate | Download | only in media_galleries
      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 // MediaFileSystemRegistry unit tests.
      6 
      7 #include <algorithm>
      8 #include <set>
      9 
     10 #include "base/bind_helpers.h"
     11 #include "base/command_line.h"
     12 #include "base/files/file_util.h"
     13 #include "base/files/scoped_temp_dir.h"
     14 #include "base/memory/ref_counted.h"
     15 #include "base/memory/scoped_ptr.h"
     16 #include "base/memory/scoped_vector.h"
     17 #include "base/message_loop/message_loop.h"
     18 #include "base/path_service.h"
     19 #include "base/run_loop.h"
     20 #include "base/stl_util.h"
     21 #include "base/strings/stringprintf.h"
     22 #include "base/strings/utf_string_conversions.h"
     23 #include "base/threading/sequenced_worker_pool.h"
     24 #include "base/values.h"
     25 #include "chrome/browser/extensions/extension_service.h"
     26 #include "chrome/browser/extensions/test_extension_system.h"
     27 #include "chrome/browser/media_galleries/media_file_system_context.h"
     28 #include "chrome/browser/media_galleries/media_file_system_registry.h"
     29 #include "chrome/browser/media_galleries/media_galleries_preferences_factory.h"
     30 #include "chrome/browser/media_galleries/media_galleries_test_util.h"
     31 #include "chrome/common/chrome_paths.h"
     32 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
     33 #include "chrome/test/base/testing_browser_process.h"
     34 #include "chrome/test/base/testing_profile.h"
     35 #include "components/storage_monitor/removable_device_constants.h"
     36 #include "components/storage_monitor/storage_info.h"
     37 #include "components/storage_monitor/storage_monitor.h"
     38 #include "components/storage_monitor/test_storage_monitor.h"
     39 #include "content/public/browser/render_process_host.h"
     40 #include "content/public/browser/render_process_host_factory.h"
     41 #include "content/public/browser/render_view_host.h"
     42 #include "content/public/browser/web_contents.h"
     43 #include "content/public/test/mock_render_process_host.h"
     44 #include "content/public/test/test_browser_thread.h"
     45 #include "content/public/test/web_contents_tester.h"
     46 #include "extensions/browser/extension_system.h"
     47 #include "extensions/common/extension.h"
     48 #include "sync/api/string_ordinal.h"
     49 #include "testing/gtest/include/gtest/gtest.h"
     50 
     51 #if defined(OS_CHROMEOS)
     52 #include "chrome/browser/chromeos/login/users/scoped_test_user_manager.h"
     53 #include "chrome/browser/chromeos/settings/cros_settings.h"
     54 #include "chrome/browser/chromeos/settings/device_settings_service.h"
     55 #endif
     56 
     57 using content::BrowserThread;
     58 using storage_monitor::StorageInfo;
     59 using storage_monitor::StorageMonitor;
     60 using storage_monitor::TestStorageMonitor;
     61 
     62 // Not anonymous so it can be friends with MediaFileSystemRegistry.
     63 class TestMediaFileSystemContext : public MediaFileSystemContext {
     64  public:
     65   struct FSInfo {
     66     FSInfo() {}
     67     FSInfo(const std::string& device_id, const base::FilePath& path,
     68            const std::string& fs_name);
     69 
     70     bool operator<(const FSInfo& other) const;
     71 
     72     std::string device_id;
     73     base::FilePath path;
     74     std::string fs_name;
     75   };
     76 
     77   explicit TestMediaFileSystemContext(MediaFileSystemRegistry* registry);
     78   virtual ~TestMediaFileSystemContext() {}
     79 
     80   // MediaFileSystemContext implementation.
     81   virtual bool RegisterFileSystem(const std::string& device_id,
     82                                   const std::string& fs_name,
     83                                   const base::FilePath& path) OVERRIDE;
     84 
     85   virtual void RevokeFileSystem(const std::string& fs_name) OVERRIDE;
     86 
     87   virtual base::FilePath GetRegisteredPath(
     88       const std::string& fs_name) const OVERRIDE;
     89 
     90   MediaFileSystemRegistry* registry() { return registry_; }
     91 
     92  private:
     93   void AddFSEntry(const std::string& device_id,
     94                   const base::FilePath& path,
     95                   const std::string& fs_name);
     96 
     97   MediaFileSystemRegistry* registry_;
     98 
     99   // The currently allocated mock file systems.
    100   std::map<std::string /*fs_name*/, FSInfo> file_systems_by_name_;
    101 };
    102 
    103 TestMediaFileSystemContext::FSInfo::FSInfo(const std::string& device_id,
    104                                            const base::FilePath& path,
    105                                            const std::string& fs_name)
    106     : device_id(device_id),
    107       path(path),
    108       fs_name(fs_name) {
    109 }
    110 
    111 bool TestMediaFileSystemContext::FSInfo::operator<(const FSInfo& other) const {
    112   if (device_id != other.device_id)
    113     return device_id < other.device_id;
    114   if (path.value() != other.path.value())
    115     return path.value() < other.path.value();
    116   return fs_name < other.fs_name;
    117 }
    118 
    119 TestMediaFileSystemContext::TestMediaFileSystemContext(
    120     MediaFileSystemRegistry* registry)
    121     : registry_(registry) {
    122   registry_->file_system_context_.reset(this);
    123 }
    124 
    125 bool TestMediaFileSystemContext::RegisterFileSystem(
    126     const std::string& device_id,
    127     const std::string& fs_name,
    128     const base::FilePath& path) {
    129   AddFSEntry(device_id, path, fs_name);
    130   return true;
    131 }
    132 
    133 void TestMediaFileSystemContext::RevokeFileSystem(const std::string& fs_name) {
    134   if (!ContainsKey(file_systems_by_name_, fs_name))
    135     return;
    136   EXPECT_EQ(1U, file_systems_by_name_.erase(fs_name));
    137 }
    138 
    139 base::FilePath TestMediaFileSystemContext::GetRegisteredPath(
    140     const std::string& fs_name) const {
    141   std::map<std::string /*fs_name*/, FSInfo>::const_iterator it =
    142       file_systems_by_name_.find(fs_name);
    143   if (it == file_systems_by_name_.end())
    144     return base::FilePath();
    145   return it->second.path;
    146 }
    147 
    148 void TestMediaFileSystemContext::AddFSEntry(const std::string& device_id,
    149                                             const base::FilePath& path,
    150                                             const std::string& fs_name) {
    151   DCHECK_CURRENTLY_ON(BrowserThread::UI);
    152   DCHECK(path.IsAbsolute());
    153   DCHECK(!path.ReferencesParent());
    154 
    155   FSInfo info(device_id, path, fs_name);
    156   file_systems_by_name_[fs_name] = info;
    157 }
    158 
    159 namespace {
    160 
    161 typedef std::map<MediaGalleryPrefId, MediaFileSystemInfo> FSInfoMap;
    162 
    163 void GetGalleryInfoCallback(
    164     FSInfoMap* results,
    165     const std::vector<MediaFileSystemInfo>& file_systems) {
    166   for (size_t i = 0; i < file_systems.size(); ++i) {
    167     ASSERT_FALSE(ContainsKey(*results, file_systems[i].pref_id));
    168     (*results)[file_systems[i].pref_id] = file_systems[i];
    169   }
    170 }
    171 
    172 void CheckGalleryInfo(const MediaFileSystemInfo& info,
    173                       TestMediaFileSystemContext* fs_context,
    174                       const base::FilePath& path,
    175                       bool removable,
    176                       bool media_device) {
    177   EXPECT_EQ(path, info.path);
    178   EXPECT_EQ(removable, info.removable);
    179   EXPECT_EQ(media_device, info.media_device);
    180   EXPECT_NE(0UL, info.pref_id);
    181 
    182   if (removable)
    183     EXPECT_NE(0UL, info.transient_device_id.size());
    184   else
    185     EXPECT_EQ(0UL, info.transient_device_id.size());
    186 
    187   base::FilePath fsid_path = fs_context->GetRegisteredPath(info.fsid);
    188   EXPECT_EQ(path, fsid_path);
    189 }
    190 
    191 class MockProfileSharedRenderProcessHostFactory
    192     : public content::RenderProcessHostFactory {
    193  public:
    194   MockProfileSharedRenderProcessHostFactory() {}
    195   virtual ~MockProfileSharedRenderProcessHostFactory();
    196 
    197   // RPH created with this factory are owned by it.  If the RPH is destroyed
    198   // for testing purposes, it must be removed from the factory first.
    199   content::MockRenderProcessHost* ReleaseRPH(
    200       content::BrowserContext* browser_context);
    201 
    202   virtual content::RenderProcessHost* CreateRenderProcessHost(
    203       content::BrowserContext* browser_context,
    204       content::SiteInstance* site_instance) const OVERRIDE;
    205 
    206  private:
    207   typedef std::map<content::BrowserContext*, content::MockRenderProcessHost*>
    208       ProfileRPHMap;
    209   mutable ProfileRPHMap rph_map_;
    210 
    211   DISALLOW_COPY_AND_ASSIGN(MockProfileSharedRenderProcessHostFactory);
    212 };
    213 
    214 class ProfileState {
    215  public:
    216   explicit ProfileState(
    217       MockProfileSharedRenderProcessHostFactory* rph_factory);
    218   ~ProfileState();
    219 
    220   MediaGalleriesPreferences* GetMediaGalleriesPrefs();
    221 
    222   void CheckGalleries(
    223       const std::string& test,
    224       const std::vector<MediaFileSystemInfo>& regular_extension_galleries,
    225       const std::vector<MediaFileSystemInfo>& all_extension_galleries);
    226 
    227   FSInfoMap GetGalleriesInfo(extensions::Extension* extension);
    228 
    229   extensions::Extension* all_permission_extension();
    230   extensions::Extension* regular_permission_extension();
    231   Profile* profile();
    232 
    233   void AddNameForReadCompare(const base::string16& name);
    234   void AddNameForAllCompare(const base::string16& name);
    235 
    236  private:
    237   void CompareResults(const std::string& test,
    238                       const std::vector<base::string16>& names,
    239                       const std::vector<MediaFileSystemInfo>& expected,
    240                       const std::vector<MediaFileSystemInfo>& actual);
    241   bool ContainsEntry(const MediaFileSystemInfo& info,
    242                      const std::vector<MediaFileSystemInfo>& container);
    243 
    244   int GetAndClearComparisonCount();
    245 
    246   int num_comparisons_;
    247 
    248   scoped_ptr<TestingProfile> profile_;
    249 
    250   scoped_refptr<extensions::Extension> all_permission_extension_;
    251   scoped_refptr<extensions::Extension> regular_permission_extension_;
    252   scoped_refptr<extensions::Extension> no_permissions_extension_;
    253 
    254   scoped_ptr<content::WebContents> single_web_contents_;
    255   scoped_ptr<content::WebContents> shared_web_contents1_;
    256   scoped_ptr<content::WebContents> shared_web_contents2_;
    257 
    258   // The RenderProcessHosts are freed when their respective WebContents /
    259   // RenderViewHosts go away.
    260   content::MockRenderProcessHost* single_rph_;
    261   content::MockRenderProcessHost* shared_rph_;
    262 
    263   std::vector<base::string16> compare_names_read_;
    264   std::vector<base::string16> compare_names_all_;
    265 
    266   DISALLOW_COPY_AND_ASSIGN(ProfileState);
    267 };
    268 
    269 base::string16 GetExpectedFolderName(const base::FilePath& path) {
    270 #if defined(OS_CHROMEOS)
    271   return path.BaseName().LossyDisplayName();
    272 #else
    273   return path.LossyDisplayName();
    274 #endif
    275 }
    276 
    277 }  // namespace
    278 
    279 class MediaFileSystemRegistryTest : public ChromeRenderViewHostTestHarness {
    280  public:
    281   void CreateProfileState(size_t profile_count);
    282 
    283   ProfileState* GetProfileState(size_t i);
    284 
    285   MediaGalleriesPreferences* GetPreferences(Profile* profile);
    286 
    287   base::FilePath empty_dir() {
    288     return empty_dir_;
    289   }
    290 
    291   base::FilePath dcim_dir() {
    292     return dcim_dir_;
    293   }
    294 
    295   TestMediaFileSystemContext* test_file_system_context() {
    296     return test_file_system_context_;
    297   }
    298 
    299   // Create a user added gallery based on the information passed and add it to
    300   // |profiles|. Returns the device id.
    301   std::string AddUserGallery(StorageInfo::Type type,
    302                              const std::string& unique_id,
    303                              const base::FilePath& path);
    304 
    305   // Returns the device id.
    306   std::string AttachDevice(StorageInfo::Type type,
    307                            const std::string& unique_id,
    308                            const base::FilePath& location);
    309 
    310   void DetachDevice(const std::string& device_id);
    311 
    312   void SetGalleryPermission(ProfileState* profile_state,
    313                             extensions::Extension* extension,
    314                             const std::string& device_id,
    315                             bool has_access);
    316 
    317   void AssertAllAutoAddedGalleries();
    318 
    319   void InitForGalleriesInfoTest(FSInfoMap* galleries_info);
    320 
    321   void CheckNewGalleryInfo(ProfileState* profile_state,
    322                            const FSInfoMap& galleries_info,
    323                            const base::FilePath& location,
    324                            bool removable,
    325                            bool media_device);
    326 
    327   std::vector<MediaFileSystemInfo> GetAutoAddedGalleries(
    328       ProfileState* profile_state);
    329 
    330   void ProcessAttach(const std::string& id,
    331                      const base::string16& name,
    332                      const base::FilePath::StringType& location) {
    333     StorageInfo info(id, location, name, base::string16(), base::string16(), 0);
    334     StorageMonitor::GetInstance()->receiver()->ProcessAttach(info);
    335   }
    336 
    337   void ProcessDetach(const std::string& id) {
    338     StorageMonitor::GetInstance()->receiver()->ProcessDetach(id);
    339   }
    340 
    341   MediaFileSystemRegistry* registry() {
    342     return test_file_system_context_->registry();
    343   }
    344 
    345   size_t GetExtensionGalleriesHostCount(
    346       const MediaFileSystemRegistry* registry) const;
    347 
    348   int num_auto_galleries() {
    349     return media_directories_.num_galleries();
    350   }
    351 
    352  protected:
    353   virtual void SetUp() OVERRIDE;
    354   virtual void TearDown() OVERRIDE;
    355 
    356  private:
    357   // This makes sure that at least one default gallery exists on the file
    358   // system.
    359   EnsureMediaDirectoriesExists media_directories_;
    360 
    361   // Some test gallery directories.
    362   base::ScopedTempDir galleries_dir_;
    363   // An empty directory in |galleries_dir_|
    364   base::FilePath empty_dir_;
    365   // A directory in |galleries_dir_| with a DCIM directory in it.
    366   base::FilePath dcim_dir_;
    367 
    368   // MediaFileSystemRegistry owns this.
    369   TestMediaFileSystemContext* test_file_system_context_;
    370 
    371   // Needed for extension service & friends to work.
    372 
    373 #if defined(OS_CHROMEOS)
    374   chromeos::ScopedTestDeviceSettingsService test_device_settings_service_;
    375   chromeos::ScopedTestCrosSettings test_cros_settings_;
    376   scoped_ptr<chromeos::ScopedTestUserManager> test_user_manager_;
    377 #endif
    378 
    379   MockProfileSharedRenderProcessHostFactory rph_factory_;
    380 
    381   ScopedVector<ProfileState> profile_states_;
    382 };
    383 
    384 namespace {
    385 
    386 bool MediaFileSystemInfoComparator(const MediaFileSystemInfo& a,
    387                                    const MediaFileSystemInfo& b) {
    388   CHECK_NE(a.name, b.name);  // Name must be unique.
    389   return a.name < b.name;
    390 }
    391 
    392 ///////////////////////////////////////////////
    393 // MockProfileSharedRenderProcessHostFactory //
    394 ///////////////////////////////////////////////
    395 
    396 MockProfileSharedRenderProcessHostFactory::
    397     ~MockProfileSharedRenderProcessHostFactory() {
    398   STLDeleteValues(&rph_map_);
    399 }
    400 
    401 content::MockRenderProcessHost*
    402 MockProfileSharedRenderProcessHostFactory::ReleaseRPH(
    403     content::BrowserContext* browser_context) {
    404   ProfileRPHMap::iterator existing = rph_map_.find(browser_context);
    405   if (existing == rph_map_.end())
    406     return NULL;
    407   content::MockRenderProcessHost* result = existing->second;
    408   rph_map_.erase(existing);
    409   return result;
    410 }
    411 
    412 content::RenderProcessHost*
    413 MockProfileSharedRenderProcessHostFactory::CreateRenderProcessHost(
    414     content::BrowserContext* browser_context,
    415     content::SiteInstance* site_instance) const {
    416   ProfileRPHMap::const_iterator existing = rph_map_.find(browser_context);
    417   if (existing != rph_map_.end())
    418     return existing->second;
    419   rph_map_[browser_context] =
    420       new content::MockRenderProcessHost(browser_context);
    421   return rph_map_[browser_context];
    422 }
    423 
    424 //////////////////
    425 // ProfileState //
    426 //////////////////
    427 
    428 ProfileState::ProfileState(
    429     MockProfileSharedRenderProcessHostFactory* rph_factory)
    430     : num_comparisons_(0),
    431       profile_(new TestingProfile()) {
    432   extensions::TestExtensionSystem* extension_system(
    433       static_cast<extensions::TestExtensionSystem*>(
    434           extensions::ExtensionSystem::Get(profile_.get())));
    435   extension_system->CreateExtensionService(
    436       CommandLine::ForCurrentProcess(), base::FilePath(), false);
    437 
    438   std::vector<std::string> all_permissions;
    439   all_permissions.push_back("allAutoDetected");
    440   all_permissions.push_back("read");
    441   std::vector<std::string> read_permissions;
    442   read_permissions.push_back("read");
    443 
    444   all_permission_extension_ =
    445       AddMediaGalleriesApp("all", all_permissions, profile_.get());
    446   regular_permission_extension_ =
    447       AddMediaGalleriesApp("regular", read_permissions, profile_.get());
    448   no_permissions_extension_ =
    449       AddMediaGalleriesApp("no", read_permissions, profile_.get());
    450 
    451   single_web_contents_.reset(
    452       content::WebContentsTester::CreateTestWebContents(profile_.get(), NULL));
    453   single_rph_ = rph_factory->ReleaseRPH(profile_.get());
    454 
    455   shared_web_contents1_.reset(
    456       content::WebContentsTester::CreateTestWebContents(profile_.get(), NULL));
    457   shared_web_contents2_.reset(
    458       content::WebContentsTester::CreateTestWebContents(profile_.get(), NULL));
    459   shared_rph_ = rph_factory->ReleaseRPH(profile_.get());
    460 }
    461 
    462 ProfileState::~ProfileState() {
    463   // TestExtensionSystem uses DeleteSoon, so we need to delete the profiles
    464   // and then run the message queue to clean up.  But first we have to
    465   // delete everything that references the profile.
    466   single_web_contents_.reset();
    467   shared_web_contents1_.reset();
    468   shared_web_contents2_.reset();
    469   profile_.reset();
    470 
    471   base::MessageLoop::current()->RunUntilIdle();
    472 }
    473 
    474 MediaGalleriesPreferences* ProfileState::GetMediaGalleriesPrefs() {
    475   MediaGalleriesPreferences* prefs =
    476       MediaGalleriesPreferencesFactory::GetForProfile(profile_.get());
    477   base::RunLoop loop;
    478   prefs->EnsureInitialized(loop.QuitClosure());
    479   loop.Run();
    480   return prefs;
    481 }
    482 
    483 void ProfileState::CheckGalleries(
    484     const std::string& test,
    485     const std::vector<MediaFileSystemInfo>& regular_extension_galleries,
    486     const std::vector<MediaFileSystemInfo>& all_extension_galleries) {
    487   content::RenderViewHost* rvh = single_web_contents_->GetRenderViewHost();
    488   MediaFileSystemRegistry* registry =
    489       g_browser_process->media_file_system_registry();
    490 
    491   // No Media Galleries permissions.
    492   std::vector<MediaFileSystemInfo> empty_expectation;
    493   std::vector<base::string16> empty_names;
    494   registry->GetMediaFileSystemsForExtension(
    495       rvh, no_permissions_extension_.get(),
    496       base::Bind(&ProfileState::CompareResults, base::Unretained(this),
    497                  base::StringPrintf("%s (no permission)", test.c_str()),
    498                  base::ConstRef(empty_names),
    499                  base::ConstRef(empty_expectation)));
    500   base::MessageLoop::current()->RunUntilIdle();
    501   EXPECT_EQ(1, GetAndClearComparisonCount());
    502 
    503   // Read permission only.
    504   registry->GetMediaFileSystemsForExtension(
    505       rvh, regular_permission_extension_.get(),
    506       base::Bind(&ProfileState::CompareResults, base::Unretained(this),
    507                  base::StringPrintf("%s (regular permission)", test.c_str()),
    508                  base::ConstRef(compare_names_read_),
    509                  base::ConstRef(regular_extension_galleries)));
    510   base::MessageLoop::current()->RunUntilIdle();
    511   EXPECT_EQ(1, GetAndClearComparisonCount());
    512 
    513   // All galleries permission.
    514   registry->GetMediaFileSystemsForExtension(
    515       rvh, all_permission_extension_.get(),
    516       base::Bind(&ProfileState::CompareResults, base::Unretained(this),
    517                  base::StringPrintf("%s (all permission)", test.c_str()),
    518                  base::ConstRef(compare_names_all_),
    519                  base::ConstRef(all_extension_galleries)));
    520   base::MessageLoop::current()->RunUntilIdle();
    521   EXPECT_EQ(1, GetAndClearComparisonCount());
    522 }
    523 
    524 FSInfoMap ProfileState::GetGalleriesInfo(extensions::Extension* extension) {
    525   content::RenderViewHost* rvh = single_web_contents_->GetRenderViewHost();
    526   FSInfoMap results;
    527   MediaFileSystemRegistry* registry =
    528       g_browser_process->media_file_system_registry();
    529   registry->GetMediaFileSystemsForExtension(
    530       rvh, extension,
    531       base::Bind(&GetGalleryInfoCallback, base::Unretained(&results)));
    532   base::MessageLoop::current()->RunUntilIdle();
    533   return results;
    534 }
    535 
    536 extensions::Extension* ProfileState::all_permission_extension() {
    537   return all_permission_extension_.get();
    538 }
    539 
    540 extensions::Extension* ProfileState::regular_permission_extension() {
    541   return regular_permission_extension_.get();
    542 }
    543 
    544 Profile* ProfileState::profile() {
    545   return profile_.get();
    546 }
    547 
    548 void ProfileState::AddNameForReadCompare(const base::string16& name) {
    549   compare_names_read_.push_back(name);
    550 }
    551 
    552 void ProfileState::AddNameForAllCompare(const base::string16& name) {
    553   compare_names_all_.push_back(name);
    554 }
    555 
    556 bool ProfileState::ContainsEntry(
    557     const MediaFileSystemInfo& info,
    558     const std::vector<MediaFileSystemInfo>& container) {
    559   for (size_t i = 0; i < container.size(); ++i) {
    560     if (info.path.value() == container[i].path.value()) {
    561       EXPECT_FALSE(container[i].fsid.empty());
    562       if (!info.fsid.empty())
    563         EXPECT_EQ(info.fsid, container[i].fsid);
    564       return true;
    565     }
    566   }
    567   return false;
    568 }
    569 
    570 void ProfileState::CompareResults(
    571     const std::string& test,
    572     const std::vector<base::string16>& names,
    573     const std::vector<MediaFileSystemInfo>& expected,
    574     const std::vector<MediaFileSystemInfo>& actual) {
    575   num_comparisons_++;
    576   EXPECT_EQ(expected.size(), actual.size()) << test;
    577 
    578   // Order isn't important, so sort the results.
    579   std::vector<MediaFileSystemInfo> sorted(actual);
    580   std::sort(sorted.begin(), sorted.end(), MediaFileSystemInfoComparator);
    581   std::vector<MediaFileSystemInfo> expect(expected);
    582   std::sort(expect.begin(), expect.end(), MediaFileSystemInfoComparator);
    583   std::vector<base::string16> expect_names(names);
    584   std::sort(expect_names.begin(), expect_names.end());
    585 
    586   for (size_t i = 0; i < expect.size() && i < sorted.size(); ++i) {
    587     if (expect_names.size() > i)
    588       EXPECT_EQ(expect_names[i], sorted[i].name) << test;
    589     EXPECT_TRUE(ContainsEntry(expect[i], sorted)) << test;
    590   }
    591 }
    592 
    593 int ProfileState::GetAndClearComparisonCount() {
    594   int result = num_comparisons_;
    595   num_comparisons_ = 0;
    596   return result;
    597 }
    598 
    599 }  // namespace
    600 
    601 /////////////////////////////////
    602 // MediaFileSystemRegistryTest //
    603 /////////////////////////////////
    604 
    605 void MediaFileSystemRegistryTest::CreateProfileState(size_t profile_count) {
    606   for (size_t i = 0; i < profile_count; ++i) {
    607     ProfileState* state = new ProfileState(&rph_factory_);
    608     profile_states_.push_back(state);
    609   }
    610 }
    611 
    612 ProfileState* MediaFileSystemRegistryTest::GetProfileState(size_t i) {
    613   return profile_states_[i];
    614 }
    615 
    616 MediaGalleriesPreferences* MediaFileSystemRegistryTest::GetPreferences(
    617     Profile* profile) {
    618   MediaGalleriesPreferences* prefs = registry()->GetPreferences(profile);
    619   base::RunLoop loop;
    620   prefs->EnsureInitialized(loop.QuitClosure());
    621   loop.Run();
    622   return prefs;
    623 }
    624 
    625 std::string MediaFileSystemRegistryTest::AddUserGallery(
    626     StorageInfo::Type type,
    627     const std::string& unique_id,
    628     const base::FilePath& path) {
    629   std::string device_id = StorageInfo::MakeDeviceId(type, unique_id);
    630   DCHECK(!StorageInfo::IsMediaDevice(device_id));
    631 
    632   for (size_t i = 0; i < profile_states_.size(); ++i) {
    633     profile_states_[i]->GetMediaGalleriesPrefs()->AddGallery(
    634         device_id, base::FilePath(), MediaGalleryPrefInfo::kUserAdded,
    635         base::string16(), base::string16(), base::string16(), 0,
    636         base::Time::Now(), 0, 0, 0);
    637   }
    638   return device_id;
    639 }
    640 
    641 std::string MediaFileSystemRegistryTest::AttachDevice(
    642     StorageInfo::Type type,
    643     const std::string& unique_id,
    644     const base::FilePath& location) {
    645   std::string device_id = StorageInfo::MakeDeviceId(type, unique_id);
    646   DCHECK(StorageInfo::IsRemovableDevice(device_id));
    647   base::string16 label = location.BaseName().LossyDisplayName();
    648   ProcessAttach(device_id, label, location.value());
    649   base::MessageLoop::current()->RunUntilIdle();
    650   return device_id;
    651 }
    652 
    653 void MediaFileSystemRegistryTest::DetachDevice(const std::string& device_id) {
    654   DCHECK(StorageInfo::IsRemovableDevice(device_id));
    655   ProcessDetach(device_id);
    656   base::MessageLoop::current()->RunUntilIdle();
    657 }
    658 
    659 void MediaFileSystemRegistryTest::SetGalleryPermission(
    660     ProfileState* profile_state, extensions::Extension* extension,
    661     const std::string& device_id, bool has_access) {
    662   MediaGalleriesPreferences* preferences =
    663       profile_state->GetMediaGalleriesPrefs();
    664   MediaGalleryPrefIdSet pref_id =
    665       preferences->LookUpGalleriesByDeviceId(device_id);
    666   ASSERT_EQ(1U, pref_id.size());
    667   preferences->SetGalleryPermissionForExtension(*extension, *pref_id.begin(),
    668                                                 has_access);
    669 }
    670 
    671 void MediaFileSystemRegistryTest::AssertAllAutoAddedGalleries() {
    672   for (size_t i = 0; i < profile_states_.size(); ++i) {
    673     MediaGalleriesPreferences* prefs =
    674         profile_states_[0]->GetMediaGalleriesPrefs();
    675 
    676     // Make sure that we have at least one gallery and that they are all
    677     // auto added galleries.
    678     const MediaGalleriesPrefInfoMap& galleries = prefs->known_galleries();
    679 #if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
    680     ASSERT_GT(galleries.size(), 0U);
    681 #endif
    682     for (MediaGalleriesPrefInfoMap::const_iterator it = galleries.begin();
    683          it != galleries.end();
    684          ++it) {
    685       ASSERT_EQ(MediaGalleryPrefInfo::kAutoDetected, it->second.type);
    686     }
    687   }
    688 }
    689 
    690 void MediaFileSystemRegistryTest::InitForGalleriesInfoTest(
    691     FSInfoMap* galleries_info) {
    692   CreateProfileState(1);
    693   AssertAllAutoAddedGalleries();
    694 
    695   // Get all existing gallery names.
    696   ProfileState* profile_state = GetProfileState(0U);
    697   *galleries_info = profile_state->GetGalleriesInfo(
    698       profile_state->all_permission_extension());
    699 #if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
    700   ASSERT_EQ(3U, galleries_info->size());
    701 #else
    702   ASSERT_EQ(0U, galleries_info->size());
    703 #endif
    704 }
    705 
    706 void MediaFileSystemRegistryTest::CheckNewGalleryInfo(
    707     ProfileState* profile_state,
    708     const FSInfoMap& galleries_info,
    709     const base::FilePath& location,
    710     bool removable,
    711     bool media_device) {
    712   // Get new galleries.
    713   FSInfoMap new_galleries_info = profile_state->GetGalleriesInfo(
    714       profile_state->all_permission_extension());
    715   ASSERT_EQ(galleries_info.size() + 1U, new_galleries_info.size());
    716 
    717   bool found_new = false;
    718   for (FSInfoMap::const_iterator it = new_galleries_info.begin();
    719        it != new_galleries_info.end();
    720        ++it) {
    721     if (ContainsKey(galleries_info, it->first))
    722       continue;
    723 
    724     ASSERT_FALSE(found_new);
    725     CheckGalleryInfo(it->second, test_file_system_context_, location,
    726                      removable, media_device);
    727     found_new = true;
    728   }
    729   ASSERT_TRUE(found_new);
    730 }
    731 
    732 std::vector<MediaFileSystemInfo>
    733 MediaFileSystemRegistryTest::GetAutoAddedGalleries(
    734     ProfileState* profile_state) {
    735   const MediaGalleriesPrefInfoMap& galleries =
    736       profile_state->GetMediaGalleriesPrefs()->known_galleries();
    737   std::vector<MediaFileSystemInfo> result;
    738   for (MediaGalleriesPrefInfoMap::const_iterator it = galleries.begin();
    739        it != galleries.end();
    740        ++it) {
    741     if (it->second.type == MediaGalleryPrefInfo::kAutoDetected) {
    742       base::FilePath path = it->second.AbsolutePath();
    743       MediaFileSystemInfo info(path.BaseName().LossyDisplayName(), path,
    744                                std::string(), 0, std::string(), false, false);
    745       result.push_back(info);
    746     }
    747   }
    748   std::sort(result.begin(), result.end(), MediaFileSystemInfoComparator);
    749   return result;
    750 }
    751 
    752 size_t MediaFileSystemRegistryTest::GetExtensionGalleriesHostCount(
    753     const MediaFileSystemRegistry* registry) const {
    754   size_t extension_galleries_host_count = 0;
    755   for (MediaFileSystemRegistry::ExtensionGalleriesHostMap::const_iterator it =
    756            registry->extension_hosts_map_.begin();
    757        it != registry->extension_hosts_map_.end();
    758        ++it) {
    759     extension_galleries_host_count += it->second.size();
    760   }
    761   return extension_galleries_host_count;
    762 }
    763 
    764 
    765 void MediaFileSystemRegistryTest::SetUp() {
    766   ChromeRenderViewHostTestHarness::SetUp();
    767   ASSERT_TRUE(TestStorageMonitor::CreateAndInstall());
    768 
    769   DeleteContents();
    770   SetRenderProcessHostFactory(&rph_factory_);
    771 
    772   test_file_system_context_ = new TestMediaFileSystemContext(
    773       g_browser_process->media_file_system_registry());
    774 
    775 #if defined(OS_CHROMEOS)
    776   test_user_manager_.reset(new chromeos::ScopedTestUserManager());
    777 #endif
    778 
    779   ASSERT_TRUE(galleries_dir_.CreateUniqueTempDir());
    780   empty_dir_ = galleries_dir_.path().AppendASCII("empty");
    781   ASSERT_TRUE(base::CreateDirectory(empty_dir_));
    782   dcim_dir_ = galleries_dir_.path().AppendASCII("with_dcim");
    783   ASSERT_TRUE(base::CreateDirectory(dcim_dir_));
    784   ASSERT_TRUE(base::CreateDirectory(
    785       dcim_dir_.Append(storage_monitor::kDCIMDirectoryName)));
    786 }
    787 
    788 void MediaFileSystemRegistryTest::TearDown() {
    789   profile_states_.clear();
    790   MediaFileSystemRegistry* registry =
    791       g_browser_process->media_file_system_registry();
    792   EXPECT_EQ(0U, GetExtensionGalleriesHostCount(registry));
    793   TestStorageMonitor::Destroy();
    794 #if defined(OS_CHROMEOS)
    795   test_user_manager_.reset();
    796 #endif
    797 
    798   ChromeRenderViewHostTestHarness::TearDown();
    799 }
    800 
    801 ///////////
    802 // Tests //
    803 ///////////
    804 
    805 TEST_F(MediaFileSystemRegistryTest, Basic) {
    806   CreateProfileState(1);
    807   AssertAllAutoAddedGalleries();
    808 
    809   ProfileState* profile_state = GetProfileState(0);
    810   std::vector<MediaFileSystemInfo> auto_galleries =
    811       GetAutoAddedGalleries(profile_state);
    812   std::vector<MediaFileSystemInfo> empty_expectation;
    813   profile_state->CheckGalleries("basic", empty_expectation, auto_galleries);
    814 }
    815 
    816 TEST_F(MediaFileSystemRegistryTest, UserAddedGallery) {
    817   CreateProfileState(1);
    818   AssertAllAutoAddedGalleries();
    819   ProfileState* profile_state = GetProfileState(0);
    820   std::vector<MediaFileSystemInfo> auto_galleries =
    821       GetAutoAddedGalleries(profile_state);
    822   std::vector<MediaFileSystemInfo> added_galleries;
    823   profile_state->CheckGalleries("user added init", added_galleries,
    824                                 auto_galleries);
    825 
    826   // Add a user gallery to the regular permission extension.
    827   std::string device_id = AddUserGallery(StorageInfo::FIXED_MASS_STORAGE,
    828                                          empty_dir().AsUTF8Unsafe(),
    829                                          empty_dir());
    830   SetGalleryPermission(profile_state,
    831                        profile_state->regular_permission_extension(),
    832                        device_id,
    833                        true /*has access*/);
    834   MediaFileSystemInfo added_info(empty_dir().LossyDisplayName(), empty_dir(),
    835                                  std::string(), 0, std::string(), false, false);
    836   added_galleries.push_back(added_info);
    837   profile_state->CheckGalleries("user added regular", added_galleries,
    838                                 auto_galleries);
    839 
    840   // Add it to the all galleries extension.
    841   SetGalleryPermission(profile_state,
    842                        profile_state->all_permission_extension(),
    843                        device_id,
    844                        true /*has access*/);
    845   auto_galleries.push_back(added_info);
    846   profile_state->CheckGalleries("user added all", added_galleries,
    847                                 auto_galleries);
    848 }
    849 
    850 // Regression test to make sure erasing galleries does not result a crash.
    851 TEST_F(MediaFileSystemRegistryTest, EraseGalleries) {
    852   CreateProfileState(1);
    853   AssertAllAutoAddedGalleries();
    854 
    855   ProfileState* profile_state = GetProfileState(0);
    856   std::vector<MediaFileSystemInfo> auto_galleries =
    857       GetAutoAddedGalleries(profile_state);
    858   std::vector<MediaFileSystemInfo> empty_expectation;
    859   profile_state->CheckGalleries("erase", empty_expectation, auto_galleries);
    860 
    861   MediaGalleriesPreferences* prefs = profile_state->GetMediaGalleriesPrefs();
    862   MediaGalleriesPrefInfoMap galleries = prefs->known_galleries();
    863   for (MediaGalleriesPrefInfoMap::const_iterator it = galleries.begin();
    864        it != galleries.end(); ++it) {
    865     prefs->ForgetGalleryById(it->first);
    866   }
    867 }
    868 
    869 // Regression test to make sure calling GetPreferences() does not re-insert
    870 // galleries on auto-detected removable devices that were blacklisted.
    871 TEST_F(MediaFileSystemRegistryTest,
    872        GetPreferencesDoesNotReinsertBlacklistedGalleries) {
    873   CreateProfileState(1);
    874   AssertAllAutoAddedGalleries();
    875 
    876   ProfileState* profile_state = GetProfileState(0);
    877   const size_t gallery_count = GetAutoAddedGalleries(profile_state).size();
    878 
    879   // Attach a device.
    880   const std::string device_id = AttachDevice(
    881       StorageInfo::REMOVABLE_MASS_STORAGE_WITH_DCIM,
    882       "removable_dcim_fake_id",
    883       dcim_dir());
    884   EXPECT_EQ(gallery_count + 1, GetAutoAddedGalleries(profile_state).size());
    885 
    886   // Forget the device.
    887   bool forget_gallery = false;
    888   MediaGalleriesPreferences* prefs = GetPreferences(profile_state->profile());
    889   const MediaGalleriesPrefInfoMap& galleries = prefs->known_galleries();
    890   for (MediaGalleriesPrefInfoMap::const_iterator it = galleries.begin();
    891        it != galleries.end(); ++it) {
    892     if (it->second.device_id == device_id) {
    893       prefs->ForgetGalleryById(it->first);
    894       forget_gallery = true;
    895       break;
    896     }
    897   }
    898   base::MessageLoop::current()->RunUntilIdle();
    899   EXPECT_TRUE(forget_gallery);
    900   EXPECT_EQ(gallery_count, GetAutoAddedGalleries(profile_state).size());
    901 
    902   // Call GetPreferences() and the gallery count should not change.
    903   prefs = GetPreferences(profile_state->profile());
    904   EXPECT_EQ(gallery_count, GetAutoAddedGalleries(profile_state).size());
    905 }
    906 
    907 TEST_F(MediaFileSystemRegistryTest, GalleryNameDefault) {
    908   FSInfoMap galleries_info;
    909   InitForGalleriesInfoTest(&galleries_info);
    910 
    911   for (FSInfoMap::const_iterator it = galleries_info.begin();
    912        it != galleries_info.end();
    913        ++it) {
    914     CheckGalleryInfo(it->second, test_file_system_context(),
    915                      it->second.path, false, false);
    916   }
    917 }
    918 
    919 // TODO(gbillock): Move the remaining test into the linux directory.
    920 #if !defined(OS_MACOSX) && !defined(OS_WIN)
    921 TEST_F(MediaFileSystemRegistryTest, GalleryMTP) {
    922   FSInfoMap galleries_info;
    923   InitForGalleriesInfoTest(&galleries_info);
    924 
    925   base::FilePath location(FILE_PATH_LITERAL("/mtp_bogus"));
    926   AttachDevice(StorageInfo::MTP_OR_PTP, "mtp_fake_id", location);
    927   CheckNewGalleryInfo(GetProfileState(0U), galleries_info, location,
    928                       true /*removable*/, true /* media device */);
    929 }
    930 #endif
    931 
    932 TEST_F(MediaFileSystemRegistryTest, GalleryDCIM) {
    933   FSInfoMap galleries_info;
    934   InitForGalleriesInfoTest(&galleries_info);
    935 
    936   AttachDevice(StorageInfo::REMOVABLE_MASS_STORAGE_WITH_DCIM,
    937                "removable_dcim_fake_id",
    938                dcim_dir());
    939   CheckNewGalleryInfo(GetProfileState(0U), galleries_info, dcim_dir(),
    940                       true /*removable*/, true /* media device */);
    941 }
    942 
    943 TEST_F(MediaFileSystemRegistryTest, GalleryNoDCIM) {
    944   FSInfoMap galleries_info;
    945   InitForGalleriesInfoTest(&galleries_info);
    946 
    947   std::string device_id =
    948       AttachDevice(StorageInfo::REMOVABLE_MASS_STORAGE_NO_DCIM,
    949                    empty_dir().AsUTF8Unsafe(),
    950                    empty_dir());
    951   std::string device_id2 =
    952       AddUserGallery(StorageInfo::REMOVABLE_MASS_STORAGE_NO_DCIM,
    953                      empty_dir().AsUTF8Unsafe(),
    954                      empty_dir());
    955   ASSERT_EQ(device_id, device_id2);
    956   // Add permission for new non-default gallery.
    957   ProfileState* profile_state = GetProfileState(0U);
    958   SetGalleryPermission(profile_state,
    959                        profile_state->all_permission_extension(),
    960                        device_id,
    961                        true /*has access*/);
    962   CheckNewGalleryInfo(profile_state, galleries_info, empty_dir(),
    963                       true /*removable*/, false /* media device */);
    964 }
    965 
    966 TEST_F(MediaFileSystemRegistryTest, GalleryUserAddedPath) {
    967   FSInfoMap galleries_info;
    968   InitForGalleriesInfoTest(&galleries_info);
    969 
    970   std::string device_id = AddUserGallery(StorageInfo::FIXED_MASS_STORAGE,
    971                                          empty_dir().AsUTF8Unsafe(),
    972                                          empty_dir());
    973   // Add permission for new non-default gallery.
    974   ProfileState* profile_state = GetProfileState(0U);
    975   SetGalleryPermission(profile_state,
    976                        profile_state->all_permission_extension(),
    977                        device_id,
    978                        true /*has access*/);
    979   CheckNewGalleryInfo(profile_state, galleries_info, empty_dir(),
    980                       false /*removable*/, false /* media device */);
    981 }
    982 
    983 TEST_F(MediaFileSystemRegistryTest, DetachedDeviceGalleryPath) {
    984   const std::string device_id = AttachDevice(
    985       StorageInfo::REMOVABLE_MASS_STORAGE_WITH_DCIM,
    986       "removable_dcim_fake_id",
    987       dcim_dir());
    988 
    989   MediaGalleryPrefInfo pref_info;
    990   pref_info.device_id = device_id;
    991   EXPECT_EQ(dcim_dir().value(), pref_info.AbsolutePath().value());
    992 
    993   MediaGalleryPrefInfo pref_info_with_relpath;
    994   pref_info_with_relpath.path =
    995       base::FilePath(FILE_PATH_LITERAL("test_relpath"));
    996   pref_info_with_relpath.device_id = device_id;
    997   EXPECT_EQ(dcim_dir().Append(pref_info_with_relpath.path).value(),
    998             pref_info_with_relpath.AbsolutePath().value());
    999 
   1000   DetachDevice(device_id);
   1001   EXPECT_TRUE(pref_info.AbsolutePath().empty());
   1002   EXPECT_TRUE(pref_info_with_relpath.AbsolutePath().empty());
   1003 }
   1004 
   1005 TEST_F(MediaFileSystemRegistryTest, TestNameConstruction) {
   1006   CreateProfileState(1);
   1007   AssertAllAutoAddedGalleries();
   1008 
   1009   ProfileState* profile_state = GetProfileState(0);
   1010 
   1011   std::string user_gallery = AddUserGallery(StorageInfo::FIXED_MASS_STORAGE,
   1012                                             empty_dir().AsUTF8Unsafe(),
   1013                                             empty_dir());
   1014   SetGalleryPermission(profile_state,
   1015                        profile_state->regular_permission_extension(),
   1016                        user_gallery,
   1017                        true /*has access*/);
   1018   SetGalleryPermission(profile_state,
   1019                        profile_state->all_permission_extension(),
   1020                        user_gallery,
   1021                        true /*has access*/);
   1022 
   1023   std::vector<MediaFileSystemInfo> auto_galleries =
   1024       GetAutoAddedGalleries(profile_state);
   1025   MediaFileSystemInfo added_info(empty_dir().BaseName().LossyDisplayName(),
   1026                                  empty_dir(), std::string(), 0, std::string(),
   1027                                  false, false);
   1028   auto_galleries.push_back(added_info);
   1029   std::vector<MediaFileSystemInfo> one_expectation;
   1030   one_expectation.push_back(added_info);
   1031 
   1032   base::string16 empty_dir_name = GetExpectedFolderName(empty_dir());
   1033   profile_state->AddNameForReadCompare(empty_dir_name);
   1034   profile_state->AddNameForAllCompare(empty_dir_name);
   1035 
   1036   // This part of the test is conditional on default directories existing
   1037   // on the test platform. In ChromeOS, these directories do not exist.
   1038   base::FilePath path;
   1039   if (num_auto_galleries() > 0) {
   1040     ASSERT_TRUE(PathService::Get(chrome::DIR_USER_MUSIC, &path));
   1041     profile_state->AddNameForAllCompare(GetExpectedFolderName(path));
   1042     ASSERT_TRUE(PathService::Get(chrome::DIR_USER_PICTURES, &path));
   1043     profile_state->AddNameForAllCompare(GetExpectedFolderName(path));
   1044     ASSERT_TRUE(PathService::Get(chrome::DIR_USER_VIDEOS, &path));
   1045     profile_state->AddNameForAllCompare(GetExpectedFolderName(path));
   1046 
   1047     profile_state->CheckGalleries("names-dir", one_expectation, auto_galleries);
   1048   } else {
   1049     profile_state->CheckGalleries("names", one_expectation, one_expectation);
   1050   }
   1051 }
   1052 
   1053 TEST_F(MediaFileSystemRegistryTest, PreferenceListener) {
   1054   CreateProfileState(1);
   1055   AssertAllAutoAddedGalleries();
   1056 
   1057   // Add a user gallery to the regular permission extension.
   1058   std::string device_id = AddUserGallery(StorageInfo::FIXED_MASS_STORAGE,
   1059                                          empty_dir().AsUTF8Unsafe(),
   1060                                          empty_dir());
   1061   ProfileState* profile_state = GetProfileState(0);
   1062   SetGalleryPermission(profile_state,
   1063                        profile_state->regular_permission_extension(),
   1064                        device_id,
   1065                        true /*has access*/);
   1066 
   1067   FSInfoMap fs_info = profile_state->GetGalleriesInfo(
   1068       profile_state->regular_permission_extension());
   1069   ASSERT_EQ(1U, fs_info.size());
   1070   EXPECT_FALSE(test_file_system_context()->GetRegisteredPath(
   1071       fs_info.begin()->second.fsid).empty());
   1072 
   1073   // Revoke permission and ensure that the file system is revoked.
   1074   SetGalleryPermission(profile_state,
   1075                        profile_state->regular_permission_extension(),
   1076                        device_id,
   1077                        false /*has access*/);
   1078   EXPECT_TRUE(test_file_system_context()->GetRegisteredPath(
   1079       fs_info.begin()->second.fsid).empty());
   1080 }
   1081