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