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 "base/basictypes.h"
7 #include "base/file_util.h"
8 #include "base/location.h"
9 #include "base/message_loop_proxy.h"
10 #include "base/run_loop.h"
11 #include "base/stl_util.h"
12 #include "base/threading/thread.h"
13 #include "chrome/browser/sync_file_system/local_file_sync_service.h"
14 #include "chrome/browser/sync_file_system/mock_local_change_processor.h"
15 #include "chrome/browser/sync_file_system/sync_file_system_test_util.h"
16 #include "chrome/test/base/testing_profile.h"
17 #include "testing/gmock/include/gmock/gmock.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19 #include "webkit/fileapi/file_system_context.h"
20 #include "webkit/fileapi/syncable/canned_syncable_file_system.h"
21 #include "webkit/fileapi/syncable/file_change.h"
22 #include "webkit/fileapi/syncable/local_file_change_tracker.h"
23 #include "webkit/fileapi/syncable/local_file_sync_context.h"
24 #include "webkit/fileapi/syncable/local_file_sync_status.h"
25 #include "webkit/fileapi/syncable/mock_sync_status_observer.h"
26 #include "webkit/fileapi/syncable/sync_file_metadata.h"
27 #include "webkit/fileapi/syncable/sync_status_code.h"
28 #include "webkit/fileapi/syncable/syncable_file_system_util.h"
30 using fileapi::FileSystemURL
;
32 using ::testing::AtLeast
;
33 using ::testing::InvokeWithoutArgs
;
34 using ::testing::StrictMock
;
36 namespace sync_file_system
{
40 const char kOrigin
[] = "http://example.com";
41 const char kServiceName
[] = "test";
43 void DidPrepareForProcessRemoteChange(const tracked_objects::Location
& where
,
44 const base::Closure
& oncompleted
,
45 SyncStatusCode expected_status
,
46 const SyncFileMetadata
& expected_metadata
,
47 SyncStatusCode status
,
48 const SyncFileMetadata
& metadata
,
49 const FileChangeList
& changes
) {
50 SCOPED_TRACE(testing::Message() << where
.ToString());
51 ASSERT_EQ(expected_status
, status
);
52 ASSERT_EQ(expected_metadata
.file_type
, metadata
.file_type
);
53 ASSERT_EQ(expected_metadata
.size
, metadata
.size
);
54 ASSERT_TRUE(changes
.empty());
58 void OnSyncCompleted(const tracked_objects::Location
& where
,
59 const base::Closure
& oncompleted
,
60 SyncStatusCode expected_status
,
61 const FileSystemURL
& expected_url
,
62 SyncStatusCode status
,
63 const FileSystemURL
& url
) {
64 SCOPED_TRACE(testing::Message() << where
.ToString());
65 ASSERT_EQ(expected_status
, status
);
66 ASSERT_EQ(expected_url
, url
);
70 void OnGetFileMetadata(const tracked_objects::Location
& where
,
71 const base::Closure
& oncompleted
,
72 SyncStatusCode
* status_out
,
73 SyncFileMetadata
* metadata_out
,
74 SyncStatusCode status
,
75 const SyncFileMetadata
& metadata
) {
76 SCOPED_TRACE(testing::Message() << where
.ToString());
78 *metadata_out
= metadata
;
82 ACTION_P(MockStatusCallback
, status
) {
83 base::MessageLoopProxy::current()->PostTask(
84 FROM_HERE
, base::Bind(arg4
, status
));
87 ACTION_P2(MockStatusCallbackAndRecordChange
, status
, changes
) {
88 base::MessageLoopProxy::current()->PostTask(
89 FROM_HERE
, base::Bind(arg4
, status
));
90 changes
->push_back(arg0
);
95 class LocalFileSyncServiceTest
96 : public testing::Test
,
97 public LocalFileSyncService::Observer
{
99 LocalFileSyncServiceTest() : num_changes_(0) {}
101 virtual ~LocalFileSyncServiceTest() {}
103 virtual void SetUp() OVERRIDE
{
104 ASSERT_TRUE(temp_dir_
.CreateUniqueTempDir());
106 thread_helper_
.SetUp();
108 file_system_
.reset(new CannedSyncableFileSystem(
109 GURL(kOrigin
), kServiceName
,
110 thread_helper_
.io_task_runner(),
111 thread_helper_
.file_task_runner()));
113 local_service_
.reset(new LocalFileSyncService(&profile_
));
115 file_system_
->SetUp();
117 base::RunLoop run_loop
;
118 SyncStatusCode status
= SYNC_STATUS_UNKNOWN
;
119 local_service_
->MaybeInitializeFileSystemContext(
120 GURL(kOrigin
), kServiceName
, file_system_
->file_system_context(),
121 AssignAndQuitCallback(&run_loop
, &status
));
124 local_service_
->AddChangeObserver(this);
126 EXPECT_EQ(base::PLATFORM_FILE_OK
, file_system_
->OpenFileSystem());
128 file_system_
->file_system_context()->sync_context()->
129 set_mock_notify_changes_duration_in_sec(0);
132 virtual void TearDown() OVERRIDE
{
133 local_service_
->Shutdown();
134 file_system_
->TearDown();
135 RevokeSyncableFileSystem(kServiceName
);
137 thread_helper_
.TearDown();
140 // LocalChangeObserver overrides.
141 virtual void OnLocalChangeAvailable(int64 num_changes
) OVERRIDE
{
142 num_changes_
= num_changes
;
145 void PrepareForProcessRemoteChange(
146 const FileSystemURL
& url
,
147 const tracked_objects::Location
& where
,
148 SyncStatusCode expected_status
,
149 const SyncFileMetadata
& expected_metadata
) {
150 base::RunLoop run_loop
;
151 local_service_
->PrepareForProcessRemoteChange(
154 base::Bind(&DidPrepareForProcessRemoteChange
,
156 run_loop
.QuitClosure(),
162 SyncStatusCode
ApplyRemoteChange(const FileChange
& change
,
163 const base::FilePath
& local_path
,
164 const FileSystemURL
& url
) {
165 base::RunLoop run_loop
;
166 SyncStatusCode sync_status
= SYNC_STATUS_UNKNOWN
;
167 local_service_
->ApplyRemoteChange(
168 change
, local_path
, url
,
169 AssignAndQuitCallback(&run_loop
, &sync_status
));
174 int64
GetNumChangesInTracker() const {
175 return file_system_
->file_system_context()->change_tracker()->num_changes();
178 TestingProfile profile_
;
180 MultiThreadTestHelper thread_helper_
;
182 base::ScopedTempDir temp_dir_
;
184 scoped_ptr
<CannedSyncableFileSystem
> file_system_
;
185 scoped_ptr
<LocalFileSyncService
> local_service_
;
190 // More complete tests for PrepareForProcessRemoteChange and ApplyRemoteChange
191 // are also in content_unittest:LocalFileSyncContextTest.
192 TEST_F(LocalFileSyncServiceTest
, RemoteSyncStepsSimple
) {
193 const FileSystemURL
kFile(file_system_
->URL("file"));
194 const FileSystemURL
kDir(file_system_
->URL("dir"));
195 const char kTestFileData
[] = "0123456789";
196 const int kTestFileDataSize
= static_cast<int>(arraysize(kTestFileData
) - 1);
198 base::FilePath local_path
;
199 ASSERT_TRUE(file_util::CreateTemporaryFileInDir(temp_dir_
.path(),
201 ASSERT_EQ(kTestFileDataSize
,
202 file_util::WriteFile(local_path
, kTestFileData
, kTestFileDataSize
));
204 // Run PrepareForProcessRemoteChange for kFile.
205 SyncFileMetadata expected_metadata
;
206 expected_metadata
.file_type
= SYNC_FILE_TYPE_UNKNOWN
;
207 expected_metadata
.size
= 0;
208 PrepareForProcessRemoteChange(kFile
, FROM_HERE
,
212 // Run ApplyRemoteChange for kFile.
213 FileChange
change(FileChange::FILE_CHANGE_ADD_OR_UPDATE
,
214 SYNC_FILE_TYPE_FILE
);
215 EXPECT_EQ(SYNC_STATUS_OK
,
216 ApplyRemoteChange(change
, local_path
, kFile
));
218 // Verify the file is synced.
219 EXPECT_EQ(base::PLATFORM_FILE_OK
,
220 file_system_
->VerifyFile(kFile
, kTestFileData
));
222 // Run PrepareForProcessRemoteChange for kDir.
223 PrepareForProcessRemoteChange(kDir
, FROM_HERE
,
227 // Run ApplyRemoteChange for kDir.
228 change
= FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE
,
229 SYNC_FILE_TYPE_DIRECTORY
);
230 EXPECT_EQ(SYNC_STATUS_OK
,
231 ApplyRemoteChange(change
, base::FilePath(), kDir
));
233 // Verify the directory.
234 EXPECT_EQ(base::PLATFORM_FILE_OK
,
235 file_system_
->DirectoryExists(kDir
));
237 // Run PrepareForProcessRemoteChange and ApplyRemoteChange for
238 // kDir once again for deletion.
239 expected_metadata
.file_type
= SYNC_FILE_TYPE_DIRECTORY
;
240 expected_metadata
.size
= 0;
241 PrepareForProcessRemoteChange(kDir
, FROM_HERE
,
245 change
= FileChange(FileChange::FILE_CHANGE_DELETE
, SYNC_FILE_TYPE_UNKNOWN
);
246 EXPECT_EQ(SYNC_STATUS_OK
, ApplyRemoteChange(change
, base::FilePath(), kDir
));
248 // Now the directory must have deleted.
249 EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND
,
250 file_system_
->DirectoryExists(kDir
));
253 TEST_F(LocalFileSyncServiceTest
, LocalChangeObserver
) {
254 const FileSystemURL
kFile(file_system_
->URL("file"));
255 const FileSystemURL
kDir(file_system_
->URL("dir"));
256 const char kTestFileData
[] = "0123456789";
257 const int kTestFileDataSize
= static_cast<int>(arraysize(kTestFileData
) - 1);
259 EXPECT_EQ(base::PLATFORM_FILE_OK
, file_system_
->CreateFile(kFile
));
261 EXPECT_EQ(1, num_changes_
);
263 EXPECT_EQ(base::PLATFORM_FILE_OK
, file_system_
->CreateDirectory(kDir
));
264 EXPECT_EQ(kTestFileDataSize
,
265 file_system_
->WriteString(kFile
, kTestFileData
));
267 EXPECT_EQ(2, num_changes_
);
271 // Flaky: http://crbug.com/171487
272 #define MAYBE_LocalChangeObserverMultipleContexts\
273 DISABLED_LocalChangeObserverMultipleContexts
275 #define MAYBE_LocalChangeObserverMultipleContexts\
276 LocalChangeObserverMultipleContexts
279 TEST_F(LocalFileSyncServiceTest
, MAYBE_LocalChangeObserverMultipleContexts
) {
280 const char kOrigin2
[] = "http://foo";
281 CannedSyncableFileSystem
file_system2(GURL(kOrigin2
),
283 thread_helper_
.io_task_runner(),
284 thread_helper_
.file_task_runner());
285 file_system2
.SetUp();
287 base::RunLoop run_loop
;
288 SyncStatusCode status
= SYNC_STATUS_UNKNOWN
;
289 local_service_
->MaybeInitializeFileSystemContext(
290 GURL(kOrigin2
), kServiceName
, file_system2
.file_system_context(),
291 AssignAndQuitCallback(&run_loop
, &status
));
294 EXPECT_EQ(base::PLATFORM_FILE_OK
, file_system2
.OpenFileSystem());
295 file_system2
.file_system_context()->sync_context()->
296 set_mock_notify_changes_duration_in_sec(0);
298 const FileSystemURL
kFile1(file_system_
->URL("file1"));
299 const FileSystemURL
kFile2(file_system_
->URL("file2"));
300 const FileSystemURL
kFile3(file_system2
.URL("file3"));
301 const FileSystemURL
kFile4(file_system2
.URL("file4"));
303 EXPECT_EQ(base::PLATFORM_FILE_OK
, file_system_
->CreateFile(kFile1
));
304 EXPECT_EQ(base::PLATFORM_FILE_OK
, file_system_
->CreateFile(kFile2
));
305 EXPECT_EQ(base::PLATFORM_FILE_OK
, file_system2
.CreateFile(kFile3
));
306 EXPECT_EQ(base::PLATFORM_FILE_OK
, file_system2
.CreateFile(kFile4
));
308 EXPECT_EQ(4, num_changes_
);
310 file_system2
.TearDown();
313 TEST_F(LocalFileSyncServiceTest
, ProcessLocalChange_CreateFile
) {
314 const FileSystemURL
kFile(file_system_
->URL("foo"));
315 const char kTestFileData
[] = "0123456789";
316 const int kTestFileDataSize
= static_cast<int>(arraysize(kTestFileData
) - 1);
318 base::RunLoop run_loop
;
320 // We should get called OnSyncEnabled on kFile.
321 StrictMock
<MockSyncStatusObserver
> status_observer
;
322 EXPECT_CALL(status_observer
, OnSyncEnabled(kFile
))
324 file_system_
->AddSyncStatusObserver(&status_observer
);
326 // Creates and writes into a file.
327 EXPECT_EQ(base::PLATFORM_FILE_OK
, file_system_
->CreateFile(kFile
));
328 EXPECT_EQ(kTestFileDataSize
,
329 file_system_
->WriteString(kFile
, std::string(kTestFileData
)));
331 // Retrieve the expected platform_path.
332 base::PlatformFileInfo info
;
333 base::FilePath platform_path
;
334 EXPECT_EQ(base::PLATFORM_FILE_OK
,
335 file_system_
->GetMetadata(kFile
, &info
, &platform_path
));
337 ASSERT_FALSE(info
.is_directory
);
338 ASSERT_EQ(kTestFileDataSize
, info
.size
);
340 SyncFileMetadata metadata
;
341 metadata
.file_type
= SYNC_FILE_TYPE_FILE
;
342 metadata
.size
= info
.size
;
343 metadata
.last_modified
= info
.last_modified
;
345 // The local_change_processor's ApplyLocalChange should be called once
346 // with ADD_OR_UPDATE change for TYPE_FILE.
347 StrictMock
<MockLocalChangeProcessor
> local_change_processor
;
348 const FileChange
change(FileChange::FILE_CHANGE_ADD_OR_UPDATE
,
349 SYNC_FILE_TYPE_FILE
);
350 EXPECT_CALL(local_change_processor
,
351 ApplyLocalChange(change
, platform_path
, metadata
, kFile
, _
))
352 .WillOnce(MockStatusCallback(SYNC_STATUS_OK
));
354 local_service_
->SetLocalChangeProcessor(&local_change_processor
);
355 local_service_
->ProcessLocalChange(
356 base::Bind(&OnSyncCompleted
, FROM_HERE
, run_loop
.QuitClosure(),
357 SYNC_STATUS_OK
, kFile
));
361 file_system_
->RemoveSyncStatusObserver(&status_observer
);
363 EXPECT_EQ(0, GetNumChangesInTracker());
366 TEST_F(LocalFileSyncServiceTest
, ProcessLocalChange_CreateAndRemoveFile
) {
367 const FileSystemURL
kFile(file_system_
->URL("foo"));
369 base::RunLoop run_loop
;
371 // We should get called OnSyncEnabled and OnWriteEnabled on kFile.
372 StrictMock
<MockSyncStatusObserver
> status_observer
;
373 EXPECT_CALL(status_observer
, OnSyncEnabled(kFile
))
375 file_system_
->AddSyncStatusObserver(&status_observer
);
377 // Creates and then deletes a file.
378 EXPECT_EQ(base::PLATFORM_FILE_OK
, file_system_
->CreateFile(kFile
));
379 EXPECT_EQ(base::PLATFORM_FILE_OK
, file_system_
->Remove(kFile
, false));
381 // The local_change_processor's ApplyLocalChange should be called once
382 // with DELETE change for TYPE_FILE.
383 // The file will NOT exist in the remote side and the processor might
384 // return SYNC_FILE_ERROR_NOT_FOUND (as mocked).
385 StrictMock
<MockLocalChangeProcessor
> local_change_processor
;
386 const FileChange
change(FileChange::FILE_CHANGE_DELETE
, SYNC_FILE_TYPE_FILE
);
387 EXPECT_CALL(local_change_processor
, ApplyLocalChange(change
, _
, _
, kFile
, _
))
388 .WillOnce(MockStatusCallback(SYNC_FILE_ERROR_NOT_FOUND
));
390 // The sync should succeed anyway.
391 local_service_
->SetLocalChangeProcessor(&local_change_processor
);
392 local_service_
->ProcessLocalChange(
393 base::Bind(&OnSyncCompleted
, FROM_HERE
, run_loop
.QuitClosure(),
394 SYNC_STATUS_OK
, kFile
));
398 file_system_
->RemoveSyncStatusObserver(&status_observer
);
400 EXPECT_EQ(0, GetNumChangesInTracker());
403 TEST_F(LocalFileSyncServiceTest
, ProcessLocalChange_CreateAndRemoveDirectory
) {
404 const FileSystemURL
kDir(file_system_
->URL("foo"));
406 base::RunLoop run_loop
;
408 // OnSyncEnabled is expected to be called at least or more than once.
409 StrictMock
<MockSyncStatusObserver
> status_observer
;
410 EXPECT_CALL(status_observer
, OnSyncEnabled(kDir
)).Times(AtLeast(1));
411 file_system_
->AddSyncStatusObserver(&status_observer
);
413 // Creates and then deletes a directory.
414 EXPECT_EQ(base::PLATFORM_FILE_OK
, file_system_
->CreateDirectory(kDir
));
415 EXPECT_EQ(base::PLATFORM_FILE_OK
, file_system_
->Remove(kDir
, false));
417 // The local_change_processor's ApplyLocalChange should never be called.
418 StrictMock
<MockLocalChangeProcessor
> local_change_processor
;
420 local_service_
->SetLocalChangeProcessor(&local_change_processor
);
421 local_service_
->ProcessLocalChange(
422 base::Bind(&OnSyncCompleted
, FROM_HERE
, run_loop
.QuitClosure(),
423 SYNC_STATUS_NO_CHANGE_TO_SYNC
, FileSystemURL()));
427 file_system_
->RemoveSyncStatusObserver(&status_observer
);
429 EXPECT_EQ(0, GetNumChangesInTracker());
432 TEST_F(LocalFileSyncServiceTest
, ProcessLocalChange_MultipleChanges
) {
433 const FileSystemURL
kPath(file_system_
->URL("foo"));
434 const FileSystemURL
kOther(file_system_
->URL("bar"));
436 base::RunLoop run_loop
;
438 // We should get called OnSyncEnabled and OnWriteEnabled on kPath and
439 // OnSyncEnabled on kOther.
440 StrictMock
<MockSyncStatusObserver
> status_observer
;
441 EXPECT_CALL(status_observer
, OnSyncEnabled(kPath
)).Times(AtLeast(1));
442 EXPECT_CALL(status_observer
, OnSyncEnabled(kOther
)).Times(AtLeast(1));
443 file_system_
->AddSyncStatusObserver(&status_observer
);
445 // Creates a file, delete the file and creates a directory with the same
447 EXPECT_EQ(base::PLATFORM_FILE_OK
, file_system_
->CreateFile(kPath
));
448 EXPECT_EQ(base::PLATFORM_FILE_OK
, file_system_
->Remove(kPath
, false));
449 EXPECT_EQ(base::PLATFORM_FILE_OK
, file_system_
->CreateDirectory(kPath
));
451 // Creates one more file.
452 EXPECT_EQ(base::PLATFORM_FILE_OK
, file_system_
->CreateFile(kOther
));
454 // The local_change_processor's ApplyLocalChange will be called
455 // twice for FILE_TYPE and FILE_DIRECTORY.
456 StrictMock
<MockLocalChangeProcessor
> local_change_processor
;
457 std::vector
<FileChange
> changes
;
458 EXPECT_CALL(local_change_processor
, ApplyLocalChange(_
, _
, _
, kPath
, _
))
460 .WillOnce(MockStatusCallbackAndRecordChange(SYNC_STATUS_OK
, &changes
))
461 .WillOnce(MockStatusCallbackAndRecordChange(SYNC_STATUS_OK
, &changes
));
462 local_service_
->SetLocalChangeProcessor(&local_change_processor
);
463 local_service_
->ProcessLocalChange(
464 base::Bind(&OnSyncCompleted
, FROM_HERE
, run_loop
.QuitClosure(),
465 SYNC_STATUS_OK
, kPath
));
469 EXPECT_EQ(2U, changes
.size());
470 EXPECT_EQ(FileChange(FileChange::FILE_CHANGE_DELETE
, SYNC_FILE_TYPE_FILE
),
472 EXPECT_EQ(FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE
,
473 SYNC_FILE_TYPE_DIRECTORY
),
476 file_system_
->RemoveSyncStatusObserver(&status_observer
);
478 // We have one more change for kOther.
479 EXPECT_EQ(1, GetNumChangesInTracker());
482 TEST_F(LocalFileSyncServiceTest
, ProcessLocalChange_GetLocalMetadata
) {
483 const FileSystemURL
kURL(file_system_
->URL("foo"));
484 const base::Time kTime
= base::Time::FromDoubleT(333);
485 const int kSize
= 555;
487 base::RunLoop run_loop
;
490 EXPECT_EQ(base::PLATFORM_FILE_OK
, file_system_
->CreateFile(kURL
));
491 EXPECT_EQ(base::PLATFORM_FILE_OK
, file_system_
->TruncateFile(kURL
, kSize
));
492 EXPECT_EQ(base::PLATFORM_FILE_OK
,
493 file_system_
->TouchFile(kURL
, base::Time(), kTime
));
495 SyncStatusCode status
= SYNC_STATUS_UNKNOWN
;
496 SyncFileMetadata metadata
;
497 local_service_
->GetLocalFileMetadata(
499 base::Bind(&OnGetFileMetadata
, FROM_HERE
, run_loop
.QuitClosure(),
500 &status
, &metadata
));
504 EXPECT_EQ(SYNC_STATUS_OK
, status
);
505 EXPECT_EQ(kTime
, metadata
.last_modified
);
506 EXPECT_EQ(kSize
, metadata
.size
);
509 TEST_F(LocalFileSyncServiceTest
, RecordFakeChange
) {
510 const FileSystemURL
kURL(file_system_
->URL("foo"));
512 // Create a file and reset the changes (as preparation).
513 EXPECT_EQ(base::PLATFORM_FILE_OK
, file_system_
->CreateFile(kURL
));
514 file_system_
->ClearChangeForURLInTracker(kURL
);
516 EXPECT_EQ(0, GetNumChangesInTracker());
518 fileapi::FileSystemURLSet urlset
;
519 file_system_
->GetChangedURLsInTracker(&urlset
);
520 EXPECT_TRUE(urlset
.empty());
522 const FileChange
change(FileChange::FILE_CHANGE_ADD_OR_UPDATE
,
523 SYNC_FILE_TYPE_FILE
);
525 // Call RecordFakeLocalChange to add an ADD_OR_UPDATE change.
527 base::RunLoop run_loop
;
528 SyncStatusCode status
= SYNC_STATUS_UNKNOWN
;
529 local_service_
->RecordFakeLocalChange(
530 kURL
, change
, AssignAndQuitCallback(&run_loop
, &status
));
532 EXPECT_EQ(SYNC_STATUS_OK
, status
);
535 EXPECT_EQ(1, GetNumChangesInTracker());
536 file_system_
->GetChangedURLsInTracker(&urlset
);
537 EXPECT_EQ(1U, urlset
.size());
538 EXPECT_TRUE(urlset
.find(kURL
) != urlset
.end());
540 // Next local sync should pick up the recorded change.
541 StrictMock
<MockLocalChangeProcessor
> local_change_processor
;
542 std::vector
<FileChange
> changes
;
543 EXPECT_CALL(local_change_processor
, ApplyLocalChange(_
, _
, _
, kURL
, _
))
544 .WillOnce(MockStatusCallbackAndRecordChange(SYNC_STATUS_OK
, &changes
));
546 base::RunLoop run_loop
;
547 local_service_
->SetLocalChangeProcessor(&local_change_processor
);
548 local_service_
->ProcessLocalChange(
549 base::Bind(&OnSyncCompleted
, FROM_HERE
, run_loop
.QuitClosure(),
550 SYNC_STATUS_OK
, kURL
));
554 EXPECT_EQ(1U, changes
.size());
555 EXPECT_EQ(change
, changes
[0]);
558 // TODO(kinuko): Add tests for multiple file changes and multiple
559 // FileSystemContexts.
561 // Unit test for OriginChangeMap ---------------------------------------------
563 class OriginChangeMapTest
: public testing::Test
{
565 OriginChangeMapTest() {}
566 virtual ~OriginChangeMapTest() {}
568 bool NextOriginToProcess(GURL
* origin
) {
569 return map_
.NextOriginToProcess(origin
);
572 int64
GetTotalChangeCount() const {
573 return map_
.GetTotalChangeCount();
576 void SetOriginChangeCount(const GURL
& origin
, int64 changes
) {
577 map_
.SetOriginChangeCount(origin
, changes
);
580 void SetOriginEnabled(const GURL
& origin
, bool enabled
) {
581 map_
.SetOriginEnabled(origin
, enabled
);
584 LocalFileSyncService::OriginChangeMap map_
;
587 TEST_F(OriginChangeMapTest
, Basic
) {
588 const GURL
kOrigin1("chrome-extension://foo");
589 const GURL
kOrigin2("chrome-extension://bar");
590 const GURL
kOrigin3("chrome-extension://baz");
592 ASSERT_EQ(0, GetTotalChangeCount());
594 SetOriginChangeCount(kOrigin1
, 1);
595 SetOriginChangeCount(kOrigin2
, 2);
597 ASSERT_EQ(1 + 2, GetTotalChangeCount());
599 SetOriginChangeCount(kOrigin3
, 4);
601 ASSERT_EQ(1 + 2 + 4, GetTotalChangeCount());
603 const GURL kOrigins
[] = { kOrigin1
, kOrigin2
, kOrigin3
};
604 std::set
<GURL
> all_origins
;
605 all_origins
.insert(kOrigins
, kOrigins
+ ARRAYSIZE_UNSAFE(kOrigins
));
608 while (!all_origins
.empty()) {
609 ASSERT_TRUE(NextOriginToProcess(&origin
));
610 ASSERT_TRUE(ContainsKey(all_origins
, origin
));
611 all_origins
.erase(origin
);
614 // Set kOrigin2's change count 0.
615 SetOriginChangeCount(kOrigin2
, 0);
616 ASSERT_EQ(1 + 4, GetTotalChangeCount());
618 // kOrigin2 won't return this time.
619 all_origins
.insert(kOrigin1
);
620 all_origins
.insert(kOrigin3
);
621 while (!all_origins
.empty()) {
622 ASSERT_TRUE(NextOriginToProcess(&origin
));
623 ASSERT_TRUE(ContainsKey(all_origins
, origin
));
624 all_origins
.erase(origin
);
627 // Calling NextOriginToProcess() again will just return
628 // the same set of origins (as far as we don't change the
630 all_origins
.insert(kOrigin1
);
631 all_origins
.insert(kOrigin3
);
632 while (!all_origins
.empty()) {
633 ASSERT_TRUE(NextOriginToProcess(&origin
));
634 ASSERT_TRUE(ContainsKey(all_origins
, origin
));
635 all_origins
.erase(origin
);
638 // Set kOrigin2's change count 8.
639 SetOriginChangeCount(kOrigin2
, 8);
640 ASSERT_EQ(1 + 4 + 8, GetTotalChangeCount());
642 all_origins
.insert(kOrigins
, kOrigins
+ ARRAYSIZE_UNSAFE(kOrigins
));
643 while (!all_origins
.empty()) {
644 ASSERT_TRUE(NextOriginToProcess(&origin
));
645 ASSERT_TRUE(ContainsKey(all_origins
, origin
));
646 all_origins
.erase(origin
);
650 TEST_F(OriginChangeMapTest
, WithDisabled
) {
651 const GURL
kOrigin1("chrome-extension://foo");
652 const GURL
kOrigin2("chrome-extension://bar");
653 const GURL
kOrigin3("chrome-extension://baz");
654 const GURL kOrigins
[] = { kOrigin1
, kOrigin2
, kOrigin3
};
656 ASSERT_EQ(0, GetTotalChangeCount());
658 SetOriginChangeCount(kOrigin1
, 1);
659 SetOriginChangeCount(kOrigin2
, 2);
660 SetOriginChangeCount(kOrigin3
, 4);
662 ASSERT_EQ(1 + 2 + 4, GetTotalChangeCount());
664 std::set
<GURL
> all_origins
;
665 all_origins
.insert(kOrigins
, kOrigins
+ ARRAYSIZE_UNSAFE(kOrigins
));
668 while (!all_origins
.empty()) {
669 ASSERT_TRUE(NextOriginToProcess(&origin
));
670 ASSERT_TRUE(ContainsKey(all_origins
, origin
));
671 all_origins
.erase(origin
);
674 SetOriginEnabled(kOrigin2
, false);
675 ASSERT_EQ(1 + 4, GetTotalChangeCount());
677 // kOrigin2 won't return this time.
678 all_origins
.insert(kOrigin1
);
679 all_origins
.insert(kOrigin3
);
680 while (!all_origins
.empty()) {
681 ASSERT_TRUE(NextOriginToProcess(&origin
));
682 ASSERT_TRUE(ContainsKey(all_origins
, origin
));
683 all_origins
.erase(origin
);
686 // kOrigin1 and kOrigin2 are now disabled.
687 SetOriginEnabled(kOrigin1
, false);
688 ASSERT_EQ(4, GetTotalChangeCount());
690 ASSERT_TRUE(NextOriginToProcess(&origin
));
691 ASSERT_EQ(kOrigin3
, origin
);
693 // Re-enable kOrigin2.
694 SetOriginEnabled(kOrigin2
, true);
695 ASSERT_EQ(2 + 4, GetTotalChangeCount());
697 // kOrigin1 won't return this time.
698 all_origins
.insert(kOrigin2
);
699 all_origins
.insert(kOrigin3
);
700 while (!all_origins
.empty()) {
701 ASSERT_TRUE(NextOriginToProcess(&origin
));
702 ASSERT_TRUE(ContainsKey(all_origins
, origin
));
703 all_origins
.erase(origin
);
707 } // namespace sync_file_system