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

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

Issue 2620393002: Refactor budget computation to be more tuneable. (Closed)
Patch Set: Changed LayoutTest to expect integral budgets. (Also rebased) Created 3 years, 11 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
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 <math.h>
7 #include <vector> 8 #include <vector>
8 9
9 #include "base/memory/ptr_util.h" 10 #include "base/memory/ptr_util.h"
10 #include "base/run_loop.h" 11 #include "base/run_loop.h"
11 #include "base/test/histogram_tester.h" 12 #include "base/test/histogram_tester.h"
12 #include "base/test/simple_test_clock.h" 13 #include "base/test/simple_test_clock.h"
13 #include "base/threading/thread_task_runner_handle.h" 14 #include "base/threading/thread_task_runner_handle.h"
14 #include "chrome/browser/budget_service/budget.pb.h" 15 #include "chrome/browser/budget_service/budget.pb.h"
16 #include "chrome/browser/engagement/site_engagement_score.h"
15 #include "chrome/browser/engagement/site_engagement_service.h" 17 #include "chrome/browser/engagement/site_engagement_service.h"
16 #include "chrome/test/base/testing_profile.h" 18 #include "chrome/test/base/testing_profile.h"
17 #include "components/leveldb_proto/proto_database.h" 19 #include "components/leveldb_proto/proto_database.h"
18 #include "components/leveldb_proto/proto_database_impl.h" 20 #include "components/leveldb_proto/proto_database_impl.h"
19 #include "content/public/browser/browser_thread.h" 21 #include "content/public/browser/browser_thread.h"
20 #include "content/public/test/test_browser_thread_bundle.h" 22 #include "content/public/test/test_browser_thread_bundle.h"
21 #include "testing/gtest/include/gtest/gtest.h" 23 #include "testing/gtest/include/gtest/gtest.h"
22 #include "url/gurl.h" 24 #include "url/gurl.h"
23 #include "url/origin.h" 25 #include "url/origin.h"
24 26
25 namespace { 27 namespace {
26 28
27 const double kDefaultExpirationInHours = 96; 29 // These values mirror the defaults in budget_database.cc
28 const double kDefaultEngagement = 30.0; 30 const double kDefaultExpirationInDays = 4;
31 const double kMaxDailyBudget = 12;
32
33 const double kEngagement = 25;
29 34
30 const char kTestOrigin[] = "https://example.com"; 35 const char kTestOrigin[] = "https://example.com";
31 36
32 } // namespace 37 } // namespace
33 38
34 class BudgetDatabaseTest : public ::testing::Test { 39 class BudgetDatabaseTest : public ::testing::Test {
35 public: 40 public:
36 BudgetDatabaseTest() 41 BudgetDatabaseTest()
37 : success_(false), 42 : success_(false),
38 db_(&profile_, 43 db_(&profile_,
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
107 TEST_F(BudgetDatabaseTest, GetBudgetNoBudgetOrSES) { 112 TEST_F(BudgetDatabaseTest, GetBudgetNoBudgetOrSES) {
108 GetBudgetDetails(); 113 GetBudgetDetails();
109 ASSERT_TRUE(success_); 114 ASSERT_TRUE(success_);
110 ASSERT_EQ(2U, prediction_.size()); 115 ASSERT_EQ(2U, prediction_.size());
111 EXPECT_EQ(0, prediction_[0]->budget_at); 116 EXPECT_EQ(0, prediction_[0]->budget_at);
112 } 117 }
113 118
114 TEST_F(BudgetDatabaseTest, AddEngagementBudgetTest) { 119 TEST_F(BudgetDatabaseTest, AddEngagementBudgetTest) {
115 base::SimpleTestClock* clock = SetClockForTesting(); 120 base::SimpleTestClock* clock = SetClockForTesting();
116 base::Time expiration_time = 121 base::Time expiration_time =
117 clock->Now() + base::TimeDelta::FromHours(kDefaultExpirationInHours); 122 clock->Now() + base::TimeDelta::FromDays(kDefaultExpirationInDays);
118 123
119 // Set the default site engagement. 124 // Set the default site engagement.
120 SetSiteEngagementScore(kDefaultEngagement); 125 SetSiteEngagementScore(kEngagement);
121 126
122 // The budget should include a full share of the engagement. 127 // The budget should include kDefaultExpirationInDays days worth of
128 // engagement.
129 double daily_budget =
130 kMaxDailyBudget * (kEngagement / SiteEngagementScore::kMaxPoints);
123 GetBudgetDetails(); 131 GetBudgetDetails();
124 ASSERT_TRUE(success_); 132 ASSERT_TRUE(success_);
125 ASSERT_EQ(2U, prediction_.size()); 133 ASSERT_EQ(2U, prediction_.size());
126 ASSERT_EQ(kDefaultEngagement, prediction_[0]->budget_at); 134 ASSERT_DOUBLE_EQ(daily_budget * kDefaultExpirationInDays,
135 prediction_[0]->budget_at);
127 ASSERT_EQ(0, prediction_[1]->budget_at); 136 ASSERT_EQ(0, prediction_[1]->budget_at);
128 ASSERT_EQ(expiration_time.ToDoubleT(), prediction_[1]->time); 137 ASSERT_EQ(expiration_time.ToDoubleT(), prediction_[1]->time);
129 138
130 // Advance time 1 day and add more engagement budget. 139 // Advance time 1 day and add more engagement budget.
131 clock->Advance(base::TimeDelta::FromDays(1)); 140 clock->Advance(base::TimeDelta::FromDays(1));
132 GetBudgetDetails(); 141 GetBudgetDetails();
133 142
134 // The budget should now have 1 full share plus 1 daily budget. 143 // The budget should now have 1 full share plus 1 daily budget.
135 ASSERT_TRUE(success_); 144 ASSERT_TRUE(success_);
136 ASSERT_EQ(3U, prediction_.size()); 145 ASSERT_EQ(3U, prediction_.size());
137 double daily_budget = kDefaultEngagement * 24 / kDefaultExpirationInHours; 146 ASSERT_DOUBLE_EQ(daily_budget * (kDefaultExpirationInDays + 1),
138 ASSERT_DOUBLE_EQ(kDefaultEngagement + daily_budget,
139 prediction_[0]->budget_at); 147 prediction_[0]->budget_at);
140 ASSERT_DOUBLE_EQ(daily_budget, prediction_[1]->budget_at); 148 ASSERT_DOUBLE_EQ(daily_budget, prediction_[1]->budget_at);
141 ASSERT_EQ(expiration_time.ToDoubleT(), prediction_[1]->time); 149 ASSERT_EQ(expiration_time.ToDoubleT(), prediction_[1]->time);
142 ASSERT_EQ(0, prediction_[2]->budget_at); 150 ASSERT_DOUBLE_EQ(0, prediction_[2]->budget_at);
143 ASSERT_EQ((expiration_time + base::TimeDelta::FromDays(1)).ToDoubleT(), 151 ASSERT_EQ((expiration_time + base::TimeDelta::FromDays(1)).ToDoubleT(),
144 prediction_[2]->time); 152 prediction_[2]->time);
145 153
146 // Advance time by 59 minutes and check that no engagement budget is added 154 // Advance time by 59 minutes and check that no engagement budget is added
147 // since budget should only be added for > 1 hour increments. 155 // since budget should only be added for > 1 hour increments.
148 clock->Advance(base::TimeDelta::FromMinutes(59)); 156 clock->Advance(base::TimeDelta::FromMinutes(59));
149 GetBudgetDetails(); 157 GetBudgetDetails();
150 158
151 // The budget should be the same as before the attempted add. 159 // The budget should be the same as before the attempted add.
152 ASSERT_TRUE(success_); 160 ASSERT_TRUE(success_);
153 ASSERT_EQ(3U, prediction_.size()); 161 ASSERT_EQ(3U, prediction_.size());
154 ASSERT_DOUBLE_EQ(kDefaultEngagement + daily_budget, 162 ASSERT_DOUBLE_EQ(daily_budget * (kDefaultExpirationInDays + 1),
155 prediction_[0]->budget_at); 163 prediction_[0]->budget_at);
156 } 164 }
157 165
158 TEST_F(BudgetDatabaseTest, SpendBudgetTest) { 166 TEST_F(BudgetDatabaseTest, SpendBudgetTest) {
159 base::SimpleTestClock* clock = SetClockForTesting(); 167 base::SimpleTestClock* clock = SetClockForTesting();
160 168
161 // Set the default site engagement. 169 // Set the default site engagement.
162 SetSiteEngagementScore(kDefaultEngagement); 170 SetSiteEngagementScore(kEngagement);
163 171
164 // Intialize the budget with several chunks. 172 // Intialize the budget with several chunks.
165 GetBudgetDetails(); 173 GetBudgetDetails();
166 clock->Advance(base::TimeDelta::FromDays(1)); 174 clock->Advance(base::TimeDelta::FromDays(1));
167 GetBudgetDetails(); 175 GetBudgetDetails();
168 clock->Advance(base::TimeDelta::FromDays(1)); 176 clock->Advance(base::TimeDelta::FromDays(1));
169 GetBudgetDetails(); 177 GetBudgetDetails();
170 178
171 // Spend an amount of budget less than kDefaultEngagement. 179 // Spend an amount of budget less than the daily budget.
172 ASSERT_TRUE(SpendBudget(1)); 180 ASSERT_TRUE(SpendBudget(1));
173 GetBudgetDetails(); 181 GetBudgetDetails();
174 182
175 // There should still be three chunks of budget of size kDefaultEngagement-1, 183 // There should still be three chunks of budget of size daily_budget-1,
176 // kDefaultEngagement, and kDefaultEngagement. 184 // daily_budget, and kDefaultExpirationInDays * daily_budget.
185 double daily_budget =
186 kMaxDailyBudget * (kEngagement / SiteEngagementScore::kMaxPoints);
177 ASSERT_EQ(4U, prediction_.size()); 187 ASSERT_EQ(4U, prediction_.size());
178 double daily_budget = kDefaultEngagement * 24 / kDefaultExpirationInHours; 188 ASSERT_DOUBLE_EQ((2 + kDefaultExpirationInDays) * daily_budget - 1,
179 ASSERT_DOUBLE_EQ(kDefaultEngagement + 2 * daily_budget - 1,
180 prediction_[0]->budget_at); 189 prediction_[0]->budget_at);
181 ASSERT_DOUBLE_EQ(daily_budget * 2, prediction_[1]->budget_at); 190 ASSERT_DOUBLE_EQ(daily_budget * 2, prediction_[1]->budget_at);
182 ASSERT_DOUBLE_EQ(daily_budget, prediction_[2]->budget_at); 191 ASSERT_DOUBLE_EQ(daily_budget, prediction_[2]->budget_at);
183 ASSERT_DOUBLE_EQ(0, prediction_[3]->budget_at); 192 ASSERT_DOUBLE_EQ(0, prediction_[3]->budget_at);
184 193
185 // Now spend enough that it will use up the rest of the first chunk and all of 194 // Now spend enough that it will use up the rest of the first chunk and all of
186 // the second chunk, but not all of the third chunk. 195 // the second chunk, but not all of the third chunk.
187 ASSERT_TRUE(SpendBudget(kDefaultEngagement + daily_budget)); 196 ASSERT_TRUE(SpendBudget((1 + kDefaultExpirationInDays) * daily_budget));
188 GetBudgetDetails(); 197 GetBudgetDetails();
189 ASSERT_EQ(2U, prediction_.size()); 198 ASSERT_EQ(2U, prediction_.size());
190 ASSERT_DOUBLE_EQ(daily_budget - 1, prediction_[0]->budget_at); 199 ASSERT_DOUBLE_EQ(daily_budget - 1, prediction_[0]->budget_at);
191 200
192 // Validate that the code returns false if SpendBudget tries to spend more 201 // Validate that the code returns false if SpendBudget tries to spend more
193 // budget than the origin has. 202 // budget than the origin has.
194 EXPECT_FALSE(SpendBudget(kDefaultEngagement)); 203 EXPECT_FALSE(SpendBudget(kEngagement));
195 GetBudgetDetails(); 204 GetBudgetDetails();
196 ASSERT_EQ(2U, prediction_.size()); 205 ASSERT_EQ(2U, prediction_.size());
197 ASSERT_DOUBLE_EQ(daily_budget - 1, prediction_[0]->budget_at); 206 ASSERT_DOUBLE_EQ(daily_budget - 1, prediction_[0]->budget_at);
198 207
199 // Advance time until the last remaining chunk should be expired, then query 208 // Advance time until the last remaining chunk should be expired, then query
200 // for the full engagement worth of budget. 209 // for the full engagement worth of budget.
201 clock->Advance(base::TimeDelta::FromHours(kDefaultExpirationInHours + 1)); 210 clock->Advance(base::TimeDelta::FromDays(kDefaultExpirationInDays + 1));
202 EXPECT_TRUE(SpendBudget(kDefaultEngagement)); 211 EXPECT_TRUE(SpendBudget(daily_budget * kDefaultExpirationInDays));
203 } 212 }
204 213
205 // There are times when a device's clock could move backwards in time, either 214 // There are times when a device's clock could move backwards in time, either
206 // due to hardware issues or user actions. Test here to make sure that even if 215 // due to hardware issues or user actions. Test here to make sure that even if
207 // time goes backwards and then forwards again, the origin isn't granted extra 216 // time goes backwards and then forwards again, the origin isn't granted extra
208 // budget. 217 // budget.
209 TEST_F(BudgetDatabaseTest, GetBudgetNegativeTime) { 218 TEST_F(BudgetDatabaseTest, GetBudgetNegativeTime) {
210 base::SimpleTestClock* clock = SetClockForTesting(); 219 base::SimpleTestClock* clock = SetClockForTesting();
211 220
212 // Set the default site engagement. 221 // Set the default site engagement.
213 SetSiteEngagementScore(kDefaultEngagement); 222 SetSiteEngagementScore(kEngagement);
214 223
215 // Initialize the budget with two chunks. 224 // Initialize the budget with two chunks.
216 GetBudgetDetails(); 225 GetBudgetDetails();
217 clock->Advance(base::TimeDelta::FromDays(1)); 226 clock->Advance(base::TimeDelta::FromDays(1));
218 GetBudgetDetails(); 227 GetBudgetDetails();
219 228
220 // Save off the budget total. 229 // Save off the budget total.
221 ASSERT_EQ(3U, prediction_.size()); 230 ASSERT_EQ(3U, prediction_.size());
222 double budget = prediction_[0]->budget_at; 231 double budget = prediction_[0]->budget_at;
223 232
(...skipping 10 matching lines...) Expand all
234 clock->SetNow(clock->Now() + base::TimeDelta::FromDays(5)); 243 clock->SetNow(clock->Now() + base::TimeDelta::FromDays(5));
235 GetBudgetDetails(); 244 GetBudgetDetails();
236 ASSERT_EQ(3U, prediction_.size()); 245 ASSERT_EQ(3U, prediction_.size());
237 ASSERT_EQ(budget, prediction_[0]->budget_at); 246 ASSERT_EQ(budget, prediction_[0]->budget_at);
238 } 247 }
239 248
240 TEST_F(BudgetDatabaseTest, CheckBackgroundBudgetHistogram) { 249 TEST_F(BudgetDatabaseTest, CheckBackgroundBudgetHistogram) {
241 base::SimpleTestClock* clock = SetClockForTesting(); 250 base::SimpleTestClock* clock = SetClockForTesting();
242 251
243 // Set the default site engagement. 252 // Set the default site engagement.
244 SetSiteEngagementScore(kDefaultEngagement); 253 SetSiteEngagementScore(kEngagement);
245 254
246 // Initialize the budget with some interesting chunks: 30 budget (full 255 // Initialize the budget with some interesting chunks: 30 budget (full
247 // engagement), 15 budget (half of the engagement), 0 budget (less than an 256 // engagement), 15 budget (half of the engagement), 0 budget (less than an
248 // hour), and then after the first two expire, another 30 budget. 257 // hour), and then after the first two expire, another 30 budget.
249 GetBudgetDetails(); 258 GetBudgetDetails();
250 clock->Advance(base::TimeDelta::FromHours(kDefaultExpirationInHours / 2)); 259 clock->Advance(base::TimeDelta::FromDays(kDefaultExpirationInDays / 2));
251 GetBudgetDetails(); 260 GetBudgetDetails();
252 clock->Advance(base::TimeDelta::FromMinutes(59)); 261 clock->Advance(base::TimeDelta::FromMinutes(59));
253 GetBudgetDetails(); 262 GetBudgetDetails();
254 clock->Advance(base::TimeDelta::FromHours(kDefaultExpirationInHours + 1)); 263 clock->Advance(base::TimeDelta::FromDays(kDefaultExpirationInDays + 1));
255 GetBudgetDetails(); 264 GetBudgetDetails();
256 265
257 // The BackgroundBudget UMA is recorded when budget is added to the origin. 266 // The BackgroundBudget UMA is recorded when budget is added to the origin.
258 // This can happen a maximum of once per hour so there should be two entries. 267 // This can happen a maximum of once per hour so there should be two entries.
259 std::vector<base::Bucket> buckets = 268 std::vector<base::Bucket> buckets =
260 GetHistogramTester()->GetAllSamples("PushMessaging.BackgroundBudget"); 269 GetHistogramTester()->GetAllSamples("PushMessaging.BackgroundBudget");
261 ASSERT_EQ(2U, buckets.size()); 270 ASSERT_EQ(2U, buckets.size());
262 // First bucket is for full engagement, which should have 2 entries. 271 // First bucket is for full award, which should have 2 entries.
263 EXPECT_EQ(kDefaultEngagement, buckets[0].min); 272 double full_award = kMaxDailyBudget * kEngagement /
273 SiteEngagementScore::kMaxPoints *
274 kDefaultExpirationInDays;
275 EXPECT_EQ(floor(full_award), buckets[0].min);
264 EXPECT_EQ(2, buckets[0].count); 276 EXPECT_EQ(2, buckets[0].count);
265 // Second bucket is for 1.5 * engagement, which should have 1 entry. 277 // Second bucket is for 1.5 * award, which should have 1 entry.
266 EXPECT_EQ(kDefaultEngagement * 1.5, buckets[1].min); 278 EXPECT_EQ(floor(full_award * 1.5), buckets[1].min);
267 EXPECT_EQ(1, buckets[1].count); 279 EXPECT_EQ(1, buckets[1].count);
268 } 280 }
269 281
270 TEST_F(BudgetDatabaseTest, CheckEngagementHistograms) { 282 TEST_F(BudgetDatabaseTest, CheckEngagementHistograms) {
271 base::SimpleTestClock* clock = SetClockForTesting(); 283 base::SimpleTestClock* clock = SetClockForTesting();
272 284
273 // Set the engagement to twice the cost of an action. 285 // Manipulate the engagement so that the budget is twice the cost of an
286 // action.
274 double cost = 2; 287 double cost = 2;
275 double engagement = cost * 2; 288 double engagement = 2 * cost * SiteEngagementScore::kMaxPoints /
289 kDefaultExpirationInDays / kMaxDailyBudget;
276 SetSiteEngagementScore(engagement); 290 SetSiteEngagementScore(engagement);
277 291
278 // Get the budget, which will award a chunk of budget equal to engagement. 292 // Get the budget, which will award a chunk of budget equal to engagement.
279 GetBudgetDetails(); 293 GetBudgetDetails();
280 294
281 // Now spend the budget to trigger the UMA recording the SES score. The first 295 // Now spend the budget to trigger the UMA recording the SES score. The first
282 // call shouldn't write any UMA. The second should write a lowSES entry, and 296 // call shouldn't write any UMA. The second should write a lowSES entry, and
283 // the third should write a noSES entry. 297 // the third should write a noSES entry.
284 ASSERT_TRUE(SpendBudget(cost)); 298 ASSERT_TRUE(SpendBudget(cost));
285 ASSERT_TRUE(SpendBudget(cost)); 299 ASSERT_TRUE(SpendBudget(cost));
286 ASSERT_FALSE(SpendBudget(cost)); 300 ASSERT_FALSE(SpendBudget(cost));
287 301
288 // Advance the clock by 12 days (to guarantee a full new engagement grant) 302 // Advance the clock by 12 days (to guarantee a full new engagement grant)
289 // then change the SES score to get a different UMA entry, then spend the 303 // then change the SES score to get a different UMA entry, then spend the
290 // budget again. 304 // budget again.
291 clock->Advance(base::TimeDelta::FromDays(12)); 305 clock->Advance(base::TimeDelta::FromDays(12));
292 GetBudgetDetails(); 306 GetBudgetDetails();
293 SetSiteEngagementScore(engagement * 2); 307 SetSiteEngagementScore(engagement * 2);
294 ASSERT_TRUE(SpendBudget(cost)); 308 ASSERT_TRUE(SpendBudget(cost));
295 ASSERT_TRUE(SpendBudget(cost)); 309 ASSERT_TRUE(SpendBudget(cost));
296 ASSERT_FALSE(SpendBudget(cost)); 310 ASSERT_FALSE(SpendBudget(cost));
297 311
298 // Now check the UMA. Both UMA should have 2 buckets with 1 entry each. 312 // Now check the UMA. Both UMA should have 2 buckets with 1 entry each.
299 std::vector<base::Bucket> no_budget_buckets = 313 std::vector<base::Bucket> no_budget_buckets =
300 GetHistogramTester()->GetAllSamples("PushMessaging.SESForNoBudgetOrigin"); 314 GetHistogramTester()->GetAllSamples("PushMessaging.SESForNoBudgetOrigin");
301 ASSERT_EQ(2U, no_budget_buckets.size()); 315 ASSERT_EQ(2U, no_budget_buckets.size());
302 EXPECT_EQ(engagement, no_budget_buckets[0].min); 316 EXPECT_EQ(floor(engagement), no_budget_buckets[0].min);
303 EXPECT_EQ(1, no_budget_buckets[0].count); 317 EXPECT_EQ(1, no_budget_buckets[0].count);
304 EXPECT_EQ(engagement * 2, no_budget_buckets[1].min); 318 EXPECT_EQ(floor(engagement * 2), no_budget_buckets[1].min);
305 EXPECT_EQ(1, no_budget_buckets[1].count); 319 EXPECT_EQ(1, no_budget_buckets[1].count);
306 320
307 std::vector<base::Bucket> low_budget_buckets = 321 std::vector<base::Bucket> low_budget_buckets =
308 GetHistogramTester()->GetAllSamples( 322 GetHistogramTester()->GetAllSamples(
309 "PushMessaging.SESForLowBudgetOrigin"); 323 "PushMessaging.SESForLowBudgetOrigin");
310 ASSERT_EQ(2U, low_budget_buckets.size()); 324 ASSERT_EQ(2U, low_budget_buckets.size());
311 EXPECT_EQ(engagement, low_budget_buckets[0].min); 325 EXPECT_EQ(floor(engagement), low_budget_buckets[0].min);
312 EXPECT_EQ(1, low_budget_buckets[0].count); 326 EXPECT_EQ(1, low_budget_buckets[0].count);
313 EXPECT_EQ(engagement * 2, low_budget_buckets[1].min); 327 EXPECT_EQ(floor(engagement * 2), low_budget_buckets[1].min);
314 EXPECT_EQ(1, low_budget_buckets[1].count); 328 EXPECT_EQ(1, low_budget_buckets[1].count);
315 } 329 }
OLDNEW
« no previous file with comments | « chrome/browser/budget_service/budget_database.cc ('k') | chrome/browser/budget_service/budget_manager_browsertest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698