| Index: chrome/browser/extensions/activity_log/counting_policy_unittest.cc | 
| diff --git a/chrome/browser/extensions/activity_log/fullstream_ui_policy_unittest.cc b/chrome/browser/extensions/activity_log/counting_policy_unittest.cc | 
| similarity index 64% | 
| copy from chrome/browser/extensions/activity_log/fullstream_ui_policy_unittest.cc | 
| copy to chrome/browser/extensions/activity_log/counting_policy_unittest.cc | 
| index 0421357a93013ccbfb5f35cda6e4ea82c27f11b4..37b0fb266cac161c3c3473ed70324092a1275871 100644 | 
| --- a/chrome/browser/extensions/activity_log/fullstream_ui_policy_unittest.cc | 
| +++ b/chrome/browser/extensions/activity_log/counting_policy_unittest.cc | 
| @@ -6,10 +6,11 @@ | 
| #include "base/command_line.h" | 
| #include "base/memory/scoped_ptr.h" | 
| #include "base/run_loop.h" | 
| +#include "base/strings/stringprintf.h" | 
| #include "base/synchronization/waitable_event.h" | 
| #include "base/test/simple_test_clock.h" | 
| #include "chrome/browser/extensions/activity_log/activity_log.h" | 
| -#include "chrome/browser/extensions/activity_log/fullstream_ui_policy.h" | 
| +#include "chrome/browser/extensions/activity_log/counting_policy.h" | 
| #include "chrome/browser/extensions/extension_service.h" | 
| #include "chrome/browser/extensions/test_extension_system.h" | 
| #include "chrome/common/chrome_constants.h" | 
| @@ -29,9 +30,9 @@ | 
|  | 
| namespace extensions { | 
|  | 
| -class FullStreamUIPolicyTest : public testing::Test { | 
| +class CountingPolicyTest : public testing::Test { | 
| public: | 
| -  FullStreamUIPolicyTest() | 
| +  CountingPolicyTest() | 
| : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP), | 
| saved_cmdline_(CommandLine::NO_PROGRAM) { | 
| #if defined OS_CHROMEOS | 
| @@ -49,7 +50,7 @@ class FullStreamUIPolicyTest : public testing::Test { | 
| (&command_line, base::FilePath(), false); | 
| } | 
|  | 
| -  virtual ~FullStreamUIPolicyTest() { | 
| +  virtual ~CountingPolicyTest() { | 
| #if defined OS_CHROMEOS | 
| test_user_manager_.reset(); | 
| #endif | 
| @@ -73,14 +74,14 @@ class FullStreamUIPolicyTest : public testing::Test { | 
| policy->ReadData( | 
| extension_id, | 
| day, | 
| -        base::Bind(&FullStreamUIPolicyTest::CheckWrapper, | 
| +        base::Bind(&CountingPolicyTest::CheckWrapper, | 
| checker, | 
| base::MessageLoop::current()->QuitClosure())); | 
|  | 
| // Set up a timeout that will trigger after 5 seconds; if we haven't | 
| // received any results by then assume that the test is broken. | 
| base::CancelableClosure timeout( | 
| -        base::Bind(&FullStreamUIPolicyTest::TimeoutCallback)); | 
| +        base::Bind(&CountingPolicyTest::TimeoutCallback)); | 
| base::MessageLoop::current()->PostDelayedTask( | 
| FROM_HERE, timeout.callback(), base::TimeDelta::FromSeconds(5)); | 
|  | 
| @@ -104,43 +105,55 @@ class FullStreamUIPolicyTest : public testing::Test { | 
| FAIL() << "Policy test timed out waiting for results"; | 
| } | 
|  | 
| -  static void RetrieveActions_LogAndFetchActions( | 
| -      scoped_ptr<std::vector<scoped_refptr<Action> > > i) { | 
| -    ASSERT_EQ(2, static_cast<int>(i->size())); | 
| -  } | 
| - | 
| -  static void Arguments_Present(scoped_ptr<Action::ActionVector> i) { | 
| +  static void Arguments_Stripped(scoped_ptr<Action::ActionVector> i) { | 
| scoped_refptr<Action> last = i->front(); | 
| std::string args = | 
| "ID=odlameecjipmbmbejkplpemijjgpljce CATEGORY=api_call " | 
| -        "API=extension.connect ARGS=[\"hello\",\"world\"]"; | 
| +        "API=extension.connect ARGS=[\"hello\",\"world\"] COUNT=1"; | 
| ASSERT_EQ(args, last->PrintForDebug()); | 
| } | 
|  | 
| static void Arguments_GetTodaysActions( | 
| scoped_ptr<Action::ActionVector> actions) { | 
| +    std::string api_stripped_print = | 
| +        "ID=punky CATEGORY=api_call API=brewster COUNT=2"; | 
| std::string api_print = | 
| -        "ID=punky CATEGORY=api_call API=brewster ARGS=[\"woof\"]"; | 
| +        "ID=punky CATEGORY=api_call API=extension.sendMessage " | 
| +        "ARGS=[\"not\",\"stripped\"] COUNT=1"; | 
| std::string dom_print = | 
| "ID=punky CATEGORY=dom_access API=lets ARGS=[\"vamoose\"] " | 
| -        "PAGE_URL=http://www.google.com/"; | 
| -    ASSERT_EQ(2, static_cast<int>(actions->size())); | 
| +        "PAGE_URL=http://www.google.com/ COUNT=1"; | 
| +    ASSERT_EQ(3, static_cast<int>(actions->size())); | 
| ASSERT_EQ(dom_print, actions->at(0)->PrintForDebug()); | 
| ASSERT_EQ(api_print, actions->at(1)->PrintForDebug()); | 
| +    ASSERT_EQ(api_stripped_print, actions->at(2)->PrintForDebug()); | 
| } | 
|  | 
| static void Arguments_GetOlderActions( | 
| scoped_ptr<Action::ActionVector> actions) { | 
| std::string api_print = | 
| -        "ID=punky CATEGORY=api_call API=brewster ARGS=[\"woof\"]"; | 
| +        "ID=punky CATEGORY=api_call API=brewster COUNT=1"; | 
| std::string dom_print = | 
| "ID=punky CATEGORY=dom_access API=lets ARGS=[\"vamoose\"] " | 
| -        "PAGE_URL=http://www.google.com/"; | 
| +        "PAGE_URL=http://www.google.com/ COUNT=1"; | 
| ASSERT_EQ(2, static_cast<int>(actions->size())); | 
| ASSERT_EQ(dom_print, actions->at(0)->PrintForDebug()); | 
| ASSERT_EQ(api_print, actions->at(1)->PrintForDebug()); | 
| } | 
|  | 
| +  static void Arguments_CheckMergeCount( | 
| +      int count, | 
| +      scoped_ptr<Action::ActionVector> actions) { | 
| +    std::string api_print = base::StringPrintf( | 
| +        "ID=punky CATEGORY=api_call API=brewster COUNT=%d", count); | 
| +    if (count > 0) { | 
| +      ASSERT_EQ(1u, actions->size()); | 
| +      ASSERT_EQ(api_print, actions->at(0)->PrintForDebug()); | 
| +    } else { | 
| +      ASSERT_EQ(0u, actions->size()); | 
| +    } | 
| +  } | 
| + | 
| protected: | 
| ExtensionService* extension_service_; | 
| scoped_ptr<TestingProfile> profile_; | 
| @@ -158,8 +171,8 @@ class FullStreamUIPolicyTest : public testing::Test { | 
| #endif | 
| }; | 
|  | 
| -TEST_F(FullStreamUIPolicyTest, Construct) { | 
| -  ActivityLogPolicy* policy = new FullStreamUIPolicy(profile_.get()); | 
| +TEST_F(CountingPolicyTest, Construct) { | 
| +  ActivityLogPolicy* policy = new CountingPolicy(profile_.get()); | 
| scoped_refptr<const Extension> extension = | 
| ExtensionBuilder() | 
| .SetManifest(DictionaryBuilder() | 
| @@ -178,45 +191,8 @@ TEST_F(FullStreamUIPolicyTest, Construct) { | 
| policy->Close(); | 
| } | 
|  | 
| -TEST_F(FullStreamUIPolicyTest, LogAndFetchActions) { | 
| -  ActivityLogPolicy* policy = new FullStreamUIPolicy(profile_.get()); | 
| -  scoped_refptr<const Extension> extension = | 
| -      ExtensionBuilder() | 
| -          .SetManifest(DictionaryBuilder() | 
| -                       .Set("name", "Test extension") | 
| -                       .Set("version", "1.0.0") | 
| -                       .Set("manifest_version", 2)) | 
| -          .Build(); | 
| -  extension_service_->AddExtension(extension.get()); | 
| -  GURL gurl("http://www.google.com"); | 
| - | 
| -  // Write some API calls | 
| -  scoped_refptr<Action> action_api = new Action(extension->id(), | 
| -                                                base::Time::Now(), | 
| -                                                Action::ACTION_API_CALL, | 
| -                                                "tabs.testMethod"); | 
| -  action_api->set_args(make_scoped_ptr(new base::ListValue())); | 
| -  policy->ProcessAction(action_api); | 
| - | 
| -  scoped_refptr<Action> action_dom = new Action(extension->id(), | 
| -                                                base::Time::Now(), | 
| -                                                Action::ACTION_DOM_ACCESS, | 
| -                                                "document.write"); | 
| -  action_dom->set_args(make_scoped_ptr(new base::ListValue())); | 
| -  action_dom->set_page_url(gurl); | 
| -  policy->ProcessAction(action_dom); | 
| - | 
| -  CheckReadData( | 
| -      policy, | 
| -      extension->id(), | 
| -      0, | 
| -      base::Bind(&FullStreamUIPolicyTest::RetrieveActions_LogAndFetchActions)); | 
| - | 
| -  policy->Close(); | 
| -} | 
| - | 
| -TEST_F(FullStreamUIPolicyTest, LogWithArguments) { | 
| -  ActivityLogPolicy* policy = new FullStreamUIPolicy(profile_.get()); | 
| +TEST_F(CountingPolicyTest, LogWithStrippedArguments) { | 
| +  ActivityLogPolicy* policy = new CountingPolicy(profile_.get()); | 
| scoped_refptr<const Extension> extension = | 
| ExtensionBuilder() | 
| .SetManifest(DictionaryBuilder() | 
| @@ -239,12 +215,15 @@ TEST_F(FullStreamUIPolicyTest, LogWithArguments) { | 
| CheckReadData(policy, | 
| extension->id(), | 
| 0, | 
| -                base::Bind(&FullStreamUIPolicyTest::Arguments_Present)); | 
| +                base::Bind(&CountingPolicyTest::Arguments_Stripped)); | 
| policy->Close(); | 
| } | 
|  | 
| -TEST_F(FullStreamUIPolicyTest, GetTodaysActions) { | 
| -  ActivityLogPolicy* policy = new FullStreamUIPolicy(profile_.get()); | 
| +TEST_F(CountingPolicyTest, GetTodaysActions) { | 
| +  CountingPolicy* policy = new CountingPolicy(profile_.get()); | 
| +  // Disable row expiration for this test by setting a time before any actions | 
| +  // we generate. | 
| +  policy->set_retention_time(base::TimeDelta::FromDays(14)); | 
|  | 
| // Use a mock clock to ensure that events are not recorded on the wrong day | 
| // when the test is run close to local midnight. | 
| @@ -262,6 +241,21 @@ TEST_F(FullStreamUIPolicyTest, GetTodaysActions) { | 
| action->mutable_args()->AppendString("woof"); | 
| policy->ProcessAction(action); | 
|  | 
| +  action = new Action("punky", | 
| +                      mock_clock.Now() - base::TimeDelta::FromMinutes(30), | 
| +                      Action::ACTION_API_CALL, | 
| +                      "brewster"); | 
| +  action->mutable_args()->AppendString("meow"); | 
| +  policy->ProcessAction(action); | 
| + | 
| +  action = new Action("punky", | 
| +                      mock_clock.Now() - base::TimeDelta::FromMinutes(20), | 
| +                      Action::ACTION_API_CALL, | 
| +                      "extension.sendMessage"); | 
| +  action->mutable_args()->AppendString("not"); | 
| +  action->mutable_args()->AppendString("stripped"); | 
| +  policy->ProcessAction(action); | 
| + | 
| action = | 
| new Action("punky", mock_clock.Now(), Action::ACTION_DOM_ACCESS, "lets"); | 
| action->mutable_args()->AppendString("vamoose"); | 
| @@ -278,13 +272,14 @@ TEST_F(FullStreamUIPolicyTest, GetTodaysActions) { | 
| policy, | 
| "punky", | 
| 0, | 
| -      base::Bind(&FullStreamUIPolicyTest::Arguments_GetTodaysActions)); | 
| +      base::Bind(&CountingPolicyTest::Arguments_GetTodaysActions)); | 
| policy->Close(); | 
| } | 
|  | 
| // Check that we can read back less recent actions in the db. | 
| -TEST_F(FullStreamUIPolicyTest, GetOlderActions) { | 
| -  ActivityLogPolicy* policy = new FullStreamUIPolicy(profile_.get()); | 
| +TEST_F(CountingPolicyTest, GetOlderActions) { | 
| +  CountingPolicy* policy = new CountingPolicy(profile_.get()); | 
| +  policy->set_retention_time(base::TimeDelta::FromDays(14)); | 
|  | 
| // Use a mock clock to ensure that events are not recorded on the wrong day | 
| // when the test is run close to local midnight. | 
| @@ -331,7 +326,78 @@ TEST_F(FullStreamUIPolicyTest, GetOlderActions) { | 
| policy, | 
| "punky", | 
| 3, | 
| -      base::Bind(&FullStreamUIPolicyTest::Arguments_GetOlderActions)); | 
| +      base::Bind(&CountingPolicyTest::Arguments_GetOlderActions)); | 
| + | 
| +  policy->Close(); | 
| +} | 
| + | 
| +// Check that merging of actions only occurs within the same day, not across | 
| +// days, and that old data can be expired from the database. | 
| +TEST_F(CountingPolicyTest, MergingAndExpiring) { | 
| +  CountingPolicy* policy = new CountingPolicy(profile_.get()); | 
| +  // Initially disable expiration by setting a retention time before any | 
| +  // actions we generate. | 
| +  policy->set_retention_time(base::TimeDelta::FromDays(14)); | 
| + | 
| +  // Use a mock clock to ensure that events are not recorded on the wrong day | 
| +  // when the test is run close to local midnight. | 
| +  base::SimpleTestClock mock_clock; | 
| +  mock_clock.SetNow(base::Time::Now().LocalMidnight() + | 
| +                    base::TimeDelta::FromHours(12)); | 
| +  policy->SetClockForTesting(&mock_clock); | 
| + | 
| +  // The first two actions should be merged; the last one is on a separate day | 
| +  // and should not be. | 
| +  scoped_refptr<Action> action = | 
| +      new Action("punky", | 
| +                 mock_clock.Now() - base::TimeDelta::FromDays(3) - | 
| +                     base::TimeDelta::FromMinutes(40), | 
| +                 Action::ACTION_API_CALL, | 
| +                 "brewster"); | 
| +  policy->ProcessAction(action); | 
| + | 
| +  action = new Action("punky", | 
| +                      mock_clock.Now() - base::TimeDelta::FromDays(3) - | 
| +                          base::TimeDelta::FromMinutes(20), | 
| +                      Action::ACTION_API_CALL, | 
| +                      "brewster"); | 
| +  policy->ProcessAction(action); | 
| + | 
| +  action = new Action("punky", | 
| +                      mock_clock.Now() - base::TimeDelta::FromDays(2) - | 
| +                          base::TimeDelta::FromMinutes(20), | 
| +                      Action::ACTION_API_CALL, | 
| +                      "brewster"); | 
| +  policy->ProcessAction(action); | 
| + | 
| +  CheckReadData(policy, | 
| +                "punky", | 
| +                3, | 
| +                base::Bind(&CountingPolicyTest::Arguments_CheckMergeCount, 2)); | 
| +  CheckReadData(policy, | 
| +                "punky", | 
| +                2, | 
| +                base::Bind(&CountingPolicyTest::Arguments_CheckMergeCount, 1)); | 
| + | 
| +  // Clean actions before midnight two days ago.  Force expiration to run by | 
| +  // clearing last_database_cleaning_time_ and submitting a new action. | 
| +  policy->set_retention_time(base::TimeDelta::FromDays(2)); | 
| +  policy->last_database_cleaning_time_ = base::Time(); | 
| +  action = new Action("punky", | 
| +                      mock_clock.Now(), | 
| +                      Action::ACTION_API_CALL, | 
| +                      "brewster"); | 
| +  policy->ProcessAction(action); | 
| + | 
| +  CheckReadData(policy, | 
| +                "punky", | 
| +                3, | 
| +                base::Bind(&CountingPolicyTest::Arguments_CheckMergeCount, 0)); | 
| +  CheckReadData(policy, | 
| +                "punky", | 
| +                2, | 
| +                base::Bind(&CountingPolicyTest::Arguments_CheckMergeCount, 1)); | 
| + | 
| policy->Close(); | 
| } | 
|  | 
|  |