OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // Browser test for basic Chrome OS file manager functionality: | 5 // Browser test for basic Chrome OS file manager functionality: |
6 // - The file list is updated when a file is added externally to the Downloads | 6 // - The file list is updated when a file is added externally to the Downloads |
7 // folder. | 7 // folder. |
8 // - Selecting a file and copy-pasting it with the keyboard copies the file. | 8 // - Selecting a file and copy-pasting it with the keyboard copies the file. |
9 // - Selecting a file and pressing delete deletes it. | 9 // - Selecting a file and pressing delete deletes it. |
10 | 10 |
(...skipping 21 matching lines...) Expand all Loading... |
32 #include "content/public/browser/browser_context.h" | 32 #include "content/public/browser/browser_context.h" |
33 #include "content/public/browser/render_view_host.h" | 33 #include "content/public/browser/render_view_host.h" |
34 #include "net/base/escape.h" | 34 #include "net/base/escape.h" |
35 #include "webkit/fileapi/external_mount_points.h" | 35 #include "webkit/fileapi/external_mount_points.h" |
36 | 36 |
37 namespace { | 37 namespace { |
38 | 38 |
39 const char kFileManagerExtensionId[] = "hhaomjibdihmijegdhdafkllkbggdgoj"; | 39 const char kFileManagerExtensionId[] = "hhaomjibdihmijegdhdafkllkbggdgoj"; |
40 | 40 |
41 const char kKeyboardTestFileName[] = "world.mpeg"; | 41 const char kKeyboardTestFileName[] = "world.mpeg"; |
42 const int kKeyboardTestFileSize = 1000; | 42 const int64 kKeyboardTestFileSize = 1000; |
43 const char kKeyboardTestFileCopyName[] = "world (1).mpeg"; | 43 const char kKeyboardTestFileCopyName[] = "world (1).mpeg"; |
44 | 44 |
45 // The base test class. Used by FileManagerBrowserLocalTest and | 45 // The base test class. Used by FileManagerBrowserLocalTest and |
46 // FileManagerBrowserDriveTest. | 46 // FileManagerBrowserDriveTest. |
47 // TODO(satorux): Add the latter: crbug.com/224534. | 47 // TODO(satorux): Add the latter: crbug.com/224534. |
48 class FileManagerBrowserTestBase : public ExtensionApiTest { | 48 class FileManagerBrowserTestBase : public ExtensionApiTest { |
49 protected: | 49 protected: |
50 // Loads the file manager extension, navigating it to |directory_path| for | 50 // Loads the file manager extension, navigating it to |directory_path| for |
51 // testing, and waits for it to finish initializing. This is invoked at the | 51 // testing, and waits for it to finish initializing. This is invoked at the |
52 // start of each test (it crashes if run in SetUp). | 52 // start of each test (it crashes if run in SetUp). |
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
191 // watcher.RunMessageLoopUntilConditionSatisfied(); | 191 // watcher.RunMessageLoopUntilConditionSatisfied(); |
192 class TestFilePathWatcher { | 192 class TestFilePathWatcher { |
193 public: | 193 public: |
194 typedef base::Callback<bool(const base::FilePath& file_path)> | 194 typedef base::Callback<bool(const base::FilePath& file_path)> |
195 ConditionCallback; | 195 ConditionCallback; |
196 | 196 |
197 // Stores the supplied |path| and |condition| for later use (no side effects). | 197 // Stores the supplied |path| and |condition| for later use (no side effects). |
198 TestFilePathWatcher(const base::FilePath& path, | 198 TestFilePathWatcher(const base::FilePath& path, |
199 const ConditionCallback& condition); | 199 const ConditionCallback& condition); |
200 | 200 |
201 // Starts the FilePathWatcher and returns once it's watching for changes. | |
202 void StartAndWaitUntilReady(); | |
203 | |
204 // Waits (running a message pump) until the callback returns true or | 201 // Waits (running a message pump) until the callback returns true or |
205 // FilePathWatcher reports an error. Return true on success. | 202 // FilePathWatcher reports an error. Return true on success. |
206 bool RunMessageLoopUntilConditionSatisfied(); | 203 bool RunMessageLoopUntilConditionSatisfied(); |
207 | 204 |
208 private: | 205 private: |
209 // FILE thread callback to start the FilePathWatcher. | 206 // Starts the FilePathWatcher to watch the target file. Also check if the |
| 207 // condition is already met. |
210 void StartWatching(); | 208 void StartWatching(); |
211 | 209 |
212 // FilePathWatcher callback (on the FILE thread). Posts Done() to the UI | 210 // FilePathWatcher callback (on the FILE thread). Posts Done() to the UI |
213 // thread when the condition is satisfied or there is an error. | 211 // thread when the condition is satisfied or there is an error. |
214 void FilePathWatcherCallback(const base::FilePath& path, bool error); | 212 void FilePathWatcherCallback(const base::FilePath& path, bool error); |
215 | 213 |
216 // Sets done_ and stops the message pump if running. | |
217 void Done(); | |
218 | |
219 const base::FilePath path_; | 214 const base::FilePath path_; |
220 ConditionCallback condition_; | 215 ConditionCallback condition_; |
221 scoped_ptr<base::FilePathWatcher> watcher_; | 216 scoped_ptr<base::FilePathWatcher> watcher_; |
| 217 base::RunLoop run_loop_; |
222 base::Closure quit_closure_; | 218 base::Closure quit_closure_; |
223 bool done_; | 219 bool failed_; |
224 bool error_; | |
225 }; | 220 }; |
226 | 221 |
227 TestFilePathWatcher::TestFilePathWatcher(const base::FilePath& path, | 222 TestFilePathWatcher::TestFilePathWatcher(const base::FilePath& path, |
228 const ConditionCallback& condition) | 223 const ConditionCallback& condition) |
229 : path_(path), | 224 : path_(path), |
230 condition_(condition), | 225 condition_(condition), |
231 done_(false), | 226 quit_closure_(run_loop_.QuitClosure()), |
232 error_(false) { | 227 failed_(false) { |
233 } | |
234 | |
235 void TestFilePathWatcher::StartAndWaitUntilReady() { | |
236 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
237 base::RunLoop run_loop; | |
238 content::BrowserThread::PostTaskAndReply( | |
239 content::BrowserThread::FILE, | |
240 FROM_HERE, | |
241 base::Bind(&TestFilePathWatcher::StartWatching, | |
242 base::Unretained(this)), | |
243 run_loop.QuitClosure()); | |
244 run_loop.Run(); | |
245 } | 228 } |
246 | 229 |
247 void TestFilePathWatcher::StartWatching() { | 230 void TestFilePathWatcher::StartWatching() { |
248 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); | 231 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); |
| 232 |
249 watcher_.reset(new base::FilePathWatcher); | 233 watcher_.reset(new base::FilePathWatcher); |
250 bool ok = watcher_->Watch( | 234 bool ok = watcher_->Watch( |
251 path_, false /*recursive*/, | 235 path_, false /*recursive*/, |
252 base::Bind(&TestFilePathWatcher::FilePathWatcherCallback, | 236 base::Bind(&TestFilePathWatcher::FilePathWatcherCallback, |
253 base::Unretained(this))); | 237 base::Unretained(this))); |
254 ASSERT_TRUE(ok); | 238 DCHECK(ok); |
| 239 |
| 240 // If the condition was already met before FilePathWatcher was launched, |
| 241 // FilePathWatcher won't be able to detect a change, so check the condition |
| 242 // here. |
| 243 if (condition_.Run(path_)) { |
| 244 watcher_.reset(); |
| 245 content::BrowserThread::PostTask(content::BrowserThread::UI, |
| 246 FROM_HERE, |
| 247 quit_closure_); |
| 248 return; |
| 249 } |
255 } | 250 } |
256 | 251 |
257 void TestFilePathWatcher::FilePathWatcherCallback(const base::FilePath& path, | 252 void TestFilePathWatcher::FilePathWatcherCallback(const base::FilePath& path, |
258 bool error) { | 253 bool failed) { |
259 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); | 254 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); |
260 ASSERT_EQ(path_, path); | 255 DCHECK_EQ(path_.value(), path.value()); |
261 if (error || condition_.Run(path)) { | 256 |
262 error_ = error; | 257 if (failed || condition_.Run(path)) { |
| 258 failed_ = failed; |
263 watcher_.reset(); | 259 watcher_.reset(); |
264 content::BrowserThread::PostTask( | 260 content::BrowserThread::PostTask(content::BrowserThread::UI, |
265 content::BrowserThread::UI, | 261 FROM_HERE, |
266 FROM_HERE, | 262 quit_closure_); |
267 base::Bind(&TestFilePathWatcher::Done, base::Unretained(this))); | |
268 } | 263 } |
269 } | 264 } |
270 | 265 |
271 void TestFilePathWatcher::Done() { | 266 bool TestFilePathWatcher::RunMessageLoopUntilConditionSatisfied() { |
272 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 267 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
273 done_ = true; | 268 |
274 if (!quit_closure_.is_null()) | 269 content::BrowserThread::PostTask( |
275 quit_closure_.Run(); | 270 content::BrowserThread::FILE, |
| 271 FROM_HERE, |
| 272 base::Bind(&TestFilePathWatcher::StartWatching, |
| 273 base::Unretained(this))); |
| 274 |
| 275 // Wait until the condition is met. |
| 276 run_loop_.Run(); |
| 277 return !failed_; |
276 } | 278 } |
277 | 279 |
278 bool TestFilePathWatcher::RunMessageLoopUntilConditionSatisfied() { | 280 // Returns true if a file with the given size is present at |path|. |
279 if (done_) | 281 bool FilePresentWithSize(const int64 file_size, |
280 return !error_; | 282 const base::FilePath& path) { |
281 base::RunLoop message_loop_runner; | |
282 quit_closure_ = message_loop_runner.QuitClosure(); | |
283 message_loop_runner.Run(); | |
284 quit_closure_ = base::Closure(); | |
285 return !error_; | |
286 } | |
287 | |
288 bool CopiedFilePresent(const base::FilePath& path) { | |
289 int64 copy_size = 0; | 283 int64 copy_size = 0; |
290 // If the file doesn't exist yet this will fail and we'll keep waiting. | 284 // If the file doesn't exist yet this will fail and we'll keep waiting. |
291 if (!file_util::GetFileSize(path, ©_size)) | 285 if (!file_util::GetFileSize(path, ©_size)) |
292 return false; | 286 return false; |
293 return (copy_size == kKeyboardTestFileSize); | 287 return (copy_size == file_size); |
294 } | 288 } |
295 | 289 |
296 bool DeletedFileGone(const base::FilePath& path) { | 290 // Returns true if a file is not present at |path|. |
| 291 bool FileNotPresent(const base::FilePath& path) { |
297 return !file_util::PathExists(path); | 292 return !file_util::PathExists(path); |
298 }; | 293 }; |
299 | 294 |
300 IN_PROC_BROWSER_TEST_P(FileManagerBrowserLocalTest, TestFileDisplay) { | 295 IN_PROC_BROWSER_TEST_P(FileManagerBrowserLocalTest, TestFileDisplay) { |
301 AddMountPointToFakeDownloads(); | 296 AddMountPointToFakeDownloads(); |
302 StartFileManager("/Downloads"); | 297 StartFileManager("/Downloads"); |
303 | 298 |
304 ResultCatcher catcher; | 299 ResultCatcher catcher; |
305 | 300 |
306 StartTest("file display"); | 301 StartTest("file display"); |
307 | 302 |
308 ExtensionTestMessageListener listener("initial check done", true); | 303 ExtensionTestMessageListener listener("initial check done", true); |
309 ASSERT_TRUE(listener.WaitUntilSatisfied()); | 304 ASSERT_TRUE(listener.WaitUntilSatisfied()); |
310 CreateTestFile("newly added file.mp3", 2000, "4 Sep 1998 00:00:00"); | 305 CreateTestFile("newly added file.mp3", 2000, "4 Sep 1998 00:00:00"); |
311 listener.Reply("file added"); | 306 listener.Reply("file added"); |
312 | 307 |
313 ASSERT_TRUE(catcher.GetNextResult()) << catcher.message(); | 308 ASSERT_TRUE(catcher.GetNextResult()) << catcher.message(); |
314 } | 309 } |
315 | 310 |
316 IN_PROC_BROWSER_TEST_P(FileManagerBrowserLocalTest, TestKeyboardCopy) { | 311 IN_PROC_BROWSER_TEST_P(FileManagerBrowserLocalTest, TestKeyboardCopy) { |
317 AddMountPointToFakeDownloads(); | 312 AddMountPointToFakeDownloads(); |
318 StartFileManager("/Downloads"); | 313 StartFileManager("/Downloads"); |
319 | 314 |
320 base::FilePath copy_path = | 315 base::FilePath copy_path = |
321 downloads_path_.AppendASCII(kKeyboardTestFileCopyName); | 316 downloads_path_.AppendASCII(kKeyboardTestFileCopyName); |
322 ASSERT_FALSE(file_util::PathExists(copy_path)); | 317 ASSERT_FALSE(file_util::PathExists(copy_path)); |
323 TestFilePathWatcher watcher(copy_path, base::Bind(CopiedFilePresent)); | |
324 watcher.StartAndWaitUntilReady(); | |
325 | 318 |
326 ResultCatcher catcher; | 319 ResultCatcher catcher; |
327 StartTest("keyboard copy"); | 320 StartTest("keyboard copy"); |
| 321 |
328 ASSERT_TRUE(catcher.GetNextResult()) << catcher.message(); | 322 ASSERT_TRUE(catcher.GetNextResult()) << catcher.message(); |
329 | 323 |
| 324 TestFilePathWatcher watcher( |
| 325 copy_path, |
| 326 base::Bind(FilePresentWithSize, kKeyboardTestFileSize)); |
330 ASSERT_TRUE(watcher.RunMessageLoopUntilConditionSatisfied()); | 327 ASSERT_TRUE(watcher.RunMessageLoopUntilConditionSatisfied()); |
331 | 328 |
332 // Check that it was a copy, not a move. | 329 // Check that it was a copy, not a move. |
333 base::FilePath source_path = | 330 base::FilePath source_path = |
334 downloads_path_.AppendASCII(kKeyboardTestFileName); | 331 downloads_path_.AppendASCII(kKeyboardTestFileName); |
335 ASSERT_TRUE(file_util::PathExists(source_path)); | 332 ASSERT_TRUE(file_util::PathExists(source_path)); |
336 } | 333 } |
337 | 334 |
338 IN_PROC_BROWSER_TEST_P(FileManagerBrowserLocalTest, TestKeyboardDelete) { | 335 IN_PROC_BROWSER_TEST_P(FileManagerBrowserLocalTest, TestKeyboardDelete) { |
339 AddMountPointToFakeDownloads(); | 336 AddMountPointToFakeDownloads(); |
340 StartFileManager("/Downloads"); | 337 StartFileManager("/Downloads"); |
341 | 338 |
342 base::FilePath delete_path = | 339 base::FilePath delete_path = |
343 downloads_path_.AppendASCII(kKeyboardTestFileName); | 340 downloads_path_.AppendASCII(kKeyboardTestFileName); |
344 ASSERT_TRUE(file_util::PathExists(delete_path)); | 341 ASSERT_TRUE(file_util::PathExists(delete_path)); |
345 TestFilePathWatcher watcher(delete_path, base::Bind(DeletedFileGone)); | |
346 watcher.StartAndWaitUntilReady(); | |
347 | 342 |
348 ResultCatcher catcher; | 343 ResultCatcher catcher; |
349 StartTest("keyboard delete"); | 344 StartTest("keyboard delete"); |
350 ASSERT_TRUE(catcher.GetNextResult()) << catcher.message(); | 345 ASSERT_TRUE(catcher.GetNextResult()) << catcher.message(); |
351 | 346 |
| 347 TestFilePathWatcher watcher(delete_path, |
| 348 base::Bind(FileNotPresent)); |
352 ASSERT_TRUE(watcher.RunMessageLoopUntilConditionSatisfied()); | 349 ASSERT_TRUE(watcher.RunMessageLoopUntilConditionSatisfied()); |
353 } | 350 } |
354 | 351 |
355 } // namespace | 352 } // namespace |
OLD | NEW |