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