1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include <set> 6 #include <utility> 7 #include <vector> 8 9 #include "base/message_loop/message_loop.h" 10 #include "base/strings/utf_string_conversions.h" 11 #include "chrome/browser/predictors/predictor_database.h" 12 #include "chrome/browser/predictors/resource_prefetch_predictor_tables.h" 13 #include "chrome/test/base/testing_profile.h" 14 #include "content/public/test/test_browser_thread.h" 15 #include "sql/statement.h" 16 #include "testing/gtest/include/gtest/gtest.h" 17 18 namespace predictors { 19 20 class ResourcePrefetchPredictorTablesTest : public testing::Test { 21 public: 22 ResourcePrefetchPredictorTablesTest(); 23 virtual ~ResourcePrefetchPredictorTablesTest(); 24 virtual void SetUp() OVERRIDE; 25 virtual void TearDown() OVERRIDE; 26 27 protected: 28 void TestGetAllData(); 29 void TestUpdateData(); 30 void TestDeleteData(); 31 void TestDeleteSingleDataPoint(); 32 void TestDeleteAllData(); 33 34 base::MessageLoop loop_; 35 content::TestBrowserThread db_thread_; 36 TestingProfile profile_; 37 scoped_ptr<PredictorDatabase> db_; 38 scoped_refptr<ResourcePrefetchPredictorTables> tables_; 39 40 private: 41 typedef ResourcePrefetchPredictorTables::ResourceRow ResourceRow; 42 typedef std::vector<ResourceRow> ResourceRows; 43 typedef ResourcePrefetchPredictorTables::PrefetchData PrefetchData; 44 typedef ResourcePrefetchPredictorTables::PrefetchDataMap PrefetchDataMap; 45 46 // Initializes the tables, |test_url_data_| and |test_host_data_|. 47 void InitializeSampleData(); 48 49 // Checks that the input PrefetchData are the same, although the resources 50 // can be in different order. 51 void TestPrefetchDataAreEqual(const PrefetchDataMap& lhs, 52 const PrefetchDataMap& rhs) const; 53 void TestResourceRowsAreEqual(const ResourceRows& lhs, 54 const ResourceRows& rhs) const; 55 56 void AddKey(PrefetchDataMap* m, const std::string& key) const; 57 58 // Useful for debugging test. 59 void PrintPrefetchData(const PrefetchData& data) const { 60 LOG(ERROR) << "[" << data.key_type << "," << data.primary_key 61 << "," << data.last_visit.ToInternalValue() << "]"; 62 for (ResourceRows::const_iterator it = data.resources.begin(); 63 it != data.resources.end(); ++it) { 64 LOG(ERROR) << "\t\t" << it->resource_url << "\t" << it->resource_type 65 << "\t" << it->number_of_hits << "\t" << it->number_of_misses 66 << "\t" << it->consecutive_misses 67 << "\t" << it->average_position 68 << "\t" << it->score; 69 } 70 } 71 72 PrefetchDataMap test_url_data_; 73 PrefetchDataMap test_host_data_; 74 }; 75 76 class ResourcePrefetchPredictorTablesReopenTest 77 : public ResourcePrefetchPredictorTablesTest { 78 public: 79 virtual void SetUp() OVERRIDE { 80 // Write data to the table, and then reopen the db. 81 ResourcePrefetchPredictorTablesTest::SetUp(); 82 ResourcePrefetchPredictorTablesTest::TearDown(); 83 84 db_.reset(new PredictorDatabase(&profile_)); 85 loop_.RunUntilIdle(); 86 tables_ = db_->resource_prefetch_tables(); 87 } 88 }; 89 90 ResourcePrefetchPredictorTablesTest::ResourcePrefetchPredictorTablesTest() 91 : loop_(base::MessageLoop::TYPE_DEFAULT), 92 db_thread_(content::BrowserThread::DB, &loop_), 93 db_(new PredictorDatabase(&profile_)), 94 tables_(db_->resource_prefetch_tables()) { 95 loop_.RunUntilIdle(); 96 } 97 98 ResourcePrefetchPredictorTablesTest::~ResourcePrefetchPredictorTablesTest() { 99 } 100 101 void ResourcePrefetchPredictorTablesTest::SetUp() { 102 tables_->DeleteAllData(); 103 InitializeSampleData(); 104 } 105 106 void ResourcePrefetchPredictorTablesTest::TearDown() { 107 tables_ = NULL; 108 db_.reset(); 109 loop_.RunUntilIdle(); 110 } 111 112 void ResourcePrefetchPredictorTablesTest::TestGetAllData() { 113 PrefetchDataMap actual_url_data, actual_host_data; 114 tables_->GetAllData(&actual_url_data, &actual_host_data); 115 116 TestPrefetchDataAreEqual(test_url_data_, actual_url_data); 117 TestPrefetchDataAreEqual(test_host_data_, actual_host_data); 118 } 119 120 void ResourcePrefetchPredictorTablesTest::TestDeleteData() { 121 std::vector<std::string> urls_to_delete, hosts_to_delete; 122 urls_to_delete.push_back("http://www.google.com"); 123 urls_to_delete.push_back("http://www.yahoo.com"); 124 hosts_to_delete.push_back("www.yahoo.com"); 125 126 tables_->DeleteData(urls_to_delete, hosts_to_delete); 127 128 PrefetchDataMap actual_url_data, actual_host_data; 129 tables_->GetAllData(&actual_url_data, &actual_host_data); 130 131 PrefetchDataMap expected_url_data, expected_host_data; 132 AddKey(&expected_url_data, "http://www.reddit.com"); 133 AddKey(&expected_host_data, "www.facebook.com"); 134 135 TestPrefetchDataAreEqual(expected_url_data, actual_url_data); 136 TestPrefetchDataAreEqual(expected_host_data, actual_host_data); 137 } 138 139 void ResourcePrefetchPredictorTablesTest::TestDeleteSingleDataPoint() { 140 // Delete a URL. 141 tables_->DeleteSingleDataPoint("http://www.reddit.com", 142 PREFETCH_KEY_TYPE_URL); 143 144 PrefetchDataMap actual_url_data, actual_host_data; 145 tables_->GetAllData(&actual_url_data, &actual_host_data); 146 147 PrefetchDataMap expected_url_data; 148 AddKey(&expected_url_data, "http://www.google.com"); 149 AddKey(&expected_url_data, "http://www.yahoo.com"); 150 151 TestPrefetchDataAreEqual(expected_url_data, actual_url_data); 152 TestPrefetchDataAreEqual(test_host_data_, actual_host_data); 153 154 // Delete a host. 155 tables_->DeleteSingleDataPoint("www.facebook.com", PREFETCH_KEY_TYPE_HOST); 156 actual_url_data.clear(); 157 actual_host_data.clear(); 158 tables_->GetAllData(&actual_url_data, &actual_host_data); 159 160 PrefetchDataMap expected_host_data; 161 AddKey(&expected_host_data, "www.yahoo.com"); 162 163 TestPrefetchDataAreEqual(expected_url_data, actual_url_data); 164 TestPrefetchDataAreEqual(expected_host_data, actual_host_data); 165 } 166 167 void ResourcePrefetchPredictorTablesTest::TestUpdateData() { 168 PrefetchData google(PREFETCH_KEY_TYPE_URL, "http://www.google.com"); 169 google.last_visit = base::Time::FromInternalValue(10); 170 google.resources.push_back(ResourceRow(std::string(), 171 "http://www.google.com/style.css", 172 content::RESOURCE_TYPE_STYLESHEET, 173 6, 174 2, 175 0, 176 1.0)); 177 google.resources.push_back(ResourceRow(std::string(), 178 "http://www.google.com/image.png", 179 content::RESOURCE_TYPE_IMAGE, 180 6, 181 4, 182 1, 183 4.2)); 184 google.resources.push_back(ResourceRow(std::string(), 185 "http://www.google.com/a.xml", 186 content::RESOURCE_TYPE_LAST_TYPE, 187 1, 188 0, 189 0, 190 6.1)); 191 google.resources 192 .push_back(ResourceRow(std::string(), 193 "http://www.resources.google.com/script.js", 194 content::RESOURCE_TYPE_SCRIPT, 195 12, 196 0, 197 0, 198 8.5)); 199 200 PrefetchData yahoo(PREFETCH_KEY_TYPE_HOST, "www.yahoo.com"); 201 yahoo.last_visit = base::Time::FromInternalValue(7); 202 yahoo.resources.push_back(ResourceRow(std::string(), 203 "http://www.yahoo.com/image.png", 204 content::RESOURCE_TYPE_IMAGE, 205 120, 206 1, 207 1, 208 10.0)); 209 210 tables_->UpdateData(google, yahoo); 211 212 PrefetchDataMap actual_url_data, actual_host_data; 213 tables_->GetAllData(&actual_url_data, &actual_host_data); 214 215 PrefetchDataMap expected_url_data, expected_host_data; 216 AddKey(&expected_url_data, "http://www.reddit.com"); 217 AddKey(&expected_url_data, "http://www.yahoo.com"); 218 expected_url_data.insert(std::make_pair("http://www.google.com", google)); 219 220 AddKey(&expected_host_data, "www.facebook.com"); 221 expected_host_data.insert(std::make_pair("www.yahoo.com", yahoo)); 222 223 TestPrefetchDataAreEqual(expected_url_data, actual_url_data); 224 TestPrefetchDataAreEqual(expected_host_data, actual_host_data); 225 } 226 227 void ResourcePrefetchPredictorTablesTest::TestDeleteAllData() { 228 tables_->DeleteAllData(); 229 230 PrefetchDataMap actual_url_data, actual_host_data; 231 tables_->GetAllData(&actual_url_data, &actual_host_data); 232 EXPECT_TRUE(actual_url_data.empty()); 233 EXPECT_TRUE(actual_host_data.empty()); 234 } 235 236 void ResourcePrefetchPredictorTablesTest::TestPrefetchDataAreEqual( 237 const PrefetchDataMap& lhs, 238 const PrefetchDataMap& rhs) const { 239 EXPECT_EQ(lhs.size(), rhs.size()); 240 241 for (PrefetchDataMap::const_iterator rhs_it = rhs.begin(); 242 rhs_it != rhs.end(); ++rhs_it) { 243 PrefetchDataMap::const_iterator lhs_it = lhs.find(rhs_it->first); 244 ASSERT_TRUE(lhs_it != lhs.end()) << rhs_it->first; 245 246 TestResourceRowsAreEqual(lhs_it->second.resources, 247 rhs_it->second.resources); 248 } 249 } 250 251 void ResourcePrefetchPredictorTablesTest::TestResourceRowsAreEqual( 252 const ResourceRows& lhs, 253 const ResourceRows& rhs) const { 254 EXPECT_EQ(lhs.size(), rhs.size()); 255 256 std::set<GURL> resources_seen; 257 for (ResourceRows::const_iterator rhs_it = rhs.begin(); 258 rhs_it != rhs.end(); ++rhs_it) { 259 const GURL& resource = rhs_it->resource_url; 260 EXPECT_FALSE(ContainsKey(resources_seen, resource)); 261 262 for (ResourceRows::const_iterator lhs_it = lhs.begin(); 263 lhs_it != lhs.end(); ++lhs_it) { 264 if (*rhs_it == *lhs_it) { 265 resources_seen.insert(resource); 266 break; 267 } 268 } 269 EXPECT_TRUE(ContainsKey(resources_seen, resource)); 270 } 271 EXPECT_EQ(lhs.size(), resources_seen.size()); 272 } 273 274 void ResourcePrefetchPredictorTablesTest::AddKey(PrefetchDataMap* m, 275 const std::string& key) const { 276 PrefetchDataMap::const_iterator it = test_url_data_.find(key); 277 if (it != test_url_data_.end()) { 278 m->insert(std::make_pair(it->first, it->second)); 279 return; 280 } 281 it = test_host_data_.find(key); 282 ASSERT_TRUE(it != test_host_data_.end()); 283 m->insert(std::make_pair(it->first, it->second)); 284 } 285 286 void ResourcePrefetchPredictorTablesTest::InitializeSampleData() { 287 { // Url data. 288 PrefetchData google(PREFETCH_KEY_TYPE_URL, "http://www.google.com"); 289 google.last_visit = base::Time::FromInternalValue(1); 290 google.resources.push_back(ResourceRow(std::string(), 291 "http://www.google.com/style.css", 292 content::RESOURCE_TYPE_STYLESHEET, 293 5, 294 2, 295 1, 296 1.1)); 297 google.resources.push_back(ResourceRow(std::string(), 298 "http://www.google.com/script.js", 299 content::RESOURCE_TYPE_SCRIPT, 300 4, 301 0, 302 1, 303 2.1)); 304 google.resources.push_back(ResourceRow(std::string(), 305 "http://www.google.com/image.png", 306 content::RESOURCE_TYPE_IMAGE, 307 6, 308 3, 309 0, 310 2.2)); 311 google.resources.push_back(ResourceRow(std::string(), 312 "http://www.google.com/a.font", 313 content::RESOURCE_TYPE_LAST_TYPE, 314 2, 315 0, 316 0, 317 5.1)); 318 google.resources 319 .push_back(ResourceRow(std::string(), 320 "http://www.resources.google.com/script.js", 321 content::RESOURCE_TYPE_SCRIPT, 322 11, 323 0, 324 0, 325 8.5)); 326 327 PrefetchData reddit(PREFETCH_KEY_TYPE_URL, "http://www.reddit.com"); 328 reddit.last_visit = base::Time::FromInternalValue(2); 329 reddit.resources 330 .push_back(ResourceRow(std::string(), 331 "http://reddit-resource.com/script1.js", 332 content::RESOURCE_TYPE_SCRIPT, 333 4, 334 0, 335 1, 336 1.0)); 337 reddit.resources 338 .push_back(ResourceRow(std::string(), 339 "http://reddit-resource.com/script2.js", 340 content::RESOURCE_TYPE_SCRIPT, 341 2, 342 0, 343 0, 344 2.1)); 345 346 PrefetchData yahoo(PREFETCH_KEY_TYPE_URL, "http://www.yahoo.com"); 347 yahoo.last_visit = base::Time::FromInternalValue(3); 348 yahoo.resources.push_back(ResourceRow(std::string(), 349 "http://www.google.com/image.png", 350 content::RESOURCE_TYPE_IMAGE, 351 20, 352 1, 353 0, 354 10.0)); 355 356 test_url_data_.clear(); 357 test_url_data_.insert(std::make_pair("http://www.google.com", google)); 358 test_url_data_.insert(std::make_pair("http://www.reddit.com", reddit)); 359 test_url_data_.insert(std::make_pair("http://www.yahoo.com", yahoo)); 360 361 PrefetchData empty_host_data(PREFETCH_KEY_TYPE_HOST, std::string()); 362 tables_->UpdateData(google, empty_host_data); 363 tables_->UpdateData(reddit, empty_host_data); 364 tables_->UpdateData(yahoo, empty_host_data); 365 } 366 367 { // Host data. 368 PrefetchData facebook(PREFETCH_KEY_TYPE_HOST, "www.facebook.com"); 369 facebook.last_visit = base::Time::FromInternalValue(4); 370 facebook.resources 371 .push_back(ResourceRow(std::string(), 372 "http://www.facebook.com/style.css", 373 content::RESOURCE_TYPE_STYLESHEET, 374 5, 375 2, 376 1, 377 1.1)); 378 facebook.resources 379 .push_back(ResourceRow(std::string(), 380 "http://www.facebook.com/script.js", 381 content::RESOURCE_TYPE_SCRIPT, 382 4, 383 0, 384 1, 385 2.1)); 386 facebook.resources 387 .push_back(ResourceRow(std::string(), 388 "http://www.facebook.com/image.png", 389 content::RESOURCE_TYPE_IMAGE, 390 6, 391 3, 392 0, 393 2.2)); 394 facebook.resources.push_back(ResourceRow(std::string(), 395 "http://www.facebook.com/a.font", 396 content::RESOURCE_TYPE_LAST_TYPE, 397 2, 398 0, 399 0, 400 5.1)); 401 facebook.resources 402 .push_back(ResourceRow(std::string(), 403 "http://www.resources.facebook.com/script.js", 404 content::RESOURCE_TYPE_SCRIPT, 405 11, 406 0, 407 0, 408 8.5)); 409 410 PrefetchData yahoo(PREFETCH_KEY_TYPE_HOST, "www.yahoo.com"); 411 yahoo.last_visit = base::Time::FromInternalValue(5); 412 yahoo.resources.push_back(ResourceRow(std::string(), 413 "http://www.google.com/image.png", 414 content::RESOURCE_TYPE_IMAGE, 415 20, 416 1, 417 0, 418 10.0)); 419 420 test_host_data_.clear(); 421 test_host_data_.insert(std::make_pair("www.facebook.com", facebook)); 422 test_host_data_.insert(std::make_pair("www.yahoo.com", yahoo)); 423 424 PrefetchData empty_url_data(PREFETCH_KEY_TYPE_URL, std::string()); 425 tables_->UpdateData(empty_url_data, facebook); 426 tables_->UpdateData(empty_url_data, yahoo); 427 } 428 } 429 430 // Test cases. 431 432 TEST_F(ResourcePrefetchPredictorTablesTest, GetAllData) { 433 TestGetAllData(); 434 } 435 436 TEST_F(ResourcePrefetchPredictorTablesTest, UpdateData) { 437 TestUpdateData(); 438 } 439 440 TEST_F(ResourcePrefetchPredictorTablesTest, DeleteData) { 441 TestDeleteData(); 442 } 443 444 TEST_F(ResourcePrefetchPredictorTablesTest, DeleteSingleDataPoint) { 445 TestDeleteSingleDataPoint(); 446 } 447 448 TEST_F(ResourcePrefetchPredictorTablesTest, DeleteAllData) { 449 TestDeleteAllData(); 450 } 451 452 TEST_F(ResourcePrefetchPredictorTablesReopenTest, GetAllData) { 453 TestGetAllData(); 454 } 455 456 TEST_F(ResourcePrefetchPredictorTablesReopenTest, UpdateData) { 457 TestUpdateData(); 458 } 459 460 TEST_F(ResourcePrefetchPredictorTablesReopenTest, DeleteData) { 461 TestDeleteData(); 462 } 463 464 TEST_F(ResourcePrefetchPredictorTablesReopenTest, DeleteSingleDataPoint) { 465 TestDeleteSingleDataPoint(); 466 } 467 468 TEST_F(ResourcePrefetchPredictorTablesReopenTest, DeleteAllData) { 469 TestDeleteAllData(); 470 } 471 472 } // namespace predictors 473