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/engine/directory_commit_contribution.h"
7 #include "base/message_loop/message_loop.h"
8 #include "sync/sessions/status_controller.h"
9 #include "sync/syncable/entry.h"
10 #include "sync/syncable/mutable_entry.h"
11 #include "sync/syncable/syncable_read_transaction.h"
12 #include "sync/syncable/syncable_write_transaction.h"
13 #include "sync/test/engine/test_directory_setter_upper.h"
14 #include "sync/test/engine/test_id_factory.h"
15 #include "sync/test/engine/test_syncable_utils.h"
16 #include "testing/gtest/include/gtest/gtest.h"
20 class DirectoryCommitContributionTest
: public ::testing::Test
{
22 virtual void SetUp() OVERRIDE
{
25 syncable::WriteTransaction
trans(FROM_HERE
, syncable::UNITTEST
, dir());
26 CreateTypeRoot(&trans
, dir(), PREFERENCES
);
27 CreateTypeRoot(&trans
, dir(), EXTENSIONS
);
30 virtual void TearDown() OVERRIDE
{
31 dir_maker_
.TearDown();
35 int64
CreateUnsyncedItem(syncable::WriteTransaction
* trans
,
37 const std::string
& tag
) {
38 syncable::Entry
parent_entry(
40 syncable::GET_BY_SERVER_TAG
,
41 ModelTypeToRootTag(type
));
42 syncable::MutableEntry
entry(
48 entry
.PutIsUnsynced(true);
49 return entry
.GetMetahandle();
52 void CreateSuccessfulCommitResponse(
53 const sync_pb::SyncEntity
& entity
,
54 sync_pb::CommitResponse::EntryResponse
* response
) {
55 response
->set_response_type(sync_pb::CommitResponse::SUCCESS
);
56 response
->set_non_unique_name(entity
.name());
57 response
->set_version(entity
.version() + 1);
58 response
->set_parent_id_string(entity
.parent_id_string());
60 if (entity
.id_string()[0] == '-') // Look for the - in 'c-1234' style IDs.
61 response
->set_id_string(id_factory_
.NewServerId().GetServerId());
63 response
->set_id_string(entity
.id_string());
66 syncable::Directory
* dir() {
67 return dir_maker_
.directory();
70 TestIdFactory id_factory_
;
73 base::MessageLoop loop_
; // Neeed to initialize the directory.
74 TestDirectorySetterUpper dir_maker_
;
77 // Verify that the DirectoryCommitContribution contains only entries of its
79 TEST_F(DirectoryCommitContributionTest
, GatherByTypes
) {
82 syncable::WriteTransaction
trans(FROM_HERE
, syncable::UNITTEST
, dir());
83 pref1
= CreateUnsyncedItem(&trans
, PREFERENCES
, "pref1");
84 CreateUnsyncedItem(&trans
, PREFERENCES
, "pref2");
85 CreateUnsyncedItem(&trans
, EXTENSIONS
, "extension1");
88 DirectoryTypeDebugInfoEmitter emitter
;
89 scoped_ptr
<DirectoryCommitContribution
> cc(
90 DirectoryCommitContribution::Build(dir(), PREFERENCES
, 5, &emitter
));
91 ASSERT_EQ(2U, cc
->GetNumEntries());
93 const std::vector
<int64
>& metahandles
= cc
->metahandles_
;
94 EXPECT_TRUE(std::find(metahandles
.begin(), metahandles
.end(), pref1
) !=
96 EXPECT_TRUE(std::find(metahandles
.begin(), metahandles
.end(), pref1
) !=
102 // Verify that the DirectoryCommitContributionTest builder function
103 // truncates if necessary.
104 TEST_F(DirectoryCommitContributionTest
, GatherAndTruncate
) {
108 syncable::WriteTransaction
trans(FROM_HERE
, syncable::UNITTEST
, dir());
109 pref1
= CreateUnsyncedItem(&trans
, PREFERENCES
, "pref1");
110 pref2
= CreateUnsyncedItem(&trans
, PREFERENCES
, "pref2");
111 CreateUnsyncedItem(&trans
, EXTENSIONS
, "extension1");
114 DirectoryTypeDebugInfoEmitter emitter
;
115 scoped_ptr
<DirectoryCommitContribution
> cc(
116 DirectoryCommitContribution::Build(dir(), PREFERENCES
, 1, &emitter
));
117 ASSERT_EQ(1U, cc
->GetNumEntries());
119 int64 only_metahandle
= cc
->metahandles_
[0];
120 EXPECT_TRUE(only_metahandle
== pref1
|| only_metahandle
== pref2
);
125 // Sanity check for building commits from DirectoryCommitContributions.
126 // This test makes two CommitContribution objects of different types and uses
127 // them to initialize a commit message. Then it checks that the contents of the
128 // commit message match those of the directory they came from.
129 TEST_F(DirectoryCommitContributionTest
, PrepareCommit
) {
131 syncable::WriteTransaction
trans(FROM_HERE
, syncable::UNITTEST
, dir());
132 CreateUnsyncedItem(&trans
, PREFERENCES
, "pref1");
133 CreateUnsyncedItem(&trans
, PREFERENCES
, "pref2");
134 CreateUnsyncedItem(&trans
, EXTENSIONS
, "extension1");
137 DirectoryTypeDebugInfoEmitter emitter1
;
138 DirectoryTypeDebugInfoEmitter emitter2
;
139 scoped_ptr
<DirectoryCommitContribution
> pref_cc(
140 DirectoryCommitContribution::Build(dir(), PREFERENCES
, 25, &emitter1
));
141 scoped_ptr
<DirectoryCommitContribution
> ext_cc(
142 DirectoryCommitContribution::Build(dir(), EXTENSIONS
, 25, &emitter2
));
144 sync_pb::ClientToServerMessage message
;
145 pref_cc
->AddToCommitMessage(&message
);
146 ext_cc
->AddToCommitMessage(&message
);
148 const sync_pb::CommitMessage
& commit_message
= message
.commit();
150 std::set
<syncable::Id
> ids_for_commit
;
151 ASSERT_EQ(3, commit_message
.entries_size());
152 for (int i
= 0; i
< commit_message
.entries_size(); ++i
) {
153 const sync_pb::SyncEntity
& entity
= commit_message
.entries(i
);
154 // The entities in this test have client-style IDs since they've never been
155 // committed before, so we must use CreateFromClientString to re-create them
156 // from the commit message.
157 ids_for_commit
.insert(syncable::Id::CreateFromClientString(
158 entity
.id_string()));
161 ASSERT_EQ(3U, ids_for_commit
.size());
163 syncable::ReadTransaction
trans(FROM_HERE
, dir());
164 for (std::set
<syncable::Id
>::iterator it
= ids_for_commit
.begin();
165 it
!= ids_for_commit
.end(); ++it
) {
166 SCOPED_TRACE(it
->value());
167 syncable::Entry
entry(&trans
, syncable::GET_BY_ID
, *it
);
168 ASSERT_TRUE(entry
.good());
169 EXPECT_TRUE(entry
.GetSyncing());
177 // Creates some unsynced items, pretends to commit them, and hands back a
178 // specially crafted response to the syncer in order to test commit response
179 // processing. The response simulates a succesful commit scenario.
180 TEST_F(DirectoryCommitContributionTest
, ProcessCommitResponse
) {
185 syncable::WriteTransaction
trans(FROM_HERE
, syncable::UNITTEST
, dir());
186 pref1_handle
= CreateUnsyncedItem(&trans
, PREFERENCES
, "pref1");
187 pref2_handle
= CreateUnsyncedItem(&trans
, PREFERENCES
, "pref2");
188 ext1_handle
= CreateUnsyncedItem(&trans
, EXTENSIONS
, "extension1");
191 DirectoryTypeDebugInfoEmitter emitter1
;
192 DirectoryTypeDebugInfoEmitter emitter2
;
193 scoped_ptr
<DirectoryCommitContribution
> pref_cc(
194 DirectoryCommitContribution::Build(dir(), PREFERENCES
, 25, &emitter1
));
195 scoped_ptr
<DirectoryCommitContribution
> ext_cc(
196 DirectoryCommitContribution::Build(dir(), EXTENSIONS
, 25, &emitter2
));
198 sync_pb::ClientToServerMessage message
;
199 pref_cc
->AddToCommitMessage(&message
);
200 ext_cc
->AddToCommitMessage(&message
);
202 const sync_pb::CommitMessage
& commit_message
= message
.commit();
203 ASSERT_EQ(3, commit_message
.entries_size());
205 sync_pb::ClientToServerResponse response
;
206 for (int i
= 0; i
< commit_message
.entries_size(); ++i
) {
207 sync_pb::SyncEntity entity
= commit_message
.entries(i
);
208 sync_pb::CommitResponse_EntryResponse
* entry_response
=
209 response
.mutable_commit()->add_entryresponse();
210 CreateSuccessfulCommitResponse(entity
, entry_response
);
213 sessions::StatusController status
;
215 // Process these in reverse order. Just because we can.
216 ext_cc
->ProcessCommitResponse(response
, &status
);
217 pref_cc
->ProcessCommitResponse(response
, &status
);
220 syncable::ReadTransaction
trans(FROM_HERE
, dir());
221 syncable::Entry
p1(&trans
, syncable::GET_BY_HANDLE
, pref1_handle
);
222 EXPECT_TRUE(p1
.GetId().ServerKnows());
223 EXPECT_FALSE(p1
.GetSyncing());
224 EXPECT_LT(0, p1
.GetServerVersion());
226 syncable::Entry
p2(&trans
, syncable::GET_BY_HANDLE
, pref2_handle
);
227 EXPECT_TRUE(p2
.GetId().ServerKnows());
228 EXPECT_FALSE(p2
.GetSyncing());
229 EXPECT_LT(0, p2
.GetServerVersion());
231 syncable::Entry
e1(&trans
, syncable::GET_BY_HANDLE
, ext1_handle
);
232 EXPECT_TRUE(e1
.GetId().ServerKnows());
233 EXPECT_FALSE(e1
.GetSyncing());
234 EXPECT_LT(0, e1
.GetServerVersion());
241 } // namespace syncer