1 // Copyright 2014 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 // MediaGalleries gallery watch API browser tests.
6 
7 #include "base/callback_helpers.h"
8 #include "base/files/file_path.h"
9 #include "base/files/file_path_watcher.h"
10 #include "base/files/file_util.h"
11 #include "base/macros.h"
12 #include "base/run_loop.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "base/threading/thread_restrictions.h"
15 #include "build/build_config.h"
16 #include "chrome/browser/browser_process.h"
17 #include "chrome/browser/extensions/extension_apitest.h"
18 #include "chrome/browser/media_galleries/media_file_system_registry.h"
19 #include "chrome/browser/media_galleries/media_galleries_preferences.h"
20 #include "chrome/browser/media_galleries/media_galleries_test_util.h"
21 #include "chrome/common/chrome_paths.h"
22 #include "content/public/browser/render_frame_host.h"
23 #include "content/public/browser/render_view_host.h"
24 #include "content/public/test/browser_test.h"
25 #include "extensions/browser/process_manager.h"
26 #include "extensions/common/extension.h"
27 #include "extensions/common/switches.h"
28 #include "extensions/test/extension_test_message_listener.h"
29 
30 namespace {
31 
32 // Id of test extension from
33 // chrome/test/data/extensions/api_test/|kTestExtensionPath|
34 const char kTestExtensionId[] = "gceegfkgibmgpfopknlcgleimclbknie";
35 const char kTestExtensionPath[] = "media_galleries/gallerywatch";
36 
37 // JS commands.
38 const char kGetMediaFileSystemsCmd[] = "getMediaFileSystems()";
39 const char kSetupWatchOnValidGalleriesCmd[] = "setupWatchOnValidGalleries()";
40 const char kSetupWatchOnUnlistenedValidGalleriesCmd[] =
41     "setupWatchOnUnlistenedValidGalleries()";
42 const char kAddGalleryChangedListenerCmd[] = "addGalleryChangedListener()";
43 const char kAddCheckingGalleryChangedListenerCmd[] =
44     "addCheckingGalleryChangedListener()";
45 const char kRemoveGalleryChangedListenerCmd[] =
46     "removeGalleryChangedListener()";
47 const char kRemoveGalleryWatchCmd[] = "removeGalleryWatch()";
48 const char kSetupWatchOnInvalidGalleryCmd[] = "setupWatchOnInvalidGallery()";
49 
50 // And JS reply messages.
51 const char kAddGalleryWatchOK[] = "add_gallery_watch_ok";
52 const char kGetMediaFileSystemsCallbackOK[] =
53     "get_media_file_systems_callback_ok";
54 const char kGetMediaFileSystemsOK[] = "get_media_file_systems_ok";
55 const char kAddGalleryChangedListenerOK[] = "add_gallery_changed_listener_ok";
56 const char kRemoveGalleryChangedListenerOK[] =
57     "remove_gallery_changed_listener_ok";
58 const char kRemoveGalleryWatchOK[] = "remove_gallery_watch_ok";
59 const char kOnGalleryChangedCheckingOK[] = "on_gallery_changed_checking_ok";
60 
61 // Test reply messages.
62 const char kAddGalleryWatchRequestFailed[] = "add_watch_request_failed";
63 const char kAddGalleryWatchRequestRuntimeError[] =
64     "add_watch_request_runtime_error";
65 const char kAddGalleryWatchRequestSucceeded[] = "add_watch_request_succeeded";
66 const char kGalleryChangedEventReceived[] = "gallery_changed_event_received";
67 
68 }  // namespace
69 
70 ///////////////////////////////////////////////////////////////////////////////
71 //                 MediaGalleriesGalleryWatchApiTest                         //
72 ///////////////////////////////////////////////////////////////////////////////
73 
74 class MediaGalleriesGalleryWatchApiTest : public extensions::ExtensionApiTest {
75  public:
MediaGalleriesGalleryWatchApiTest()76   MediaGalleriesGalleryWatchApiTest()
77       : extension_(nullptr), background_host_(nullptr) {}
~MediaGalleriesGalleryWatchApiTest()78   ~MediaGalleriesGalleryWatchApiTest() override {}
79 
80  protected:
81   // ExtensionApiTest overrides.
SetUpCommandLine(base::CommandLine * command_line)82   void SetUpCommandLine(base::CommandLine* command_line) override {
83     extensions::ExtensionApiTest::SetUpCommandLine(command_line);
84     command_line->AppendSwitchASCII(
85         extensions::switches::kAllowlistedExtensionID, kTestExtensionId);
86   }
SetUpOnMainThread()87   void SetUpOnMainThread() override {
88     extensions::ExtensionApiTest::SetUpOnMainThread();
89     ensure_media_directories_exists_.reset(new EnsureMediaDirectoriesExists);
90     extension_ = LoadExtension(test_data_dir_.AppendASCII(kTestExtensionPath));
91     GetBackgroundHostForTestExtension();
92     CreateTestGallery();
93     FetchMediaGalleriesList();
94   }
TearDownOnMainThread()95   void TearDownOnMainThread() override {
96     extension_ = nullptr;
97     background_host_ = nullptr;
98     ensure_media_directories_exists_.reset();
99     extensions::ExtensionApiTest::TearDownOnMainThread();
100   }
101 
GalleryWatchesSupported()102   bool GalleryWatchesSupported() {
103     return base::FilePathWatcher::RecursiveWatchAvailable();
104   }
105 
ExecuteCmdAndCheckReply(const std::string & js_command,const std::string & ok_message)106   void ExecuteCmdAndCheckReply(const std::string& js_command,
107                                const std::string& ok_message) {
108     ExtensionTestMessageListener listener(ok_message, false);
109     background_host_->GetMainFrame()->ExecuteJavaScriptForTests(
110         base::ASCIIToUTF16(js_command), base::NullCallback());
111     EXPECT_TRUE(listener.WaitUntilSatisfied());
112   }
113 
AddNewFileInTestGallery()114   bool AddNewFileInTestGallery() {
115     base::ScopedAllowBlockingForTesting allow_blocking;
116     base::FilePath gallery_file =
117         test_gallery_.GetPath().Append(FILE_PATH_LITERAL("test1.txt"));
118     return base::WriteFile(gallery_file, "new content");
119   }
120 
SetupGalleryWatches()121   void SetupGalleryWatches() {
122     std::string expected_result = GalleryWatchesSupported()
123                                       ? kAddGalleryWatchRequestSucceeded
124                                       : kAddGalleryWatchRequestFailed;
125 
126     ExtensionTestMessageListener add_gallery_watch_finished(
127         expected_result, false /* no reply */);
128     ExecuteCmdAndCheckReply(kSetupWatchOnValidGalleriesCmd, kAddGalleryWatchOK);
129     EXPECT_TRUE(add_gallery_watch_finished.WaitUntilSatisfied());
130   }
131 
132  private:
GetBackgroundHostForTestExtension()133   void GetBackgroundHostForTestExtension() {
134     ASSERT_TRUE(extension_);
135     background_host_ = extensions::ProcessManager::Get(browser()->profile())
136                            ->GetBackgroundHostForExtension(extension_->id())
137                            ->render_view_host();
138     ASSERT_TRUE(background_host_);
139   }
140 
CreateTestGallery()141   void CreateTestGallery() {
142     MediaGalleriesPreferences* preferences =
143         g_browser_process->media_file_system_registry()->GetPreferences(
144             browser()->profile());
145     base::RunLoop runloop;
146     preferences->EnsureInitialized(runloop.QuitClosure());
147     runloop.Run();
148 
149     ASSERT_TRUE(test_gallery_.CreateUniqueTempDir());
150     MediaGalleryPrefInfo gallery_info;
151     ASSERT_FALSE(preferences->LookUpGalleryByPath(test_gallery_.GetPath(),
152                                                   &gallery_info));
153     MediaGalleryPrefId id = preferences->AddGallery(
154         gallery_info.device_id, gallery_info.path,
155         MediaGalleryPrefInfo::kAutoDetected, gallery_info.volume_label,
156         gallery_info.vendor_name, gallery_info.model_name,
157         gallery_info.total_size_in_bytes, gallery_info.last_attach_time, 0, 0,
158         0);
159 
160     preferences->SetGalleryPermissionForExtension(*extension_, id, true);
161   }
162 
FetchMediaGalleriesList()163   void FetchMediaGalleriesList() {
164     ExtensionTestMessageListener get_media_systems_finished(
165         kGetMediaFileSystemsCallbackOK, false /* no reply */);
166     ExecuteCmdAndCheckReply(kGetMediaFileSystemsCmd, kGetMediaFileSystemsOK);
167     EXPECT_TRUE(get_media_systems_finished.WaitUntilSatisfied());
168   }
169 
170   std::unique_ptr<EnsureMediaDirectoriesExists>
171       ensure_media_directories_exists_;
172 
173   base::ScopedTempDir test_gallery_;
174 
175   const extensions::Extension* extension_;
176 
177   content::RenderViewHost* background_host_;
178 
179   DISALLOW_COPY_AND_ASSIGN(MediaGalleriesGalleryWatchApiTest);
180 };
181 
IN_PROC_BROWSER_TEST_F(MediaGalleriesGalleryWatchApiTest,BasicGalleryWatch)182 IN_PROC_BROWSER_TEST_F(MediaGalleriesGalleryWatchApiTest, BasicGalleryWatch) {
183   // Add gallery watch listener.
184   ExecuteCmdAndCheckReply(kAddGalleryChangedListenerCmd,
185                           kAddGalleryChangedListenerOK);
186 
187   SetupGalleryWatches();
188 
189   // Modify gallery contents.
190   ExtensionTestMessageListener gallery_change_event_received(
191       kGalleryChangedEventReceived, false /* no reply */);
192 
193   ASSERT_TRUE(AddNewFileInTestGallery());
194   if (GalleryWatchesSupported())
195     EXPECT_TRUE(gallery_change_event_received.WaitUntilSatisfied());
196 
197   // Remove gallery watch listener.
198   ExecuteCmdAndCheckReply(kRemoveGalleryChangedListenerCmd,
199                           kRemoveGalleryChangedListenerOK);
200 
201   // Remove gallery watch request.
202   if (GalleryWatchesSupported())
203     ExecuteCmdAndCheckReply(kRemoveGalleryWatchCmd, kRemoveGalleryWatchOK);
204 }
205 
IN_PROC_BROWSER_TEST_F(MediaGalleriesGalleryWatchApiTest,CorrectResponseOnModifyingWatchedGallery)206 IN_PROC_BROWSER_TEST_F(MediaGalleriesGalleryWatchApiTest,
207                        CorrectResponseOnModifyingWatchedGallery) {
208   if (!GalleryWatchesSupported())
209     return;
210 
211   // Add gallery watch listener.
212   ExecuteCmdAndCheckReply(kAddCheckingGalleryChangedListenerCmd,
213                           kAddGalleryChangedListenerOK);
214   SetupGalleryWatches();
215 
216   // Modify gallery contents; expect correct details.
217   ExtensionTestMessageListener got_correct_details(kOnGalleryChangedCheckingOK,
218                                                    false);
219   ASSERT_TRUE(AddNewFileInTestGallery());
220   EXPECT_TRUE(got_correct_details.WaitUntilSatisfied());
221 }
222 
IN_PROC_BROWSER_TEST_F(MediaGalleriesGalleryWatchApiTest,RemoveListenerAndModifyGallery)223 IN_PROC_BROWSER_TEST_F(MediaGalleriesGalleryWatchApiTest,
224                        RemoveListenerAndModifyGallery) {
225   if (!GalleryWatchesSupported())
226     return;
227 
228   // Add a gallery watch listener.
229   ExecuteCmdAndCheckReply(kAddGalleryChangedListenerCmd,
230                           kAddGalleryChangedListenerOK);
231   SetupGalleryWatches();
232 
233   // Modify gallery contents.
234   ExtensionTestMessageListener gallery_change_event_received(
235       kGalleryChangedEventReceived, false /* no reply */);
236   ASSERT_TRUE(AddNewFileInTestGallery());
237   EXPECT_TRUE(gallery_change_event_received.WaitUntilSatisfied());
238 
239   // Remove gallery watch listener.
240   ExecuteCmdAndCheckReply(kRemoveGalleryChangedListenerCmd,
241                           kRemoveGalleryChangedListenerOK);
242 
243   // No listener, modify gallery contents.
244   ASSERT_TRUE(AddNewFileInTestGallery());
245 
246   // Remove gallery watch.
247   ExecuteCmdAndCheckReply(kRemoveGalleryWatchCmd, kRemoveGalleryWatchOK);
248 }
249 
IN_PROC_BROWSER_TEST_F(MediaGalleriesGalleryWatchApiTest,SetupGalleryWatchWithoutListeners)250 IN_PROC_BROWSER_TEST_F(MediaGalleriesGalleryWatchApiTest,
251                        SetupGalleryWatchWithoutListeners) {
252   if (!GalleryWatchesSupported())
253     return;
254 
255   ExecuteCmdAndCheckReply(kSetupWatchOnUnlistenedValidGalleriesCmd,
256                           kAddGalleryWatchRequestRuntimeError);
257 }
258 
IN_PROC_BROWSER_TEST_F(MediaGalleriesGalleryWatchApiTest,SetupGalleryChangedListenerWithoutWatchers)259 IN_PROC_BROWSER_TEST_F(MediaGalleriesGalleryWatchApiTest,
260                        SetupGalleryChangedListenerWithoutWatchers) {
261   // Add gallery watch listener.
262   ExecuteCmdAndCheckReply(kAddGalleryChangedListenerCmd,
263                           kAddGalleryChangedListenerOK);
264 
265   // Modify gallery contents. Listener should not get called because add watch
266   // request was not called.
267   ExtensionTestMessageListener gallery_change_event_received(
268       kGalleryChangedEventReceived, false /* no reply */);
269   ASSERT_TRUE(AddNewFileInTestGallery());
270 
271   // Remove gallery watch listener.
272   ExecuteCmdAndCheckReply(kRemoveGalleryChangedListenerCmd,
273                           kRemoveGalleryChangedListenerOK);
274 }
275 
IN_PROC_BROWSER_TEST_F(MediaGalleriesGalleryWatchApiTest,SetupWatchOnInvalidGallery)276 IN_PROC_BROWSER_TEST_F(MediaGalleriesGalleryWatchApiTest,
277                        SetupWatchOnInvalidGallery) {
278   // Add gallery watch listener.
279   ExecuteCmdAndCheckReply(kAddGalleryChangedListenerCmd,
280                           kAddGalleryChangedListenerOK);
281   // Set up a invalid gallery watch.
282   ExecuteCmdAndCheckReply(kSetupWatchOnInvalidGalleryCmd,
283                           kAddGalleryWatchRequestFailed);
284 }
285