- add sources.
[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/common/extensions/extension_builder.h"
21 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
22 #include "chrome/test/base/testing_profile.h"
23 #include "content/public/test/test_browser_thread_bundle.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 namespace extensions {
34
35 class CountingPolicyTest : public testing::Test {
36  public:
37   CountingPolicyTest()
38       : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP),
39         saved_cmdline_(CommandLine::NO_PROGRAM) {
40 #if defined OS_CHROMEOS
41     test_user_manager_.reset(new chromeos::ScopedTestUserManager());
42 #endif
43     CommandLine command_line(CommandLine::NO_PROGRAM);
44     saved_cmdline_ = *CommandLine::ForCurrentProcess();
45     profile_.reset(new TestingProfile());
46     CommandLine::ForCurrentProcess()->AppendSwitch(
47         switches::kEnableExtensionActivityLogging);
48     extension_service_ = static_cast<TestExtensionSystem*>(
49         ExtensionSystem::Get(profile_.get()))->CreateExtensionService
50             (&command_line, base::FilePath(), false);
51   }
52
53   virtual ~CountingPolicyTest() {
54 #if defined OS_CHROMEOS
55     test_user_manager_.reset();
56 #endif
57     base::RunLoop().RunUntilIdle();
58     profile_.reset(NULL);
59     base::RunLoop().RunUntilIdle();
60     // Restore the original command line and undo the affects of SetUp().
61     *CommandLine::ForCurrentProcess() = saved_cmdline_;
62   }
63
64   // Wait for the task queue for the specified thread to empty.
65   void WaitOnThread(const content::BrowserThread::ID& thread) {
66     BrowserThread::PostTaskAndReply(
67         thread,
68         FROM_HERE,
69         base::Bind(&base::DoNothing),
70         base::MessageLoop::current()->QuitClosure());
71     base::MessageLoop::current()->Run();
72   }
73
74   // A wrapper function for CheckReadFilteredData, so that we don't need to
75   // enter empty string values for parameters we don't care about.
76   void CheckReadData(
77       ActivityLogDatabasePolicy* policy,
78       const std::string& extension_id,
79       int day,
80       const base::Callback<void(scoped_ptr<Action::ActionVector>)>& checker) {
81     CheckReadFilteredData(
82         policy, extension_id, Action::ACTION_ANY, "", "", "", day, checker);
83   }
84
85   // A helper function to call ReadFilteredData on a policy object and wait for
86   // the results to be processed.
87   void CheckReadFilteredData(
88       ActivityLogDatabasePolicy* policy,
89       const std::string& extension_id,
90       const Action::ActionType type,
91       const std::string& api_name,
92       const std::string& page_url,
93       const std::string& arg_url,
94       int day,
95       const base::Callback<void(scoped_ptr<Action::ActionVector>)>& checker) {
96     // Submit a request to the policy to read back some data, and call the
97     // checker function when results are available.  This will happen on the
98     // database thread.
99     policy->ReadFilteredData(
100         extension_id,
101         type,
102         api_name,
103         page_url,
104         arg_url,
105         day,
106         base::Bind(&CountingPolicyTest::CheckWrapper,
107                    checker,
108                    base::MessageLoop::current()->QuitClosure()));
109
110     // Set up a timeout for receiving results; if we haven't received anything
111     // when the timeout triggers then assume that the test is broken.
112     base::CancelableClosure timeout(
113         base::Bind(&CountingPolicyTest::TimeoutCallback));
114     base::MessageLoop::current()->PostDelayedTask(
115         FROM_HERE, timeout.callback(), TestTimeouts::action_timeout());
116
117     // Wait for results; either the checker or the timeout callbacks should
118     // cause the main loop to exit.
119     base::MessageLoop::current()->Run();
120
121     timeout.Cancel();
122   }
123
124   // A helper function which verifies that the string_ids and url_ids tables in
125   // the database have the specified sizes.
126   static void CheckStringTableSizes(CountingPolicy* policy,
127                                     int string_size,
128                                     int url_size) {
129     sql::Connection* db = policy->GetDatabaseConnection();
130     sql::Statement statement1(db->GetCachedStatement(
131         sql::StatementID(SQL_FROM_HERE), "SELECT COUNT(*) FROM string_ids"));
132     ASSERT_TRUE(statement1.Step());
133     ASSERT_EQ(string_size, statement1.ColumnInt(0));
134
135     sql::Statement statement2(db->GetCachedStatement(
136         sql::StatementID(SQL_FROM_HERE), "SELECT COUNT(*) FROM url_ids"));
137     ASSERT_TRUE(statement2.Step());
138     ASSERT_EQ(url_size, statement2.ColumnInt(0));
139   }
140
141   // Checks that the number of queued actions to be written out does not exceed
142   // kSizeThresholdForFlush.  Runs on the database thread.
143   static void CheckQueueSize(CountingPolicy* policy) {
144     // This should be updated if kSizeThresholdForFlush in activity_database.cc
145     // changes.
146     ASSERT_LE(policy->queued_actions_.size(), 200U);
147   }
148
149   static void CheckWrapper(
150       const base::Callback<void(scoped_ptr<Action::ActionVector>)>& checker,
151       const base::Closure& done,
152       scoped_ptr<Action::ActionVector> results) {
153     checker.Run(results.Pass());
154     done.Run();
155   }
156
157   static void TimeoutCallback() {
158     base::MessageLoop::current()->QuitWhenIdle();
159     FAIL() << "Policy test timed out waiting for results";
160   }
161
162   static void RetrieveActions_FetchFilteredActions0(
163       scoped_ptr<std::vector<scoped_refptr<Action> > > i) {
164     ASSERT_EQ(0, static_cast<int>(i->size()));
165   }
166
167   static void RetrieveActions_FetchFilteredActions1(
168       scoped_ptr<std::vector<scoped_refptr<Action> > > i) {
169     ASSERT_EQ(1, static_cast<int>(i->size()));
170   }
171
172   static void RetrieveActions_FetchFilteredActions2(
173       scoped_ptr<std::vector<scoped_refptr<Action> > > i) {
174     ASSERT_EQ(2, static_cast<int>(i->size()));
175   }
176
177   static void RetrieveActions_FetchFilteredActions300(
178       scoped_ptr<std::vector<scoped_refptr<Action> > > i) {
179     ASSERT_EQ(300, static_cast<int>(i->size()));
180   }
181
182   static void Arguments_Stripped(scoped_ptr<Action::ActionVector> i) {
183     scoped_refptr<Action> last = i->front();
184     CheckAction(*last, "odlameecjipmbmbejkplpemijjgpljce",
185                 Action::ACTION_API_CALL, "extension.connect",
186                 "[\"hello\",\"world\"]", "", "", "", 1);
187   }
188
189   static void Arguments_GetTodaysActions(
190       scoped_ptr<Action::ActionVector> actions) {
191     ASSERT_EQ(3, static_cast<int>(actions->size()));
192     CheckAction(*actions->at(0), "punky", Action::ACTION_API_CALL, "brewster",
193                 "", "", "", "", 2);
194     CheckAction(*actions->at(1), "punky", Action::ACTION_DOM_ACCESS, "lets",
195                 "", "http://www.google.com/", "", "", 1);
196     CheckAction(*actions->at(2), "punky", Action::ACTION_API_CALL,
197                 "extension.sendMessage", "[\"not\",\"stripped\"]", "", "", "",
198                 1);
199   }
200
201   static void Arguments_GetOlderActions(
202       scoped_ptr<Action::ActionVector> actions) {
203     ASSERT_EQ(2, static_cast<int>(actions->size()));
204     CheckAction(*actions->at(0), "punky", Action::ACTION_DOM_ACCESS, "lets",
205                 "", "http://www.google.com/", "", "", 1);
206     CheckAction(*actions->at(1), "punky", Action::ACTION_API_CALL, "brewster",
207                 "", "", "", "", 1);
208   }
209
210   static void Arguments_CheckMergeCount(
211       int count,
212       scoped_ptr<Action::ActionVector> actions) {
213     if (count > 0) {
214       ASSERT_EQ(1u, actions->size());
215       CheckAction(*actions->at(0), "punky", Action::ACTION_API_CALL, "brewster",
216                   "", "", "", "", count);
217     } else {
218       ASSERT_EQ(0u, actions->size());
219     }
220   }
221
222   static void Arguments_CheckMergeCountAndTime(
223       int count,
224       const base::Time& time,
225       scoped_ptr<Action::ActionVector> actions) {
226     if (count > 0) {
227       ASSERT_EQ(1u, actions->size());
228       CheckAction(*actions->at(0), "punky", Action::ACTION_API_CALL, "brewster",
229                   "", "", "", "", count);
230       ASSERT_EQ(time, actions->at(0)->time());
231     } else {
232       ASSERT_EQ(0u, actions->size());
233     }
234   }
235
236   static void AllURLsRemoved(scoped_ptr<Action::ActionVector> actions) {
237     ASSERT_EQ(2, static_cast<int>(actions->size()));
238     CheckAction(*actions->at(0), "punky", Action::ACTION_DOM_ACCESS, "lets",
239                 "", "", "", "", 1);
240     CheckAction(*actions->at(1), "punky", Action::ACTION_DOM_ACCESS, "lets",
241                 "", "", "", "", 1);
242   }
243
244   static void SomeURLsRemoved(scoped_ptr<Action::ActionVector> actions) {
245     // These will be in the vector in reverse time order.
246     ASSERT_EQ(5, static_cast<int>(actions->size()));
247     CheckAction(*actions->at(0), "punky", Action::ACTION_DOM_ACCESS, "lets",
248                 "", "http://www.google.com/", "Google",
249                 "http://www.args-url.com/", 1);
250     CheckAction(*actions->at(1), "punky", Action::ACTION_DOM_ACCESS, "lets",
251                 "", "http://www.google.com/", "Google", "", 1);
252     CheckAction(*actions->at(2), "punky", Action::ACTION_DOM_ACCESS, "lets",
253                 "", "", "", "", 1);
254     CheckAction(*actions->at(3), "punky", Action::ACTION_DOM_ACCESS, "lets",
255                 "", "", "", "http://www.google.com/", 1);
256     CheckAction(*actions->at(4), "punky", Action::ACTION_DOM_ACCESS, "lets",
257                 "", "", "", "", 1);
258   }
259
260   static void CheckDuplicates(scoped_ptr<Action::ActionVector> actions) {
261     ASSERT_EQ(2u, actions->size());
262     int total_count = 0;
263     for (size_t i = 0; i < actions->size(); i++) {
264       total_count += actions->at(i)->count();
265     }
266     ASSERT_EQ(3, total_count);
267   }
268
269   static void CheckAction(const Action& action,
270                           const std::string& expected_id,
271                           const Action::ActionType& expected_type,
272                           const std::string& expected_api_name,
273                           const std::string& expected_args_str,
274                           const std::string& expected_page_url,
275                           const std::string& expected_page_title,
276                           const std::string& expected_arg_url,
277                           int expected_count) {
278     ASSERT_EQ(expected_id, action.extension_id());
279     ASSERT_EQ(expected_type, action.action_type());
280     ASSERT_EQ(expected_api_name, action.api_name());
281     ASSERT_EQ(expected_args_str,
282               ActivityLogPolicy::Util::Serialize(action.args()));
283     ASSERT_EQ(expected_page_url, action.SerializePageUrl());
284     ASSERT_EQ(expected_page_title, action.page_title());
285     ASSERT_EQ(expected_arg_url, action.SerializeArgUrl());
286     ASSERT_EQ(expected_count, action.count());
287   }
288
289  protected:
290   ExtensionService* extension_service_;
291   scoped_ptr<TestingProfile> profile_;
292   content::TestBrowserThreadBundle thread_bundle_;
293   // Used to preserve a copy of the original command line.
294   // The test framework will do this itself as well. However, by then,
295   // it is too late to call ActivityLog::RecomputeLoggingIsEnabled() in
296   // TearDown().
297   CommandLine saved_cmdline_;
298
299 #if defined OS_CHROMEOS
300   chromeos::ScopedTestDeviceSettingsService test_device_settings_service_;
301   chromeos::ScopedTestCrosSettings test_cros_settings_;
302   scoped_ptr<chromeos::ScopedTestUserManager> test_user_manager_;
303 #endif
304 };
305
306 TEST_F(CountingPolicyTest, Construct) {
307   ActivityLogDatabasePolicy* policy = new CountingPolicy(profile_.get());
308   policy->Init();
309   scoped_refptr<const Extension> extension =
310       ExtensionBuilder()
311           .SetManifest(DictionaryBuilder()
312                        .Set("name", "Test extension")
313                        .Set("version", "1.0.0")
314                        .Set("manifest_version", 2))
315           .Build();
316   extension_service_->AddExtension(extension.get());
317   scoped_ptr<base::ListValue> args(new base::ListValue());
318   scoped_refptr<Action> action = new Action(extension->id(),
319                                             base::Time::Now(),
320                                             Action::ACTION_API_CALL,
321                                             "tabs.testMethod");
322   action->set_args(args.Pass());
323   policy->ProcessAction(action);
324   policy->Close();
325 }
326
327 TEST_F(CountingPolicyTest, LogWithStrippedArguments) {
328   ActivityLogDatabasePolicy* policy = new CountingPolicy(profile_.get());
329   policy->Init();
330   scoped_refptr<const Extension> extension =
331       ExtensionBuilder()
332           .SetManifest(DictionaryBuilder()
333                        .Set("name", "Test extension")
334                        .Set("version", "1.0.0")
335                        .Set("manifest_version", 2))
336           .Build();
337   extension_service_->AddExtension(extension.get());
338
339   scoped_ptr<base::ListValue> args(new base::ListValue());
340   args->Set(0, new base::StringValue("hello"));
341   args->Set(1, new base::StringValue("world"));
342   scoped_refptr<Action> action = new Action(extension->id(),
343                                             base::Time::Now(),
344                                             Action::ACTION_API_CALL,
345                                             "extension.connect");
346   action->set_args(args.Pass());
347
348   policy->ProcessAction(action);
349   CheckReadData(policy,
350                 extension->id(),
351                 0,
352                 base::Bind(&CountingPolicyTest::Arguments_Stripped));
353   policy->Close();
354 }
355
356 TEST_F(CountingPolicyTest, GetTodaysActions) {
357   CountingPolicy* policy = new CountingPolicy(profile_.get());
358   policy->Init();
359   // Disable row expiration for this test by setting a time before any actions
360   // we generate.
361   policy->set_retention_time(base::TimeDelta::FromDays(14));
362
363   // Use a mock clock to ensure that events are not recorded on the wrong day
364   // when the test is run close to local midnight.  Note: Ownership is passed
365   // to the policy, but we still keep a pointer locally.  The policy will take
366   // care of destruction; this is safe since the policy outlives all our
367   // accesses to the mock clock.
368   base::SimpleTestClock* mock_clock = new base::SimpleTestClock();
369   mock_clock->SetNow(base::Time::Now().LocalMidnight() +
370                      base::TimeDelta::FromHours(12));
371   policy->SetClockForTesting(scoped_ptr<base::Clock>(mock_clock));
372
373   // Record some actions
374   scoped_refptr<Action> action =
375       new Action("punky",
376                  mock_clock->Now() - base::TimeDelta::FromMinutes(40),
377                  Action::ACTION_API_CALL,
378                  "brewster");
379   action->mutable_args()->AppendString("woof");
380   policy->ProcessAction(action);
381
382   action = new Action("punky",
383                       mock_clock->Now() - base::TimeDelta::FromMinutes(30),
384                       Action::ACTION_API_CALL,
385                       "brewster");
386   action->mutable_args()->AppendString("meow");
387   policy->ProcessAction(action);
388
389   action = new Action("punky",
390                       mock_clock->Now() - base::TimeDelta::FromMinutes(20),
391                       Action::ACTION_API_CALL,
392                       "extension.sendMessage");
393   action->mutable_args()->AppendString("not");
394   action->mutable_args()->AppendString("stripped");
395   policy->ProcessAction(action);
396
397   action =
398       new Action("punky", mock_clock->Now(), Action::ACTION_DOM_ACCESS, "lets");
399   action->mutable_args()->AppendString("vamoose");
400   action->set_page_url(GURL("http://www.google.com"));
401   policy->ProcessAction(action);
402
403   action = new Action(
404       "scoobydoo", mock_clock->Now(), Action::ACTION_DOM_ACCESS, "lets");
405   action->mutable_args()->AppendString("vamoose");
406   action->set_page_url(GURL("http://www.google.com"));
407   policy->ProcessAction(action);
408
409   CheckReadData(
410       policy,
411       "punky",
412       0,
413       base::Bind(&CountingPolicyTest::Arguments_GetTodaysActions));
414   policy->Close();
415 }
416
417 // Check that we can read back less recent actions in the db.
418 TEST_F(CountingPolicyTest, GetOlderActions) {
419   CountingPolicy* policy = new CountingPolicy(profile_.get());
420   policy->Init();
421   policy->set_retention_time(base::TimeDelta::FromDays(14));
422
423   // Use a mock clock to ensure that events are not recorded on the wrong day
424   // when the test is run close to local midnight.
425   base::SimpleTestClock* mock_clock = new base::SimpleTestClock();
426   mock_clock->SetNow(base::Time::Now().LocalMidnight() +
427                      base::TimeDelta::FromHours(12));
428   policy->SetClockForTesting(scoped_ptr<base::Clock>(mock_clock));
429
430   // Record some actions
431   scoped_refptr<Action> action =
432       new Action("punky",
433                  mock_clock->Now() - base::TimeDelta::FromDays(3) -
434                      base::TimeDelta::FromMinutes(40),
435                  Action::ACTION_API_CALL,
436                  "brewster");
437   action->mutable_args()->AppendString("woof");
438   policy->ProcessAction(action);
439
440   action = new Action("punky",
441                       mock_clock->Now() - base::TimeDelta::FromDays(3),
442                       Action::ACTION_DOM_ACCESS,
443                       "lets");
444   action->mutable_args()->AppendString("vamoose");
445   action->set_page_url(GURL("http://www.google.com"));
446   policy->ProcessAction(action);
447
448   action = new Action("punky",
449                       mock_clock->Now(),
450                       Action::ACTION_DOM_ACCESS,
451                       "lets");
452   action->mutable_args()->AppendString("too new");
453   action->set_page_url(GURL("http://www.google.com"));
454   policy->ProcessAction(action);
455
456   action = new Action("punky",
457                       mock_clock->Now() - base::TimeDelta::FromDays(7),
458                       Action::ACTION_DOM_ACCESS,
459                       "lets");
460   action->mutable_args()->AppendString("too old");
461   action->set_page_url(GURL("http://www.google.com"));
462   policy->ProcessAction(action);
463
464   CheckReadData(
465       policy,
466       "punky",
467       3,
468       base::Bind(&CountingPolicyTest::Arguments_GetOlderActions));
469
470   policy->Close();
471 }
472
473 TEST_F(CountingPolicyTest, LogAndFetchFilteredActions) {
474   ActivityLogDatabasePolicy* policy = new CountingPolicy(profile_.get());
475   policy->Init();
476   scoped_refptr<const Extension> extension =
477       ExtensionBuilder()
478           .SetManifest(DictionaryBuilder()
479                        .Set("name", "Test extension")
480                        .Set("version", "1.0.0")
481                        .Set("manifest_version", 2))
482           .Build();
483   extension_service_->AddExtension(extension.get());
484   GURL gurl("http://www.google.com");
485
486   // Write some API calls
487   scoped_refptr<Action> action_api = new Action(extension->id(),
488                                                 base::Time::Now(),
489                                                 Action::ACTION_API_CALL,
490                                                 "tabs.testMethod");
491   action_api->set_args(make_scoped_ptr(new base::ListValue()));
492   policy->ProcessAction(action_api);
493
494   scoped_refptr<Action> action_dom = new Action(extension->id(),
495                                                 base::Time::Now(),
496                                                 Action::ACTION_DOM_ACCESS,
497                                                 "document.write");
498   action_dom->set_args(make_scoped_ptr(new base::ListValue()));
499   action_dom->set_page_url(gurl);
500   policy->ProcessAction(action_dom);
501
502   CheckReadFilteredData(
503       policy,
504       extension->id(),
505       Action::ACTION_API_CALL,
506       "tabs.testMethod",
507       "",
508       "",
509       -1,
510       base::Bind(
511           &CountingPolicyTest::RetrieveActions_FetchFilteredActions1));
512
513   CheckReadFilteredData(
514       policy,
515       "",
516       Action::ACTION_DOM_ACCESS,
517       "",
518       "",
519       "",
520       -1,
521       base::Bind(
522           &CountingPolicyTest::RetrieveActions_FetchFilteredActions1));
523
524   CheckReadFilteredData(
525       policy,
526       "",
527       Action::ACTION_DOM_ACCESS,
528       "",
529       "http://www.google.com/",
530       "",
531       -1,
532       base::Bind(
533           &CountingPolicyTest::RetrieveActions_FetchFilteredActions1));
534
535   CheckReadFilteredData(
536       policy,
537       "",
538       Action::ACTION_DOM_ACCESS,
539       "",
540       "http://www.google.com",
541       "",
542       -1,
543       base::Bind(
544           &CountingPolicyTest::RetrieveActions_FetchFilteredActions1));
545
546   CheckReadFilteredData(
547       policy,
548       "",
549       Action::ACTION_DOM_ACCESS,
550       "",
551       "http://www.goo",
552       "",
553       -1,
554       base::Bind(
555           &CountingPolicyTest::RetrieveActions_FetchFilteredActions1));
556
557   CheckReadFilteredData(
558       policy,
559       extension->id(),
560       Action::ACTION_ANY,
561       "",
562       "",
563       "",
564       -1,
565       base::Bind(
566           &CountingPolicyTest::RetrieveActions_FetchFilteredActions2));
567
568   policy->Close();
569 }
570
571 // Check that merging of actions only occurs within the same day, not across
572 // days, and that old data can be expired from the database.
573 TEST_F(CountingPolicyTest, MergingAndExpiring) {
574   CountingPolicy* policy = new CountingPolicy(profile_.get());
575   policy->Init();
576   // Initially disable expiration by setting a retention time before any
577   // actions we generate.
578   policy->set_retention_time(base::TimeDelta::FromDays(14));
579
580   // Use a mock clock to ensure that events are not recorded on the wrong day
581   // when the test is run close to local midnight.
582   base::SimpleTestClock* mock_clock = new base::SimpleTestClock();
583   mock_clock->SetNow(base::Time::Now().LocalMidnight() +
584                     base::TimeDelta::FromHours(12));
585   policy->SetClockForTesting(scoped_ptr<base::Clock>(mock_clock));
586
587   // The first two actions should be merged; the last one is on a separate day
588   // and should not be.
589   scoped_refptr<Action> action =
590       new Action("punky",
591                  mock_clock->Now() - base::TimeDelta::FromDays(3) -
592                      base::TimeDelta::FromMinutes(40),
593                  Action::ACTION_API_CALL,
594                  "brewster");
595   policy->ProcessAction(action);
596
597   action = new Action("punky",
598                       mock_clock->Now() - base::TimeDelta::FromDays(3) -
599                           base::TimeDelta::FromMinutes(20),
600                       Action::ACTION_API_CALL,
601                       "brewster");
602   policy->ProcessAction(action);
603
604   action = new Action("punky",
605                       mock_clock->Now() - base::TimeDelta::FromDays(2) -
606                           base::TimeDelta::FromMinutes(20),
607                       Action::ACTION_API_CALL,
608                       "brewster");
609   policy->ProcessAction(action);
610
611   CheckReadData(policy,
612                 "punky",
613                 3,
614                 base::Bind(&CountingPolicyTest::Arguments_CheckMergeCount, 2));
615   CheckReadData(policy,
616                 "punky",
617                 2,
618                 base::Bind(&CountingPolicyTest::Arguments_CheckMergeCount, 1));
619
620   // Clean actions before midnight two days ago.  Force expiration to run by
621   // clearing last_database_cleaning_time_ and submitting a new action.
622   policy->set_retention_time(base::TimeDelta::FromDays(2));
623   policy->last_database_cleaning_time_ = base::Time();
624   action = new Action("punky",
625                       mock_clock->Now(),
626                       Action::ACTION_API_CALL,
627                       "brewster");
628   policy->ProcessAction(action);
629
630   CheckReadData(policy,
631                 "punky",
632                 3,
633                 base::Bind(&CountingPolicyTest::Arguments_CheckMergeCount, 0));
634   CheckReadData(policy,
635                 "punky",
636                 2,
637                 base::Bind(&CountingPolicyTest::Arguments_CheckMergeCount, 1));
638
639   policy->Close();
640 }
641
642 // Test cleaning of old data in the string and URL tables.
643 TEST_F(CountingPolicyTest, StringTableCleaning) {
644   CountingPolicy* policy = new CountingPolicy(profile_.get());
645   policy->Init();
646   // Initially disable expiration by setting a retention time before any
647   // actions we generate.
648   policy->set_retention_time(base::TimeDelta::FromDays(14));
649
650   base::SimpleTestClock* mock_clock = new base::SimpleTestClock();
651   mock_clock->SetNow(base::Time::Now());
652   policy->SetClockForTesting(scoped_ptr<base::Clock>(mock_clock));
653
654   // Insert an action; this should create entries in both the string table (for
655   // the extension and API name) and the URL table (for page_url).
656   scoped_refptr<Action> action =
657       new Action("punky",
658                  mock_clock->Now() - base::TimeDelta::FromDays(7),
659                  Action::ACTION_API_CALL,
660                  "brewster");
661   action->set_page_url(GURL("http://www.google.com/"));
662   policy->ProcessAction(action);
663
664   // Add an action which will not be expired, so that some strings will remain
665   // in use.
666   action = new Action(
667       "punky", mock_clock->Now(), Action::ACTION_API_CALL, "tabs.create");
668   policy->ProcessAction(action);
669
670   // There should now be three strings ("punky", "brewster", "tabs.create") and
671   // one URL in the tables.
672   policy->Flush();
673   policy->ScheduleAndForget(policy,
674                             &CountingPolicyTest::CheckStringTableSizes,
675                             3,
676                             1);
677   WaitOnThread(BrowserThread::DB);
678
679   // Trigger a cleaning.  The oldest action is expired when we submit a
680   // duplicate of the newer action.  After this, there should be two strings
681   // and no URLs.
682   policy->set_retention_time(base::TimeDelta::FromDays(2));
683   policy->last_database_cleaning_time_ = base::Time();
684   policy->ProcessAction(action);
685   policy->Flush();
686   policy->ScheduleAndForget(policy,
687                             &CountingPolicyTest::CheckStringTableSizes,
688                             2,
689                             0);
690   WaitOnThread(BrowserThread::DB);
691
692   policy->Close();
693 }
694
695 // A stress test for memory- and database-based merging of actions.  Submit
696 // multiple items, not in chronological order, spanning a few days.  Check that
697 // items are merged properly and final timestamps are correct.
698 TEST_F(CountingPolicyTest, MoreMerging) {
699   CountingPolicy* policy = new CountingPolicy(profile_.get());
700   policy->Init();
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   // Create an action 2 days ago, then 1 day ago, then 2 days ago.  Make sure
711   // that we end up with two merged records (one for each day), and each has
712   // the appropriate timestamp.  These merges should happen in the database
713   // since the date keeps changing.
714   base::Time time1 =
715       mock_clock->Now() - base::TimeDelta::FromDays(2) -
716       base::TimeDelta::FromMinutes(40);
717   base::Time time2 =
718       mock_clock->Now() - base::TimeDelta::FromDays(1) -
719       base::TimeDelta::FromMinutes(40);
720   base::Time time3 =
721       mock_clock->Now() - base::TimeDelta::FromDays(2) -
722       base::TimeDelta::FromMinutes(20);
723
724   scoped_refptr<Action> action =
725       new Action("punky", time1, Action::ACTION_API_CALL, "brewster");
726   policy->ProcessAction(action);
727
728   action = new Action("punky", time2, Action::ACTION_API_CALL, "brewster");
729   policy->ProcessAction(action);
730
731   action = new Action("punky", time3, Action::ACTION_API_CALL, "brewster");
732   policy->ProcessAction(action);
733
734   CheckReadData(
735       policy,
736       "punky",
737       2,
738       base::Bind(
739           &CountingPolicyTest::Arguments_CheckMergeCountAndTime, 2, time3));
740   CheckReadData(
741       policy,
742       "punky",
743       1,
744       base::Bind(
745           &CountingPolicyTest::Arguments_CheckMergeCountAndTime, 1, time2));
746
747   // Create three actions today, where the merges should happen in memory.
748   // Again these are not chronological; timestamp time5 should win out since it
749   // is the latest.
750   base::Time time4 = mock_clock->Now() - base::TimeDelta::FromMinutes(60);
751   base::Time time5 = mock_clock->Now() - base::TimeDelta::FromMinutes(20);
752   base::Time time6 = mock_clock->Now() - base::TimeDelta::FromMinutes(40);
753
754   action = new Action("punky", time4, Action::ACTION_API_CALL, "brewster");
755   policy->ProcessAction(action);
756
757   action = new Action("punky", time5, Action::ACTION_API_CALL, "brewster");
758   policy->ProcessAction(action);
759
760   action = new Action("punky", time6, Action::ACTION_API_CALL, "brewster");
761   policy->ProcessAction(action);
762
763   CheckReadData(
764       policy,
765       "punky",
766       0,
767       base::Bind(
768           &CountingPolicyTest::Arguments_CheckMergeCountAndTime, 3, time5));
769   policy->Close();
770 }
771
772 // Check that actions are flushed to disk before letting too many accumulate in
773 // memory.
774 TEST_F(CountingPolicyTest, EarlyFlush) {
775   CountingPolicy* policy = new CountingPolicy(profile_.get());
776   policy->Init();
777
778   for (int i = 0; i < 500; i++) {
779     scoped_refptr<Action> action =
780         new Action("punky",
781                    base::Time::Now(),
782                    Action::ACTION_API_CALL,
783                    base::StringPrintf("apicall_%d", i));
784     policy->ProcessAction(action);
785   }
786
787   policy->ScheduleAndForget(policy, &CountingPolicyTest::CheckQueueSize);
788   WaitOnThread(BrowserThread::DB);
789
790   policy->Close();
791 }
792
793 TEST_F(CountingPolicyTest, CapReturns) {
794   CountingPolicy* policy = new CountingPolicy(profile_.get());
795   policy->Init();
796
797   for (int i = 0; i < 305; i++) {
798     scoped_refptr<Action> action =
799         new Action("punky",
800                    base::Time::Now(),
801                    Action::ACTION_API_CALL,
802                    base::StringPrintf("apicall_%d", i));
803     policy->ProcessAction(action);
804   }
805
806   policy->Flush();
807   WaitOnThread(BrowserThread::DB);
808
809   CheckReadFilteredData(
810       policy,
811       "punky",
812       Action::ACTION_ANY,
813       "",
814       "",
815       "",
816       -1,
817       base::Bind(
818           &CountingPolicyTest::RetrieveActions_FetchFilteredActions300));
819   policy->Close();
820 }
821
822 TEST_F(CountingPolicyTest, RemoveAllURLs) {
823   ActivityLogDatabasePolicy* policy = new CountingPolicy(profile_.get());
824   policy->Init();
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   // Record some actions
834   scoped_refptr<Action> action =
835       new Action("punky", mock_clock->Now(),
836                  Action::ACTION_DOM_ACCESS, "lets");
837   action->mutable_args()->AppendString("vamoose");
838   action->set_page_url(GURL("http://www.google.com"));
839   action->set_page_title("Google");
840   action->set_arg_url(GURL("http://www.args-url.com"));
841   policy->ProcessAction(action);
842
843   mock_clock->Advance(base::TimeDelta::FromSeconds(1));
844   action = new Action(
845       "punky", mock_clock->Now(), Action::ACTION_DOM_ACCESS, "lets");
846   action->mutable_args()->AppendString("vamoose");
847   action->set_page_url(GURL("http://www.google2.com"));
848   action->set_page_title("Google");
849   // Deliberately no arg url set to make sure it stills works if there is no arg
850   // url.
851   policy->ProcessAction(action);
852
853   // Clean all the URLs.
854   std::vector<GURL> no_url_restrictions;
855   policy->RemoveURLs(no_url_restrictions);
856
857   CheckReadData(
858       policy,
859       "punky",
860       0,
861       base::Bind(&CountingPolicyTest::AllURLsRemoved));
862   policy->Close();
863 }
864
865 TEST_F(CountingPolicyTest, RemoveSpecificURLs) {
866   ActivityLogDatabasePolicy* policy = new CountingPolicy(profile_.get());
867   policy->Init();
868
869   // Use a mock clock to ensure that events are not recorded on the wrong day
870   // when the test is run close to local midnight.
871   base::SimpleTestClock* mock_clock = new base::SimpleTestClock();
872   mock_clock->SetNow(base::Time::Now().LocalMidnight() +
873                      base::TimeDelta::FromHours(12));
874   policy->SetClockForTesting(scoped_ptr<base::Clock>(mock_clock));
875
876   // Record some actions
877   // This should have the page url and args url cleared.
878   scoped_refptr<Action> action = new Action("punky", mock_clock->Now(),
879                                             Action::ACTION_DOM_ACCESS, "lets");
880   action->mutable_args()->AppendString("vamoose");
881   action->set_page_url(GURL("http://www.google1.com"));
882   action->set_page_title("Google");
883   action->set_arg_url(GURL("http://www.google1.com"));
884   policy->ProcessAction(action);
885
886   // This should have the page url cleared but not args url.
887   mock_clock->Advance(base::TimeDelta::FromSeconds(1));
888   action = new Action(
889       "punky", mock_clock->Now(), Action::ACTION_DOM_ACCESS, "lets");
890   action->mutable_args()->AppendString("vamoose");
891   action->set_page_url(GURL("http://www.google1.com"));
892   action->set_page_title("Google");
893   action->set_arg_url(GURL("http://www.google.com"));
894   policy->ProcessAction(action);
895
896   // This should have the page url cleared. The args url is deliberately not
897   // set to make sure this doesn't cause any issues.
898   mock_clock->Advance(base::TimeDelta::FromSeconds(1));
899   action = new Action(
900       "punky", mock_clock->Now(), Action::ACTION_DOM_ACCESS, "lets");
901   action->mutable_args()->AppendString("vamoose");
902   action->set_page_url(GURL("http://www.google2.com"));
903   action->set_page_title("Google");
904   policy->ProcessAction(action);
905
906   // This should have the args url cleared but not the page url or page title.
907   mock_clock->Advance(base::TimeDelta::FromSeconds(1));
908   action = new Action(
909       "punky", mock_clock->Now(), Action::ACTION_DOM_ACCESS, "lets");
910   action->mutable_args()->AppendString("vamoose");
911   action->set_page_url(GURL("http://www.google.com"));
912   action->set_page_title("Google");
913   action->set_arg_url(GURL("http://www.google1.com"));
914   policy->ProcessAction(action);
915
916   // This should have neither cleared.
917   mock_clock->Advance(base::TimeDelta::FromSeconds(1));
918   action = new Action(
919       "punky", mock_clock->Now(), Action::ACTION_DOM_ACCESS, "lets");
920   action->mutable_args()->AppendString("vamoose");
921   action->set_page_url(GURL("http://www.google.com"));
922   action->set_page_title("Google");
923   action->set_arg_url(GURL("http://www.args-url.com"));
924   action->set_count(5);
925   policy->ProcessAction(action);
926
927     // Clean some URLs.
928   std::vector<GURL> urls;
929   urls.push_back(GURL("http://www.google1.com"));
930   urls.push_back(GURL("http://www.google2.com"));
931   urls.push_back(GURL("http://www.url_not_in_db.com"));
932   policy->RemoveURLs(urls);
933
934   CheckReadData(
935       policy,
936       "punky",
937       0,
938       base::Bind(&CountingPolicyTest::SomeURLsRemoved));
939   policy->Close();
940 }
941
942 TEST_F(CountingPolicyTest, RemoveExtensionData) {
943   CountingPolicy* policy = new CountingPolicy(profile_.get());
944   policy->Init();
945
946   // Use a mock clock to ensure that events are not recorded on the wrong day
947   // when the test is run close to local midnight.
948   base::SimpleTestClock* mock_clock = new base::SimpleTestClock();
949   mock_clock->SetNow(base::Time::Now().LocalMidnight() +
950                      base::TimeDelta::FromHours(12));
951   policy->SetClockForTesting(scoped_ptr<base::Clock>(mock_clock));
952
953   // Record some actions
954   scoped_refptr<Action> action = new Action("deleteextensiondata",
955                                             mock_clock->Now(),
956                                             Action::ACTION_DOM_ACCESS,
957                                             "lets");
958   action->mutable_args()->AppendString("vamoose");
959   action->set_page_title("Google");
960   action->set_arg_url(GURL("http://www.google.com"));
961   policy->ProcessAction(action);
962   policy->ProcessAction(action);
963   policy->ProcessAction(action);
964
965   scoped_refptr<Action> action2 = new Action("dontdelete",
966                                              mock_clock->Now(),
967                                              Action::ACTION_DOM_ACCESS,
968                                              "lets");
969   action->mutable_args()->AppendString("vamoose");
970   action->set_page_title("Google");
971   action->set_arg_url(GURL("http://www.google.com"));
972   policy->ProcessAction(action2);
973
974   policy->Flush();
975   policy->RemoveExtensionData("deleteextensiondata");
976
977   CheckReadFilteredData(
978       policy,
979       "deleteextensiondata",
980       Action::ACTION_ANY,
981       "",
982       "",
983       "",
984       -1,
985       base::Bind(
986           &CountingPolicyTest::RetrieveActions_FetchFilteredActions0));
987
988   CheckReadFilteredData(
989       policy,
990       "dontdelete",
991       Action::ACTION_ANY,
992       "",
993       "",
994       "",
995       -1,
996       base::Bind(
997           &CountingPolicyTest::RetrieveActions_FetchFilteredActions1));
998   policy->Close();
999 }
1000
1001 TEST_F(CountingPolicyTest, DeleteActions) {
1002   CountingPolicy* policy = new CountingPolicy(profile_.get());
1003   policy->Init();
1004   // Disable row expiration for this test by setting a time before any actions
1005   // we generate.
1006   policy->set_retention_time(base::TimeDelta::FromDays(14));
1007
1008   // Use a mock clock to ensure that events are not recorded on the wrong day
1009   // when the test is run close to local midnight.  Note: Ownership is passed
1010   // to the policy, but we still keep a pointer locally.  The policy will take
1011   // care of destruction; this is safe since the policy outlives all our
1012   // accesses to the mock clock.
1013   base::SimpleTestClock* mock_clock = new base::SimpleTestClock();
1014   mock_clock->SetNow(base::Time::Now().LocalMidnight() +
1015                      base::TimeDelta::FromHours(12));
1016   policy->SetClockForTesting(scoped_ptr<base::Clock>(mock_clock));
1017
1018   // Record some actions
1019   scoped_refptr<Action> action =
1020       new Action("punky",
1021                  mock_clock->Now() - base::TimeDelta::FromMinutes(40),
1022                  Action::ACTION_API_CALL,
1023                  "brewster");
1024   action->mutable_args()->AppendString("woof");
1025   policy->ProcessAction(action);
1026
1027   action = new Action("punky",
1028                       mock_clock->Now() - base::TimeDelta::FromMinutes(30),
1029                       Action::ACTION_API_CALL,
1030                       "brewster");
1031   action->mutable_args()->AppendString("meow");
1032   policy->ProcessAction(action);
1033
1034   action = new Action("punky",
1035                       mock_clock->Now() - base::TimeDelta::FromMinutes(20),
1036                       Action::ACTION_API_CALL,
1037                       "extension.sendMessage");
1038   action->mutable_args()->AppendString("not");
1039   action->mutable_args()->AppendString("stripped");
1040   policy->ProcessAction(action);
1041
1042   action =
1043       new Action("punky", mock_clock->Now(), Action::ACTION_DOM_ACCESS, "lets");
1044   action->mutable_args()->AppendString("vamoose");
1045   action->set_page_url(GURL("http://www.google.com"));
1046   policy->ProcessAction(action);
1047
1048   action = new Action(
1049       "scoobydoo", mock_clock->Now(), Action::ACTION_DOM_ACCESS, "lets");
1050   action->mutable_args()->AppendString("vamoose");
1051   action->set_page_url(GURL("http://www.google.com"));
1052   policy->ProcessAction(action);
1053
1054   CheckReadData(
1055       policy,
1056       "punky",
1057       0,
1058       base::Bind(&CountingPolicyTest::Arguments_GetTodaysActions));
1059
1060   policy->DeleteDatabase();
1061
1062   CheckReadFilteredData(
1063       policy,
1064       "",
1065       Action::ACTION_ANY,
1066       "",
1067       "",
1068       "",
1069       -1,
1070       base::Bind(
1071           &CountingPolicyTest::RetrieveActions_FetchFilteredActions0));
1072
1073   policy->Close();
1074 }
1075
1076 // Tests that duplicate rows in the activity log database are handled properly
1077 // when updating counts.
1078 TEST_F(CountingPolicyTest, DuplicateRows) {
1079   CountingPolicy* policy = new CountingPolicy(profile_.get());
1080   policy->Init();
1081   base::SimpleTestClock* mock_clock = new base::SimpleTestClock();
1082   mock_clock->SetNow(base::Time::Now().LocalMidnight() +
1083                      base::TimeDelta::FromHours(12));
1084   policy->SetClockForTesting(scoped_ptr<base::Clock>(mock_clock));
1085
1086   // Record two actions with distinct URLs.
1087   scoped_refptr<Action> action;
1088   action = new Action(
1089       "punky", mock_clock->Now(), Action::ACTION_API_CALL, "brewster");
1090   action->set_page_url(GURL("http://www.google.com"));
1091   policy->ProcessAction(action);
1092
1093   action = new Action(
1094       "punky", mock_clock->Now(), Action::ACTION_API_CALL, "brewster");
1095   action->set_page_url(GURL("http://www.google.co.uk"));
1096   policy->ProcessAction(action);
1097
1098   // Manipulate the database to clear the URLs, so that we end up with
1099   // duplicate rows.
1100   std::vector<GURL> no_url_restrictions;
1101   policy->RemoveURLs(no_url_restrictions);
1102
1103   // Record one more action, with no URL.  This should increment the count on
1104   // one, and exactly one, of the existing rows.
1105   action = new Action(
1106       "punky", mock_clock->Now(), Action::ACTION_API_CALL, "brewster");
1107   policy->ProcessAction(action);
1108
1109   CheckReadData(
1110       policy,
1111       "punky",
1112       0,
1113       base::Bind(&CountingPolicyTest::CheckDuplicates));
1114   policy->Close();
1115 }
1116
1117 }  // namespace extensions