blob: a95ff628210238cf030a465e92e99154810516eb [file] [log] [blame]
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/sync/engine/commit_processor.h"
#include <memory>
#include "components/sync/engine/commit_contribution.h"
#include "components/sync/engine/commit_contributor.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace syncer {
namespace {
constexpr int kMaxEntries = 17;
using testing::_;
using testing::IsEmpty;
using testing::Pair;
using testing::UnorderedElementsAre;
MATCHER_P(HasNumEntries, num_entries, "") {
return static_cast<int>(arg->GetNumEntries()) == num_entries;
}
// Simple implementation of CommitContribution that only implements
// GetNumEntries().
class FakeCommitContribution : public CommitContribution {
public:
explicit FakeCommitContribution(size_t num_entries)
: num_entries_(num_entries) {}
~FakeCommitContribution() override = default;
// CommitContribution implementation.
void AddToCommitMessage(sync_pb::ClientToServerMessage* msg) override {}
SyncerError ProcessCommitResponse(
const sync_pb::ClientToServerResponse& response,
StatusController* status) override {
return SyncerError();
}
void ProcessCommitFailure(SyncCommitError commit_error) override {}
size_t GetNumEntries() const override { return num_entries_; }
private:
const size_t num_entries_;
};
ACTION_P(ReturnContributionWithEntries, num_entries) {
return std::make_unique<FakeCommitContribution>(num_entries);
}
class MockCommitContributor : public CommitContributor {
public:
MockCommitContributor() = default;
~MockCommitContributor() override = default;
MOCK_METHOD(std::unique_ptr<CommitContribution>,
GetContribution,
(size_t max_entries),
(override));
};
class CommitProcessorTest : public testing::Test {
protected:
CommitProcessorTest()
: contributor_map_{{NIGORI, &nigori_contributor_},
{SHARING_MESSAGE, &sharing_message_contributor_},
{BOOKMARKS, &bookmark_contributor_},
{PREFERENCES, &preference_contributor_}},
processor_(/*commit_types=*/ModelTypeSet{NIGORI, SHARING_MESSAGE,
BOOKMARKS, PREFERENCES},
&contributor_map_) {
EXPECT_TRUE(PriorityUserTypes().Has(SHARING_MESSAGE));
EXPECT_FALSE(PriorityUserTypes().Has(BOOKMARKS));
EXPECT_FALSE(PriorityUserTypes().Has(PREFERENCES));
}
testing::NiceMock<MockCommitContributor> nigori_contributor_;
// A priority user type.
testing::NiceMock<MockCommitContributor> sharing_message_contributor_;
// Regular user types.
testing::NiceMock<MockCommitContributor> bookmark_contributor_;
testing::NiceMock<MockCommitContributor> preference_contributor_;
CommitContributorMap contributor_map_;
CommitProcessor processor_;
};
TEST_F(CommitProcessorTest, ShouldGatherNigoriOnlyContribution) {
EXPECT_CALL(nigori_contributor_, GetContribution(kMaxEntries))
.WillOnce(ReturnContributionWithEntries(/*num_entries=*/1));
// No user types should be gathered and combined with NIGORI.
EXPECT_CALL(sharing_message_contributor_, GetContribution).Times(0);
EXPECT_CALL(bookmark_contributor_, GetContribution).Times(0);
EXPECT_CALL(preference_contributor_, GetContribution).Times(0);
EXPECT_THAT(processor_.GatherCommitContributions(/*max_entries=*/kMaxEntries),
UnorderedElementsAre(Pair(NIGORI, HasNumEntries(1))));
}
TEST_F(CommitProcessorTest, ShouldGatherPriorityUserTypesOnlyContribution) {
const int kNumReturnedEntries = 3;
EXPECT_CALL(sharing_message_contributor_, GetContribution(kMaxEntries))
.WillOnce(ReturnContributionWithEntries(kNumReturnedEntries));
// Non-priority user types shouldn't even be gathered.
EXPECT_CALL(bookmark_contributor_, GetContribution).Times(0);
EXPECT_CALL(preference_contributor_, GetContribution).Times(0);
EXPECT_THAT(processor_.GatherCommitContributions(/*max_entries=*/kMaxEntries),
UnorderedElementsAre(
Pair(SHARING_MESSAGE, HasNumEntries(kNumReturnedEntries))));
}
TEST_F(CommitProcessorTest, ShouldGatherRegularUserTypes) {
const int kNumReturnedBookmarks = 7;
// High-priority types should be gathered, but no entries are produced. Nigori
// is even gathered twice (once in each gathering phase).
EXPECT_CALL(nigori_contributor_, GetContribution(kMaxEntries)).Times(2);
EXPECT_CALL(sharing_message_contributor_, GetContribution(kMaxEntries));
// Return |kNumReturnedBookmarks| bookmarks.
EXPECT_CALL(bookmark_contributor_, GetContribution(kMaxEntries))
.WillOnce(ReturnContributionWithEntries(kNumReturnedBookmarks));
// Preferences should also be gathered, but no entries are produced in this
// test. The precise argument depends on the iteration order so it's not
// verified in this test.
EXPECT_CALL(preference_contributor_, GetContribution);
EXPECT_THAT(processor_.GatherCommitContributions(/*max_entries=*/kMaxEntries),
UnorderedElementsAre(
Pair(BOOKMARKS, HasNumEntries(kNumReturnedBookmarks))));
}
TEST_F(CommitProcessorTest, ShouldGatherMultipleRegularUserTypes) {
const int kNumReturnedBookmarks = 7;
const int kNumReturnedPreferences = 8;
// Return |kNumReturnedBookmarks| bookmarks and |kNumReturnedPreferences|
// preferences.
EXPECT_CALL(bookmark_contributor_, GetContribution)
.WillOnce(ReturnContributionWithEntries(kNumReturnedBookmarks));
EXPECT_CALL(preference_contributor_, GetContribution)
.WillOnce(ReturnContributionWithEntries(kNumReturnedPreferences));
EXPECT_THAT(processor_.GatherCommitContributions(/*max_entries=*/kMaxEntries),
UnorderedElementsAre(
Pair(BOOKMARKS, HasNumEntries(kNumReturnedBookmarks)),
Pair(PREFERENCES, HasNumEntries(kNumReturnedPreferences))));
}
TEST_F(CommitProcessorTest, ShouldContinueGatheringPriorityContributions) {
const int kNumReturnedSharingMessages = 3;
// First, return |kMaxEntries| sharing messages.
EXPECT_CALL(sharing_message_contributor_, GetContribution(kMaxEntries))
.WillOnce(ReturnContributionWithEntries(kMaxEntries));
// Non-priority user types shouldn't even be gathered.
EXPECT_CALL(bookmark_contributor_, GetContribution).Times(0);
EXPECT_CALL(preference_contributor_, GetContribution).Times(0);
EXPECT_THAT(
processor_.GatherCommitContributions(/*max_entries=*/kMaxEntries),
UnorderedElementsAre(Pair(SHARING_MESSAGE, HasNumEntries(kMaxEntries))));
// Now, return only |kNumReturnedSharingMessages| bookmarks (all that's left).
EXPECT_CALL(sharing_message_contributor_, GetContribution)
.WillOnce(ReturnContributionWithEntries(kNumReturnedSharingMessages));
EXPECT_THAT(
processor_.GatherCommitContributions(/*max_entries=*/kMaxEntries),
UnorderedElementsAre(
Pair(SHARING_MESSAGE, HasNumEntries(kNumReturnedSharingMessages))));
// There are no contributions left, do not return any further and do not even
// call the contributor.
EXPECT_CALL(sharing_message_contributor_, GetContribution).Times(0);
// At the same time, the other contributors should get called now (don't
// return anything in this test).
EXPECT_CALL(bookmark_contributor_, GetContribution).Times(1);
EXPECT_CALL(preference_contributor_, GetContribution).Times(1);
EXPECT_THAT(processor_.GatherCommitContributions(/*max_entries=*/kMaxEntries),
IsEmpty());
}
TEST_F(CommitProcessorTest, ShouldContinueGatheringRegularContributions) {
const int kNumReturnedBookmarks = 7;
// First, return |kMaxEntries| bookmarks.
EXPECT_CALL(bookmark_contributor_, GetContribution(kMaxEntries))
.WillOnce(ReturnContributionWithEntries(kMaxEntries));
EXPECT_THAT(
processor_.GatherCommitContributions(/*max_entries=*/kMaxEntries),
UnorderedElementsAre(Pair(BOOKMARKS, HasNumEntries(kMaxEntries))));
// Now, return only |kNumReturnedBookmarks| bookmarks (all that's left).
EXPECT_CALL(bookmark_contributor_, GetContribution)
.WillOnce(ReturnContributionWithEntries(kNumReturnedBookmarks));
EXPECT_THAT(processor_.GatherCommitContributions(/*max_entries=*/kMaxEntries),
UnorderedElementsAre(
Pair(BOOKMARKS, HasNumEntries(kNumReturnedBookmarks))));
// There are no contributions left, do not return any further and do not even
// call the contributor.
EXPECT_CALL(bookmark_contributor_, GetContribution).Times(0);
EXPECT_THAT(processor_.GatherCommitContributions(/*max_entries=*/kMaxEntries),
IsEmpty());
}
TEST_F(CommitProcessorTest,
ShouldContinueGatheringRegularContributionsIfMatchingMaxEntries) {
// Return |kMaxEntries| bookmarks.
EXPECT_CALL(bookmark_contributor_, GetContribution(kMaxEntries))
.WillOnce(ReturnContributionWithEntries(kMaxEntries));
EXPECT_THAT(
processor_.GatherCommitContributions(/*max_entries=*/kMaxEntries),
UnorderedElementsAre(Pair(BOOKMARKS, HasNumEntries(kMaxEntries))));
// There are no contributions left, do not return any further.
// GetContribution() should however get called since |processor| cannot tell
// that there are no left.
EXPECT_CALL(bookmark_contributor_, GetContribution);
EXPECT_THAT(processor_.GatherCommitContributions(/*max_entries=*/kMaxEntries),
IsEmpty());
}
TEST_F(CommitProcessorTest, ShouldGatherFirstPriorityThenOtherUserTypes) {
const int kNumReturnedSharingMessages = 3;
const int kNumReturnedBookmarks = 7;
const int kNumReturnedPreferences = 8;
// All three types have non-zero contributions.
EXPECT_CALL(sharing_message_contributor_, GetContribution(kMaxEntries))
.WillOnce(ReturnContributionWithEntries(kNumReturnedSharingMessages))
.RetiresOnSaturation();
EXPECT_CALL(bookmark_contributor_, GetContribution)
.WillOnce(ReturnContributionWithEntries(kNumReturnedBookmarks));
EXPECT_CALL(preference_contributor_, GetContribution)
.WillOnce(ReturnContributionWithEntries(kNumReturnedPreferences));
// The first call should return only the priority types.
EXPECT_THAT(
processor_.GatherCommitContributions(/*max_entries=*/kMaxEntries),
UnorderedElementsAre(
Pair(SHARING_MESSAGE, HasNumEntries(kNumReturnedSharingMessages))));
// Processor has gathered all contributions for SHARING_MESSAGE previously, no
// further call should happen.
EXPECT_CALL(sharing_message_contributor_, GetContribution(kMaxEntries))
.Times(0);
// The second call should return all the other types.
EXPECT_THAT(processor_.GatherCommitContributions(/*max_entries=*/kMaxEntries),
UnorderedElementsAre(
Pair(BOOKMARKS, HasNumEntries(kNumReturnedBookmarks)),
Pair(PREFERENCES, HasNumEntries(kNumReturnedPreferences))));
}
} // namespace
} // namespace syncer