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.
4
5 #include "sync/engine/syncer_proto_util.h"
6
7 #include <string>
8
9 #include "base/basictypes.h"
10 #include "base/compiler_specific.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/time/time.h"
13 #include "sync/internal_api/public/base/cancelation_signal.h"
14 #include "sync/internal_api/public/base/model_type_test_util.h"
15 #include "sync/protocol/bookmark_specifics.pb.h"
16 #include "sync/protocol/password_specifics.pb.h"
17 #include "sync/protocol/sync.pb.h"
18 #include "sync/protocol/sync_enums.pb.h"
19 #include "sync/sessions/sync_session_context.h"
20 #include "sync/syncable/blob.h"
21 #include "sync/syncable/directory.h"
22 #include "sync/test/engine/mock_connection_manager.h"
23 #include "sync/test/engine/test_directory_setter_upper.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25
26 using ::testing::_;
27
28 using sync_pb::ClientToServerMessage;
29 using sync_pb::CommitResponse_EntryResponse;
30 using sync_pb::SyncEntity;
31
32 namespace syncer {
33
34 using sessions::SyncSessionContext;
35 using syncable::Blob;
36
37 class MockDelegate : public sessions::SyncSession::Delegate {
38 public:
MockDelegate()39 MockDelegate() {}
~MockDelegate()40 ~MockDelegate() {}
41
42 MOCK_METHOD1(OnReceivedShortPollIntervalUpdate, void(const base::TimeDelta&));
43 MOCK_METHOD1(OnReceivedLongPollIntervalUpdate ,void(const base::TimeDelta&));
44 MOCK_METHOD1(OnReceivedSessionsCommitDelay, void(const base::TimeDelta&));
45 MOCK_METHOD1(OnReceivedClientInvalidationHintBufferSize, void(int));
46 MOCK_METHOD1(OnSyncProtocolError, void(const SyncProtocolError&));
47 };
48
49 // Builds a ClientToServerResponse with some data type ids, including
50 // invalid ones. GetTypesToMigrate() should return only the valid
51 // model types.
TEST(SyncerProtoUtil,GetTypesToMigrate)52 TEST(SyncerProtoUtil, GetTypesToMigrate) {
53 sync_pb::ClientToServerResponse response;
54 response.add_migrated_data_type_id(
55 GetSpecificsFieldNumberFromModelType(BOOKMARKS));
56 response.add_migrated_data_type_id(
57 GetSpecificsFieldNumberFromModelType(HISTORY_DELETE_DIRECTIVES));
58 response.add_migrated_data_type_id(-1);
59 EXPECT_TRUE(
60 GetTypesToMigrate(response).Equals(
61 ModelTypeSet(BOOKMARKS, HISTORY_DELETE_DIRECTIVES)));
62 }
63
64 // Builds a ClientToServerResponse_Error with some error data type
65 // ids, including invalid ones. ConvertErrorPBToLocalType() should
66 // return a SyncProtocolError with only the valid model types.
TEST(SyncerProtoUtil,ConvertErrorPBToLocalType)67 TEST(SyncerProtoUtil, ConvertErrorPBToLocalType) {
68 sync_pb::ClientToServerResponse_Error error_pb;
69 error_pb.set_error_type(sync_pb::SyncEnums::THROTTLED);
70 error_pb.add_error_data_type_ids(
71 GetSpecificsFieldNumberFromModelType(BOOKMARKS));
72 error_pb.add_error_data_type_ids(
73 GetSpecificsFieldNumberFromModelType(HISTORY_DELETE_DIRECTIVES));
74 error_pb.add_error_data_type_ids(-1);
75 SyncProtocolError error = ConvertErrorPBToLocalType(error_pb);
76 EXPECT_TRUE(
77 error.error_data_types.Equals(
78 ModelTypeSet(BOOKMARKS, HISTORY_DELETE_DIRECTIVES)));
79 }
80
TEST(SyncerProtoUtil,TestBlobToProtocolBufferBytesUtilityFunctions)81 TEST(SyncerProtoUtil, TestBlobToProtocolBufferBytesUtilityFunctions) {
82 unsigned char test_data1[] = {1, 2, 3, 4, 5, 6, 7, 8, 0, 1, 4, 2, 9};
83 unsigned char test_data2[] = {1, 99, 3, 4, 5, 6, 7, 8, 0, 1, 4, 2, 9};
84 unsigned char test_data3[] = {99, 2, 3, 4, 5, 6, 7, 8};
85
86 syncable::Blob test_blob1, test_blob2, test_blob3;
87 for (size_t i = 0; i < arraysize(test_data1); ++i)
88 test_blob1.push_back(test_data1[i]);
89 for (size_t i = 0; i < arraysize(test_data2); ++i)
90 test_blob2.push_back(test_data2[i]);
91 for (size_t i = 0; i < arraysize(test_data3); ++i)
92 test_blob3.push_back(test_data3[i]);
93
94 std::string test_message1(reinterpret_cast<char*>(test_data1),
95 arraysize(test_data1));
96 std::string test_message2(reinterpret_cast<char*>(test_data2),
97 arraysize(test_data2));
98 std::string test_message3(reinterpret_cast<char*>(test_data3),
99 arraysize(test_data3));
100
101 EXPECT_TRUE(SyncerProtoUtil::ProtoBytesEqualsBlob(test_message1,
102 test_blob1));
103 EXPECT_FALSE(SyncerProtoUtil::ProtoBytesEqualsBlob(test_message1,
104 test_blob2));
105 EXPECT_FALSE(SyncerProtoUtil::ProtoBytesEqualsBlob(test_message1,
106 test_blob3));
107 EXPECT_FALSE(SyncerProtoUtil::ProtoBytesEqualsBlob(test_message2,
108 test_blob1));
109 EXPECT_TRUE(SyncerProtoUtil::ProtoBytesEqualsBlob(test_message2,
110 test_blob2));
111 EXPECT_FALSE(SyncerProtoUtil::ProtoBytesEqualsBlob(test_message2,
112 test_blob3));
113 EXPECT_FALSE(SyncerProtoUtil::ProtoBytesEqualsBlob(test_message3,
114 test_blob1));
115 EXPECT_FALSE(SyncerProtoUtil::ProtoBytesEqualsBlob(test_message3,
116 test_blob2));
117 EXPECT_TRUE(SyncerProtoUtil::ProtoBytesEqualsBlob(test_message3,
118 test_blob3));
119
120 Blob blob1_copy;
121 EXPECT_FALSE(SyncerProtoUtil::ProtoBytesEqualsBlob(test_message1,
122 blob1_copy));
123 SyncerProtoUtil::CopyProtoBytesIntoBlob(test_message1, &blob1_copy);
124 EXPECT_TRUE(SyncerProtoUtil::ProtoBytesEqualsBlob(test_message1,
125 blob1_copy));
126
127 std::string message2_copy;
128 EXPECT_FALSE(SyncerProtoUtil::ProtoBytesEqualsBlob(message2_copy,
129 test_blob2));
130 SyncerProtoUtil::CopyBlobIntoProtoBytes(test_blob2, &message2_copy);
131 EXPECT_TRUE(SyncerProtoUtil::ProtoBytesEqualsBlob(message2_copy,
132 test_blob2));
133 }
134
135 // Tests NameFromSyncEntity and NameFromCommitEntryResponse when only the name
136 // field is provided.
TEST(SyncerProtoUtil,NameExtractionOneName)137 TEST(SyncerProtoUtil, NameExtractionOneName) {
138 SyncEntity one_name_entity;
139 CommitResponse_EntryResponse one_name_response;
140
141 const std::string one_name_string("Eggheadednesses");
142 one_name_entity.set_name(one_name_string);
143 one_name_response.set_name(one_name_string);
144
145 const std::string name_a =
146 SyncerProtoUtil::NameFromSyncEntity(one_name_entity);
147 EXPECT_EQ(one_name_string, name_a);
148 }
149
TEST(SyncerProtoUtil,NameExtractionOneUniqueName)150 TEST(SyncerProtoUtil, NameExtractionOneUniqueName) {
151 SyncEntity one_name_entity;
152 CommitResponse_EntryResponse one_name_response;
153
154 const std::string one_name_string("Eggheadednesses");
155
156 one_name_entity.set_non_unique_name(one_name_string);
157 one_name_response.set_non_unique_name(one_name_string);
158
159 const std::string name_a =
160 SyncerProtoUtil::NameFromSyncEntity(one_name_entity);
161 EXPECT_EQ(one_name_string, name_a);
162 }
163
164 // Tests NameFromSyncEntity and NameFromCommitEntryResponse when both the name
165 // field and the non_unique_name fields are provided.
166 // Should prioritize non_unique_name.
TEST(SyncerProtoUtil,NameExtractionTwoNames)167 TEST(SyncerProtoUtil, NameExtractionTwoNames) {
168 SyncEntity two_name_entity;
169 CommitResponse_EntryResponse two_name_response;
170
171 const std::string neuro("Neuroanatomists");
172 const std::string oxyphen("Oxyphenbutazone");
173
174 two_name_entity.set_name(oxyphen);
175 two_name_entity.set_non_unique_name(neuro);
176
177 two_name_response.set_name(oxyphen);
178 two_name_response.set_non_unique_name(neuro);
179
180 const std::string name_a =
181 SyncerProtoUtil::NameFromSyncEntity(two_name_entity);
182 EXPECT_EQ(neuro, name_a);
183 }
184
185 class SyncerProtoUtilTest : public testing::Test {
186 public:
SetUp()187 virtual void SetUp() {
188 dir_maker_.SetUp();
189 }
190
TearDown()191 virtual void TearDown() {
192 dir_maker_.TearDown();
193 }
194
directory()195 syncable::Directory* directory() {
196 return dir_maker_.directory();
197 }
198
199 protected:
200 base::MessageLoop message_loop_;
201 TestDirectorySetterUpper dir_maker_;
202 };
203
TEST_F(SyncerProtoUtilTest,VerifyResponseBirthday)204 TEST_F(SyncerProtoUtilTest, VerifyResponseBirthday) {
205 // Both sides empty
206 EXPECT_TRUE(directory()->store_birthday().empty());
207 sync_pb::ClientToServerResponse response;
208 EXPECT_FALSE(SyncerProtoUtil::VerifyResponseBirthday(response, directory()));
209
210 // Remote set, local empty
211 response.set_store_birthday("flan");
212 EXPECT_TRUE(SyncerProtoUtil::VerifyResponseBirthday(response, directory()));
213 EXPECT_EQ(directory()->store_birthday(), "flan");
214
215 // Remote empty, local set.
216 response.clear_store_birthday();
217 EXPECT_TRUE(SyncerProtoUtil::VerifyResponseBirthday(response, directory()));
218 EXPECT_EQ(directory()->store_birthday(), "flan");
219
220 // Doesn't match
221 response.set_store_birthday("meat");
222 EXPECT_FALSE(SyncerProtoUtil::VerifyResponseBirthday(response, directory()));
223
224 response.set_error_code(sync_pb::SyncEnums::CLEAR_PENDING);
225 EXPECT_FALSE(SyncerProtoUtil::VerifyResponseBirthday(response, directory()));
226 }
227
TEST_F(SyncerProtoUtilTest,VerifyDisabledByAdmin)228 TEST_F(SyncerProtoUtilTest, VerifyDisabledByAdmin) {
229 // No error code
230 sync_pb::ClientToServerResponse response;
231 EXPECT_FALSE(SyncerProtoUtil::IsSyncDisabledByAdmin(response));
232
233 // Has error code, but not disabled
234 response.set_error_code(sync_pb::SyncEnums::NOT_MY_BIRTHDAY);
235 EXPECT_FALSE(SyncerProtoUtil::IsSyncDisabledByAdmin(response));
236
237 // Has error code, and is disabled by admin
238 response.set_error_code(sync_pb::SyncEnums::DISABLED_BY_ADMIN);
239 EXPECT_TRUE(SyncerProtoUtil::IsSyncDisabledByAdmin(response));
240 }
241
TEST_F(SyncerProtoUtilTest,AddRequestBirthday)242 TEST_F(SyncerProtoUtilTest, AddRequestBirthday) {
243 EXPECT_TRUE(directory()->store_birthday().empty());
244 ClientToServerMessage msg;
245 SyncerProtoUtil::AddRequestBirthday(directory(), &msg);
246 EXPECT_FALSE(msg.has_store_birthday());
247
248 directory()->set_store_birthday("meat");
249 SyncerProtoUtil::AddRequestBirthday(directory(), &msg);
250 EXPECT_EQ(msg.store_birthday(), "meat");
251 }
252
253 class DummyConnectionManager : public ServerConnectionManager {
254 public:
DummyConnectionManager(CancelationSignal * signal)255 DummyConnectionManager(CancelationSignal* signal)
256 : ServerConnectionManager("unused", 0, false, signal),
257 send_error_(false),
258 access_denied_(false) {}
259
~DummyConnectionManager()260 virtual ~DummyConnectionManager() {}
PostBufferWithCachedAuth(PostBufferParams * params,ScopedServerStatusWatcher * watcher)261 virtual bool PostBufferWithCachedAuth(
262 PostBufferParams* params,
263 ScopedServerStatusWatcher* watcher) OVERRIDE {
264 if (send_error_) {
265 return false;
266 }
267
268 sync_pb::ClientToServerResponse response;
269 if (access_denied_) {
270 response.set_error_code(sync_pb::SyncEnums::ACCESS_DENIED);
271 }
272 response.SerializeToString(¶ms->buffer_out);
273
274 return true;
275 }
276
set_send_error(bool send)277 void set_send_error(bool send) {
278 send_error_ = send;
279 }
280
set_access_denied(bool denied)281 void set_access_denied(bool denied) {
282 access_denied_ = denied;
283 }
284
285 private:
286 bool send_error_;
287 bool access_denied_;
288 };
289
TEST_F(SyncerProtoUtilTest,PostAndProcessHeaders)290 TEST_F(SyncerProtoUtilTest, PostAndProcessHeaders) {
291 CancelationSignal signal;
292 DummyConnectionManager dcm(&signal);
293 ClientToServerMessage msg;
294 SyncerProtoUtil::SetProtocolVersion(&msg);
295 msg.set_share("required");
296 msg.set_message_contents(ClientToServerMessage::GET_UPDATES);
297 sync_pb::ClientToServerResponse response;
298
299 dcm.set_send_error(true);
300 EXPECT_FALSE(SyncerProtoUtil::PostAndProcessHeaders(&dcm, NULL,
301 msg, &response));
302
303 dcm.set_send_error(false);
304 EXPECT_TRUE(SyncerProtoUtil::PostAndProcessHeaders(&dcm, NULL,
305 msg, &response));
306
307 dcm.set_access_denied(true);
308 EXPECT_FALSE(SyncerProtoUtil::PostAndProcessHeaders(&dcm, NULL,
309 msg, &response));
310 }
311
312 } // namespace syncer
313