OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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 #include "webkit/fileapi/syncable/local_file_sync_context.h" | 5 #include "webkit/fileapi/syncable/local_file_sync_context.h" |
6 | 6 |
7 #include <vector> | 7 #include <vector> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/file_path.h" | 10 #include "base/file_path.h" |
11 #include "base/message_loop.h" | 11 #include "base/message_loop.h" |
| 12 #include "base/platform_file.h" |
12 #include "base/single_thread_task_runner.h" | 13 #include "base/single_thread_task_runner.h" |
13 #include "base/threading/thread.h" | 14 #include "base/threading/thread.h" |
14 #include "testing/gtest/include/gtest/gtest.h" | 15 #include "testing/gtest/include/gtest/gtest.h" |
15 #include "webkit/fileapi/file_system_context.h" | 16 #include "webkit/fileapi/file_system_context.h" |
| 17 #include "webkit/fileapi/file_system_operation.h" |
16 #include "webkit/fileapi/isolated_context.h" | 18 #include "webkit/fileapi/isolated_context.h" |
17 #include "webkit/fileapi/syncable/canned_syncable_file_system.h" | 19 #include "webkit/fileapi/syncable/canned_syncable_file_system.h" |
18 #include "webkit/fileapi/syncable/local_file_change_tracker.h" | 20 #include "webkit/fileapi/syncable/local_file_change_tracker.h" |
19 #include "webkit/fileapi/syncable/sync_status_code.h" | 21 #include "webkit/fileapi/syncable/sync_status_code.h" |
20 #include "webkit/fileapi/syncable/syncable_file_system_util.h" | 22 #include "webkit/fileapi/syncable/syncable_file_system_util.h" |
21 | 23 |
22 // This tests LocalFileSyncContext behavior in multi-thread / | 24 // This tests LocalFileSyncContext behavior in multi-thread / |
23 // multi-file-system-context environment. | 25 // multi-file-system-context environment. |
24 // Basic combined tests (single-thread / single-file-system-context) | 26 // Basic combined tests (single-thread / single-file-system-context) |
25 // that involve LocalFileSyncContext are also in | 27 // that involve LocalFileSyncContext are also in |
26 // syncable_file_system_unittests.cc. | 28 // syncable_file_system_unittests.cc. |
27 | 29 |
28 namespace fileapi { | 30 namespace fileapi { |
29 | 31 |
30 namespace { | 32 namespace { |
31 const char kOrigin1[] = "http://example.com"; | 33 const char kOrigin1[] = "http://example.com"; |
32 const char kOrigin2[] = "http://chromium.org"; | 34 const char kOrigin2[] = "http://chromium.org"; |
33 const char kServiceName[] = "test"; | 35 const char kServiceName[] = "test"; |
34 } | 36 } |
35 | 37 |
36 class LocalFileSyncContextTest : public testing::Test { | 38 class LocalFileSyncContextTest : public testing::Test { |
37 protected: | 39 protected: |
38 LocalFileSyncContextTest() | 40 LocalFileSyncContextTest() |
39 : status_(SYNC_FILE_ERROR_FAILED) {} | 41 : status_(SYNC_FILE_ERROR_FAILED), |
| 42 file_error_(base::PLATFORM_FILE_ERROR_FAILED), |
| 43 async_modify_finished_(false) {} |
40 | 44 |
41 virtual void SetUp() OVERRIDE { | 45 virtual void SetUp() OVERRIDE { |
42 EXPECT_TRUE(fileapi::RegisterSyncableFileSystem(kServiceName)); | 46 EXPECT_TRUE(fileapi::RegisterSyncableFileSystem(kServiceName)); |
43 | 47 |
44 io_thread_.reset(new base::Thread("Thread_IO")); | 48 io_thread_.reset(new base::Thread("Thread_IO")); |
45 file_thread_.reset(new base::Thread("Thread_File")); | 49 file_thread_.reset(new base::Thread("Thread_File")); |
46 io_thread_->StartWithOptions( | 50 io_thread_->StartWithOptions( |
47 base::Thread::Options(MessageLoop::TYPE_IO, 0)); | 51 base::Thread::Options(MessageLoop::TYPE_IO, 0)); |
48 file_thread_->Start(); | 52 file_thread_->Start(); |
49 | 53 |
50 ui_task_runner_ = MessageLoop::current()->message_loop_proxy(); | 54 ui_task_runner_ = MessageLoop::current()->message_loop_proxy(); |
51 io_task_runner_ = io_thread_->message_loop_proxy(); | 55 io_task_runner_ = io_thread_->message_loop_proxy(); |
52 file_task_runner_ = file_thread_->message_loop_proxy(); | 56 file_task_runner_ = file_thread_->message_loop_proxy(); |
53 } | 57 } |
54 | 58 |
55 virtual void TearDown() OVERRIDE { | 59 virtual void TearDown() OVERRIDE { |
56 EXPECT_TRUE(fileapi::RevokeSyncableFileSystem(kServiceName)); | 60 EXPECT_TRUE(fileapi::RevokeSyncableFileSystem(kServiceName)); |
57 io_thread_->Stop(); | 61 io_thread_->Stop(); |
58 file_thread_->Stop(); | 62 file_thread_->Stop(); |
59 } | 63 } |
60 | 64 |
| 65 SyncStatusCode PrepareForSync(LocalFileSyncContext* sync_context, |
| 66 const FileSystemURL& url, |
| 67 FileChangeList* changes) { |
| 68 status_ = SYNC_STATUS_UNKNOWN; |
| 69 sync_context->PrepareForSync( |
| 70 url, |
| 71 base::Bind(&LocalFileSyncContextTest::DidPrepareForSync, |
| 72 base::Unretained(this), changes)); |
| 73 MessageLoop::current()->Run(); |
| 74 return status_; |
| 75 } |
| 76 |
| 77 void DidPrepareForSync(FileChangeList* changes_out, |
| 78 SyncStatusCode status, |
| 79 const FileChangeList& changes) { |
| 80 ASSERT_TRUE(ui_task_runner_->RunsTasksOnCurrentThread()); |
| 81 status_ = status; |
| 82 *changes_out = changes; |
| 83 MessageLoop::current()->Quit(); |
| 84 } |
| 85 |
| 86 void StartModifyFileOnIOThread(CannedSyncableFileSystem* file_system, |
| 87 const FileSystemURL& url) { |
| 88 async_modify_finished_ = false; |
| 89 ASSERT_TRUE(file_system != NULL); |
| 90 if (!io_task_runner_->RunsTasksOnCurrentThread()) { |
| 91 ASSERT_TRUE(ui_task_runner_->RunsTasksOnCurrentThread()); |
| 92 io_task_runner_->PostTask( |
| 93 FROM_HERE, |
| 94 base::Bind(&LocalFileSyncContextTest::StartModifyFileOnIOThread, |
| 95 base::Unretained(this), file_system, url)); |
| 96 return; |
| 97 } |
| 98 ASSERT_TRUE(io_task_runner_->RunsTasksOnCurrentThread()); |
| 99 file_error_ = base::PLATFORM_FILE_ERROR_FAILED; |
| 100 file_system->NewOperation()->Truncate( |
| 101 url, 1, base::Bind(&LocalFileSyncContextTest::DidModifyFile, |
| 102 base::Unretained(this))); |
| 103 } |
| 104 |
| 105 base::PlatformFileError WaitUntilModifyFileIsDone() { |
| 106 while (!async_modify_finished_) |
| 107 MessageLoop::current()->RunAllPending(); |
| 108 return file_error_; |
| 109 } |
| 110 |
| 111 void DidModifyFile(base::PlatformFileError error) { |
| 112 if (!ui_task_runner_->RunsTasksOnCurrentThread()) { |
| 113 ASSERT_TRUE(io_task_runner_->RunsTasksOnCurrentThread()); |
| 114 ui_task_runner_->PostTask( |
| 115 FROM_HERE, |
| 116 base::Bind(&LocalFileSyncContextTest::DidModifyFile, |
| 117 base::Unretained(this), error)); |
| 118 return; |
| 119 } |
| 120 ASSERT_TRUE(ui_task_runner_->RunsTasksOnCurrentThread()); |
| 121 file_error_ = error; |
| 122 async_modify_finished_ = true; |
| 123 } |
| 124 |
61 // These need to remain until the very end. | 125 // These need to remain until the very end. |
62 scoped_ptr<base::Thread> io_thread_; | 126 scoped_ptr<base::Thread> io_thread_; |
63 scoped_ptr<base::Thread> file_thread_; | 127 scoped_ptr<base::Thread> file_thread_; |
64 MessageLoop loop_; | 128 MessageLoop loop_; |
65 | 129 |
66 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_; | 130 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_; |
67 scoped_refptr<base::SingleThreadTaskRunner> file_task_runner_; | 131 scoped_refptr<base::SingleThreadTaskRunner> file_task_runner_; |
68 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_; | 132 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_; |
69 | 133 |
70 scoped_refptr<LocalFileSyncContext> sync_context_; | 134 scoped_refptr<LocalFileSyncContext> sync_context_; |
71 | 135 |
72 SyncStatusCode status_; | 136 SyncStatusCode status_; |
| 137 base::PlatformFileError file_error_; |
| 138 bool async_modify_finished_; |
73 }; | 139 }; |
74 | 140 |
75 TEST_F(LocalFileSyncContextTest, ConstructAndDestruct) { | 141 TEST_F(LocalFileSyncContextTest, ConstructAndDestruct) { |
76 sync_context_ = new LocalFileSyncContext( | 142 sync_context_ = new LocalFileSyncContext( |
77 ui_task_runner_, io_task_runner_); | 143 ui_task_runner_, io_task_runner_); |
78 sync_context_->ShutdownOnUIThread(); | 144 sync_context_->ShutdownOnUIThread(); |
79 } | 145 } |
80 | 146 |
81 TEST_F(LocalFileSyncContextTest, InitializeFileSystemContext) { | 147 TEST_F(LocalFileSyncContextTest, InitializeFileSystemContext) { |
82 CannedSyncableFileSystem file_system(GURL(kOrigin1), kServiceName, | 148 CannedSyncableFileSystem file_system(GURL(kOrigin1), kServiceName, |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
163 file_system1.file_system_context()->change_tracker()->GetChangedURLs(&urls); | 229 file_system1.file_system_context()->change_tracker()->GetChangedURLs(&urls); |
164 ASSERT_EQ(1U, urls.size()); | 230 ASSERT_EQ(1U, urls.size()); |
165 EXPECT_EQ(kURL1, urls[0]); | 231 EXPECT_EQ(kURL1, urls[0]); |
166 | 232 |
167 // file_system2's tracker now must have the change for kURL2. | 233 // file_system2's tracker now must have the change for kURL2. |
168 urls.clear(); | 234 urls.clear(); |
169 file_system2.file_system_context()->change_tracker()->GetChangedURLs(&urls); | 235 file_system2.file_system_context()->change_tracker()->GetChangedURLs(&urls); |
170 ASSERT_EQ(1U, urls.size()); | 236 ASSERT_EQ(1U, urls.size()); |
171 EXPECT_EQ(kURL2, urls[0]); | 237 EXPECT_EQ(kURL2, urls[0]); |
172 | 238 |
| 239 FileChangeList changes; |
| 240 EXPECT_EQ(SYNC_STATUS_OK, PrepareForSync(sync_context_, kURL1, &changes)); |
| 241 EXPECT_EQ(1U, changes.size()); |
| 242 EXPECT_TRUE(changes.list().back().IsFile()); |
| 243 EXPECT_TRUE(changes.list().back().IsAddOrUpdate()); |
| 244 |
| 245 changes.clear(); |
| 246 EXPECT_EQ(SYNC_STATUS_OK, PrepareForSync(sync_context_, kURL2, &changes)); |
| 247 EXPECT_EQ(1U, changes.size()); |
| 248 EXPECT_FALSE(changes.list().back().IsFile()); |
| 249 EXPECT_TRUE(changes.list().back().IsAddOrUpdate()); |
| 250 |
173 sync_context_->ShutdownOnUIThread(); | 251 sync_context_->ShutdownOnUIThread(); |
174 sync_context_ = NULL; | 252 sync_context_ = NULL; |
175 | 253 |
176 file_system1.TearDown(); | 254 file_system1.TearDown(); |
177 file_system2.TearDown(); | 255 file_system2.TearDown(); |
178 } | 256 } |
179 | 257 |
| 258 TEST_F(LocalFileSyncContextTest, PrepareSyncWhileWriting) { |
| 259 CannedSyncableFileSystem file_system(GURL(kOrigin1), kServiceName, |
| 260 io_task_runner_); |
| 261 file_system.SetUp(); |
| 262 sync_context_ = new LocalFileSyncContext(ui_task_runner_, io_task_runner_); |
| 263 EXPECT_EQ(SYNC_STATUS_OK, |
| 264 file_system.MaybeInitializeFileSystemContext(sync_context_)); |
| 265 |
| 266 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system.OpenFileSystem()); |
| 267 |
| 268 const FileSystemURL kURL1(file_system.URL("foo")); |
| 269 |
| 270 // Creates a file in file_system. |
| 271 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system.CreateFile(kURL1)); |
| 272 |
| 273 // Kick file write on IO thread. |
| 274 StartModifyFileOnIOThread(&file_system, kURL1); |
| 275 |
| 276 // Until the operation finishes PrepareForSync should return BUSY error. |
| 277 FileChangeList changes; |
| 278 EXPECT_EQ(SYNC_STATUS_FILE_BUSY, |
| 279 PrepareForSync(sync_context_, kURL1, &changes)); |
| 280 EXPECT_TRUE(changes.empty()); |
| 281 |
| 282 // Wait for the completion. |
| 283 EXPECT_EQ(base::PLATFORM_FILE_OK, WaitUntilModifyFileIsDone()); |
| 284 |
| 285 // Now PrepareForSync should return OK. |
| 286 changes.clear(); |
| 287 EXPECT_EQ(SYNC_STATUS_OK, PrepareForSync(sync_context_, kURL1, &changes)); |
| 288 EXPECT_EQ(1U, changes.size()); |
| 289 EXPECT_TRUE(changes.list().back().IsFile()); |
| 290 EXPECT_TRUE(changes.list().back().IsAddOrUpdate()); |
| 291 |
| 292 sync_context_->ShutdownOnUIThread(); |
| 293 sync_context_ = NULL; |
| 294 |
| 295 file_system.TearDown(); |
| 296 } |
| 297 |
180 } // namespace fileapi | 298 } // namespace fileapi |
OLD | NEW |