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 "chrome/browser/chromeos/drive/file_system/update_operation.h"
7 #include "base/callback_helpers.h"
8 #include "base/file_util.h"
10 #include "base/task_runner_util.h"
11 #include "chrome/browser/chromeos/drive/file_cache.h"
12 #include "chrome/browser/chromeos/drive/file_system/operation_test_base.h"
13 #include "chrome/browser/chromeos/drive/file_system_interface.h"
14 #include "chrome/browser/drive/fake_drive_service.h"
15 #include "google_apis/drive/gdata_wapi_parser.h"
16 #include "google_apis/drive/test_util.h"
17 #include "testing/gtest/include/gtest/gtest.h"
20 namespace file_system
{
22 class UpdateOperationTest
: public OperationTestBase
{
24 virtual void SetUp() OVERRIDE
{
25 OperationTestBase::SetUp();
26 operation_
.reset(new UpdateOperation(blocking_task_runner(),
33 // Stores |content| to the cache and mark it as dirty.
34 FileError
StoreAndMarkDirty(const std::string
& local_id
,
35 const std::string
& content
) {
37 if (!base::CreateTemporaryFileInDir(temp_dir(), &path
) ||
38 !google_apis::test_util::WriteStringToFile(path
, content
))
39 return FILE_ERROR_FAILED
;
41 // Store the file to cache.
42 FileError error
= FILE_ERROR_FAILED
;
43 base::PostTaskAndReplyWithResult(
44 blocking_task_runner(),
46 base::Bind(&internal::FileCache::Store
,
47 base::Unretained(cache()),
48 local_id
, base::MD5String(content
), path
,
49 internal::FileCache::FILE_OPERATION_COPY
),
50 google_apis::test_util::CreateCopyResultCallback(&error
));
51 test_util::RunBlockingPoolTask();
52 if (error
!= FILE_ERROR_OK
)
56 error
= FILE_ERROR_FAILED
;
57 scoped_ptr
<base::ScopedClosureRunner
> file_closer
;
58 base::PostTaskAndReplyWithResult(
59 blocking_task_runner(),
61 base::Bind(&internal::FileCache::OpenForWrite
,
62 base::Unretained(cache()),
65 google_apis::test_util::CreateCopyResultCallback(&error
));
66 test_util::RunBlockingPoolTask();
70 scoped_ptr
<UpdateOperation
> operation_
;
73 TEST_F(UpdateOperationTest
, UpdateFileByLocalId
) {
74 const base::FilePath
kFilePath(FILE_PATH_LITERAL("drive/root/File 1.txt"));
75 const std::string
kResourceId("file:2_file_resource_id");
77 const std::string local_id
= GetLocalId(kFilePath
);
78 EXPECT_FALSE(local_id
.empty());
80 const std::string kTestFileContent
= "I'm being uploaded! Yay!";
81 EXPECT_EQ(FILE_ERROR_OK
, StoreAndMarkDirty(local_id
, kTestFileContent
));
83 int64 original_changestamp
= fake_service()->largest_changestamp();
85 // The callback will be called upon completion of UpdateFileByLocalId().
86 FileError error
= FILE_ERROR_FAILED
;
87 operation_
->UpdateFileByLocalId(
89 ClientContext(USER_INITIATED
),
90 UpdateOperation::RUN_CONTENT_CHECK
,
91 google_apis::test_util::CreateCopyResultCallback(&error
));
92 test_util::RunBlockingPoolTask();
93 EXPECT_EQ(FILE_ERROR_OK
, error
);
95 // Check that the server has received an update.
96 EXPECT_LT(original_changestamp
, fake_service()->largest_changestamp());
98 // Check that the file size is updated to that of the updated content.
99 google_apis::GDataErrorCode gdata_error
= google_apis::GDATA_OTHER_ERROR
;
100 scoped_ptr
<google_apis::ResourceEntry
> server_entry
;
101 fake_service()->GetResourceEntry(
103 google_apis::test_util::CreateCopyResultCallback(&gdata_error
,
105 test_util::RunBlockingPoolTask();
106 EXPECT_EQ(google_apis::HTTP_SUCCESS
, gdata_error
);
107 EXPECT_EQ(static_cast<int64
>(kTestFileContent
.size()),
108 server_entry
->file_size());
110 // Make sure that the cache is no longer dirty.
111 bool success
= false;
112 FileCacheEntry cache_entry
;
113 base::PostTaskAndReplyWithResult(
114 blocking_task_runner(),
116 base::Bind(&internal::FileCache::GetCacheEntry
,
117 base::Unretained(cache()),
120 google_apis::test_util::CreateCopyResultCallback(&success
));
121 test_util::RunBlockingPoolTask();
122 ASSERT_TRUE(success
);
123 EXPECT_FALSE(cache_entry
.is_dirty());
126 TEST_F(UpdateOperationTest
, UpdateFileByLocalId_NonexistentFile
) {
127 FileError error
= FILE_ERROR_OK
;
128 operation_
->UpdateFileByLocalId(
129 "nonexistent_local_id",
130 ClientContext(USER_INITIATED
),
131 UpdateOperation::RUN_CONTENT_CHECK
,
132 google_apis::test_util::CreateCopyResultCallback(&error
));
133 test_util::RunBlockingPoolTask();
134 EXPECT_EQ(FILE_ERROR_NOT_FOUND
, error
);
137 TEST_F(UpdateOperationTest
, UpdateFileByLocalId_Md5
) {
138 const base::FilePath
kFilePath(FILE_PATH_LITERAL("drive/root/File 1.txt"));
139 const std::string
kResourceId("file:2_file_resource_id");
141 const std::string local_id
= GetLocalId(kFilePath
);
142 EXPECT_FALSE(local_id
.empty());
144 const std::string kTestFileContent
= "I'm being uploaded! Yay!";
145 EXPECT_EQ(FILE_ERROR_OK
, StoreAndMarkDirty(local_id
, kTestFileContent
));
147 int64 original_changestamp
= fake_service()->largest_changestamp();
149 // The callback will be called upon completion of UpdateFileByLocalId().
150 FileError error
= FILE_ERROR_FAILED
;
151 operation_
->UpdateFileByLocalId(
153 ClientContext(USER_INITIATED
),
154 UpdateOperation::RUN_CONTENT_CHECK
,
155 google_apis::test_util::CreateCopyResultCallback(&error
));
156 test_util::RunBlockingPoolTask();
157 EXPECT_EQ(FILE_ERROR_OK
, error
);
159 // Check that the server has received an update.
160 EXPECT_LT(original_changestamp
, fake_service()->largest_changestamp());
162 // Check that the file size is updated to that of the updated content.
163 google_apis::GDataErrorCode gdata_error
= google_apis::GDATA_OTHER_ERROR
;
164 scoped_ptr
<google_apis::ResourceEntry
> server_entry
;
165 fake_service()->GetResourceEntry(
167 google_apis::test_util::CreateCopyResultCallback(&gdata_error
,
169 test_util::RunBlockingPoolTask();
170 EXPECT_EQ(google_apis::HTTP_SUCCESS
, gdata_error
);
171 EXPECT_EQ(static_cast<int64
>(kTestFileContent
.size()),
172 server_entry
->file_size());
174 // Make sure that the cache is no longer dirty.
175 bool success
= false;
176 FileCacheEntry cache_entry
;
177 base::PostTaskAndReplyWithResult(
178 blocking_task_runner(),
180 base::Bind(&internal::FileCache::GetCacheEntry
,
181 base::Unretained(cache()),
184 google_apis::test_util::CreateCopyResultCallback(&success
));
185 test_util::RunBlockingPoolTask();
186 ASSERT_TRUE(success
);
187 EXPECT_FALSE(cache_entry
.is_dirty());
189 // Again mark the cache file dirty.
190 scoped_ptr
<base::ScopedClosureRunner
> file_closer
;
191 error
= FILE_ERROR_FAILED
;
192 base::PostTaskAndReplyWithResult(
193 blocking_task_runner(),
195 base::Bind(&internal::FileCache::OpenForWrite
,
196 base::Unretained(cache()),
199 google_apis::test_util::CreateCopyResultCallback(&error
));
200 test_util::RunBlockingPoolTask();
201 EXPECT_EQ(FILE_ERROR_OK
, error
);
203 // And call UpdateFileByLocalId again.
204 // In this case, although the file is marked as dirty, but the content
205 // hasn't been changed. Thus, the actual uploading should be skipped.
206 original_changestamp
= fake_service()->largest_changestamp();
207 error
= FILE_ERROR_FAILED
;
208 operation_
->UpdateFileByLocalId(
210 ClientContext(USER_INITIATED
),
211 UpdateOperation::RUN_CONTENT_CHECK
,
212 google_apis::test_util::CreateCopyResultCallback(&error
));
213 test_util::RunBlockingPoolTask();
214 EXPECT_EQ(FILE_ERROR_OK
, error
);
216 EXPECT_EQ(original_changestamp
, fake_service()->largest_changestamp());
218 // Make sure that the cache is no longer dirty.
220 base::PostTaskAndReplyWithResult(
221 blocking_task_runner(),
223 base::Bind(&internal::FileCache::GetCacheEntry
,
224 base::Unretained(cache()),
227 google_apis::test_util::CreateCopyResultCallback(&success
));
228 test_util::RunBlockingPoolTask();
229 ASSERT_TRUE(success
);
230 EXPECT_FALSE(cache_entry
.is_dirty());
232 // Once again mark the cache file dirty.
233 error
= FILE_ERROR_FAILED
;
234 base::PostTaskAndReplyWithResult(
235 blocking_task_runner(),
237 base::Bind(&internal::FileCache::OpenForWrite
,
238 base::Unretained(cache()),
241 google_apis::test_util::CreateCopyResultCallback(&error
));
242 test_util::RunBlockingPoolTask();
243 EXPECT_EQ(FILE_ERROR_OK
, error
);
245 // And call UpdateFileByLocalId again.
246 // In this case, NO_CONTENT_CHECK is set, so the actual uploading should run
247 // no matter the content is changed or not.
248 original_changestamp
= fake_service()->largest_changestamp();
249 error
= FILE_ERROR_FAILED
;
250 operation_
->UpdateFileByLocalId(
252 ClientContext(USER_INITIATED
),
253 UpdateOperation::NO_CONTENT_CHECK
,
254 google_apis::test_util::CreateCopyResultCallback(&error
));
255 test_util::RunBlockingPoolTask();
256 EXPECT_EQ(FILE_ERROR_OK
, error
);
258 // Make sure that the server is receiving a change.
259 EXPECT_LE(original_changestamp
, fake_service()->largest_changestamp());
262 TEST_F(UpdateOperationTest
, UpdateFileByLocalId_OpenedForWrite
) {
263 const base::FilePath
kFilePath(FILE_PATH_LITERAL("drive/root/File 1.txt"));
264 const std::string
kResourceId("file:2_file_resource_id");
266 const std::string local_id
= GetLocalId(kFilePath
);
267 EXPECT_FALSE(local_id
.empty());
269 const std::string kTestFileContent
= "I'm being uploaded! Yay!";
270 EXPECT_EQ(FILE_ERROR_OK
, StoreAndMarkDirty(local_id
, kTestFileContent
));
272 // Emulate a situation where someone is writing to the file.
273 scoped_ptr
<base::ScopedClosureRunner
> file_closer
;
274 FileError error
= FILE_ERROR_FAILED
;
275 base::PostTaskAndReplyWithResult(
276 blocking_task_runner(),
278 base::Bind(&internal::FileCache::OpenForWrite
,
279 base::Unretained(cache()),
282 google_apis::test_util::CreateCopyResultCallback(&error
));
283 test_util::RunBlockingPoolTask();
284 EXPECT_EQ(FILE_ERROR_OK
, error
);
286 // Update. This should not clear the dirty bit.
287 error
= FILE_ERROR_FAILED
;
288 operation_
->UpdateFileByLocalId(
290 ClientContext(USER_INITIATED
),
291 UpdateOperation::RUN_CONTENT_CHECK
,
292 google_apis::test_util::CreateCopyResultCallback(&error
));
293 test_util::RunBlockingPoolTask();
294 EXPECT_EQ(FILE_ERROR_OK
, error
);
296 // Make sure that the cache is still dirty.
297 bool success
= false;
298 FileCacheEntry cache_entry
;
299 base::PostTaskAndReplyWithResult(
300 blocking_task_runner(),
302 base::Bind(&internal::FileCache::GetCacheEntry
,
303 base::Unretained(cache()),
306 google_apis::test_util::CreateCopyResultCallback(&success
));
307 test_util::RunBlockingPoolTask();
308 EXPECT_TRUE(success
);
309 EXPECT_TRUE(cache_entry
.is_dirty());
314 // Update. This should clear the dirty bit.
315 error
= FILE_ERROR_FAILED
;
316 operation_
->UpdateFileByLocalId(
318 ClientContext(USER_INITIATED
),
319 UpdateOperation::RUN_CONTENT_CHECK
,
320 google_apis::test_util::CreateCopyResultCallback(&error
));
321 test_util::RunBlockingPoolTask();
322 EXPECT_EQ(FILE_ERROR_OK
, error
);
324 // Make sure that the cache is no longer dirty.
325 base::PostTaskAndReplyWithResult(
326 blocking_task_runner(),
328 base::Bind(&internal::FileCache::GetCacheEntry
,
329 base::Unretained(cache()),
332 google_apis::test_util::CreateCopyResultCallback(&success
));
333 test_util::RunBlockingPoolTask();
334 EXPECT_TRUE(success
);
335 EXPECT_FALSE(cache_entry
.is_dirty());
338 } // namespace file_system