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/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, "odlameecjipmbmbejkplpemijjgpljce",
158                Action::ACTION_API_CALL, "extension.connect",
159                "[\"hello\",\"world\"]", "", "", "");
160  }
161
162  static void Arguments_GetTodaysActions(
163      scoped_ptr<Action::ActionVector> actions) {
164    ASSERT_EQ(2, static_cast<int>(actions->size()));
165    CheckAction(*actions->at(0), "punky", Action::ACTION_DOM_ACCESS, "lets",
166                "[\"vamoose\"]", "http://www.google.com/", "Page Title",
167                "http://www.arg-url.com/");
168    CheckAction(*actions->at(1), "punky", Action::ACTION_API_CALL, "brewster",
169                "[\"woof\"]", "", "Page Title", "http://www.arg-url.com/");
170  }
171
172  static void Arguments_GetOlderActions(
173      scoped_ptr<Action::ActionVector> actions) {
174    ASSERT_EQ(2, static_cast<int>(actions->size()));
175    CheckAction(*actions->at(0), "punky", Action::ACTION_DOM_ACCESS, "lets",
176                "[\"vamoose\"]", "http://www.google.com/", "", "");
177    CheckAction(*actions->at(1), "punky", Action::ACTION_API_CALL, "brewster",
178                "[\"woof\"]", "", "", "");
179  }
180
181  static void AllURLsRemoved(scoped_ptr<Action::ActionVector> actions) {
182    ASSERT_EQ(2, static_cast<int>(actions->size()));
183    CheckAction(*actions->at(0), "punky", Action::ACTION_API_CALL, "lets",
184                "[\"vamoose\"]", "", "", "");
185    CheckAction(*actions->at(1), "punky", Action::ACTION_DOM_ACCESS, "lets",
186                "[\"vamoose\"]", "", "", "");
187  }
188
189  static void SomeURLsRemoved(scoped_ptr<Action::ActionVector> actions) {
190    // These will be in the vector in reverse time order.
191    ASSERT_EQ(5, static_cast<int>(actions->size()));
192    CheckAction(*actions->at(0), "punky", Action::ACTION_DOM_ACCESS, "lets",
193                "[\"vamoose\"]", "http://www.google.com/", "Google",
194                "http://www.args-url.com/");
195    CheckAction(*actions->at(1), "punky", Action::ACTION_DOM_ACCESS, "lets",
196                "[\"vamoose\"]", "http://www.google.com/", "Google", "");
197    CheckAction(*actions->at(2), "punky", Action::ACTION_DOM_ACCESS, "lets",
198                "[\"vamoose\"]", "", "", "");
199    CheckAction(*actions->at(3), "punky", Action::ACTION_DOM_ACCESS, "lets",
200                "[\"vamoose\"]", "", "", "http://www.google.com/");
201    CheckAction(*actions->at(4), "punky", Action::ACTION_DOM_ACCESS, "lets",
202                "[\"vamoose\"]", "", "", "");
203  }
204
205  static void CheckAction(const Action& action,
206                          const std::string& expected_id,
207                          const Action::ActionType& expected_type,
208                          const std::string& expected_api_name,
209                          const std::string& expected_args_str,
210                          const std::string& expected_page_url,
211                          const std::string& expected_page_title,
212                          const std::string& expected_arg_url) {
213    ASSERT_EQ(expected_id, action.extension_id());
214    ASSERT_EQ(expected_type, action.action_type());
215    ASSERT_EQ(expected_api_name, action.api_name());
216    ASSERT_EQ(expected_args_str,
217              ActivityLogPolicy::Util::Serialize(action.args()));
218    ASSERT_EQ(expected_page_url, action.SerializePageUrl());
219    ASSERT_EQ(expected_page_title, action.page_title());
220    ASSERT_EQ(expected_arg_url, action.SerializeArgUrl());
221    ASSERT_NE(-1, action.action_id());
222  }
223
224  // A helper function initializes the policy with a number of actions, calls
225  // RemoveActions on a policy object and then checks the result of the
226  // deletion.
227  void CheckRemoveActions(
228      ActivityLogDatabasePolicy* policy,
229      const std::vector<int64>& action_ids,
230      const base::Callback<void(scoped_ptr<Action::ActionVector>)>& checker) {
231
232    // Use a mock clock to ensure that events are not recorded on the wrong day
233    // when the test is run close to local midnight.
234    base::SimpleTestClock* mock_clock = new base::SimpleTestClock();
235    mock_clock->SetNow(base::Time::Now().LocalMidnight() +
236                       base::TimeDelta::FromHours(12));
237    policy->SetClockForTesting(scoped_ptr<base::Clock>(mock_clock));
238
239    // Record some actions
240    scoped_refptr<Action> action =
241        new Action("punky1",
242                   mock_clock->Now() - base::TimeDelta::FromMinutes(40),
243                   Action::ACTION_DOM_ACCESS,
244                   "lets1");
245    action->mutable_args()->AppendString("vamoose1");
246    action->set_page_url(GURL("http://www.google1.com"));
247    action->set_page_title("Google1");
248    action->set_arg_url(GURL("http://www.args-url1.com"));
249    policy->ProcessAction(action);
250    // Record the same action twice, so there are multiple entries in the
251    // database.
252    policy->ProcessAction(action);
253
254    action = new Action("punky2",
255                        mock_clock->Now() - base::TimeDelta::FromMinutes(30),
256                        Action::ACTION_API_CALL,
257                        "lets2");
258    action->mutable_args()->AppendString("vamoose2");
259    action->set_page_url(GURL("http://www.google2.com"));
260    action->set_page_title("Google2");
261    action->set_arg_url(GURL("http://www.args-url2.com"));
262    policy->ProcessAction(action);
263    // Record the same action twice, so there are multiple entries in the
264    // database.
265    policy->ProcessAction(action);
266
267    // Submit a request to delete actions.
268    policy->RemoveActions(action_ids);
269
270    // Check the result of the deletion. The checker function gets all
271    // activities in the database.
272    CheckReadData(policy, "", -1, checker);
273
274    // Clean database.
275    policy->DeleteDatabase();
276  }
277
278  static void AllActionsDeleted(scoped_ptr<Action::ActionVector> actions) {
279    ASSERT_EQ(0, static_cast<int>(actions->size()));
280  }
281
282  static void NoActionsDeleted(scoped_ptr<Action::ActionVector> actions) {
283    // These will be in the vector in reverse time order.
284    ASSERT_EQ(4, static_cast<int>(actions->size()));
285    CheckAction(*actions->at(0),
286                "punky2",
287                Action::ACTION_API_CALL,
288                "lets2",
289                "[\"vamoose2\"]",
290                "http://www.google2.com/",
291                "Google2",
292                "http://www.args-url2.com/");
293    ASSERT_EQ(3, actions->at(0)->action_id());
294    CheckAction(*actions->at(1),
295                "punky2",
296                Action::ACTION_API_CALL,
297                "lets2",
298                "[\"vamoose2\"]",
299                "http://www.google2.com/",
300                "Google2",
301                "http://www.args-url2.com/");
302    ASSERT_EQ(4, actions->at(1)->action_id());
303    CheckAction(*actions->at(2),
304                "punky1",
305                Action::ACTION_DOM_ACCESS,
306                "lets1",
307                "[\"vamoose1\"]",
308                "http://www.google1.com/",
309                "Google1",
310                "http://www.args-url1.com/");
311    ASSERT_EQ(1, actions->at(2)->action_id());
312    CheckAction(*actions->at(3),
313                "punky1",
314                Action::ACTION_DOM_ACCESS,
315                "lets1",
316                "[\"vamoose1\"]",
317                "http://www.google1.com/",
318                "Google1",
319                "http://www.args-url1.com/");
320    ASSERT_EQ(2, actions->at(3)->action_id());
321  }
322
323  static void Action1Deleted(scoped_ptr<Action::ActionVector> actions) {
324    // These will be in the vector in reverse time order.
325    ASSERT_EQ(2, static_cast<int>(actions->size()));
326    CheckAction(*actions->at(0),
327                "punky2",
328                Action::ACTION_API_CALL,
329                "lets2",
330                "[\"vamoose2\"]",
331                "http://www.google2.com/",
332                "Google2",
333                "http://www.args-url2.com/");
334    ASSERT_EQ(3, actions->at(0)->action_id());
335    CheckAction(*actions->at(1),
336                "punky2",
337                Action::ACTION_API_CALL,
338                "lets2",
339                "[\"vamoose2\"]",
340                "http://www.google2.com/",
341                "Google2",
342                "http://www.args-url2.com/");
343    ASSERT_EQ(4, actions->at(1)->action_id());
344  }
345
346  static void Action2Deleted(scoped_ptr<Action::ActionVector> actions) {
347    // These will be in the vector in reverse time order.
348    ASSERT_EQ(2, static_cast<int>(actions->size()));
349    CheckAction(*actions->at(0),
350                "punky1",
351                Action::ACTION_DOM_ACCESS,
352                "lets1",
353                "[\"vamoose1\"]",
354                "http://www.google1.com/",
355                "Google1",
356                "http://www.args-url1.com/");
357    ASSERT_EQ(1, actions->at(0)->action_id());
358    CheckAction(*actions->at(1),
359                "punky1",
360                Action::ACTION_DOM_ACCESS,
361                "lets1",
362                "[\"vamoose1\"]",
363                "http://www.google1.com/",
364                "Google1",
365                "http://www.args-url1.com/");
366    ASSERT_EQ(2, actions->at(1)->action_id());
367  }
368
369 protected:
370  ExtensionService* extension_service_;
371  scoped_ptr<TestingProfile> profile_;
372  content::TestBrowserThreadBundle thread_bundle_;
373  // Used to preserve a copy of the original command line.
374  // The test framework will do this itself as well. However, by then,
375  // it is too late to call ActivityLog::RecomputeLoggingIsEnabled() in
376  // TearDown().
377  CommandLine saved_cmdline_;
378
379#if defined OS_CHROMEOS
380  chromeos::ScopedTestDeviceSettingsService test_device_settings_service_;
381  chromeos::ScopedTestCrosSettings test_cros_settings_;
382  scoped_ptr<chromeos::ScopedTestUserManager> test_user_manager_;
383#endif
384};
385
386TEST_F(FullStreamUIPolicyTest, Construct) {
387  ActivityLogDatabasePolicy* policy = new FullStreamUIPolicy(profile_.get());
388  policy->Init();
389  scoped_refptr<const Extension> extension =
390      ExtensionBuilder()
391          .SetManifest(DictionaryBuilder()
392                       .Set("name", "Test extension")
393                       .Set("version", "1.0.0")
394                       .Set("manifest_version", 2))
395          .Build();
396  extension_service_->AddExtension(extension.get());
397  scoped_ptr<base::ListValue> args(new base::ListValue());
398  scoped_refptr<Action> action = new Action(extension->id(),
399                                            base::Time::Now(),
400                                            Action::ACTION_API_CALL,
401                                            "tabs.testMethod");
402  action->set_args(args.Pass());
403  policy->ProcessAction(action);
404  policy->Close();
405}
406
407TEST_F(FullStreamUIPolicyTest, LogAndFetchActions) {
408  ActivityLogDatabasePolicy* policy = new FullStreamUIPolicy(profile_.get());
409  policy->Init();
410  scoped_refptr<const Extension> extension =
411      ExtensionBuilder()
412          .SetManifest(DictionaryBuilder()
413                       .Set("name", "Test extension")
414                       .Set("version", "1.0.0")
415                       .Set("manifest_version", 2))
416          .Build();
417  extension_service_->AddExtension(extension.get());
418  GURL gurl("http://www.google.com");
419
420  // Write some API calls
421  scoped_refptr<Action> action_api = new Action(extension->id(),
422                                                base::Time::Now(),
423                                                Action::ACTION_API_CALL,
424                                                "tabs.testMethod");
425  action_api->set_args(make_scoped_ptr(new base::ListValue()));
426  policy->ProcessAction(action_api);
427
428  scoped_refptr<Action> action_dom = new Action(extension->id(),
429                                                base::Time::Now(),
430                                                Action::ACTION_DOM_ACCESS,
431                                                "document.write");
432  action_dom->set_args(make_scoped_ptr(new base::ListValue()));
433  action_dom->set_page_url(gurl);
434  policy->ProcessAction(action_dom);
435
436  CheckReadData(
437      policy,
438      extension->id(),
439      0,
440      base::Bind(&FullStreamUIPolicyTest::RetrieveActions_LogAndFetchActions));
441
442  policy->Close();
443}
444
445TEST_F(FullStreamUIPolicyTest, LogAndFetchFilteredActions) {
446  ActivityLogDatabasePolicy* policy = new FullStreamUIPolicy(profile_.get());
447  policy->Init();
448  scoped_refptr<const Extension> extension =
449      ExtensionBuilder()
450          .SetManifest(DictionaryBuilder()
451                       .Set("name", "Test extension")
452                       .Set("version", "1.0.0")
453                       .Set("manifest_version", 2))
454          .Build();
455  extension_service_->AddExtension(extension.get());
456  GURL gurl("http://www.google.com");
457
458  // Write some API calls
459  scoped_refptr<Action> action_api = new Action(extension->id(),
460                                                base::Time::Now(),
461                                                Action::ACTION_API_CALL,
462                                                "tabs.testMethod");
463  action_api->set_args(make_scoped_ptr(new base::ListValue()));
464  policy->ProcessAction(action_api);
465
466  scoped_refptr<Action> action_dom = new Action(extension->id(),
467                                                base::Time::Now(),
468                                                Action::ACTION_DOM_ACCESS,
469                                                "document.write");
470  action_dom->set_args(make_scoped_ptr(new base::ListValue()));
471  action_dom->set_page_url(gurl);
472  policy->ProcessAction(action_dom);
473
474  CheckReadFilteredData(
475      policy,
476      extension->id(),
477      Action::ACTION_API_CALL,
478      "tabs.testMethod",
479      "",
480      "",
481      -1,
482      base::Bind(
483          &FullStreamUIPolicyTest::RetrieveActions_FetchFilteredActions1));
484
485  CheckReadFilteredData(
486      policy,
487      "",
488      Action::ACTION_DOM_ACCESS,
489      "",
490      "",
491      "",
492      -1,
493      base::Bind(
494          &FullStreamUIPolicyTest::RetrieveActions_FetchFilteredActions1));
495
496  CheckReadFilteredData(
497      policy,
498      "",
499      Action::ACTION_DOM_ACCESS,
500      "",
501      "http://www.google.com/",
502      "",
503      -1,
504      base::Bind(
505          &FullStreamUIPolicyTest::RetrieveActions_FetchFilteredActions1));
506
507  CheckReadFilteredData(
508      policy,
509      "",
510      Action::ACTION_DOM_ACCESS,
511      "",
512      "http://www.google.com",
513      "",
514      -1,
515      base::Bind(
516          &FullStreamUIPolicyTest::RetrieveActions_FetchFilteredActions1));
517
518  CheckReadFilteredData(
519      policy,
520      "",
521      Action::ACTION_DOM_ACCESS,
522      "",
523      "http://www.goo",
524      "",
525      -1,
526      base::Bind(
527          &FullStreamUIPolicyTest::RetrieveActions_FetchFilteredActions1));
528
529  CheckReadFilteredData(
530      policy,
531      extension->id(),
532      Action::ACTION_ANY,
533      "",
534      "",
535      "",
536      -1,
537      base::Bind(
538          &FullStreamUIPolicyTest::RetrieveActions_FetchFilteredActions2));
539
540  policy->Close();
541}
542
543TEST_F(FullStreamUIPolicyTest, LogWithArguments) {
544  ActivityLogDatabasePolicy* policy = new FullStreamUIPolicy(profile_.get());
545  policy->Init();
546  scoped_refptr<const Extension> extension =
547      ExtensionBuilder()
548          .SetManifest(DictionaryBuilder()
549                       .Set("name", "Test extension")
550                       .Set("version", "1.0.0")
551                       .Set("manifest_version", 2))
552          .Build();
553  extension_service_->AddExtension(extension.get());
554
555  scoped_ptr<base::ListValue> args(new base::ListValue());
556  args->Set(0, new base::StringValue("hello"));
557  args->Set(1, new base::StringValue("world"));
558  scoped_refptr<Action> action = new Action(extension->id(),
559                                            base::Time::Now(),
560                                            Action::ACTION_API_CALL,
561                                            "extension.connect");
562  action->set_args(args.Pass());
563
564  policy->ProcessAction(action);
565  CheckReadData(policy,
566                extension->id(),
567                0,
568                base::Bind(&FullStreamUIPolicyTest::Arguments_Present));
569  policy->Close();
570}
571
572TEST_F(FullStreamUIPolicyTest, GetTodaysActions) {
573  ActivityLogDatabasePolicy* policy = new FullStreamUIPolicy(profile_.get());
574  policy->Init();
575
576  // Use a mock clock to ensure that events are not recorded on the wrong day
577  // when the test is run close to local midnight.  Note: Ownership is passed
578  // to the policy, but we still keep a pointer locally.  The policy will take
579  // care of destruction; this is safe since the policy outlives all our
580  // accesses to the mock clock.
581  base::SimpleTestClock* mock_clock = new base::SimpleTestClock();
582  mock_clock->SetNow(base::Time::Now().LocalMidnight() +
583                     base::TimeDelta::FromHours(12));
584  policy->SetClockForTesting(scoped_ptr<base::Clock>(mock_clock));
585
586  // Record some actions
587  scoped_refptr<Action> action =
588      new Action("punky",
589                 mock_clock->Now() - base::TimeDelta::FromMinutes(40),
590                 Action::ACTION_API_CALL,
591                 "brewster");
592  action->mutable_args()->AppendString("woof");
593  action->set_arg_url(GURL("http://www.arg-url.com"));
594  action->set_page_title("Page Title");
595  policy->ProcessAction(action);
596
597  action =
598      new Action("punky", mock_clock->Now(), Action::ACTION_DOM_ACCESS, "lets");
599  action->mutable_args()->AppendString("vamoose");
600  action->set_page_url(GURL("http://www.google.com"));
601  action->set_arg_url(GURL("http://www.arg-url.com"));
602  action->set_page_title("Page Title");
603  policy->ProcessAction(action);
604
605  action = new Action(
606      "scoobydoo", mock_clock->Now(), Action::ACTION_DOM_ACCESS, "lets");
607  action->mutable_args()->AppendString("vamoose");
608  action->set_page_url(GURL("http://www.google.com"));
609  action->set_arg_url(GURL("http://www.arg-url.com"));
610  policy->ProcessAction(action);
611
612  CheckReadData(
613      policy,
614      "punky",
615      0,
616      base::Bind(&FullStreamUIPolicyTest::Arguments_GetTodaysActions));
617  policy->Close();
618}
619
620// Check that we can read back less recent actions in the db.
621TEST_F(FullStreamUIPolicyTest, GetOlderActions) {
622  ActivityLogDatabasePolicy* policy = new FullStreamUIPolicy(profile_.get());
623  policy->Init();
624
625  // Use a mock clock to ensure that events are not recorded on the wrong day
626  // when the test is run close to local midnight.
627  base::SimpleTestClock* mock_clock = new base::SimpleTestClock();
628  mock_clock->SetNow(base::Time::Now().LocalMidnight() +
629                     base::TimeDelta::FromHours(12));
630  policy->SetClockForTesting(scoped_ptr<base::Clock>(mock_clock));
631
632  // Record some actions
633  scoped_refptr<Action> action =
634      new Action("punky",
635                 mock_clock->Now() - base::TimeDelta::FromDays(3) -
636                     base::TimeDelta::FromMinutes(40),
637                 Action::ACTION_API_CALL,
638                 "brewster");
639  action->mutable_args()->AppendString("woof");
640  policy->ProcessAction(action);
641
642  action = new Action("punky",
643                      mock_clock->Now() - base::TimeDelta::FromDays(3),
644                      Action::ACTION_DOM_ACCESS,
645                      "lets");
646  action->mutable_args()->AppendString("vamoose");
647  action->set_page_url(GURL("http://www.google.com"));
648  policy->ProcessAction(action);
649
650  action = new Action("punky",
651                      mock_clock->Now(),
652                      Action::ACTION_DOM_ACCESS,
653                      "lets");
654  action->mutable_args()->AppendString("too new");
655  action->set_page_url(GURL("http://www.google.com"));
656  policy->ProcessAction(action);
657
658  action = new Action("punky",
659                      mock_clock->Now() - base::TimeDelta::FromDays(7),
660                      Action::ACTION_DOM_ACCESS,
661                      "lets");
662  action->mutable_args()->AppendString("too old");
663  action->set_page_url(GURL("http://www.google.com"));
664  policy->ProcessAction(action);
665
666  CheckReadData(
667      policy,
668      "punky",
669      3,
670      base::Bind(&FullStreamUIPolicyTest::Arguments_GetOlderActions));
671  policy->Close();
672}
673
674TEST_F(FullStreamUIPolicyTest, RemoveAllURLs) {
675  ActivityLogDatabasePolicy* policy = new FullStreamUIPolicy(profile_.get());
676  policy->Init();
677
678  // Use a mock clock to ensure that events are not recorded on the wrong day
679  // when the test is run close to local midnight.
680  base::SimpleTestClock* mock_clock = new base::SimpleTestClock();
681  mock_clock->SetNow(base::Time::Now().LocalMidnight() +
682                     base::TimeDelta::FromHours(12));
683  policy->SetClockForTesting(scoped_ptr<base::Clock>(mock_clock));
684
685  // Record some actions
686  scoped_refptr<Action> action =
687      new Action("punky", mock_clock->Now(),
688                 Action::ACTION_DOM_ACCESS, "lets");
689  action->mutable_args()->AppendString("vamoose");
690  action->set_page_url(GURL("http://www.google.com"));
691  action->set_page_title("Google");
692  action->set_arg_url(GURL("http://www.google.com"));
693  policy->ProcessAction(action);
694
695  mock_clock->Advance(base::TimeDelta::FromSeconds(1));
696  action = new Action(
697      "punky", mock_clock->Now(), Action::ACTION_API_CALL, "lets");
698  action->mutable_args()->AppendString("vamoose");
699  action->set_page_url(GURL("http://www.google2.com"));
700  action->set_page_title("Google");
701  // Deliberately no arg url set to make sure it still works when there is no
702  // arg url.
703  policy->ProcessAction(action);
704
705  // Clean all the URLs.
706  std::vector<GURL> no_url_restrictions;
707  policy->RemoveURLs(no_url_restrictions);
708
709  CheckReadData(
710      policy,
711      "punky",
712      0,
713      base::Bind(&FullStreamUIPolicyTest::AllURLsRemoved));
714  policy->Close();
715}
716
717TEST_F(FullStreamUIPolicyTest, RemoveSpecificURLs) {
718  ActivityLogDatabasePolicy* policy = new FullStreamUIPolicy(profile_.get());
719  policy->Init();
720
721  // Use a mock clock to ensure that events are not recorded on the wrong day
722  // when the test is run close to local midnight.
723  base::SimpleTestClock* mock_clock = new base::SimpleTestClock();
724  mock_clock->SetNow(base::Time::Now().LocalMidnight() +
725                     base::TimeDelta::FromHours(12));
726  policy->SetClockForTesting(scoped_ptr<base::Clock>(mock_clock));
727
728  // Record some actions
729  // This should have the page url and args url cleared.
730  scoped_refptr<Action> action = new Action("punky", mock_clock->Now(),
731                                            Action::ACTION_DOM_ACCESS, "lets");
732  action->mutable_args()->AppendString("vamoose");
733  action->set_page_url(GURL("http://www.google1.com"));
734  action->set_page_title("Google");
735  action->set_arg_url(GURL("http://www.google1.com"));
736  policy->ProcessAction(action);
737
738  // This should have the page url cleared but not args url.
739  mock_clock->Advance(base::TimeDelta::FromSeconds(1));
740  action = new Action(
741      "punky", mock_clock->Now(), Action::ACTION_DOM_ACCESS, "lets");
742  action->mutable_args()->AppendString("vamoose");
743  action->set_page_url(GURL("http://www.google1.com"));
744  action->set_page_title("Google");
745  action->set_arg_url(GURL("http://www.google.com"));
746  policy->ProcessAction(action);
747
748  // This should have the page url cleared. The args url is deliberately not set
749  // to make sure this doesn't cause any issues.
750  mock_clock->Advance(base::TimeDelta::FromSeconds(1));
751  action = new Action(
752      "punky", mock_clock->Now(), Action::ACTION_DOM_ACCESS, "lets");
753  action->mutable_args()->AppendString("vamoose");
754  action->set_page_url(GURL("http://www.google2.com"));
755  action->set_page_title("Google");
756  policy->ProcessAction(action);
757
758  // This should have the args url cleared but not the page url or page title.
759  mock_clock->Advance(base::TimeDelta::FromSeconds(1));
760  action = new Action(
761      "punky", mock_clock->Now(), Action::ACTION_DOM_ACCESS, "lets");
762  action->mutable_args()->AppendString("vamoose");
763  action->set_page_url(GURL("http://www.google.com"));
764  action->set_page_title("Google");
765  action->set_arg_url(GURL("http://www.google1.com"));
766  policy->ProcessAction(action);
767
768  // This should have neither cleared.
769  mock_clock->Advance(base::TimeDelta::FromSeconds(1));
770  action = new Action(
771      "punky", mock_clock->Now(), Action::ACTION_DOM_ACCESS, "lets");
772  action->mutable_args()->AppendString("vamoose");
773  action->set_page_url(GURL("http://www.google.com"));
774  action->set_page_title("Google");
775  action->set_arg_url(GURL("http://www.args-url.com"));
776  policy->ProcessAction(action);
777
778  // Clean some URLs.
779  std::vector<GURL> urls;
780  urls.push_back(GURL("http://www.google1.com"));
781  urls.push_back(GURL("http://www.google2.com"));
782  urls.push_back(GURL("http://www.url_not_in_db.com"));
783  policy->RemoveURLs(urls);
784
785  CheckReadData(
786      policy,
787      "punky",
788      0,
789      base::Bind(&FullStreamUIPolicyTest::SomeURLsRemoved));
790  policy->Close();
791}
792
793TEST_F(FullStreamUIPolicyTest, RemoveExtensionData) {
794  FullStreamUIPolicy* policy = new FullStreamUIPolicy(profile_.get());
795  policy->Init();
796
797  // Use a mock clock to ensure that events are not recorded on the wrong day
798  // when the test is run close to local midnight.
799  base::SimpleTestClock* mock_clock = new base::SimpleTestClock();
800  mock_clock->SetNow(base::Time::Now().LocalMidnight() +
801                     base::TimeDelta::FromHours(12));
802  policy->SetClockForTesting(scoped_ptr<base::Clock>(mock_clock));
803
804  // Record some actions
805  scoped_refptr<Action> action = new Action("deleteextensiondata",
806                                            mock_clock->Now(),
807                                            Action::ACTION_DOM_ACCESS,
808                                            "lets");
809  action->mutable_args()->AppendString("vamoose");
810  action->set_page_title("Google");
811  action->set_arg_url(GURL("http://www.google.com"));
812  policy->ProcessAction(action);
813  policy->ProcessAction(action);
814  policy->ProcessAction(action);
815
816  scoped_refptr<Action> action2 = new Action("dontdelete",
817                                             mock_clock->Now(),
818                                             Action::ACTION_DOM_ACCESS,
819                                             "lets");
820  action->mutable_args()->AppendString("vamoose");
821  action->set_page_title("Google");
822  action->set_arg_url(GURL("http://www.google.com"));
823  policy->ProcessAction(action2);
824
825  policy->Flush();
826  policy->RemoveExtensionData("deleteextensiondata");
827
828  CheckReadFilteredData(
829      policy,
830      "deleteextensiondata",
831      Action::ACTION_ANY,
832      "",
833      "",
834      "",
835      -1,
836      base::Bind(
837          &FullStreamUIPolicyTest::RetrieveActions_FetchFilteredActions0));
838
839  CheckReadFilteredData(
840      policy,
841      "dontdelete",
842      Action::ACTION_ANY,
843      "",
844      "",
845      "",
846      -1,
847      base::Bind(
848          &FullStreamUIPolicyTest::RetrieveActions_FetchFilteredActions1));
849  policy->Close();
850}
851
852TEST_F(FullStreamUIPolicyTest, CapReturns) {
853  FullStreamUIPolicy* policy = new FullStreamUIPolicy(profile_.get());
854  policy->Init();
855
856  for (int i = 0; i < 305; i++) {
857    scoped_refptr<Action> action =
858        new Action("punky",
859                   base::Time::Now(),
860                   Action::ACTION_API_CALL,
861                   base::StringPrintf("apicall_%d", i));
862    policy->ProcessAction(action);
863  }
864
865  policy->Flush();
866  BrowserThread::PostTaskAndReply(
867      BrowserThread::DB,
868      FROM_HERE,
869      base::Bind(&base::DoNothing),
870      base::MessageLoop::current()->QuitClosure());
871  base::MessageLoop::current()->Run();
872
873  CheckReadFilteredData(
874      policy,
875      "punky",
876      Action::ACTION_ANY,
877      "",
878      "",
879      "",
880      -1,
881      base::Bind(
882          &FullStreamUIPolicyTest::RetrieveActions_FetchFilteredActions300));
883  policy->Close();
884}
885
886TEST_F(FullStreamUIPolicyTest, DeleteDatabase) {
887  ActivityLogDatabasePolicy* policy = new FullStreamUIPolicy(profile_.get());
888  policy->Init();
889  scoped_refptr<const Extension> extension =
890      ExtensionBuilder()
891          .SetManifest(DictionaryBuilder()
892                       .Set("name", "Test extension")
893                       .Set("version", "1.0.0")
894                       .Set("manifest_version", 2))
895          .Build();
896  extension_service_->AddExtension(extension.get());
897  GURL gurl("http://www.google.com");
898
899  // Write some API calls.
900  scoped_refptr<Action> action_api = new Action(extension->id(),
901                                                base::Time::Now(),
902                                                Action::ACTION_API_CALL,
903                                                "tabs.testMethod");
904  action_api->set_args(make_scoped_ptr(new base::ListValue()));
905  policy->ProcessAction(action_api);
906
907  scoped_refptr<Action> action_dom = new Action(extension->id(),
908                                                base::Time::Now(),
909                                                Action::ACTION_DOM_ACCESS,
910                                                "document.write");
911  action_dom->set_args(make_scoped_ptr(new base::ListValue()));
912  action_dom->set_page_url(gurl);
913  policy->ProcessAction(action_dom);
914
915  CheckReadData(
916      policy,
917      extension->id(),
918      0,
919      base::Bind(&FullStreamUIPolicyTest::RetrieveActions_LogAndFetchActions));
920
921  // Now delete them.
922  policy->DeleteDatabase();
923
924  CheckReadFilteredData(
925      policy,
926      "",
927      Action::ACTION_ANY,
928      "",
929      "",
930      "",
931      -1,
932      base::Bind(
933          &FullStreamUIPolicyTest::RetrieveActions_FetchFilteredActions0));
934
935  policy->Close();
936}
937
938TEST_F(FullStreamUIPolicyTest, RemoveActions) {
939  ActivityLogDatabasePolicy* policy = new FullStreamUIPolicy(profile_.get());
940  policy->Init();
941
942  std::vector<int64> action_ids;
943
944  CheckRemoveActions(policy,
945                     action_ids,
946                     base::Bind(&FullStreamUIPolicyTest::NoActionsDeleted));
947
948  action_ids.push_back(-1);
949  action_ids.push_back(-10);
950  action_ids.push_back(0);
951  action_ids.push_back(5);
952  action_ids.push_back(10);
953  CheckRemoveActions(policy,
954                     action_ids,
955                     base::Bind(&FullStreamUIPolicyTest::NoActionsDeleted));
956  action_ids.clear();
957
958  for (int i = 0; i < 50; i++) {
959    action_ids.push_back(i + 5);
960  }
961  CheckRemoveActions(policy,
962                     action_ids,
963                     base::Bind(&FullStreamUIPolicyTest::NoActionsDeleted));
964  action_ids.clear();
965
966  // CheckRemoveActions pushes four actions to the Activity Log database with
967  // IDs 1, 2, 3, and 4.
968  action_ids.push_back(1);
969  action_ids.push_back(2);
970  action_ids.push_back(3);
971  action_ids.push_back(4);
972  CheckRemoveActions(policy,
973                     action_ids,
974                     base::Bind(&FullStreamUIPolicyTest::AllActionsDeleted));
975  action_ids.clear();
976
977  action_ids.push_back(1);
978  action_ids.push_back(2);
979  CheckRemoveActions(
980      policy, action_ids, base::Bind(&FullStreamUIPolicyTest::Action1Deleted));
981  action_ids.clear();
982
983  action_ids.push_back(3);
984  action_ids.push_back(4);
985  CheckRemoveActions(
986      policy, action_ids, base::Bind(&FullStreamUIPolicyTest::Action2Deleted));
987  action_ids.clear();
988
989  policy->Close();
990}
991
992}  // namespace extensions
993