Check USB device path access when prompting users to select a device.
[chromium-blink-merge.git] / chrome / browser / sync_file_system / local / local_file_sync_service_unittest.cc
blob67c7088a759b60efe9aaa412047c8b8683112e3a
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 <vector>
7 #include "base/basictypes.h"
8 #include "base/bind.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;
40 using ::testing::_;
41 using ::testing::AtLeast;
42 using ::testing::InvokeWithoutArgs;
43 using ::testing::StrictMock;
45 namespace sync_file_system {
47 namespace {
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());
63 oncompleted.Run();
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);
75 oncompleted.Run();
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());
85 *status_out = status;
86 *metadata_out = metadata;
87 oncompleted.Run();
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);
101 } // namespace
103 class LocalFileSyncServiceTest
104 : public testing::Test,
105 public LocalFileSyncService::Observer {
106 protected:
107 LocalFileSyncServiceTest()
108 : thread_bundle_(content::TestBrowserThreadBundle::REAL_FILE_THREAD |
109 content::TestBrowserThreadBundle::REAL_IO_THREAD),
110 num_changes_(0) {}
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(
117 GURL(kOrigin),
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));
132 run_loop.Run();
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(
162 url,
163 base::Bind(&DidPrepareForProcessRemoteChange,
164 where,
165 run_loop.QuitClosure(),
166 expected_status,
167 expected_metadata));
168 run_loop.Run();
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));
180 run_loop.Run();
183 base::RunLoop run_loop;
184 local_service_->FinalizeRemoteSync(
185 url,
186 sync_status == SYNC_STATUS_OK,
187 run_loop.QuitClosure());
188 run_loop.Run();
190 return sync_status;
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_;
206 int64 num_changes_;
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,
227 SYNC_STATUS_OK,
228 expected_metadata);
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,
242 SYNC_STATUS_OK,
243 expected_metadata);
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,
260 SYNC_STATUS_OK,
261 expected_metadata);
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_);
288 #if defined(OS_WIN)
289 // Flaky: http://crbug.com/171487
290 #define MAYBE_LocalChangeObserverMultipleContexts\
291 DISABLED_LocalChangeObserverMultipleContexts
292 #else
293 #define MAYBE_LocalChangeObserverMultipleContexts\
294 LocalChangeObserverMultipleContexts
295 #endif
297 TEST_F(LocalFileSyncServiceTest, MAYBE_LocalChangeObserverMultipleContexts) {
298 const char kOrigin2[] = "http://foo";
299 CannedSyncableFileSystem file_system2(
300 GURL(kOrigin2),
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));
311 run_loop.Run();
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));
381 run_loop.Run();
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));
419 run_loop.Run();
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()));
448 run_loop.Run();
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
469 // name.
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, _))
482 .Times(2)
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));
495 run_loop.Run();
497 EXPECT_EQ(2U, changes.size());
498 EXPECT_EQ(FileChange(FileChange::FILE_CHANGE_DELETE, SYNC_FILE_TYPE_FILE),
499 changes[0]);
500 EXPECT_EQ(FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
501 SYNC_FILE_TYPE_DIRECTORY),
502 changes[1]);
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;
517 // Creates a file.
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(
526 kURL,
527 base::Bind(&OnGetFileMetadata, FROM_HERE, run_loop.QuitClosure(),
528 &status, &metadata));
530 run_loop.Run();
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));
559 run_loop.Run();
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));
579 run_loop.Run();
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 {
592 protected:
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));
635 GURL origin;
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
657 // change count).
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));
695 GURL origin;
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