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

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

Issue 2281673002: Full hookup of BudgetManager interfaces to BudgetDatabase. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@manager
Patch Set: Rebase and integrate with Reserve plumbing and new error type parameter. 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
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 <vector>
8
7 #include "base/run_loop.h" 9 #include "base/run_loop.h"
10 #include "base/test/histogram_tester.h"
8 #include "base/test/simple_test_clock.h" 11 #include "base/test/simple_test_clock.h"
9 #include "base/threading/thread_task_runner_handle.h" 12 #include "base/threading/thread_task_runner_handle.h"
10 #include "chrome/browser/budget_service/budget.pb.h" 13 #include "chrome/browser/budget_service/budget.pb.h"
11 #include "chrome/browser/engagement/site_engagement_service.h" 14 #include "chrome/browser/engagement/site_engagement_service.h"
12 #include "chrome/test/base/testing_profile.h" 15 #include "chrome/test/base/testing_profile.h"
13 #include "components/leveldb_proto/proto_database.h" 16 #include "components/leveldb_proto/proto_database.h"
14 #include "components/leveldb_proto/proto_database_impl.h" 17 #include "components/leveldb_proto/proto_database_impl.h"
15 #include "content/public/browser/browser_thread.h" 18 #include "content/public/browser/browser_thread.h"
16 #include "content/public/test/test_browser_thread_bundle.h" 19 #include "content/public/test/test_browser_thread_bundle.h"
20 #include "mojo/public/cpp/bindings/array.h"
17 #include "testing/gtest/include/gtest/gtest.h" 21 #include "testing/gtest/include/gtest/gtest.h"
18 22
19 namespace { 23 namespace {
20 24
21 const double kDefaultExpirationInHours = 72; 25 const double kDefaultExpirationInHours = 240;
22 const double kDefaultEngagement = 30.0; 26 const double kDefaultEngagement = 30.0;
23 27
24 const char kTestOrigin[] = "https://example.com"; 28 const char kTestOrigin[] = "https://example.com";
25 29
26 } // namespace 30 } // namespace
27 31
28 class BudgetDatabaseTest : public ::testing::Test { 32 class BudgetDatabaseTest : public ::testing::Test {
29 public: 33 public:
30 BudgetDatabaseTest() 34 BudgetDatabaseTest()
31 : success_(false), 35 : success_(false),
(...skipping 11 matching lines...) Expand all
43 base::RunLoop run_loop; 47 base::RunLoop run_loop;
44 db_.SpendBudget(origin, amount, 48 db_.SpendBudget(origin, amount,
45 base::Bind(&BudgetDatabaseTest::WriteBudgetComplete, 49 base::Bind(&BudgetDatabaseTest::WriteBudgetComplete,
46 base::Unretained(this), run_loop.QuitClosure())); 50 base::Unretained(this), run_loop.QuitClosure()));
47 run_loop.Run(); 51 run_loop.Run();
48 return success_; 52 return success_;
49 } 53 }
50 54
51 void GetBudgetDetailsComplete( 55 void GetBudgetDetailsComplete(
52 base::Closure run_loop_closure, 56 base::Closure run_loop_closure,
53 bool success, 57 blink::mojom::BudgetServiceErrorType error,
54 const BudgetDatabase::BudgetPrediction& prediction) { 58 mojo::Array<blink::mojom::BudgetStatePtr> predictions) {
55 success_ = success; 59 success_ =
56 // Convert BudgetPrediction to a vector for random access to check values. 60 (error == blink::mojom::BudgetServiceErrorType::NONE) ? true : false;
Peter Beverloo 2016/09/07 16:56:35 Why do you do this? The result of a comparison alr
harkness 2016/09/07 17:10:29 I was mis-reading a code style rule, updated it.
57 prediction_.assign(prediction.begin(), prediction.end()); 61 prediction_.Swap(&predictions);
58 run_loop_closure.Run(); 62 run_loop_closure.Run();
59 } 63 }
60 64
61 // Get the full set of budget predictions for the origin. 65 // Get the full set of budget predictions for the origin.
62 void GetBudgetDetails() { 66 void GetBudgetDetails() {
63 base::RunLoop run_loop; 67 base::RunLoop run_loop;
64 db_.GetBudgetDetails( 68 db_.GetBudgetDetails(
65 GURL(kTestOrigin), 69 GURL(kTestOrigin),
66 base::Bind(&BudgetDatabaseTest::GetBudgetDetailsComplete, 70 base::Bind(&BudgetDatabaseTest::GetBudgetDetailsComplete,
67 base::Unretained(this), run_loop.QuitClosure())); 71 base::Unretained(this), run_loop.QuitClosure()));
68 run_loop.Run(); 72 run_loop.Run();
69 } 73 }
70 74
71 Profile* profile() { return &profile_; } 75 Profile* profile() { return &profile_; }
72 76
73 // Setup a test clock so that the tests can control time. 77 // Setup a test clock so that the tests can control time.
74 base::SimpleTestClock* SetClockForTesting() { 78 base::SimpleTestClock* SetClockForTesting() {
75 base::SimpleTestClock* clock = new base::SimpleTestClock(); 79 base::SimpleTestClock* clock = new base::SimpleTestClock();
76 db_.SetClockForTesting(base::WrapUnique(clock)); 80 db_.SetClockForTesting(base::WrapUnique(clock));
77 return clock; 81 return clock;
78 } 82 }
79 83
80 void SetSiteEngagementScore(const GURL& url, double score) { 84 void SetSiteEngagementScore(const GURL& url, double score) {
81 SiteEngagementService* service = SiteEngagementService::Get(&profile_); 85 SiteEngagementService* service = SiteEngagementService::Get(&profile_);
82 service->ResetScoreForURL(url, score); 86 service->ResetScoreForURL(url, score);
83 } 87 }
84 88
85 protected: 89 protected:
90 base::HistogramTester* GetHistogramTester() { return &histogram_tester_; }
86 bool success_; 91 bool success_;
87 std::vector<BudgetDatabase::BudgetStatus> prediction_; 92 mojo::Array<blink::mojom::BudgetStatePtr> prediction_;
88 93
89 private: 94 private:
90 content::TestBrowserThreadBundle thread_bundle_; 95 content::TestBrowserThreadBundle thread_bundle_;
91 std::unique_ptr<budget_service::Budget> budget_; 96 std::unique_ptr<budget_service::Budget> budget_;
92 TestingProfile profile_; 97 TestingProfile profile_;
93 BudgetDatabase db_; 98 BudgetDatabase db_;
99 base::HistogramTester histogram_tester_;
94 }; 100 };
95 101
102 TEST_F(BudgetDatabaseTest, GetBudgetNoBudgetOrSES) {
103 const GURL origin(kTestOrigin);
104 GetBudgetDetails();
105 ASSERT_TRUE(success_);
106 ASSERT_EQ(2U, prediction_.size());
107 EXPECT_EQ(0, prediction_[0]->budget_at);
108 }
109
96 TEST_F(BudgetDatabaseTest, AddEngagementBudgetTest) { 110 TEST_F(BudgetDatabaseTest, AddEngagementBudgetTest) {
97 const GURL origin(kTestOrigin); 111 const GURL origin(kTestOrigin);
98 base::SimpleTestClock* clock = SetClockForTesting(); 112 base::SimpleTestClock* clock = SetClockForTesting();
99 base::Time expiration_time = 113 base::Time expiration_time =
100 clock->Now() + base::TimeDelta::FromHours(kDefaultExpirationInHours); 114 clock->Now() + base::TimeDelta::FromHours(kDefaultExpirationInHours);
101 115
102 // Set the default site engagement. 116 // Set the default site engagement.
103 SetSiteEngagementScore(origin, kDefaultEngagement); 117 SetSiteEngagementScore(origin, kDefaultEngagement);
104 118
105 // The budget should include a full share of the engagement. 119 // The budget should include a full share of the engagement.
106 GetBudgetDetails(); 120 GetBudgetDetails();
107 ASSERT_TRUE(success_); 121 ASSERT_TRUE(success_);
108 ASSERT_EQ(2U, prediction_.size()); 122 ASSERT_EQ(2U, prediction_.size());
109 ASSERT_EQ(kDefaultEngagement, prediction_[0].budget_at); 123 ASSERT_EQ(kDefaultEngagement, prediction_[0]->budget_at);
110 ASSERT_EQ(0, prediction_[1].budget_at); 124 ASSERT_EQ(0, prediction_[1]->budget_at);
111 ASSERT_EQ(expiration_time, prediction_[1].time); 125 ASSERT_EQ(expiration_time.ToDoubleT(), prediction_[1]->time);
112 126
113 // Advance time 1 day and add more engagement budget. 127 // Advance time 1 day and add more engagement budget.
114 clock->Advance(base::TimeDelta::FromDays(1)); 128 clock->Advance(base::TimeDelta::FromDays(1));
115 GetBudgetDetails(); 129 GetBudgetDetails();
116 130
117 // The budget should now have 1 full share plus 1/3 share. 131 // The budget should now have 1 full share plus 1 daily budget.
118 ASSERT_TRUE(success_); 132 ASSERT_TRUE(success_);
119 ASSERT_EQ(3U, prediction_.size()); 133 ASSERT_EQ(3U, prediction_.size());
120 ASSERT_DOUBLE_EQ(kDefaultEngagement * 4 / 3, prediction_[0].budget_at); 134 double daily_budget = kDefaultEngagement * 24 / kDefaultExpirationInHours;
121 ASSERT_DOUBLE_EQ(kDefaultEngagement * 1 / 3, prediction_[1].budget_at); 135 ASSERT_DOUBLE_EQ(kDefaultEngagement + daily_budget,
122 ASSERT_EQ(expiration_time, prediction_[1].time); 136 prediction_[0]->budget_at);
123 ASSERT_EQ(0, prediction_[2].budget_at); 137 ASSERT_DOUBLE_EQ(daily_budget, prediction_[1]->budget_at);
124 ASSERT_EQ(expiration_time + base::TimeDelta::FromDays(1), 138 ASSERT_EQ(expiration_time.ToDoubleT(), prediction_[1]->time);
125 prediction_[2].time); 139 ASSERT_EQ(0, prediction_[2]->budget_at);
140 ASSERT_EQ((expiration_time + base::TimeDelta::FromDays(1)).ToDoubleT(),
141 prediction_[2]->time);
126 142
127 // Advance time by 59 minutes and check that no engagement budget is added 143 // Advance time by 59 minutes and check that no engagement budget is added
128 // since budget should only be added for > 1 hour increments. 144 // since budget should only be added for > 1 hour increments.
129 clock->Advance(base::TimeDelta::FromMinutes(59)); 145 clock->Advance(base::TimeDelta::FromMinutes(59));
146 GetBudgetDetails();
130 147
131 // The budget should be the same as before the attempted add. 148 // The budget should be the same as before the attempted add.
132 GetBudgetDetails();
133 ASSERT_TRUE(success_); 149 ASSERT_TRUE(success_);
134 ASSERT_EQ(3U, prediction_.size()); 150 ASSERT_EQ(3U, prediction_.size());
135 ASSERT_DOUBLE_EQ(kDefaultEngagement * 4 / 3, prediction_[0].budget_at); 151 ASSERT_DOUBLE_EQ(kDefaultEngagement + daily_budget,
152 prediction_[0]->budget_at);
136 } 153 }
137 154
138 TEST_F(BudgetDatabaseTest, SpendBudgetTest) { 155 TEST_F(BudgetDatabaseTest, SpendBudgetTest) {
139 const GURL origin(kTestOrigin); 156 const GURL origin(kTestOrigin);
140 base::SimpleTestClock* clock = SetClockForTesting(); 157 base::SimpleTestClock* clock = SetClockForTesting();
141 158
142 // Set the default site engagement. 159 // Set the default site engagement.
143 SetSiteEngagementScore(origin, kDefaultEngagement); 160 SetSiteEngagementScore(origin, kDefaultEngagement);
144 161
145 // Intialize the budget with several chunks. 162 // Intialize the budget with several chunks.
146 GetBudgetDetails(); 163 GetBudgetDetails();
147 clock->Advance(base::TimeDelta::FromDays(1)); 164 clock->Advance(base::TimeDelta::FromDays(1));
148 GetBudgetDetails(); 165 GetBudgetDetails();
149 clock->Advance(base::TimeDelta::FromDays(1)); 166 clock->Advance(base::TimeDelta::FromDays(1));
150 GetBudgetDetails(); 167 GetBudgetDetails();
151 168
152 // Spend an amount of budget less than kDefaultEngagement. 169 // Spend an amount of budget less than kDefaultEngagement.
153 ASSERT_TRUE(SpendBudget(origin, 1)); 170 ASSERT_TRUE(SpendBudget(origin, 1));
154 GetBudgetDetails(); 171 GetBudgetDetails();
155 172
156 // There should still be three chunks of budget of size kDefaultEngagement-1, 173 // There should still be three chunks of budget of size kDefaultEngagement-1,
157 // kDefaultEngagement, and kDefaultEngagement. 174 // kDefaultEngagement, and kDefaultEngagement.
158 ASSERT_EQ(4U, prediction_.size()); 175 ASSERT_EQ(4U, prediction_.size());
159 ASSERT_DOUBLE_EQ(kDefaultEngagement * 5 / 3 - 1, prediction_[0].budget_at); 176 double daily_budget = kDefaultEngagement * 24 / kDefaultExpirationInHours;
160 ASSERT_DOUBLE_EQ(kDefaultEngagement * 2 / 3, prediction_[1].budget_at); 177 ASSERT_DOUBLE_EQ(kDefaultEngagement + 2 * daily_budget - 1,
161 ASSERT_DOUBLE_EQ(kDefaultEngagement * 1 / 3, prediction_[2].budget_at); 178 prediction_[0]->budget_at);
162 ASSERT_DOUBLE_EQ(0, prediction_[3].budget_at); 179 ASSERT_DOUBLE_EQ(daily_budget * 2, prediction_[1]->budget_at);
180 ASSERT_DOUBLE_EQ(daily_budget, prediction_[2]->budget_at);
181 ASSERT_DOUBLE_EQ(0, prediction_[3]->budget_at);
163 182
164 // Now spend enough that it will use up the rest of the first chunk and all of 183 // Now spend enough that it will use up the rest of the first chunk and all of
165 // the second chunk, but not all of the third chunk. 184 // the second chunk, but not all of the third chunk.
166 ASSERT_TRUE(SpendBudget(origin, kDefaultEngagement * 4 / 3)); 185 ASSERT_TRUE(SpendBudget(origin, kDefaultEngagement + daily_budget));
167 GetBudgetDetails(); 186 GetBudgetDetails();
168 ASSERT_EQ(2U, prediction_.size()); 187 ASSERT_EQ(2U, prediction_.size());
169 ASSERT_DOUBLE_EQ(kDefaultEngagement * 1 / 3 - 1, 188 ASSERT_DOUBLE_EQ(daily_budget - 1, prediction_[0]->budget_at);
170 prediction_.begin()->budget_at);
171 189
172 // Validate that the code returns false if SpendBudget tries to spend more 190 // Validate that the code returns false if SpendBudget tries to spend more
173 // budget than the origin has. 191 // budget than the origin has.
174 EXPECT_FALSE(SpendBudget(origin, kDefaultEngagement)); 192 EXPECT_FALSE(SpendBudget(origin, kDefaultEngagement));
175 GetBudgetDetails(); 193 GetBudgetDetails();
176 ASSERT_EQ(2U, prediction_.size()); 194 ASSERT_EQ(2U, prediction_.size());
177 ASSERT_DOUBLE_EQ(kDefaultEngagement * 1 / 3 - 1, 195 ASSERT_DOUBLE_EQ(daily_budget - 1, prediction_[0]->budget_at);
178 prediction_.begin()->budget_at);
179 196
180 // Advance time until the last remaining chunk should be expired, then query 197 // Advance time until the last remaining chunk should be expired, then query
181 // for the full engagement worth of budget. 198 // for the full engagement worth of budget.
182 clock->Advance(base::TimeDelta::FromDays(6)); 199 clock->Advance(base::TimeDelta::FromHours(kDefaultExpirationInHours + 1));
183 EXPECT_TRUE(SpendBudget(origin, kDefaultEngagement)); 200 EXPECT_TRUE(SpendBudget(origin, kDefaultEngagement));
184 } 201 }
202
203 // There are times when a device's clock could move backwards in time, either
204 // due to hardware issues or user actions. Test here to make sure that even if
205 // time goes backwards and then forwards again, the origin isn't granted extra
206 // budget.
207 TEST_F(BudgetDatabaseTest, GetBudgetNegativeTime) {
208 const GURL origin(kTestOrigin);
209 base::SimpleTestClock* clock = SetClockForTesting();
210
211 // Set the default site engagement.
212 SetSiteEngagementScore(origin, kDefaultEngagement);
213
214 // Initialize the budget with two chunks.
215 GetBudgetDetails();
216 clock->Advance(base::TimeDelta::FromDays(1));
217 GetBudgetDetails();
218
219 // Save off the budget total.
220 ASSERT_EQ(3U, prediction_.size());
221 double budget = prediction_[0]->budget_at;
222
223 // Move the clock backwards in time to before the budget awards.
224 clock->SetNow(clock->Now() - base::TimeDelta::FromDays(5));
225
226 // Make sure the budget is the same.
227 GetBudgetDetails();
228 ASSERT_EQ(3U, prediction_.size());
229 ASSERT_EQ(budget, prediction_[0]->budget_at);
230
231 // Now move the clock back to the original time and check that no extra budget
232 // is awarded.
233 clock->SetNow(clock->Now() + base::TimeDelta::FromDays(5));
234 GetBudgetDetails();
235 ASSERT_EQ(3U, prediction_.size());
236 ASSERT_EQ(budget, prediction_[0]->budget_at);
237 }
238
239 TEST_F(BudgetDatabaseTest, CheckBackgroundBudgetHistogram) {
240 const GURL origin(kTestOrigin);
241 base::SimpleTestClock* clock = SetClockForTesting();
242
243 // Set the default site engagement.
244 SetSiteEngagementScore(origin, kDefaultEngagement);
245
246 // Initialize the budget with some interesting chunks: 30 budget, 3 budget,
247 // 0 budget, and then after the first two expire, another 30 budget.
248 GetBudgetDetails();
249 clock->Advance(base::TimeDelta::FromDays(2));
250 GetBudgetDetails();
251 clock->Advance(base::TimeDelta::FromMinutes(59));
252 GetBudgetDetails();
253 clock->Advance(base::TimeDelta::FromDays(11));
254 GetBudgetDetails();
255
256 // The BackgroundBudget UMA is recorded when budget is added to the origin.
257 // This can happen a maximum of once per hour so there should be two entries.
258 std::vector<base::Bucket> buckets =
259 GetHistogramTester()->GetAllSamples("PushMessaging.BackgroundBudget");
260 ASSERT_EQ(2U, buckets.size());
261 // First bucket is for 30 budget, which should have 2 entries.
262 EXPECT_EQ(30, buckets[0].min);
263 EXPECT_EQ(2, buckets[0].count);
264 // Second bucket is for 36 budget, which should have 1 entry.
265 EXPECT_EQ(36, buckets[1].min);
266 EXPECT_EQ(1, buckets[1].count);
267 }
268
269 TEST_F(BudgetDatabaseTest, CheckEngagementHistograms) {
270 const GURL origin(kTestOrigin);
271 base::SimpleTestClock* clock = SetClockForTesting();
272
273 // Set the engagement to twice the cost of an action.
274 double cost = 2;
275 double engagement = cost * 2;
276 SetSiteEngagementScore(origin, engagement);
277
278 // Get the budget, which will award a chunk of budget equal to engagement.
279 GetBudgetDetails();
280
281 // 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
283 // the third should write a noSES entry.
284 ASSERT_TRUE(SpendBudget(origin, cost));
285 ASSERT_TRUE(SpendBudget(origin, cost));
286 ASSERT_FALSE(SpendBudget(origin, cost));
287
288 // 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
290 // budget again.
291 clock->Advance(base::TimeDelta::FromDays(12));
292 GetBudgetDetails();
293 SetSiteEngagementScore(origin, engagement * 2);
294 ASSERT_TRUE(SpendBudget(origin, cost));
295 ASSERT_TRUE(SpendBudget(origin, cost));
296 ASSERT_FALSE(SpendBudget(origin, cost));
297
298 // Now check the UMA. Both UMA should have 2 buckets with 1 entry each.
299 std::vector<base::Bucket> no_budget_buckets =
300 GetHistogramTester()->GetAllSamples("PushMessaging.SESForNoBudgetOrigin");
301 ASSERT_EQ(2U, no_budget_buckets.size());
302 EXPECT_EQ(engagement, no_budget_buckets[0].min);
303 EXPECT_EQ(1, no_budget_buckets[0].count);
304 EXPECT_EQ(engagement * 2, no_budget_buckets[1].min);
305 EXPECT_EQ(1, no_budget_buckets[1].count);
306
307 std::vector<base::Bucket> low_budget_buckets =
308 GetHistogramTester()->GetAllSamples(
309 "PushMessaging.SESForLowBudgetOrigin");
310 ASSERT_EQ(2U, low_budget_buckets.size());
311 EXPECT_EQ(engagement, low_budget_buckets[0].min);
312 EXPECT_EQ(1, low_budget_buckets[0].count);
313 EXPECT_EQ(engagement * 2, low_budget_buckets[1].min);
314 EXPECT_EQ(1, low_budget_buckets[1].count);
315 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698