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/scoped_test_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.get(),
    187                 "odlameecjipmbmbejkplpemijjgpljce",
    188                 Action::ACTION_API_CALL,
    189                 "extension.connect",
    190                 "[\"hello\",\"world\"]",
    191                 "",
    192                 "",
    193                 "",
    194                 1);
    195   }
    196 
    197   static void Arguments_GetSinglesAction(
    198       scoped_ptr<Action::ActionVector> actions) {
    199     ASSERT_EQ(1, static_cast<int>(actions->size()));
    200     CheckAction(*actions->at(0).get(),
    201                 "punky",
    202                 Action::ACTION_DOM_ACCESS,
    203                 "lets",
    204                 "",
    205                 "http://www.google.com/",
    206                 "",
    207                 "",
    208                 1);
    209   }
    210 
    211   static void Arguments_GetTodaysActions(
    212       scoped_ptr<Action::ActionVector> actions) {
    213     ASSERT_EQ(3, static_cast<int>(actions->size()));
    214     CheckAction(*actions->at(0).get(),
    215                 "punky",
    216                 Action::ACTION_API_CALL,
    217                 "brewster",
    218                 "",
    219                 "",
    220                 "",
    221                 "",
    222                 2);
    223     CheckAction(*actions->at(1).get(),
    224                 "punky",
    225                 Action::ACTION_DOM_ACCESS,
    226                 "lets",
    227                 "",
    228                 "http://www.google.com/",
    229                 "",
    230                 "",
    231                 1);
    232     CheckAction(*actions->at(2).get(),
    233                 "punky",
    234                 Action::ACTION_API_CALL,
    235                 "extension.sendMessage",
    236                 "[\"not\",\"stripped\"]",
    237                 "",
    238                 "",
    239                 "",
    240                 1);
    241   }
    242 
    243   static void Arguments_GetOlderActions(
    244       scoped_ptr<Action::ActionVector> actions) {
    245     ASSERT_EQ(2, static_cast<int>(actions->size()));
    246     CheckAction(*actions->at(0).get(),
    247                 "punky",
    248                 Action::ACTION_DOM_ACCESS,
    249                 "lets",
    250                 "",
    251                 "http://www.google.com/",
    252                 "",
    253                 "",
    254                 1);
    255     CheckAction(*actions->at(1).get(),
    256                 "punky",
    257                 Action::ACTION_API_CALL,
    258                 "brewster",
    259                 "",
    260                 "",
    261                 "",
    262                 "",
    263                 1);
    264   }
    265 
    266   static void Arguments_CheckMergeCount(
    267       int count,
    268       scoped_ptr<Action::ActionVector> actions) {
    269     if (count > 0) {
    270       ASSERT_EQ(1u, actions->size());
    271       CheckAction(*actions->at(0).get(),
    272                   "punky",
    273                   Action::ACTION_API_CALL,
    274                   "brewster",
    275                   "",
    276                   "",
    277                   "",
    278                   "",
    279                   count);
    280     } else {
    281       ASSERT_EQ(0u, actions->size());
    282     }
    283   }
    284 
    285   static void Arguments_CheckMergeCountAndTime(
    286       int count,
    287       const base::Time& time,
    288       scoped_ptr<Action::ActionVector> actions) {
    289     if (count > 0) {
    290       ASSERT_EQ(1u, actions->size());
    291       CheckAction(*actions->at(0).get(),
    292                   "punky",
    293                   Action::ACTION_API_CALL,
    294                   "brewster",
    295                   "",
    296                   "",
    297                   "",
    298                   "",
    299                   count);
    300       ASSERT_EQ(time, actions->at(0)->time());
    301     } else {
    302       ASSERT_EQ(0u, actions->size());
    303     }
    304   }
    305 
    306   static void AllURLsRemoved(scoped_ptr<Action::ActionVector> actions) {
    307     ASSERT_EQ(2, static_cast<int>(actions->size()));
    308     CheckAction(*actions->at(0).get(),
    309                 "punky",
    310                 Action::ACTION_DOM_ACCESS,
    311                 "lets",
    312                 "",
    313                 "",
    314                 "",
    315                 "",
    316                 1);
    317     CheckAction(*actions->at(1).get(),
    318                 "punky",
    319                 Action::ACTION_DOM_ACCESS,
    320                 "lets",
    321                 "",
    322                 "",
    323                 "",
    324                 "",
    325                 1);
    326   }
    327 
    328   static void SomeURLsRemoved(scoped_ptr<Action::ActionVector> actions) {
    329     // These will be in the vector in reverse time order.
    330     ASSERT_EQ(5, static_cast<int>(actions->size()));
    331     CheckAction(*actions->at(0).get(),
    332                 "punky",
    333                 Action::ACTION_DOM_ACCESS,
    334                 "lets",
    335                 "",
    336                 "http://www.google.com/",
    337                 "Google",
    338                 "http://www.args-url.com/",
    339                 1);
    340     CheckAction(*actions->at(1).get(),
    341                 "punky",
    342                 Action::ACTION_DOM_ACCESS,
    343                 "lets",
    344                 "",
    345                 "http://www.google.com/",
    346                 "Google",
    347                 "",
    348                 1);
    349     CheckAction(*actions->at(2).get(),
    350                 "punky",
    351                 Action::ACTION_DOM_ACCESS,
    352                 "lets",
    353                 "",
    354                 "",
    355                 "",
    356                 "",
    357                 1);
    358     CheckAction(*actions->at(3).get(),
    359                 "punky",
    360                 Action::ACTION_DOM_ACCESS,
    361                 "lets",
    362                 "",
    363                 "",
    364                 "",
    365                 "http://www.google.com/",
    366                 1);
    367     CheckAction(*actions->at(4).get(),
    368                 "punky",
    369                 Action::ACTION_DOM_ACCESS,
    370                 "lets",
    371                 "",
    372                 "",
    373                 "",
    374                 "",
    375                 1);
    376   }
    377 
    378   static void CheckDuplicates(scoped_ptr<Action::ActionVector> actions) {
    379     ASSERT_EQ(2u, actions->size());
    380     int total_count = 0;
    381     for (size_t i = 0; i < actions->size(); i++) {
    382       total_count += actions->at(i)->count();
    383     }
    384     ASSERT_EQ(3, total_count);
    385   }
    386 
    387   static void CheckAction(const Action& action,
    388                           const std::string& expected_id,
    389                           const Action::ActionType& expected_type,
    390                           const std::string& expected_api_name,
    391                           const std::string& expected_args_str,
    392                           const std::string& expected_page_url,
    393                           const std::string& expected_page_title,
    394                           const std::string& expected_arg_url,
    395                           int expected_count) {
    396     ASSERT_EQ(expected_id, action.extension_id());
    397     ASSERT_EQ(expected_type, action.action_type());
    398     ASSERT_EQ(expected_api_name, action.api_name());
    399     ASSERT_EQ(expected_args_str,
    400               ActivityLogPolicy::Util::Serialize(action.args()));
    401     ASSERT_EQ(expected_page_url, action.SerializePageUrl());
    402     ASSERT_EQ(expected_page_title, action.page_title());
    403     ASSERT_EQ(expected_arg_url, action.SerializeArgUrl());
    404     ASSERT_EQ(expected_count, action.count());
    405     ASSERT_NE(-1, action.action_id());
    406   }
    407 
    408   // A helper function initializes the policy with a number of actions, calls
    409   // RemoveActions on a policy object and then checks the result of the
    410   // deletion.
    411   void CheckRemoveActions(
    412       ActivityLogDatabasePolicy* policy,
    413       const std::vector<int64>& action_ids,
    414       const base::Callback<void(scoped_ptr<Action::ActionVector>)>& checker) {
    415 
    416     // Use a mock clock to ensure that events are not recorded on the wrong day
    417     // when the test is run close to local midnight.
    418     base::SimpleTestClock* mock_clock = new base::SimpleTestClock();
    419     mock_clock->SetNow(base::Time::Now().LocalMidnight() +
    420                        base::TimeDelta::FromHours(12));
    421     policy->SetClockForTesting(scoped_ptr<base::Clock>(mock_clock));
    422 
    423     // Record some actions
    424     scoped_refptr<Action> action =
    425         new Action("punky1",
    426                    mock_clock->Now() - base::TimeDelta::FromMinutes(40),
    427                    Action::ACTION_DOM_ACCESS,
    428                    "lets1");
    429     action->mutable_args()->AppendString("vamoose1");
    430     action->set_page_url(GURL("http://www.google1.com"));
    431     action->set_page_title("Google1");
    432     action->set_arg_url(GURL("http://www.args-url1.com"));
    433     policy->ProcessAction(action);
    434     // Record the same action twice, so there are multiple entries in the
    435     // database.
    436     policy->ProcessAction(action);
    437 
    438     action = new Action("punky2",
    439                         mock_clock->Now() - base::TimeDelta::FromMinutes(30),
    440                         Action::ACTION_API_CALL,
    441                         "lets2");
    442     action->mutable_args()->AppendString("vamoose2");
    443     action->set_page_url(GURL("http://www.google2.com"));
    444     action->set_page_title("Google2");
    445     action->set_arg_url(GURL("http://www.args-url2.com"));
    446     policy->ProcessAction(action);
    447     // Record the same action twice, so there are multiple entries in the
    448     // database.
    449     policy->ProcessAction(action);
    450 
    451     // Submit a request to delete actions.
    452     policy->RemoveActions(action_ids);
    453 
    454     // Check the result of the deletion. The checker function gets all
    455     // activities in the database.
    456     CheckReadData(policy, "", -1, checker);
    457 
    458     // Clean database.
    459     policy->DeleteDatabase();
    460   }
    461 
    462   static void AllActionsDeleted(scoped_ptr<Action::ActionVector> actions) {
    463     ASSERT_EQ(0, static_cast<int>(actions->size()));
    464   }
    465 
    466   static void NoActionsDeleted(scoped_ptr<Action::ActionVector> actions) {
    467     // These will be in the vector in reverse time order.
    468     ASSERT_EQ(2, static_cast<int>(actions->size()));
    469     CheckAction(*actions->at(0).get(),
    470                 "punky2",
    471                 Action::ACTION_API_CALL,
    472                 "lets2",
    473                 "",
    474                 "http://www.google2.com/",
    475                 "Google2",
    476                 "http://www.args-url2.com/",
    477                 2);
    478     ASSERT_EQ(2, actions->at(0)->action_id());
    479     CheckAction(*actions->at(1).get(),
    480                 "punky1",
    481                 Action::ACTION_DOM_ACCESS,
    482                 "lets1",
    483                 "",
    484                 "http://www.google1.com/",
    485                 "Google1",
    486                 "http://www.args-url1.com/",
    487                 2);
    488     ASSERT_EQ(1, actions->at(1)->action_id());
    489   }
    490 
    491   static void Action1Deleted(scoped_ptr<Action::ActionVector> actions) {
    492     // These will be in the vector in reverse time order.
    493     ASSERT_EQ(1, static_cast<int>(actions->size()));
    494     CheckAction(*actions->at(0).get(),
    495                 "punky2",
    496                 Action::ACTION_API_CALL,
    497                 "lets2",
    498                 "",
    499                 "http://www.google2.com/",
    500                 "Google2",
    501                 "http://www.args-url2.com/",
    502                 2);
    503     ASSERT_EQ(2, actions->at(0)->action_id());
    504   }
    505 
    506   static void Action2Deleted(scoped_ptr<Action::ActionVector> actions) {
    507     // These will be in the vector in reverse time order.
    508     ASSERT_EQ(1, static_cast<int>(actions->size()));
    509     CheckAction(*actions->at(0).get(),
    510                 "punky1",
    511                 Action::ACTION_DOM_ACCESS,
    512                 "lets1",
    513                 "",
    514                 "http://www.google1.com/",
    515                 "Google1",
    516                 "http://www.args-url1.com/",
    517                 2);
    518     ASSERT_EQ(1, actions->at(0)->action_id());
    519   }
    520 
    521  protected:
    522   ExtensionService* extension_service_;
    523   scoped_ptr<TestingProfile> profile_;
    524   content::TestBrowserThreadBundle thread_bundle_;
    525   // Used to preserve a copy of the original command line.
    526   // The test framework will do this itself as well. However, by then,
    527   // it is too late to call ActivityLog::RecomputeLoggingIsEnabled() in
    528   // TearDown().
    529   CommandLine saved_cmdline_;
    530 
    531 #if defined OS_CHROMEOS
    532   chromeos::ScopedTestDeviceSettingsService test_device_settings_service_;
    533   chromeos::ScopedTestCrosSettings test_cros_settings_;
    534   scoped_ptr<chromeos::ScopedTestUserManager> test_user_manager_;
    535 #endif
    536 };
    537 
    538 TEST_F(CountingPolicyTest, Construct) {
    539   ActivityLogDatabasePolicy* policy = new CountingPolicy(profile_.get());
    540   policy->Init();
    541   scoped_refptr<const Extension> extension =
    542       ExtensionBuilder()
    543           .SetManifest(DictionaryBuilder()
    544                        .Set("name", "Test extension")
    545                        .Set("version", "1.0.0")
    546                        .Set("manifest_version", 2))
    547           .Build();
    548   extension_service_->AddExtension(extension.get());
    549   scoped_ptr<base::ListValue> args(new base::ListValue());
    550   scoped_refptr<Action> action = new Action(extension->id(),
    551                                             base::Time::Now(),
    552                                             Action::ACTION_API_CALL,
    553                                             "tabs.testMethod");
    554   action->set_args(args.Pass());
    555   policy->ProcessAction(action);
    556   policy->Close();
    557 }
    558 
    559 TEST_F(CountingPolicyTest, LogWithStrippedArguments) {
    560   ActivityLogDatabasePolicy* policy = new CountingPolicy(profile_.get());
    561   policy->Init();
    562   scoped_refptr<const Extension> extension =
    563       ExtensionBuilder()
    564           .SetManifest(DictionaryBuilder()
    565                        .Set("name", "Test extension")
    566                        .Set("version", "1.0.0")
    567                        .Set("manifest_version", 2))
    568           .Build();
    569   extension_service_->AddExtension(extension.get());
    570 
    571   scoped_ptr<base::ListValue> args(new base::ListValue());
    572   args->Set(0, new base::StringValue("hello"));
    573   args->Set(1, new base::StringValue("world"));
    574   scoped_refptr<Action> action = new Action(extension->id(),
    575                                             base::Time::Now(),
    576                                             Action::ACTION_API_CALL,
    577                                             "extension.connect");
    578   action->set_args(args.Pass());
    579 
    580   policy->ProcessAction(action);
    581   CheckReadData(policy,
    582                 extension->id(),
    583                 0,
    584                 base::Bind(&CountingPolicyTest::Arguments_Stripped));
    585   policy->Close();
    586 }
    587 
    588 TEST_F(CountingPolicyTest, GetTodaysActions) {
    589   CountingPolicy* policy = new CountingPolicy(profile_.get());
    590   policy->Init();
    591   // Disable row expiration for this test by setting a time before any actions
    592   // we generate.
    593   policy->set_retention_time(base::TimeDelta::FromDays(14));
    594 
    595   // Use a mock clock to ensure that events are not recorded on the wrong day
    596   // when the test is run close to local midnight.  Note: Ownership is passed
    597   // to the policy, but we still keep a pointer locally.  The policy will take
    598   // care of destruction; this is safe since the policy outlives all our
    599   // accesses to the mock clock.
    600   base::SimpleTestClock* mock_clock = new base::SimpleTestClock();
    601   mock_clock->SetNow(base::Time::Now().LocalMidnight() +
    602                      base::TimeDelta::FromHours(12));
    603   policy->SetClockForTesting(scoped_ptr<base::Clock>(mock_clock));
    604 
    605   // Record some actions
    606   scoped_refptr<Action> action =
    607       new Action("punky",
    608                  mock_clock->Now() - base::TimeDelta::FromMinutes(40),
    609                  Action::ACTION_API_CALL,
    610                  "brewster");
    611   action->mutable_args()->AppendString("woof");
    612   policy->ProcessAction(action);
    613 
    614   action = new Action("punky",
    615                       mock_clock->Now() - base::TimeDelta::FromMinutes(30),
    616                       Action::ACTION_API_CALL,
    617                       "brewster");
    618   action->mutable_args()->AppendString("meow");
    619   policy->ProcessAction(action);
    620 
    621   action = new Action("punky",
    622                       mock_clock->Now() - base::TimeDelta::FromMinutes(20),
    623                       Action::ACTION_API_CALL,
    624                       "extension.sendMessage");
    625   action->mutable_args()->AppendString("not");
    626   action->mutable_args()->AppendString("stripped");
    627   policy->ProcessAction(action);
    628 
    629   action =
    630       new Action("punky", mock_clock->Now(), Action::ACTION_DOM_ACCESS, "lets");
    631   action->mutable_args()->AppendString("vamoose");
    632   action->set_page_url(GURL("http://www.google.com"));
    633   policy->ProcessAction(action);
    634 
    635   action = new Action(
    636       "scoobydoo", mock_clock->Now(), Action::ACTION_DOM_ACCESS, "lets");
    637   action->mutable_args()->AppendString("vamoose");
    638   action->set_page_url(GURL("http://www.google.com"));
    639   policy->ProcessAction(action);
    640 
    641   CheckReadData(
    642       policy,
    643       "punky",
    644       0,
    645       base::Bind(&CountingPolicyTest::Arguments_GetTodaysActions));
    646   policy->Close();
    647 }
    648 
    649 // Check that we can read back less recent actions in the db.
    650 TEST_F(CountingPolicyTest, GetOlderActions) {
    651   CountingPolicy* policy = new CountingPolicy(profile_.get());
    652   policy->Init();
    653   policy->set_retention_time(base::TimeDelta::FromDays(14));
    654 
    655   // Use a mock clock to ensure that events are not recorded on the wrong day
    656   // when the test is run close to local midnight.
    657   base::SimpleTestClock* mock_clock = new base::SimpleTestClock();
    658   mock_clock->SetNow(base::Time::Now().LocalMidnight() +
    659                      base::TimeDelta::FromHours(12));
    660   policy->SetClockForTesting(scoped_ptr<base::Clock>(mock_clock));
    661 
    662   // Record some actions
    663   scoped_refptr<Action> action =
    664       new Action("punky",
    665                  mock_clock->Now() - base::TimeDelta::FromDays(3) -
    666                      base::TimeDelta::FromMinutes(40),
    667                  Action::ACTION_API_CALL,
    668                  "brewster");
    669   action->mutable_args()->AppendString("woof");
    670   policy->ProcessAction(action);
    671 
    672   action = new Action("punky",
    673                       mock_clock->Now() - base::TimeDelta::FromDays(3),
    674                       Action::ACTION_DOM_ACCESS,
    675                       "lets");
    676   action->mutable_args()->AppendString("vamoose");
    677   action->set_page_url(GURL("http://www.google.com"));
    678   policy->ProcessAction(action);
    679 
    680   action = new Action("punky",
    681                       mock_clock->Now(),
    682                       Action::ACTION_DOM_ACCESS,
    683                       "lets");
    684   action->mutable_args()->AppendString("too new");
    685   action->set_page_url(GURL("http://www.google.com"));
    686   policy->ProcessAction(action);
    687 
    688   action = new Action("punky",
    689                       mock_clock->Now() - base::TimeDelta::FromDays(7),
    690                       Action::ACTION_DOM_ACCESS,
    691                       "lets");
    692   action->mutable_args()->AppendString("too old");
    693   action->set_page_url(GURL("http://www.google.com"));
    694   policy->ProcessAction(action);
    695 
    696   CheckReadData(
    697       policy,
    698       "punky",
    699       3,
    700       base::Bind(&CountingPolicyTest::Arguments_GetOlderActions));
    701 
    702   policy->Close();
    703 }
    704 
    705 TEST_F(CountingPolicyTest, LogAndFetchFilteredActions) {
    706   ActivityLogDatabasePolicy* policy = new CountingPolicy(profile_.get());
    707   policy->Init();
    708   scoped_refptr<const Extension> extension =
    709       ExtensionBuilder()
    710           .SetManifest(DictionaryBuilder()
    711                        .Set("name", "Test extension")
    712                        .Set("version", "1.0.0")
    713                        .Set("manifest_version", 2))
    714           .Build();
    715   extension_service_->AddExtension(extension.get());
    716   GURL gurl("http://www.google.com");
    717 
    718   // Write some API calls
    719   scoped_refptr<Action> action_api = new Action(extension->id(),
    720                                                 base::Time::Now(),
    721                                                 Action::ACTION_API_CALL,
    722                                                 "tabs.testMethod");
    723   action_api->set_args(make_scoped_ptr(new base::ListValue()));
    724   policy->ProcessAction(action_api);
    725 
    726   scoped_refptr<Action> action_dom = new Action(extension->id(),
    727                                                 base::Time::Now(),
    728                                                 Action::ACTION_DOM_ACCESS,
    729                                                 "document.write");
    730   action_dom->set_args(make_scoped_ptr(new base::ListValue()));
    731   action_dom->set_page_url(gurl);
    732   policy->ProcessAction(action_dom);
    733 
    734   CheckReadFilteredData(
    735       policy,
    736       extension->id(),
    737       Action::ACTION_API_CALL,
    738       "tabs.testMethod",
    739       "",
    740       "",
    741       -1,
    742       base::Bind(
    743           &CountingPolicyTest::RetrieveActions_FetchFilteredActions1));
    744 
    745   CheckReadFilteredData(
    746       policy,
    747       "",
    748       Action::ACTION_DOM_ACCESS,
    749       "",
    750       "",
    751       "",
    752       -1,
    753       base::Bind(
    754           &CountingPolicyTest::RetrieveActions_FetchFilteredActions1));
    755 
    756   CheckReadFilteredData(
    757       policy,
    758       "",
    759       Action::ACTION_DOM_ACCESS,
    760       "",
    761       "http://www.google.com/",
    762       "",
    763       -1,
    764       base::Bind(
    765           &CountingPolicyTest::RetrieveActions_FetchFilteredActions1));
    766 
    767   CheckReadFilteredData(
    768       policy,
    769       "",
    770       Action::ACTION_DOM_ACCESS,
    771       "",
    772       "http://www.google.com",
    773       "",
    774       -1,
    775       base::Bind(
    776           &CountingPolicyTest::RetrieveActions_FetchFilteredActions1));
    777 
    778   CheckReadFilteredData(
    779       policy,
    780       "",
    781       Action::ACTION_DOM_ACCESS,
    782       "",
    783       "http://www.goo",
    784       "",
    785       -1,
    786       base::Bind(
    787           &CountingPolicyTest::RetrieveActions_FetchFilteredActions1));
    788 
    789   CheckReadFilteredData(
    790       policy,
    791       extension->id(),
    792       Action::ACTION_ANY,
    793       "",
    794       "",
    795       "",
    796       -1,
    797       base::Bind(
    798           &CountingPolicyTest::RetrieveActions_FetchFilteredActions2));
    799 
    800   policy->Close();
    801 }
    802 
    803 // Check that merging of actions only occurs within the same day, not across
    804 // days, and that old data can be expired from the database.
    805 TEST_F(CountingPolicyTest, MergingAndExpiring) {
    806   CountingPolicy* policy = new CountingPolicy(profile_.get());
    807   policy->Init();
    808   // Initially disable expiration by setting a retention time before any
    809   // actions we generate.
    810   policy->set_retention_time(base::TimeDelta::FromDays(14));
    811 
    812   // Use a mock clock to ensure that events are not recorded on the wrong day
    813   // when the test is run close to local midnight.
    814   base::SimpleTestClock* mock_clock = new base::SimpleTestClock();
    815   mock_clock->SetNow(base::Time::Now().LocalMidnight() +
    816                     base::TimeDelta::FromHours(12));
    817   policy->SetClockForTesting(scoped_ptr<base::Clock>(mock_clock));
    818 
    819   // The first two actions should be merged; the last one is on a separate day
    820   // and should not be.
    821   scoped_refptr<Action> action =
    822       new Action("punky",
    823                  mock_clock->Now() - base::TimeDelta::FromDays(3) -
    824                      base::TimeDelta::FromMinutes(40),
    825                  Action::ACTION_API_CALL,
    826                  "brewster");
    827   policy->ProcessAction(action);
    828 
    829   action = new Action("punky",
    830                       mock_clock->Now() - base::TimeDelta::FromDays(3) -
    831                           base::TimeDelta::FromMinutes(20),
    832                       Action::ACTION_API_CALL,
    833                       "brewster");
    834   policy->ProcessAction(action);
    835 
    836   action = new Action("punky",
    837                       mock_clock->Now() - base::TimeDelta::FromDays(2) -
    838                           base::TimeDelta::FromMinutes(20),
    839                       Action::ACTION_API_CALL,
    840                       "brewster");
    841   policy->ProcessAction(action);
    842 
    843   CheckReadData(policy,
    844                 "punky",
    845                 3,
    846                 base::Bind(&CountingPolicyTest::Arguments_CheckMergeCount, 2));
    847   CheckReadData(policy,
    848                 "punky",
    849                 2,
    850                 base::Bind(&CountingPolicyTest::Arguments_CheckMergeCount, 1));
    851 
    852   // Clean actions before midnight two days ago.  Force expiration to run by
    853   // clearing last_database_cleaning_time_ and submitting a new action.
    854   policy->set_retention_time(base::TimeDelta::FromDays(2));
    855   policy->last_database_cleaning_time_ = base::Time();
    856   action = new Action("punky",
    857                       mock_clock->Now(),
    858                       Action::ACTION_API_CALL,
    859                       "brewster");
    860   policy->ProcessAction(action);
    861 
    862   CheckReadData(policy,
    863                 "punky",
    864                 3,
    865                 base::Bind(&CountingPolicyTest::Arguments_CheckMergeCount, 0));
    866   CheckReadData(policy,
    867                 "punky",
    868                 2,
    869                 base::Bind(&CountingPolicyTest::Arguments_CheckMergeCount, 1));
    870 
    871   policy->Close();
    872 }
    873 
    874 // Test cleaning of old data in the string and URL tables.
    875 TEST_F(CountingPolicyTest, StringTableCleaning) {
    876   CountingPolicy* policy = new CountingPolicy(profile_.get());
    877   policy->Init();
    878   // Initially disable expiration by setting a retention time before any
    879   // actions we generate.
    880   policy->set_retention_time(base::TimeDelta::FromDays(14));
    881 
    882   base::SimpleTestClock* mock_clock = new base::SimpleTestClock();
    883   mock_clock->SetNow(base::Time::Now());
    884   policy->SetClockForTesting(scoped_ptr<base::Clock>(mock_clock));
    885 
    886   // Insert an action; this should create entries in both the string table (for
    887   // the extension and API name) and the URL table (for page_url).
    888   scoped_refptr<Action> action =
    889       new Action("punky",
    890                  mock_clock->Now() - base::TimeDelta::FromDays(7),
    891                  Action::ACTION_API_CALL,
    892                  "brewster");
    893   action->set_page_url(GURL("http://www.google.com/"));
    894   policy->ProcessAction(action);
    895 
    896   // Add an action which will not be expired, so that some strings will remain
    897   // in use.
    898   action = new Action(
    899       "punky", mock_clock->Now(), Action::ACTION_API_CALL, "tabs.create");
    900   policy->ProcessAction(action);
    901 
    902   // There should now be three strings ("punky", "brewster", "tabs.create") and
    903   // one URL in the tables.
    904   policy->Flush();
    905   policy->ScheduleAndForget(policy,
    906                             &CountingPolicyTest::CheckStringTableSizes,
    907                             3,
    908                             1);
    909   WaitOnThread(BrowserThread::DB);
    910 
    911   // Trigger a cleaning.  The oldest action is expired when we submit a
    912   // duplicate of the newer action.  After this, there should be two strings
    913   // and no URLs.
    914   policy->set_retention_time(base::TimeDelta::FromDays(2));
    915   policy->last_database_cleaning_time_ = base::Time();
    916   policy->ProcessAction(action);
    917   policy->Flush();
    918   policy->ScheduleAndForget(policy,
    919                             &CountingPolicyTest::CheckStringTableSizes,
    920                             2,
    921                             0);
    922   WaitOnThread(BrowserThread::DB);
    923 
    924   policy->Close();
    925 }
    926 
    927 // A stress test for memory- and database-based merging of actions.  Submit
    928 // multiple items, not in chronological order, spanning a few days.  Check that
    929 // items are merged properly and final timestamps are correct.
    930 TEST_F(CountingPolicyTest, MoreMerging) {
    931   CountingPolicy* policy = new CountingPolicy(profile_.get());
    932   policy->Init();
    933   policy->set_retention_time(base::TimeDelta::FromDays(14));
    934 
    935   // Use a mock clock to ensure that events are not recorded on the wrong day
    936   // when the test is run close to local midnight.
    937   base::SimpleTestClock* mock_clock = new base::SimpleTestClock();
    938   mock_clock->SetNow(base::Time::Now().LocalMidnight() +
    939                     base::TimeDelta::FromHours(12));
    940   policy->SetClockForTesting(scoped_ptr<base::Clock>(mock_clock));
    941 
    942   // Create an action 2 days ago, then 1 day ago, then 2 days ago.  Make sure
    943   // that we end up with two merged records (one for each day), and each has
    944   // the appropriate timestamp.  These merges should happen in the database
    945   // since the date keeps changing.
    946   base::Time time1 =
    947       mock_clock->Now() - base::TimeDelta::FromDays(2) -
    948       base::TimeDelta::FromMinutes(40);
    949   base::Time time2 =
    950       mock_clock->Now() - base::TimeDelta::FromDays(1) -
    951       base::TimeDelta::FromMinutes(40);
    952   base::Time time3 =
    953       mock_clock->Now() - base::TimeDelta::FromDays(2) -
    954       base::TimeDelta::FromMinutes(20);
    955 
    956   scoped_refptr<Action> action =
    957       new Action("punky", time1, Action::ACTION_API_CALL, "brewster");
    958   policy->ProcessAction(action);
    959 
    960   action = new Action("punky", time2, Action::ACTION_API_CALL, "brewster");
    961   policy->ProcessAction(action);
    962 
    963   action = new Action("punky", time3, Action::ACTION_API_CALL, "brewster");
    964   policy->ProcessAction(action);
    965 
    966   CheckReadData(
    967       policy,
    968       "punky",
    969       2,
    970       base::Bind(
    971           &CountingPolicyTest::Arguments_CheckMergeCountAndTime, 2, time3));
    972   CheckReadData(
    973       policy,
    974       "punky",
    975       1,
    976       base::Bind(
    977           &CountingPolicyTest::Arguments_CheckMergeCountAndTime, 1, time2));
    978 
    979   // Create three actions today, where the merges should happen in memory.
    980   // Again these are not chronological; timestamp time5 should win out since it
    981   // is the latest.
    982   base::Time time4 = mock_clock->Now() - base::TimeDelta::FromMinutes(60);
    983   base::Time time5 = mock_clock->Now() - base::TimeDelta::FromMinutes(20);
    984   base::Time time6 = mock_clock->Now() - base::TimeDelta::FromMinutes(40);
    985 
    986   action = new Action("punky", time4, Action::ACTION_API_CALL, "brewster");
    987   policy->ProcessAction(action);
    988 
    989   action = new Action("punky", time5, Action::ACTION_API_CALL, "brewster");
    990   policy->ProcessAction(action);
    991 
    992   action = new Action("punky", time6, Action::ACTION_API_CALL, "brewster");
    993   policy->ProcessAction(action);
    994 
    995   CheckReadData(
    996       policy,
    997       "punky",
    998       0,
    999       base::Bind(
   1000           &CountingPolicyTest::Arguments_CheckMergeCountAndTime, 3, time5));
   1001   policy->Close();
   1002 }
   1003 
   1004 // Check that actions are flushed to disk before letting too many accumulate in
   1005 // memory.
   1006 TEST_F(CountingPolicyTest, EarlyFlush) {
   1007   CountingPolicy* policy = new CountingPolicy(profile_.get());
   1008   policy->Init();
   1009 
   1010   for (int i = 0; i < 500; i++) {
   1011     scoped_refptr<Action> action =
   1012         new Action("punky",
   1013                    base::Time::Now(),
   1014                    Action::ACTION_API_CALL,
   1015                    base::StringPrintf("apicall_%d", i));
   1016     policy->ProcessAction(action);
   1017   }
   1018 
   1019   policy->ScheduleAndForget(policy, &CountingPolicyTest::CheckQueueSize);
   1020   WaitOnThread(BrowserThread::DB);
   1021 
   1022   policy->Close();
   1023 }
   1024 
   1025 TEST_F(CountingPolicyTest, CapReturns) {
   1026   CountingPolicy* policy = new CountingPolicy(profile_.get());
   1027   policy->Init();
   1028 
   1029   for (int i = 0; i < 305; i++) {
   1030     scoped_refptr<Action> action =
   1031         new Action("punky",
   1032                    base::Time::Now(),
   1033                    Action::ACTION_API_CALL,
   1034                    base::StringPrintf("apicall_%d", i));
   1035     policy->ProcessAction(action);
   1036   }
   1037 
   1038   policy->Flush();
   1039   WaitOnThread(BrowserThread::DB);
   1040 
   1041   CheckReadFilteredData(
   1042       policy,
   1043       "punky",
   1044       Action::ACTION_ANY,
   1045       "",
   1046       "",
   1047       "",
   1048       -1,
   1049       base::Bind(
   1050           &CountingPolicyTest::RetrieveActions_FetchFilteredActions300));
   1051   policy->Close();
   1052 }
   1053 
   1054 TEST_F(CountingPolicyTest, RemoveAllURLs) {
   1055   ActivityLogDatabasePolicy* policy = new CountingPolicy(profile_.get());
   1056   policy->Init();
   1057 
   1058   // Use a mock clock to ensure that events are not recorded on the wrong day
   1059   // when the test is run close to local midnight.
   1060   base::SimpleTestClock* mock_clock = new base::SimpleTestClock();
   1061   mock_clock->SetNow(base::Time::Now().LocalMidnight() +
   1062                      base::TimeDelta::FromHours(12));
   1063   policy->SetClockForTesting(scoped_ptr<base::Clock>(mock_clock));
   1064 
   1065   // Record some actions
   1066   scoped_refptr<Action> action =
   1067       new Action("punky", mock_clock->Now(),
   1068                  Action::ACTION_DOM_ACCESS, "lets");
   1069   action->mutable_args()->AppendString("vamoose");
   1070   action->set_page_url(GURL("http://www.google.com"));
   1071   action->set_page_title("Google");
   1072   action->set_arg_url(GURL("http://www.args-url.com"));
   1073   policy->ProcessAction(action);
   1074 
   1075   mock_clock->Advance(base::TimeDelta::FromSeconds(1));
   1076   action = new Action(
   1077       "punky", mock_clock->Now(), Action::ACTION_DOM_ACCESS, "lets");
   1078   action->mutable_args()->AppendString("vamoose");
   1079   action->set_page_url(GURL("http://www.google2.com"));
   1080   action->set_page_title("Google");
   1081   // Deliberately no arg url set to make sure it stills works if there is no arg
   1082   // url.
   1083   policy->ProcessAction(action);
   1084 
   1085   // Clean all the URLs.
   1086   std::vector<GURL> no_url_restrictions;
   1087   policy->RemoveURLs(no_url_restrictions);
   1088 
   1089   CheckReadData(
   1090       policy,
   1091       "punky",
   1092       0,
   1093       base::Bind(&CountingPolicyTest::AllURLsRemoved));
   1094   policy->Close();
   1095 }
   1096 
   1097 TEST_F(CountingPolicyTest, RemoveSpecificURLs) {
   1098   ActivityLogDatabasePolicy* policy = new CountingPolicy(profile_.get());
   1099   policy->Init();
   1100 
   1101   // Use a mock clock to ensure that events are not recorded on the wrong day
   1102   // when the test is run close to local midnight.
   1103   base::SimpleTestClock* mock_clock = new base::SimpleTestClock();
   1104   mock_clock->SetNow(base::Time::Now().LocalMidnight() +
   1105                      base::TimeDelta::FromHours(12));
   1106   policy->SetClockForTesting(scoped_ptr<base::Clock>(mock_clock));
   1107 
   1108   // Record some actions
   1109   // This should have the page url and args url cleared.
   1110   scoped_refptr<Action> action = new Action("punky", mock_clock->Now(),
   1111                                             Action::ACTION_DOM_ACCESS, "lets");
   1112   action->mutable_args()->AppendString("vamoose");
   1113   action->set_page_url(GURL("http://www.google1.com"));
   1114   action->set_page_title("Google");
   1115   action->set_arg_url(GURL("http://www.google1.com"));
   1116   policy->ProcessAction(action);
   1117 
   1118   // This should have the page url cleared but not args url.
   1119   mock_clock->Advance(base::TimeDelta::FromSeconds(1));
   1120   action = new Action(
   1121       "punky", mock_clock->Now(), Action::ACTION_DOM_ACCESS, "lets");
   1122   action->mutable_args()->AppendString("vamoose");
   1123   action->set_page_url(GURL("http://www.google1.com"));
   1124   action->set_page_title("Google");
   1125   action->set_arg_url(GURL("http://www.google.com"));
   1126   policy->ProcessAction(action);
   1127 
   1128   // This should have the page url cleared. The args url is deliberately not
   1129   // set to make sure this doesn't cause any issues.
   1130   mock_clock->Advance(base::TimeDelta::FromSeconds(1));
   1131   action = new Action(
   1132       "punky", mock_clock->Now(), Action::ACTION_DOM_ACCESS, "lets");
   1133   action->mutable_args()->AppendString("vamoose");
   1134   action->set_page_url(GURL("http://www.google2.com"));
   1135   action->set_page_title("Google");
   1136   policy->ProcessAction(action);
   1137 
   1138   // This should have the args url cleared but not the page url or page title.
   1139   mock_clock->Advance(base::TimeDelta::FromSeconds(1));
   1140   action = new Action(
   1141       "punky", mock_clock->Now(), Action::ACTION_DOM_ACCESS, "lets");
   1142   action->mutable_args()->AppendString("vamoose");
   1143   action->set_page_url(GURL("http://www.google.com"));
   1144   action->set_page_title("Google");
   1145   action->set_arg_url(GURL("http://www.google1.com"));
   1146   policy->ProcessAction(action);
   1147 
   1148   // This should have neither cleared.
   1149   mock_clock->Advance(base::TimeDelta::FromSeconds(1));
   1150   action = new Action(
   1151       "punky", mock_clock->Now(), Action::ACTION_DOM_ACCESS, "lets");
   1152   action->mutable_args()->AppendString("vamoose");
   1153   action->set_page_url(GURL("http://www.google.com"));
   1154   action->set_page_title("Google");
   1155   action->set_arg_url(GURL("http://www.args-url.com"));
   1156   action->set_count(5);
   1157   policy->ProcessAction(action);
   1158 
   1159     // Clean some URLs.
   1160   std::vector<GURL> urls;
   1161   urls.push_back(GURL("http://www.google1.com"));
   1162   urls.push_back(GURL("http://www.google2.com"));
   1163   urls.push_back(GURL("http://www.url_not_in_db.com"));
   1164   policy->RemoveURLs(urls);
   1165 
   1166   CheckReadData(
   1167       policy,
   1168       "punky",
   1169       0,
   1170       base::Bind(&CountingPolicyTest::SomeURLsRemoved));
   1171   policy->Close();
   1172 }
   1173 
   1174 TEST_F(CountingPolicyTest, RemoveExtensionData) {
   1175   CountingPolicy* policy = new CountingPolicy(profile_.get());
   1176   policy->Init();
   1177 
   1178   // Use a mock clock to ensure that events are not recorded on the wrong day
   1179   // when the test is run close to local midnight.
   1180   base::SimpleTestClock* mock_clock = new base::SimpleTestClock();
   1181   mock_clock->SetNow(base::Time::Now().LocalMidnight() +
   1182                      base::TimeDelta::FromHours(12));
   1183   policy->SetClockForTesting(scoped_ptr<base::Clock>(mock_clock));
   1184 
   1185   // Record some actions
   1186   scoped_refptr<Action> action = new Action("deleteextensiondata",
   1187                                             mock_clock->Now(),
   1188                                             Action::ACTION_DOM_ACCESS,
   1189                                             "lets");
   1190   action->mutable_args()->AppendString("vamoose");
   1191   action->set_page_title("Google");
   1192   action->set_arg_url(GURL("http://www.google.com"));
   1193   policy->ProcessAction(action);
   1194   policy->ProcessAction(action);
   1195   policy->ProcessAction(action);
   1196 
   1197   scoped_refptr<Action> action2 = new Action("dontdelete",
   1198                                              mock_clock->Now(),
   1199                                              Action::ACTION_DOM_ACCESS,
   1200                                              "lets");
   1201   action->mutable_args()->AppendString("vamoose");
   1202   action->set_page_title("Google");
   1203   action->set_arg_url(GURL("http://www.google.com"));
   1204   policy->ProcessAction(action2);
   1205 
   1206   policy->Flush();
   1207   policy->RemoveExtensionData("deleteextensiondata");
   1208 
   1209   CheckReadFilteredData(
   1210       policy,
   1211       "deleteextensiondata",
   1212       Action::ACTION_ANY,
   1213       "",
   1214       "",
   1215       "",
   1216       -1,
   1217       base::Bind(
   1218           &CountingPolicyTest::RetrieveActions_FetchFilteredActions0));
   1219 
   1220   CheckReadFilteredData(
   1221       policy,
   1222       "dontdelete",
   1223       Action::ACTION_ANY,
   1224       "",
   1225       "",
   1226       "",
   1227       -1,
   1228       base::Bind(
   1229           &CountingPolicyTest::RetrieveActions_FetchFilteredActions1));
   1230   policy->Close();
   1231 }
   1232 
   1233 TEST_F(CountingPolicyTest, DeleteDatabase) {
   1234   CountingPolicy* policy = new CountingPolicy(profile_.get());
   1235   policy->Init();
   1236   // Disable row expiration for this test by setting a time before any actions
   1237   // we generate.
   1238   policy->set_retention_time(base::TimeDelta::FromDays(14));
   1239 
   1240   // Use a mock clock to ensure that events are not recorded on the wrong day
   1241   // when the test is run close to local midnight.  Note: Ownership is passed
   1242   // to the policy, but we still keep a pointer locally.  The policy will take
   1243   // care of destruction; this is safe since the policy outlives all our
   1244   // accesses to the mock clock.
   1245   base::SimpleTestClock* mock_clock = new base::SimpleTestClock();
   1246   mock_clock->SetNow(base::Time::Now().LocalMidnight() +
   1247                      base::TimeDelta::FromHours(12));
   1248   policy->SetClockForTesting(scoped_ptr<base::Clock>(mock_clock));
   1249 
   1250   // Record some actions
   1251   scoped_refptr<Action> action =
   1252       new Action("punky",
   1253                  mock_clock->Now() - base::TimeDelta::FromMinutes(40),
   1254                  Action::ACTION_API_CALL,
   1255                  "brewster");
   1256   action->mutable_args()->AppendString("woof");
   1257   policy->ProcessAction(action);
   1258 
   1259   action = new Action("punky",
   1260                       mock_clock->Now() - base::TimeDelta::FromMinutes(30),
   1261                       Action::ACTION_API_CALL,
   1262                       "brewster");
   1263   action->mutable_args()->AppendString("meow");
   1264   policy->ProcessAction(action);
   1265 
   1266   action = new Action("punky",
   1267                       mock_clock->Now() - base::TimeDelta::FromMinutes(20),
   1268                       Action::ACTION_API_CALL,
   1269                       "extension.sendMessage");
   1270   action->mutable_args()->AppendString("not");
   1271   action->mutable_args()->AppendString("stripped");
   1272   policy->ProcessAction(action);
   1273 
   1274   action =
   1275       new Action("punky", mock_clock->Now(), Action::ACTION_DOM_ACCESS, "lets");
   1276   action->mutable_args()->AppendString("vamoose");
   1277   action->set_page_url(GURL("http://www.google.com"));
   1278   policy->ProcessAction(action);
   1279 
   1280   action = new Action(
   1281       "scoobydoo", mock_clock->Now(), Action::ACTION_DOM_ACCESS, "lets");
   1282   action->mutable_args()->AppendString("vamoose");
   1283   action->set_page_url(GURL("http://www.google.com"));
   1284   policy->ProcessAction(action);
   1285 
   1286   CheckReadData(
   1287       policy,
   1288       "punky",
   1289       0,
   1290       base::Bind(&CountingPolicyTest::Arguments_GetTodaysActions));
   1291 
   1292   policy->DeleteDatabase();
   1293 
   1294   CheckReadFilteredData(
   1295       policy,
   1296       "",
   1297       Action::ACTION_ANY,
   1298       "",
   1299       "",
   1300       "",
   1301       -1,
   1302       base::Bind(
   1303           &CountingPolicyTest::RetrieveActions_FetchFilteredActions0));
   1304 
   1305   // The following code tests that the caches of url and string tables were
   1306   // cleared by the deletion above.
   1307   // https://code.google.com/p/chromium/issues/detail?id=341674.
   1308   action =
   1309     new Action("punky", mock_clock->Now(), Action::ACTION_DOM_ACCESS, "lets");
   1310   action->mutable_args()->AppendString("vamoose");
   1311   action->set_page_url(GURL("http://www.google.com"));
   1312   policy->ProcessAction(action);
   1313 
   1314   CheckReadData(
   1315       policy,
   1316       "",
   1317       -1,
   1318       base::Bind(&CountingPolicyTest::Arguments_GetSinglesAction));
   1319 
   1320   policy->DeleteDatabase();
   1321 
   1322   CheckReadFilteredData(
   1323       policy,
   1324       "",
   1325       Action::ACTION_ANY,
   1326       "",
   1327       "",
   1328       "",
   1329       -1,
   1330       base::Bind(
   1331           &CountingPolicyTest::RetrieveActions_FetchFilteredActions0));
   1332 
   1333   policy->Close();
   1334 }
   1335 
   1336 // Tests that duplicate rows in the activity log database are handled properly
   1337 // when updating counts.
   1338 TEST_F(CountingPolicyTest, DuplicateRows) {
   1339   CountingPolicy* policy = new CountingPolicy(profile_.get());
   1340   policy->Init();
   1341   base::SimpleTestClock* mock_clock = new base::SimpleTestClock();
   1342   mock_clock->SetNow(base::Time::Now().LocalMidnight() +
   1343                      base::TimeDelta::FromHours(12));
   1344   policy->SetClockForTesting(scoped_ptr<base::Clock>(mock_clock));
   1345 
   1346   // Record two actions with distinct URLs.
   1347   scoped_refptr<Action> action;
   1348   action = new Action(
   1349       "punky", mock_clock->Now(), Action::ACTION_API_CALL, "brewster");
   1350   action->set_page_url(GURL("http://www.google.com"));
   1351   policy->ProcessAction(action);
   1352 
   1353   action = new Action(
   1354       "punky", mock_clock->Now(), Action::ACTION_API_CALL, "brewster");
   1355   action->set_page_url(GURL("http://www.google.co.uk"));
   1356   policy->ProcessAction(action);
   1357 
   1358   // Manipulate the database to clear the URLs, so that we end up with
   1359   // duplicate rows.
   1360   std::vector<GURL> no_url_restrictions;
   1361   policy->RemoveURLs(no_url_restrictions);
   1362 
   1363   // Record one more action, with no URL.  This should increment the count on
   1364   // one, and exactly one, of the existing rows.
   1365   action = new Action(
   1366       "punky", mock_clock->Now(), Action::ACTION_API_CALL, "brewster");
   1367   policy->ProcessAction(action);
   1368 
   1369   CheckReadData(
   1370       policy,
   1371       "punky",
   1372       0,
   1373       base::Bind(&CountingPolicyTest::CheckDuplicates));
   1374   policy->Close();
   1375 }
   1376 
   1377 TEST_F(CountingPolicyTest, RemoveActions) {
   1378   ActivityLogDatabasePolicy* policy = new CountingPolicy(profile_.get());
   1379   policy->Init();
   1380 
   1381   std::vector<int64> action_ids;
   1382 
   1383   CheckRemoveActions(
   1384       policy, action_ids, base::Bind(&CountingPolicyTest::NoActionsDeleted));
   1385 
   1386   action_ids.push_back(-1);
   1387   action_ids.push_back(-10);
   1388   action_ids.push_back(0);
   1389   action_ids.push_back(5);
   1390   action_ids.push_back(10);
   1391   CheckRemoveActions(
   1392       policy, action_ids, base::Bind(&CountingPolicyTest::NoActionsDeleted));
   1393   action_ids.clear();
   1394 
   1395   for (int i = 0; i < 50; i++) {
   1396     action_ids.push_back(i + 3);
   1397   }
   1398   CheckRemoveActions(
   1399       policy, action_ids, base::Bind(&CountingPolicyTest::NoActionsDeleted));
   1400   action_ids.clear();
   1401 
   1402   // CheckRemoveActions pushes two actions to the Activity Log database with IDs
   1403   // 1 and 2.
   1404   action_ids.push_back(1);
   1405   action_ids.push_back(2);
   1406   CheckRemoveActions(
   1407       policy, action_ids, base::Bind(&CountingPolicyTest::AllActionsDeleted));
   1408   action_ids.clear();
   1409 
   1410   action_ids.push_back(1);
   1411   CheckRemoveActions(
   1412       policy, action_ids, base::Bind(&CountingPolicyTest::Action1Deleted));
   1413   action_ids.clear();
   1414 
   1415   action_ids.push_back(2);
   1416   CheckRemoveActions(
   1417       policy, action_ids, base::Bind(&CountingPolicyTest::Action2Deleted));
   1418   action_ids.clear();
   1419 
   1420   policy->Close();
   1421 }
   1422 
   1423 }  // namespace extensions
   1424