Fix Win8 metro startup crash from window switcher button
[chromium-blink-merge.git] / webkit / fileapi / syncable / syncable_file_operation_runner_unittest.cc
blobb6c45fea77e6ba6af348cffe248c6de5953d073b
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 <string>
7 #include "base/basictypes.h"
8 #include "base/file_util.h"
9 #include "base/location.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/message_loop.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13 #include "webkit/blob/mock_blob_url_request_context.h"
14 #include "webkit/fileapi/file_system_context.h"
15 #include "webkit/fileapi/syncable/canned_syncable_file_system.h"
16 #include "webkit/fileapi/syncable/local_file_change_tracker.h"
17 #include "webkit/fileapi/syncable/local_file_sync_context.h"
18 #include "webkit/fileapi/syncable/local_file_sync_status.h"
19 #include "webkit/fileapi/syncable/syncable_file_operation_runner.h"
20 #include "webkit/fileapi/syncable/syncable_file_system_operation.h"
21 #include "webkit/fileapi/syncable/syncable_file_system_util.h"
23 using fileapi::FileSystemOperation;
24 using fileapi::FileSystemURL;
25 using webkit_blob::MockBlobURLRequestContext;
26 using webkit_blob::ScopedTextBlob;
27 using base::PlatformFileError;
29 namespace sync_file_system {
31 namespace {
32 const std::string kServiceName = "test";
33 const std::string kParent = "foo";
34 const std::string kFile = "foo/file";
35 const std::string kDir = "foo/dir";
36 const std::string kChild = "foo/dir/bar";
37 const std::string kOther = "bar";
38 } // namespace
40 class SyncableFileOperationRunnerTest : public testing::Test {
41 protected:
42 typedef FileSystemOperation::StatusCallback StatusCallback;
44 // Use the current thread as IO thread so that we can directly call
45 // operations in the tests.
46 SyncableFileOperationRunnerTest()
47 : message_loop_(base::MessageLoop::TYPE_IO),
48 file_system_(GURL("http://example.com"), kServiceName,
49 base::MessageLoopProxy::current(),
50 base::MessageLoopProxy::current()),
51 callback_count_(0),
52 write_status_(base::PLATFORM_FILE_ERROR_FAILED),
53 write_bytes_(0),
54 write_complete_(false),
55 url_request_context_(file_system_.file_system_context()),
56 weak_factory_(this) {}
58 virtual void SetUp() OVERRIDE {
59 ASSERT_TRUE(dir_.CreateUniqueTempDir());
60 file_system_.SetUp();
61 sync_context_ = new LocalFileSyncContext(base::MessageLoopProxy::current(),
62 base::MessageLoopProxy::current());
63 ASSERT_EQ(SYNC_STATUS_OK,
64 file_system_.MaybeInitializeFileSystemContext(sync_context_));
66 ASSERT_EQ(base::PLATFORM_FILE_OK, file_system_.OpenFileSystem());
67 ASSERT_EQ(base::PLATFORM_FILE_OK,
68 file_system_.CreateDirectory(URL(kParent)));
71 virtual void TearDown() OVERRIDE {
72 if (sync_context_)
73 sync_context_->ShutdownOnUIThread();
74 sync_context_ = NULL;
76 file_system_.TearDown();
77 message_loop_.RunUntilIdle();
78 RevokeSyncableFileSystem(kServiceName);
81 FileSystemURL URL(const std::string& path) {
82 return file_system_.URL(path);
85 LocalFileSyncStatus* sync_status() {
86 return file_system_.file_system_context()->sync_context()->sync_status();
89 void ResetCallbackStatus() {
90 write_status_ = base::PLATFORM_FILE_ERROR_FAILED;
91 write_bytes_ = 0;
92 write_complete_ = false;
93 callback_count_ = 0;
96 StatusCallback ExpectStatus(const tracked_objects::Location& location,
97 PlatformFileError expect) {
98 return base::Bind(&SyncableFileOperationRunnerTest::DidFinish,
99 weak_factory_.GetWeakPtr(), location, expect);
102 FileSystemOperation::WriteCallback GetWriteCallback(
103 const tracked_objects::Location& location) {
104 return base::Bind(&SyncableFileOperationRunnerTest::DidWrite,
105 weak_factory_.GetWeakPtr(), location);
108 void DidWrite(const tracked_objects::Location& location,
109 PlatformFileError status, int64 bytes, bool complete) {
110 SCOPED_TRACE(testing::Message() << location.ToString());
111 write_status_ = status;
112 write_bytes_ += bytes;
113 write_complete_ = complete;
114 ++callback_count_;
117 void DidFinish(const tracked_objects::Location& location,
118 PlatformFileError expect, PlatformFileError status) {
119 SCOPED_TRACE(testing::Message() << location.ToString());
120 EXPECT_EQ(expect, status);
121 ++callback_count_;
124 bool CreateTempFile(base::FilePath* path) {
125 return file_util::CreateTemporaryFileInDir(dir_.path(), path);
128 base::ScopedTempDir dir_;
130 base::MessageLoop message_loop_;
131 CannedSyncableFileSystem file_system_;
132 scoped_refptr<LocalFileSyncContext> sync_context_;
134 int callback_count_;
135 PlatformFileError write_status_;
136 size_t write_bytes_;
137 bool write_complete_;
139 MockBlobURLRequestContext url_request_context_;
141 base::WeakPtrFactory<SyncableFileOperationRunnerTest> weak_factory_;
143 DISALLOW_COPY_AND_ASSIGN(SyncableFileOperationRunnerTest);
146 TEST_F(SyncableFileOperationRunnerTest, SimpleQueue) {
147 sync_status()->StartSyncing(URL(kFile));
148 ASSERT_FALSE(sync_status()->IsWritable(URL(kFile)));
150 // The URL is in syncing so the write operations won't run.
151 ResetCallbackStatus();
152 file_system_.NewOperation()->CreateFile(
153 URL(kFile), false /* exclusive */,
154 ExpectStatus(FROM_HERE, base::PLATFORM_FILE_OK));
155 file_system_.NewOperation()->Truncate(
156 URL(kFile), 1,
157 ExpectStatus(FROM_HERE, base::PLATFORM_FILE_OK));
158 base::MessageLoop::current()->RunUntilIdle();
159 EXPECT_EQ(0, callback_count_);
161 // Read operations are not blocked (and are executed before queued ones).
162 file_system_.NewOperation()->FileExists(
163 URL(kFile), ExpectStatus(FROM_HERE, base::PLATFORM_FILE_ERROR_NOT_FOUND));
164 base::MessageLoop::current()->RunUntilIdle();
165 EXPECT_EQ(1, callback_count_);
167 // End syncing (to enable write).
168 sync_status()->EndSyncing(URL(kFile));
169 ASSERT_TRUE(sync_status()->IsWritable(URL(kFile)));
171 ResetCallbackStatus();
172 base::MessageLoop::current()->RunUntilIdle();
173 EXPECT_EQ(2, callback_count_);
175 // Now the file must have been created and updated.
176 ResetCallbackStatus();
177 file_system_.NewOperation()->FileExists(
178 URL(kFile), ExpectStatus(FROM_HERE, base::PLATFORM_FILE_OK));
179 base::MessageLoop::current()->RunUntilIdle();
180 EXPECT_EQ(1, callback_count_);
183 TEST_F(SyncableFileOperationRunnerTest, WriteToParentAndChild) {
184 // First create the kDir directory and kChild in the dir.
185 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system_.CreateDirectory(URL(kDir)));
186 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system_.CreateFile(URL(kChild)));
188 // Start syncing the kDir directory.
189 sync_status()->StartSyncing(URL(kDir));
190 ASSERT_FALSE(sync_status()->IsWritable(URL(kDir)));
192 // Writes to kParent and kChild should be all queued up.
193 ResetCallbackStatus();
194 file_system_.NewOperation()->Truncate(
195 URL(kChild), 1, ExpectStatus(FROM_HERE, base::PLATFORM_FILE_OK));
196 file_system_.NewOperation()->Remove(
197 URL(kParent), true /* recursive */,
198 ExpectStatus(FROM_HERE, base::PLATFORM_FILE_OK));
199 base::MessageLoop::current()->RunUntilIdle();
200 EXPECT_EQ(0, callback_count_);
202 // Read operations are not blocked (and are executed before queued ones).
203 file_system_.NewOperation()->DirectoryExists(
204 URL(kDir), ExpectStatus(FROM_HERE, base::PLATFORM_FILE_OK));
205 base::MessageLoop::current()->RunUntilIdle();
206 EXPECT_EQ(1, callback_count_);
208 // Writes to unrelated files must succeed as well.
209 ResetCallbackStatus();
210 file_system_.NewOperation()->CreateDirectory(
211 URL(kOther), false /* exclusive */, false /* recursive */,
212 ExpectStatus(FROM_HERE, base::PLATFORM_FILE_OK));
213 base::MessageLoop::current()->RunUntilIdle();
214 EXPECT_EQ(1, callback_count_);
216 // End syncing (to enable write).
217 sync_status()->EndSyncing(URL(kDir));
218 ASSERT_TRUE(sync_status()->IsWritable(URL(kDir)));
220 ResetCallbackStatus();
221 base::MessageLoop::current()->RunUntilIdle();
222 EXPECT_EQ(2, callback_count_);
225 TEST_F(SyncableFileOperationRunnerTest, CopyAndMove) {
226 // First create the kDir directory and kChild in the dir.
227 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system_.CreateDirectory(URL(kDir)));
228 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system_.CreateFile(URL(kChild)));
230 // Start syncing the kParent directory.
231 sync_status()->StartSyncing(URL(kParent));
233 // Copying kDir to other directory should succeed, while moving would fail
234 // (since the source directory is in syncing).
235 ResetCallbackStatus();
236 file_system_.NewOperation()->Copy(
237 URL(kDir), URL("dest-copy"),
238 ExpectStatus(FROM_HERE, base::PLATFORM_FILE_OK));
239 file_system_.NewOperation()->Move(
240 URL(kDir), URL("dest-move"),
241 ExpectStatus(FROM_HERE, base::PLATFORM_FILE_OK));
242 base::MessageLoop::current()->RunUntilIdle();
243 EXPECT_EQ(1, callback_count_);
245 // Only "dest-copy1" should exist.
246 EXPECT_EQ(base::PLATFORM_FILE_OK,
247 file_system_.DirectoryExists(URL("dest-copy")));
248 EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND,
249 file_system_.DirectoryExists(URL("dest-move")));
251 // Start syncing the "dest-copy2" directory.
252 sync_status()->StartSyncing(URL("dest-copy2"));
254 // Now the destination is also locked copying kDir should be queued.
255 ResetCallbackStatus();
256 file_system_.NewOperation()->Copy(
257 URL(kDir), URL("dest-copy2"),
258 ExpectStatus(FROM_HERE, base::PLATFORM_FILE_OK));
259 base::MessageLoop::current()->RunUntilIdle();
260 EXPECT_EQ(0, callback_count_);
262 // Finish syncing the "dest-copy2" directory to unlock Copy.
263 sync_status()->EndSyncing(URL("dest-copy2"));
264 ResetCallbackStatus();
265 base::MessageLoop::current()->RunUntilIdle();
266 EXPECT_EQ(1, callback_count_);
268 // Now we should have "dest-copy2".
269 EXPECT_EQ(base::PLATFORM_FILE_OK,
270 file_system_.DirectoryExists(URL("dest-copy2")));
272 // Finish syncing the kParent to unlock Move.
273 sync_status()->EndSyncing(URL(kParent));
274 ResetCallbackStatus();
275 base::MessageLoop::current()->RunUntilIdle();
276 EXPECT_EQ(1, callback_count_);
278 // Now we should have "dest-move".
279 EXPECT_EQ(base::PLATFORM_FILE_OK,
280 file_system_.DirectoryExists(URL("dest-move")));
283 TEST_F(SyncableFileOperationRunnerTest, Write) {
284 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system_.CreateFile(URL(kFile)));
285 const GURL kBlobURL("blob:foo");
286 const std::string kData("Lorem ipsum.");
287 ScopedTextBlob blob(url_request_context_, kBlobURL, kData);
289 sync_status()->StartSyncing(URL(kFile));
291 ResetCallbackStatus();
292 file_system_.NewOperation()->Write(
293 &url_request_context_,
294 URL(kFile), kBlobURL, 0, GetWriteCallback(FROM_HERE));
295 base::MessageLoop::current()->RunUntilIdle();
296 EXPECT_EQ(0, callback_count_);
298 sync_status()->EndSyncing(URL(kFile));
299 ResetCallbackStatus();
301 while (!write_complete_)
302 base::MessageLoop::current()->RunUntilIdle();
304 EXPECT_EQ(base::PLATFORM_FILE_OK, write_status_);
305 EXPECT_EQ(kData.size(), write_bytes_);
306 EXPECT_TRUE(write_complete_);
309 TEST_F(SyncableFileOperationRunnerTest, QueueAndCancel) {
310 sync_status()->StartSyncing(URL(kFile));
311 ASSERT_FALSE(sync_status()->IsWritable(URL(kFile)));
313 ResetCallbackStatus();
314 file_system_.NewOperation()->CreateFile(
315 URL(kFile), false /* exclusive */,
316 ExpectStatus(FROM_HERE, base::PLATFORM_FILE_ERROR_ABORT));
317 file_system_.NewOperation()->Truncate(
318 URL(kFile), 1,
319 ExpectStatus(FROM_HERE, base::PLATFORM_FILE_ERROR_ABORT));
320 base::MessageLoop::current()->RunUntilIdle();
321 EXPECT_EQ(0, callback_count_);
323 ResetCallbackStatus();
325 // This shouldn't crash nor leak memory.
326 sync_context_->ShutdownOnUIThread();
327 sync_context_ = NULL;
328 base::MessageLoop::current()->RunUntilIdle();
329 EXPECT_EQ(2, callback_count_);
332 // Test if CopyInForeignFile runs cooperatively with other Sync operations
333 // when it is called directly via AsLocalFileSystemOperation.
334 TEST_F(SyncableFileOperationRunnerTest, CopyInForeignFile) {
335 const std::string kTestData("test data");
337 base::FilePath temp_path;
338 ASSERT_TRUE(CreateTempFile(&temp_path));
339 ASSERT_EQ(static_cast<int>(kTestData.size()),
340 file_util::WriteFile(
341 temp_path, kTestData.data(), kTestData.size()));
343 sync_status()->StartSyncing(URL(kFile));
344 ASSERT_FALSE(sync_status()->IsWritable(URL(kFile)));
346 // The URL is in syncing so CopyIn (which is a write operation) won't run.
347 ResetCallbackStatus();
348 file_system_.NewOperation()->AsLocalFileSystemOperation()->CopyInForeignFile(
349 temp_path, URL(kFile),
350 ExpectStatus(FROM_HERE, base::PLATFORM_FILE_OK));
351 base::MessageLoop::current()->RunUntilIdle();
352 EXPECT_EQ(0, callback_count_);
354 // End syncing (to enable write).
355 sync_status()->EndSyncing(URL(kFile));
356 ASSERT_TRUE(sync_status()->IsWritable(URL(kFile)));
358 ResetCallbackStatus();
359 base::MessageLoop::current()->RunUntilIdle();
360 EXPECT_EQ(1, callback_count_);
362 // Now the file must have been created and have the same content as temp_path.
363 ResetCallbackStatus();
364 file_system_.DoVerifyFile(
365 URL(kFile), kTestData,
366 ExpectStatus(FROM_HERE, base::PLATFORM_FILE_OK));
367 base::MessageLoop::current()->RunUntilIdle();
368 EXPECT_EQ(1, callback_count_);
371 } // namespace sync_file_system