Index: chrome/browser/sync/test/integration/single_client_user_events_sync_test.cc |
diff --git a/chrome/browser/sync/test/integration/single_client_user_events_sync_test.cc b/chrome/browser/sync/test/integration/single_client_user_events_sync_test.cc |
index 8a7564ce2da64a5042e8f0e9e91a64769ea03130..d5f69296ccb2f3fc980f2f0db841d91089b5710b 100644 |
--- a/chrome/browser/sync/test/integration/single_client_user_events_sync_test.cc |
+++ b/chrome/browser/sync/test/integration/single_client_user_events_sync_test.cc |
@@ -11,12 +11,44 @@ |
#include "components/sync/protocol/user_event_specifics.pb.h" |
#include "components/sync/user_events/user_event_service.h" |
+using base::Time; |
+using base::TimeDelta; |
using fake_server::FakeServer; |
using sync_pb::UserEventSpecifics; |
using sync_pb::SyncEntity; |
+using sync_pb::CommitResponse; |
namespace { |
+UserEventSpecifics CreateEvent(int minutes_ago) { |
+ UserEventSpecifics specifics; |
+ specifics.set_event_time_usec( |
+ (Time::Now() - TimeDelta::FromMinutes(minutes_ago)).ToInternalValue()); |
+ specifics.mutable_test_event(); |
+ return specifics; |
+} |
+ |
+CommitResponse::ResponseType BounceType( |
+ CommitResponse::ResponseType type, |
+ const fake_server::FakeServerEntity& entity) { |
+ return type; |
+} |
+ |
+CommitResponse::ResponseType TransientErrorFirst( |
+ bool* first, |
+ UserEventSpecifics* retry_specifics, |
+ const fake_server::FakeServerEntity& entity) { |
+ if (*first) { |
+ *first = false; |
+ SyncEntity sync_entity; |
+ entity.SerializeAsProto(&sync_entity); |
+ *retry_specifics = sync_entity.specifics().user_event(); |
+ return CommitResponse::TRANSIENT_ERROR; |
+ } else { |
+ return CommitResponse::SUCCESS; |
+ } |
+} |
+ |
class UserEventEqualityChecker : public SingleClientStatusChangeChecker { |
public: |
UserEventEqualityChecker(browser_sync::ProfileSyncService* service, |
@@ -24,7 +56,8 @@ class UserEventEqualityChecker : public SingleClientStatusChangeChecker { |
std::vector<UserEventSpecifics> expected_specifics) |
: SingleClientStatusChangeChecker(service), fake_server_(fake_server) { |
for (const UserEventSpecifics& specifics : expected_specifics) { |
- expected_specifics_[specifics.event_time_usec()] = specifics; |
+ expected_specifics_.insert(std::pair<int64_t, UserEventSpecifics>( |
+ specifics.event_time_usec(), specifics)); |
} |
} |
@@ -40,17 +73,24 @@ class UserEventEqualityChecker : public SingleClientStatusChangeChecker { |
return false; |
} |
+ // Because we have a multimap, we cannot just check counts and equality of |
+ // items, but we need to make sure 2 of A and 1 of B is not the same as 1 of |
+ // A and 2 of B. So to make this easy, copy the multimap and remove items. |
+ std::multimap<int64_t, UserEventSpecifics> copied_expected_( |
+ expected_specifics_.begin(), expected_specifics_.end()); |
for (const SyncEntity& entity : entities) { |
UserEventSpecifics server_specifics = entity.specifics().user_event(); |
- auto iter = expected_specifics_.find(server_specifics.event_time_usec()); |
+ auto iter = copied_expected_.find(server_specifics.event_time_usec()); |
// We don't expect to encounter id matching events with different values, |
// this isn't going to recover so fail the test case now. |
- CHECK(expected_specifics_.end() != iter); |
+ CHECK(copied_expected_.end() != iter); |
// TODO(skym): This may need to change if we start updating navigation_id |
// based on what sessions data is committed, and end up committing the |
// same event multiple times. |
EXPECT_EQ(iter->second.navigation_id(), server_specifics.navigation_id()); |
EXPECT_EQ(iter->second.event_case(), server_specifics.event_case()); |
+ |
+ copied_expected_.erase(iter); |
} |
return true; |
@@ -62,7 +102,7 @@ class UserEventEqualityChecker : public SingleClientStatusChangeChecker { |
private: |
FakeServer* fake_server_; |
- std::map<int64_t, UserEventSpecifics> expected_specifics_; |
+ std::multimap<int64_t, UserEventSpecifics> expected_specifics_; |
}; |
class SingleClientUserEventsSyncTest : public SyncTest { |
@@ -82,12 +122,67 @@ IN_PROC_BROWSER_TEST_F(SingleClientUserEventsSyncTest, Sanity) { |
GetFakeServer()->GetSyncEntitiesByModelType(syncer::USER_EVENTS).size()); |
syncer::UserEventService* event_service = |
browser_sync::UserEventServiceFactory::GetForProfile(GetProfile(0)); |
- UserEventSpecifics specifics1; |
- specifics1.set_event_time_usec(base::Time::Now().ToInternalValue()); |
- specifics1.mutable_test_event(); |
+ UserEventSpecifics specifics = CreateEvent(0); |
+ event_service->RecordUserEvent(specifics); |
+ UserEventEqualityChecker(GetSyncService(0), GetFakeServer(), {specifics}) |
+ .Wait(); |
+} |
+ |
+IN_PROC_BROWSER_TEST_F(SingleClientUserEventsSyncTest, RetrySequential) { |
+ ASSERT_TRUE(SetupSync()); |
+ UserEventSpecifics specifics1 = CreateEvent(1); |
+ UserEventSpecifics specifics2 = CreateEvent(2); |
+ syncer::UserEventService* event_service = |
+ browser_sync::UserEventServiceFactory::GetForProfile(GetProfile(0)); |
+ |
+ GetFakeServer()->OverrideResponseType( |
+ base::Bind(&BounceType, CommitResponse::TRANSIENT_ERROR)); |
event_service->RecordUserEvent(specifics1); |
+ |
+ // This will block until we hit a TRANSIENT_ERROR, at which point we will |
+ // regain control and can switch back to SUCCESS. |
UserEventEqualityChecker(GetSyncService(0), GetFakeServer(), {specifics1}) |
.Wait(); |
+ GetFakeServer()->OverrideResponseType( |
+ base::Bind(&BounceType, CommitResponse::SUCCESS)); |
+ // Because the fake server records commits even on failure, we are able to |
+ // verify that the commit for this event reached the server twice. |
+ UserEventEqualityChecker(GetSyncService(0), GetFakeServer(), |
+ {specifics1, specifics1}) |
+ .Wait(); |
+ |
+ // Only record |specifics2| after |specifics1| was successful to avoid race |
+ // conditions. |
+ event_service->RecordUserEvent(specifics2); |
+ UserEventEqualityChecker(GetSyncService(0), GetFakeServer(), |
+ {specifics1, specifics1, specifics2}) |
+ .Wait(); |
+} |
+ |
+IN_PROC_BROWSER_TEST_F(SingleClientUserEventsSyncTest, RetryParallel) { |
+ ASSERT_TRUE(SetupSync()); |
+ bool first = true; |
+ UserEventSpecifics specifics1 = CreateEvent(1); |
+ UserEventSpecifics specifics2 = CreateEvent(2); |
+ UserEventSpecifics retry_specifics; |
+ |
+ syncer::UserEventService* event_service = |
+ browser_sync::UserEventServiceFactory::GetForProfile(GetProfile(0)); |
+ |
+ // We're not really sure if |specifics1| or |specifics2| is going to see the |
+ // error, so record the one that does into |retry_specifics| and use it in |
+ // expectations. |
+ GetFakeServer()->OverrideResponseType( |
+ base::Bind(&TransientErrorFirst, &first, &retry_specifics)); |
+ |
+ event_service->RecordUserEvent(specifics2); |
+ event_service->RecordUserEvent(specifics1); |
+ UserEventEqualityChecker(GetSyncService(0), GetFakeServer(), |
+ {specifics1, specifics2}) |
+ .Wait(); |
+ UserEventEqualityChecker(GetSyncService(0), GetFakeServer(), |
+ {specifics1, specifics2, retry_specifics}) |
+ .Wait(); |
} |
} // namespace |