max_vote_aggregator_unittest.cc 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. // Copyright 2019 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. #include "components/performance_manager/execution_context_priority/max_vote_aggregator.h"
  5. #include "base/rand_util.h"
  6. #include "components/performance_manager/test_support/voting.h"
  7. #include "testing/gtest/include/gtest/gtest.h"
  8. namespace performance_manager {
  9. namespace execution_context_priority {
  10. // Expose the VoteData type for testing.
  11. class MaxVoteAggregatorTestAccess {
  12. public:
  13. using VoteData = MaxVoteAggregator::VoteData;
  14. using StampedVote = MaxVoteAggregator::StampedVote;
  15. };
  16. using VoteData = MaxVoteAggregatorTestAccess::VoteData;
  17. using StampedVote = MaxVoteAggregatorTestAccess::StampedVote;
  18. namespace {
  19. using DummyVoteObserver = voting::test::DummyVoteObserver<Vote>;
  20. // Some dummy execution contexts.
  21. const ExecutionContext* kExecutionContext0 =
  22. reinterpret_cast<const ExecutionContext*>(0xDEADBEEF);
  23. const ExecutionContext* kExecutionContext1 =
  24. reinterpret_cast<const ExecutionContext*>(0xBAADF00D);
  25. static const Vote kLowPriorityVote0(base::TaskPriority::LOWEST, "low reason 0");
  26. static const Vote kLowPriorityVote1(base::TaskPriority::LOWEST, "low reason 1");
  27. static const Vote kMediumPriorityVote0(base::TaskPriority::USER_VISIBLE,
  28. "medium reason 0");
  29. static const Vote kMediumPriorityVote1(base::TaskPriority::USER_VISIBLE,
  30. "medium reason 1");
  31. static const Vote kHighPriorityVote0(base::TaskPriority::HIGHEST,
  32. "high reason 0");
  33. static const Vote kHighPriorityVote1(base::TaskPriority::HIGHEST,
  34. "high reason 1");
  35. } // namespace
  36. class MaxVoteAggregatorTest : public testing::Test {
  37. public:
  38. MaxVoteAggregatorTest() = default;
  39. ~MaxVoteAggregatorTest() override = default;
  40. void SetUp() override {
  41. VotingChannel channel = observer_.BuildVotingChannel();
  42. aggregator_voter_id_ = channel.voter_id();
  43. aggregator_.SetUpstreamVotingChannel(std::move(channel));
  44. }
  45. void TearDown() override {}
  46. VoterId aggregator_voter_id() const { return aggregator_voter_id_; }
  47. const DummyVoteObserver& observer() const { return observer_; }
  48. MaxVoteAggregator* aggregator() { return &aggregator_; }
  49. private:
  50. DummyVoteObserver observer_;
  51. MaxVoteAggregator aggregator_;
  52. VoterId aggregator_voter_id_;
  53. };
  54. // Tests that in the case of a single voter, the vote is simply propagated
  55. // upwards.
  56. TEST_F(MaxVoteAggregatorTest, SingleVoter) {
  57. VotingChannel voter0 = aggregator()->GetVotingChannel();
  58. EXPECT_FALSE(observer().HasVote(aggregator_voter_id(), kExecutionContext0));
  59. voter0.SubmitVote(kExecutionContext0, kLowPriorityVote0);
  60. EXPECT_EQ(observer().GetVoteCount(), 1u);
  61. EXPECT_TRUE(observer().HasVote(aggregator_voter_id(), kExecutionContext0,
  62. kLowPriorityVote0));
  63. // Change only the reason.
  64. voter0.ChangeVote(kExecutionContext0, kLowPriorityVote1);
  65. EXPECT_EQ(observer().GetVoteCount(), 1u);
  66. EXPECT_TRUE(observer().HasVote(aggregator_voter_id(), kExecutionContext0,
  67. kLowPriorityVote1));
  68. // Change the priority.
  69. voter0.ChangeVote(kExecutionContext0, kHighPriorityVote0);
  70. EXPECT_EQ(observer().GetVoteCount(), 1u);
  71. EXPECT_TRUE(observer().HasVote(aggregator_voter_id(), kExecutionContext0,
  72. kHighPriorityVote0));
  73. // Add a vote for a different execution context.
  74. voter0.SubmitVote(kExecutionContext1, kMediumPriorityVote0);
  75. EXPECT_EQ(observer().GetVoteCount(), 2u);
  76. EXPECT_TRUE(observer().HasVote(aggregator_voter_id(), kExecutionContext0,
  77. kHighPriorityVote0));
  78. EXPECT_TRUE(observer().HasVote(aggregator_voter_id(), kExecutionContext1,
  79. kMediumPriorityVote0));
  80. voter0.ChangeVote(kExecutionContext1, kHighPriorityVote1);
  81. EXPECT_EQ(observer().GetVoteCount(), 2u);
  82. EXPECT_TRUE(observer().HasVote(aggregator_voter_id(), kExecutionContext0,
  83. kHighPriorityVote0));
  84. EXPECT_TRUE(observer().HasVote(aggregator_voter_id(), kExecutionContext1,
  85. kHighPriorityVote1));
  86. // Invalidate vote for the first execution context.
  87. voter0.InvalidateVote(kExecutionContext0);
  88. EXPECT_EQ(observer().GetVoteCount(), 1u);
  89. EXPECT_FALSE(observer().HasVote(aggregator_voter_id(), kExecutionContext0));
  90. EXPECT_TRUE(observer().HasVote(aggregator_voter_id(), kExecutionContext1,
  91. kHighPriorityVote1));
  92. voter0.InvalidateVote(kExecutionContext1);
  93. EXPECT_EQ(observer().GetVoteCount(), 0u);
  94. EXPECT_FALSE(observer().HasVote(aggregator_voter_id(), kExecutionContext0));
  95. EXPECT_FALSE(observer().HasVote(aggregator_voter_id(), kExecutionContext0));
  96. }
  97. TEST_F(MaxVoteAggregatorTest, TwoVotersOneContext) {
  98. VotingChannel voter0 = aggregator()->GetVotingChannel();
  99. VotingChannel voter1 = aggregator()->GetVotingChannel();
  100. EXPECT_FALSE(observer().HasVote(aggregator_voter_id(), kExecutionContext0));
  101. // Submit a first vote to the execution context. Using the 2nd voter to test
  102. // the stability.
  103. voter1.SubmitVote(kExecutionContext0, kLowPriorityVote1);
  104. EXPECT_EQ(observer().GetVoteCount(), 1u);
  105. EXPECT_TRUE(observer().HasVote(aggregator_voter_id(), kExecutionContext0,
  106. kLowPriorityVote1));
  107. // Votes are stable. Voting with the same priority but a different reason will
  108. // not change the upstream vote.
  109. voter0.SubmitVote(kExecutionContext0, kLowPriorityVote0);
  110. EXPECT_EQ(observer().GetVoteCount(), 1u);
  111. EXPECT_TRUE(observer().HasVote(aggregator_voter_id(), kExecutionContext0,
  112. kLowPriorityVote1));
  113. // Change the vote of the first voter to a higher priority. This will modify
  114. // the upstream.
  115. voter0.ChangeVote(kExecutionContext0, kHighPriorityVote0);
  116. EXPECT_EQ(observer().GetVoteCount(), 1u);
  117. EXPECT_TRUE(observer().HasVote(aggregator_voter_id(), kExecutionContext0,
  118. kHighPriorityVote0));
  119. // Change the vote of the second voter to a higher priority but still lower
  120. // than the first voter's vote.
  121. voter1.ChangeVote(kExecutionContext0, kMediumPriorityVote1);
  122. EXPECT_EQ(observer().GetVoteCount(), 1u);
  123. EXPECT_TRUE(observer().HasVote(aggregator_voter_id(), kExecutionContext0,
  124. kHighPriorityVote0));
  125. // Invalidate the top vote. This means the second voter will dictate the new
  126. // top vote.
  127. voter0.InvalidateVote(kExecutionContext0);
  128. EXPECT_EQ(observer().GetVoteCount(), 1u);
  129. EXPECT_TRUE(observer().HasVote(aggregator_voter_id(), kExecutionContext0,
  130. kMediumPriorityVote1));
  131. // Invalidate the vote for the second voter. The upstream vote should also be
  132. // invalidated.
  133. voter1.InvalidateVote(kExecutionContext0);
  134. EXPECT_EQ(observer().GetVoteCount(), 0u);
  135. EXPECT_FALSE(observer().HasVote(aggregator_voter_id(), kExecutionContext0));
  136. }
  137. // A less extensive test than TwoVotersOneContext that sanity checks that votes
  138. // for different contextes are aggregated independently.
  139. TEST_F(MaxVoteAggregatorTest, TwoVotersMultipleContext) {
  140. VotingChannel voter0 = aggregator()->GetVotingChannel();
  141. VotingChannel voter1 = aggregator()->GetVotingChannel();
  142. // Vote for execution context 1, making sure the first voter submits a higher
  143. // priority vote.
  144. voter0.SubmitVote(kExecutionContext0, kHighPriorityVote0);
  145. voter1.SubmitVote(kExecutionContext0, kMediumPriorityVote1);
  146. // Vote for execution context 2, making sure the second voter submits a higher
  147. // priority vote.
  148. voter0.SubmitVote(kExecutionContext1, kLowPriorityVote0);
  149. voter1.SubmitVote(kExecutionContext1, kMediumPriorityVote1);
  150. // There is an aggregated vote for each context.
  151. EXPECT_EQ(observer().GetVoteCount(), 2u);
  152. EXPECT_TRUE(observer().HasVote(aggregator_voter_id(), kExecutionContext0,
  153. kHighPriorityVote0));
  154. EXPECT_TRUE(observer().HasVote(aggregator_voter_id(), kExecutionContext1,
  155. kMediumPriorityVote1));
  156. // Cleanup.
  157. voter0.InvalidateVote(kExecutionContext0);
  158. voter0.InvalidateVote(kExecutionContext1);
  159. voter1.InvalidateVote(kExecutionContext0);
  160. voter1.InvalidateVote(kExecutionContext1);
  161. EXPECT_EQ(observer().GetVoteCount(), 0u);
  162. }
  163. // A simple test that ensures MaxVoteAggregator supports an arbitrary number of
  164. // voters.
  165. TEST_F(MaxVoteAggregatorTest, LotsOfVoters) {
  166. static constexpr int kNumVoters = 2000;
  167. std::vector<VotingChannel> voters;
  168. voters.reserve(kNumVoters);
  169. for (int i = 0; i < kNumVoters; ++i) {
  170. VotingChannel voter = aggregator()->GetVotingChannel();
  171. voters.push_back(std::move(voter));
  172. }
  173. for (auto& voter : voters)
  174. voter.SubmitVote(kExecutionContext0, kLowPriorityVote0);
  175. EXPECT_EQ(observer().GetVoteCount(), 1u);
  176. EXPECT_TRUE(observer().HasVote(aggregator_voter_id(), kExecutionContext0,
  177. kLowPriorityVote0));
  178. // Pick a random voter and change its vote.
  179. int chosen_voter_index = base::RandGenerator(kNumVoters);
  180. voters[chosen_voter_index].ChangeVote(kExecutionContext0, kHighPriorityVote0);
  181. EXPECT_EQ(observer().GetVoteCount(), 1u);
  182. EXPECT_TRUE(observer().HasVote(aggregator_voter_id(), kExecutionContext0,
  183. kHighPriorityVote0));
  184. // Cleanup.
  185. for (auto& voter : voters)
  186. voter.InvalidateVote(kExecutionContext0);
  187. EXPECT_EQ(observer().GetVoteCount(), 0u);
  188. }
  189. } // namespace execution_context_priority
  190. } // namespace performance_manager