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.
7 #include "base/basictypes.h"
9 #include "base/files/file_util.h"
10 #include "base/location.h"
11 #include "base/run_loop.h"
12 #include "base/stl_util.h"
13 #include "base/thread_task_runner_handle.h"
14 #include "base/threading/thread.h"
15 #include "chrome/browser/sync_file_system/file_change.h"
16 #include "chrome/browser/sync_file_system/local/canned_syncable_file_system.h"
17 #include "chrome/browser/sync_file_system/local/local_file_change_tracker.h"
18 #include "chrome/browser/sync_file_system/local/local_file_sync_context.h"
19 #include "chrome/browser/sync_file_system/local/local_file_sync_service.h"
20 #include "chrome/browser/sync_file_system/local/local_file_sync_status.h"
21 #include "chrome/browser/sync_file_system/local/mock_sync_status_observer.h"
22 #include "chrome/browser/sync_file_system/local/sync_file_system_backend.h"
23 #include "chrome/browser/sync_file_system/mock_local_change_processor.h"
24 #include "chrome/browser/sync_file_system/sync_file_metadata.h"
25 #include "chrome/browser/sync_file_system/sync_file_system_test_util.h"
26 #include "chrome/browser/sync_file_system/sync_status_code.h"
27 #include "chrome/browser/sync_file_system/syncable_file_system_util.h"
28 #include "chrome/test/base/testing_profile.h"
29 #include "content/public/browser/browser_thread.h"
30 #include "content/public/test/test_browser_thread_bundle.h"
31 #include "content/public/test/test_utils.h"
32 #include "storage/browser/fileapi/file_system_context.h"
33 #include "testing/gmock/include/gmock/gmock.h"
34 #include "testing/gtest/include/gtest/gtest.h"
35 #include "third_party/leveldatabase/src/helpers/memenv/memenv.h"
36 #include "third_party/leveldatabase/src/include/leveldb/env.h"
38 using content::BrowserThread
;
39 using storage::FileSystemURL
;
41 using ::testing::AtLeast
;
42 using ::testing::InvokeWithoutArgs
;
43 using ::testing::StrictMock
;
45 namespace sync_file_system
{
49 const char kOrigin
[] = "http://example.com";
51 void DidPrepareForProcessRemoteChange(const tracked_objects::Location
& where
,
52 const base::Closure
& oncompleted
,
53 SyncStatusCode expected_status
,
54 const SyncFileMetadata
& expected_metadata
,
55 SyncStatusCode status
,
56 const SyncFileMetadata
& metadata
,
57 const FileChangeList
& changes
) {
58 SCOPED_TRACE(testing::Message() << where
.ToString());
59 ASSERT_EQ(expected_status
, status
);
60 ASSERT_EQ(expected_metadata
.file_type
, metadata
.file_type
);
61 ASSERT_EQ(expected_metadata
.size
, metadata
.size
);
62 ASSERT_TRUE(changes
.empty());
66 void OnSyncCompleted(const tracked_objects::Location
& where
,
67 const base::Closure
& oncompleted
,
68 SyncStatusCode expected_status
,
69 const FileSystemURL
& expected_url
,
70 SyncStatusCode status
,
71 const FileSystemURL
& url
) {
72 SCOPED_TRACE(testing::Message() << where
.ToString());
73 ASSERT_EQ(expected_status
, status
);
74 ASSERT_EQ(expected_url
, url
);
78 void OnGetFileMetadata(const tracked_objects::Location
& where
,
79 const base::Closure
& oncompleted
,
80 SyncStatusCode
* status_out
,
81 SyncFileMetadata
* metadata_out
,
82 SyncStatusCode status
,
83 const SyncFileMetadata
& metadata
) {
84 SCOPED_TRACE(testing::Message() << where
.ToString());
86 *metadata_out
= metadata
;
90 ACTION_P(MockStatusCallback
, status
) {
91 base::ThreadTaskRunnerHandle::Get()->PostTask(
92 FROM_HERE
, base::Bind(arg4
, status
));
95 ACTION_P2(MockStatusCallbackAndRecordChange
, status
, changes
) {
96 base::ThreadTaskRunnerHandle::Get()->PostTask(
97 FROM_HERE
, base::Bind(arg4
, status
));
98 changes
->push_back(arg0
);
103 class LocalFileSyncServiceTest
104 : public testing::Test
,
105 public LocalFileSyncService::Observer
{
107 LocalFileSyncServiceTest()
108 : thread_bundle_(content::TestBrowserThreadBundle::REAL_FILE_THREAD
|
109 content::TestBrowserThreadBundle::REAL_IO_THREAD
),
112 void SetUp() override
{
113 ASSERT_TRUE(temp_dir_
.CreateUniqueTempDir());
114 in_memory_env_
.reset(leveldb::NewMemEnv(leveldb::Env::Default()));
116 file_system_
.reset(new CannedSyncableFileSystem(
118 in_memory_env_
.get(),
119 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO
),
120 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE)));
122 local_service_
= LocalFileSyncService::CreateForTesting(
123 &profile_
, in_memory_env_
.get());
125 file_system_
->SetUp(CannedSyncableFileSystem::QUOTA_ENABLED
);
127 base::RunLoop run_loop
;
128 SyncStatusCode status
= SYNC_STATUS_UNKNOWN
;
129 local_service_
->MaybeInitializeFileSystemContext(
130 GURL(kOrigin
), file_system_
->file_system_context(),
131 AssignAndQuitCallback(&run_loop
, &status
));
134 local_service_
->AddChangeObserver(this);
136 EXPECT_EQ(base::File::FILE_OK
, file_system_
->OpenFileSystem());
138 file_system_
->backend()->sync_context()->
139 set_mock_notify_changes_duration_in_sec(0);
142 void TearDown() override
{
143 local_service_
->Shutdown();
144 file_system_
->TearDown();
145 RevokeSyncableFileSystem();
146 content::RunAllPendingInMessageLoop(BrowserThread::FILE);
147 content::RunAllPendingInMessageLoop(BrowserThread::IO
);
150 // LocalChangeObserver overrides.
151 void OnLocalChangeAvailable(int64 num_changes
) override
{
152 num_changes_
= num_changes
;
155 void PrepareForProcessRemoteChange(
156 const FileSystemURL
& url
,
157 const tracked_objects::Location
& where
,
158 SyncStatusCode expected_status
,
159 const SyncFileMetadata
& expected_metadata
) {
160 base::RunLoop run_loop
;
161 local_service_
->PrepareForProcessRemoteChange(
163 base::Bind(&DidPrepareForProcessRemoteChange
,
165 run_loop
.QuitClosure(),
171 SyncStatusCode
ApplyRemoteChange(const FileChange
& change
,
172 const base::FilePath
& local_path
,
173 const FileSystemURL
& url
) {
174 SyncStatusCode sync_status
= SYNC_STATUS_UNKNOWN
;
176 base::RunLoop run_loop
;
177 local_service_
->ApplyRemoteChange(
178 change
, local_path
, url
,
179 AssignAndQuitCallback(&run_loop
, &sync_status
));
183 base::RunLoop run_loop
;
184 local_service_
->FinalizeRemoteSync(
186 sync_status
== SYNC_STATUS_OK
,
187 run_loop
.QuitClosure());
193 int64
GetNumChangesInTracker() const {
194 return file_system_
->backend()->change_tracker()->num_changes();
197 content::TestBrowserThreadBundle thread_bundle_
;
199 base::ScopedTempDir temp_dir_
;
200 scoped_ptr
<leveldb::Env
> in_memory_env_
;
201 TestingProfile profile_
;
203 scoped_ptr
<CannedSyncableFileSystem
> file_system_
;
204 scoped_ptr
<LocalFileSyncService
> local_service_
;
209 // More complete tests for PrepareForProcessRemoteChange and ApplyRemoteChange
210 // are also in content_unittest:LocalFileSyncContextTest.
211 TEST_F(LocalFileSyncServiceTest
, RemoteSyncStepsSimple
) {
212 const FileSystemURL
kFile(file_system_
->URL("file"));
213 const FileSystemURL
kDir(file_system_
->URL("dir"));
214 const char kTestFileData
[] = "0123456789";
215 const int kTestFileDataSize
= static_cast<int>(arraysize(kTestFileData
) - 1);
217 base::FilePath local_path
;
218 ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir_
.path(), &local_path
));
219 ASSERT_EQ(kTestFileDataSize
,
220 base::WriteFile(local_path
, kTestFileData
, kTestFileDataSize
));
222 // Run PrepareForProcessRemoteChange for kFile.
223 SyncFileMetadata expected_metadata
;
224 expected_metadata
.file_type
= SYNC_FILE_TYPE_UNKNOWN
;
225 expected_metadata
.size
= 0;
226 PrepareForProcessRemoteChange(kFile
, FROM_HERE
,
230 // Run ApplyRemoteChange for kFile.
231 FileChange
change(FileChange::FILE_CHANGE_ADD_OR_UPDATE
,
232 SYNC_FILE_TYPE_FILE
);
233 EXPECT_EQ(SYNC_STATUS_OK
,
234 ApplyRemoteChange(change
, local_path
, kFile
));
236 // Verify the file is synced.
237 EXPECT_EQ(base::File::FILE_OK
,
238 file_system_
->VerifyFile(kFile
, kTestFileData
));
240 // Run PrepareForProcessRemoteChange for kDir.
241 PrepareForProcessRemoteChange(kDir
, FROM_HERE
,
245 // Run ApplyRemoteChange for kDir.
246 change
= FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE
,
247 SYNC_FILE_TYPE_DIRECTORY
);
248 EXPECT_EQ(SYNC_STATUS_OK
,
249 ApplyRemoteChange(change
, base::FilePath(), kDir
));
251 // Verify the directory.
252 EXPECT_EQ(base::File::FILE_OK
,
253 file_system_
->DirectoryExists(kDir
));
255 // Run PrepareForProcessRemoteChange and ApplyRemoteChange for
256 // kDir once again for deletion.
257 expected_metadata
.file_type
= SYNC_FILE_TYPE_DIRECTORY
;
258 expected_metadata
.size
= 0;
259 PrepareForProcessRemoteChange(kDir
, FROM_HERE
,
263 change
= FileChange(FileChange::FILE_CHANGE_DELETE
, SYNC_FILE_TYPE_UNKNOWN
);
264 EXPECT_EQ(SYNC_STATUS_OK
, ApplyRemoteChange(change
, base::FilePath(), kDir
));
266 // Now the directory must have deleted.
267 EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND
,
268 file_system_
->DirectoryExists(kDir
));
271 TEST_F(LocalFileSyncServiceTest
, LocalChangeObserver
) {
272 const FileSystemURL
kFile(file_system_
->URL("file"));
273 const FileSystemURL
kDir(file_system_
->URL("dir"));
274 const char kTestFileData
[] = "0123456789";
275 const int kTestFileDataSize
= static_cast<int>(arraysize(kTestFileData
) - 1);
277 EXPECT_EQ(base::File::FILE_OK
, file_system_
->CreateFile(kFile
));
279 EXPECT_EQ(1, num_changes_
);
281 EXPECT_EQ(base::File::FILE_OK
, file_system_
->CreateDirectory(kDir
));
282 EXPECT_EQ(kTestFileDataSize
,
283 file_system_
->WriteString(kFile
, kTestFileData
));
285 EXPECT_EQ(2, num_changes_
);
289 // Flaky: http://crbug.com/171487
290 #define MAYBE_LocalChangeObserverMultipleContexts\
291 DISABLED_LocalChangeObserverMultipleContexts
293 #define MAYBE_LocalChangeObserverMultipleContexts\
294 LocalChangeObserverMultipleContexts
297 TEST_F(LocalFileSyncServiceTest
, MAYBE_LocalChangeObserverMultipleContexts
) {
298 const char kOrigin2
[] = "http://foo";
299 CannedSyncableFileSystem
file_system2(
301 in_memory_env_
.get(),
302 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO
),
303 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE));
304 file_system2
.SetUp(CannedSyncableFileSystem::QUOTA_ENABLED
);
306 base::RunLoop run_loop
;
307 SyncStatusCode status
= SYNC_STATUS_UNKNOWN
;
308 local_service_
->MaybeInitializeFileSystemContext(
309 GURL(kOrigin2
), file_system2
.file_system_context(),
310 AssignAndQuitCallback(&run_loop
, &status
));
313 EXPECT_EQ(base::File::FILE_OK
, file_system2
.OpenFileSystem());
314 file_system2
.backend()->sync_context()->
315 set_mock_notify_changes_duration_in_sec(0);
317 const FileSystemURL
kFile1(file_system_
->URL("file1"));
318 const FileSystemURL
kFile2(file_system_
->URL("file2"));
319 const FileSystemURL
kFile3(file_system2
.URL("file3"));
320 const FileSystemURL
kFile4(file_system2
.URL("file4"));
322 EXPECT_EQ(base::File::FILE_OK
, file_system_
->CreateFile(kFile1
));
323 EXPECT_EQ(base::File::FILE_OK
, file_system_
->CreateFile(kFile2
));
324 EXPECT_EQ(base::File::FILE_OK
, file_system2
.CreateFile(kFile3
));
325 EXPECT_EQ(base::File::FILE_OK
, file_system2
.CreateFile(kFile4
));
327 EXPECT_EQ(4, num_changes_
);
329 file_system2
.TearDown();
332 TEST_F(LocalFileSyncServiceTest
, ProcessLocalChange_CreateFile
) {
333 const FileSystemURL
kFile(file_system_
->URL("foo"));
334 const char kTestFileData
[] = "0123456789";
335 const int kTestFileDataSize
= static_cast<int>(arraysize(kTestFileData
) - 1);
337 base::RunLoop run_loop
;
339 // We should get called OnSyncEnabled and OnWriteEnabled on kFile.
340 // (OnWriteEnabled is called because we release lock before returning
341 // from ApplyLocalChange)
342 StrictMock
<MockSyncStatusObserver
> status_observer
;
343 EXPECT_CALL(status_observer
, OnSyncEnabled(kFile
)).Times(AtLeast(1));
344 EXPECT_CALL(status_observer
, OnWriteEnabled(kFile
)).Times(AtLeast(0));
345 file_system_
->AddSyncStatusObserver(&status_observer
);
347 // Creates and writes into a file.
348 EXPECT_EQ(base::File::FILE_OK
, file_system_
->CreateFile(kFile
));
349 EXPECT_EQ(kTestFileDataSize
,
350 file_system_
->WriteString(kFile
, std::string(kTestFileData
)));
352 // Retrieve the expected file info.
353 base::File::Info info
;
354 base::FilePath platform_path
;
355 EXPECT_EQ(base::File::FILE_OK
,
356 file_system_
->GetMetadataAndPlatformPath(
357 kFile
, &info
, &platform_path
));
359 ASSERT_FALSE(info
.is_directory
);
360 ASSERT_EQ(kTestFileDataSize
, info
.size
);
362 SyncFileMetadata metadata
;
363 metadata
.file_type
= SYNC_FILE_TYPE_FILE
;
364 metadata
.size
= info
.size
;
365 metadata
.last_modified
= info
.last_modified
;
367 // The local_change_processor's ApplyLocalChange should be called once
368 // with ADD_OR_UPDATE change for TYPE_FILE.
369 StrictMock
<MockLocalChangeProcessor
> local_change_processor
;
370 const FileChange
change(FileChange::FILE_CHANGE_ADD_OR_UPDATE
,
371 SYNC_FILE_TYPE_FILE
);
372 EXPECT_CALL(local_change_processor
,
373 ApplyLocalChange(change
, _
, metadata
, kFile
, _
))
374 .WillOnce(MockStatusCallback(SYNC_STATUS_OK
));
376 local_service_
->SetLocalChangeProcessor(&local_change_processor
);
377 local_service_
->ProcessLocalChange(
378 base::Bind(&OnSyncCompleted
, FROM_HERE
, run_loop
.QuitClosure(),
379 SYNC_STATUS_OK
, kFile
));
383 file_system_
->RemoveSyncStatusObserver(&status_observer
);
385 EXPECT_EQ(0, GetNumChangesInTracker());
388 TEST_F(LocalFileSyncServiceTest
, ProcessLocalChange_CreateAndRemoveFile
) {
389 const FileSystemURL
kFile(file_system_
->URL("foo"));
391 base::RunLoop run_loop
;
393 // We should get called OnSyncEnabled and possibly OnWriteEnabled (depends
394 // on timing) on kFile.
395 StrictMock
<MockSyncStatusObserver
> status_observer
;
396 EXPECT_CALL(status_observer
, OnSyncEnabled(kFile
)).Times(AtLeast(1));
397 EXPECT_CALL(status_observer
, OnWriteEnabled(kFile
)).Times(AtLeast(0));
398 file_system_
->AddSyncStatusObserver(&status_observer
);
400 // Creates and then deletes a file.
401 EXPECT_EQ(base::File::FILE_OK
, file_system_
->CreateFile(kFile
));
402 EXPECT_EQ(base::File::FILE_OK
, file_system_
->Remove(kFile
, false));
404 // The local_change_processor's ApplyLocalChange should be called once
405 // with DELETE change for TYPE_FILE.
406 // The file will NOT exist in the remote side and the processor might
407 // return SYNC_FILE_ERROR_NOT_FOUND (as mocked).
408 StrictMock
<MockLocalChangeProcessor
> local_change_processor
;
409 const FileChange
change(FileChange::FILE_CHANGE_DELETE
, SYNC_FILE_TYPE_FILE
);
410 EXPECT_CALL(local_change_processor
, ApplyLocalChange(change
, _
, _
, kFile
, _
))
411 .WillOnce(MockStatusCallback(SYNC_FILE_ERROR_NOT_FOUND
));
413 // The sync should succeed anyway.
414 local_service_
->SetLocalChangeProcessor(&local_change_processor
);
415 local_service_
->ProcessLocalChange(
416 base::Bind(&OnSyncCompleted
, FROM_HERE
, run_loop
.QuitClosure(),
417 SYNC_STATUS_OK
, kFile
));
421 file_system_
->RemoveSyncStatusObserver(&status_observer
);
423 EXPECT_EQ(0, GetNumChangesInTracker());
426 TEST_F(LocalFileSyncServiceTest
, ProcessLocalChange_CreateAndRemoveDirectory
) {
427 const FileSystemURL
kDir(file_system_
->URL("foo"));
429 base::RunLoop run_loop
;
431 // OnSyncEnabled is expected to be called at least or more than once.
432 StrictMock
<MockSyncStatusObserver
> status_observer
;
433 EXPECT_CALL(status_observer
, OnSyncEnabled(kDir
)).Times(AtLeast(1));
434 file_system_
->AddSyncStatusObserver(&status_observer
);
436 // Creates and then deletes a directory.
437 EXPECT_EQ(base::File::FILE_OK
, file_system_
->CreateDirectory(kDir
));
438 EXPECT_EQ(base::File::FILE_OK
, file_system_
->Remove(kDir
, false));
440 // The local_change_processor's ApplyLocalChange should never be called.
441 StrictMock
<MockLocalChangeProcessor
> local_change_processor
;
443 local_service_
->SetLocalChangeProcessor(&local_change_processor
);
444 local_service_
->ProcessLocalChange(
445 base::Bind(&OnSyncCompleted
, FROM_HERE
, run_loop
.QuitClosure(),
446 SYNC_STATUS_NO_CHANGE_TO_SYNC
, FileSystemURL()));
450 file_system_
->RemoveSyncStatusObserver(&status_observer
);
452 EXPECT_EQ(0, GetNumChangesInTracker());
455 TEST_F(LocalFileSyncServiceTest
, ProcessLocalChange_MultipleChanges
) {
456 const FileSystemURL
kPath(file_system_
->URL("foo"));
457 const FileSystemURL
kOther(file_system_
->URL("bar"));
459 base::RunLoop run_loop
;
461 // We should get called OnSyncEnabled and OnWriteEnabled on kPath and
462 // OnSyncEnabled on kOther.
463 StrictMock
<MockSyncStatusObserver
> status_observer
;
464 EXPECT_CALL(status_observer
, OnSyncEnabled(kPath
)).Times(AtLeast(1));
465 EXPECT_CALL(status_observer
, OnSyncEnabled(kOther
)).Times(AtLeast(1));
466 file_system_
->AddSyncStatusObserver(&status_observer
);
468 // Creates a file, delete the file and creates a directory with the same
470 EXPECT_EQ(base::File::FILE_OK
, file_system_
->CreateFile(kPath
));
471 EXPECT_EQ(base::File::FILE_OK
, file_system_
->Remove(kPath
, false));
472 EXPECT_EQ(base::File::FILE_OK
, file_system_
->CreateDirectory(kPath
));
474 // Creates one more file.
475 EXPECT_EQ(base::File::FILE_OK
, file_system_
->CreateFile(kOther
));
477 // The local_change_processor's ApplyLocalChange will be called
478 // twice for FILE_TYPE and FILE_DIRECTORY.
479 StrictMock
<MockLocalChangeProcessor
> local_change_processor
;
480 std::vector
<FileChange
> changes
;
481 EXPECT_CALL(local_change_processor
, ApplyLocalChange(_
, _
, _
, kPath
, _
))
483 .WillOnce(MockStatusCallbackAndRecordChange(SYNC_STATUS_OK
, &changes
))
484 .WillOnce(MockStatusCallbackAndRecordChange(SYNC_STATUS_OK
, &changes
));
485 local_service_
->SetLocalChangeProcessor(&local_change_processor
);
487 // OnWriteEnabled will be notified on kPath (in multi-threaded this
488 // could be delayed, so AtLeast(0)).
489 EXPECT_CALL(status_observer
, OnWriteEnabled(kPath
)).Times(AtLeast(0));
491 local_service_
->ProcessLocalChange(
492 base::Bind(&OnSyncCompleted
, FROM_HERE
, run_loop
.QuitClosure(),
493 SYNC_STATUS_OK
, kPath
));
497 EXPECT_EQ(2U, changes
.size());
498 EXPECT_EQ(FileChange(FileChange::FILE_CHANGE_DELETE
, SYNC_FILE_TYPE_FILE
),
500 EXPECT_EQ(FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE
,
501 SYNC_FILE_TYPE_DIRECTORY
),
504 file_system_
->RemoveSyncStatusObserver(&status_observer
);
506 // We have one more change for kOther.
507 EXPECT_EQ(1, GetNumChangesInTracker());
510 TEST_F(LocalFileSyncServiceTest
, ProcessLocalChange_GetLocalMetadata
) {
511 const FileSystemURL
kURL(file_system_
->URL("foo"));
512 const base::Time kTime
= base::Time::FromDoubleT(333);
513 const int kSize
= 555;
515 base::RunLoop run_loop
;
518 EXPECT_EQ(base::File::FILE_OK
, file_system_
->CreateFile(kURL
));
519 EXPECT_EQ(base::File::FILE_OK
, file_system_
->TruncateFile(kURL
, kSize
));
520 EXPECT_EQ(base::File::FILE_OK
,
521 file_system_
->TouchFile(kURL
, base::Time(), kTime
));
523 SyncStatusCode status
= SYNC_STATUS_UNKNOWN
;
524 SyncFileMetadata metadata
;
525 local_service_
->GetLocalFileMetadata(
527 base::Bind(&OnGetFileMetadata
, FROM_HERE
, run_loop
.QuitClosure(),
528 &status
, &metadata
));
532 EXPECT_EQ(SYNC_STATUS_OK
, status
);
533 EXPECT_EQ(kTime
, metadata
.last_modified
);
534 EXPECT_EQ(kSize
, metadata
.size
);
537 TEST_F(LocalFileSyncServiceTest
, RecordFakeChange
) {
538 const FileSystemURL
kURL(file_system_
->URL("foo"));
540 // Create a file and reset the changes (as preparation).
541 EXPECT_EQ(base::File::FILE_OK
, file_system_
->CreateFile(kURL
));
542 file_system_
->ClearChangeForURLInTracker(kURL
);
544 EXPECT_EQ(0, GetNumChangesInTracker());
546 storage::FileSystemURLSet urlset
;
547 file_system_
->GetChangedURLsInTracker(&urlset
);
548 EXPECT_TRUE(urlset
.empty());
550 const FileChange
change(FileChange::FILE_CHANGE_ADD_OR_UPDATE
,
551 SYNC_FILE_TYPE_FILE
);
553 // Call RecordFakeLocalChange to add an ADD_OR_UPDATE change.
555 base::RunLoop run_loop
;
556 SyncStatusCode status
= SYNC_STATUS_UNKNOWN
;
557 local_service_
->RecordFakeLocalChange(
558 kURL
, change
, AssignAndQuitCallback(&run_loop
, &status
));
560 EXPECT_EQ(SYNC_STATUS_OK
, status
);
563 EXPECT_EQ(1, GetNumChangesInTracker());
564 file_system_
->GetChangedURLsInTracker(&urlset
);
565 EXPECT_EQ(1U, urlset
.size());
566 EXPECT_TRUE(urlset
.find(kURL
) != urlset
.end());
568 // Next local sync should pick up the recorded change.
569 StrictMock
<MockLocalChangeProcessor
> local_change_processor
;
570 std::vector
<FileChange
> changes
;
571 EXPECT_CALL(local_change_processor
, ApplyLocalChange(_
, _
, _
, kURL
, _
))
572 .WillOnce(MockStatusCallbackAndRecordChange(SYNC_STATUS_OK
, &changes
));
574 base::RunLoop run_loop
;
575 local_service_
->SetLocalChangeProcessor(&local_change_processor
);
576 local_service_
->ProcessLocalChange(
577 base::Bind(&OnSyncCompleted
, FROM_HERE
, run_loop
.QuitClosure(),
578 SYNC_STATUS_OK
, kURL
));
582 EXPECT_EQ(1U, changes
.size());
583 EXPECT_EQ(change
, changes
[0]);
586 // TODO(kinuko): Add tests for multiple file changes and multiple
587 // FileSystemContexts.
589 // Unit test for OriginChangeMap ---------------------------------------------
591 class OriginChangeMapTest
: public testing::Test
{
593 OriginChangeMapTest() {}
594 ~OriginChangeMapTest() override
{}
596 bool NextOriginToProcess(GURL
* origin
) {
597 return map_
.NextOriginToProcess(origin
);
600 int64
GetTotalChangeCount() const {
601 return map_
.GetTotalChangeCount();
604 void SetOriginChangeCount(const GURL
& origin
, int64 changes
) {
605 map_
.SetOriginChangeCount(origin
, changes
);
608 void SetOriginEnabled(const GURL
& origin
, bool enabled
) {
609 map_
.SetOriginEnabled(origin
, enabled
);
612 LocalFileSyncService::OriginChangeMap map_
;
615 TEST_F(OriginChangeMapTest
, Basic
) {
616 const GURL
kOrigin1("chrome-extension://foo");
617 const GURL
kOrigin2("chrome-extension://bar");
618 const GURL
kOrigin3("chrome-extension://baz");
620 ASSERT_EQ(0, GetTotalChangeCount());
622 SetOriginChangeCount(kOrigin1
, 1);
623 SetOriginChangeCount(kOrigin2
, 2);
625 ASSERT_EQ(1 + 2, GetTotalChangeCount());
627 SetOriginChangeCount(kOrigin3
, 4);
629 ASSERT_EQ(1 + 2 + 4, GetTotalChangeCount());
631 const GURL kOrigins
[] = { kOrigin1
, kOrigin2
, kOrigin3
};
632 std::set
<GURL
> all_origins
;
633 all_origins
.insert(kOrigins
, kOrigins
+ arraysize(kOrigins
));
636 while (!all_origins
.empty()) {
637 ASSERT_TRUE(NextOriginToProcess(&origin
));
638 ASSERT_TRUE(ContainsKey(all_origins
, origin
));
639 all_origins
.erase(origin
);
642 // Set kOrigin2's change count 0.
643 SetOriginChangeCount(kOrigin2
, 0);
644 ASSERT_EQ(1 + 4, GetTotalChangeCount());
646 // kOrigin2 won't return this time.
647 all_origins
.insert(kOrigin1
);
648 all_origins
.insert(kOrigin3
);
649 while (!all_origins
.empty()) {
650 ASSERT_TRUE(NextOriginToProcess(&origin
));
651 ASSERT_TRUE(ContainsKey(all_origins
, origin
));
652 all_origins
.erase(origin
);
655 // Calling NextOriginToProcess() again will just return
656 // the same set of origins (as far as we don't change the
658 all_origins
.insert(kOrigin1
);
659 all_origins
.insert(kOrigin3
);
660 while (!all_origins
.empty()) {
661 ASSERT_TRUE(NextOriginToProcess(&origin
));
662 ASSERT_TRUE(ContainsKey(all_origins
, origin
));
663 all_origins
.erase(origin
);
666 // Set kOrigin2's change count 8.
667 SetOriginChangeCount(kOrigin2
, 8);
668 ASSERT_EQ(1 + 4 + 8, GetTotalChangeCount());
670 all_origins
.insert(kOrigins
, kOrigins
+ arraysize(kOrigins
));
671 while (!all_origins
.empty()) {
672 ASSERT_TRUE(NextOriginToProcess(&origin
));
673 ASSERT_TRUE(ContainsKey(all_origins
, origin
));
674 all_origins
.erase(origin
);
678 TEST_F(OriginChangeMapTest
, WithDisabled
) {
679 const GURL
kOrigin1("chrome-extension://foo");
680 const GURL
kOrigin2("chrome-extension://bar");
681 const GURL
kOrigin3("chrome-extension://baz");
682 const GURL kOrigins
[] = { kOrigin1
, kOrigin2
, kOrigin3
};
684 ASSERT_EQ(0, GetTotalChangeCount());
686 SetOriginChangeCount(kOrigin1
, 1);
687 SetOriginChangeCount(kOrigin2
, 2);
688 SetOriginChangeCount(kOrigin3
, 4);
690 ASSERT_EQ(1 + 2 + 4, GetTotalChangeCount());
692 std::set
<GURL
> all_origins
;
693 all_origins
.insert(kOrigins
, kOrigins
+ arraysize(kOrigins
));
696 while (!all_origins
.empty()) {
697 ASSERT_TRUE(NextOriginToProcess(&origin
));
698 ASSERT_TRUE(ContainsKey(all_origins
, origin
));
699 all_origins
.erase(origin
);
702 SetOriginEnabled(kOrigin2
, false);
703 ASSERT_EQ(1 + 4, GetTotalChangeCount());
705 // kOrigin2 won't return this time.
706 all_origins
.insert(kOrigin1
);
707 all_origins
.insert(kOrigin3
);
708 while (!all_origins
.empty()) {
709 ASSERT_TRUE(NextOriginToProcess(&origin
));
710 ASSERT_TRUE(ContainsKey(all_origins
, origin
));
711 all_origins
.erase(origin
);
714 // kOrigin1 and kOrigin2 are now disabled.
715 SetOriginEnabled(kOrigin1
, false);
716 ASSERT_EQ(4, GetTotalChangeCount());
718 ASSERT_TRUE(NextOriginToProcess(&origin
));
719 ASSERT_EQ(kOrigin3
, origin
);
721 // Re-enable kOrigin2.
722 SetOriginEnabled(kOrigin2
, true);
723 ASSERT_EQ(2 + 4, GetTotalChangeCount());
725 // kOrigin1 won't return this time.
726 all_origins
.insert(kOrigin2
);
727 all_origins
.insert(kOrigin3
);
728 while (!all_origins
.empty()) {
729 ASSERT_TRUE(NextOriginToProcess(&origin
));
730 ASSERT_TRUE(ContainsKey(all_origins
, origin
));
731 all_origins
.erase(origin
);
735 } // namespace sync_file_system