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.
5 #include "base/auto_reset.h"
6 #include "base/file_util.h"
7 #include "base/files/scoped_temp_dir.h"
8 #include "base/json/json_writer.h"
9 #include "base/numerics/safe_conversions.h"
10 #include "base/path_service.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/values.h"
14 #include "chrome/browser/apps/app_browsertest_util.h"
15 #include "chrome/browser/browser_process.h"
16 #include "chrome/browser/media_galleries/media_file_system_registry.h"
17 #include "chrome/browser/media_galleries/media_folder_finder.h"
18 #include "chrome/browser/media_galleries/media_galleries_preferences.h"
19 #include "chrome/browser/media_galleries/media_galleries_test_util.h"
20 #include "chrome/browser/media_galleries/media_scan_manager.h"
21 #include "chrome/common/chrome_paths.h"
22 #include "components/storage_monitor/storage_info.h"
23 #include "components/storage_monitor/storage_monitor.h"
24 #include "content/public/test/test_utils.h"
25 #include "extensions/browser/extension_system.h"
27 #if defined(OS_WIN) || defined(OS_MACOSX)
28 #include "chrome/browser/media_galleries/fileapi/picasa_finder.h"
29 #include "chrome/common/media_galleries/picasa_test_util.h"
30 #include "chrome/common/media_galleries/picasa_types.h"
31 #include "chrome/common/media_galleries/pmp_test_util.h"
34 #if defined(OS_MACOSX)
35 #include "base/mac/foundation_util.h"
36 #include "base/strings/sys_string_conversions.h"
37 #include "chrome/browser/media_galleries/fileapi/iapps_finder_impl.h"
40 using extensions::PlatformAppBrowserTest;
44 // Dummy device properties.
45 const char kDeviceId[] = "testDeviceId";
46 const char kDeviceName[] = "foobar";
47 #if defined(FILE_PATH_USES_DRIVE_LETTERS)
48 base::FilePath::CharType kDevicePath[] = FILE_PATH_LITERAL("C:\\qux");
50 base::FilePath::CharType kDevicePath[] = FILE_PATH_LITERAL("/qux");
53 void DoNothingMediaFolderFinderResultCallback(
55 const MediaFolderFinder::MediaFolderFinderResults& /*results*/) {
58 class DoNothingMediaFolderFinder : public MediaFolderFinder {
60 explicit DoNothingMediaFolderFinder(
61 const MediaFolderFinderResultsCallback& callback)
62 : MediaFolderFinder(callback) {
64 virtual ~DoNothingMediaFolderFinder() {}
66 static MediaFolderFinder* CreateDoNothingMediaFolderFinder(
67 const MediaFolderFinderResultsCallback& callback) {
68 return new DoNothingMediaFolderFinder(
69 base::Bind(&DoNothingMediaFolderFinderResultCallback));
72 virtual void StartScan() OVERRIDE {}
79 class MediaGalleriesPlatformAppBrowserTest : public PlatformAppBrowserTest {
81 MediaGalleriesPlatformAppBrowserTest() : test_jpg_size_(0) {}
82 virtual ~MediaGalleriesPlatformAppBrowserTest() {}
84 virtual void SetUpOnMainThread() OVERRIDE {
85 PlatformAppBrowserTest::SetUpOnMainThread();
86 ensure_media_directories_exists_.reset(new EnsureMediaDirectoriesExists);
89 ASSERT_TRUE(base::GetFileSize(GetCommonDataDir().AppendASCII("test.jpg"),
91 test_jpg_size_ = base::checked_cast<int>(file_size);
94 virtual void TearDownOnMainThread() OVERRIDE {
95 ensure_media_directories_exists_.reset();
96 PlatformAppBrowserTest::TearDownOnMainThread();
99 bool RunMediaGalleriesTest(const std::string& extension_name) {
100 base::ListValue empty_list_value;
101 return RunMediaGalleriesTestWithArg(extension_name, empty_list_value);
104 bool RunMediaGalleriesTestWithArg(const std::string& extension_name,
105 const base::ListValue& custom_arg_value) {
106 // Copy the test data for this test into a temporary directory. Then add
107 // a common_injected.js to the temporary copy and run it.
108 const char kTestDir[] = "api_test/media_galleries/";
109 base::FilePath from_dir =
110 test_data_dir_.AppendASCII(kTestDir + extension_name);
111 from_dir = from_dir.NormalizePathSeparators();
113 base::ScopedTempDir temp_dir;
114 if (!temp_dir.CreateUniqueTempDir())
117 if (!base::CopyDirectory(from_dir, temp_dir.path(), true))
120 base::FilePath common_js_path(
121 GetCommonDataDir().AppendASCII("common_injected.js"));
122 base::FilePath inject_js_path(
123 temp_dir.path().AppendASCII(extension_name)
124 .AppendASCII("common_injected.js"));
125 if (!base::CopyFile(common_js_path, inject_js_path))
128 const char* custom_arg = NULL;
129 std::string json_string;
130 if (!custom_arg_value.empty()) {
131 base::JSONWriter::Write(&custom_arg_value, &json_string);
132 custom_arg = json_string.c_str();
135 base::AutoReset<base::FilePath> reset(&test_data_dir_, temp_dir.path());
136 bool result = RunPlatformAppTestWithArg(extension_name, custom_arg);
137 content::RunAllPendingInMessageLoop(); // avoid race on exit in registry.
141 void AttachFakeDevice() {
142 device_id_ = StorageInfo::MakeDeviceId(
143 StorageInfo::REMOVABLE_MASS_STORAGE_WITH_DCIM, kDeviceId);
145 StorageMonitor::GetInstance()->receiver()->ProcessAttach(
146 StorageInfo(device_id_, base::string16(), kDevicePath,
147 base::ASCIIToUTF16(kDeviceName), base::string16(),
148 base::string16(), 0));
149 content::RunAllPendingInMessageLoop();
152 void DetachFakeDevice() {
153 StorageMonitor::GetInstance()->receiver()->ProcessDetach(device_id_);
154 content::RunAllPendingInMessageLoop();
157 // Called if test only wants a single gallery it creates.
158 void RemoveAllGalleries() {
159 MediaGalleriesPreferences* preferences = GetAndInitializePreferences();
161 // Make a copy, as the iterator would be invalidated otherwise.
162 const MediaGalleriesPrefInfoMap galleries =
163 preferences->known_galleries();
164 for (MediaGalleriesPrefInfoMap::const_iterator it = galleries.begin();
165 it != galleries.end(); ++it) {
166 preferences->ForgetGalleryById(it->first);
170 // This function makes a single fake gallery. This is needed to test platforms
171 // with no default media galleries, such as CHROMEOS. This fake gallery is
172 // pre-populated with a test.jpg and test.txt.
173 void MakeSingleFakeGallery() {
174 ASSERT_TRUE(fake_gallery_temp_dir_.CreateUniqueTempDir());
176 MediaGalleriesPreferences* preferences = GetAndInitializePreferences();
178 MediaGalleryPrefInfo gallery_info;
179 ASSERT_FALSE(preferences->LookUpGalleryByPath(fake_gallery_temp_dir_.path(),
181 preferences->AddGallery(gallery_info.device_id,
183 MediaGalleryPrefInfo::kAutoDetected,
184 gallery_info.volume_label,
185 gallery_info.vendor_name,
186 gallery_info.model_name,
187 gallery_info.total_size_in_bytes,
188 gallery_info.last_attach_time,
191 content::RunAllPendingInMessageLoop();
193 base::FilePath test_data_path(GetCommonDataDir());
194 base::FilePath write_path = fake_gallery_temp_dir_.path();
196 // Valid file, should show up in JS as a FileEntry.
197 ASSERT_TRUE(base::CopyFile(test_data_path.AppendASCII("test.jpg"),
198 write_path.AppendASCII("test.jpg")));
200 // Invalid file, should not show up as a FileEntry in JS at all.
201 ASSERT_TRUE(base::CopyFile(test_data_path.AppendASCII("test.txt"),
202 write_path.AppendASCII("test.txt")));
205 #if defined(OS_WIN) || defined(OS_MACOSX)
206 void PopulatePicasaTestData(const base::FilePath& picasa_app_data_root) {
207 base::FilePath picasa_database_path =
208 picasa::MakePicasaDatabasePath(picasa_app_data_root);
209 base::FilePath picasa_temp_dir_path =
210 picasa_database_path.DirName().AppendASCII(picasa::kPicasaTempDirName);
211 ASSERT_TRUE(base::CreateDirectory(picasa_database_path));
212 ASSERT_TRUE(base::CreateDirectory(picasa_temp_dir_path));
214 // Create fake folder directories.
215 base::FilePath folders_root =
216 ensure_media_directories_exists_->GetFakePicasaFoldersRootPath();
217 base::FilePath fake_folder_1 = folders_root.AppendASCII("folder1");
218 base::FilePath fake_folder_2 = folders_root.AppendASCII("folder2");
219 ASSERT_TRUE(base::CreateDirectory(fake_folder_1));
220 ASSERT_TRUE(base::CreateDirectory(fake_folder_2));
222 // Write folder and album contents.
223 picasa::WriteTestAlbumTable(
224 picasa_database_path, fake_folder_1, fake_folder_2);
225 picasa::WriteTestAlbumsImagesIndex(fake_folder_1, fake_folder_2);
227 base::FilePath test_jpg_path = GetCommonDataDir().AppendASCII("test.jpg");
228 ASSERT_TRUE(base::CopyFile(
229 test_jpg_path, fake_folder_1.AppendASCII("InBoth.jpg")));
230 ASSERT_TRUE(base::CopyFile(
231 test_jpg_path, fake_folder_1.AppendASCII("InSecondAlbumOnly.jpg")));
232 ASSERT_TRUE(base::CopyFile(
233 test_jpg_path, fake_folder_2.AppendASCII("InFirstAlbumOnly.jpg")));
235 #endif // defined(OS_WIN) || defined(OS_MACOSX)
237 #if defined(OS_MACOSX)
238 void PopulateIPhotoTestData(const base::FilePath& iphoto_data_root) {
239 std::string xml_contents = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
240 "<plist version=\"1.0\">"
243 " <key>List of Albums</key>"
247 " <key>AlbumId</key>"
248 " <integer>1</integer>"
249 " <key>AlbumName</key>"
250 " <string>Album1</string>"
251 " <key>KeyList</key>\n"
253 " <string>1</string>"
254 " <string>2</string>"
259 " <key>AlbumId</key>"
260 " <integer>2</integer>"
261 " <key>AlbumName</key>"
262 " <string>Album2</string>"
263 " <key>KeyList</key>\n"
265 " <string>2</string>"
271 " <key>Master Image List</key>\n"
276 " <key>MediaType</key>"
277 " <string>Image</string>"
278 " <key>Caption</key>"
279 " <string>caption 1</string>"
281 " <string>1</string>"
282 " <key>ModDateAsTimerInterval</key>"
283 " <string>386221543.0000</string>"
284 " <key>DateAsTimerInterval</key>"
285 " <string>386221543.0000</string>"
286 " <key>DateAsTimerIntervalGMT</key>"
287 " <string>385123456.00</string>"
288 " <key>ImagePath</key>"
289 " <string>$path1</string>"
290 " <key>ThumbPath</key>"
291 " <string>/thumb/path</string>\n"
296 " <key>MediaType</key>"
297 " <string>Image</string>"
298 " <key>Caption</key>"
299 " <string>caption 2</string>"
301 " <string>2</string>"
302 " <key>ModDateAsTimerInterval</key>"
303 " <string>386221543.0000</string>"
304 " <key>DateAsTimerInterval</key>"
305 " <string>386221543.0000</string>"
306 " <key>DateAsTimerIntervalGMT</key>"
307 " <string>385123456.00</string>"
308 " <key>ImagePath</key>"
309 " <string>$path2</string>"
310 " <key>ThumbPath</key>"
311 " <string>/thumb/path2</string>\n"
314 " </dict>\n" // Master Image List
319 base::FilePath test_jpg_path = GetCommonDataDir().AppendASCII("test.jpg");
320 ASSERT_TRUE(base::CreateDirectory(iphoto_data_root));
321 base::FilePath first_only_jpg =
322 iphoto_data_root.AppendASCII("InFirstAlbumOnly.jpg");
323 base::FilePath in_both_jpg = iphoto_data_root.AppendASCII("InBoth.jpg");
324 ASSERT_TRUE(base::CopyFile(test_jpg_path, first_only_jpg));
325 ASSERT_TRUE(base::CopyFile(test_jpg_path, in_both_jpg));
326 ReplaceFirstSubstringAfterOffset(
327 &xml_contents, 0, std::string("$path1"), first_only_jpg.value());
328 ReplaceFirstSubstringAfterOffset(
329 &xml_contents, 0, std::string("$path2"), in_both_jpg.value());
331 base::FilePath album_xml = iphoto_data_root.AppendASCII("AlbumData.xml");
332 ASSERT_NE(-1, file_util::WriteFile(album_xml,
333 xml_contents.c_str(),
334 xml_contents.size()));
336 #endif // defined(OS_MACOSX)
338 base::FilePath GetCommonDataDir() const {
339 return test_data_dir_.AppendASCII("api_test")
340 .AppendASCII("media_galleries")
341 .AppendASCII("common");
344 int num_galleries() const {
345 return ensure_media_directories_exists_->num_galleries();
348 int test_jpg_size() const { return test_jpg_size_; }
350 EnsureMediaDirectoriesExists* ensure_media_directories_exists() const {
351 return ensure_media_directories_exists_.get();
354 void InstallDoNothingFolderFinder() {
355 MediaScanManager * scan_manager =
356 g_browser_process->media_file_system_registry()->media_scan_manager();
357 scan_manager->SetMediaFolderFinderFactory(base::Bind(
358 &DoNothingMediaFolderFinder::CreateDoNothingMediaFolderFinder));
362 MediaGalleriesPreferences* GetAndInitializePreferences() {
363 MediaGalleriesPreferences* preferences =
364 g_browser_process->media_file_system_registry()->GetPreferences(
365 browser()->profile());
366 base::RunLoop runloop;
367 preferences->EnsureInitialized(runloop.QuitClosure());
372 std::string device_id_;
373 base::ScopedTempDir fake_gallery_temp_dir_;
375 scoped_ptr<EnsureMediaDirectoriesExists> ensure_media_directories_exists_;
378 IN_PROC_BROWSER_TEST_F(MediaGalleriesPlatformAppBrowserTest,
379 MediaGalleriesNoAccess) {
380 MakeSingleFakeGallery();
382 base::ListValue custom_args;
383 custom_args.AppendInteger(num_galleries() + 1);
385 ASSERT_TRUE(RunMediaGalleriesTestWithArg("no_access", custom_args))
389 IN_PROC_BROWSER_TEST_F(MediaGalleriesPlatformAppBrowserTest, NoGalleriesRead) {
390 ASSERT_TRUE(RunMediaGalleriesTest("no_galleries")) << message_;
393 IN_PROC_BROWSER_TEST_F(MediaGalleriesPlatformAppBrowserTest,
395 ASSERT_TRUE(RunMediaGalleriesTest("no_galleries_copy_to")) << message_;
398 IN_PROC_BROWSER_TEST_F(MediaGalleriesPlatformAppBrowserTest,
399 MediaGalleriesRead) {
400 RemoveAllGalleries();
401 MakeSingleFakeGallery();
402 base::ListValue custom_args;
403 custom_args.AppendInteger(test_jpg_size());
405 ASSERT_TRUE(RunMediaGalleriesTestWithArg("read_access", custom_args))
409 IN_PROC_BROWSER_TEST_F(MediaGalleriesPlatformAppBrowserTest,
410 MediaGalleriesCopyTo) {
411 RemoveAllGalleries();
412 MakeSingleFakeGallery();
413 ASSERT_TRUE(RunMediaGalleriesTest("copy_to_access")) << message_;
416 IN_PROC_BROWSER_TEST_F(MediaGalleriesPlatformAppBrowserTest,
417 MediaGalleriesDelete) {
418 MakeSingleFakeGallery();
419 base::ListValue custom_args;
420 custom_args.AppendInteger(num_galleries() + 1);
421 ASSERT_TRUE(RunMediaGalleriesTestWithArg("delete_access", custom_args))
425 IN_PROC_BROWSER_TEST_F(MediaGalleriesPlatformAppBrowserTest,
426 MediaGalleriesAccessAttached) {
429 base::ListValue custom_args;
430 custom_args.AppendInteger(num_galleries() + 1);
431 custom_args.AppendString(kDeviceName);
433 ASSERT_TRUE(RunMediaGalleriesTestWithArg("access_attached", custom_args))
439 #if defined(OS_WIN)|| defined(OS_MACOSX)
440 IN_PROC_BROWSER_TEST_F(MediaGalleriesPlatformAppBrowserTest,
441 PicasaDefaultLocation) {
443 PopulatePicasaTestData(
444 ensure_media_directories_exists()->GetFakeLocalAppDataPath());
445 #elif defined(OS_MACOSX)
446 PopulatePicasaTestData(
447 ensure_media_directories_exists()->GetFakeAppDataPath());
450 base::ListValue custom_args;
451 custom_args.AppendInteger(test_jpg_size());
452 ASSERT_TRUE(RunMediaGalleriesTestWithArg("picasa", custom_args)) << message_;
455 IN_PROC_BROWSER_TEST_F(MediaGalleriesPlatformAppBrowserTest,
456 PicasaCustomLocation) {
457 base::ScopedTempDir custom_picasa_app_data_root;
458 ASSERT_TRUE(custom_picasa_app_data_root.CreateUniqueTempDir());
459 ensure_media_directories_exists()->SetCustomPicasaAppDataPath(
460 custom_picasa_app_data_root.path());
461 PopulatePicasaTestData(custom_picasa_app_data_root.path());
463 base::ListValue custom_args;
464 custom_args.AppendInteger(test_jpg_size());
465 ASSERT_TRUE(RunMediaGalleriesTestWithArg("picasa", custom_args)) << message_;
467 #endif // defined(OS_WIN) || defined(OS_MACOSX)
469 #if defined(OS_MACOSX)
470 IN_PROC_BROWSER_TEST_F(MediaGalleriesPlatformAppBrowserTest,
472 PopulateIPhotoTestData(
473 ensure_media_directories_exists()->GetFakeIPhotoRootPath());
475 base::ListValue custom_args;
476 custom_args.AppendInteger(test_jpg_size());
477 ASSERT_TRUE(RunMediaGalleriesTestWithArg("iphoto", custom_args)) << message_;
479 iapps::SetMacPreferencesForTesting(NULL);
481 #endif // defined(OS_MACOSX)
483 IN_PROC_BROWSER_TEST_F(MediaGalleriesPlatformAppBrowserTest, Scan) {
484 InstallDoNothingFolderFinder();
485 ASSERT_TRUE(RunMediaGalleriesTest("scan")) << message_;