1 // Copyright 2013 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 "base/cancelable_callback.h" 6 #include "base/command_line.h" 7 #include "base/memory/scoped_ptr.h" 8 #include "base/run_loop.h" 9 #include "base/strings/string_split.h" 10 #include "base/strings/stringprintf.h" 11 #include "base/synchronization/waitable_event.h" 12 #include "base/test/simple_test_clock.h" 13 #include "base/test/test_timeouts.h" 14 #include "chrome/browser/extensions/activity_log/activity_log.h" 15 #include "chrome/browser/extensions/activity_log/counting_policy.h" 16 #include "chrome/browser/extensions/extension_service.h" 17 #include "chrome/browser/extensions/test_extension_system.h" 18 #include "chrome/common/chrome_constants.h" 19 #include "chrome/common/chrome_switches.h" 20 #include "chrome/test/base/chrome_render_view_host_test_harness.h" 21 #include "chrome/test/base/testing_profile.h" 22 #include "content/public/test/test_browser_thread_bundle.h" 23 #include "extensions/common/extension_builder.h" 24 #include "sql/statement.h" 25 #include "testing/gtest/include/gtest/gtest.h" 26 27 #if defined(OS_CHROMEOS) 28 #include "chrome/browser/chromeos/login/users/user_manager.h" 29 #include "chrome/browser/chromeos/settings/cros_settings.h" 30 #include "chrome/browser/chromeos/settings/device_settings_service.h" 31 #endif 32 33 using content::BrowserThread; 34 35 namespace extensions { 36 37 class CountingPolicyTest : public testing::Test { 38 public: 39 CountingPolicyTest() 40 : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP), 41 saved_cmdline_(CommandLine::NO_PROGRAM) { 42 #if defined OS_CHROMEOS 43 test_user_manager_.reset(new chromeos::ScopedTestUserManager()); 44 #endif 45 CommandLine command_line(CommandLine::NO_PROGRAM); 46 saved_cmdline_ = *CommandLine::ForCurrentProcess(); 47 profile_.reset(new TestingProfile()); 48 CommandLine::ForCurrentProcess()->AppendSwitch( 49 switches::kEnableExtensionActivityLogging); 50 extension_service_ = static_cast<TestExtensionSystem*>( 51 ExtensionSystem::Get(profile_.get()))->CreateExtensionService 52 (&command_line, base::FilePath(), false); 53 } 54 55 virtual ~CountingPolicyTest() { 56 #if defined OS_CHROMEOS 57 test_user_manager_.reset(); 58 #endif 59 base::RunLoop().RunUntilIdle(); 60 profile_.reset(NULL); 61 base::RunLoop().RunUntilIdle(); 62 // Restore the original command line and undo the affects of SetUp(). 63 *CommandLine::ForCurrentProcess() = saved_cmdline_; 64 } 65 66 // Wait for the task queue for the specified thread to empty. 67 void WaitOnThread(const BrowserThread::ID& thread) { 68 BrowserThread::PostTaskAndReply( 69 thread, 70 FROM_HERE, 71 base::Bind(&base::DoNothing), 72 base::MessageLoop::current()->QuitClosure()); 73 base::MessageLoop::current()->Run(); 74 } 75 76 // A wrapper function for CheckReadFilteredData, so that we don't need to 77 // enter empty string values for parameters we don't care about. 78 void CheckReadData( 79 ActivityLogDatabasePolicy* policy, 80 const std::string& extension_id, 81 int day, 82 const base::Callback<void(scoped_ptr<Action::ActionVector>)>& checker) { 83 CheckReadFilteredData( 84 policy, extension_id, Action::ACTION_ANY, "", "", "", day, checker); 85 } 86 87 // A helper function to call ReadFilteredData on a policy object and wait for 88 // the results to be processed. 89 void CheckReadFilteredData( 90 ActivityLogDatabasePolicy* policy, 91 const std::string& extension_id, 92 const Action::ActionType type, 93 const std::string& api_name, 94 const std::string& page_url, 95 const std::string& arg_url, 96 int day, 97 const base::Callback<void(scoped_ptr<Action::ActionVector>)>& checker) { 98 // Submit a request to the policy to read back some data, and call the 99 // checker function when results are available. This will happen on the 100 // database thread. 101 policy->ReadFilteredData( 102 extension_id, 103 type, 104 api_name, 105 page_url, 106 arg_url, 107 day, 108 base::Bind(&CountingPolicyTest::CheckWrapper, 109 checker, 110 base::MessageLoop::current()->QuitClosure())); 111 112 // Set up a timeout for receiving results; if we haven't received anything 113 // when the timeout triggers then assume that the test is broken. 114 base::CancelableClosure timeout( 115 base::Bind(&CountingPolicyTest::TimeoutCallback)); 116 base::MessageLoop::current()->PostDelayedTask( 117 FROM_HERE, timeout.callback(), TestTimeouts::action_timeout()); 118 119 // Wait for results; either the checker or the timeout callbacks should 120 // cause the main loop to exit. 121 base::MessageLoop::current()->Run(); 122 123 timeout.Cancel(); 124 } 125 126 // A helper function which verifies that the string_ids and url_ids tables in 127 // the database have the specified sizes. 128 static void CheckStringTableSizes(CountingPolicy* policy, 129 int string_size, 130 int url_size) { 131 sql::Connection* db = policy->GetDatabaseConnection(); 132 sql::Statement statement1(db->GetCachedStatement( 133 sql::StatementID(SQL_FROM_HERE), "SELECT COUNT(*) FROM string_ids")); 134 ASSERT_TRUE(statement1.Step()); 135 ASSERT_EQ(string_size, statement1.ColumnInt(0)); 136 137 sql::Statement statement2(db->GetCachedStatement( 138 sql::StatementID(SQL_FROM_HERE), "SELECT COUNT(*) FROM url_ids")); 139 ASSERT_TRUE(statement2.Step()); 140 ASSERT_EQ(url_size, statement2.ColumnInt(0)); 141 } 142 143 // Checks that the number of queued actions to be written out does not exceed 144 // kSizeThresholdForFlush. Runs on the database thread. 145 static void CheckQueueSize(CountingPolicy* policy) { 146 // This should be updated if kSizeThresholdForFlush in activity_database.cc 147 // changes. 148 ASSERT_LE(policy->queued_actions_.size(), 200U); 149 } 150 151 static void CheckWrapper( 152 const base::Callback<void(scoped_ptr<Action::ActionVector>)>& checker, 153 const base::Closure& done, 154 scoped_ptr<Action::ActionVector> results) { 155 checker.Run(results.Pass()); 156 done.Run(); 157 } 158 159 static void TimeoutCallback() { 160 base::MessageLoop::current()->QuitWhenIdle(); 161 FAIL() << "Policy test timed out waiting for results"; 162 } 163 164 static void RetrieveActions_FetchFilteredActions0( 165 scoped_ptr<std::vector<scoped_refptr<Action> > > i) { 166 ASSERT_EQ(0, static_cast<int>(i->size())); 167 } 168 169 static void RetrieveActions_FetchFilteredActions1( 170 scoped_ptr<std::vector<scoped_refptr<Action> > > i) { 171 ASSERT_EQ(1, static_cast<int>(i->size())); 172 } 173 174 static void RetrieveActions_FetchFilteredActions2( 175 scoped_ptr<std::vector<scoped_refptr<Action> > > i) { 176 ASSERT_EQ(2, static_cast<int>(i->size())); 177 } 178 179 static void RetrieveActions_FetchFilteredActions300( 180 scoped_ptr<std::vector<scoped_refptr<Action> > > i) { 181 ASSERT_EQ(300, static_cast<int>(i->size())); 182 } 183 184 static void Arguments_Stripped(scoped_ptr<Action::ActionVector> i) { 185 scoped_refptr<Action> last = i->front(); 186 CheckAction(*last, "odlameecjipmbmbejkplpemijjgpljce", 187 Action::ACTION_API_CALL, "extension.connect", 188 "[\"hello\",\"world\"]", "", "", "", 1); 189 } 190 191 static void Arguments_GetSinglesAction( 192 scoped_ptr<Action::ActionVector> actions) { 193 ASSERT_EQ(1, static_cast<int>(actions->size())); 194 CheckAction(*actions->at(0), "punky", Action::ACTION_DOM_ACCESS, "lets", 195 "", "http://www.google.com/", "", "", 1); 196 } 197 198 static void Arguments_GetTodaysActions( 199 scoped_ptr<Action::ActionVector> actions) { 200 ASSERT_EQ(3, static_cast<int>(actions->size())); 201 CheckAction(*actions->at(0), "punky", Action::ACTION_API_CALL, "brewster", 202 "", "", "", "", 2); 203 CheckAction(*actions->at(1), "punky", Action::ACTION_DOM_ACCESS, "lets", 204 "", "http://www.google.com/", "", "", 1); 205 CheckAction(*actions->at(2), "punky", Action::ACTION_API_CALL, 206 "extension.sendMessage", "[\"not\",\"stripped\"]", "", "", "", 207 1); 208 } 209 210 static void Arguments_GetOlderActions( 211 scoped_ptr<Action::ActionVector> actions) { 212 ASSERT_EQ(2, static_cast<int>(actions->size())); 213 CheckAction(*actions->at(0), "punky", Action::ACTION_DOM_ACCESS, "lets", 214 "", "http://www.google.com/", "", "", 1); 215 CheckAction(*actions->at(1), "punky", Action::ACTION_API_CALL, "brewster", 216 "", "", "", "", 1); 217 } 218 219 static void Arguments_CheckMergeCount( 220 int count, 221 scoped_ptr<Action::ActionVector> actions) { 222 if (count > 0) { 223 ASSERT_EQ(1u, actions->size()); 224 CheckAction(*actions->at(0), "punky", Action::ACTION_API_CALL, "brewster", 225 "", "", "", "", count); 226 } else { 227 ASSERT_EQ(0u, actions->size()); 228 } 229 } 230 231 static void Arguments_CheckMergeCountAndTime( 232 int count, 233 const base::Time& time, 234 scoped_ptr<Action::ActionVector> actions) { 235 if (count > 0) { 236 ASSERT_EQ(1u, actions->size()); 237 CheckAction(*actions->at(0), "punky", Action::ACTION_API_CALL, "brewster", 238 "", "", "", "", count); 239 ASSERT_EQ(time, actions->at(0)->time()); 240 } else { 241 ASSERT_EQ(0u, actions->size()); 242 } 243 } 244 245 static void AllURLsRemoved(scoped_ptr<Action::ActionVector> actions) { 246 ASSERT_EQ(2, static_cast<int>(actions->size())); 247 CheckAction(*actions->at(0), "punky", Action::ACTION_DOM_ACCESS, "lets", 248 "", "", "", "", 1); 249 CheckAction(*actions->at(1), "punky", Action::ACTION_DOM_ACCESS, "lets", 250 "", "", "", "", 1); 251 } 252 253 static void SomeURLsRemoved(scoped_ptr<Action::ActionVector> actions) { 254 // These will be in the vector in reverse time order. 255 ASSERT_EQ(5, static_cast<int>(actions->size())); 256 CheckAction(*actions->at(0), "punky", Action::ACTION_DOM_ACCESS, "lets", 257 "", "http://www.google.com/", "Google", 258 "http://www.args-url.com/", 1); 259 CheckAction(*actions->at(1), "punky", Action::ACTION_DOM_ACCESS, "lets", 260 "", "http://www.google.com/", "Google", "", 1); 261 CheckAction(*actions->at(2), "punky", Action::ACTION_DOM_ACCESS, "lets", 262 "", "", "", "", 1); 263 CheckAction(*actions->at(3), "punky", Action::ACTION_DOM_ACCESS, "lets", 264 "", "", "", "http://www.google.com/", 1); 265 CheckAction(*actions->at(4), "punky", Action::ACTION_DOM_ACCESS, "lets", 266 "", "", "", "", 1); 267 } 268 269 static void CheckDuplicates(scoped_ptr<Action::ActionVector> actions) { 270 ASSERT_EQ(2u, actions->size()); 271 int total_count = 0; 272 for (size_t i = 0; i < actions->size(); i++) { 273 total_count += actions->at(i)->count(); 274 } 275 ASSERT_EQ(3, total_count); 276 } 277 278 static void CheckAction(const Action& action, 279 const std::string& expected_id, 280 const Action::ActionType& expected_type, 281 const std::string& expected_api_name, 282 const std::string& expected_args_str, 283 const std::string& expected_page_url, 284 const std::string& expected_page_title, 285 const std::string& expected_arg_url, 286 int expected_count) { 287 ASSERT_EQ(expected_id, action.extension_id()); 288 ASSERT_EQ(expected_type, action.action_type()); 289 ASSERT_EQ(expected_api_name, action.api_name()); 290 ASSERT_EQ(expected_args_str, 291 ActivityLogPolicy::Util::Serialize(action.args())); 292 ASSERT_EQ(expected_page_url, action.SerializePageUrl()); 293 ASSERT_EQ(expected_page_title, action.page_title()); 294 ASSERT_EQ(expected_arg_url, action.SerializeArgUrl()); 295 ASSERT_EQ(expected_count, action.count()); 296 ASSERT_NE(-1, action.action_id()); 297 } 298 299 // A helper function initializes the policy with a number of actions, calls 300 // RemoveActions on a policy object and then checks the result of the 301 // deletion. 302 void CheckRemoveActions( 303 ActivityLogDatabasePolicy* policy, 304 const std::vector<int64>& action_ids, 305 const base::Callback<void(scoped_ptr<Action::ActionVector>)>& checker) { 306 307 // Use a mock clock to ensure that events are not recorded on the wrong day 308 // when the test is run close to local midnight. 309 base::SimpleTestClock* mock_clock = new base::SimpleTestClock(); 310 mock_clock->SetNow(base::Time::Now().LocalMidnight() + 311 base::TimeDelta::FromHours(12)); 312 policy->SetClockForTesting(scoped_ptr<base::Clock>(mock_clock)); 313 314 // Record some actions 315 scoped_refptr<Action> action = 316 new Action("punky1", 317 mock_clock->Now() - base::TimeDelta::FromMinutes(40), 318 Action::ACTION_DOM_ACCESS, 319 "lets1"); 320 action->mutable_args()->AppendString("vamoose1"); 321 action->set_page_url(GURL("http://www.google1.com")); 322 action->set_page_title("Google1"); 323 action->set_arg_url(GURL("http://www.args-url1.com")); 324 policy->ProcessAction(action); 325 // Record the same action twice, so there are multiple entries in the 326 // database. 327 policy->ProcessAction(action); 328 329 action = new Action("punky2", 330 mock_clock->Now() - base::TimeDelta::FromMinutes(30), 331 Action::ACTION_API_CALL, 332 "lets2"); 333 action->mutable_args()->AppendString("vamoose2"); 334 action->set_page_url(GURL("http://www.google2.com")); 335 action->set_page_title("Google2"); 336 action->set_arg_url(GURL("http://www.args-url2.com")); 337 policy->ProcessAction(action); 338 // Record the same action twice, so there are multiple entries in the 339 // database. 340 policy->ProcessAction(action); 341 342 // Submit a request to delete actions. 343 policy->RemoveActions(action_ids); 344 345 // Check the result of the deletion. The checker function gets all 346 // activities in the database. 347 CheckReadData(policy, "", -1, checker); 348 349 // Clean database. 350 policy->DeleteDatabase(); 351 } 352 353 static void AllActionsDeleted(scoped_ptr<Action::ActionVector> actions) { 354 ASSERT_EQ(0, static_cast<int>(actions->size())); 355 } 356 357 static void NoActionsDeleted(scoped_ptr<Action::ActionVector> actions) { 358 // These will be in the vector in reverse time order. 359 ASSERT_EQ(2, static_cast<int>(actions->size())); 360 CheckAction(*actions->at(0), 361 "punky2", 362 Action::ACTION_API_CALL, 363 "lets2", 364 "", 365 "http://www.google2.com/", 366 "Google2", 367 "http://www.args-url2.com/", 368 2); 369 ASSERT_EQ(2, actions->at(0)->action_id()); 370 CheckAction(*actions->at(1), 371 "punky1", 372 Action::ACTION_DOM_ACCESS, 373 "lets1", 374 "", 375 "http://www.google1.com/", 376 "Google1", 377 "http://www.args-url1.com/", 378 2); 379 ASSERT_EQ(1, actions->at(1)->action_id()); 380 } 381 382 static void Action1Deleted(scoped_ptr<Action::ActionVector> actions) { 383 // These will be in the vector in reverse time order. 384 ASSERT_EQ(1, static_cast<int>(actions->size())); 385 CheckAction(*actions->at(0), 386 "punky2", 387 Action::ACTION_API_CALL, 388 "lets2", 389 "", 390 "http://www.google2.com/", 391 "Google2", 392 "http://www.args-url2.com/", 393 2); 394 ASSERT_EQ(2, actions->at(0)->action_id()); 395 } 396 397 static void Action2Deleted(scoped_ptr<Action::ActionVector> actions) { 398 // These will be in the vector in reverse time order. 399 ASSERT_EQ(1, static_cast<int>(actions->size())); 400 CheckAction(*actions->at(0), 401 "punky1", 402 Action::ACTION_DOM_ACCESS, 403 "lets1", 404 "", 405 "http://www.google1.com/", 406 "Google1", 407 "http://www.args-url1.com/", 408 2); 409 ASSERT_EQ(1, actions->at(0)->action_id()); 410 } 411 412 protected: 413 ExtensionService* extension_service_; 414 scoped_ptr<TestingProfile> profile_; 415 content::TestBrowserThreadBundle thread_bundle_; 416 // Used to preserve a copy of the original command line. 417 // The test framework will do this itself as well. However, by then, 418 // it is too late to call ActivityLog::RecomputeLoggingIsEnabled() in 419 // TearDown(). 420 CommandLine saved_cmdline_; 421 422 #if defined OS_CHROMEOS 423 chromeos::ScopedTestDeviceSettingsService test_device_settings_service_; 424 chromeos::ScopedTestCrosSettings test_cros_settings_; 425 scoped_ptr<chromeos::ScopedTestUserManager> test_user_manager_; 426 #endif 427 }; 428 429 TEST_F(CountingPolicyTest, Construct) { 430 ActivityLogDatabasePolicy* policy = new CountingPolicy(profile_.get()); 431 policy->Init(); 432 scoped_refptr<const Extension> extension = 433 ExtensionBuilder() 434 .SetManifest(DictionaryBuilder() 435 .Set("name", "Test extension") 436 .Set("version", "1.0.0") 437 .Set("manifest_version", 2)) 438 .Build(); 439 extension_service_->AddExtension(extension.get()); 440 scoped_ptr<base::ListValue> args(new base::ListValue()); 441 scoped_refptr<Action> action = new Action(extension->id(), 442 base::Time::Now(), 443 Action::ACTION_API_CALL, 444 "tabs.testMethod"); 445 action->set_args(args.Pass()); 446 policy->ProcessAction(action); 447 policy->Close(); 448 } 449 450 TEST_F(CountingPolicyTest, LogWithStrippedArguments) { 451 ActivityLogDatabasePolicy* policy = new CountingPolicy(profile_.get()); 452 policy->Init(); 453 scoped_refptr<const Extension> extension = 454 ExtensionBuilder() 455 .SetManifest(DictionaryBuilder() 456 .Set("name", "Test extension") 457 .Set("version", "1.0.0") 458 .Set("manifest_version", 2)) 459 .Build(); 460 extension_service_->AddExtension(extension.get()); 461 462 scoped_ptr<base::ListValue> args(new base::ListValue()); 463 args->Set(0, new base::StringValue("hello")); 464 args->Set(1, new base::StringValue("world")); 465 scoped_refptr<Action> action = new Action(extension->id(), 466 base::Time::Now(), 467 Action::ACTION_API_CALL, 468 "extension.connect"); 469 action->set_args(args.Pass()); 470 471 policy->ProcessAction(action); 472 CheckReadData(policy, 473 extension->id(), 474 0, 475 base::Bind(&CountingPolicyTest::Arguments_Stripped)); 476 policy->Close(); 477 } 478 479 TEST_F(CountingPolicyTest, GetTodaysActions) { 480 CountingPolicy* policy = new CountingPolicy(profile_.get()); 481 policy->Init(); 482 // Disable row expiration for this test by setting a time before any actions 483 // we generate. 484 policy->set_retention_time(base::TimeDelta::FromDays(14)); 485 486 // Use a mock clock to ensure that events are not recorded on the wrong day 487 // when the test is run close to local midnight. Note: Ownership is passed 488 // to the policy, but we still keep a pointer locally. The policy will take 489 // care of destruction; this is safe since the policy outlives all our 490 // accesses to the mock clock. 491 base::SimpleTestClock* mock_clock = new base::SimpleTestClock(); 492 mock_clock->SetNow(base::Time::Now().LocalMidnight() + 493 base::TimeDelta::FromHours(12)); 494 policy->SetClockForTesting(scoped_ptr<base::Clock>(mock_clock)); 495 496 // Record some actions 497 scoped_refptr<Action> action = 498 new Action("punky", 499 mock_clock->Now() - base::TimeDelta::FromMinutes(40), 500 Action::ACTION_API_CALL, 501 "brewster"); 502 action->mutable_args()->AppendString("woof"); 503 policy->ProcessAction(action); 504 505 action = new Action("punky", 506 mock_clock->Now() - base::TimeDelta::FromMinutes(30), 507 Action::ACTION_API_CALL, 508 "brewster"); 509 action->mutable_args()->AppendString("meow"); 510 policy->ProcessAction(action); 511 512 action = new Action("punky", 513 mock_clock->Now() - base::TimeDelta::FromMinutes(20), 514 Action::ACTION_API_CALL, 515 "extension.sendMessage"); 516 action->mutable_args()->AppendString("not"); 517 action->mutable_args()->AppendString("stripped"); 518 policy->ProcessAction(action); 519 520 action = 521 new Action("punky", mock_clock->Now(), Action::ACTION_DOM_ACCESS, "lets"); 522 action->mutable_args()->AppendString("vamoose"); 523 action->set_page_url(GURL("http://www.google.com")); 524 policy->ProcessAction(action); 525 526 action = new Action( 527 "scoobydoo", mock_clock->Now(), Action::ACTION_DOM_ACCESS, "lets"); 528 action->mutable_args()->AppendString("vamoose"); 529 action->set_page_url(GURL("http://www.google.com")); 530 policy->ProcessAction(action); 531 532 CheckReadData( 533 policy, 534 "punky", 535 0, 536 base::Bind(&CountingPolicyTest::Arguments_GetTodaysActions)); 537 policy->Close(); 538 } 539 540 // Check that we can read back less recent actions in the db. 541 TEST_F(CountingPolicyTest, GetOlderActions) { 542 CountingPolicy* policy = new CountingPolicy(profile_.get()); 543 policy->Init(); 544 policy->set_retention_time(base::TimeDelta::FromDays(14)); 545 546 // Use a mock clock to ensure that events are not recorded on the wrong day 547 // when the test is run close to local midnight. 548 base::SimpleTestClock* mock_clock = new base::SimpleTestClock(); 549 mock_clock->SetNow(base::Time::Now().LocalMidnight() + 550 base::TimeDelta::FromHours(12)); 551 policy->SetClockForTesting(scoped_ptr<base::Clock>(mock_clock)); 552 553 // Record some actions 554 scoped_refptr<Action> action = 555 new Action("punky", 556 mock_clock->Now() - base::TimeDelta::FromDays(3) - 557 base::TimeDelta::FromMinutes(40), 558 Action::ACTION_API_CALL, 559 "brewster"); 560 action->mutable_args()->AppendString("woof"); 561 policy->ProcessAction(action); 562 563 action = new Action("punky", 564 mock_clock->Now() - base::TimeDelta::FromDays(3), 565 Action::ACTION_DOM_ACCESS, 566 "lets"); 567 action->mutable_args()->AppendString("vamoose"); 568 action->set_page_url(GURL("http://www.google.com")); 569 policy->ProcessAction(action); 570 571 action = new Action("punky", 572 mock_clock->Now(), 573 Action::ACTION_DOM_ACCESS, 574 "lets"); 575 action->mutable_args()->AppendString("too new"); 576 action->set_page_url(GURL("http://www.google.com")); 577 policy->ProcessAction(action); 578 579 action = new Action("punky", 580 mock_clock->Now() - base::TimeDelta::FromDays(7), 581 Action::ACTION_DOM_ACCESS, 582 "lets"); 583 action->mutable_args()->AppendString("too old"); 584 action->set_page_url(GURL("http://www.google.com")); 585 policy->ProcessAction(action); 586 587 CheckReadData( 588 policy, 589 "punky", 590 3, 591 base::Bind(&CountingPolicyTest::Arguments_GetOlderActions)); 592 593 policy->Close(); 594 } 595 596 TEST_F(CountingPolicyTest, LogAndFetchFilteredActions) { 597 ActivityLogDatabasePolicy* policy = new CountingPolicy(profile_.get()); 598 policy->Init(); 599 scoped_refptr<const Extension> extension = 600 ExtensionBuilder() 601 .SetManifest(DictionaryBuilder() 602 .Set("name", "Test extension") 603 .Set("version", "1.0.0") 604 .Set("manifest_version", 2)) 605 .Build(); 606 extension_service_->AddExtension(extension.get()); 607 GURL gurl("http://www.google.com"); 608 609 // Write some API calls 610 scoped_refptr<Action> action_api = new Action(extension->id(), 611 base::Time::Now(), 612 Action::ACTION_API_CALL, 613 "tabs.testMethod"); 614 action_api->set_args(make_scoped_ptr(new base::ListValue())); 615 policy->ProcessAction(action_api); 616 617 scoped_refptr<Action> action_dom = new Action(extension->id(), 618 base::Time::Now(), 619 Action::ACTION_DOM_ACCESS, 620 "document.write"); 621 action_dom->set_args(make_scoped_ptr(new base::ListValue())); 622 action_dom->set_page_url(gurl); 623 policy->ProcessAction(action_dom); 624 625 CheckReadFilteredData( 626 policy, 627 extension->id(), 628 Action::ACTION_API_CALL, 629 "tabs.testMethod", 630 "", 631 "", 632 -1, 633 base::Bind( 634 &CountingPolicyTest::RetrieveActions_FetchFilteredActions1)); 635 636 CheckReadFilteredData( 637 policy, 638 "", 639 Action::ACTION_DOM_ACCESS, 640 "", 641 "", 642 "", 643 -1, 644 base::Bind( 645 &CountingPolicyTest::RetrieveActions_FetchFilteredActions1)); 646 647 CheckReadFilteredData( 648 policy, 649 "", 650 Action::ACTION_DOM_ACCESS, 651 "", 652 "http://www.google.com/", 653 "", 654 -1, 655 base::Bind( 656 &CountingPolicyTest::RetrieveActions_FetchFilteredActions1)); 657 658 CheckReadFilteredData( 659 policy, 660 "", 661 Action::ACTION_DOM_ACCESS, 662 "", 663 "http://www.google.com", 664 "", 665 -1, 666 base::Bind( 667 &CountingPolicyTest::RetrieveActions_FetchFilteredActions1)); 668 669 CheckReadFilteredData( 670 policy, 671 "", 672 Action::ACTION_DOM_ACCESS, 673 "", 674 "http://www.goo", 675 "", 676 -1, 677 base::Bind( 678 &CountingPolicyTest::RetrieveActions_FetchFilteredActions1)); 679 680 CheckReadFilteredData( 681 policy, 682 extension->id(), 683 Action::ACTION_ANY, 684 "", 685 "", 686 "", 687 -1, 688 base::Bind( 689 &CountingPolicyTest::RetrieveActions_FetchFilteredActions2)); 690 691 policy->Close(); 692 } 693 694 // Check that merging of actions only occurs within the same day, not across 695 // days, and that old data can be expired from the database. 696 TEST_F(CountingPolicyTest, MergingAndExpiring) { 697 CountingPolicy* policy = new CountingPolicy(profile_.get()); 698 policy->Init(); 699 // Initially disable expiration by setting a retention time before any 700 // actions we generate. 701 policy->set_retention_time(base::TimeDelta::FromDays(14)); 702 703 // Use a mock clock to ensure that events are not recorded on the wrong day 704 // when the test is run close to local midnight. 705 base::SimpleTestClock* mock_clock = new base::SimpleTestClock(); 706 mock_clock->SetNow(base::Time::Now().LocalMidnight() + 707 base::TimeDelta::FromHours(12)); 708 policy->SetClockForTesting(scoped_ptr<base::Clock>(mock_clock)); 709 710 // The first two actions should be merged; the last one is on a separate day 711 // and should not be. 712 scoped_refptr<Action> action = 713 new Action("punky", 714 mock_clock->Now() - base::TimeDelta::FromDays(3) - 715 base::TimeDelta::FromMinutes(40), 716 Action::ACTION_API_CALL, 717 "brewster"); 718 policy->ProcessAction(action); 719 720 action = new Action("punky", 721 mock_clock->Now() - base::TimeDelta::FromDays(3) - 722 base::TimeDelta::FromMinutes(20), 723 Action::ACTION_API_CALL, 724 "brewster"); 725 policy->ProcessAction(action); 726 727 action = new Action("punky", 728 mock_clock->Now() - base::TimeDelta::FromDays(2) - 729 base::TimeDelta::FromMinutes(20), 730 Action::ACTION_API_CALL, 731 "brewster"); 732 policy->ProcessAction(action); 733 734 CheckReadData(policy, 735 "punky", 736 3, 737 base::Bind(&CountingPolicyTest::Arguments_CheckMergeCount, 2)); 738 CheckReadData(policy, 739 "punky", 740 2, 741 base::Bind(&CountingPolicyTest::Arguments_CheckMergeCount, 1)); 742 743 // Clean actions before midnight two days ago. Force expiration to run by 744 // clearing last_database_cleaning_time_ and submitting a new action. 745 policy->set_retention_time(base::TimeDelta::FromDays(2)); 746 policy->last_database_cleaning_time_ = base::Time(); 747 action = new Action("punky", 748 mock_clock->Now(), 749 Action::ACTION_API_CALL, 750 "brewster"); 751 policy->ProcessAction(action); 752 753 CheckReadData(policy, 754 "punky", 755 3, 756 base::Bind(&CountingPolicyTest::Arguments_CheckMergeCount, 0)); 757 CheckReadData(policy, 758 "punky", 759 2, 760 base::Bind(&CountingPolicyTest::Arguments_CheckMergeCount, 1)); 761 762 policy->Close(); 763 } 764 765 // Test cleaning of old data in the string and URL tables. 766 TEST_F(CountingPolicyTest, StringTableCleaning) { 767 CountingPolicy* policy = new CountingPolicy(profile_.get()); 768 policy->Init(); 769 // Initially disable expiration by setting a retention time before any 770 // actions we generate. 771 policy->set_retention_time(base::TimeDelta::FromDays(14)); 772 773 base::SimpleTestClock* mock_clock = new base::SimpleTestClock(); 774 mock_clock->SetNow(base::Time::Now()); 775 policy->SetClockForTesting(scoped_ptr<base::Clock>(mock_clock)); 776 777 // Insert an action; this should create entries in both the string table (for 778 // the extension and API name) and the URL table (for page_url). 779 scoped_refptr<Action> action = 780 new Action("punky", 781 mock_clock->Now() - base::TimeDelta::FromDays(7), 782 Action::ACTION_API_CALL, 783 "brewster"); 784 action->set_page_url(GURL("http://www.google.com/")); 785 policy->ProcessAction(action); 786 787 // Add an action which will not be expired, so that some strings will remain 788 // in use. 789 action = new Action( 790 "punky", mock_clock->Now(), Action::ACTION_API_CALL, "tabs.create"); 791 policy->ProcessAction(action); 792 793 // There should now be three strings ("punky", "brewster", "tabs.create") and 794 // one URL in the tables. 795 policy->Flush(); 796 policy->ScheduleAndForget(policy, 797 &CountingPolicyTest::CheckStringTableSizes, 798 3, 799 1); 800 WaitOnThread(BrowserThread::DB); 801 802 // Trigger a cleaning. The oldest action is expired when we submit a 803 // duplicate of the newer action. After this, there should be two strings 804 // and no URLs. 805 policy->set_retention_time(base::TimeDelta::FromDays(2)); 806 policy->last_database_cleaning_time_ = base::Time(); 807 policy->ProcessAction(action); 808 policy->Flush(); 809 policy->ScheduleAndForget(policy, 810 &CountingPolicyTest::CheckStringTableSizes, 811 2, 812 0); 813 WaitOnThread(BrowserThread::DB); 814 815 policy->Close(); 816 } 817 818 // A stress test for memory- and database-based merging of actions. Submit 819 // multiple items, not in chronological order, spanning a few days. Check that 820 // items are merged properly and final timestamps are correct. 821 TEST_F(CountingPolicyTest, MoreMerging) { 822 CountingPolicy* policy = new CountingPolicy(profile_.get()); 823 policy->Init(); 824 policy->set_retention_time(base::TimeDelta::FromDays(14)); 825 826 // Use a mock clock to ensure that events are not recorded on the wrong day 827 // when the test is run close to local midnight. 828 base::SimpleTestClock* mock_clock = new base::SimpleTestClock(); 829 mock_clock->SetNow(base::Time::Now().LocalMidnight() + 830 base::TimeDelta::FromHours(12)); 831 policy->SetClockForTesting(scoped_ptr<base::Clock>(mock_clock)); 832 833 // Create an action 2 days ago, then 1 day ago, then 2 days ago. Make sure 834 // that we end up with two merged records (one for each day), and each has 835 // the appropriate timestamp. These merges should happen in the database 836 // since the date keeps changing. 837 base::Time time1 = 838 mock_clock->Now() - base::TimeDelta::FromDays(2) - 839 base::TimeDelta::FromMinutes(40); 840 base::Time time2 = 841 mock_clock->Now() - base::TimeDelta::FromDays(1) - 842 base::TimeDelta::FromMinutes(40); 843 base::Time time3 = 844 mock_clock->Now() - base::TimeDelta::FromDays(2) - 845 base::TimeDelta::FromMinutes(20); 846 847 scoped_refptr<Action> action = 848 new Action("punky", time1, Action::ACTION_API_CALL, "brewster"); 849 policy->ProcessAction(action); 850 851 action = new Action("punky", time2, Action::ACTION_API_CALL, "brewster"); 852 policy->ProcessAction(action); 853 854 action = new Action("punky", time3, Action::ACTION_API_CALL, "brewster"); 855 policy->ProcessAction(action); 856 857 CheckReadData( 858 policy, 859 "punky", 860 2, 861 base::Bind( 862 &CountingPolicyTest::Arguments_CheckMergeCountAndTime, 2, time3)); 863 CheckReadData( 864 policy, 865 "punky", 866 1, 867 base::Bind( 868 &CountingPolicyTest::Arguments_CheckMergeCountAndTime, 1, time2)); 869 870 // Create three actions today, where the merges should happen in memory. 871 // Again these are not chronological; timestamp time5 should win out since it 872 // is the latest. 873 base::Time time4 = mock_clock->Now() - base::TimeDelta::FromMinutes(60); 874 base::Time time5 = mock_clock->Now() - base::TimeDelta::FromMinutes(20); 875 base::Time time6 = mock_clock->Now() - base::TimeDelta::FromMinutes(40); 876 877 action = new Action("punky", time4, Action::ACTION_API_CALL, "brewster"); 878 policy->ProcessAction(action); 879 880 action = new Action("punky", time5, Action::ACTION_API_CALL, "brewster"); 881 policy->ProcessAction(action); 882 883 action = new Action("punky", time6, Action::ACTION_API_CALL, "brewster"); 884 policy->ProcessAction(action); 885 886 CheckReadData( 887 policy, 888 "punky", 889 0, 890 base::Bind( 891 &CountingPolicyTest::Arguments_CheckMergeCountAndTime, 3, time5)); 892 policy->Close(); 893 } 894 895 // Check that actions are flushed to disk before letting too many accumulate in 896 // memory. 897 TEST_F(CountingPolicyTest, EarlyFlush) { 898 CountingPolicy* policy = new CountingPolicy(profile_.get()); 899 policy->Init(); 900 901 for (int i = 0; i < 500; i++) { 902 scoped_refptr<Action> action = 903 new Action("punky", 904 base::Time::Now(), 905 Action::ACTION_API_CALL, 906 base::StringPrintf("apicall_%d", i)); 907 policy->ProcessAction(action); 908 } 909 910 policy->ScheduleAndForget(policy, &CountingPolicyTest::CheckQueueSize); 911 WaitOnThread(BrowserThread::DB); 912 913 policy->Close(); 914 } 915 916 TEST_F(CountingPolicyTest, CapReturns) { 917 CountingPolicy* policy = new CountingPolicy(profile_.get()); 918 policy->Init(); 919 920 for (int i = 0; i < 305; i++) { 921 scoped_refptr<Action> action = 922 new Action("punky", 923 base::Time::Now(), 924 Action::ACTION_API_CALL, 925 base::StringPrintf("apicall_%d", i)); 926 policy->ProcessAction(action); 927 } 928 929 policy->Flush(); 930 WaitOnThread(BrowserThread::DB); 931 932 CheckReadFilteredData( 933 policy, 934 "punky", 935 Action::ACTION_ANY, 936 "", 937 "", 938 "", 939 -1, 940 base::Bind( 941 &CountingPolicyTest::RetrieveActions_FetchFilteredActions300)); 942 policy->Close(); 943 } 944 945 TEST_F(CountingPolicyTest, RemoveAllURLs) { 946 ActivityLogDatabasePolicy* policy = new CountingPolicy(profile_.get()); 947 policy->Init(); 948 949 // Use a mock clock to ensure that events are not recorded on the wrong day 950 // when the test is run close to local midnight. 951 base::SimpleTestClock* mock_clock = new base::SimpleTestClock(); 952 mock_clock->SetNow(base::Time::Now().LocalMidnight() + 953 base::TimeDelta::FromHours(12)); 954 policy->SetClockForTesting(scoped_ptr<base::Clock>(mock_clock)); 955 956 // Record some actions 957 scoped_refptr<Action> action = 958 new Action("punky", mock_clock->Now(), 959 Action::ACTION_DOM_ACCESS, "lets"); 960 action->mutable_args()->AppendString("vamoose"); 961 action->set_page_url(GURL("http://www.google.com")); 962 action->set_page_title("Google"); 963 action->set_arg_url(GURL("http://www.args-url.com")); 964 policy->ProcessAction(action); 965 966 mock_clock->Advance(base::TimeDelta::FromSeconds(1)); 967 action = new Action( 968 "punky", mock_clock->Now(), Action::ACTION_DOM_ACCESS, "lets"); 969 action->mutable_args()->AppendString("vamoose"); 970 action->set_page_url(GURL("http://www.google2.com")); 971 action->set_page_title("Google"); 972 // Deliberately no arg url set to make sure it stills works if there is no arg 973 // url. 974 policy->ProcessAction(action); 975 976 // Clean all the URLs. 977 std::vector<GURL> no_url_restrictions; 978 policy->RemoveURLs(no_url_restrictions); 979 980 CheckReadData( 981 policy, 982 "punky", 983 0, 984 base::Bind(&CountingPolicyTest::AllURLsRemoved)); 985 policy->Close(); 986 } 987 988 TEST_F(CountingPolicyTest, RemoveSpecificURLs) { 989 ActivityLogDatabasePolicy* policy = new CountingPolicy(profile_.get()); 990 policy->Init(); 991 992 // Use a mock clock to ensure that events are not recorded on the wrong day 993 // when the test is run close to local midnight. 994 base::SimpleTestClock* mock_clock = new base::SimpleTestClock(); 995 mock_clock->SetNow(base::Time::Now().LocalMidnight() + 996 base::TimeDelta::FromHours(12)); 997 policy->SetClockForTesting(scoped_ptr<base::Clock>(mock_clock)); 998 999 // Record some actions 1000 // This should have the page url and args url cleared. 1001 scoped_refptr<Action> action = new Action("punky", mock_clock->Now(), 1002 Action::ACTION_DOM_ACCESS, "lets"); 1003 action->mutable_args()->AppendString("vamoose"); 1004 action->set_page_url(GURL("http://www.google1.com")); 1005 action->set_page_title("Google"); 1006 action->set_arg_url(GURL("http://www.google1.com")); 1007 policy->ProcessAction(action); 1008 1009 // This should have the page url cleared but not args url. 1010 mock_clock->Advance(base::TimeDelta::FromSeconds(1)); 1011 action = new Action( 1012 "punky", mock_clock->Now(), Action::ACTION_DOM_ACCESS, "lets"); 1013 action->mutable_args()->AppendString("vamoose"); 1014 action->set_page_url(GURL("http://www.google1.com")); 1015 action->set_page_title("Google"); 1016 action->set_arg_url(GURL("http://www.google.com")); 1017 policy->ProcessAction(action); 1018 1019 // This should have the page url cleared. The args url is deliberately not 1020 // set to make sure this doesn't cause any issues. 1021 mock_clock->Advance(base::TimeDelta::FromSeconds(1)); 1022 action = new Action( 1023 "punky", mock_clock->Now(), Action::ACTION_DOM_ACCESS, "lets"); 1024 action->mutable_args()->AppendString("vamoose"); 1025 action->set_page_url(GURL("http://www.google2.com")); 1026 action->set_page_title("Google"); 1027 policy->ProcessAction(action); 1028 1029 // This should have the args url cleared but not the page url or page title. 1030 mock_clock->Advance(base::TimeDelta::FromSeconds(1)); 1031 action = new Action( 1032 "punky", mock_clock->Now(), Action::ACTION_DOM_ACCESS, "lets"); 1033 action->mutable_args()->AppendString("vamoose"); 1034 action->set_page_url(GURL("http://www.google.com")); 1035 action->set_page_title("Google"); 1036 action->set_arg_url(GURL("http://www.google1.com")); 1037 policy->ProcessAction(action); 1038 1039 // This should have neither cleared. 1040 mock_clock->Advance(base::TimeDelta::FromSeconds(1)); 1041 action = new Action( 1042 "punky", mock_clock->Now(), Action::ACTION_DOM_ACCESS, "lets"); 1043 action->mutable_args()->AppendString("vamoose"); 1044 action->set_page_url(GURL("http://www.google.com")); 1045 action->set_page_title("Google"); 1046 action->set_arg_url(GURL("http://www.args-url.com")); 1047 action->set_count(5); 1048 policy->ProcessAction(action); 1049 1050 // Clean some URLs. 1051 std::vector<GURL> urls; 1052 urls.push_back(GURL("http://www.google1.com")); 1053 urls.push_back(GURL("http://www.google2.com")); 1054 urls.push_back(GURL("http://www.url_not_in_db.com")); 1055 policy->RemoveURLs(urls); 1056 1057 CheckReadData( 1058 policy, 1059 "punky", 1060 0, 1061 base::Bind(&CountingPolicyTest::SomeURLsRemoved)); 1062 policy->Close(); 1063 } 1064 1065 TEST_F(CountingPolicyTest, RemoveExtensionData) { 1066 CountingPolicy* policy = new CountingPolicy(profile_.get()); 1067 policy->Init(); 1068 1069 // Use a mock clock to ensure that events are not recorded on the wrong day 1070 // when the test is run close to local midnight. 1071 base::SimpleTestClock* mock_clock = new base::SimpleTestClock(); 1072 mock_clock->SetNow(base::Time::Now().LocalMidnight() + 1073 base::TimeDelta::FromHours(12)); 1074 policy->SetClockForTesting(scoped_ptr<base::Clock>(mock_clock)); 1075 1076 // Record some actions 1077 scoped_refptr<Action> action = new Action("deleteextensiondata", 1078 mock_clock->Now(), 1079 Action::ACTION_DOM_ACCESS, 1080 "lets"); 1081 action->mutable_args()->AppendString("vamoose"); 1082 action->set_page_title("Google"); 1083 action->set_arg_url(GURL("http://www.google.com")); 1084 policy->ProcessAction(action); 1085 policy->ProcessAction(action); 1086 policy->ProcessAction(action); 1087 1088 scoped_refptr<Action> action2 = new Action("dontdelete", 1089 mock_clock->Now(), 1090 Action::ACTION_DOM_ACCESS, 1091 "lets"); 1092 action->mutable_args()->AppendString("vamoose"); 1093 action->set_page_title("Google"); 1094 action->set_arg_url(GURL("http://www.google.com")); 1095 policy->ProcessAction(action2); 1096 1097 policy->Flush(); 1098 policy->RemoveExtensionData("deleteextensiondata"); 1099 1100 CheckReadFilteredData( 1101 policy, 1102 "deleteextensiondata", 1103 Action::ACTION_ANY, 1104 "", 1105 "", 1106 "", 1107 -1, 1108 base::Bind( 1109 &CountingPolicyTest::RetrieveActions_FetchFilteredActions0)); 1110 1111 CheckReadFilteredData( 1112 policy, 1113 "dontdelete", 1114 Action::ACTION_ANY, 1115 "", 1116 "", 1117 "", 1118 -1, 1119 base::Bind( 1120 &CountingPolicyTest::RetrieveActions_FetchFilteredActions1)); 1121 policy->Close(); 1122 } 1123 1124 TEST_F(CountingPolicyTest, DeleteDatabase) { 1125 CountingPolicy* policy = new CountingPolicy(profile_.get()); 1126 policy->Init(); 1127 // Disable row expiration for this test by setting a time before any actions 1128 // we generate. 1129 policy->set_retention_time(base::TimeDelta::FromDays(14)); 1130 1131 // Use a mock clock to ensure that events are not recorded on the wrong day 1132 // when the test is run close to local midnight. Note: Ownership is passed 1133 // to the policy, but we still keep a pointer locally. The policy will take 1134 // care of destruction; this is safe since the policy outlives all our 1135 // accesses to the mock clock. 1136 base::SimpleTestClock* mock_clock = new base::SimpleTestClock(); 1137 mock_clock->SetNow(base::Time::Now().LocalMidnight() + 1138 base::TimeDelta::FromHours(12)); 1139 policy->SetClockForTesting(scoped_ptr<base::Clock>(mock_clock)); 1140 1141 // Record some actions 1142 scoped_refptr<Action> action = 1143 new Action("punky", 1144 mock_clock->Now() - base::TimeDelta::FromMinutes(40), 1145 Action::ACTION_API_CALL, 1146 "brewster"); 1147 action->mutable_args()->AppendString("woof"); 1148 policy->ProcessAction(action); 1149 1150 action = new Action("punky", 1151 mock_clock->Now() - base::TimeDelta::FromMinutes(30), 1152 Action::ACTION_API_CALL, 1153 "brewster"); 1154 action->mutable_args()->AppendString("meow"); 1155 policy->ProcessAction(action); 1156 1157 action = new Action("punky", 1158 mock_clock->Now() - base::TimeDelta::FromMinutes(20), 1159 Action::ACTION_API_CALL, 1160 "extension.sendMessage"); 1161 action->mutable_args()->AppendString("not"); 1162 action->mutable_args()->AppendString("stripped"); 1163 policy->ProcessAction(action); 1164 1165 action = 1166 new Action("punky", mock_clock->Now(), Action::ACTION_DOM_ACCESS, "lets"); 1167 action->mutable_args()->AppendString("vamoose"); 1168 action->set_page_url(GURL("http://www.google.com")); 1169 policy->ProcessAction(action); 1170 1171 action = new Action( 1172 "scoobydoo", mock_clock->Now(), Action::ACTION_DOM_ACCESS, "lets"); 1173 action->mutable_args()->AppendString("vamoose"); 1174 action->set_page_url(GURL("http://www.google.com")); 1175 policy->ProcessAction(action); 1176 1177 CheckReadData( 1178 policy, 1179 "punky", 1180 0, 1181 base::Bind(&CountingPolicyTest::Arguments_GetTodaysActions)); 1182 1183 policy->DeleteDatabase(); 1184 1185 CheckReadFilteredData( 1186 policy, 1187 "", 1188 Action::ACTION_ANY, 1189 "", 1190 "", 1191 "", 1192 -1, 1193 base::Bind( 1194 &CountingPolicyTest::RetrieveActions_FetchFilteredActions0)); 1195 1196 // The following code tests that the caches of url and string tables were 1197 // cleared by the deletion above. 1198 // https://code.google.com/p/chromium/issues/detail?id=341674. 1199 action = 1200 new Action("punky", mock_clock->Now(), Action::ACTION_DOM_ACCESS, "lets"); 1201 action->mutable_args()->AppendString("vamoose"); 1202 action->set_page_url(GURL("http://www.google.com")); 1203 policy->ProcessAction(action); 1204 1205 CheckReadData( 1206 policy, 1207 "", 1208 -1, 1209 base::Bind(&CountingPolicyTest::Arguments_GetSinglesAction)); 1210 1211 policy->DeleteDatabase(); 1212 1213 CheckReadFilteredData( 1214 policy, 1215 "", 1216 Action::ACTION_ANY, 1217 "", 1218 "", 1219 "", 1220 -1, 1221 base::Bind( 1222 &CountingPolicyTest::RetrieveActions_FetchFilteredActions0)); 1223 1224 policy->Close(); 1225 } 1226 1227 // Tests that duplicate rows in the activity log database are handled properly 1228 // when updating counts. 1229 TEST_F(CountingPolicyTest, DuplicateRows) { 1230 CountingPolicy* policy = new CountingPolicy(profile_.get()); 1231 policy->Init(); 1232 base::SimpleTestClock* mock_clock = new base::SimpleTestClock(); 1233 mock_clock->SetNow(base::Time::Now().LocalMidnight() + 1234 base::TimeDelta::FromHours(12)); 1235 policy->SetClockForTesting(scoped_ptr<base::Clock>(mock_clock)); 1236 1237 // Record two actions with distinct URLs. 1238 scoped_refptr<Action> action; 1239 action = new Action( 1240 "punky", mock_clock->Now(), Action::ACTION_API_CALL, "brewster"); 1241 action->set_page_url(GURL("http://www.google.com")); 1242 policy->ProcessAction(action); 1243 1244 action = new Action( 1245 "punky", mock_clock->Now(), Action::ACTION_API_CALL, "brewster"); 1246 action->set_page_url(GURL("http://www.google.co.uk")); 1247 policy->ProcessAction(action); 1248 1249 // Manipulate the database to clear the URLs, so that we end up with 1250 // duplicate rows. 1251 std::vector<GURL> no_url_restrictions; 1252 policy->RemoveURLs(no_url_restrictions); 1253 1254 // Record one more action, with no URL. This should increment the count on 1255 // one, and exactly one, of the existing rows. 1256 action = new Action( 1257 "punky", mock_clock->Now(), Action::ACTION_API_CALL, "brewster"); 1258 policy->ProcessAction(action); 1259 1260 CheckReadData( 1261 policy, 1262 "punky", 1263 0, 1264 base::Bind(&CountingPolicyTest::CheckDuplicates)); 1265 policy->Close(); 1266 } 1267 1268 TEST_F(CountingPolicyTest, RemoveActions) { 1269 ActivityLogDatabasePolicy* policy = new CountingPolicy(profile_.get()); 1270 policy->Init(); 1271 1272 std::vector<int64> action_ids; 1273 1274 CheckRemoveActions( 1275 policy, action_ids, base::Bind(&CountingPolicyTest::NoActionsDeleted)); 1276 1277 action_ids.push_back(-1); 1278 action_ids.push_back(-10); 1279 action_ids.push_back(0); 1280 action_ids.push_back(5); 1281 action_ids.push_back(10); 1282 CheckRemoveActions( 1283 policy, action_ids, base::Bind(&CountingPolicyTest::NoActionsDeleted)); 1284 action_ids.clear(); 1285 1286 for (int i = 0; i < 50; i++) { 1287 action_ids.push_back(i + 3); 1288 } 1289 CheckRemoveActions( 1290 policy, action_ids, base::Bind(&CountingPolicyTest::NoActionsDeleted)); 1291 action_ids.clear(); 1292 1293 // CheckRemoveActions pushes two actions to the Activity Log database with IDs 1294 // 1 and 2. 1295 action_ids.push_back(1); 1296 action_ids.push_back(2); 1297 CheckRemoveActions( 1298 policy, action_ids, base::Bind(&CountingPolicyTest::AllActionsDeleted)); 1299 action_ids.clear(); 1300 1301 action_ids.push_back(1); 1302 CheckRemoveActions( 1303 policy, action_ids, base::Bind(&CountingPolicyTest::Action1Deleted)); 1304 action_ids.clear(); 1305 1306 action_ids.push_back(2); 1307 CheckRemoveActions( 1308 policy, action_ids, base::Bind(&CountingPolicyTest::Action2Deleted)); 1309 action_ids.clear(); 1310 1311 policy->Close(); 1312 } 1313 1314 } // namespace extensions 1315