OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/message_loop/message_loop.h" | 5 #include "base/message_loop/message_loop.h" |
6 #include "base/run_loop.h" | 6 #include "base/run_loop.h" |
7 #include "sync/internal_api/public/base/model_type_test_util.h" | 7 #include "sync/internal_api/public/base/model_type_test_util.h" |
8 #include "sync/notifier/invalidation_util.h" | 8 #include "sync/notifier/invalidation_util.h" |
9 #include "sync/notifier/mock_ack_handler.h" | 9 #include "sync/notifier/mock_ack_handler.h" |
10 #include "sync/notifier/object_id_invalidation_map.h" | 10 #include "sync/notifier/object_id_invalidation_map.h" |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
62 } | 62 } |
63 | 63 |
64 int ProtoRefreshRequestedCount(ModelType type) const { | 64 int ProtoRefreshRequestedCount(ModelType type) const { |
65 sync_pb::GetUpdateTriggers gu_trigger; | 65 sync_pb::GetUpdateTriggers gu_trigger; |
66 nudge_tracker_.FillProtoMessage(type, &gu_trigger); | 66 nudge_tracker_.FillProtoMessage(type, &gu_trigger); |
67 return gu_trigger.datatype_refresh_nudges(); | 67 return gu_trigger.datatype_refresh_nudges(); |
68 } | 68 } |
69 | 69 |
70 void SetInvalidationsInSync() { | 70 void SetInvalidationsInSync() { |
71 nudge_tracker_.OnInvalidationsEnabled(); | 71 nudge_tracker_.OnInvalidationsEnabled(); |
72 nudge_tracker_.RecordSuccessfulSyncCycle(base::TimeTicks::Now()); | 72 nudge_tracker_.RecordSuccessfulSyncCycle(); |
73 } | 73 } |
74 | 74 |
75 protected: | 75 protected: |
76 NudgeTracker nudge_tracker_; | 76 NudgeTracker nudge_tracker_; |
77 }; | 77 }; |
78 | 78 |
79 // Exercise an empty NudgeTracker. | 79 // Exercise an empty NudgeTracker. |
80 // Use with valgrind to detect uninitialized members. | 80 // Use with valgrind to detect uninitialized members. |
81 TEST_F(NudgeTrackerTest, EmptyNudgeTracker) { | 81 TEST_F(NudgeTrackerTest, EmptyNudgeTracker) { |
82 // Now we're at the normal, "idle" state. | 82 // Now we're at the normal, "idle" state. |
83 EXPECT_FALSE(nudge_tracker_.IsSyncRequired()); | 83 EXPECT_FALSE(nudge_tracker_.IsSyncRequired()); |
84 EXPECT_FALSE(nudge_tracker_.IsGetUpdatesRequired(base::TimeTicks::Now())); | 84 EXPECT_FALSE(nudge_tracker_.IsGetUpdatesRequired()); |
85 EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::UNKNOWN, | 85 EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::UNKNOWN, |
86 nudge_tracker_.updates_source()); | 86 nudge_tracker_.updates_source()); |
87 | 87 |
88 sync_pb::GetUpdateTriggers gu_trigger; | 88 sync_pb::GetUpdateTriggers gu_trigger; |
89 nudge_tracker_.FillProtoMessage(BOOKMARKS, &gu_trigger); | 89 nudge_tracker_.FillProtoMessage(BOOKMARKS, &gu_trigger); |
90 | 90 |
91 EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::UNKNOWN, | 91 EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::UNKNOWN, |
92 nudge_tracker_.updates_source()); | 92 nudge_tracker_.updates_source()); |
93 } | 93 } |
94 | 94 |
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
264 nudge_tracker_.RecordRemoteInvalidation(invalidation_map); | 264 nudge_tracker_.RecordRemoteInvalidation(invalidation_map); |
265 { | 265 { |
266 sync_pb::GetUpdateTriggers gu_trigger; | 266 sync_pb::GetUpdateTriggers gu_trigger; |
267 nudge_tracker_.FillProtoMessage(BOOKMARKS, &gu_trigger); | 267 nudge_tracker_.FillProtoMessage(BOOKMARKS, &gu_trigger); |
268 EXPECT_TRUE(gu_trigger.server_dropped_hints()); | 268 EXPECT_TRUE(gu_trigger.server_dropped_hints()); |
269 EXPECT_FALSE(gu_trigger.client_dropped_hints()); | 269 EXPECT_FALSE(gu_trigger.client_dropped_hints()); |
270 ASSERT_EQ(0, gu_trigger.notification_hint_size()); | 270 ASSERT_EQ(0, gu_trigger.notification_hint_size()); |
271 } | 271 } |
272 | 272 |
273 // Clear status then verify. | 273 // Clear status then verify. |
274 nudge_tracker_.RecordSuccessfulSyncCycle(base::TimeTicks::Now()); | 274 nudge_tracker_.RecordSuccessfulSyncCycle(); |
275 { | 275 { |
276 sync_pb::GetUpdateTriggers gu_trigger; | 276 sync_pb::GetUpdateTriggers gu_trigger; |
277 nudge_tracker_.FillProtoMessage(BOOKMARKS, &gu_trigger); | 277 nudge_tracker_.FillProtoMessage(BOOKMARKS, &gu_trigger); |
278 EXPECT_FALSE(gu_trigger.client_dropped_hints()); | 278 EXPECT_FALSE(gu_trigger.client_dropped_hints()); |
279 EXPECT_FALSE(gu_trigger.server_dropped_hints()); | 279 EXPECT_FALSE(gu_trigger.server_dropped_hints()); |
280 ASSERT_EQ(0, gu_trigger.notification_hint_size()); | 280 ASSERT_EQ(0, gu_trigger.notification_hint_size()); |
281 } | 281 } |
282 } | 282 } |
283 | 283 |
284 // Tests the receipt of 'unknown version' invalidations. This test also | 284 // Tests the receipt of 'unknown version' invalidations. This test also |
285 // includes a known version invalidation to mix things up a bit. | 285 // includes a known version invalidation to mix things up a bit. |
286 TEST_F(NudgeTrackerTest, DropHintsAtServer_WithOtherInvalidations) { | 286 TEST_F(NudgeTrackerTest, DropHintsAtServer_WithOtherInvalidations) { |
287 ObjectIdInvalidationMap invalidation_map; | 287 ObjectIdInvalidationMap invalidation_map; |
288 invalidation_map.Insert(BuildUnknownVersionInvalidation(BOOKMARKS)); | 288 invalidation_map.Insert(BuildUnknownVersionInvalidation(BOOKMARKS)); |
289 invalidation_map.Insert(BuildInvalidation(BOOKMARKS, 10, "hint")); | 289 invalidation_map.Insert(BuildInvalidation(BOOKMARKS, 10, "hint")); |
290 | 290 |
291 // Record the two invalidations, one with unknown version, the other unknown. | 291 // Record the two invalidations, one with unknown version, the other unknown. |
292 nudge_tracker_.RecordRemoteInvalidation(invalidation_map); | 292 nudge_tracker_.RecordRemoteInvalidation(invalidation_map); |
293 { | 293 { |
294 sync_pb::GetUpdateTriggers gu_trigger; | 294 sync_pb::GetUpdateTriggers gu_trigger; |
295 nudge_tracker_.FillProtoMessage(BOOKMARKS, &gu_trigger); | 295 nudge_tracker_.FillProtoMessage(BOOKMARKS, &gu_trigger); |
296 EXPECT_TRUE(gu_trigger.server_dropped_hints()); | 296 EXPECT_TRUE(gu_trigger.server_dropped_hints()); |
297 EXPECT_FALSE(gu_trigger.client_dropped_hints()); | 297 EXPECT_FALSE(gu_trigger.client_dropped_hints()); |
298 ASSERT_EQ(1, gu_trigger.notification_hint_size()); | 298 ASSERT_EQ(1, gu_trigger.notification_hint_size()); |
299 EXPECT_EQ("hint", gu_trigger.notification_hint(0)); | 299 EXPECT_EQ("hint", gu_trigger.notification_hint(0)); |
300 } | 300 } |
301 | 301 |
302 // Clear status then verify. | 302 // Clear status then verify. |
303 nudge_tracker_.RecordSuccessfulSyncCycle(base::TimeTicks::Now()); | 303 nudge_tracker_.RecordSuccessfulSyncCycle(); |
304 { | 304 { |
305 sync_pb::GetUpdateTriggers gu_trigger; | 305 sync_pb::GetUpdateTriggers gu_trigger; |
306 nudge_tracker_.FillProtoMessage(BOOKMARKS, &gu_trigger); | 306 nudge_tracker_.FillProtoMessage(BOOKMARKS, &gu_trigger); |
307 EXPECT_FALSE(gu_trigger.client_dropped_hints()); | 307 EXPECT_FALSE(gu_trigger.client_dropped_hints()); |
308 EXPECT_FALSE(gu_trigger.server_dropped_hints()); | 308 EXPECT_FALSE(gu_trigger.server_dropped_hints()); |
309 ASSERT_EQ(0, gu_trigger.notification_hint_size()); | 309 ASSERT_EQ(0, gu_trigger.notification_hint_size()); |
310 } | 310 } |
311 } | 311 } |
312 | 312 |
313 // Checks the behaviour of the invalidations-out-of-sync flag. | 313 // Checks the behaviour of the invalidations-out-of-sync flag. |
314 TEST_F(NudgeTrackerTest, EnableDisableInvalidations) { | 314 TEST_F(NudgeTrackerTest, EnableDisableInvalidations) { |
315 // Start with invalidations offline. | 315 // Start with invalidations offline. |
316 nudge_tracker_.OnInvalidationsDisabled(); | 316 nudge_tracker_.OnInvalidationsDisabled(); |
317 EXPECT_TRUE(InvalidationsOutOfSync()); | 317 EXPECT_TRUE(InvalidationsOutOfSync()); |
318 EXPECT_TRUE(nudge_tracker_.IsGetUpdatesRequired(base::TimeTicks::Now())); | 318 EXPECT_TRUE(nudge_tracker_.IsGetUpdatesRequired()); |
319 | 319 |
320 // Simply enabling invalidations does not bring us back into sync. | 320 // Simply enabling invalidations does not bring us back into sync. |
321 nudge_tracker_.OnInvalidationsEnabled(); | 321 nudge_tracker_.OnInvalidationsEnabled(); |
322 EXPECT_TRUE(InvalidationsOutOfSync()); | 322 EXPECT_TRUE(InvalidationsOutOfSync()); |
323 EXPECT_TRUE(nudge_tracker_.IsGetUpdatesRequired(base::TimeTicks::Now())); | 323 EXPECT_TRUE(nudge_tracker_.IsGetUpdatesRequired()); |
324 | 324 |
325 // We must successfully complete a sync cycle while invalidations are enabled | 325 // We must successfully complete a sync cycle while invalidations are enabled |
326 // to be sure that we're in sync. | 326 // to be sure that we're in sync. |
327 nudge_tracker_.RecordSuccessfulSyncCycle(base::TimeTicks::Now()); | 327 nudge_tracker_.RecordSuccessfulSyncCycle(); |
328 EXPECT_FALSE(InvalidationsOutOfSync()); | 328 EXPECT_FALSE(InvalidationsOutOfSync()); |
329 EXPECT_FALSE(nudge_tracker_.IsGetUpdatesRequired(base::TimeTicks::Now())); | 329 EXPECT_FALSE(nudge_tracker_.IsGetUpdatesRequired()); |
330 | 330 |
331 // If the invalidator malfunctions, we go become unsynced again. | 331 // If the invalidator malfunctions, we go become unsynced again. |
332 nudge_tracker_.OnInvalidationsDisabled(); | 332 nudge_tracker_.OnInvalidationsDisabled(); |
333 EXPECT_TRUE(InvalidationsOutOfSync()); | 333 EXPECT_TRUE(InvalidationsOutOfSync()); |
334 EXPECT_TRUE(nudge_tracker_.IsGetUpdatesRequired(base::TimeTicks::Now())); | 334 EXPECT_TRUE(nudge_tracker_.IsGetUpdatesRequired()); |
335 | 335 |
336 // A sync cycle while invalidations are disabled won't reset the flag. | 336 // A sync cycle while invalidations are disabled won't reset the flag. |
337 nudge_tracker_.RecordSuccessfulSyncCycle(base::TimeTicks::Now()); | 337 nudge_tracker_.RecordSuccessfulSyncCycle(); |
338 EXPECT_TRUE(InvalidationsOutOfSync()); | 338 EXPECT_TRUE(InvalidationsOutOfSync()); |
339 EXPECT_TRUE(nudge_tracker_.IsGetUpdatesRequired(base::TimeTicks::Now())); | 339 EXPECT_TRUE(nudge_tracker_.IsGetUpdatesRequired()); |
340 | 340 |
341 // Nor will the re-enabling of invalidations be sufficient, even now that | 341 // Nor will the re-enabling of invalidations be sufficient, even now that |
342 // we've had a successful sync cycle. | 342 // we've had a successful sync cycle. |
343 nudge_tracker_.RecordSuccessfulSyncCycle(base::TimeTicks::Now()); | 343 nudge_tracker_.RecordSuccessfulSyncCycle(); |
344 EXPECT_TRUE(InvalidationsOutOfSync()); | 344 EXPECT_TRUE(InvalidationsOutOfSync()); |
345 EXPECT_TRUE(nudge_tracker_.IsGetUpdatesRequired(base::TimeTicks::Now())); | 345 EXPECT_TRUE(nudge_tracker_.IsGetUpdatesRequired()); |
346 } | 346 } |
347 | 347 |
348 // Tests that locally modified types are correctly written out to the | 348 // Tests that locally modified types are correctly written out to the |
349 // GetUpdateTriggers proto. | 349 // GetUpdateTriggers proto. |
350 TEST_F(NudgeTrackerTest, WriteLocallyModifiedTypesToProto) { | 350 TEST_F(NudgeTrackerTest, WriteLocallyModifiedTypesToProto) { |
351 // Should not be locally modified by default. | 351 // Should not be locally modified by default. |
352 EXPECT_EQ(0, ProtoLocallyModifiedCount(PREFERENCES)); | 352 EXPECT_EQ(0, ProtoLocallyModifiedCount(PREFERENCES)); |
353 | 353 |
354 // Record a local bookmark change. Verify it was registered correctly. | 354 // Record a local bookmark change. Verify it was registered correctly. |
355 nudge_tracker_.RecordLocalChange(ModelTypeSet(PREFERENCES)); | 355 nudge_tracker_.RecordLocalChange(ModelTypeSet(PREFERENCES)); |
356 EXPECT_EQ(1, ProtoLocallyModifiedCount(PREFERENCES)); | 356 EXPECT_EQ(1, ProtoLocallyModifiedCount(PREFERENCES)); |
357 | 357 |
358 // Record a successful sync cycle. Verify the count is cleared. | 358 // Record a successful sync cycle. Verify the count is cleared. |
359 nudge_tracker_.RecordSuccessfulSyncCycle(base::TimeTicks::Now()); | 359 nudge_tracker_.RecordSuccessfulSyncCycle(); |
360 EXPECT_EQ(0, ProtoLocallyModifiedCount(PREFERENCES)); | 360 EXPECT_EQ(0, ProtoLocallyModifiedCount(PREFERENCES)); |
361 } | 361 } |
362 | 362 |
363 // Tests that refresh requested types are correctly written out to the | 363 // Tests that refresh requested types are correctly written out to the |
364 // GetUpdateTriggers proto. | 364 // GetUpdateTriggers proto. |
365 TEST_F(NudgeTrackerTest, WriteRefreshRequestedTypesToProto) { | 365 TEST_F(NudgeTrackerTest, WriteRefreshRequestedTypesToProto) { |
366 // There should be no refresh requested by default. | 366 // There should be no refresh requested by default. |
367 EXPECT_EQ(0, ProtoRefreshRequestedCount(SESSIONS)); | 367 EXPECT_EQ(0, ProtoRefreshRequestedCount(SESSIONS)); |
368 | 368 |
369 // Record a local refresh request. Verify it was registered correctly. | 369 // Record a local refresh request. Verify it was registered correctly. |
370 nudge_tracker_.RecordLocalRefreshRequest(ModelTypeSet(SESSIONS)); | 370 nudge_tracker_.RecordLocalRefreshRequest(ModelTypeSet(SESSIONS)); |
371 EXPECT_EQ(1, ProtoRefreshRequestedCount(SESSIONS)); | 371 EXPECT_EQ(1, ProtoRefreshRequestedCount(SESSIONS)); |
372 | 372 |
373 // Record a successful sync cycle. Verify the count is cleared. | 373 // Record a successful sync cycle. Verify the count is cleared. |
374 nudge_tracker_.RecordSuccessfulSyncCycle(base::TimeTicks::Now()); | 374 nudge_tracker_.RecordSuccessfulSyncCycle(); |
375 EXPECT_EQ(0, ProtoRefreshRequestedCount(SESSIONS)); | 375 EXPECT_EQ(0, ProtoRefreshRequestedCount(SESSIONS)); |
376 } | 376 } |
377 | 377 |
378 // Basic tests for the IsSyncRequired() flag. | 378 // Basic tests for the IsSyncRequired() flag. |
379 TEST_F(NudgeTrackerTest, IsSyncRequired) { | 379 TEST_F(NudgeTrackerTest, IsSyncRequired) { |
380 EXPECT_FALSE(nudge_tracker_.IsSyncRequired()); | 380 EXPECT_FALSE(nudge_tracker_.IsSyncRequired()); |
381 | 381 |
382 // Local changes. | 382 // Local changes. |
383 nudge_tracker_.RecordLocalChange(ModelTypeSet(SESSIONS)); | 383 nudge_tracker_.RecordLocalChange(ModelTypeSet(SESSIONS)); |
384 EXPECT_TRUE(nudge_tracker_.IsSyncRequired()); | 384 EXPECT_TRUE(nudge_tracker_.IsSyncRequired()); |
385 nudge_tracker_.RecordSuccessfulSyncCycle(base::TimeTicks::Now()); | 385 nudge_tracker_.RecordSuccessfulSyncCycle(); |
386 EXPECT_FALSE(nudge_tracker_.IsSyncRequired()); | 386 EXPECT_FALSE(nudge_tracker_.IsSyncRequired()); |
387 | 387 |
388 // Refresh requests. | 388 // Refresh requests. |
389 nudge_tracker_.RecordLocalRefreshRequest(ModelTypeSet(SESSIONS)); | 389 nudge_tracker_.RecordLocalRefreshRequest(ModelTypeSet(SESSIONS)); |
390 EXPECT_TRUE(nudge_tracker_.IsSyncRequired()); | 390 EXPECT_TRUE(nudge_tracker_.IsSyncRequired()); |
391 nudge_tracker_.RecordSuccessfulSyncCycle(base::TimeTicks::Now()); | 391 nudge_tracker_.RecordSuccessfulSyncCycle(); |
392 EXPECT_FALSE(nudge_tracker_.IsSyncRequired()); | 392 EXPECT_FALSE(nudge_tracker_.IsSyncRequired()); |
393 | 393 |
394 // Invalidations. | 394 // Invalidations. |
395 ObjectIdInvalidationMap invalidation_map = | 395 ObjectIdInvalidationMap invalidation_map = |
396 BuildInvalidationMap(PREFERENCES, 1, "hint"); | 396 BuildInvalidationMap(PREFERENCES, 1, "hint"); |
397 nudge_tracker_.RecordRemoteInvalidation(invalidation_map); | 397 nudge_tracker_.RecordRemoteInvalidation(invalidation_map); |
398 EXPECT_TRUE(nudge_tracker_.IsSyncRequired()); | 398 EXPECT_TRUE(nudge_tracker_.IsSyncRequired()); |
399 nudge_tracker_.RecordSuccessfulSyncCycle(base::TimeTicks::Now()); | 399 nudge_tracker_.RecordSuccessfulSyncCycle(); |
400 EXPECT_FALSE(nudge_tracker_.IsSyncRequired()); | 400 EXPECT_FALSE(nudge_tracker_.IsSyncRequired()); |
401 } | 401 } |
402 | 402 |
403 // Basic tests for the IsGetUpdatesRequired() flag. | 403 // Basic tests for the IsGetUpdatesRequired() flag. |
404 TEST_F(NudgeTrackerTest, IsGetUpdatesRequired) { | 404 TEST_F(NudgeTrackerTest, IsGetUpdatesRequired) { |
405 EXPECT_FALSE(nudge_tracker_.IsGetUpdatesRequired(base::TimeTicks::Now())); | 405 EXPECT_FALSE(nudge_tracker_.IsGetUpdatesRequired()); |
406 | 406 |
407 // Local changes. | 407 // Local changes. |
408 nudge_tracker_.RecordLocalChange(ModelTypeSet(SESSIONS)); | 408 nudge_tracker_.RecordLocalChange(ModelTypeSet(SESSIONS)); |
409 EXPECT_FALSE(nudge_tracker_.IsGetUpdatesRequired(base::TimeTicks::Now())); | 409 EXPECT_FALSE(nudge_tracker_.IsGetUpdatesRequired()); |
410 nudge_tracker_.RecordSuccessfulSyncCycle(base::TimeTicks::Now()); | 410 nudge_tracker_.RecordSuccessfulSyncCycle(); |
411 EXPECT_FALSE(nudge_tracker_.IsGetUpdatesRequired(base::TimeTicks::Now())); | 411 EXPECT_FALSE(nudge_tracker_.IsGetUpdatesRequired()); |
412 | 412 |
413 // Refresh requests. | 413 // Refresh requests. |
414 nudge_tracker_.RecordLocalRefreshRequest(ModelTypeSet(SESSIONS)); | 414 nudge_tracker_.RecordLocalRefreshRequest(ModelTypeSet(SESSIONS)); |
415 EXPECT_TRUE(nudge_tracker_.IsGetUpdatesRequired(base::TimeTicks::Now())); | 415 EXPECT_TRUE(nudge_tracker_.IsGetUpdatesRequired()); |
416 nudge_tracker_.RecordSuccessfulSyncCycle(base::TimeTicks::Now()); | 416 nudge_tracker_.RecordSuccessfulSyncCycle(); |
417 EXPECT_FALSE(nudge_tracker_.IsGetUpdatesRequired(base::TimeTicks::Now())); | 417 EXPECT_FALSE(nudge_tracker_.IsGetUpdatesRequired()); |
418 | 418 |
419 // Invalidations. | 419 // Invalidations. |
420 ObjectIdInvalidationMap invalidation_map = | 420 ObjectIdInvalidationMap invalidation_map = |
421 BuildInvalidationMap(PREFERENCES, 1, "hint"); | 421 BuildInvalidationMap(PREFERENCES, 1, "hint"); |
422 nudge_tracker_.RecordRemoteInvalidation(invalidation_map); | 422 nudge_tracker_.RecordRemoteInvalidation(invalidation_map); |
423 EXPECT_TRUE(nudge_tracker_.IsGetUpdatesRequired(base::TimeTicks::Now())); | 423 EXPECT_TRUE(nudge_tracker_.IsGetUpdatesRequired()); |
424 nudge_tracker_.RecordSuccessfulSyncCycle(base::TimeTicks::Now()); | 424 nudge_tracker_.RecordSuccessfulSyncCycle(); |
425 EXPECT_FALSE(nudge_tracker_.IsGetUpdatesRequired(base::TimeTicks::Now())); | 425 EXPECT_FALSE(nudge_tracker_.IsGetUpdatesRequired()); |
426 } | 426 } |
427 | 427 |
428 // Test IsSyncRequired() responds correctly to data type throttling. | 428 // Test IsSyncRequired() responds correctly to data type throttling. |
429 TEST_F(NudgeTrackerTest, IsSyncRequired_Throttling) { | 429 TEST_F(NudgeTrackerTest, IsSyncRequired_Throttling) { |
430 const base::TimeTicks t0 = base::TimeTicks::FromInternalValue(1234); | 430 const base::TimeTicks t0 = base::TimeTicks::FromInternalValue(1234); |
431 const base::TimeDelta throttle_length = base::TimeDelta::FromMinutes(10); | 431 const base::TimeDelta throttle_length = base::TimeDelta::FromMinutes(10); |
432 const base::TimeTicks t1 = t0 + throttle_length; | 432 const base::TimeTicks t1 = t0 + throttle_length; |
433 | 433 |
434 EXPECT_FALSE(nudge_tracker_.IsSyncRequired()); | 434 EXPECT_FALSE(nudge_tracker_.IsSyncRequired()); |
435 | 435 |
436 // A local change to sessions enables the flag. | 436 // A local change to sessions enables the flag. |
437 nudge_tracker_.RecordLocalChange(ModelTypeSet(SESSIONS)); | 437 nudge_tracker_.RecordLocalChange(ModelTypeSet(SESSIONS)); |
438 EXPECT_TRUE(nudge_tracker_.IsSyncRequired()); | 438 EXPECT_TRUE(nudge_tracker_.IsSyncRequired()); |
439 | 439 |
440 // But the throttling of sessions unsets it. | 440 // But the throttling of sessions unsets it. |
441 nudge_tracker_.SetTypesThrottledUntil(ModelTypeSet(SESSIONS), | 441 nudge_tracker_.SetTypesThrottledUntil(ModelTypeSet(SESSIONS), |
442 throttle_length, | 442 throttle_length, |
443 t0); | 443 t0); |
444 EXPECT_FALSE(nudge_tracker_.IsSyncRequired()); | 444 EXPECT_FALSE(nudge_tracker_.IsSyncRequired()); |
445 | 445 |
446 // A refresh request for bookmarks means we have reason to sync again. | 446 // A refresh request for bookmarks means we have reason to sync again. |
447 nudge_tracker_.RecordLocalRefreshRequest(ModelTypeSet(BOOKMARKS)); | 447 nudge_tracker_.RecordLocalRefreshRequest(ModelTypeSet(BOOKMARKS)); |
448 EXPECT_TRUE(nudge_tracker_.IsSyncRequired()); | 448 EXPECT_TRUE(nudge_tracker_.IsSyncRequired()); |
449 | 449 |
450 // A successful sync cycle means we took care of bookmarks. | 450 // A successful sync cycle means we took care of bookmarks. |
451 nudge_tracker_.RecordSuccessfulSyncCycle(base::TimeTicks::Now()); | 451 nudge_tracker_.RecordSuccessfulSyncCycle(); |
452 EXPECT_FALSE(nudge_tracker_.IsSyncRequired()); | 452 EXPECT_FALSE(nudge_tracker_.IsSyncRequired()); |
453 | 453 |
454 // But we still haven't dealt with sessions. We'll need to remember | 454 // But we still haven't dealt with sessions. We'll need to remember |
455 // that sessions are out of sync and re-enable the flag when their | 455 // that sessions are out of sync and re-enable the flag when their |
456 // throttling interval expires. | 456 // throttling interval expires. |
457 nudge_tracker_.UpdateTypeThrottlingState(t1); | 457 nudge_tracker_.UpdateTypeThrottlingState(t1); |
458 EXPECT_FALSE(nudge_tracker_.IsTypeThrottled(SESSIONS)); | 458 EXPECT_FALSE(nudge_tracker_.IsTypeThrottled(SESSIONS)); |
459 EXPECT_TRUE(nudge_tracker_.IsSyncRequired()); | 459 EXPECT_TRUE(nudge_tracker_.IsSyncRequired()); |
460 } | 460 } |
461 | 461 |
462 // Test IsGetUpdatesRequired() responds correctly to data type throttling. | 462 // Test IsGetUpdatesRequired() responds correctly to data type throttling. |
463 TEST_F(NudgeTrackerTest, IsGetUpdatesRequired_Throttling) { | 463 TEST_F(NudgeTrackerTest, IsGetUpdatesRequired_Throttling) { |
464 const base::TimeTicks t0 = base::TimeTicks::FromInternalValue(1234); | 464 const base::TimeTicks t0 = base::TimeTicks::FromInternalValue(1234); |
465 const base::TimeDelta throttle_length = base::TimeDelta::FromMinutes(10); | 465 const base::TimeDelta throttle_length = base::TimeDelta::FromMinutes(10); |
466 const base::TimeTicks t1 = t0 + throttle_length; | 466 const base::TimeTicks t1 = t0 + throttle_length; |
467 | 467 |
468 EXPECT_FALSE(nudge_tracker_.IsGetUpdatesRequired(base::TimeTicks::Now())); | 468 EXPECT_FALSE(nudge_tracker_.IsGetUpdatesRequired()); |
469 | 469 |
470 // A refresh request to sessions enables the flag. | 470 // A refresh request to sessions enables the flag. |
471 nudge_tracker_.RecordLocalRefreshRequest(ModelTypeSet(SESSIONS)); | 471 nudge_tracker_.RecordLocalRefreshRequest(ModelTypeSet(SESSIONS)); |
472 EXPECT_TRUE(nudge_tracker_.IsGetUpdatesRequired(base::TimeTicks::Now())); | 472 EXPECT_TRUE(nudge_tracker_.IsGetUpdatesRequired()); |
473 | 473 |
474 // But the throttling of sessions unsets it. | 474 // But the throttling of sessions unsets it. |
475 nudge_tracker_.SetTypesThrottledUntil(ModelTypeSet(SESSIONS), | 475 nudge_tracker_.SetTypesThrottledUntil(ModelTypeSet(SESSIONS), |
476 throttle_length, | 476 throttle_length, |
477 t0); | 477 t0); |
478 EXPECT_FALSE(nudge_tracker_.IsGetUpdatesRequired(base::TimeTicks::Now())); | 478 EXPECT_FALSE(nudge_tracker_.IsGetUpdatesRequired()); |
479 | 479 |
480 // A refresh request for bookmarks means we have reason to sync again. | 480 // A refresh request for bookmarks means we have reason to sync again. |
481 nudge_tracker_.RecordLocalRefreshRequest(ModelTypeSet(BOOKMARKS)); | 481 nudge_tracker_.RecordLocalRefreshRequest(ModelTypeSet(BOOKMARKS)); |
482 EXPECT_TRUE(nudge_tracker_.IsGetUpdatesRequired(base::TimeTicks::Now())); | 482 EXPECT_TRUE(nudge_tracker_.IsGetUpdatesRequired()); |
483 | 483 |
484 // A successful sync cycle means we took care of bookmarks. | 484 // A successful sync cycle means we took care of bookmarks. |
485 nudge_tracker_.RecordSuccessfulSyncCycle(base::TimeTicks::Now()); | 485 nudge_tracker_.RecordSuccessfulSyncCycle(); |
486 EXPECT_FALSE(nudge_tracker_.IsGetUpdatesRequired(base::TimeTicks::Now())); | 486 EXPECT_FALSE(nudge_tracker_.IsGetUpdatesRequired()); |
487 | 487 |
488 // But we still haven't dealt with sessions. We'll need to remember | 488 // But we still haven't dealt with sessions. We'll need to remember |
489 // that sessions are out of sync and re-enable the flag when their | 489 // that sessions are out of sync and re-enable the flag when their |
490 // throttling interval expires. | 490 // throttling interval expires. |
491 nudge_tracker_.UpdateTypeThrottlingState(t1); | 491 nudge_tracker_.UpdateTypeThrottlingState(t1); |
492 EXPECT_FALSE(nudge_tracker_.IsTypeThrottled(SESSIONS)); | 492 EXPECT_FALSE(nudge_tracker_.IsTypeThrottled(SESSIONS)); |
493 EXPECT_TRUE(nudge_tracker_.IsGetUpdatesRequired(base::TimeTicks::Now())); | 493 EXPECT_TRUE(nudge_tracker_.IsGetUpdatesRequired()); |
494 } | 494 } |
495 | 495 |
496 // Tests throttling-related getter functions when no types are throttled. | 496 // Tests throttling-related getter functions when no types are throttled. |
497 TEST_F(NudgeTrackerTest, NoTypesThrottled) { | 497 TEST_F(NudgeTrackerTest, NoTypesThrottled) { |
498 EXPECT_FALSE(nudge_tracker_.IsAnyTypeThrottled()); | 498 EXPECT_FALSE(nudge_tracker_.IsAnyTypeThrottled()); |
499 EXPECT_FALSE(nudge_tracker_.IsTypeThrottled(SESSIONS)); | 499 EXPECT_FALSE(nudge_tracker_.IsTypeThrottled(SESSIONS)); |
500 EXPECT_TRUE(nudge_tracker_.GetThrottledTypes().Empty()); | 500 EXPECT_TRUE(nudge_tracker_.GetThrottledTypes().Empty()); |
501 } | 501 } |
502 | 502 |
503 // Tests throttling-related getter functions when some types are throttled. | 503 // Tests throttling-related getter functions when some types are throttled. |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
560 nudge_tracker_.GetThrottledTypes())); | 560 nudge_tracker_.GetThrottledTypes())); |
561 EXPECT_EQ(throttle2_length - throttle1_length, | 561 EXPECT_EQ(throttle2_length - throttle1_length, |
562 nudge_tracker_.GetTimeUntilNextUnthrottle(t1)); | 562 nudge_tracker_.GetTimeUntilNextUnthrottle(t1)); |
563 | 563 |
564 // Expire the second interval. | 564 // Expire the second interval. |
565 nudge_tracker_.UpdateTypeThrottlingState(t2); | 565 nudge_tracker_.UpdateTypeThrottlingState(t2); |
566 EXPECT_TRUE(nudge_tracker_.GetThrottledTypes().Empty()); | 566 EXPECT_TRUE(nudge_tracker_.GetThrottledTypes().Empty()); |
567 } | 567 } |
568 | 568 |
569 TEST_F(NudgeTrackerTest, Retry) { | 569 TEST_F(NudgeTrackerTest, Retry) { |
570 const base::TimeTicks retry_time = base::TimeTicks::FromInternalValue(12345); | 570 const base::TimeTicks t0 = base::TimeTicks::FromInternalValue(12345); |
571 const base::TimeTicks pre_retry_time = | 571 const base::TimeTicks t3 = t0 + base::TimeDelta::FromSeconds(3); |
572 retry_time - base::TimeDelta::FromSeconds(1); | 572 const base::TimeTicks t4 = t0 + base::TimeDelta::FromSeconds(4); |
573 const base::TimeTicks post_retry_time = | |
574 retry_time + base::TimeDelta::FromSeconds(1); | |
575 nudge_tracker_.set_next_retry_time(retry_time); | |
576 | 573 |
577 EXPECT_FALSE(nudge_tracker_.IsRetryRequired(pre_retry_time)); | 574 // Set retry for t3. |
578 EXPECT_FALSE(nudge_tracker_.IsGetUpdatesRequired(pre_retry_time)); | 575 nudge_tracker_.SetNextRetryTime(t3); |
579 nudge_tracker_.RecordSuccessfulSyncCycle(pre_retry_time); | |
580 | 576 |
581 EXPECT_TRUE(nudge_tracker_.IsRetryRequired(post_retry_time)); | 577 // Not due yet at t0. |
582 EXPECT_TRUE(nudge_tracker_.IsGetUpdatesRequired(post_retry_time)); | 578 nudge_tracker_.SetSyncCycleStartTime(t0); |
583 nudge_tracker_.RecordSuccessfulSyncCycle(post_retry_time); | 579 EXPECT_FALSE(nudge_tracker_.IsRetryRequired()); |
584 EXPECT_FALSE(nudge_tracker_.IsRetryRequired( | 580 EXPECT_FALSE(nudge_tracker_.IsGetUpdatesRequired()); |
585 post_retry_time + base::TimeDelta::FromSeconds(1))); | 581 |
| 582 // Successful sync cycle at t0 changes nothing. |
| 583 nudge_tracker_.RecordSuccessfulSyncCycle(); |
| 584 EXPECT_FALSE(nudge_tracker_.IsRetryRequired()); |
| 585 EXPECT_FALSE(nudge_tracker_.IsGetUpdatesRequired()); |
| 586 |
| 587 // At t4, the retry becomes due. |
| 588 nudge_tracker_.SetSyncCycleStartTime(t4); |
| 589 EXPECT_TRUE(nudge_tracker_.IsRetryRequired()); |
| 590 EXPECT_TRUE(nudge_tracker_.IsGetUpdatesRequired()); |
| 591 |
| 592 // A sync cycle unsets the flag. |
| 593 nudge_tracker_.RecordSuccessfulSyncCycle(); |
| 594 EXPECT_FALSE(nudge_tracker_.IsRetryRequired()); |
| 595 |
| 596 // It's still unset at the start of the next sync cycle. |
| 597 nudge_tracker_.SetSyncCycleStartTime(t4); |
| 598 EXPECT_FALSE(nudge_tracker_.IsRetryRequired()); |
| 599 } |
| 600 |
| 601 // Test a mid-cycle update when IsRetryRequired() was true before the cycle |
| 602 // began. |
| 603 TEST_F(NudgeTrackerTest, IsRetryRequired_MidCycleUpdate1) { |
| 604 const base::TimeTicks t0 = base::TimeTicks::FromInternalValue(12345); |
| 605 const base::TimeTicks t1 = t0 + base::TimeDelta::FromSeconds(1); |
| 606 const base::TimeTicks t2 = t0 + base::TimeDelta::FromSeconds(2); |
| 607 const base::TimeTicks t5 = t0 + base::TimeDelta::FromSeconds(5); |
| 608 const base::TimeTicks t6 = t0 + base::TimeDelta::FromSeconds(6); |
| 609 |
| 610 nudge_tracker_.SetNextRetryTime(t0); |
| 611 nudge_tracker_.SetSyncCycleStartTime(t1); |
| 612 |
| 613 EXPECT_TRUE(nudge_tracker_.IsRetryRequired()); |
| 614 |
| 615 // Pretend that we were updated mid-cycle. SetSyncCycleStartTime is |
| 616 // called only at the start of the sync cycle, so don't call it here. |
| 617 // The update should have no effect on IsRetryRequired(). |
| 618 nudge_tracker_.SetNextRetryTime(t5); |
| 619 |
| 620 EXPECT_TRUE(nudge_tracker_.IsRetryRequired()); |
| 621 |
| 622 // Verify that the successful sync cycle clears the flag. |
| 623 nudge_tracker_.RecordSuccessfulSyncCycle(); |
| 624 EXPECT_FALSE(nudge_tracker_.IsRetryRequired()); |
| 625 |
| 626 // Verify expecations around the new retry time. |
| 627 nudge_tracker_.SetSyncCycleStartTime(t2); |
| 628 EXPECT_FALSE(nudge_tracker_.IsRetryRequired()); |
| 629 |
| 630 nudge_tracker_.SetSyncCycleStartTime(t6); |
| 631 EXPECT_TRUE(nudge_tracker_.IsRetryRequired()); |
| 632 } |
| 633 |
| 634 // Test a mid-cycle update when IsRetryRequired() was false before the cycle |
| 635 // began. |
| 636 TEST_F(NudgeTrackerTest, IsRetryRequired_MidCycleUpdate2) { |
| 637 const base::TimeTicks t0 = base::TimeTicks::FromInternalValue(12345); |
| 638 const base::TimeTicks t1 = t0 + base::TimeDelta::FromSeconds(1); |
| 639 const base::TimeTicks t3 = t0 + base::TimeDelta::FromSeconds(3); |
| 640 const base::TimeTicks t5 = t0 + base::TimeDelta::FromSeconds(5); |
| 641 const base::TimeTicks t6 = t0 + base::TimeDelta::FromSeconds(6); |
| 642 |
| 643 // Schedule a future retry, and a nudge unrelated to it. |
| 644 nudge_tracker_.RecordLocalChange(ModelTypeSet(BOOKMARKS)); |
| 645 nudge_tracker_.SetNextRetryTime(t1); |
| 646 nudge_tracker_.SetSyncCycleStartTime(t0); |
| 647 EXPECT_FALSE(nudge_tracker_.IsRetryRequired()); |
| 648 |
| 649 // Pretend this happened in mid-cycle. This should have no effect on |
| 650 // IsRetryRequired(). |
| 651 nudge_tracker_.SetNextRetryTime(t5); |
| 652 EXPECT_FALSE(nudge_tracker_.IsRetryRequired()); |
| 653 |
| 654 // The cycle succeeded. |
| 655 nudge_tracker_.RecordSuccessfulSyncCycle(); |
| 656 |
| 657 // The time t3 is greater than the GU retry time scheduled at the beginning of |
| 658 // the test, but later than the retry time that overwrote it during the |
| 659 // pretend 'sync cycle'. |
| 660 nudge_tracker_.SetSyncCycleStartTime(t3); |
| 661 EXPECT_FALSE(nudge_tracker_.IsRetryRequired()); |
| 662 |
| 663 // Finally, the retry established during the sync cycle becomes due. |
| 664 nudge_tracker_.SetSyncCycleStartTime(t6); |
| 665 EXPECT_TRUE(nudge_tracker_.IsRetryRequired()); |
| 666 } |
| 667 |
| 668 // Simulate the case where a sync cycle fails. |
| 669 TEST_F(NudgeTrackerTest, IsRetryRequired_FailedCycle) { |
| 670 const base::TimeTicks t0 = base::TimeTicks::FromInternalValue(12345); |
| 671 const base::TimeTicks t1 = t0 + base::TimeDelta::FromSeconds(1); |
| 672 const base::TimeTicks t2 = t0 + base::TimeDelta::FromSeconds(2); |
| 673 |
| 674 nudge_tracker_.SetNextRetryTime(t0); |
| 675 nudge_tracker_.SetSyncCycleStartTime(t1); |
| 676 EXPECT_TRUE(nudge_tracker_.IsRetryRequired()); |
| 677 |
| 678 // The nudge tracker receives no notifications for a failed sync cycle. |
| 679 // Pretend one happened here. |
| 680 EXPECT_TRUE(nudge_tracker_.IsRetryRequired()); |
| 681 |
| 682 // Think of this as the retry cycle. |
| 683 nudge_tracker_.SetSyncCycleStartTime(t2); |
| 684 EXPECT_TRUE(nudge_tracker_.IsRetryRequired()); |
| 685 |
| 686 // The second cycle is a success. |
| 687 nudge_tracker_.RecordSuccessfulSyncCycle(); |
| 688 EXPECT_FALSE(nudge_tracker_.IsRetryRequired()); |
| 689 } |
| 690 |
| 691 // Simulate a partially failed sync cycle. The callback to update the GU retry |
| 692 // was invoked, but the sync cycle did not complete successfully. |
| 693 TEST_F(NudgeTrackerTest, IsRetryRequired_FailedCycleIncludesUpdate) { |
| 694 const base::TimeTicks t0 = base::TimeTicks::FromInternalValue(12345); |
| 695 const base::TimeTicks t1 = t0 + base::TimeDelta::FromSeconds(1); |
| 696 const base::TimeTicks t3 = t0 + base::TimeDelta::FromSeconds(3); |
| 697 const base::TimeTicks t4 = t0 + base::TimeDelta::FromSeconds(4); |
| 698 const base::TimeTicks t5 = t0 + base::TimeDelta::FromSeconds(5); |
| 699 const base::TimeTicks t6 = t0 + base::TimeDelta::FromSeconds(6); |
| 700 |
| 701 nudge_tracker_.SetNextRetryTime(t0); |
| 702 nudge_tracker_.SetSyncCycleStartTime(t1); |
| 703 EXPECT_TRUE(nudge_tracker_.IsRetryRequired()); |
| 704 |
| 705 // The cycle is in progress. A new GU Retry time is received. |
| 706 // The flag is not because this cycle is still in progress. |
| 707 nudge_tracker_.SetNextRetryTime(t5); |
| 708 EXPECT_TRUE(nudge_tracker_.IsRetryRequired()); |
| 709 |
| 710 // The nudge tracker receives no notifications for a failed sync cycle. |
| 711 // Pretend the cycle failed here. |
| 712 |
| 713 // The next sync cycle starts. The new GU time has not taken effect by this |
| 714 // time, but the NudgeTracker hasn't forgotten that we have not yet serviced |
| 715 // the retry from the previous cycle. |
| 716 nudge_tracker_.SetSyncCycleStartTime(t3); |
| 717 EXPECT_TRUE(nudge_tracker_.IsRetryRequired()); |
| 718 |
| 719 // It succeeds. The retry time is not updated, so it should remain at t5. |
| 720 nudge_tracker_.RecordSuccessfulSyncCycle(); |
| 721 |
| 722 // Another sync cycle. This one is still before the scheduled retry. It does |
| 723 // not change the scheduled retry time. |
| 724 nudge_tracker_.SetSyncCycleStartTime(t4); |
| 725 EXPECT_FALSE(nudge_tracker_.IsRetryRequired()); |
| 726 nudge_tracker_.RecordSuccessfulSyncCycle(); |
| 727 |
| 728 // The retry scheduled way back during the first cycle of this test finally |
| 729 // becomes due. Perform a successful sync cycle to service it. |
| 730 nudge_tracker_.SetSyncCycleStartTime(t6); |
| 731 EXPECT_TRUE(nudge_tracker_.IsRetryRequired()); |
| 732 nudge_tracker_.RecordSuccessfulSyncCycle(); |
586 } | 733 } |
587 | 734 |
588 class NudgeTrackerAckTrackingTest : public NudgeTrackerTest { | 735 class NudgeTrackerAckTrackingTest : public NudgeTrackerTest { |
589 public: | 736 public: |
590 NudgeTrackerAckTrackingTest() {} | 737 NudgeTrackerAckTrackingTest() {} |
591 | 738 |
592 bool IsInvalidationUnacknowledged(const syncer::Invalidation& invalidation) { | 739 bool IsInvalidationUnacknowledged(const syncer::Invalidation& invalidation) { |
593 // Run pending tasks before checking with the MockAckHandler. | 740 // Run pending tasks before checking with the MockAckHandler. |
594 // The WeakHandle may have posted some tasks for it. | 741 // The WeakHandle may have posted some tasks for it. |
595 base::RunLoop().RunUntilIdle(); | 742 base::RunLoop().RunUntilIdle(); |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
639 // Send it to the NudgeTracker. | 786 // Send it to the NudgeTracker. |
640 ObjectIdInvalidationMap invalidation_map; | 787 ObjectIdInvalidationMap invalidation_map; |
641 invalidation_map.Insert(invalidation); | 788 invalidation_map.Insert(invalidation); |
642 nudge_tracker_.RecordRemoteInvalidation(invalidation_map); | 789 nudge_tracker_.RecordRemoteInvalidation(invalidation_map); |
643 | 790 |
644 // Return it to the test framework for use in assertions. | 791 // Return it to the test framework for use in assertions. |
645 return invalidation; | 792 return invalidation; |
646 } | 793 } |
647 | 794 |
648 void RecordSuccessfulSyncCycle() { | 795 void RecordSuccessfulSyncCycle() { |
649 nudge_tracker_.RecordSuccessfulSyncCycle(base::TimeTicks::Now()); | 796 nudge_tracker_.RecordSuccessfulSyncCycle(); |
650 } | 797 } |
651 | 798 |
652 private: | 799 private: |
653 syncer::MockAckHandler mock_ack_handler_; | 800 syncer::MockAckHandler mock_ack_handler_; |
654 base::MessageLoop loop_; | 801 base::MessageLoop loop_; |
655 }; | 802 }; |
656 | 803 |
657 // Test the acknowledgement of a single invalidation. | 804 // Test the acknowledgement of a single invalidation. |
658 TEST_F(NudgeTrackerAckTrackingTest, SimpleAcknowledgement) { | 805 TEST_F(NudgeTrackerAckTrackingTest, SimpleAcknowledgement) { |
659 Invalidation inv = SendInvalidation(BOOKMARKS, 10, "hint"); | 806 Invalidation inv = SendInvalidation(BOOKMARKS, 10, "hint"); |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
752 EXPECT_TRUE(IsInvalidationAcknowledged(inv2)); | 899 EXPECT_TRUE(IsInvalidationAcknowledged(inv2)); |
753 EXPECT_TRUE(IsInvalidationAcknowledged(inv3)); | 900 EXPECT_TRUE(IsInvalidationAcknowledged(inv3)); |
754 EXPECT_TRUE(IsInvalidationAcknowledged(inv4)); | 901 EXPECT_TRUE(IsInvalidationAcknowledged(inv4)); |
755 EXPECT_TRUE(IsInvalidationAcknowledged(inv5)); | 902 EXPECT_TRUE(IsInvalidationAcknowledged(inv5)); |
756 | 903 |
757 EXPECT_TRUE(AllInvalidationsAccountedFor()); | 904 EXPECT_TRUE(AllInvalidationsAccountedFor()); |
758 } | 905 } |
759 | 906 |
760 } // namespace sessions | 907 } // namespace sessions |
761 } // namespace syncer | 908 } // namespace syncer |
OLD | NEW |