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