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