Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / activity_log / counting_policy_unittest.cc
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/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