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