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.
5 #include "base/cancelable_callback.h"
6 #include "base/command_line.h"
7 #include "base/memory/scoped_ptr.h"
8 #include "base/run_loop.h"
9 #include "base/strings/string_split.h"
10 #include "base/strings/stringprintf.h"
11 #include "base/synchronization/waitable_event.h"
12 #include "base/test/simple_test_clock.h"
13 #include "base/test/test_timeouts.h"
14 #include "chrome/browser/extensions/activity_log/activity_log.h"
15 #include "chrome/browser/extensions/activity_log/counting_policy.h"
16 #include "chrome/browser/extensions/extension_service.h"
17 #include "chrome/browser/extensions/test_extension_system.h"
18 #include "chrome/common/chrome_constants.h"
19 #include "chrome/common/chrome_switches.h"
20 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
21 #include "chrome/test/base/testing_profile.h"
22 #include "content/public/test/test_browser_thread_bundle.h"
23 #include "extensions/common/extension_builder.h"
24 #include "sql/statement.h"
25 #include "testing/gtest/include/gtest/gtest.h"
27 #if defined(OS_CHROMEOS)
28 #include "chrome/browser/chromeos/login/users/scoped_test_user_manager.h"
29 #include "chrome/browser/chromeos/settings/cros_settings.h"
30 #include "chrome/browser/chromeos/settings/device_settings_service.h"
33 using content::BrowserThread
;
35 namespace extensions
{
37 class CountingPolicyTest
: public testing::Test
{
40 : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP
),
41 saved_cmdline_(base::CommandLine::NO_PROGRAM
) {
42 #if defined OS_CHROMEOS
43 test_user_manager_
.reset(new chromeos::ScopedTestUserManager());
45 base::CommandLine
command_line(base::CommandLine::NO_PROGRAM
);
46 saved_cmdline_
= *base::CommandLine::ForCurrentProcess();
47 profile_
.reset(new TestingProfile());
48 base::CommandLine::ForCurrentProcess()->AppendSwitch(
49 switches::kEnableExtensionActivityLogging
);
50 extension_service_
= static_cast<TestExtensionSystem
*>(
51 ExtensionSystem::Get(profile_
.get()))->CreateExtensionService
52 (&command_line
, base::FilePath(), false);
55 ~CountingPolicyTest() override
{
56 #if defined OS_CHROMEOS
57 test_user_manager_
.reset();
59 base::RunLoop().RunUntilIdle();
61 base::RunLoop().RunUntilIdle();
62 // Restore the original command line and undo the affects of SetUp().
63 *base::CommandLine::ForCurrentProcess() = saved_cmdline_
;
66 // Wait for the task queue for the specified thread to empty.
67 void WaitOnThread(const BrowserThread::ID
& thread
) {
68 BrowserThread::PostTaskAndReply(
71 base::Bind(&base::DoNothing
),
72 base::MessageLoop::current()->QuitClosure());
73 base::MessageLoop::current()->Run();
76 // A wrapper function for CheckReadFilteredData, so that we don't need to
77 // enter empty string values for parameters we don't care about.
79 ActivityLogDatabasePolicy
* policy
,
80 const std::string
& extension_id
,
82 const base::Callback
<void(scoped_ptr
<Action::ActionVector
>)>& checker
) {
83 CheckReadFilteredData(
84 policy
, extension_id
, Action::ACTION_ANY
, "", "", "", day
, checker
);
87 // A helper function to call ReadFilteredData on a policy object and wait for
88 // the results to be processed.
89 void CheckReadFilteredData(
90 ActivityLogDatabasePolicy
* policy
,
91 const std::string
& extension_id
,
92 const Action::ActionType type
,
93 const std::string
& api_name
,
94 const std::string
& page_url
,
95 const std::string
& arg_url
,
97 const base::Callback
<void(scoped_ptr
<Action::ActionVector
>)>& checker
) {
98 // Submit a request to the policy to read back some data, and call the
99 // checker function when results are available. This will happen on the
101 policy
->ReadFilteredData(
108 base::Bind(&CountingPolicyTest::CheckWrapper
,
110 base::MessageLoop::current()->QuitClosure()));
112 // Set up a timeout for receiving results; if we haven't received anything
113 // when the timeout triggers then assume that the test is broken.
114 base::CancelableClosure
timeout(
115 base::Bind(&CountingPolicyTest::TimeoutCallback
));
116 base::MessageLoop::current()->PostDelayedTask(
117 FROM_HERE
, timeout
.callback(), TestTimeouts::action_timeout());
119 // Wait for results; either the checker or the timeout callbacks should
120 // cause the main loop to exit.
121 base::MessageLoop::current()->Run();
126 // A helper function which verifies that the string_ids and url_ids tables in
127 // the database have the specified sizes.
128 static void CheckStringTableSizes(CountingPolicy
* policy
,
131 sql::Connection
* db
= policy
->GetDatabaseConnection();
132 sql::Statement
statement1(db
->GetCachedStatement(
133 sql::StatementID(SQL_FROM_HERE
), "SELECT COUNT(*) FROM string_ids"));
134 ASSERT_TRUE(statement1
.Step());
135 ASSERT_EQ(string_size
, statement1
.ColumnInt(0));
137 sql::Statement
statement2(db
->GetCachedStatement(
138 sql::StatementID(SQL_FROM_HERE
), "SELECT COUNT(*) FROM url_ids"));
139 ASSERT_TRUE(statement2
.Step());
140 ASSERT_EQ(url_size
, statement2
.ColumnInt(0));
143 // Checks that the number of queued actions to be written out does not exceed
144 // kSizeThresholdForFlush. Runs on the database thread.
145 static void CheckQueueSize(CountingPolicy
* policy
) {
146 // This should be updated if kSizeThresholdForFlush in activity_database.cc
148 ASSERT_LE(policy
->queued_actions_
.size(), 200U);
151 static void CheckWrapper(
152 const base::Callback
<void(scoped_ptr
<Action::ActionVector
>)>& checker
,
153 const base::Closure
& done
,
154 scoped_ptr
<Action::ActionVector
> results
) {
155 checker
.Run(results
.Pass());
159 static void TimeoutCallback() {
160 base::MessageLoop::current()->QuitWhenIdle();
161 FAIL() << "Policy test timed out waiting for results";
164 static void RetrieveActions_FetchFilteredActions0(
165 scoped_ptr
<std::vector
<scoped_refptr
<Action
> > > i
) {
166 ASSERT_EQ(0, static_cast<int>(i
->size()));
169 static void RetrieveActions_FetchFilteredActions1(
170 scoped_ptr
<std::vector
<scoped_refptr
<Action
> > > i
) {
171 ASSERT_EQ(1, static_cast<int>(i
->size()));
174 static void RetrieveActions_FetchFilteredActions2(
175 scoped_ptr
<std::vector
<scoped_refptr
<Action
> > > i
) {
176 ASSERT_EQ(2, static_cast<int>(i
->size()));
179 static void RetrieveActions_FetchFilteredActions300(
180 scoped_ptr
<std::vector
<scoped_refptr
<Action
> > > i
) {
181 ASSERT_EQ(300, static_cast<int>(i
->size()));
184 static void Arguments_Stripped(scoped_ptr
<Action::ActionVector
> i
) {
185 scoped_refptr
<Action
> last
= i
->front();
186 CheckAction(*last
.get(),
187 "odlameecjipmbmbejkplpemijjgpljce",
188 Action::ACTION_API_CALL
,
190 "[\"hello\",\"world\"]",
197 static void Arguments_GetSinglesAction(
198 scoped_ptr
<Action::ActionVector
> actions
) {
199 ASSERT_EQ(1, static_cast<int>(actions
->size()));
200 CheckAction(*actions
->at(0).get(),
202 Action::ACTION_DOM_ACCESS
,
205 "http://www.google.com/",
211 static void Arguments_GetTodaysActions(
212 scoped_ptr
<Action::ActionVector
> actions
) {
213 ASSERT_EQ(3, static_cast<int>(actions
->size()));
214 CheckAction(*actions
->at(0).get(),
216 Action::ACTION_API_CALL
,
223 CheckAction(*actions
->at(1).get(),
225 Action::ACTION_DOM_ACCESS
,
228 "http://www.google.com/",
232 CheckAction(*actions
->at(2).get(),
234 Action::ACTION_API_CALL
,
235 "extension.sendMessage",
236 "[\"not\",\"stripped\"]",
243 static void Arguments_GetOlderActions(
244 scoped_ptr
<Action::ActionVector
> actions
) {
245 ASSERT_EQ(2, static_cast<int>(actions
->size()));
246 CheckAction(*actions
->at(0).get(),
248 Action::ACTION_DOM_ACCESS
,
251 "http://www.google.com/",
255 CheckAction(*actions
->at(1).get(),
257 Action::ACTION_API_CALL
,
266 static void Arguments_CheckMergeCount(
268 scoped_ptr
<Action::ActionVector
> actions
) {
270 ASSERT_EQ(1u, actions
->size());
271 CheckAction(*actions
->at(0).get(),
273 Action::ACTION_API_CALL
,
281 ASSERT_EQ(0u, actions
->size());
285 static void Arguments_CheckMergeCountAndTime(
287 const base::Time
& time
,
288 scoped_ptr
<Action::ActionVector
> actions
) {
290 ASSERT_EQ(1u, actions
->size());
291 CheckAction(*actions
->at(0).get(),
293 Action::ACTION_API_CALL
,
300 ASSERT_EQ(time
, actions
->at(0)->time());
302 ASSERT_EQ(0u, actions
->size());
306 static void AllURLsRemoved(scoped_ptr
<Action::ActionVector
> actions
) {
307 ASSERT_EQ(2, static_cast<int>(actions
->size()));
308 CheckAction(*actions
->at(0).get(),
310 Action::ACTION_DOM_ACCESS
,
317 CheckAction(*actions
->at(1).get(),
319 Action::ACTION_DOM_ACCESS
,
328 static void SomeURLsRemoved(scoped_ptr
<Action::ActionVector
> actions
) {
329 // These will be in the vector in reverse time order.
330 ASSERT_EQ(5, static_cast<int>(actions
->size()));
331 CheckAction(*actions
->at(0).get(),
333 Action::ACTION_DOM_ACCESS
,
336 "http://www.google.com/",
338 "http://www.args-url.com/",
340 CheckAction(*actions
->at(1).get(),
342 Action::ACTION_DOM_ACCESS
,
345 "http://www.google.com/",
349 CheckAction(*actions
->at(2).get(),
351 Action::ACTION_DOM_ACCESS
,
358 CheckAction(*actions
->at(3).get(),
360 Action::ACTION_DOM_ACCESS
,
365 "http://www.google.com/",
367 CheckAction(*actions
->at(4).get(),
369 Action::ACTION_DOM_ACCESS
,
378 static void CheckDuplicates(scoped_ptr
<Action::ActionVector
> actions
) {
379 ASSERT_EQ(2u, actions
->size());
381 for (size_t i
= 0; i
< actions
->size(); i
++) {
382 total_count
+= actions
->at(i
)->count();
384 ASSERT_EQ(3, total_count
);
387 static void CheckAction(const Action
& action
,
388 const std::string
& expected_id
,
389 const Action::ActionType
& expected_type
,
390 const std::string
& expected_api_name
,
391 const std::string
& expected_args_str
,
392 const std::string
& expected_page_url
,
393 const std::string
& expected_page_title
,
394 const std::string
& expected_arg_url
,
395 int expected_count
) {
396 ASSERT_EQ(expected_id
, action
.extension_id());
397 ASSERT_EQ(expected_type
, action
.action_type());
398 ASSERT_EQ(expected_api_name
, action
.api_name());
399 ASSERT_EQ(expected_args_str
,
400 ActivityLogPolicy::Util::Serialize(action
.args()));
401 ASSERT_EQ(expected_page_url
, action
.SerializePageUrl());
402 ASSERT_EQ(expected_page_title
, action
.page_title());
403 ASSERT_EQ(expected_arg_url
, action
.SerializeArgUrl());
404 ASSERT_EQ(expected_count
, action
.count());
405 ASSERT_NE(-1, action
.action_id());
408 // A helper function initializes the policy with a number of actions, calls
409 // RemoveActions on a policy object and then checks the result of the
411 void CheckRemoveActions(
412 ActivityLogDatabasePolicy
* policy
,
413 const std::vector
<int64
>& action_ids
,
414 const base::Callback
<void(scoped_ptr
<Action::ActionVector
>)>& checker
) {
416 // Use a mock clock to ensure that events are not recorded on the wrong day
417 // when the test is run close to local midnight.
418 base::SimpleTestClock
* mock_clock
= new base::SimpleTestClock();
419 mock_clock
->SetNow(base::Time::Now().LocalMidnight() +
420 base::TimeDelta::FromHours(12));
421 policy
->SetClockForTesting(scoped_ptr
<base::Clock
>(mock_clock
));
423 // Record some actions
424 scoped_refptr
<Action
> action
=
426 mock_clock
->Now() - base::TimeDelta::FromMinutes(40),
427 Action::ACTION_DOM_ACCESS
,
429 action
->mutable_args()->AppendString("vamoose1");
430 action
->set_page_url(GURL("http://www.google1.com"));
431 action
->set_page_title("Google1");
432 action
->set_arg_url(GURL("http://www.args-url1.com"));
433 policy
->ProcessAction(action
);
434 // Record the same action twice, so there are multiple entries in the
436 policy
->ProcessAction(action
);
438 action
= new Action("punky2",
439 mock_clock
->Now() - base::TimeDelta::FromMinutes(30),
440 Action::ACTION_API_CALL
,
442 action
->mutable_args()->AppendString("vamoose2");
443 action
->set_page_url(GURL("http://www.google2.com"));
444 action
->set_page_title("Google2");
445 action
->set_arg_url(GURL("http://www.args-url2.com"));
446 policy
->ProcessAction(action
);
447 // Record the same action twice, so there are multiple entries in the
449 policy
->ProcessAction(action
);
451 // Submit a request to delete actions.
452 policy
->RemoveActions(action_ids
);
454 // Check the result of the deletion. The checker function gets all
455 // activities in the database.
456 CheckReadData(policy
, "", -1, checker
);
459 policy
->DeleteDatabase();
462 static void AllActionsDeleted(scoped_ptr
<Action::ActionVector
> actions
) {
463 ASSERT_EQ(0, static_cast<int>(actions
->size()));
466 static void NoActionsDeleted(scoped_ptr
<Action::ActionVector
> actions
) {
467 // These will be in the vector in reverse time order.
468 ASSERT_EQ(2, static_cast<int>(actions
->size()));
469 CheckAction(*actions
->at(0).get(),
471 Action::ACTION_API_CALL
,
474 "http://www.google2.com/",
476 "http://www.args-url2.com/",
478 ASSERT_EQ(2, actions
->at(0)->action_id());
479 CheckAction(*actions
->at(1).get(),
481 Action::ACTION_DOM_ACCESS
,
484 "http://www.google1.com/",
486 "http://www.args-url1.com/",
488 ASSERT_EQ(1, actions
->at(1)->action_id());
491 static void Action1Deleted(scoped_ptr
<Action::ActionVector
> actions
) {
492 // These will be in the vector in reverse time order.
493 ASSERT_EQ(1, static_cast<int>(actions
->size()));
494 CheckAction(*actions
->at(0).get(),
496 Action::ACTION_API_CALL
,
499 "http://www.google2.com/",
501 "http://www.args-url2.com/",
503 ASSERT_EQ(2, actions
->at(0)->action_id());
506 static void Action2Deleted(scoped_ptr
<Action::ActionVector
> actions
) {
507 // These will be in the vector in reverse time order.
508 ASSERT_EQ(1, static_cast<int>(actions
->size()));
509 CheckAction(*actions
->at(0).get(),
511 Action::ACTION_DOM_ACCESS
,
514 "http://www.google1.com/",
516 "http://www.args-url1.com/",
518 ASSERT_EQ(1, actions
->at(0)->action_id());
522 ExtensionService
* extension_service_
;
523 scoped_ptr
<TestingProfile
> profile_
;
524 content::TestBrowserThreadBundle thread_bundle_
;
525 // Used to preserve a copy of the original command line.
526 // The test framework will do this itself as well. However, by then,
527 // it is too late to call ActivityLog::RecomputeLoggingIsEnabled() in
529 base::CommandLine saved_cmdline_
;
531 #if defined OS_CHROMEOS
532 chromeos::ScopedTestDeviceSettingsService test_device_settings_service_
;
533 chromeos::ScopedTestCrosSettings test_cros_settings_
;
534 scoped_ptr
<chromeos::ScopedTestUserManager
> test_user_manager_
;
538 TEST_F(CountingPolicyTest
, Construct
) {
539 ActivityLogDatabasePolicy
* policy
= new CountingPolicy(profile_
.get());
541 scoped_refptr
<const Extension
> extension
=
543 .SetManifest(DictionaryBuilder()
544 .Set("name", "Test extension")
545 .Set("version", "1.0.0")
546 .Set("manifest_version", 2))
548 extension_service_
->AddExtension(extension
.get());
549 scoped_ptr
<base::ListValue
> args(new base::ListValue());
550 scoped_refptr
<Action
> action
= new Action(extension
->id(),
552 Action::ACTION_API_CALL
,
554 action
->set_args(args
.Pass());
555 policy
->ProcessAction(action
);
559 TEST_F(CountingPolicyTest
, LogWithStrippedArguments
) {
560 ActivityLogDatabasePolicy
* policy
= new CountingPolicy(profile_
.get());
562 scoped_refptr
<const Extension
> extension
=
564 .SetManifest(DictionaryBuilder()
565 .Set("name", "Test extension")
566 .Set("version", "1.0.0")
567 .Set("manifest_version", 2))
569 extension_service_
->AddExtension(extension
.get());
571 scoped_ptr
<base::ListValue
> args(new base::ListValue());
572 args
->Set(0, new base::StringValue("hello"));
573 args
->Set(1, new base::StringValue("world"));
574 scoped_refptr
<Action
> action
= new Action(extension
->id(),
576 Action::ACTION_API_CALL
,
577 "extension.connect");
578 action
->set_args(args
.Pass());
580 policy
->ProcessAction(action
);
581 CheckReadData(policy
,
584 base::Bind(&CountingPolicyTest::Arguments_Stripped
));
588 TEST_F(CountingPolicyTest
, GetTodaysActions
) {
589 CountingPolicy
* policy
= new CountingPolicy(profile_
.get());
591 // Disable row expiration for this test by setting a time before any actions
593 policy
->set_retention_time(base::TimeDelta::FromDays(14));
595 // Use a mock clock to ensure that events are not recorded on the wrong day
596 // when the test is run close to local midnight. Note: Ownership is passed
597 // to the policy, but we still keep a pointer locally. The policy will take
598 // care of destruction; this is safe since the policy outlives all our
599 // accesses to the mock clock.
600 base::SimpleTestClock
* mock_clock
= new base::SimpleTestClock();
601 mock_clock
->SetNow(base::Time::Now().LocalMidnight() +
602 base::TimeDelta::FromHours(12));
603 policy
->SetClockForTesting(scoped_ptr
<base::Clock
>(mock_clock
));
605 // Record some actions
606 scoped_refptr
<Action
> action
=
608 mock_clock
->Now() - base::TimeDelta::FromMinutes(40),
609 Action::ACTION_API_CALL
,
611 action
->mutable_args()->AppendString("woof");
612 policy
->ProcessAction(action
);
614 action
= new Action("punky",
615 mock_clock
->Now() - base::TimeDelta::FromMinutes(30),
616 Action::ACTION_API_CALL
,
618 action
->mutable_args()->AppendString("meow");
619 policy
->ProcessAction(action
);
621 action
= new Action("punky",
622 mock_clock
->Now() - base::TimeDelta::FromMinutes(20),
623 Action::ACTION_API_CALL
,
624 "extension.sendMessage");
625 action
->mutable_args()->AppendString("not");
626 action
->mutable_args()->AppendString("stripped");
627 policy
->ProcessAction(action
);
630 new Action("punky", mock_clock
->Now(), Action::ACTION_DOM_ACCESS
, "lets");
631 action
->mutable_args()->AppendString("vamoose");
632 action
->set_page_url(GURL("http://www.google.com"));
633 policy
->ProcessAction(action
);
636 "scoobydoo", mock_clock
->Now(), Action::ACTION_DOM_ACCESS
, "lets");
637 action
->mutable_args()->AppendString("vamoose");
638 action
->set_page_url(GURL("http://www.google.com"));
639 policy
->ProcessAction(action
);
645 base::Bind(&CountingPolicyTest::Arguments_GetTodaysActions
));
649 // Check that we can read back less recent actions in the db.
650 TEST_F(CountingPolicyTest
, GetOlderActions
) {
651 CountingPolicy
* policy
= new CountingPolicy(profile_
.get());
653 policy
->set_retention_time(base::TimeDelta::FromDays(14));
655 // Use a mock clock to ensure that events are not recorded on the wrong day
656 // when the test is run close to local midnight.
657 base::SimpleTestClock
* mock_clock
= new base::SimpleTestClock();
658 mock_clock
->SetNow(base::Time::Now().LocalMidnight() +
659 base::TimeDelta::FromHours(12));
660 policy
->SetClockForTesting(scoped_ptr
<base::Clock
>(mock_clock
));
662 // Record some actions
663 scoped_refptr
<Action
> action
=
665 mock_clock
->Now() - base::TimeDelta::FromDays(3) -
666 base::TimeDelta::FromMinutes(40),
667 Action::ACTION_API_CALL
,
669 action
->mutable_args()->AppendString("woof");
670 policy
->ProcessAction(action
);
672 action
= new Action("punky",
673 mock_clock
->Now() - base::TimeDelta::FromDays(3),
674 Action::ACTION_DOM_ACCESS
,
676 action
->mutable_args()->AppendString("vamoose");
677 action
->set_page_url(GURL("http://www.google.com"));
678 policy
->ProcessAction(action
);
680 action
= new Action("punky",
682 Action::ACTION_DOM_ACCESS
,
684 action
->mutable_args()->AppendString("too new");
685 action
->set_page_url(GURL("http://www.google.com"));
686 policy
->ProcessAction(action
);
688 action
= new Action("punky",
689 mock_clock
->Now() - base::TimeDelta::FromDays(7),
690 Action::ACTION_DOM_ACCESS
,
692 action
->mutable_args()->AppendString("too old");
693 action
->set_page_url(GURL("http://www.google.com"));
694 policy
->ProcessAction(action
);
700 base::Bind(&CountingPolicyTest::Arguments_GetOlderActions
));
705 TEST_F(CountingPolicyTest
, LogAndFetchFilteredActions
) {
706 ActivityLogDatabasePolicy
* policy
= new CountingPolicy(profile_
.get());
708 scoped_refptr
<const Extension
> extension
=
710 .SetManifest(DictionaryBuilder()
711 .Set("name", "Test extension")
712 .Set("version", "1.0.0")
713 .Set("manifest_version", 2))
715 extension_service_
->AddExtension(extension
.get());
716 GURL
gurl("http://www.google.com");
718 // Write some API calls
719 scoped_refptr
<Action
> action_api
= new Action(extension
->id(),
721 Action::ACTION_API_CALL
,
723 action_api
->set_args(make_scoped_ptr(new base::ListValue()));
724 policy
->ProcessAction(action_api
);
726 scoped_refptr
<Action
> action_dom
= new Action(extension
->id(),
728 Action::ACTION_DOM_ACCESS
,
730 action_dom
->set_args(make_scoped_ptr(new base::ListValue()));
731 action_dom
->set_page_url(gurl
);
732 policy
->ProcessAction(action_dom
);
734 CheckReadFilteredData(
737 Action::ACTION_API_CALL
,
743 &CountingPolicyTest::RetrieveActions_FetchFilteredActions1
));
745 CheckReadFilteredData(
748 Action::ACTION_DOM_ACCESS
,
754 &CountingPolicyTest::RetrieveActions_FetchFilteredActions1
));
756 CheckReadFilteredData(
759 Action::ACTION_DOM_ACCESS
,
761 "http://www.google.com/",
765 &CountingPolicyTest::RetrieveActions_FetchFilteredActions1
));
767 CheckReadFilteredData(
770 Action::ACTION_DOM_ACCESS
,
772 "http://www.google.com",
776 &CountingPolicyTest::RetrieveActions_FetchFilteredActions1
));
778 CheckReadFilteredData(
781 Action::ACTION_DOM_ACCESS
,
787 &CountingPolicyTest::RetrieveActions_FetchFilteredActions1
));
789 CheckReadFilteredData(
798 &CountingPolicyTest::RetrieveActions_FetchFilteredActions2
));
803 // Check that merging of actions only occurs within the same day, not across
804 // days, and that old data can be expired from the database.
805 TEST_F(CountingPolicyTest
, MergingAndExpiring
) {
806 CountingPolicy
* policy
= new CountingPolicy(profile_
.get());
808 // Initially disable expiration by setting a retention time before any
809 // actions we generate.
810 policy
->set_retention_time(base::TimeDelta::FromDays(14));
812 // Use a mock clock to ensure that events are not recorded on the wrong day
813 // when the test is run close to local midnight.
814 base::SimpleTestClock
* mock_clock
= new base::SimpleTestClock();
815 mock_clock
->SetNow(base::Time::Now().LocalMidnight() +
816 base::TimeDelta::FromHours(12));
817 policy
->SetClockForTesting(scoped_ptr
<base::Clock
>(mock_clock
));
819 // The first two actions should be merged; the last one is on a separate day
820 // and should not be.
821 scoped_refptr
<Action
> action
=
823 mock_clock
->Now() - base::TimeDelta::FromDays(3) -
824 base::TimeDelta::FromMinutes(40),
825 Action::ACTION_API_CALL
,
827 policy
->ProcessAction(action
);
829 action
= new Action("punky",
830 mock_clock
->Now() - base::TimeDelta::FromDays(3) -
831 base::TimeDelta::FromMinutes(20),
832 Action::ACTION_API_CALL
,
834 policy
->ProcessAction(action
);
836 action
= new Action("punky",
837 mock_clock
->Now() - base::TimeDelta::FromDays(2) -
838 base::TimeDelta::FromMinutes(20),
839 Action::ACTION_API_CALL
,
841 policy
->ProcessAction(action
);
843 CheckReadData(policy
,
846 base::Bind(&CountingPolicyTest::Arguments_CheckMergeCount
, 2));
847 CheckReadData(policy
,
850 base::Bind(&CountingPolicyTest::Arguments_CheckMergeCount
, 1));
852 // Clean actions before midnight two days ago. Force expiration to run by
853 // clearing last_database_cleaning_time_ and submitting a new action.
854 policy
->set_retention_time(base::TimeDelta::FromDays(2));
855 policy
->last_database_cleaning_time_
= base::Time();
856 action
= new Action("punky",
858 Action::ACTION_API_CALL
,
860 policy
->ProcessAction(action
);
862 CheckReadData(policy
,
865 base::Bind(&CountingPolicyTest::Arguments_CheckMergeCount
, 0));
866 CheckReadData(policy
,
869 base::Bind(&CountingPolicyTest::Arguments_CheckMergeCount
, 1));
874 // Test cleaning of old data in the string and URL tables.
875 TEST_F(CountingPolicyTest
, StringTableCleaning
) {
876 CountingPolicy
* policy
= new CountingPolicy(profile_
.get());
878 // Initially disable expiration by setting a retention time before any
879 // actions we generate.
880 policy
->set_retention_time(base::TimeDelta::FromDays(14));
882 base::SimpleTestClock
* mock_clock
= new base::SimpleTestClock();
883 mock_clock
->SetNow(base::Time::Now());
884 policy
->SetClockForTesting(scoped_ptr
<base::Clock
>(mock_clock
));
886 // Insert an action; this should create entries in both the string table (for
887 // the extension and API name) and the URL table (for page_url).
888 scoped_refptr
<Action
> action
=
890 mock_clock
->Now() - base::TimeDelta::FromDays(7),
891 Action::ACTION_API_CALL
,
893 action
->set_page_url(GURL("http://www.google.com/"));
894 policy
->ProcessAction(action
);
896 // Add an action which will not be expired, so that some strings will remain
899 "punky", mock_clock
->Now(), Action::ACTION_API_CALL
, "tabs.create");
900 policy
->ProcessAction(action
);
902 // There should now be three strings ("punky", "brewster", "tabs.create") and
903 // one URL in the tables.
905 policy
->ScheduleAndForget(policy
,
906 &CountingPolicyTest::CheckStringTableSizes
,
909 WaitOnThread(BrowserThread::DB
);
911 // Trigger a cleaning. The oldest action is expired when we submit a
912 // duplicate of the newer action. After this, there should be two strings
914 policy
->set_retention_time(base::TimeDelta::FromDays(2));
915 policy
->last_database_cleaning_time_
= base::Time();
916 policy
->ProcessAction(action
);
918 policy
->ScheduleAndForget(policy
,
919 &CountingPolicyTest::CheckStringTableSizes
,
922 WaitOnThread(BrowserThread::DB
);
927 // A stress test for memory- and database-based merging of actions. Submit
928 // multiple items, not in chronological order, spanning a few days. Check that
929 // items are merged properly and final timestamps are correct.
930 TEST_F(CountingPolicyTest
, MoreMerging
) {
931 CountingPolicy
* policy
= new CountingPolicy(profile_
.get());
933 policy
->set_retention_time(base::TimeDelta::FromDays(14));
935 // Use a mock clock to ensure that events are not recorded on the wrong day
936 // when the test is run close to local midnight.
937 base::SimpleTestClock
* mock_clock
= new base::SimpleTestClock();
938 mock_clock
->SetNow(base::Time::Now().LocalMidnight() +
939 base::TimeDelta::FromHours(12));
940 policy
->SetClockForTesting(scoped_ptr
<base::Clock
>(mock_clock
));
942 // Create an action 2 days ago, then 1 day ago, then 2 days ago. Make sure
943 // that we end up with two merged records (one for each day), and each has
944 // the appropriate timestamp. These merges should happen in the database
945 // since the date keeps changing.
947 mock_clock
->Now() - base::TimeDelta::FromDays(2) -
948 base::TimeDelta::FromMinutes(40);
950 mock_clock
->Now() - base::TimeDelta::FromDays(1) -
951 base::TimeDelta::FromMinutes(40);
953 mock_clock
->Now() - base::TimeDelta::FromDays(2) -
954 base::TimeDelta::FromMinutes(20);
956 scoped_refptr
<Action
> action
=
957 new Action("punky", time1
, Action::ACTION_API_CALL
, "brewster");
958 policy
->ProcessAction(action
);
960 action
= new Action("punky", time2
, Action::ACTION_API_CALL
, "brewster");
961 policy
->ProcessAction(action
);
963 action
= new Action("punky", time3
, Action::ACTION_API_CALL
, "brewster");
964 policy
->ProcessAction(action
);
971 &CountingPolicyTest::Arguments_CheckMergeCountAndTime
, 2, time3
));
977 &CountingPolicyTest::Arguments_CheckMergeCountAndTime
, 1, time2
));
979 // Create three actions today, where the merges should happen in memory.
980 // Again these are not chronological; timestamp time5 should win out since it
982 base::Time time4
= mock_clock
->Now() - base::TimeDelta::FromMinutes(60);
983 base::Time time5
= mock_clock
->Now() - base::TimeDelta::FromMinutes(20);
984 base::Time time6
= mock_clock
->Now() - base::TimeDelta::FromMinutes(40);
986 action
= new Action("punky", time4
, Action::ACTION_API_CALL
, "brewster");
987 policy
->ProcessAction(action
);
989 action
= new Action("punky", time5
, Action::ACTION_API_CALL
, "brewster");
990 policy
->ProcessAction(action
);
992 action
= new Action("punky", time6
, Action::ACTION_API_CALL
, "brewster");
993 policy
->ProcessAction(action
);
1000 &CountingPolicyTest::Arguments_CheckMergeCountAndTime
, 3, time5
));
1004 // Check that actions are flushed to disk before letting too many accumulate in
1006 TEST_F(CountingPolicyTest
, EarlyFlush
) {
1007 CountingPolicy
* policy
= new CountingPolicy(profile_
.get());
1010 for (int i
= 0; i
< 500; i
++) {
1011 scoped_refptr
<Action
> action
=
1014 Action::ACTION_API_CALL
,
1015 base::StringPrintf("apicall_%d", i
));
1016 policy
->ProcessAction(action
);
1019 policy
->ScheduleAndForget(policy
, &CountingPolicyTest::CheckQueueSize
);
1020 WaitOnThread(BrowserThread::DB
);
1025 TEST_F(CountingPolicyTest
, CapReturns
) {
1026 CountingPolicy
* policy
= new CountingPolicy(profile_
.get());
1029 for (int i
= 0; i
< 305; i
++) {
1030 scoped_refptr
<Action
> action
=
1033 Action::ACTION_API_CALL
,
1034 base::StringPrintf("apicall_%d", i
));
1035 policy
->ProcessAction(action
);
1039 WaitOnThread(BrowserThread::DB
);
1041 CheckReadFilteredData(
1050 &CountingPolicyTest::RetrieveActions_FetchFilteredActions300
));
1054 TEST_F(CountingPolicyTest
, RemoveAllURLs
) {
1055 ActivityLogDatabasePolicy
* policy
= new CountingPolicy(profile_
.get());
1058 // Use a mock clock to ensure that events are not recorded on the wrong day
1059 // when the test is run close to local midnight.
1060 base::SimpleTestClock
* mock_clock
= new base::SimpleTestClock();
1061 mock_clock
->SetNow(base::Time::Now().LocalMidnight() +
1062 base::TimeDelta::FromHours(12));
1063 policy
->SetClockForTesting(scoped_ptr
<base::Clock
>(mock_clock
));
1065 // Record some actions
1066 scoped_refptr
<Action
> action
=
1067 new Action("punky", mock_clock
->Now(),
1068 Action::ACTION_DOM_ACCESS
, "lets");
1069 action
->mutable_args()->AppendString("vamoose");
1070 action
->set_page_url(GURL("http://www.google.com"));
1071 action
->set_page_title("Google");
1072 action
->set_arg_url(GURL("http://www.args-url.com"));
1073 policy
->ProcessAction(action
);
1075 mock_clock
->Advance(base::TimeDelta::FromSeconds(1));
1076 action
= new Action(
1077 "punky", mock_clock
->Now(), Action::ACTION_DOM_ACCESS
, "lets");
1078 action
->mutable_args()->AppendString("vamoose");
1079 action
->set_page_url(GURL("http://www.google2.com"));
1080 action
->set_page_title("Google");
1081 // Deliberately no arg url set to make sure it stills works if there is no arg
1083 policy
->ProcessAction(action
);
1085 // Clean all the URLs.
1086 std::vector
<GURL
> no_url_restrictions
;
1087 policy
->RemoveURLs(no_url_restrictions
);
1093 base::Bind(&CountingPolicyTest::AllURLsRemoved
));
1097 TEST_F(CountingPolicyTest
, RemoveSpecificURLs
) {
1098 ActivityLogDatabasePolicy
* policy
= new CountingPolicy(profile_
.get());
1101 // Use a mock clock to ensure that events are not recorded on the wrong day
1102 // when the test is run close to local midnight.
1103 base::SimpleTestClock
* mock_clock
= new base::SimpleTestClock();
1104 mock_clock
->SetNow(base::Time::Now().LocalMidnight() +
1105 base::TimeDelta::FromHours(12));
1106 policy
->SetClockForTesting(scoped_ptr
<base::Clock
>(mock_clock
));
1108 // Record some actions
1109 // This should have the page url and args url cleared.
1110 scoped_refptr
<Action
> action
= new Action("punky", mock_clock
->Now(),
1111 Action::ACTION_DOM_ACCESS
, "lets");
1112 action
->mutable_args()->AppendString("vamoose");
1113 action
->set_page_url(GURL("http://www.google1.com"));
1114 action
->set_page_title("Google");
1115 action
->set_arg_url(GURL("http://www.google1.com"));
1116 policy
->ProcessAction(action
);
1118 // This should have the page url cleared but not args url.
1119 mock_clock
->Advance(base::TimeDelta::FromSeconds(1));
1120 action
= new Action(
1121 "punky", mock_clock
->Now(), Action::ACTION_DOM_ACCESS
, "lets");
1122 action
->mutable_args()->AppendString("vamoose");
1123 action
->set_page_url(GURL("http://www.google1.com"));
1124 action
->set_page_title("Google");
1125 action
->set_arg_url(GURL("http://www.google.com"));
1126 policy
->ProcessAction(action
);
1128 // This should have the page url cleared. The args url is deliberately not
1129 // set to make sure this doesn't cause any issues.
1130 mock_clock
->Advance(base::TimeDelta::FromSeconds(1));
1131 action
= new Action(
1132 "punky", mock_clock
->Now(), Action::ACTION_DOM_ACCESS
, "lets");
1133 action
->mutable_args()->AppendString("vamoose");
1134 action
->set_page_url(GURL("http://www.google2.com"));
1135 action
->set_page_title("Google");
1136 policy
->ProcessAction(action
);
1138 // This should have the args url cleared but not the page url or page title.
1139 mock_clock
->Advance(base::TimeDelta::FromSeconds(1));
1140 action
= new Action(
1141 "punky", mock_clock
->Now(), Action::ACTION_DOM_ACCESS
, "lets");
1142 action
->mutable_args()->AppendString("vamoose");
1143 action
->set_page_url(GURL("http://www.google.com"));
1144 action
->set_page_title("Google");
1145 action
->set_arg_url(GURL("http://www.google1.com"));
1146 policy
->ProcessAction(action
);
1148 // This should have neither cleared.
1149 mock_clock
->Advance(base::TimeDelta::FromSeconds(1));
1150 action
= new Action(
1151 "punky", mock_clock
->Now(), Action::ACTION_DOM_ACCESS
, "lets");
1152 action
->mutable_args()->AppendString("vamoose");
1153 action
->set_page_url(GURL("http://www.google.com"));
1154 action
->set_page_title("Google");
1155 action
->set_arg_url(GURL("http://www.args-url.com"));
1156 action
->set_count(5);
1157 policy
->ProcessAction(action
);
1160 std::vector
<GURL
> urls
;
1161 urls
.push_back(GURL("http://www.google1.com"));
1162 urls
.push_back(GURL("http://www.google2.com"));
1163 urls
.push_back(GURL("http://www.url_not_in_db.com"));
1164 policy
->RemoveURLs(urls
);
1170 base::Bind(&CountingPolicyTest::SomeURLsRemoved
));
1174 TEST_F(CountingPolicyTest
, RemoveExtensionData
) {
1175 CountingPolicy
* policy
= new CountingPolicy(profile_
.get());
1178 // Use a mock clock to ensure that events are not recorded on the wrong day
1179 // when the test is run close to local midnight.
1180 base::SimpleTestClock
* mock_clock
= new base::SimpleTestClock();
1181 mock_clock
->SetNow(base::Time::Now().LocalMidnight() +
1182 base::TimeDelta::FromHours(12));
1183 policy
->SetClockForTesting(scoped_ptr
<base::Clock
>(mock_clock
));
1185 // Record some actions
1186 scoped_refptr
<Action
> action
= new Action("deleteextensiondata",
1188 Action::ACTION_DOM_ACCESS
,
1190 action
->mutable_args()->AppendString("vamoose");
1191 action
->set_page_title("Google");
1192 action
->set_arg_url(GURL("http://www.google.com"));
1193 policy
->ProcessAction(action
);
1194 policy
->ProcessAction(action
);
1195 policy
->ProcessAction(action
);
1197 scoped_refptr
<Action
> action2
= new Action("dontdelete",
1199 Action::ACTION_DOM_ACCESS
,
1201 action
->mutable_args()->AppendString("vamoose");
1202 action
->set_page_title("Google");
1203 action
->set_arg_url(GURL("http://www.google.com"));
1204 policy
->ProcessAction(action2
);
1207 policy
->RemoveExtensionData("deleteextensiondata");
1209 CheckReadFilteredData(
1211 "deleteextensiondata",
1218 &CountingPolicyTest::RetrieveActions_FetchFilteredActions0
));
1220 CheckReadFilteredData(
1229 &CountingPolicyTest::RetrieveActions_FetchFilteredActions1
));
1233 TEST_F(CountingPolicyTest
, DeleteDatabase
) {
1234 CountingPolicy
* policy
= new CountingPolicy(profile_
.get());
1236 // Disable row expiration for this test by setting a time before any actions
1238 policy
->set_retention_time(base::TimeDelta::FromDays(14));
1240 // Use a mock clock to ensure that events are not recorded on the wrong day
1241 // when the test is run close to local midnight. Note: Ownership is passed
1242 // to the policy, but we still keep a pointer locally. The policy will take
1243 // care of destruction; this is safe since the policy outlives all our
1244 // accesses to the mock clock.
1245 base::SimpleTestClock
* mock_clock
= new base::SimpleTestClock();
1246 mock_clock
->SetNow(base::Time::Now().LocalMidnight() +
1247 base::TimeDelta::FromHours(12));
1248 policy
->SetClockForTesting(scoped_ptr
<base::Clock
>(mock_clock
));
1250 // Record some actions
1251 scoped_refptr
<Action
> action
=
1253 mock_clock
->Now() - base::TimeDelta::FromMinutes(40),
1254 Action::ACTION_API_CALL
,
1256 action
->mutable_args()->AppendString("woof");
1257 policy
->ProcessAction(action
);
1259 action
= new Action("punky",
1260 mock_clock
->Now() - base::TimeDelta::FromMinutes(30),
1261 Action::ACTION_API_CALL
,
1263 action
->mutable_args()->AppendString("meow");
1264 policy
->ProcessAction(action
);
1266 action
= new Action("punky",
1267 mock_clock
->Now() - base::TimeDelta::FromMinutes(20),
1268 Action::ACTION_API_CALL
,
1269 "extension.sendMessage");
1270 action
->mutable_args()->AppendString("not");
1271 action
->mutable_args()->AppendString("stripped");
1272 policy
->ProcessAction(action
);
1275 new Action("punky", mock_clock
->Now(), Action::ACTION_DOM_ACCESS
, "lets");
1276 action
->mutable_args()->AppendString("vamoose");
1277 action
->set_page_url(GURL("http://www.google.com"));
1278 policy
->ProcessAction(action
);
1280 action
= new Action(
1281 "scoobydoo", mock_clock
->Now(), Action::ACTION_DOM_ACCESS
, "lets");
1282 action
->mutable_args()->AppendString("vamoose");
1283 action
->set_page_url(GURL("http://www.google.com"));
1284 policy
->ProcessAction(action
);
1290 base::Bind(&CountingPolicyTest::Arguments_GetTodaysActions
));
1292 policy
->DeleteDatabase();
1294 CheckReadFilteredData(
1303 &CountingPolicyTest::RetrieveActions_FetchFilteredActions0
));
1305 // The following code tests that the caches of url and string tables were
1306 // cleared by the deletion above.
1307 // https://code.google.com/p/chromium/issues/detail?id=341674.
1309 new Action("punky", mock_clock
->Now(), Action::ACTION_DOM_ACCESS
, "lets");
1310 action
->mutable_args()->AppendString("vamoose");
1311 action
->set_page_url(GURL("http://www.google.com"));
1312 policy
->ProcessAction(action
);
1318 base::Bind(&CountingPolicyTest::Arguments_GetSinglesAction
));
1320 policy
->DeleteDatabase();
1322 CheckReadFilteredData(
1331 &CountingPolicyTest::RetrieveActions_FetchFilteredActions0
));
1336 // Tests that duplicate rows in the activity log database are handled properly
1337 // when updating counts.
1338 TEST_F(CountingPolicyTest
, DuplicateRows
) {
1339 CountingPolicy
* policy
= new CountingPolicy(profile_
.get());
1341 base::SimpleTestClock
* mock_clock
= new base::SimpleTestClock();
1342 mock_clock
->SetNow(base::Time::Now().LocalMidnight() +
1343 base::TimeDelta::FromHours(12));
1344 policy
->SetClockForTesting(scoped_ptr
<base::Clock
>(mock_clock
));
1346 // Record two actions with distinct URLs.
1347 scoped_refptr
<Action
> action
;
1348 action
= new Action(
1349 "punky", mock_clock
->Now(), Action::ACTION_API_CALL
, "brewster");
1350 action
->set_page_url(GURL("http://www.google.com"));
1351 policy
->ProcessAction(action
);
1353 action
= new Action(
1354 "punky", mock_clock
->Now(), Action::ACTION_API_CALL
, "brewster");
1355 action
->set_page_url(GURL("http://www.google.co.uk"));
1356 policy
->ProcessAction(action
);
1358 // Manipulate the database to clear the URLs, so that we end up with
1360 std::vector
<GURL
> no_url_restrictions
;
1361 policy
->RemoveURLs(no_url_restrictions
);
1363 // Record one more action, with no URL. This should increment the count on
1364 // one, and exactly one, of the existing rows.
1365 action
= new Action(
1366 "punky", mock_clock
->Now(), Action::ACTION_API_CALL
, "brewster");
1367 policy
->ProcessAction(action
);
1373 base::Bind(&CountingPolicyTest::CheckDuplicates
));
1377 TEST_F(CountingPolicyTest
, RemoveActions
) {
1378 ActivityLogDatabasePolicy
* policy
= new CountingPolicy(profile_
.get());
1381 std::vector
<int64
> action_ids
;
1384 policy
, action_ids
, base::Bind(&CountingPolicyTest::NoActionsDeleted
));
1386 action_ids
.push_back(-1);
1387 action_ids
.push_back(-10);
1388 action_ids
.push_back(0);
1389 action_ids
.push_back(5);
1390 action_ids
.push_back(10);
1392 policy
, action_ids
, base::Bind(&CountingPolicyTest::NoActionsDeleted
));
1395 for (int i
= 0; i
< 50; i
++) {
1396 action_ids
.push_back(i
+ 3);
1399 policy
, action_ids
, base::Bind(&CountingPolicyTest::NoActionsDeleted
));
1402 // CheckRemoveActions pushes two actions to the Activity Log database with IDs
1404 action_ids
.push_back(1);
1405 action_ids
.push_back(2);
1407 policy
, action_ids
, base::Bind(&CountingPolicyTest::AllActionsDeleted
));
1410 action_ids
.push_back(1);
1412 policy
, action_ids
, base::Bind(&CountingPolicyTest::Action1Deleted
));
1415 action_ids
.push_back(2);
1417 policy
, action_ids
, base::Bind(&CountingPolicyTest::Action2Deleted
));
1423 } // namespace extensions