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

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

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