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 "sync/internal_api/public/read_node.h"
9 #include "sync/internal_api/public/read_transaction.h"
10 #include "sync/internal_api/public/sessions/sync_session_snapshot.h"
11 #include "sync/internal_api/public/test/test_internal_components_factory.h"
12 #include "sync/internal_api/public/write_node.h"
13 #include "sync/internal_api/public/write_transaction.h"
14 #include "sync/internal_api/sync_backup_manager.h"
15 #include "sync/syncable/entry.h"
16 #include "sync/test/engine/fake_model_worker.h"
17 #include "sync/test/test_directory_backing_store.h"
18 #include "testing/gmock/include/gmock/gmock.h"
19 #include "testing/gtest/include/gtest/gtest.h"
22 using ::testing::DoDefault
;
23 using ::testing::Invoke
;
24 using ::testing::Truly
;
25 using ::testing::WithArgs
;
31 class TestChangeDelegate
: public SyncManager::ChangeDelegate
{
33 TestChangeDelegate() {
34 ON_CALL(*this, OnChangesApplied(_
, _
, _
, _
))
36 WithArgs
<3>(Invoke(this,
37 &TestChangeDelegate::VerifyDeletes
)));
40 void add_expected_delete(int64 v
) {
41 expected_deletes_
.insert(v
);
44 MOCK_METHOD4(OnChangesApplied
,
45 void(ModelType model_type
,
47 const BaseTransaction
* trans
,
48 const ImmutableChangeRecordList
& changes
));
49 MOCK_METHOD1(OnChangesComplete
, void(ModelType model_type
));
52 void VerifyDeletes(const ImmutableChangeRecordList
& changes
) {
53 std::set
<int64
> deleted
;
54 for (size_t i
= 0; i
< changes
.Get().size(); ++i
) {
55 const ChangeRecord
& change
= (changes
.Get())[i
];
56 EXPECT_EQ(ChangeRecord::ACTION_DELETE
, change
.action
);
57 EXPECT_TRUE(deleted
.find(change
.id
) == deleted
.end());
58 deleted
.insert(change
.id
);
60 EXPECT_TRUE(expected_deletes_
== deleted
);
63 std::set
<int64
> expected_deletes_
;
66 class SyncRollbackManagerTest
: public testing::Test
,
67 public SyncManager::Observer
{
69 virtual void SetUp() OVERRIDE
{
70 CHECK(temp_dir_
.CreateUniqueTempDir());
72 worker_
= new FakeModelWorker(GROUP_UI
);
75 MOCK_METHOD1(OnSyncCycleCompleted
,
76 void(const sessions::SyncSessionSnapshot
&));
77 MOCK_METHOD1(OnConnectionStatusChange
, void(ConnectionStatus
));
78 MOCK_METHOD4(OnInitializationComplete
,
79 void(const WeakHandle
<JsBackend
>&,
80 const WeakHandle
<DataTypeDebugInfoListener
>&,
82 MOCK_METHOD1(OnActionableError
, void(const SyncProtocolError
&));
83 MOCK_METHOD1(OnMigrationRequested
, void(ModelTypeSet
));;
84 MOCK_METHOD1(OnProtocolEvent
, void(const ProtocolEvent
&));
86 void OnConfigDone(bool success
) {
90 int64
CreateEntry(UserShare
* user_share
, ModelType type
,
91 const std::string
& client_tag
) {
92 WriteTransaction
trans(FROM_HERE
, user_share
);
93 ReadNode
type_root(&trans
);
94 EXPECT_EQ(BaseNode::INIT_OK
,
95 type_root
.InitByTagLookup(ModelTypeToRootTag(type
)));
97 WriteNode
node(&trans
);
98 EXPECT_EQ(WriteNode::INIT_SUCCESS
,
99 node
.InitUniqueByCreation(type
, type_root
, client_tag
));
100 return node
.GetEntry()->GetMetahandle();
103 void InitManager(SyncManager
* manager
, ModelTypeSet types
,
104 TestChangeDelegate
* delegate
) {
105 manager
->AddObserver(this);
106 TestInternalComponentsFactory
factory(InternalComponentsFactory::Switches(),
109 manager
->Init(temp_dir_
.path(),
110 MakeWeakHandle(base::WeakPtr
<JsEventHandler
>()),
111 "", 0, true, scoped_ptr
<HttpPostProviderFactory
>().Pass(),
112 std::vector
<scoped_refptr
<ModelSafeWorker
> >(1,
114 NULL
, delegate
, SyncCredentials(), "", "", "", &factory
,
115 NULL
, scoped_ptr
<UnrecoverableErrorHandler
>().Pass(),
117 manager
->ConfigureSyncer(
118 CONFIGURE_REASON_NEW_CLIENT
,
120 ModelTypeSet(), ModelTypeSet(), ModelTypeSet(), ModelSafeRoutingInfo(),
121 base::Bind(&SyncRollbackManagerTest::OnConfigDone
,
122 base::Unretained(this), true),
123 base::Bind(&SyncRollbackManagerTest::OnConfigDone
,
124 base::Unretained(this), false));
127 // Create and persist an entry by unique tag in DB.
128 void PrepopulateDb(ModelType type
, const std::string
& client_tag
) {
129 SyncBackupManager backup_manager
;
130 TestChangeDelegate delegate
;
131 InitManager(&backup_manager
, ModelTypeSet(type
), &delegate
);
132 CreateEntry(backup_manager
.GetUserShare(), type
, client_tag
);
133 backup_manager
.ShutdownOnSyncThread();
136 // Verify entry with |client_tag| exists in sync directory.
137 bool VerifyEntry(UserShare
* user_share
, ModelType type
,
138 const std::string
& client_tag
) {
139 ReadTransaction
trans(FROM_HERE
, user_share
);
140 ReadNode
node(&trans
);
141 return BaseNode::INIT_OK
== node
.InitByClientTagLookup(type
, client_tag
);
144 base::ScopedTempDir temp_dir_
;
145 scoped_refptr
<ModelSafeWorker
> worker_
;
146 base::MessageLoop loop_
; // Needed for WeakHandle
149 bool IsRollbackDoneAction(SyncProtocolError e
) {
150 return e
.action
== syncer::ROLLBACK_DONE
;
153 TEST_F(SyncRollbackManagerTest
, RollbackBasic
) {
154 PrepopulateDb(PREFERENCES
, "pref1");
156 TestChangeDelegate delegate
;
157 SyncRollbackManager rollback_manager
;
158 InitManager(&rollback_manager
, ModelTypeSet(PREFERENCES
), &delegate
);
160 // Simulate a new entry added during type initialization.
162 CreateEntry(rollback_manager
.GetUserShare(), PREFERENCES
, "pref2");
164 delegate
.add_expected_delete(new_pref_id
);
165 EXPECT_CALL(delegate
, OnChangesApplied(_
, _
, _
, _
))
167 .WillOnce(DoDefault());
168 EXPECT_CALL(delegate
, OnChangesComplete(_
)).Times(1);
169 EXPECT_CALL(*this, OnActionableError(Truly(IsRollbackDoneAction
))).Times(1);
171 ModelSafeRoutingInfo routing_info
;
172 routing_info
[PREFERENCES
] = GROUP_UI
;
173 rollback_manager
.StartSyncingNormally(routing_info
);
176 TEST_F(SyncRollbackManagerTest
, NoRollbackOfTypesNotBackedUp
) {
177 PrepopulateDb(PREFERENCES
, "pref1");
179 TestChangeDelegate delegate
;
180 SyncRollbackManager rollback_manager
;
181 InitManager(&rollback_manager
, ModelTypeSet(PREFERENCES
, APPS
), &delegate
);
183 // Simulate new entry added during type initialization.
185 CreateEntry(rollback_manager
.GetUserShare(), PREFERENCES
, "pref2");
186 CreateEntry(rollback_manager
.GetUserShare(), APPS
, "app1");
188 delegate
.add_expected_delete(new_pref_id
);
189 EXPECT_CALL(delegate
, OnChangesApplied(_
, _
, _
, _
))
191 .WillOnce(DoDefault());
192 EXPECT_CALL(delegate
, OnChangesComplete(_
)).Times(1);
194 ModelSafeRoutingInfo routing_info
;
195 routing_info
[PREFERENCES
] = GROUP_UI
;
196 rollback_manager
.StartSyncingNormally(routing_info
);
198 // APP entry is still valid.
199 EXPECT_TRUE(VerifyEntry(rollback_manager
.GetUserShare(), APPS
, "app1"));
202 TEST_F(SyncRollbackManagerTest
, BackupDbNotChangedOnAbort
) {
203 PrepopulateDb(PREFERENCES
, "pref1");
205 TestChangeDelegate delegate
;
206 scoped_ptr
<SyncRollbackManager
> rollback_manager(
207 new SyncRollbackManager
);
208 InitManager(rollback_manager
.get(), ModelTypeSet(PREFERENCES
), &delegate
);
210 // Simulate a new entry added during type initialization.
211 CreateEntry(rollback_manager
->GetUserShare(), PREFERENCES
, "pref2");
213 // Manager was shut down before sync starts.
214 rollback_manager
->ShutdownOnSyncThread();
216 // Verify new entry was not persisted.
217 rollback_manager
.reset(new SyncRollbackManager
);
218 InitManager(rollback_manager
.get(), ModelTypeSet(PREFERENCES
), &delegate
);
219 EXPECT_FALSE(VerifyEntry(rollback_manager
->GetUserShare(), PREFERENCES
,
223 } // anonymous namespace
225 } // namespace syncer