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

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: nits 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_ = (error == blink::mojom::BudgetServiceErrorType::NONE);
56 // Convert BudgetPrediction to a vector for random access to check values. 60 prediction_.Swap(&predictions);
57 prediction_.assign(prediction.begin(), prediction.end());
58 run_loop_closure.Run(); 61 run_loop_closure.Run();
59 } 62 }
60 63
61 // Get the full set of budget predictions for the origin. 64 // Get the full set of budget predictions for the origin.
62 void GetBudgetDetails() { 65 void GetBudgetDetails() {
63 base::RunLoop run_loop; 66 base::RunLoop run_loop;
64 db_.GetBudgetDetails( 67 db_.GetBudgetDetails(
65 GURL(kTestOrigin), 68 GURL(kTestOrigin),
66 base::Bind(&BudgetDatabaseTest::GetBudgetDetailsComplete, 69 base::Bind(&BudgetDatabaseTest::GetBudgetDetailsComplete,
67 base::Unretained(this), run_loop.QuitClosure())); 70 base::Unretained(this), run_loop.QuitClosure()));
68 run_loop.Run(); 71 run_loop.Run();
69 } 72 }
70 73
71 Profile* profile() { return &profile_; } 74 Profile* profile() { return &profile_; }
72 75
73 // Setup a test clock so that the tests can control time. 76 // Setup a test clock so that the tests can control time.
74 base::SimpleTestClock* SetClockForTesting() { 77 base::SimpleTestClock* SetClockForTesting() {
75 base::SimpleTestClock* clock = new base::SimpleTestClock(); 78 base::SimpleTestClock* clock = new base::SimpleTestClock();
76 db_.SetClockForTesting(base::WrapUnique(clock)); 79 db_.SetClockForTesting(base::WrapUnique(clock));
77 return clock; 80 return clock;
78 } 81 }
79 82
80 void SetSiteEngagementScore(const GURL& url, double score) { 83 void SetSiteEngagementScore(const GURL& url, double score) {
81 SiteEngagementService* service = SiteEngagementService::Get(&profile_); 84 SiteEngagementService* service = SiteEngagementService::Get(&profile_);
82 service->ResetScoreForURL(url, score); 85 service->ResetScoreForURL(url, score);
83 } 86 }
84 87
85 protected: 88 protected:
89 base::HistogramTester* GetHistogramTester() { return &histogram_tester_; }
86 bool success_; 90 bool success_;
87 std::vector<BudgetDatabase::BudgetStatus> prediction_; 91 mojo::Array<blink::mojom::BudgetStatePtr> prediction_;
88 92
89 private: 93 private:
90 content::TestBrowserThreadBundle thread_bundle_; 94 content::TestBrowserThreadBundle thread_bundle_;
91 std::unique_ptr<budget_service::Budget> budget_; 95 std::unique_ptr<budget_service::Budget> budget_;
92 TestingProfile profile_; 96 TestingProfile profile_;
93 BudgetDatabase db_; 97 BudgetDatabase db_;
98 base::HistogramTester histogram_tester_;
94 }; 99 };
95 100
101 TEST_F(BudgetDatabaseTest, GetBudgetNoBudgetOrSES) {
102 const GURL origin(kTestOrigin);
103 GetBudgetDetails();
104 ASSERT_TRUE(success_);
105 ASSERT_EQ(2U, prediction_.size());
106 EXPECT_EQ(0, prediction_[0]->budget_at);
107 }
108
96 TEST_F(BudgetDatabaseTest, AddEngagementBudgetTest) { 109 TEST_F(BudgetDatabaseTest, AddEngagementBudgetTest) {
97 const GURL origin(kTestOrigin); 110 const GURL origin(kTestOrigin);
98 base::SimpleTestClock* clock = SetClockForTesting(); 111 base::SimpleTestClock* clock = SetClockForTesting();
99 base::Time expiration_time = 112 base::Time expiration_time =
100 clock->Now() + base::TimeDelta::FromHours(kDefaultExpirationInHours); 113 clock->Now() + base::TimeDelta::FromHours(kDefaultExpirationInHours);
101 114
102 // Set the default site engagement. 115 // Set the default site engagement.
103 SetSiteEngagementScore(origin, kDefaultEngagement); 116 SetSiteEngagementScore(origin, kDefaultEngagement);
104 117
105 // The budget should include a full share of the engagement. 118 // The budget should include a full share of the engagement.
106 GetBudgetDetails(); 119 GetBudgetDetails();
107 ASSERT_TRUE(success_); 120 ASSERT_TRUE(success_);
108 ASSERT_EQ(2U, prediction_.size()); 121 ASSERT_EQ(2U, prediction_.size());
109 ASSERT_EQ(kDefaultEngagement, prediction_[0].budget_at); 122 ASSERT_EQ(kDefaultEngagement, prediction_[0]->budget_at);
110 ASSERT_EQ(0, prediction_[1].budget_at); 123 ASSERT_EQ(0, prediction_[1]->budget_at);
111 ASSERT_EQ(expiration_time, prediction_[1].time); 124 ASSERT_EQ(expiration_time.ToDoubleT(), prediction_[1]->time);
112 125
113 // Advance time 1 day and add more engagement budget. 126 // Advance time 1 day and add more engagement budget.
114 clock->Advance(base::TimeDelta::FromDays(1)); 127 clock->Advance(base::TimeDelta::FromDays(1));
115 GetBudgetDetails(); 128 GetBudgetDetails();
116 129
117 // The budget should now have 1 full share plus 1/3 share. 130 // The budget should now have 1 full share plus 1 daily budget.
118 ASSERT_TRUE(success_); 131 ASSERT_TRUE(success_);
119 ASSERT_EQ(3U, prediction_.size()); 132 ASSERT_EQ(3U, prediction_.size());
120 ASSERT_DOUBLE_EQ(kDefaultEngagement * 4 / 3, prediction_[0].budget_at); 133 double daily_budget = kDefaultEngagement * 24 / kDefaultExpirationInHours;
121 ASSERT_DOUBLE_EQ(kDefaultEngagement * 1 / 3, prediction_[1].budget_at); 134 ASSERT_DOUBLE_EQ(kDefaultEngagement + daily_budget,
122 ASSERT_EQ(expiration_time, prediction_[1].time); 135 prediction_[0]->budget_at);
123 ASSERT_EQ(0, prediction_[2].budget_at); 136 ASSERT_DOUBLE_EQ(daily_budget, prediction_[1]->budget_at);
124 ASSERT_EQ(expiration_time + base::TimeDelta::FromDays(1), 137 ASSERT_EQ(expiration_time.ToDoubleT(), prediction_[1]->time);
125 prediction_[2].time); 138 ASSERT_EQ(0, prediction_[2]->budget_at);
139 ASSERT_EQ((expiration_time + base::TimeDelta::FromDays(1)).ToDoubleT(),
140 prediction_[2]->time);
126 141
127 // Advance time by 59 minutes and check that no engagement budget is added 142 // Advance time by 59 minutes and check that no engagement budget is added
128 // since budget should only be added for > 1 hour increments. 143 // since budget should only be added for > 1 hour increments.
129 clock->Advance(base::TimeDelta::FromMinutes(59)); 144 clock->Advance(base::TimeDelta::FromMinutes(59));
145 GetBudgetDetails();
130 146
131 // The budget should be the same as before the attempted add. 147 // The budget should be the same as before the attempted add.
132 GetBudgetDetails();
133 ASSERT_TRUE(success_); 148 ASSERT_TRUE(success_);
134 ASSERT_EQ(3U, prediction_.size()); 149 ASSERT_EQ(3U, prediction_.size());
135 ASSERT_DOUBLE_EQ(kDefaultEngagement * 4 / 3, prediction_[0].budget_at); 150 ASSERT_DOUBLE_EQ(kDefaultEngagement + daily_budget,
151 prediction_[0]->budget_at);
136 } 152 }
137 153
138 TEST_F(BudgetDatabaseTest, SpendBudgetTest) { 154 TEST_F(BudgetDatabaseTest, SpendBudgetTest) {
139 const GURL origin(kTestOrigin); 155 const GURL origin(kTestOrigin);
140 base::SimpleTestClock* clock = SetClockForTesting(); 156 base::SimpleTestClock* clock = SetClockForTesting();
141 157
142 // Set the default site engagement. 158 // Set the default site engagement.
143 SetSiteEngagementScore(origin, kDefaultEngagement); 159 SetSiteEngagementScore(origin, kDefaultEngagement);
144 160
145 // Intialize the budget with several chunks. 161 // Intialize the budget with several chunks.
146 GetBudgetDetails(); 162 GetBudgetDetails();
147 clock->Advance(base::TimeDelta::FromDays(1)); 163 clock->Advance(base::TimeDelta::FromDays(1));
148 GetBudgetDetails(); 164 GetBudgetDetails();
149 clock->Advance(base::TimeDelta::FromDays(1)); 165 clock->Advance(base::TimeDelta::FromDays(1));
150 GetBudgetDetails(); 166 GetBudgetDetails();
151 167
152 // Spend an amount of budget less than kDefaultEngagement. 168 // Spend an amount of budget less than kDefaultEngagement.
153 ASSERT_TRUE(SpendBudget(origin, 1)); 169 ASSERT_TRUE(SpendBudget(origin, 1));
154 GetBudgetDetails(); 170 GetBudgetDetails();
155 171
156 // There should still be three chunks of budget of size kDefaultEngagement-1, 172 // There should still be three chunks of budget of size kDefaultEngagement-1,
157 // kDefaultEngagement, and kDefaultEngagement. 173 // kDefaultEngagement, and kDefaultEngagement.
158 ASSERT_EQ(4U, prediction_.size()); 174 ASSERT_EQ(4U, prediction_.size());
159 ASSERT_DOUBLE_EQ(kDefaultEngagement * 5 / 3 - 1, prediction_[0].budget_at); 175 double daily_budget = kDefaultEngagement * 24 / kDefaultExpirationInHours;
160 ASSERT_DOUBLE_EQ(kDefaultEngagement * 2 / 3, prediction_[1].budget_at); 176 ASSERT_DOUBLE_EQ(kDefaultEngagement + 2 * daily_budget - 1,
161 ASSERT_DOUBLE_EQ(kDefaultEngagement * 1 / 3, prediction_[2].budget_at); 177 prediction_[0]->budget_at);
162 ASSERT_DOUBLE_EQ(0, prediction_[3].budget_at); 178 ASSERT_DOUBLE_EQ(daily_budget * 2, prediction_[1]->budget_at);
179 ASSERT_DOUBLE_EQ(daily_budget, prediction_[2]->budget_at);
180 ASSERT_DOUBLE_EQ(0, prediction_[3]->budget_at);
163 181
164 // Now spend enough that it will use up the rest of the first chunk and all of 182 // 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. 183 // the second chunk, but not all of the third chunk.
166 ASSERT_TRUE(SpendBudget(origin, kDefaultEngagement * 4 / 3)); 184 ASSERT_TRUE(SpendBudget(origin, kDefaultEngagement + daily_budget));
167 GetBudgetDetails(); 185 GetBudgetDetails();
168 ASSERT_EQ(2U, prediction_.size()); 186 ASSERT_EQ(2U, prediction_.size());
169 ASSERT_DOUBLE_EQ(kDefaultEngagement * 1 / 3 - 1, 187 ASSERT_DOUBLE_EQ(daily_budget - 1, prediction_[0]->budget_at);
170 prediction_.begin()->budget_at);
171 188
172 // Validate that the code returns false if SpendBudget tries to spend more 189 // Validate that the code returns false if SpendBudget tries to spend more
173 // budget than the origin has. 190 // budget than the origin has.
174 EXPECT_FALSE(SpendBudget(origin, kDefaultEngagement)); 191 EXPECT_FALSE(SpendBudget(origin, kDefaultEngagement));
175 GetBudgetDetails(); 192 GetBudgetDetails();
176 ASSERT_EQ(2U, prediction_.size()); 193 ASSERT_EQ(2U, prediction_.size());
177 ASSERT_DOUBLE_EQ(kDefaultEngagement * 1 / 3 - 1, 194 ASSERT_DOUBLE_EQ(daily_budget - 1, prediction_[0]->budget_at);
178 prediction_.begin()->budget_at);
179 195
180 // Advance time until the last remaining chunk should be expired, then query 196 // Advance time until the last remaining chunk should be expired, then query
181 // for the full engagement worth of budget. 197 // for the full engagement worth of budget.
182 clock->Advance(base::TimeDelta::FromDays(6)); 198 clock->Advance(base::TimeDelta::FromHours(kDefaultExpirationInHours + 1));
183 EXPECT_TRUE(SpendBudget(origin, kDefaultEngagement)); 199 EXPECT_TRUE(SpendBudget(origin, kDefaultEngagement));
184 } 200 }
201
202 // There are times when a device's clock could move backwards in time, either
203 // due to hardware issues or user actions. Test here to make sure that even if
204 // time goes backwards and then forwards again, the origin isn't granted extra
205 // budget.
206 TEST_F(BudgetDatabaseTest, GetBudgetNegativeTime) {
207 const GURL origin(kTestOrigin);
208 base::SimpleTestClock* clock = SetClockForTesting();
209
210 // Set the default site engagement.
211 SetSiteEngagementScore(origin, kDefaultEngagement);
212
213 // Initialize the budget with two chunks.
214 GetBudgetDetails();
215 clock->Advance(base::TimeDelta::FromDays(1));
216 GetBudgetDetails();
217
218 // Save off the budget total.
219 ASSERT_EQ(3U, prediction_.size());
220 double budget = prediction_[0]->budget_at;
221
222 // Move the clock backwards in time to before the budget awards.
223 clock->SetNow(clock->Now() - base::TimeDelta::FromDays(5));
224
225 // Make sure the budget is the same.
226 GetBudgetDetails();
227 ASSERT_EQ(3U, prediction_.size());
228 ASSERT_EQ(budget, prediction_[0]->budget_at);
229
230 // Now move the clock back to the original time and check that no extra budget
231 // is awarded.
232 clock->SetNow(clock->Now() + base::TimeDelta::FromDays(5));
233 GetBudgetDetails();
234 ASSERT_EQ(3U, prediction_.size());
235 ASSERT_EQ(budget, prediction_[0]->budget_at);
236 }
237
238 TEST_F(BudgetDatabaseTest, CheckBackgroundBudgetHistogram) {
239 const GURL origin(kTestOrigin);
240 base::SimpleTestClock* clock = SetClockForTesting();
241
242 // Set the default site engagement.
243 SetSiteEngagementScore(origin, kDefaultEngagement);
244
245 // Initialize the budget with some interesting chunks: 30 budget, 3 budget,
246 // 0 budget, and then after the first two expire, another 30 budget.
247 GetBudgetDetails();
248 clock->Advance(base::TimeDelta::FromDays(2));
249 GetBudgetDetails();
250 clock->Advance(base::TimeDelta::FromMinutes(59));
251 GetBudgetDetails();
252 clock->Advance(base::TimeDelta::FromDays(11));
253 GetBudgetDetails();
254
255 // The BackgroundBudget UMA is recorded when budget is added to the origin.
256 // This can happen a maximum of once per hour so there should be two entries.
257 std::vector<base::Bucket> buckets =
258 GetHistogramTester()->GetAllSamples("PushMessaging.BackgroundBudget");
259 ASSERT_EQ(2U, buckets.size());
260 // First bucket is for 30 budget, which should have 2 entries.
261 EXPECT_EQ(30, buckets[0].min);
262 EXPECT_EQ(2, buckets[0].count);
263 // Second bucket is for 36 budget, which should have 1 entry.
264 EXPECT_EQ(36, buckets[1].min);
265 EXPECT_EQ(1, buckets[1].count);
266 }
267
268 TEST_F(BudgetDatabaseTest, CheckEngagementHistograms) {
269 const GURL origin(kTestOrigin);
270 base::SimpleTestClock* clock = SetClockForTesting();
271
272 // Set the engagement to twice the cost of an action.
273 double cost = 2;
274 double engagement = cost * 2;
275 SetSiteEngagementScore(origin, engagement);
276
277 // Get the budget, which will award a chunk of budget equal to engagement.
278 GetBudgetDetails();
279
280 // Now spend the budget to trigger the UMA recording the SES score. The first
281 // call shouldn't write any UMA. The second should write a lowSES entry, and
282 // the third should write a noSES entry.
283 ASSERT_TRUE(SpendBudget(origin, cost));
284 ASSERT_TRUE(SpendBudget(origin, cost));
285 ASSERT_FALSE(SpendBudget(origin, cost));
286
287 // Advance the clock by 12 days (to guarantee a full new engagement grant)
288 // then change the SES score to get a different UMA entry, then spend the
289 // budget again.
290 clock->Advance(base::TimeDelta::FromDays(12));
291 GetBudgetDetails();
292 SetSiteEngagementScore(origin, engagement * 2);
293 ASSERT_TRUE(SpendBudget(origin, cost));
294 ASSERT_TRUE(SpendBudget(origin, cost));
295 ASSERT_FALSE(SpendBudget(origin, cost));
296
297 // Now check the UMA. Both UMA should have 2 buckets with 1 entry each.
298 std::vector<base::Bucket> no_budget_buckets =
299 GetHistogramTester()->GetAllSamples("PushMessaging.SESForNoBudgetOrigin");
300 ASSERT_EQ(2U, no_budget_buckets.size());
301 EXPECT_EQ(engagement, no_budget_buckets[0].min);
302 EXPECT_EQ(1, no_budget_buckets[0].count);
303 EXPECT_EQ(engagement * 2, no_budget_buckets[1].min);
304 EXPECT_EQ(1, no_budget_buckets[1].count);
305
306 std::vector<base::Bucket> low_budget_buckets =
307 GetHistogramTester()->GetAllSamples(
308 "PushMessaging.SESForLowBudgetOrigin");
309 ASSERT_EQ(2U, low_budget_buckets.size());
310 EXPECT_EQ(engagement, low_budget_buckets[0].min);
311 EXPECT_EQ(1, low_budget_buckets[0].count);
312 EXPECT_EQ(engagement * 2, low_budget_buckets[1].min);
313 EXPECT_EQ(1, low_budget_buckets[1].count);
314 }
OLDNEW
« no previous file with comments | « chrome/browser/budget_service/budget_database.cc ('k') | chrome/browser/budget_service/budget_manager.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698