Home | History | Annotate | Download | only in activity_log
      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