Upstream version 10.39.225.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/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