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

Side by Side Diff: chrome/browser/budget_service/budget_database_unittest.cc

Issue 2255813002: AddEngagementBudget and SpendBudget added to BudgetDatabase. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Cleanup Created 4 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
« no previous file with comments | « chrome/browser/budget_service/budget_database.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 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 "chrome/browser/budget_service/budget_database.h" 5 #include "chrome/browser/budget_service/budget_database.h"
6 6
7 #include "base/run_loop.h" 7 #include "base/run_loop.h"
8 #include "base/test/simple_test_clock.h" 8 #include "base/test/simple_test_clock.h"
9 #include "base/threading/thread_task_runner_handle.h" 9 #include "base/threading/thread_task_runner_handle.h"
10 #include "chrome/browser/budget_service/budget.pb.h" 10 #include "chrome/browser/budget_service/budget.pb.h"
11 #include "chrome/test/base/testing_profile.h" 11 #include "chrome/test/base/testing_profile.h"
12 #include "components/leveldb_proto/proto_database.h" 12 #include "components/leveldb_proto/proto_database.h"
13 #include "components/leveldb_proto/proto_database_impl.h" 13 #include "components/leveldb_proto/proto_database_impl.h"
14 #include "content/public/browser/browser_thread.h" 14 #include "content/public/browser/browser_thread.h"
15 #include "content/public/test/test_browser_thread_bundle.h" 15 #include "content/public/test/test_browser_thread_bundle.h"
16 #include "testing/gtest/include/gtest/gtest.h" 16 #include "testing/gtest/include/gtest/gtest.h"
17 17
18 namespace { 18 namespace {
19 19
20 const double kDefaultBudget1 = 1.234; 20 const double kDefaultBudget1 = 1.234;
21 const double kDefaultBudget2 = 2.345; 21 const double kDefaultBudget2 = 2.345;
22 const double kDefaultExpirationInHours = 72; 22 const double kDefaultExpirationInHours = 72;
23 const double kDefaultEngagement = 30.0;
23 24
24 const char kTestOrigin[] = "https://example.com"; 25 const char kTestOrigin[] = "https://example.com";
25 26
26 } // namespace 27 } // namespace
27 28
28 class BudgetDatabaseTest : public ::testing::Test { 29 class BudgetDatabaseTest : public ::testing::Test {
29 public: 30 public:
30 BudgetDatabaseTest() 31 BudgetDatabaseTest()
31 : success_(false), 32 : success_(false),
32 db_(profile_.GetPath().Append(FILE_PATH_LITERAL("BudgetDabase")), 33 db_(profile_.GetPath().Append(FILE_PATH_LITERAL("BudgetDabase")),
33 base::ThreadTaskRunnerHandle::Get()) {} 34 base::ThreadTaskRunnerHandle::Get()) {}
34 35
35 // The BudgetDatabase assumes that a budget will always be queried before it 36 // The BudgetDatabase assumes that a budget will always be queried before it
36 // is written to. Use GetBudgetDetails() to pre-populate the cache. 37 // is written to. Use GetBudgetDetails() to pre-populate the cache.
37 void SetUp() override { GetBudgetDetails(); } 38 void SetUp() override { GetBudgetDetails(); }
38 39
39 void AddBudgetComplete(base::Closure run_loop_closure, bool success) { 40 void WriteBudgetComplete(base::Closure run_loop_closure, bool success) {
40 success_ = success; 41 success_ = success;
41 run_loop_closure.Run(); 42 run_loop_closure.Run();
42 } 43 }
43 44
44 // Add budget to the origin. 45 // Add budget to the origin.
45 bool AddBudget(const GURL& origin, double amount) { 46 bool AddBudget(const GURL& origin, double amount) {
46 base::RunLoop run_loop; 47 base::RunLoop run_loop;
47 db_.AddBudget(origin, amount, 48 db_.AddBudget(origin, amount,
48 base::Bind(&BudgetDatabaseTest::AddBudgetComplete, 49 base::Bind(&BudgetDatabaseTest::WriteBudgetComplete,
49 base::Unretained(this), run_loop.QuitClosure())); 50 base::Unretained(this), run_loop.QuitClosure()));
50 run_loop.Run(); 51 run_loop.Run();
51 return success_; 52 return success_;
52 } 53 }
53 54
55 // Add engagement based budget to the origin.
56 bool AddEngagementBudget(const GURL& origin, double sesScore) {
57 base::RunLoop run_loop;
58 db_.AddEngagementBudget(
59 origin, sesScore,
60 base::Bind(&BudgetDatabaseTest::WriteBudgetComplete,
61 base::Unretained(this), run_loop.QuitClosure()));
62 run_loop.Run();
63 return success_;
64 }
65
66 // Spend budget for the origin.
67 bool SpendBudget(const GURL& origin, double amount) {
68 base::RunLoop run_loop;
69 db_.SpendBudget(origin, amount,
70 base::Bind(&BudgetDatabaseTest::WriteBudgetComplete,
71 base::Unretained(this), run_loop.QuitClosure()));
72 run_loop.Run();
73 return success_;
74 }
75
54 void GetBudgetDetailsComplete( 76 void GetBudgetDetailsComplete(
55 base::Closure run_loop_closure, 77 base::Closure run_loop_closure,
56 bool success, 78 bool success,
57 const BudgetDatabase::BudgetExpectation& expectation) { 79 const BudgetDatabase::BudgetPrediction& prediction) {
58 success_ = success; 80 success_ = success;
59 expectation_ = expectation; 81 // Convert BudgetPrediction to a vector for random access to check values.
82 /*
83 prediction_.clear();
84 for (auto& chunk : prediction)
85 prediction_.push_back(chunk);
86 */
87 prediction_.assign(prediction.begin(), prediction.end());
60 run_loop_closure.Run(); 88 run_loop_closure.Run();
61 } 89 }
62 90
63 // Get the full set of budget expectations for the origin. 91 // Get the full set of budget predictions for the origin.
64 void GetBudgetDetails() { 92 void GetBudgetDetails() {
65 base::RunLoop run_loop; 93 base::RunLoop run_loop;
66 db_.GetBudgetDetails( 94 db_.GetBudgetDetails(
67 GURL(kTestOrigin), 95 GURL(kTestOrigin),
68 base::Bind(&BudgetDatabaseTest::GetBudgetDetailsComplete, 96 base::Bind(&BudgetDatabaseTest::GetBudgetDetailsComplete,
69 base::Unretained(this), run_loop.QuitClosure())); 97 base::Unretained(this), run_loop.QuitClosure()));
70 run_loop.Run(); 98 run_loop.Run();
71 } 99 }
72 100
73 Profile* profile() { return &profile_; } 101 Profile* profile() { return &profile_; }
74 const BudgetDatabase::BudgetExpectation& expectation() {
75 return expectation_;
76 }
77 102
78 // Setup a test clock so that the tests can control time. 103 // Setup a test clock so that the tests can control time.
79 base::SimpleTestClock* SetClockForTesting() { 104 base::SimpleTestClock* SetClockForTesting() {
80 base::SimpleTestClock* clock = new base::SimpleTestClock(); 105 base::SimpleTestClock* clock = new base::SimpleTestClock();
81 db_.SetClockForTesting(base::WrapUnique(clock)); 106 db_.SetClockForTesting(base::WrapUnique(clock));
82 return clock; 107 return clock;
83 } 108 }
84 109
85 // Query the database to check if the origin is in the cache. 110 // Query the database to check if the origin is in the cache.
86 bool IsCached(const GURL& origin) { return db_.IsCached(origin); } 111 bool IsCached(const GURL& origin) { return db_.IsCached(origin); }
87 112
88 protected: 113 protected:
89 bool success_; 114 bool success_;
115 std::vector<BudgetDatabase::BudgetStatus> prediction_;
90 116
91 private: 117 private:
92 content::TestBrowserThreadBundle thread_bundle_; 118 content::TestBrowserThreadBundle thread_bundle_;
93 std::unique_ptr<budget_service::Budget> budget_; 119 std::unique_ptr<budget_service::Budget> budget_;
94 TestingProfile profile_; 120 TestingProfile profile_;
95 BudgetDatabase db_; 121 BudgetDatabase db_;
96 BudgetDatabase::BudgetExpectation expectation_;
97 }; 122 };
98 123
99 TEST_F(BudgetDatabaseTest, ReadAndWriteTest) { 124 TEST_F(BudgetDatabaseTest, ReadAndWriteTest) {
100 const GURL origin(kTestOrigin); 125 const GURL origin(kTestOrigin);
101 base::SimpleTestClock* clock = SetClockForTesting(); 126 base::SimpleTestClock* clock = SetClockForTesting();
102 base::TimeDelta expiration( 127 base::TimeDelta expiration(
103 base::TimeDelta::FromHours(kDefaultExpirationInHours)); 128 base::TimeDelta::FromHours(kDefaultExpirationInHours));
104 base::Time starting_time = clock->Now(); 129 base::Time starting_time = clock->Now();
105 base::Time expiration_time = clock->Now() + expiration; 130 base::Time expiration_time = clock->Now() + expiration;
106 131
107 // Add two budget chunks with different expirations (default expiration and 132 // Add two budget chunks with different expirations (default expiration and
108 // default expiration + 1 day). 133 // default expiration + 1 day).
109 ASSERT_TRUE(AddBudget(origin, kDefaultBudget1)); 134 ASSERT_TRUE(AddBudget(origin, kDefaultBudget1));
110 clock->Advance(base::TimeDelta::FromDays(1)); 135 clock->Advance(base::TimeDelta::FromDays(1));
111 ASSERT_TRUE(AddBudget(origin, kDefaultBudget2)); 136 ASSERT_TRUE(AddBudget(origin, kDefaultBudget2));
112 137
113 // Get the budget. 138 // Get the budget.
114 GetBudgetDetails(); 139 GetBudgetDetails();
115 140
116 // Get the expectation and validate it. 141 // Get the prediction and validate it.
117 const auto& expected_value = expectation();
118 ASSERT_TRUE(success_); 142 ASSERT_TRUE(success_);
119 ASSERT_EQ(3U, expected_value.size()); 143 ASSERT_EQ(3U, prediction_.size());
120 144
121 // Make sure that the correct data is returned. 145 // Make sure that the correct data is returned.
122 auto iter = expected_value.begin();
123
124 // First value should be [total_budget, now] 146 // First value should be [total_budget, now]
125 EXPECT_EQ(kDefaultBudget1 + kDefaultBudget2, iter->budget_at); 147 EXPECT_EQ(kDefaultBudget1 + kDefaultBudget2, prediction_[0].budget_at);
126 EXPECT_EQ(clock->Now(), iter->time); 148 EXPECT_EQ(clock->Now(), prediction_[0].time);
127 149
128 // The next value should be the budget after the first chunk expires. 150 // The next value should be the budget after the first chunk expires.
129 iter++; 151 EXPECT_EQ(kDefaultBudget2, prediction_[1].budget_at);
130 EXPECT_EQ(kDefaultBudget2, iter->budget_at); 152 EXPECT_EQ(expiration_time, prediction_[1].time);
131 EXPECT_EQ(expiration_time, iter->time);
132 153
133 // The final value gives the budget of 0.0 after the second chunk expires. 154 // The final value gives the budget of 0.0 after the second chunk expires.
134 expiration_time += base::TimeDelta::FromDays(1); 155 expiration_time += base::TimeDelta::FromDays(1);
135 iter++; 156 EXPECT_EQ(0, prediction_[2].budget_at);
136 EXPECT_EQ(0, iter->budget_at); 157 EXPECT_EQ(expiration_time, prediction_[2].time);
137 EXPECT_EQ(expiration_time, iter->time);
138 158
139 // Advance the time until the first chunk of budget should be expired. 159 // Advance the time until the first chunk of budget should be expired.
140 clock->SetNow(starting_time + 160 clock->SetNow(starting_time +
141 base::TimeDelta::FromHours(kDefaultExpirationInHours)); 161 base::TimeDelta::FromHours(kDefaultExpirationInHours));
142 162
143 // Get the new budget and check that kDefaultBudget1 has been removed. 163 // Get the new budget and check that kDefaultBudget1 has been removed.
144 GetBudgetDetails(); 164 GetBudgetDetails();
145 iter = expectation().begin(); 165 ASSERT_EQ(2U, prediction_.size());
146 ASSERT_EQ(2U, expectation().size()); 166 EXPECT_EQ(kDefaultBudget2, prediction_[0].budget_at);
147 EXPECT_EQ(kDefaultBudget2, iter->budget_at); 167 EXPECT_EQ(0, prediction_[1].budget_at);
148 iter++;
149 EXPECT_EQ(0, iter->budget_at);
150 168
151 // Advace the time until both chunks of budget should be expired. 169 // Advace the time until both chunks of budget should be expired.
152 clock->SetNow(starting_time + 170 clock->SetNow(starting_time +
153 base::TimeDelta::FromHours(kDefaultExpirationInHours) + 171 base::TimeDelta::FromHours(kDefaultExpirationInHours) +
154 base::TimeDelta::FromDays(1)); 172 base::TimeDelta::FromDays(1));
155 173
156 GetBudgetDetails(); 174 GetBudgetDetails();
157 iter = expectation().begin(); 175 ASSERT_EQ(1U, prediction_.size());
158 ASSERT_EQ(1U, expectation().size()); 176 EXPECT_EQ(0, prediction_[0].budget_at);
159 EXPECT_EQ(0, iter->budget_at);
160 177
161 // Now that the entire budget has expired, check that the entry in the map 178 // Now that the entire budget has expired, check that the entry in the map
162 // has been removed. 179 // has been removed.
163 EXPECT_FALSE(IsCached(origin)); 180 EXPECT_FALSE(IsCached(origin));
164 } 181 }
182
183 TEST_F(BudgetDatabaseTest, AddEngagementBudgetTest) {
184 const GURL origin(kTestOrigin);
185 base::SimpleTestClock* clock = SetClockForTesting();
186 base::Time expiration_time =
187 clock->Now() + base::TimeDelta::FromHours(kDefaultExpirationInHours);
188
189 // Add a chunk of budget to a non-existant origin. This should add the full
190 // amount of engagement.
191 ASSERT_TRUE(AddEngagementBudget(origin, kDefaultEngagement));
192
193 // The budget should include a full share of the engagement.
194 GetBudgetDetails();
195 ASSERT_TRUE(success_);
196 ASSERT_EQ(2U, prediction_.size());
197 ASSERT_EQ(kDefaultEngagement, prediction_[0].budget_at);
198 ASSERT_EQ(0, prediction_[1].budget_at);
199 ASSERT_EQ(expiration_time, prediction_[1].time);
200
201 // Advance time 1 day and add more engagement budget.
202 clock->Advance(base::TimeDelta::FromDays(1));
203 ASSERT_TRUE(AddEngagementBudget(origin, kDefaultEngagement));
204
205 // The budget should now have 1 full share plus 1/3 share.
206 GetBudgetDetails();
207 ASSERT_TRUE(success_);
208 ASSERT_EQ(3U, prediction_.size());
209 ASSERT_DOUBLE_EQ(kDefaultEngagement * 4 / 3, prediction_[0].budget_at);
210 ASSERT_DOUBLE_EQ(kDefaultEngagement * 1 / 3, prediction_[1].budget_at);
211 ASSERT_EQ(expiration_time, prediction_[1].time);
212 ASSERT_EQ(0, prediction_[2].budget_at);
213 ASSERT_EQ(expiration_time + base::TimeDelta::FromDays(1),
214 prediction_[2].time);
215
216 // Advance time by 59 minutes and check that no engagement budget is added
217 // since budget should only be added for > 1 hour increments.
218 clock->Advance(base::TimeDelta::FromMinutes(59));
219 ASSERT_TRUE(AddEngagementBudget(origin, kDefaultEngagement));
220
221 // The budget should be the same as before the attempted add.
222 GetBudgetDetails();
223 ASSERT_TRUE(success_);
224 ASSERT_EQ(3U, prediction_.size());
225 ASSERT_DOUBLE_EQ(kDefaultEngagement * 4 / 3, prediction_[0].budget_at);
226 }
227
228 TEST_F(BudgetDatabaseTest, SpendBudgetTest) {
229 const GURL origin(kTestOrigin);
230 base::SimpleTestClock* clock = SetClockForTesting();
231 base::Time starting_time = clock->Now();
232
233 // Intialize the budget with several chunks.
234 ASSERT_TRUE(AddBudget(origin, kDefaultBudget1));
235 clock->Advance(base::TimeDelta::FromDays(1));
236 ASSERT_TRUE(AddBudget(origin, kDefaultBudget1));
237 clock->Advance(base::TimeDelta::FromDays(1));
238 ASSERT_TRUE(AddBudget(origin, kDefaultBudget1));
239
240 // Reset the clock then spend an amount of budget less than kDefaultBudget.
241 clock->SetNow(starting_time);
242 ASSERT_TRUE(SpendBudget(origin, 1));
243 GetBudgetDetails();
244
245 // There should still be three chunks of budget of size kDefaultBudget-1,
246 // kDefaultBudget, and kDefaultBudget.
247 ASSERT_EQ(4U, prediction_.size());
248 ASSERT_DOUBLE_EQ(kDefaultBudget1 * 3 - 1, prediction_[0].budget_at);
249 ASSERT_DOUBLE_EQ(kDefaultBudget1 * 2, prediction_[1].budget_at);
250 ASSERT_DOUBLE_EQ(kDefaultBudget1, prediction_[2].budget_at);
251 ASSERT_DOUBLE_EQ(0, prediction_[3].budget_at);
252
253 // Now spend enough that it will use up the rest of the first chunk and all of
254 // the second chunk, but not all of the third chunk.
255 ASSERT_TRUE(SpendBudget(origin, kDefaultBudget1 * 2));
256 GetBudgetDetails();
257 ASSERT_EQ(2U, prediction_.size());
258 ASSERT_DOUBLE_EQ(kDefaultBudget1 - 1, prediction_.begin()->budget_at);
259
260 // Validate that the code returns false if SpendBudget tries to spend more
261 // budget than the origin has.
262 EXPECT_FALSE(SpendBudget(origin, kDefaultBudget1));
263 GetBudgetDetails();
264 ASSERT_EQ(2U, prediction_.size());
265 ASSERT_DOUBLE_EQ(kDefaultBudget1 - 1, prediction_.begin()->budget_at);
266
267 // Advance time until the last remaining chunk should be expired, then query
268 // for what would be a valid amount of budget if the chunks weren't expired.
269 clock->Advance(base::TimeDelta::FromDays(6));
270 EXPECT_FALSE(SpendBudget(origin, 0.01));
271 }
OLDNEW
« no previous file with comments | « chrome/browser/budget_service/budget_database.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698