Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(181)

Side by Side Diff: sync/notifier/invalidator_test_template.h

Issue 10874096: [Sync] Rework Invalidator-related unit tests (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix compile Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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 // This class defines tests that implementations of Invalidator should pass in
6 // order to be conformant. Here's how you use it to test your implementation.
7 //
8 // Say your class is called MyInvalidator. Then you need to define a class
9 // called MyInvalidatorTestDelegate in my_sync_notifier_unittest.cc like this:
10 //
11 // class MyInvalidatorTestDelegate {
12 // public:
13 // MyInvalidatorTestDelegate() ...
14 //
15 // ~MyInvalidatorTestDelegate() {
16 // // DestroyInvalidator() may not be explicitly called by tests.
17 // DestroyInvalidator();
18 // }
19 //
20 // // Create the Invalidator implementation with the given parameters.
21 // void CreateInvalidator(
22 // const std::string& initial_state,
23 // const base::WeakPtr<InvalidationStateTracker>&
24 // invalidation_state_tracker) {
25 // ...
26 // }
27 //
28 // // Should return the Invalidator implementation. Only called after
29 // // CreateInvalidator and before DestroyInvalidator.
30 // MyInvalidator* GetInvalidator() {
31 // ...
32 // }
33 //
34 // // Destroy the Invalidator implementation.
35 // void DestroyInvalidator() {
36 // ...
37 // }
38 //
39 // // Called after a call to SetStateDeprecated(), SetUniqueId(), or
40 // // UpdateCredentials() on the Invalidator implementation. Should block
41 // // until the effects of the call are visible on the current thread.
42 // void WaitForInvalidator() {
43 // ...
44 // }
45 //
46 // // The Trigger* functions below should block until the effects of
47 // // the call are visible on the current thread.
48 //
49 // // Should cause OnNotificationsEnabled() to be called on all
50 // // observers of the Invalidator implementation.
51 // void TriggerOnNotificationsEnabled() {
52 // ...
53 // }
54 //
55 // // Should cause OnIncomingNotification() to be called on all
56 // // observers of the Invalidator implementation with the given
57 // // parameters.
58 // void TriggerOnIncomingNotification(const ObjectIdStateMap& id_state_map,
59 // IncomingNotificationSource source) {
60 // ...
61 // }
62 //
63 // // Should cause OnNotificationsDisabled() to be called on all
64 // // observers of the Invalidator implementation with the given
65 // // parameters.
66 // void TriggerOnNotificationsDisabled(
67 // NotificationsDisabledReason reason) {
68 // ...
69 // }
70 //
71 // // Returns whether or not the notifier handles storing the old
72 // // (deprecated) notifier state.
73 // static bool InvalidatorHandlesDeprecatedState() {
74 // return false;
75 // }
76 // };
77 //
78 // The InvalidatorTest test harness will have a member variable of
79 // this delegate type and will call its functions in the various
80 // tests.
81 //
82 // Then you simply #include this file as well as gtest.h and add the
83 // following statement to my_sync_notifier_unittest.cc:
84 //
85 // INSTANTIATE_TYPED_TEST_CASE_P(
86 // MyInvalidator, InvalidatorTest, MyInvalidatorTestDelegate);
87 //
88 // Easy!
89
90 #ifndef SYNC_NOTIFIER_INVALIDATOR_TEST_TEMPLATE_H_
91 #define SYNC_NOTIFIER_INVALIDATOR_TEST_TEMPLATE_H_
92
93 #include "google/cacheinvalidation/include/types.h"
94 #include "google/cacheinvalidation/types.pb.h"
95 #include "sync/notifier/fake_invalidation_handler.h"
96 #include "sync/notifier/fake_invalidation_state_tracker.h"
97 #include "sync/notifier/invalidator.h"
98 #include "sync/notifier/object_id_state_map.h"
99 #include "sync/notifier/object_id_state_map_test_util.h"
100 #include "testing/gtest/include/gtest/gtest.h"
101
102 namespace syncer {
103
104 template <typename InvalidatorTestDelegate>
105 class InvalidatorTest : public testing::Test {
106 protected:
107 InvalidatorTest()
108 : id1(ipc::invalidation::ObjectSource::TEST, "a"),
109 id2(ipc::invalidation::ObjectSource::TEST, "b"),
110 id3(ipc::invalidation::ObjectSource::TEST, "c"),
111 id4(ipc::invalidation::ObjectSource::TEST, "d") {
112 }
113
114 Invalidator* CreateAndInitializeInvalidator() {
115 this->delegate_.CreateInvalidator("fake_initial_state",
Nicolas Zea 2012/08/29 23:41:05 why are all the "this->"'s necessary?
akalin 2012/08/30 22:20:38 Basically because they're type-parametrized tests
116 this->fake_tracker_.AsWeakPtr());
117 Invalidator* const invalidator = this->delegate_.GetInvalidator();
118
119 // TODO(tim): This call should be a no-op. Remove once bug 124140 and
Nicolas Zea 2012/08/29 23:41:05 this bug is fixed, do we still need the call aroun
akalin 2012/08/30 22:20:38 Actually, I think we still can't remove it yet? I
120 // associated issues are fixed.
121 invalidator->SetStateDeprecated("fake_state");
122 this->delegate_.WaitForInvalidator();
123 // We don't expect |fake_tracker_|'s state to change, as we
124 // initialized with non-empty initial_invalidation_state above.
125 EXPECT_TRUE(this->fake_tracker_.GetInvalidationState().empty());
126 invalidator->SetUniqueId("fake_id");
127 this->delegate_.WaitForInvalidator();
128 invalidator->UpdateCredentials("foo@bar.com", "fake_token");
129 this->delegate_.WaitForInvalidator();
130
131 return invalidator;
132 }
133
134 FakeInvalidationStateTracker fake_tracker_;
135 InvalidatorTestDelegate delegate_;
136
137 const invalidation::ObjectId id1;
138 const invalidation::ObjectId id2;
139 const invalidation::ObjectId id3;
140 const invalidation::ObjectId id4;
141 };
142
143 TYPED_TEST_CASE_P(InvalidatorTest);
144
145 // Initialize the invalidator, register a handler, register some IDs for that
146 // handler, and then unregister the handler, dispatching invalidations in
147 // between. The handler should only see invalidations when its registered and
148 // its IDs are registered.
149 TYPED_TEST_P(InvalidatorTest, Basic) {
150 Invalidator* const invalidator = this->CreateAndInitializeInvalidator();
151
152 FakeInvalidationHandler handler;
153
154 invalidator->RegisterHandler(&handler);
155
156 ObjectIdStateMap states;
157 states[this->id1].payload = "1";
158 states[this->id2].payload = "2";
159 states[this->id3].payload = "3";
160
161 // Should be ignored since no IDs are registered to |handler|.
162 this->delegate_.TriggerOnIncomingNotification(states, REMOTE_NOTIFICATION);
163 EXPECT_EQ(0, handler.GetNotificationCount());
164
165 ObjectIdSet ids;
166 ids.insert(this->id1);
167 ids.insert(this->id2);
168 invalidator->UpdateRegisteredIds(&handler, ids);
169
170 this->delegate_.TriggerOnNotificationsEnabled();
171 EXPECT_EQ(NO_NOTIFICATION_ERROR,
172 handler.GetNotificationsDisabledReason());
173
174 ObjectIdStateMap expected_states;
175 expected_states[this->id1].payload = "1";
176 expected_states[this->id2].payload = "2";
177
178 this->delegate_.TriggerOnIncomingNotification(states, REMOTE_NOTIFICATION);
179 EXPECT_EQ(1, handler.GetNotificationCount());
180 EXPECT_THAT(
181 expected_states,
182 Eq(handler.GetLastNotificationIdStateMap()));
183 EXPECT_EQ(REMOTE_NOTIFICATION, handler.GetLastNotificationSource());
184
185 ids.erase(this->id1);
186 ids.insert(this->id3);
187 invalidator->UpdateRegisteredIds(&handler, ids);
188
189 expected_states.erase(this->id1);
190 expected_states[this->id3].payload = "3";
191
192 // Removed object IDs should not be notified, newly-added ones should.
193 this->delegate_.TriggerOnIncomingNotification(states, REMOTE_NOTIFICATION);
194 EXPECT_EQ(2, handler.GetNotificationCount());
195 EXPECT_THAT(
196 expected_states,
197 Eq(handler.GetLastNotificationIdStateMap()));
198 EXPECT_EQ(REMOTE_NOTIFICATION, handler.GetLastNotificationSource());
199
200 this->delegate_.TriggerOnNotificationsDisabled(TRANSIENT_NOTIFICATION_ERROR);
201 EXPECT_EQ(TRANSIENT_NOTIFICATION_ERROR,
202 handler.GetNotificationsDisabledReason());
203
204 this->delegate_.TriggerOnNotificationsDisabled(
205 NOTIFICATION_CREDENTIALS_REJECTED);
206 EXPECT_EQ(NOTIFICATION_CREDENTIALS_REJECTED,
207 handler.GetNotificationsDisabledReason());
208
209 invalidator->UnregisterHandler(&handler);
210
211 // Should be ignored since |handler| isn't registered anymore.
212 this->delegate_.TriggerOnIncomingNotification(states, REMOTE_NOTIFICATION);
213 EXPECT_EQ(2, handler.GetNotificationCount());
214 }
215
216 // Register handlers and some IDs for those handlers, register a handler with
217 // no IDs, and register a handler with some IDs but unregister it. Then,
218 // dispatch some notifications and invalidations. Handlers that are registered
219 // should get notifications, and the ones that have registered IDs should
220 // receive invalidations for those IDs.
221 TYPED_TEST_P(InvalidatorTest, MultipleHandlers) {
222 Invalidator* const invalidator = this->CreateAndInitializeInvalidator();
223
224 FakeInvalidationHandler handler1;
225 FakeInvalidationHandler handler2;
226 FakeInvalidationHandler handler3;
227 FakeInvalidationHandler handler4;
228
229 invalidator->RegisterHandler(&handler1);
230 invalidator->RegisterHandler(&handler2);
231 invalidator->RegisterHandler(&handler3);
232 invalidator->RegisterHandler(&handler4);
233
234 {
235 ObjectIdSet ids;
236 ids.insert(this->id1);
237 ids.insert(this->id2);
238 invalidator->UpdateRegisteredIds(&handler1, ids);
239 }
240
241 {
242 ObjectIdSet ids;
243 ids.insert(this->id3);
244 invalidator->UpdateRegisteredIds(&handler2, ids);
245 }
246
247 // Don't register any IDs for handler3.
248
249 {
250 ObjectIdSet ids;
251 ids.insert(this->id4);
252 invalidator->UpdateRegisteredIds(&handler4, ids);
253 }
254
255 invalidator->UnregisterHandler(&handler4);
256
257 this->delegate_.TriggerOnNotificationsEnabled();
258 EXPECT_EQ(NO_NOTIFICATION_ERROR,
259 handler1.GetNotificationsDisabledReason());
260 EXPECT_EQ(NO_NOTIFICATION_ERROR,
261 handler2.GetNotificationsDisabledReason());
262 EXPECT_EQ(NO_NOTIFICATION_ERROR,
263 handler3.GetNotificationsDisabledReason());
264 EXPECT_EQ(TRANSIENT_NOTIFICATION_ERROR,
265 handler4.GetNotificationsDisabledReason());
266
267 {
268 ObjectIdStateMap states;
269 states[this->id1].payload = "1";
270 states[this->id2].payload = "2";
271 states[this->id3].payload = "3";
272 states[this->id4].payload = "4";
273 this->delegate_.TriggerOnIncomingNotification(states, REMOTE_NOTIFICATION);
274
275 ObjectIdStateMap expected_states;
276 expected_states[this->id1].payload = "1";
277 expected_states[this->id2].payload = "2";
278
279 EXPECT_EQ(1, handler1.GetNotificationCount());
280 EXPECT_THAT(
281 expected_states,
282 Eq(handler1.GetLastNotificationIdStateMap()));
283 EXPECT_EQ(REMOTE_NOTIFICATION, handler1.GetLastNotificationSource());
284
285 expected_states.clear();
286 expected_states[this->id3].payload = "3";
287
288 EXPECT_EQ(1, handler2.GetNotificationCount());
289 EXPECT_THAT(
290 expected_states,
291 Eq(handler2.GetLastNotificationIdStateMap()));
292 EXPECT_EQ(REMOTE_NOTIFICATION, handler2.GetLastNotificationSource());
293
294 EXPECT_EQ(0, handler3.GetNotificationCount());
295 EXPECT_EQ(0, handler4.GetNotificationCount());
296 }
297
298 this->delegate_.TriggerOnNotificationsDisabled(TRANSIENT_NOTIFICATION_ERROR);
299 EXPECT_EQ(TRANSIENT_NOTIFICATION_ERROR,
300 handler1.GetNotificationsDisabledReason());
301 EXPECT_EQ(TRANSIENT_NOTIFICATION_ERROR,
302 handler2.GetNotificationsDisabledReason());
303 EXPECT_EQ(TRANSIENT_NOTIFICATION_ERROR,
304 handler3.GetNotificationsDisabledReason());
305 EXPECT_EQ(TRANSIENT_NOTIFICATION_ERROR,
306 handler4.GetNotificationsDisabledReason());
307 }
308
309 // Make sure that passing an empty set to UpdateRegisteredIds clears the
310 // corresponding entries for the handler.
311 TYPED_TEST_P(InvalidatorTest, EmptySetUnregisters) {
312 Invalidator* const invalidator = this->CreateAndInitializeInvalidator();
313
314 FakeInvalidationHandler handler1;
315
316 // Control observer.
317 FakeInvalidationHandler handler2;
318
319 invalidator->RegisterHandler(&handler1);
320 invalidator->RegisterHandler(&handler2);
321
322 {
323 ObjectIdSet ids;
324 ids.insert(this->id1);
325 ids.insert(this->id2);
326 invalidator->UpdateRegisteredIds(&handler1, ids);
327 }
328
329 {
330 ObjectIdSet ids;
331 ids.insert(this->id3);
332 invalidator->UpdateRegisteredIds(&handler2, ids);
333 }
334
335 // Unregister the IDs for the first observer. It should not receive any
336 // further invalidations.
337 invalidator->UpdateRegisteredIds(&handler1, ObjectIdSet());
338
339 this->delegate_.TriggerOnNotificationsEnabled();
340 EXPECT_EQ(NO_NOTIFICATION_ERROR,
341 handler1.GetNotificationsDisabledReason());
342 EXPECT_EQ(NO_NOTIFICATION_ERROR,
343 handler2.GetNotificationsDisabledReason());
344
345 {
346 ObjectIdStateMap states;
347 states[this->id1].payload = "1";
348 states[this->id2].payload = "2";
349 states[this->id3].payload = "3";
350 this->delegate_.TriggerOnIncomingNotification(states, REMOTE_NOTIFICATION);
351 EXPECT_EQ(0, handler1.GetNotificationCount());
352 EXPECT_EQ(1, handler2.GetNotificationCount());
353 }
354
355 this->delegate_.TriggerOnNotificationsDisabled(TRANSIENT_NOTIFICATION_ERROR);
356 EXPECT_EQ(TRANSIENT_NOTIFICATION_ERROR,
357 handler1.GetNotificationsDisabledReason());
358 EXPECT_EQ(TRANSIENT_NOTIFICATION_ERROR,
359 handler2.GetNotificationsDisabledReason());
360 }
361
362 // Initialize the invalidator with an empty initial state. Call the deprecated
363 // state setter function a number of times, destroying and re-creating the
364 // invalidator in between. Only the first one should take effect (i.e., state
365 // migration should only happen once).
366 TYPED_TEST_P(InvalidatorTest, MigrateState) {
367 if (!this->delegate_.InvalidatorHandlesDeprecatedState()) {
368 DLOG(INFO) << "This Invalidator doesn't handle deprecated state; "
369 << "skipping";
370 return;
371 }
372
373 this->delegate_.CreateInvalidator(std::string(),
374 this->fake_tracker_.AsWeakPtr());
Nicolas Zea 2012/08/29 23:41:05 fix indent
akalin 2012/08/30 22:20:38 Done.
375 Invalidator* invalidator = this->delegate_.GetInvalidator();
376
377 invalidator->SetStateDeprecated("fake_state");
378 this->delegate_.WaitForInvalidator();
379 EXPECT_EQ("fake_state", this->fake_tracker_.GetInvalidationState());
380
381 // Should do nothing.
382 invalidator->SetStateDeprecated("spurious_fake_state");
383 this->delegate_.WaitForInvalidator();
384 EXPECT_EQ("fake_state", this->fake_tracker_.GetInvalidationState());
385
386 // Pretend that Chrome has shut down.
387 this->delegate_.DestroyInvalidator();
388 this->delegate_.CreateInvalidator("fake_state",
389 this->fake_tracker_.AsWeakPtr());
390 invalidator = this->delegate_.GetInvalidator();
391
392 // Should do nothing.
393 invalidator->SetStateDeprecated("more_spurious_fake_state");
394 this->delegate_.WaitForInvalidator();
395 EXPECT_EQ("fake_state", this->fake_tracker_.GetInvalidationState());
396 }
397
398 REGISTER_TYPED_TEST_CASE_P(InvalidatorTest,
399 Basic, MultipleHandlers, EmptySetUnregisters,
400 MigrateState);
401
402 } // namespace syncer
403
404 #endif // SYNC_NOTIFIER_INVALIDATOR_TEST_TEMPLATE_H_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698