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 "chrome/browser/extensions/api/synced_notifications_private/synced_notifications_shim.h"
7 #include "base/json/json_writer.h"
8 #include "extensions/browser/event_router.h"
9 #include "sync/api/fake_sync_change_processor.h"
10 #include "sync/api/sync_change.h"
11 #include "sync/api/sync_error_factory.h"
12 #include "sync/protocol/sync.pb.h"
13 #include "testing/gtest/include/gtest/gtest.h"
15 using namespace extensions
;
16 using namespace extensions::api
;
20 // Builds a SyncData for the specified |type| based on |key|.
21 syncer::SyncData
BuildData(syncer::ModelType type
, const std::string
& key
) {
22 sync_pb::EntitySpecifics specifics
;
23 if (type
== syncer::SYNCED_NOTIFICATIONS
) {
24 specifics
.mutable_synced_notification()
25 ->mutable_coalesced_notification()
28 specifics
.mutable_synced_notification_app_info()
29 ->add_synced_notification_app_info()
32 syncer::SyncData data
= syncer::SyncData::CreateLocalData(
37 // Builds a SyncChange with an update to the specified |type| based on |key|.
38 syncer::SyncChange
BuildChange(syncer::ModelType type
, const std::string
& key
) {
39 syncer::SyncChangeList change_list
;
40 syncer::SyncData data
= BuildData(type
, key
);
41 return syncer::SyncChange(FROM_HERE
, syncer::SyncChange::ACTION_UPDATE
, data
);
44 // Verifies that the specifics within |data| match the serialized specifics
45 // within |serialized|.
46 testing::AssertionResult
DataSpecificsMatch(const syncer::SyncData
& data
,
47 const std::string
& serialized
) {
48 if (data
.GetDataType() == syncer::SYNCED_NOTIFICATIONS
) {
49 const sync_pb::SyncedNotificationSpecifics
& proto
=
50 data
.GetSpecifics().synced_notification();
51 if (serialized
!= proto
.SerializeAsString())
52 return testing::AssertionFailure() << "Notification specifics mismatch";
54 const sync_pb::SyncedNotificationAppInfoSpecifics
& proto
=
55 data
.GetSpecifics().synced_notification_app_info();
56 if (serialized
!= proto
.SerializeAsString())
57 return testing::AssertionFailure() << "App info specifics mismatch";
59 return testing::AssertionSuccess();
62 // Verifies that the update within |change| matchs the serialized specifics
63 // within |serialized|.
64 testing::AssertionResult
ChangeSpecificsMatch(const syncer::SyncChange
& change
,
65 const std::string
& serialized
) {
66 if (change
.change_type() != syncer::SyncChange::ACTION_UPDATE
)
67 return testing::AssertionFailure() << "Invalid change type";
68 return DataSpecificsMatch(change
.sync_data(), serialized
);
71 class SyncedNotificationsShimTest
: public testing::Test
{
73 SyncedNotificationsShimTest();
74 virtual ~SyncedNotificationsShimTest();
76 // Starts sync for both sync types.
78 // Starts sync for the specified datatype |type|.
79 void StartSync(syncer::ModelType type
);
81 // Transfers ownership of the last event received.
82 scoped_ptr
<Event
> GetLastEvent();
84 // Records that a refresh has been requested.
85 void RequestRefresh();
87 SyncedNotificationsShim
* shim() { return &shim_
; }
88 syncer::FakeSyncChangeProcessor
* notification_processor() {
89 return notification_processor_
;
91 syncer::FakeSyncChangeProcessor
* app_info_processor() {
92 return app_info_processor_
;
94 bool refresh_requested() const { return refresh_requested_
; }
97 void EventCallback(scoped_ptr
<Event
> event
);
100 SyncedNotificationsShim shim_
;
102 syncer::FakeSyncChangeProcessor
* notification_processor_
;
103 syncer::FakeSyncChangeProcessor
* app_info_processor_
;
105 // The last event fired by the shim.
106 scoped_ptr
<Event
> last_event_fired_
;
108 // Whether a refresh has been requested;
109 bool refresh_requested_
;
112 SyncedNotificationsShimTest::SyncedNotificationsShimTest()
113 : shim_(base::Bind(&SyncedNotificationsShimTest::EventCallback
,
114 base::Unretained(this)),
115 base::Bind(&SyncedNotificationsShimTest::RequestRefresh
,
116 base::Unretained(this))),
117 notification_processor_(NULL
),
118 app_info_processor_(NULL
),
119 refresh_requested_(false) {}
121 SyncedNotificationsShimTest::~SyncedNotificationsShimTest() {}
123 void SyncedNotificationsShimTest::EventCallback(scoped_ptr
<Event
> event
) {
124 ASSERT_FALSE(last_event_fired_
);
125 last_event_fired_
= event
.Pass();
128 void SyncedNotificationsShimTest::RequestRefresh() {
129 ASSERT_FALSE(refresh_requested_
);
130 refresh_requested_
= true;
133 scoped_ptr
<Event
> SyncedNotificationsShimTest::GetLastEvent() {
134 return last_event_fired_
.Pass();
137 void SyncedNotificationsShimTest::StartSync() {
138 StartSync(syncer::SYNCED_NOTIFICATIONS
);
139 StartSync(syncer::SYNCED_NOTIFICATION_APP_INFO
);
143 void SyncedNotificationsShimTest::StartSync(syncer::ModelType type
) {
144 scoped_ptr
<syncer::FakeSyncChangeProcessor
> change_processor(
145 new syncer::FakeSyncChangeProcessor());
146 if (type
== syncer::SYNCED_NOTIFICATIONS
)
147 notification_processor_
= change_processor
.get();
149 app_info_processor_
= change_processor
.get();
150 syncer::SyncDataList sync_data
;
151 shim_
.MergeDataAndStartSyncing(
154 change_processor
.PassAs
<syncer::SyncChangeProcessor
>(),
155 scoped_ptr
<syncer::SyncErrorFactory
>());
158 // Starting sync should fire the sync started event, but only after both types
160 TEST_F(SyncedNotificationsShimTest
, StartSync
) {
161 EXPECT_FALSE(shim()->IsSyncReady());
162 StartSync(syncer::SYNCED_NOTIFICATIONS
);
163 EXPECT_FALSE(shim()->IsSyncReady());
164 EXPECT_FALSE(GetLastEvent());
166 StartSync(syncer::SYNCED_NOTIFICATION_APP_INFO
);
167 EXPECT_TRUE(shim()->IsSyncReady());
169 scoped_ptr
<Event
> event
= GetLastEvent();
171 EXPECT_EQ(synced_notifications_private::OnSyncStartup::kEventName
,
174 EXPECT_TRUE(notification_processor()->changes().empty());
175 EXPECT_TRUE(app_info_processor()->changes().empty());
178 // A sync update should fire the OnDataChanges event with the updated
180 TEST_F(SyncedNotificationsShimTest
, ProcessSyncChangesSingleNotification
) {
182 syncer::SyncChangeList change_list
;
183 change_list
.push_back(BuildChange(syncer::SYNCED_NOTIFICATIONS
, "key"));
184 shim()->ProcessSyncChanges(FROM_HERE
, change_list
);
185 scoped_ptr
<Event
> event
= GetLastEvent();
187 EXPECT_EQ(synced_notifications_private::OnDataChanges::kEventName
,
189 ASSERT_TRUE(event
->event_args
);
190 EXPECT_EQ(1U, event
->event_args
->GetSize());
192 base::ListValue
* args
= NULL
;
193 ASSERT_TRUE(event
->event_args
->GetList(0, &args
));
194 EXPECT_EQ(1U, args
->GetSize());
195 base::DictionaryValue
* sync_change_value
= NULL
;
196 ASSERT_TRUE(args
->GetDictionary(0, &sync_change_value
));
197 scoped_ptr
<synced_notifications_private::SyncChange
> sync_change
=
198 synced_notifications_private::SyncChange::FromValue(*sync_change_value
);
199 ASSERT_TRUE(sync_change
);
200 EXPECT_TRUE(ChangeSpecificsMatch(change_list
[0],
201 sync_change
->data
.data_item
));
202 EXPECT_EQ(synced_notifications_private::CHANGE_TYPE_UPDATED
,
203 sync_change
->change_type
);
206 // Verify that multiple notification updates can be sent in one event.
207 TEST_F(SyncedNotificationsShimTest
, ProcessSyncChangesMultipleNotification
) {
209 syncer::SyncChangeList change_list
;
210 change_list
.push_back(BuildChange(syncer::SYNCED_NOTIFICATIONS
, "key"));
211 change_list
.push_back(BuildChange(syncer::SYNCED_NOTIFICATIONS
, "key2"));
212 shim()->ProcessSyncChanges(FROM_HERE
, change_list
);
213 scoped_ptr
<Event
> event
= GetLastEvent();
215 EXPECT_EQ(synced_notifications_private::OnDataChanges::kEventName
,
217 ASSERT_TRUE(event
->event_args
);
218 base::ListValue
* args
= NULL
;
219 ASSERT_TRUE(event
->event_args
->GetList(0, &args
));
220 EXPECT_EQ(2U, args
->GetSize());
222 base::DictionaryValue
* sync_change_value
= NULL
;
223 ASSERT_TRUE(args
->GetDictionary(0, &sync_change_value
));
224 scoped_ptr
<synced_notifications_private::SyncChange
> sync_change
=
225 synced_notifications_private::SyncChange::FromValue(*sync_change_value
);
226 ASSERT_TRUE(sync_change
);
227 EXPECT_TRUE(ChangeSpecificsMatch(change_list
[0],
228 sync_change
->data
.data_item
));
229 EXPECT_EQ(synced_notifications_private::CHANGE_TYPE_UPDATED
,
230 sync_change
->change_type
);
232 ASSERT_TRUE(args
->GetDictionary(1, &sync_change_value
));
234 synced_notifications_private::SyncChange::FromValue(*sync_change_value
);
235 ASSERT_TRUE(sync_change
);
236 EXPECT_TRUE(ChangeSpecificsMatch(change_list
[1],
237 sync_change
->data
.data_item
));
238 EXPECT_EQ(synced_notifications_private::CHANGE_TYPE_UPDATED
,
239 sync_change
->change_type
);
242 // Verify AppInfo updates trigger OnDataChanges events.
243 TEST_F(SyncedNotificationsShimTest
, ProcessSyncChangeAppInfo
) {
245 syncer::SyncChangeList change_list
;
246 change_list
.push_back(
247 BuildChange(syncer::SYNCED_NOTIFICATION_APP_INFO
, "key"));
248 shim()->ProcessSyncChanges(FROM_HERE
, change_list
);
249 scoped_ptr
<Event
> event
= GetLastEvent();
251 EXPECT_EQ(synced_notifications_private::OnDataChanges::kEventName
,
253 ASSERT_TRUE(event
->event_args
);
254 EXPECT_EQ(1U, event
->event_args
->GetSize());
256 base::ListValue
* args
= NULL
;
257 ASSERT_TRUE(event
->event_args
->GetList(0, &args
));
258 EXPECT_EQ(1U, args
->GetSize());
259 base::DictionaryValue
* sync_change_value
= NULL
;
260 ASSERT_TRUE(args
->GetDictionary(0, &sync_change_value
));
261 scoped_ptr
<synced_notifications_private::SyncChange
> sync_change
=
262 synced_notifications_private::SyncChange::FromValue(*sync_change_value
);
263 ASSERT_TRUE(sync_change
);
264 EXPECT_TRUE(ChangeSpecificsMatch(change_list
[0],
265 sync_change
->data
.data_item
));
266 EXPECT_EQ(synced_notifications_private::CHANGE_TYPE_UPDATED
,
267 sync_change
->change_type
);
270 // Attempt to get the initial sync data both before and after sync starts.
271 TEST_F(SyncedNotificationsShimTest
, GetInitialData
) {
272 std::vector
<linked_ptr
<synced_notifications_private::SyncData
> > data
;
273 EXPECT_FALSE(shim()->GetInitialData(
274 synced_notifications_private::SYNC_DATA_TYPE_SYNCED_NOTIFICATION
, &data
));
275 EXPECT_FALSE(shim()->GetInitialData(
276 synced_notifications_private::SYNC_DATA_TYPE_APP_INFO
, &data
));
280 EXPECT_TRUE(shim()->GetInitialData(
281 synced_notifications_private::SYNC_DATA_TYPE_SYNCED_NOTIFICATION
, &data
));
282 EXPECT_TRUE(data
.empty());
283 EXPECT_TRUE(shim()->GetInitialData(
284 synced_notifications_private::SYNC_DATA_TYPE_APP_INFO
, &data
));
285 EXPECT_TRUE(data
.empty());
287 notification_processor()->data().push_back(BuildData(
288 syncer::SYNCED_NOTIFICATIONS
, "notif_key"));
289 EXPECT_TRUE(shim()->GetInitialData(
290 synced_notifications_private::SYNC_DATA_TYPE_SYNCED_NOTIFICATION
, &data
));
291 EXPECT_EQ(1U, data
.size());
292 EXPECT_TRUE(DataSpecificsMatch(notification_processor()->data()[0],
293 data
[0]->data_item
));
296 app_info_processor()->data().push_back(BuildData(
297 syncer::SYNCED_NOTIFICATION_APP_INFO
, "app_key"));
298 EXPECT_TRUE(shim()->GetInitialData(
299 synced_notifications_private::SYNC_DATA_TYPE_APP_INFO
, &data
));
300 EXPECT_EQ(1U, data
.size());
301 EXPECT_TRUE(DataSpecificsMatch(app_info_processor()->data()[0],
302 data
[0]->data_item
));
305 // Verify that notification updates are properly handled.
306 TEST_F(SyncedNotificationsShimTest
, UpdateNotification
) {
307 syncer::SyncData data
=
308 BuildData(syncer::SYNCED_NOTIFICATIONS
, "notif_key");
309 std::string serialized
=
310 data
.GetSpecifics().synced_notification().SerializeAsString();
311 EXPECT_FALSE(shim()->UpdateNotification(serialized
));
315 EXPECT_FALSE(shim()->UpdateNotification("gibberish"));
316 EXPECT_TRUE(notification_processor()->changes().empty());
318 EXPECT_TRUE(shim()->UpdateNotification(serialized
));
319 EXPECT_EQ(1U, notification_processor()->changes().size());
320 EXPECT_EQ(syncer::SyncChange::ACTION_UPDATE
,
321 notification_processor()->changes()[0].change_type());
322 EXPECT_EQ(syncer::SYNCED_NOTIFICATIONS
,
323 notification_processor()->changes()[0].sync_data().GetDataType());
324 EXPECT_EQ(serialized
,
325 notification_processor()
329 .synced_notification()
330 .SerializeAsString());
333 // Verify that SetRenderContext updates the datatype context properly.
334 TEST_F(SyncedNotificationsShimTest
, SetRenderContext
) {
335 const std::string kContext
= "context";
336 EXPECT_FALSE(shim()->SetRenderContext(
337 synced_notifications_private::REFRESH_REQUEST_REFRESH_NEEDED
, kContext
));
338 EXPECT_FALSE(refresh_requested());
342 EXPECT_TRUE(shim()->SetRenderContext(
343 synced_notifications_private::REFRESH_REQUEST_REFRESH_NEEDED
, kContext
));
344 EXPECT_EQ(kContext
, notification_processor()->context());
345 EXPECT_TRUE(refresh_requested());