Check USB device path access when prompting users to select a device.
[chromium-blink-merge.git] / chrome / browser / sync_file_system / local / syncable_file_operation_runner_unittest.cc
blob21209e82d250603eb2fbdc664cbfdada10989b6b
1 // Copyright 2013 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 <string>
7 #include "base/basictypes.h"
8 #include "base/files/file.h"
9 #include "base/files/file_util.h"
10 #include "base/location.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/run_loop.h"
14 #include "base/thread_task_runner_handle.h"
15 #include "chrome/browser/sync_file_system/local/canned_syncable_file_system.h"
16 #include "chrome/browser/sync_file_system/local/local_file_change_tracker.h"
17 #include "chrome/browser/sync_file_system/local/local_file_sync_context.h"
18 #include "chrome/browser/sync_file_system/local/local_file_sync_status.h"
19 #include "chrome/browser/sync_file_system/local/sync_file_system_backend.h"
20 #include "chrome/browser/sync_file_system/local/syncable_file_operation_runner.h"
21 #include "chrome/browser/sync_file_system/local/syncable_file_system_operation.h"
22 #include "chrome/browser/sync_file_system/syncable_file_system_util.h"
23 #include "content/public/test/mock_blob_url_request_context.h"
24 #include "content/public/test/test_browser_thread_bundle.h"
25 #include "storage/browser/fileapi/file_system_context.h"
26 #include "storage/browser/fileapi/file_system_operation_runner.h"
27 #include "testing/gtest/include/gtest/gtest.h"
28 #include "third_party/leveldatabase/src/helpers/memenv/memenv.h"
29 #include "third_party/leveldatabase/src/include/leveldb/env.h"
31 using storage::FileSystemOperation;
32 using storage::FileSystemURL;
33 using content::MockBlobURLRequestContext;
34 using content::ScopedTextBlob;
35 using base::File;
37 namespace sync_file_system {
39 namespace {
40 const std::string kParent = "foo";
41 const std::string kFile = "foo/file";
42 const std::string kDir = "foo/dir";
43 const std::string kChild = "foo/dir/bar";
44 const std::string kOther = "bar";
45 } // namespace
47 class SyncableFileOperationRunnerTest : public testing::Test {
48 protected:
49 typedef FileSystemOperation::StatusCallback StatusCallback;
51 // Use the current thread as IO thread so that we can directly call
52 // operations in the tests.
53 SyncableFileOperationRunnerTest()
54 : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP),
55 in_memory_env_(leveldb::NewMemEnv(leveldb::Env::Default())),
56 file_system_(GURL("http://example.com"),
57 in_memory_env_.get(),
58 base::ThreadTaskRunnerHandle::Get().get(),
59 base::ThreadTaskRunnerHandle::Get().get()),
60 callback_count_(0),
61 write_status_(File::FILE_ERROR_FAILED),
62 write_bytes_(0),
63 write_complete_(false),
64 url_request_context_(file_system_.file_system_context()),
65 weak_factory_(this) {}
67 void SetUp() override {
68 ASSERT_TRUE(dir_.CreateUniqueTempDir());
70 file_system_.SetUp(CannedSyncableFileSystem::QUOTA_ENABLED);
71 sync_context_ = new LocalFileSyncContext(
72 dir_.path(),
73 in_memory_env_.get(),
74 base::ThreadTaskRunnerHandle::Get().get(),
75 base::ThreadTaskRunnerHandle::Get().get());
76 ASSERT_EQ(
77 SYNC_STATUS_OK,
78 file_system_.MaybeInitializeFileSystemContext(sync_context_.get()));
80 ASSERT_EQ(File::FILE_OK, file_system_.OpenFileSystem());
81 ASSERT_EQ(File::FILE_OK,
82 file_system_.CreateDirectory(URL(kParent)));
85 void TearDown() override {
86 if (sync_context_.get())
87 sync_context_->ShutdownOnUIThread();
88 sync_context_ = nullptr;
90 file_system_.TearDown();
91 RevokeSyncableFileSystem();
94 FileSystemURL URL(const std::string& path) {
95 return file_system_.URL(path);
98 LocalFileSyncStatus* sync_status() {
99 return file_system_.backend()->sync_context()->sync_status();
102 void ResetCallbackStatus() {
103 write_status_ = File::FILE_ERROR_FAILED;
104 write_bytes_ = 0;
105 write_complete_ = false;
106 callback_count_ = 0;
109 StatusCallback ExpectStatus(const tracked_objects::Location& location,
110 File::Error expect) {
111 return base::Bind(&SyncableFileOperationRunnerTest::DidFinish,
112 weak_factory_.GetWeakPtr(), location, expect);
115 FileSystemOperation::WriteCallback GetWriteCallback(
116 const tracked_objects::Location& location) {
117 return base::Bind(&SyncableFileOperationRunnerTest::DidWrite,
118 weak_factory_.GetWeakPtr(), location);
121 void DidWrite(const tracked_objects::Location& location,
122 File::Error status, int64 bytes, bool complete) {
123 SCOPED_TRACE(testing::Message() << location.ToString());
124 write_status_ = status;
125 write_bytes_ += bytes;
126 write_complete_ = complete;
127 ++callback_count_;
130 void DidFinish(const tracked_objects::Location& location,
131 File::Error expect, File::Error status) {
132 SCOPED_TRACE(testing::Message() << location.ToString());
133 EXPECT_EQ(expect, status);
134 ++callback_count_;
135 base::MessageLoop::current()->Quit();
138 bool CreateTempFile(base::FilePath* path) {
139 return base::CreateTemporaryFileInDir(dir_.path(), path);
142 content::TestBrowserThreadBundle thread_bundle_;
144 base::ScopedTempDir dir_;
145 scoped_ptr<leveldb::Env> in_memory_env_;
147 CannedSyncableFileSystem file_system_;
148 scoped_refptr<LocalFileSyncContext> sync_context_;
150 int callback_count_;
151 File::Error write_status_;
152 size_t write_bytes_;
153 bool write_complete_;
155 MockBlobURLRequestContext url_request_context_;
157 private:
158 base::WeakPtrFactory<SyncableFileOperationRunnerTest> weak_factory_;
160 DISALLOW_COPY_AND_ASSIGN(SyncableFileOperationRunnerTest);
163 TEST_F(SyncableFileOperationRunnerTest, SimpleQueue) {
164 sync_status()->StartSyncing(URL(kFile));
165 ASSERT_FALSE(sync_status()->IsWritable(URL(kFile)));
167 // The URL is in syncing so the write operations won't run.
168 ResetCallbackStatus();
169 file_system_.operation_runner()->CreateFile(
170 URL(kFile), false /* exclusive */,
171 ExpectStatus(FROM_HERE, File::FILE_OK));
172 file_system_.operation_runner()->Truncate(
173 URL(kFile), 1,
174 ExpectStatus(FROM_HERE, File::FILE_OK));
175 base::RunLoop().RunUntilIdle();
176 EXPECT_EQ(0, callback_count_);
178 // Read operations are not blocked (and are executed before queued ones).
179 file_system_.operation_runner()->FileExists(
180 URL(kFile), ExpectStatus(FROM_HERE, File::FILE_ERROR_NOT_FOUND));
181 base::RunLoop().RunUntilIdle();
182 EXPECT_EQ(1, callback_count_);
184 // End syncing (to enable write).
185 sync_status()->EndSyncing(URL(kFile));
186 ASSERT_TRUE(sync_status()->IsWritable(URL(kFile)));
188 ResetCallbackStatus();
189 base::RunLoop().RunUntilIdle();
190 EXPECT_EQ(2, callback_count_);
192 // Now the file must have been created and updated.
193 ResetCallbackStatus();
194 file_system_.operation_runner()->FileExists(
195 URL(kFile), ExpectStatus(FROM_HERE, File::FILE_OK));
196 base::RunLoop().RunUntilIdle();
197 EXPECT_EQ(1, callback_count_);
200 TEST_F(SyncableFileOperationRunnerTest, WriteToParentAndChild) {
201 // First create the kDir directory and kChild in the dir.
202 EXPECT_EQ(File::FILE_OK, file_system_.CreateDirectory(URL(kDir)));
203 EXPECT_EQ(File::FILE_OK, file_system_.CreateFile(URL(kChild)));
205 // Start syncing the kDir directory.
206 sync_status()->StartSyncing(URL(kDir));
207 ASSERT_FALSE(sync_status()->IsWritable(URL(kDir)));
209 // Writes to kParent and kChild should be all queued up.
210 ResetCallbackStatus();
211 file_system_.operation_runner()->Truncate(
212 URL(kChild), 1, ExpectStatus(FROM_HERE, File::FILE_OK));
213 file_system_.operation_runner()->Remove(
214 URL(kParent), true /* recursive */,
215 ExpectStatus(FROM_HERE, File::FILE_OK));
216 base::RunLoop().RunUntilIdle();
217 EXPECT_EQ(0, callback_count_);
219 // Read operations are not blocked (and are executed before queued ones).
220 file_system_.operation_runner()->DirectoryExists(
221 URL(kDir), ExpectStatus(FROM_HERE, File::FILE_OK));
222 base::RunLoop().Run();
223 EXPECT_EQ(1, callback_count_);
225 // Writes to unrelated files must succeed as well.
226 ResetCallbackStatus();
227 file_system_.operation_runner()->CreateDirectory(
228 URL(kOther), false /* exclusive */, false /* recursive */,
229 ExpectStatus(FROM_HERE, File::FILE_OK));
230 base::RunLoop().Run();
231 EXPECT_EQ(1, callback_count_);
233 // End syncing (to enable write).
234 sync_status()->EndSyncing(URL(kDir));
235 ASSERT_TRUE(sync_status()->IsWritable(URL(kDir)));
237 ResetCallbackStatus();
238 base::RunLoop().Run();
239 EXPECT_EQ(2, callback_count_);
242 TEST_F(SyncableFileOperationRunnerTest, CopyAndMove) {
243 // First create the kDir directory and kChild in the dir.
244 EXPECT_EQ(File::FILE_OK, file_system_.CreateDirectory(URL(kDir)));
245 EXPECT_EQ(File::FILE_OK, file_system_.CreateFile(URL(kChild)));
247 // Start syncing the kParent directory.
248 sync_status()->StartSyncing(URL(kParent));
250 // Copying kDir to other directory should succeed, while moving would fail
251 // (since the source directory is in syncing).
252 ResetCallbackStatus();
253 file_system_.operation_runner()->Copy(
254 URL(kDir),
255 URL("dest-copy"),
256 storage::FileSystemOperation::OPTION_NONE,
257 storage::FileSystemOperationRunner::CopyProgressCallback(),
258 ExpectStatus(FROM_HERE, File::FILE_OK));
259 file_system_.operation_runner()->Move(
260 URL(kDir),
261 URL("dest-move"),
262 storage::FileSystemOperation::OPTION_NONE,
263 ExpectStatus(FROM_HERE, File::FILE_OK));
264 base::RunLoop().Run();
265 EXPECT_EQ(1, callback_count_);
267 // Only "dest-copy1" should exist.
268 EXPECT_EQ(File::FILE_OK,
269 file_system_.DirectoryExists(URL("dest-copy")));
270 EXPECT_EQ(File::FILE_ERROR_NOT_FOUND,
271 file_system_.DirectoryExists(URL("dest-move")));
273 // Start syncing the "dest-copy2" directory.
274 sync_status()->StartSyncing(URL("dest-copy2"));
276 // Now the destination is also locked copying kDir should be queued.
277 ResetCallbackStatus();
278 file_system_.operation_runner()->Copy(
279 URL(kDir),
280 URL("dest-copy2"),
281 storage::FileSystemOperation::OPTION_NONE,
282 storage::FileSystemOperationRunner::CopyProgressCallback(),
283 ExpectStatus(FROM_HERE, File::FILE_OK));
284 base::RunLoop().RunUntilIdle();
285 EXPECT_EQ(0, callback_count_);
287 // Finish syncing the "dest-copy2" directory to unlock Copy.
288 sync_status()->EndSyncing(URL("dest-copy2"));
289 ResetCallbackStatus();
290 base::RunLoop().Run();
291 EXPECT_EQ(1, callback_count_);
293 // Now we should have "dest-copy2".
294 EXPECT_EQ(File::FILE_OK,
295 file_system_.DirectoryExists(URL("dest-copy2")));
297 // Finish syncing the kParent to unlock Move.
298 sync_status()->EndSyncing(URL(kParent));
299 ResetCallbackStatus();
300 base::RunLoop().Run();
301 EXPECT_EQ(1, callback_count_);
303 // Now we should have "dest-move".
304 EXPECT_EQ(File::FILE_OK,
305 file_system_.DirectoryExists(URL("dest-move")));
308 TEST_F(SyncableFileOperationRunnerTest, Write) {
309 EXPECT_EQ(File::FILE_OK, file_system_.CreateFile(URL(kFile)));
310 const std::string kData("Lorem ipsum.");
311 ScopedTextBlob blob(url_request_context_, "blob:foo", kData);
313 sync_status()->StartSyncing(URL(kFile));
315 ResetCallbackStatus();
316 file_system_.operation_runner()->Write(
317 &url_request_context_,
318 URL(kFile), blob.GetBlobDataHandle(), 0, GetWriteCallback(FROM_HERE));
319 base::RunLoop().RunUntilIdle();
320 EXPECT_EQ(0, callback_count_);
322 sync_status()->EndSyncing(URL(kFile));
323 ResetCallbackStatus();
325 while (!write_complete_)
326 base::MessageLoop::current()->RunUntilIdle();
328 EXPECT_EQ(File::FILE_OK, write_status_);
329 EXPECT_EQ(kData.size(), write_bytes_);
330 EXPECT_TRUE(write_complete_);
333 TEST_F(SyncableFileOperationRunnerTest, QueueAndCancel) {
334 sync_status()->StartSyncing(URL(kFile));
335 ASSERT_FALSE(sync_status()->IsWritable(URL(kFile)));
337 ResetCallbackStatus();
338 file_system_.operation_runner()->CreateFile(
339 URL(kFile), false /* exclusive */,
340 ExpectStatus(FROM_HERE, File::FILE_ERROR_ABORT));
341 file_system_.operation_runner()->Truncate(
342 URL(kFile), 1,
343 ExpectStatus(FROM_HERE, File::FILE_ERROR_ABORT));
344 base::MessageLoop::current()->RunUntilIdle();
345 EXPECT_EQ(0, callback_count_);
347 ResetCallbackStatus();
349 // This shouldn't crash nor leak memory.
350 sync_context_->ShutdownOnUIThread();
351 sync_context_ = nullptr;
352 base::MessageLoop::current()->RunUntilIdle();
353 EXPECT_EQ(2, callback_count_);
356 // Test if CopyInForeignFile runs cooperatively with other Sync operations.
357 TEST_F(SyncableFileOperationRunnerTest, CopyInForeignFile) {
358 const std::string kTestData("test data");
360 base::FilePath temp_path;
361 ASSERT_TRUE(CreateTempFile(&temp_path));
362 ASSERT_EQ(static_cast<int>(kTestData.size()),
363 base::WriteFile(
364 temp_path, kTestData.data(), kTestData.size()));
366 sync_status()->StartSyncing(URL(kFile));
367 ASSERT_FALSE(sync_status()->IsWritable(URL(kFile)));
369 // The URL is in syncing so CopyIn (which is a write operation) won't run.
370 ResetCallbackStatus();
371 file_system_.operation_runner()->CopyInForeignFile(
372 temp_path, URL(kFile),
373 ExpectStatus(FROM_HERE, File::FILE_OK));
374 base::MessageLoop::current()->RunUntilIdle();
375 EXPECT_EQ(0, callback_count_);
377 // End syncing (to enable write).
378 sync_status()->EndSyncing(URL(kFile));
379 ASSERT_TRUE(sync_status()->IsWritable(URL(kFile)));
381 ResetCallbackStatus();
382 base::MessageLoop::current()->RunUntilIdle();
383 EXPECT_EQ(1, callback_count_);
385 // Now the file must have been created and have the same content as temp_path.
386 ResetCallbackStatus();
387 file_system_.DoVerifyFile(
388 URL(kFile), kTestData,
389 ExpectStatus(FROM_HERE, File::FILE_OK));
390 base::MessageLoop::current()->RunUntilIdle();
391 EXPECT_EQ(1, callback_count_);
394 TEST_F(SyncableFileOperationRunnerTest, Cancel) {
395 // Prepare a file.
396 file_system_.operation_runner()->CreateFile(
397 URL(kFile), false /* exclusive */,
398 ExpectStatus(FROM_HERE, File::FILE_OK));
399 base::MessageLoop::current()->RunUntilIdle();
400 EXPECT_EQ(1, callback_count_);
402 // Run Truncate and immediately cancel. This shouldn't crash.
403 ResetCallbackStatus();
404 storage::FileSystemOperationRunner::OperationID id =
405 file_system_.operation_runner()->Truncate(
406 URL(kFile), 10, ExpectStatus(FROM_HERE, File::FILE_OK));
407 file_system_.operation_runner()->Cancel(
408 id, ExpectStatus(FROM_HERE, File::FILE_ERROR_INVALID_OPERATION));
409 base::RunLoop().Run();
410 EXPECT_EQ(2, callback_count_);
413 } // namespace sync_file_system