1 // Copyright 2014 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 "sync/internal_api/sync_rollback_manager.h"
7 #include "base/files/scoped_temp_dir.h"
8 #include "base/run_loop.h"
9 #include "sync/internal_api/public/read_node.h"
10 #include "sync/internal_api/public/read_transaction.h"
11 #include "sync/internal_api/public/sessions/sync_session_snapshot.h"
12 #include "sync/internal_api/public/test/test_internal_components_factory.h"
13 #include "sync/internal_api/public/write_node.h"
14 #include "sync/internal_api/public/write_transaction.h"
15 #include "sync/internal_api/sync_backup_manager.h"
16 #include "sync/syncable/entry.h"
17 #include "sync/test/engine/fake_model_worker.h"
18 #include "sync/test/test_directory_backing_store.h"
19 #include "testing/gmock/include/gmock/gmock.h"
20 #include "testing/gtest/include/gtest/gtest.h"
24 using ::testing::DoDefault
;
25 using ::testing::Invoke
;
26 using ::testing::Truly
;
27 using ::testing::WithArgs
;
33 class TestChangeDelegate
: public SyncManager::ChangeDelegate
{
35 TestChangeDelegate() {
36 ON_CALL(*this, OnChangesApplied(_
, _
, _
, _
))
38 WithArgs
<3>(Invoke(this,
39 &TestChangeDelegate::VerifyDeletes
)));
42 void add_expected_delete(int64 v
) {
43 expected_deletes_
.insert(v
);
46 MOCK_METHOD4(OnChangesApplied
,
47 void(ModelType model_type
,
49 const BaseTransaction
* trans
,
50 const ImmutableChangeRecordList
& changes
));
51 MOCK_METHOD1(OnChangesComplete
, void(ModelType model_type
));
54 void VerifyDeletes(const ImmutableChangeRecordList
& changes
) {
55 std::set
<int64
> deleted
;
56 for (size_t i
= 0; i
< changes
.Get().size(); ++i
) {
57 const ChangeRecord
& change
= (changes
.Get())[i
];
58 EXPECT_EQ(ChangeRecord::ACTION_DELETE
, change
.action
);
59 EXPECT_TRUE(deleted
.find(change
.id
) == deleted
.end());
60 deleted
.insert(change
.id
);
62 EXPECT_TRUE(expected_deletes_
== deleted
);
65 std::set
<int64
> expected_deletes_
;
68 class SyncRollbackManagerTest
: public testing::Test
,
69 public SyncManager::Observer
{
71 void SetUp() override
{
72 CHECK(temp_dir_
.CreateUniqueTempDir());
74 worker_
= new FakeModelWorker(GROUP_UI
);
77 MOCK_METHOD1(OnSyncCycleCompleted
,
78 void(const sessions::SyncSessionSnapshot
&));
79 MOCK_METHOD1(OnConnectionStatusChange
, void(ConnectionStatus
));
80 MOCK_METHOD4(OnInitializationComplete
,
81 void(const WeakHandle
<JsBackend
>&,
82 const WeakHandle
<DataTypeDebugInfoListener
>&,
84 MOCK_METHOD1(OnActionableError
, void(const SyncProtocolError
&));
85 MOCK_METHOD1(OnMigrationRequested
, void(ModelTypeSet
));;
86 MOCK_METHOD1(OnProtocolEvent
, void(const ProtocolEvent
&));
88 void OnConfigDone(bool success
) {
92 int64
CreateEntry(UserShare
* user_share
, ModelType type
,
93 const std::string
& client_tag
) {
94 WriteTransaction
trans(FROM_HERE
, user_share
);
95 ReadNode
type_root(&trans
);
96 EXPECT_EQ(BaseNode::INIT_OK
, type_root
.InitTypeRoot(type
));
98 WriteNode
node(&trans
);
99 EXPECT_EQ(WriteNode::INIT_SUCCESS
,
100 node
.InitUniqueByCreation(type
, type_root
, client_tag
));
101 return node
.GetEntry()->GetMetahandle();
104 void InitManager(SyncManager
* manager
, ModelTypeSet types
,
105 TestChangeDelegate
* delegate
,
106 InternalComponentsFactory::StorageOption storage_option
) {
110 EXPECT_CALL(*this, OnInitializationComplete(_
, _
, _
, _
))
111 .WillOnce(WithArgs
<2>(Invoke(this,
112 &SyncRollbackManagerTest::HandleInit
)));
114 manager
->AddObserver(this);
116 base::RunLoop run_loop
;
117 SyncManager::InitArgs args
;
118 args
.database_location
= temp_dir_
.path();
119 args
.service_url
= GURL("https://example.com/");
120 args
.workers
.push_back(worker_
);
121 args
.change_delegate
= delegate
;
123 InternalComponentsFactory::StorageOption storage_used
;
124 args
.internal_components_factory
.reset(new TestInternalComponentsFactory(
125 InternalComponentsFactory::Switches(), storage_option
, &storage_used
));
126 manager
->Init(&args
);
127 EXPECT_EQ(storage_option
, storage_used
);
128 loop_
.PostTask(FROM_HERE
, run_loop
.QuitClosure());
132 // Create and persist an entry by unique tag in DB.
133 void PrepopulateDb(ModelType type
, const std::string
& client_tag
) {
134 SyncBackupManager backup_manager
;
135 TestChangeDelegate delegate
;
136 InitManager(&backup_manager
, ModelTypeSet(type
), &delegate
,
137 InternalComponentsFactory::STORAGE_ON_DISK_DEFERRED
);
138 CreateEntry(backup_manager
.GetUserShare(), type
, client_tag
);
139 backup_manager
.ShutdownOnSyncThread(SWITCH_MODE_SYNC
);
142 // Verify entry with |client_tag| exists in sync directory.
143 bool VerifyEntry(UserShare
* user_share
, ModelType type
,
144 const std::string
& client_tag
) {
145 ReadTransaction
trans(FROM_HERE
, user_share
);
146 ReadNode
node(&trans
);
147 return BaseNode::INIT_OK
== node
.InitByClientTagLookup(type
, client_tag
);
151 void ConfigureSyncer() {
152 manager_
->ConfigureSyncer(
153 CONFIGURE_REASON_NEW_CLIENT
,
155 ModelTypeSet(), ModelTypeSet(), ModelTypeSet(),
156 ModelSafeRoutingInfo(),
157 base::Bind(&SyncRollbackManagerTest::OnConfigDone
,
158 base::Unretained(this), true),
159 base::Bind(&SyncRollbackManagerTest::OnConfigDone
,
160 base::Unretained(this), false));
163 void HandleInit(bool success
) {
165 loop_
.PostTask(FROM_HERE
,
166 base::Bind(&SyncRollbackManagerTest::ConfigureSyncer
,
167 base::Unretained(this)));
169 manager_
->ShutdownOnSyncThread(STOP_SYNC
);
173 base::ScopedTempDir temp_dir_
;
174 scoped_refptr
<ModelSafeWorker
> worker_
;
175 base::MessageLoop loop_
; // Needed for WeakHandle
176 SyncManager
* manager_
;
180 bool IsRollbackDoneAction(SyncProtocolError e
) {
181 return e
.action
== syncer::ROLLBACK_DONE
;
184 TEST_F(SyncRollbackManagerTest
, RollbackBasic
) {
185 PrepopulateDb(PREFERENCES
, "pref1");
187 TestChangeDelegate delegate
;
188 SyncRollbackManager rollback_manager
;
189 InitManager(&rollback_manager
, ModelTypeSet(PREFERENCES
), &delegate
,
190 InternalComponentsFactory::STORAGE_ON_DISK
);
192 // Simulate a new entry added during type initialization.
194 CreateEntry(rollback_manager
.GetUserShare(), PREFERENCES
, "pref2");
196 delegate
.add_expected_delete(new_pref_id
);
197 EXPECT_CALL(delegate
, OnChangesApplied(_
, _
, _
, _
))
199 .WillOnce(DoDefault());
200 EXPECT_CALL(delegate
, OnChangesComplete(_
)).Times(1);
201 EXPECT_CALL(*this, OnActionableError(Truly(IsRollbackDoneAction
))).Times(1);
203 ModelSafeRoutingInfo routing_info
;
204 routing_info
[PREFERENCES
] = GROUP_UI
;
205 rollback_manager
.StartSyncingNormally(routing_info
);
208 TEST_F(SyncRollbackManagerTest
, NoRollbackOfTypesNotBackedUp
) {
209 PrepopulateDb(PREFERENCES
, "pref1");
211 TestChangeDelegate delegate
;
212 SyncRollbackManager rollback_manager
;
213 InitManager(&rollback_manager
, ModelTypeSet(PREFERENCES
, APPS
), &delegate
,
214 InternalComponentsFactory::STORAGE_ON_DISK
);
216 // Simulate new entry added during type initialization.
218 CreateEntry(rollback_manager
.GetUserShare(), PREFERENCES
, "pref2");
219 CreateEntry(rollback_manager
.GetUserShare(), APPS
, "app1");
221 delegate
.add_expected_delete(new_pref_id
);
222 EXPECT_CALL(delegate
, OnChangesApplied(_
, _
, _
, _
))
224 .WillOnce(DoDefault());
225 EXPECT_CALL(delegate
, OnChangesComplete(_
)).Times(1);
227 ModelSafeRoutingInfo routing_info
;
228 routing_info
[PREFERENCES
] = GROUP_UI
;
229 rollback_manager
.StartSyncingNormally(routing_info
);
231 // APP entry is still valid.
232 EXPECT_TRUE(VerifyEntry(rollback_manager
.GetUserShare(), APPS
, "app1"));
235 TEST_F(SyncRollbackManagerTest
, BackupDbNotChangedOnAbort
) {
236 PrepopulateDb(PREFERENCES
, "pref1");
238 TestChangeDelegate delegate
;
239 scoped_ptr
<SyncRollbackManager
> rollback_manager(
240 new SyncRollbackManager
);
241 InitManager(rollback_manager
.get(), ModelTypeSet(PREFERENCES
), &delegate
,
242 InternalComponentsFactory::STORAGE_ON_DISK
);
244 // Simulate a new entry added during type initialization.
245 CreateEntry(rollback_manager
->GetUserShare(), PREFERENCES
, "pref2");
247 // Manager was shut down before sync starts.
248 rollback_manager
->ShutdownOnSyncThread(STOP_SYNC
);
250 // Verify new entry was not persisted.
251 rollback_manager
.reset(new SyncRollbackManager
);
252 InitManager(rollback_manager
.get(), ModelTypeSet(PREFERENCES
), &delegate
,
253 InternalComponentsFactory::STORAGE_ON_DISK
);
254 EXPECT_FALSE(VerifyEntry(rollback_manager
->GetUserShare(), PREFERENCES
,
258 TEST_F(SyncRollbackManagerTest
, OnInitializationFailure
) {
259 // Test graceful shutdown on initialization failure.
260 scoped_ptr
<SyncRollbackManager
> rollback_manager(
261 new SyncRollbackManager
);
262 InitManager(rollback_manager
.get(), ModelTypeSet(PREFERENCES
), NULL
,
263 InternalComponentsFactory::STORAGE_ON_DISK
);
266 } // anonymous namespace
268 } // namespace syncer