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/location.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/run_loop.h"
10 #include "base/single_thread_task_runner.h"
11 #include "base/strings/string_split.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/synchronization/waitable_event.h"
14 #include "base/test/simple_test_clock.h"
15 #include "base/test/test_timeouts.h"
16 #include "base/thread_task_runner_handle.h"
17 #include "chrome/browser/extensions/activity_log/activity_log.h"
18 #include "chrome/browser/extensions/activity_log/counting_policy.h"
19 #include "chrome/browser/extensions/extension_service.h"
20 #include "chrome/browser/extensions/test_extension_system.h"
21 #include "chrome/common/chrome_constants.h"
22 #include "chrome/common/chrome_switches.h"
23 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
24 #include "chrome/test/base/testing_profile.h"
25 #include "content/public/test/test_browser_thread_bundle.h"
26 #include "extensions/common/extension_builder.h"
27 #include "sql/statement.h"
28 #include "testing/gtest/include/gtest/gtest.h"
30 #if defined(OS_CHROMEOS)
31 #include "chrome/browser/chromeos/login/users/scoped_test_user_manager.h"
32 #include "chrome/browser/chromeos/settings/cros_settings.h"
33 #include "chrome/browser/chromeos/settings/device_settings_service.h"
36 using content::BrowserThread
;
38 namespace extensions
{
40 class CountingPolicyTest
: public testing::Test
{
43 : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP
),
44 saved_cmdline_(base::CommandLine::NO_PROGRAM
) {
45 #if defined OS_CHROMEOS
46 test_user_manager_
.reset(new chromeos::ScopedTestUserManager());
48 base::CommandLine
command_line(base::CommandLine::NO_PROGRAM
);
49 saved_cmdline_
= *base::CommandLine::ForCurrentProcess();
50 profile_
.reset(new TestingProfile());
51 base::CommandLine::ForCurrentProcess()->AppendSwitch(
52 switches::kEnableExtensionActivityLogging
);
53 extension_service_
= static_cast<TestExtensionSystem
*>(
54 ExtensionSystem::Get(profile_
.get()))->CreateExtensionService
55 (&command_line
, base::FilePath(), false);
58 ~CountingPolicyTest() override
{
59 #if defined OS_CHROMEOS
60 test_user_manager_
.reset();
62 base::RunLoop().RunUntilIdle();
64 base::RunLoop().RunUntilIdle();
65 // Restore the original command line and undo the affects of SetUp().
66 *base::CommandLine::ForCurrentProcess() = saved_cmdline_
;
69 // Wait for the task queue for the specified thread to empty.
70 void WaitOnThread(const BrowserThread::ID
& thread
) {
71 BrowserThread::PostTaskAndReply(
74 base::Bind(&base::DoNothing
),
75 base::MessageLoop::current()->QuitClosure());
76 base::MessageLoop::current()->Run();
79 // A wrapper function for CheckReadFilteredData, so that we don't need to
80 // enter empty string values for parameters we don't care about.
82 ActivityLogDatabasePolicy
* policy
,
83 const std::string
& extension_id
,
85 const base::Callback
<void(scoped_ptr
<Action::ActionVector
>)>& checker
) {
86 CheckReadFilteredData(
87 policy
, extension_id
, Action::ACTION_ANY
, "", "", "", day
, checker
);
90 // A helper function to call ReadFilteredData on a policy object and wait for
91 // the results to be processed.
92 void CheckReadFilteredData(
93 ActivityLogDatabasePolicy
* policy
,
94 const std::string
& extension_id
,
95 const Action::ActionType type
,
96 const std::string
& api_name
,
97 const std::string
& page_url
,
98 const std::string
& arg_url
,
100 const base::Callback
<void(scoped_ptr
<Action::ActionVector
>)>& checker
) {
101 // Submit a request to the policy to read back some data, and call the
102 // checker function when results are available. This will happen on the
104 policy
->ReadFilteredData(
111 base::Bind(&CountingPolicyTest::CheckWrapper
,
113 base::MessageLoop::current()->QuitClosure()));
115 // Set up a timeout for receiving results; if we haven't received anything
116 // when the timeout triggers then assume that the test is broken.
117 base::CancelableClosure
timeout(
118 base::Bind(&CountingPolicyTest::TimeoutCallback
));
119 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
120 FROM_HERE
, timeout
.callback(), TestTimeouts::action_timeout());
122 // Wait for results; either the checker or the timeout callbacks should
123 // cause the main loop to exit.
124 base::MessageLoop::current()->Run();
129 // A helper function which verifies that the string_ids and url_ids tables in
130 // the database have the specified sizes.
131 static void CheckStringTableSizes(CountingPolicy
* policy
,
134 sql::Connection
* db
= policy
->GetDatabaseConnection();
135 sql::Statement
statement1(db
->GetCachedStatement(
136 sql::StatementID(SQL_FROM_HERE
), "SELECT COUNT(*) FROM string_ids"));
137 ASSERT_TRUE(statement1
.Step());
138 ASSERT_EQ(string_size
, statement1
.ColumnInt(0));
140 sql::Statement
statement2(db
->GetCachedStatement(
141 sql::StatementID(SQL_FROM_HERE
), "SELECT COUNT(*) FROM url_ids"));
142 ASSERT_TRUE(statement2
.Step());
143 ASSERT_EQ(url_size
, statement2
.ColumnInt(0));
146 // Checks that the number of queued actions to be written out does not exceed
147 // kSizeThresholdForFlush. Runs on the database thread.
148 static void CheckQueueSize(CountingPolicy
* policy
) {
149 // This should be updated if kSizeThresholdForFlush in activity_database.cc
151 ASSERT_LE(policy
->queued_actions_
.size(), 200U);
154 static void CheckWrapper(
155 const base::Callback
<void(scoped_ptr
<Action::ActionVector
>)>& checker
,
156 const base::Closure
& done
,
157 scoped_ptr
<Action::ActionVector
> results
) {
158 checker
.Run(results
.Pass());
162 static void TimeoutCallback() {
163 base::MessageLoop::current()->QuitWhenIdle();
164 FAIL() << "Policy test timed out waiting for results";
167 static void RetrieveActions_FetchFilteredActions0(
168 scoped_ptr
<std::vector
<scoped_refptr
<Action
> > > i
) {
169 ASSERT_EQ(0, static_cast<int>(i
->size()));
172 static void RetrieveActions_FetchFilteredActions1(
173 scoped_ptr
<std::vector
<scoped_refptr
<Action
> > > i
) {
174 ASSERT_EQ(1, static_cast<int>(i
->size()));
177 static void RetrieveActions_FetchFilteredActions2(
178 scoped_ptr
<std::vector
<scoped_refptr
<Action
> > > i
) {
179 ASSERT_EQ(2, static_cast<int>(i
->size()));
182 static void RetrieveActions_FetchFilteredActions300(
183 scoped_ptr
<std::vector
<scoped_refptr
<Action
> > > i
) {
184 ASSERT_EQ(300, static_cast<int>(i
->size()));
187 static void Arguments_Stripped(scoped_ptr
<Action::ActionVector
> i
) {
188 scoped_refptr
<Action
> last
= i
->front();
189 CheckAction(*last
.get(),
190 "odlameecjipmbmbejkplpemijjgpljce",
191 Action::ACTION_API_CALL
,
193 "[\"hello\",\"world\"]",
200 static void Arguments_GetSinglesAction(
201 scoped_ptr
<Action::ActionVector
> actions
) {
202 ASSERT_EQ(1, static_cast<int>(actions
->size()));
203 CheckAction(*actions
->at(0).get(),
205 Action::ACTION_DOM_ACCESS
,
208 "http://www.google.com/",
214 static void Arguments_GetTodaysActions(
215 scoped_ptr
<Action::ActionVector
> actions
) {
216 ASSERT_EQ(3, static_cast<int>(actions
->size()));
217 CheckAction(*actions
->at(0).get(),
219 Action::ACTION_API_CALL
,
226 CheckAction(*actions
->at(1).get(),
228 Action::ACTION_DOM_ACCESS
,
231 "http://www.google.com/",
235 CheckAction(*actions
->at(2).get(),
237 Action::ACTION_API_CALL
,
238 "extension.sendMessage",
239 "[\"not\",\"stripped\"]",
246 static void Arguments_GetOlderActions(
247 scoped_ptr
<Action::ActionVector
> actions
) {
248 ASSERT_EQ(2, static_cast<int>(actions
->size()));
249 CheckAction(*actions
->at(0).get(),
251 Action::ACTION_DOM_ACCESS
,
254 "http://www.google.com/",
258 CheckAction(*actions
->at(1).get(),
260 Action::ACTION_API_CALL
,
269 static void Arguments_CheckMergeCount(
271 scoped_ptr
<Action::ActionVector
> actions
) {
273 ASSERT_EQ(1u, actions
->size());
274 CheckAction(*actions
->at(0).get(),
276 Action::ACTION_API_CALL
,
284 ASSERT_EQ(0u, actions
->size());
288 static void Arguments_CheckMergeCountAndTime(
290 const base::Time
& time
,
291 scoped_ptr
<Action::ActionVector
> actions
) {
293 ASSERT_EQ(1u, actions
->size());
294 CheckAction(*actions
->at(0).get(),
296 Action::ACTION_API_CALL
,
303 ASSERT_EQ(time
, actions
->at(0)->time());
305 ASSERT_EQ(0u, actions
->size());
309 static void AllURLsRemoved(scoped_ptr
<Action::ActionVector
> actions
) {
310 ASSERT_EQ(2, static_cast<int>(actions
->size()));
311 CheckAction(*actions
->at(0).get(),
313 Action::ACTION_DOM_ACCESS
,
320 CheckAction(*actions
->at(1).get(),
322 Action::ACTION_DOM_ACCESS
,
331 static void SomeURLsRemoved(scoped_ptr
<Action::ActionVector
> actions
) {
332 // These will be in the vector in reverse time order.
333 ASSERT_EQ(5, static_cast<int>(actions
->size()));
334 CheckAction(*actions
->at(0).get(),
336 Action::ACTION_DOM_ACCESS
,
339 "http://www.google.com/",
341 "http://www.args-url.com/",
343 CheckAction(*actions
->at(1).get(),
345 Action::ACTION_DOM_ACCESS
,
348 "http://www.google.com/",
352 CheckAction(*actions
->at(2).get(),
354 Action::ACTION_DOM_ACCESS
,
361 CheckAction(*actions
->at(3).get(),
363 Action::ACTION_DOM_ACCESS
,
368 "http://www.google.com/",
370 CheckAction(*actions
->at(4).get(),
372 Action::ACTION_DOM_ACCESS
,
381 static void CheckDuplicates(scoped_ptr
<Action::ActionVector
> actions
) {
382 ASSERT_EQ(2u, actions
->size());
384 for (size_t i
= 0; i
< actions
->size(); i
++) {
385 total_count
+= actions
->at(i
)->count();
387 ASSERT_EQ(3, total_count
);
390 static void CheckAction(const Action
& action
,
391 const std::string
& expected_id
,
392 const Action::ActionType
& expected_type
,
393 const std::string
& expected_api_name
,
394 const std::string
& expected_args_str
,
395 const std::string
& expected_page_url
,
396 const std::string
& expected_page_title
,
397 const std::string
& expected_arg_url
,
398 int expected_count
) {
399 ASSERT_EQ(expected_id
, action
.extension_id());
400 ASSERT_EQ(expected_type
, action
.action_type());
401 ASSERT_EQ(expected_api_name
, action
.api_name());
402 ASSERT_EQ(expected_args_str
,
403 ActivityLogPolicy::Util::Serialize(action
.args()));
404 ASSERT_EQ(expected_page_url
, action
.SerializePageUrl());
405 ASSERT_EQ(expected_page_title
, action
.page_title());
406 ASSERT_EQ(expected_arg_url
, action
.SerializeArgUrl());
407 ASSERT_EQ(expected_count
, action
.count());
408 ASSERT_NE(-1, action
.action_id());
411 // A helper function initializes the policy with a number of actions, calls
412 // RemoveActions on a policy object and then checks the result of the
414 void CheckRemoveActions(
415 ActivityLogDatabasePolicy
* policy
,
416 const std::vector
<int64
>& action_ids
,
417 const base::Callback
<void(scoped_ptr
<Action::ActionVector
>)>& checker
) {
419 // Use a mock clock to ensure that events are not recorded on the wrong day
420 // when the test is run close to local midnight.
421 base::SimpleTestClock
* mock_clock
= new base::SimpleTestClock();
422 mock_clock
->SetNow(base::Time::Now().LocalMidnight() +
423 base::TimeDelta::FromHours(12));
424 policy
->SetClockForTesting(scoped_ptr
<base::Clock
>(mock_clock
));
426 // Record some actions
427 scoped_refptr
<Action
> action
=
429 mock_clock
->Now() - base::TimeDelta::FromMinutes(40),
430 Action::ACTION_DOM_ACCESS
,
432 action
->mutable_args()->AppendString("vamoose1");
433 action
->set_page_url(GURL("http://www.google1.com"));
434 action
->set_page_title("Google1");
435 action
->set_arg_url(GURL("http://www.args-url1.com"));
436 policy
->ProcessAction(action
);
437 // Record the same action twice, so there are multiple entries in the
439 policy
->ProcessAction(action
);
441 action
= new Action("punky2",
442 mock_clock
->Now() - base::TimeDelta::FromMinutes(30),
443 Action::ACTION_API_CALL
,
445 action
->mutable_args()->AppendString("vamoose2");
446 action
->set_page_url(GURL("http://www.google2.com"));
447 action
->set_page_title("Google2");
448 action
->set_arg_url(GURL("http://www.args-url2.com"));
449 policy
->ProcessAction(action
);
450 // Record the same action twice, so there are multiple entries in the
452 policy
->ProcessAction(action
);
454 // Submit a request to delete actions.
455 policy
->RemoveActions(action_ids
);
457 // Check the result of the deletion. The checker function gets all
458 // activities in the database.
459 CheckReadData(policy
, "", -1, checker
);
462 policy
->DeleteDatabase();
465 static void AllActionsDeleted(scoped_ptr
<Action::ActionVector
> actions
) {
466 ASSERT_EQ(0, static_cast<int>(actions
->size()));
469 static void NoActionsDeleted(scoped_ptr
<Action::ActionVector
> actions
) {
470 // These will be in the vector in reverse time order.
471 ASSERT_EQ(2, static_cast<int>(actions
->size()));
472 CheckAction(*actions
->at(0).get(),
474 Action::ACTION_API_CALL
,
477 "http://www.google2.com/",
479 "http://www.args-url2.com/",
481 ASSERT_EQ(2, actions
->at(0)->action_id());
482 CheckAction(*actions
->at(1).get(),
484 Action::ACTION_DOM_ACCESS
,
487 "http://www.google1.com/",
489 "http://www.args-url1.com/",
491 ASSERT_EQ(1, actions
->at(1)->action_id());
494 static void Action1Deleted(scoped_ptr
<Action::ActionVector
> actions
) {
495 // These will be in the vector in reverse time order.
496 ASSERT_EQ(1, static_cast<int>(actions
->size()));
497 CheckAction(*actions
->at(0).get(),
499 Action::ACTION_API_CALL
,
502 "http://www.google2.com/",
504 "http://www.args-url2.com/",
506 ASSERT_EQ(2, actions
->at(0)->action_id());
509 static void Action2Deleted(scoped_ptr
<Action::ActionVector
> actions
) {
510 // These will be in the vector in reverse time order.
511 ASSERT_EQ(1, static_cast<int>(actions
->size()));
512 CheckAction(*actions
->at(0).get(),
514 Action::ACTION_DOM_ACCESS
,
517 "http://www.google1.com/",
519 "http://www.args-url1.com/",
521 ASSERT_EQ(1, actions
->at(0)->action_id());
525 ExtensionService
* extension_service_
;
526 scoped_ptr
<TestingProfile
> profile_
;
527 content::TestBrowserThreadBundle thread_bundle_
;
528 // Used to preserve a copy of the original command line.
529 // The test framework will do this itself as well. However, by then,
530 // it is too late to call ActivityLog::RecomputeLoggingIsEnabled() in
532 base::CommandLine saved_cmdline_
;
534 #if defined OS_CHROMEOS
535 chromeos::ScopedTestDeviceSettingsService test_device_settings_service_
;
536 chromeos::ScopedTestCrosSettings test_cros_settings_
;
537 scoped_ptr
<chromeos::ScopedTestUserManager
> test_user_manager_
;
541 TEST_F(CountingPolicyTest
, Construct
) {
542 ActivityLogDatabasePolicy
* policy
= new CountingPolicy(profile_
.get());
544 scoped_refptr
<const Extension
> extension
=
546 .SetManifest(DictionaryBuilder()
547 .Set("name", "Test extension")
548 .Set("version", "1.0.0")
549 .Set("manifest_version", 2))
551 extension_service_
->AddExtension(extension
.get());
552 scoped_ptr
<base::ListValue
> args(new base::ListValue());
553 scoped_refptr
<Action
> action
= new Action(extension
->id(),
555 Action::ACTION_API_CALL
,
557 action
->set_args(args
.Pass());
558 policy
->ProcessAction(action
);
562 TEST_F(CountingPolicyTest
, LogWithStrippedArguments
) {
563 ActivityLogDatabasePolicy
* policy
= new CountingPolicy(profile_
.get());
565 scoped_refptr
<const Extension
> extension
=
567 .SetManifest(DictionaryBuilder()
568 .Set("name", "Test extension")
569 .Set("version", "1.0.0")
570 .Set("manifest_version", 2))
572 extension_service_
->AddExtension(extension
.get());
574 scoped_ptr
<base::ListValue
> args(new base::ListValue());
575 args
->Set(0, new base::StringValue("hello"));
576 args
->Set(1, new base::StringValue("world"));
577 scoped_refptr
<Action
> action
= new Action(extension
->id(),
579 Action::ACTION_API_CALL
,
580 "extension.connect");
581 action
->set_args(args
.Pass());
583 policy
->ProcessAction(action
);
584 CheckReadData(policy
,
587 base::Bind(&CountingPolicyTest::Arguments_Stripped
));
591 TEST_F(CountingPolicyTest
, GetTodaysActions
) {
592 CountingPolicy
* policy
= new CountingPolicy(profile_
.get());
594 // Disable row expiration for this test by setting a time before any actions
596 policy
->set_retention_time(base::TimeDelta::FromDays(14));
598 // Use a mock clock to ensure that events are not recorded on the wrong day
599 // when the test is run close to local midnight. Note: Ownership is passed
600 // to the policy, but we still keep a pointer locally. The policy will take
601 // care of destruction; this is safe since the policy outlives all our
602 // accesses to the mock clock.
603 base::SimpleTestClock
* mock_clock
= new base::SimpleTestClock();
604 mock_clock
->SetNow(base::Time::Now().LocalMidnight() +
605 base::TimeDelta::FromHours(12));
606 policy
->SetClockForTesting(scoped_ptr
<base::Clock
>(mock_clock
));
608 // Record some actions
609 scoped_refptr
<Action
> action
=
611 mock_clock
->Now() - base::TimeDelta::FromMinutes(40),
612 Action::ACTION_API_CALL
,
614 action
->mutable_args()->AppendString("woof");
615 policy
->ProcessAction(action
);
617 action
= new Action("punky",
618 mock_clock
->Now() - base::TimeDelta::FromMinutes(30),
619 Action::ACTION_API_CALL
,
621 action
->mutable_args()->AppendString("meow");
622 policy
->ProcessAction(action
);
624 action
= new Action("punky",
625 mock_clock
->Now() - base::TimeDelta::FromMinutes(20),
626 Action::ACTION_API_CALL
,
627 "extension.sendMessage");
628 action
->mutable_args()->AppendString("not");
629 action
->mutable_args()->AppendString("stripped");
630 policy
->ProcessAction(action
);
633 new Action("punky", mock_clock
->Now(), Action::ACTION_DOM_ACCESS
, "lets");
634 action
->mutable_args()->AppendString("vamoose");
635 action
->set_page_url(GURL("http://www.google.com"));
636 policy
->ProcessAction(action
);
639 "scoobydoo", mock_clock
->Now(), Action::ACTION_DOM_ACCESS
, "lets");
640 action
->mutable_args()->AppendString("vamoose");
641 action
->set_page_url(GURL("http://www.google.com"));
642 policy
->ProcessAction(action
);
648 base::Bind(&CountingPolicyTest::Arguments_GetTodaysActions
));
652 // Check that we can read back less recent actions in the db.
653 TEST_F(CountingPolicyTest
, GetOlderActions
) {
654 CountingPolicy
* policy
= new CountingPolicy(profile_
.get());
656 policy
->set_retention_time(base::TimeDelta::FromDays(14));
658 // Use a mock clock to ensure that events are not recorded on the wrong day
659 // when the test is run close to local midnight.
660 base::SimpleTestClock
* mock_clock
= new base::SimpleTestClock();
661 mock_clock
->SetNow(base::Time::Now().LocalMidnight() +
662 base::TimeDelta::FromHours(12));
663 policy
->SetClockForTesting(scoped_ptr
<base::Clock
>(mock_clock
));
665 // Record some actions
666 scoped_refptr
<Action
> action
=
668 mock_clock
->Now() - base::TimeDelta::FromDays(3) -
669 base::TimeDelta::FromMinutes(40),
670 Action::ACTION_API_CALL
,
672 action
->mutable_args()->AppendString("woof");
673 policy
->ProcessAction(action
);
675 action
= new Action("punky",
676 mock_clock
->Now() - base::TimeDelta::FromDays(3),
677 Action::ACTION_DOM_ACCESS
,
679 action
->mutable_args()->AppendString("vamoose");
680 action
->set_page_url(GURL("http://www.google.com"));
681 policy
->ProcessAction(action
);
683 action
= new Action("punky",
685 Action::ACTION_DOM_ACCESS
,
687 action
->mutable_args()->AppendString("too new");
688 action
->set_page_url(GURL("http://www.google.com"));
689 policy
->ProcessAction(action
);
691 action
= new Action("punky",
692 mock_clock
->Now() - base::TimeDelta::FromDays(7),
693 Action::ACTION_DOM_ACCESS
,
695 action
->mutable_args()->AppendString("too old");
696 action
->set_page_url(GURL("http://www.google.com"));
697 policy
->ProcessAction(action
);
703 base::Bind(&CountingPolicyTest::Arguments_GetOlderActions
));
708 TEST_F(CountingPolicyTest
, LogAndFetchFilteredActions
) {
709 ActivityLogDatabasePolicy
* policy
= new CountingPolicy(profile_
.get());
711 scoped_refptr
<const Extension
> extension
=
713 .SetManifest(DictionaryBuilder()
714 .Set("name", "Test extension")
715 .Set("version", "1.0.0")
716 .Set("manifest_version", 2))
718 extension_service_
->AddExtension(extension
.get());
719 GURL
gurl("http://www.google.com");
721 // Write some API calls
722 scoped_refptr
<Action
> action_api
= new Action(extension
->id(),
724 Action::ACTION_API_CALL
,
726 action_api
->set_args(make_scoped_ptr(new base::ListValue()));
727 policy
->ProcessAction(action_api
);
729 scoped_refptr
<Action
> action_dom
= new Action(extension
->id(),
731 Action::ACTION_DOM_ACCESS
,
733 action_dom
->set_args(make_scoped_ptr(new base::ListValue()));
734 action_dom
->set_page_url(gurl
);
735 policy
->ProcessAction(action_dom
);
737 CheckReadFilteredData(
740 Action::ACTION_API_CALL
,
746 &CountingPolicyTest::RetrieveActions_FetchFilteredActions1
));
748 CheckReadFilteredData(
751 Action::ACTION_DOM_ACCESS
,
757 &CountingPolicyTest::RetrieveActions_FetchFilteredActions1
));
759 CheckReadFilteredData(
762 Action::ACTION_DOM_ACCESS
,
764 "http://www.google.com/",
768 &CountingPolicyTest::RetrieveActions_FetchFilteredActions1
));
770 CheckReadFilteredData(
773 Action::ACTION_DOM_ACCESS
,
775 "http://www.google.com",
779 &CountingPolicyTest::RetrieveActions_FetchFilteredActions1
));
781 CheckReadFilteredData(
784 Action::ACTION_DOM_ACCESS
,
790 &CountingPolicyTest::RetrieveActions_FetchFilteredActions1
));
792 CheckReadFilteredData(
801 &CountingPolicyTest::RetrieveActions_FetchFilteredActions2
));
806 // Check that merging of actions only occurs within the same day, not across
807 // days, and that old data can be expired from the database.
808 TEST_F(CountingPolicyTest
, MergingAndExpiring
) {
809 CountingPolicy
* policy
= new CountingPolicy(profile_
.get());
811 // Initially disable expiration by setting a retention time before any
812 // actions we generate.
813 policy
->set_retention_time(base::TimeDelta::FromDays(14));
815 // Use a mock clock to ensure that events are not recorded on the wrong day
816 // when the test is run close to local midnight.
817 base::SimpleTestClock
* mock_clock
= new base::SimpleTestClock();
818 mock_clock
->SetNow(base::Time::Now().LocalMidnight() +
819 base::TimeDelta::FromHours(12));
820 policy
->SetClockForTesting(scoped_ptr
<base::Clock
>(mock_clock
));
822 // The first two actions should be merged; the last one is on a separate day
823 // and should not be.
824 scoped_refptr
<Action
> action
=
826 mock_clock
->Now() - base::TimeDelta::FromDays(3) -
827 base::TimeDelta::FromMinutes(40),
828 Action::ACTION_API_CALL
,
830 policy
->ProcessAction(action
);
832 action
= new Action("punky",
833 mock_clock
->Now() - base::TimeDelta::FromDays(3) -
834 base::TimeDelta::FromMinutes(20),
835 Action::ACTION_API_CALL
,
837 policy
->ProcessAction(action
);
839 action
= new Action("punky",
840 mock_clock
->Now() - base::TimeDelta::FromDays(2) -
841 base::TimeDelta::FromMinutes(20),
842 Action::ACTION_API_CALL
,
844 policy
->ProcessAction(action
);
846 CheckReadData(policy
,
849 base::Bind(&CountingPolicyTest::Arguments_CheckMergeCount
, 2));
850 CheckReadData(policy
,
853 base::Bind(&CountingPolicyTest::Arguments_CheckMergeCount
, 1));
855 // Clean actions before midnight two days ago. Force expiration to run by
856 // clearing last_database_cleaning_time_ and submitting a new action.
857 policy
->set_retention_time(base::TimeDelta::FromDays(2));
858 policy
->last_database_cleaning_time_
= base::Time();
859 action
= new Action("punky",
861 Action::ACTION_API_CALL
,
863 policy
->ProcessAction(action
);
865 CheckReadData(policy
,
868 base::Bind(&CountingPolicyTest::Arguments_CheckMergeCount
, 0));
869 CheckReadData(policy
,
872 base::Bind(&CountingPolicyTest::Arguments_CheckMergeCount
, 1));
877 // Test cleaning of old data in the string and URL tables.
878 TEST_F(CountingPolicyTest
, StringTableCleaning
) {
879 CountingPolicy
* policy
= new CountingPolicy(profile_
.get());
881 // Initially disable expiration by setting a retention time before any
882 // actions we generate.
883 policy
->set_retention_time(base::TimeDelta::FromDays(14));
885 base::SimpleTestClock
* mock_clock
= new base::SimpleTestClock();
886 mock_clock
->SetNow(base::Time::Now());
887 policy
->SetClockForTesting(scoped_ptr
<base::Clock
>(mock_clock
));
889 // Insert an action; this should create entries in both the string table (for
890 // the extension and API name) and the URL table (for page_url).
891 scoped_refptr
<Action
> action
=
893 mock_clock
->Now() - base::TimeDelta::FromDays(7),
894 Action::ACTION_API_CALL
,
896 action
->set_page_url(GURL("http://www.google.com/"));
897 policy
->ProcessAction(action
);
899 // Add an action which will not be expired, so that some strings will remain
902 "punky", mock_clock
->Now(), Action::ACTION_API_CALL
, "tabs.create");
903 policy
->ProcessAction(action
);
905 // There should now be three strings ("punky", "brewster", "tabs.create") and
906 // one URL in the tables.
908 policy
->ScheduleAndForget(policy
,
909 &CountingPolicyTest::CheckStringTableSizes
,
912 WaitOnThread(BrowserThread::DB
);
914 // Trigger a cleaning. The oldest action is expired when we submit a
915 // duplicate of the newer action. After this, there should be two strings
917 policy
->set_retention_time(base::TimeDelta::FromDays(2));
918 policy
->last_database_cleaning_time_
= base::Time();
919 policy
->ProcessAction(action
);
921 policy
->ScheduleAndForget(policy
,
922 &CountingPolicyTest::CheckStringTableSizes
,
925 WaitOnThread(BrowserThread::DB
);
930 // A stress test for memory- and database-based merging of actions. Submit
931 // multiple items, not in chronological order, spanning a few days. Check that
932 // items are merged properly and final timestamps are correct.
933 TEST_F(CountingPolicyTest
, MoreMerging
) {
934 CountingPolicy
* policy
= new CountingPolicy(profile_
.get());
936 policy
->set_retention_time(base::TimeDelta::FromDays(14));
938 // Use a mock clock to ensure that events are not recorded on the wrong day
939 // when the test is run close to local midnight.
940 base::SimpleTestClock
* mock_clock
= new base::SimpleTestClock();
941 mock_clock
->SetNow(base::Time::Now().LocalMidnight() +
942 base::TimeDelta::FromHours(12));
943 policy
->SetClockForTesting(scoped_ptr
<base::Clock
>(mock_clock
));
945 // Create an action 2 days ago, then 1 day ago, then 2 days ago. Make sure
946 // that we end up with two merged records (one for each day), and each has
947 // the appropriate timestamp. These merges should happen in the database
948 // since the date keeps changing.
950 mock_clock
->Now() - base::TimeDelta::FromDays(2) -
951 base::TimeDelta::FromMinutes(40);
953 mock_clock
->Now() - base::TimeDelta::FromDays(1) -
954 base::TimeDelta::FromMinutes(40);
956 mock_clock
->Now() - base::TimeDelta::FromDays(2) -
957 base::TimeDelta::FromMinutes(20);
959 scoped_refptr
<Action
> action
=
960 new Action("punky", time1
, Action::ACTION_API_CALL
, "brewster");
961 policy
->ProcessAction(action
);
963 action
= new Action("punky", time2
, Action::ACTION_API_CALL
, "brewster");
964 policy
->ProcessAction(action
);
966 action
= new Action("punky", time3
, Action::ACTION_API_CALL
, "brewster");
967 policy
->ProcessAction(action
);
974 &CountingPolicyTest::Arguments_CheckMergeCountAndTime
, 2, time3
));
980 &CountingPolicyTest::Arguments_CheckMergeCountAndTime
, 1, time2
));
982 // Create three actions today, where the merges should happen in memory.
983 // Again these are not chronological; timestamp time5 should win out since it
985 base::Time time4
= mock_clock
->Now() - base::TimeDelta::FromMinutes(60);
986 base::Time time5
= mock_clock
->Now() - base::TimeDelta::FromMinutes(20);
987 base::Time time6
= mock_clock
->Now() - base::TimeDelta::FromMinutes(40);
989 action
= new Action("punky", time4
, Action::ACTION_API_CALL
, "brewster");
990 policy
->ProcessAction(action
);
992 action
= new Action("punky", time5
, Action::ACTION_API_CALL
, "brewster");
993 policy
->ProcessAction(action
);
995 action
= new Action("punky", time6
, Action::ACTION_API_CALL
, "brewster");
996 policy
->ProcessAction(action
);
1003 &CountingPolicyTest::Arguments_CheckMergeCountAndTime
, 3, time5
));
1007 // Check that actions are flushed to disk before letting too many accumulate in
1009 TEST_F(CountingPolicyTest
, EarlyFlush
) {
1010 CountingPolicy
* policy
= new CountingPolicy(profile_
.get());
1013 for (int i
= 0; i
< 500; i
++) {
1014 scoped_refptr
<Action
> action
=
1017 Action::ACTION_API_CALL
,
1018 base::StringPrintf("apicall_%d", i
));
1019 policy
->ProcessAction(action
);
1022 policy
->ScheduleAndForget(policy
, &CountingPolicyTest::CheckQueueSize
);
1023 WaitOnThread(BrowserThread::DB
);
1028 TEST_F(CountingPolicyTest
, CapReturns
) {
1029 CountingPolicy
* policy
= new CountingPolicy(profile_
.get());
1032 for (int i
= 0; i
< 305; i
++) {
1033 scoped_refptr
<Action
> action
=
1036 Action::ACTION_API_CALL
,
1037 base::StringPrintf("apicall_%d", i
));
1038 policy
->ProcessAction(action
);
1042 WaitOnThread(BrowserThread::DB
);
1044 CheckReadFilteredData(
1053 &CountingPolicyTest::RetrieveActions_FetchFilteredActions300
));
1057 TEST_F(CountingPolicyTest
, RemoveAllURLs
) {
1058 ActivityLogDatabasePolicy
* policy
= new CountingPolicy(profile_
.get());
1061 // Use a mock clock to ensure that events are not recorded on the wrong day
1062 // when the test is run close to local midnight.
1063 base::SimpleTestClock
* mock_clock
= new base::SimpleTestClock();
1064 mock_clock
->SetNow(base::Time::Now().LocalMidnight() +
1065 base::TimeDelta::FromHours(12));
1066 policy
->SetClockForTesting(scoped_ptr
<base::Clock
>(mock_clock
));
1068 // Record some actions
1069 scoped_refptr
<Action
> action
=
1070 new Action("punky", mock_clock
->Now(),
1071 Action::ACTION_DOM_ACCESS
, "lets");
1072 action
->mutable_args()->AppendString("vamoose");
1073 action
->set_page_url(GURL("http://www.google.com"));
1074 action
->set_page_title("Google");
1075 action
->set_arg_url(GURL("http://www.args-url.com"));
1076 policy
->ProcessAction(action
);
1078 mock_clock
->Advance(base::TimeDelta::FromSeconds(1));
1079 action
= new Action(
1080 "punky", mock_clock
->Now(), Action::ACTION_DOM_ACCESS
, "lets");
1081 action
->mutable_args()->AppendString("vamoose");
1082 action
->set_page_url(GURL("http://www.google2.com"));
1083 action
->set_page_title("Google");
1084 // Deliberately no arg url set to make sure it stills works if there is no arg
1086 policy
->ProcessAction(action
);
1088 // Clean all the URLs.
1089 std::vector
<GURL
> no_url_restrictions
;
1090 policy
->RemoveURLs(no_url_restrictions
);
1096 base::Bind(&CountingPolicyTest::AllURLsRemoved
));
1100 TEST_F(CountingPolicyTest
, RemoveSpecificURLs
) {
1101 ActivityLogDatabasePolicy
* policy
= new CountingPolicy(profile_
.get());
1104 // Use a mock clock to ensure that events are not recorded on the wrong day
1105 // when the test is run close to local midnight.
1106 base::SimpleTestClock
* mock_clock
= new base::SimpleTestClock();
1107 mock_clock
->SetNow(base::Time::Now().LocalMidnight() +
1108 base::TimeDelta::FromHours(12));
1109 policy
->SetClockForTesting(scoped_ptr
<base::Clock
>(mock_clock
));
1111 // Record some actions
1112 // This should have the page url and args url cleared.
1113 scoped_refptr
<Action
> action
= new Action("punky", mock_clock
->Now(),
1114 Action::ACTION_DOM_ACCESS
, "lets");
1115 action
->mutable_args()->AppendString("vamoose");
1116 action
->set_page_url(GURL("http://www.google1.com"));
1117 action
->set_page_title("Google");
1118 action
->set_arg_url(GURL("http://www.google1.com"));
1119 policy
->ProcessAction(action
);
1121 // This should have the page url cleared but not args url.
1122 mock_clock
->Advance(base::TimeDelta::FromSeconds(1));
1123 action
= new Action(
1124 "punky", mock_clock
->Now(), Action::ACTION_DOM_ACCESS
, "lets");
1125 action
->mutable_args()->AppendString("vamoose");
1126 action
->set_page_url(GURL("http://www.google1.com"));
1127 action
->set_page_title("Google");
1128 action
->set_arg_url(GURL("http://www.google.com"));
1129 policy
->ProcessAction(action
);
1131 // This should have the page url cleared. The args url is deliberately not
1132 // set to make sure this doesn't cause any issues.
1133 mock_clock
->Advance(base::TimeDelta::FromSeconds(1));
1134 action
= new Action(
1135 "punky", mock_clock
->Now(), Action::ACTION_DOM_ACCESS
, "lets");
1136 action
->mutable_args()->AppendString("vamoose");
1137 action
->set_page_url(GURL("http://www.google2.com"));
1138 action
->set_page_title("Google");
1139 policy
->ProcessAction(action
);
1141 // This should have the args url cleared but not the page url or page title.
1142 mock_clock
->Advance(base::TimeDelta::FromSeconds(1));
1143 action
= new Action(
1144 "punky", mock_clock
->Now(), Action::ACTION_DOM_ACCESS
, "lets");
1145 action
->mutable_args()->AppendString("vamoose");
1146 action
->set_page_url(GURL("http://www.google.com"));
1147 action
->set_page_title("Google");
1148 action
->set_arg_url(GURL("http://www.google1.com"));
1149 policy
->ProcessAction(action
);
1151 // This should have neither cleared.
1152 mock_clock
->Advance(base::TimeDelta::FromSeconds(1));
1153 action
= new Action(
1154 "punky", mock_clock
->Now(), Action::ACTION_DOM_ACCESS
, "lets");
1155 action
->mutable_args()->AppendString("vamoose");
1156 action
->set_page_url(GURL("http://www.google.com"));
1157 action
->set_page_title("Google");
1158 action
->set_arg_url(GURL("http://www.args-url.com"));
1159 action
->set_count(5);
1160 policy
->ProcessAction(action
);
1163 std::vector
<GURL
> urls
;
1164 urls
.push_back(GURL("http://www.google1.com"));
1165 urls
.push_back(GURL("http://www.google2.com"));
1166 urls
.push_back(GURL("http://www.url_not_in_db.com"));
1167 policy
->RemoveURLs(urls
);
1173 base::Bind(&CountingPolicyTest::SomeURLsRemoved
));
1177 TEST_F(CountingPolicyTest
, RemoveExtensionData
) {
1178 CountingPolicy
* policy
= new CountingPolicy(profile_
.get());
1181 // Use a mock clock to ensure that events are not recorded on the wrong day
1182 // when the test is run close to local midnight.
1183 base::SimpleTestClock
* mock_clock
= new base::SimpleTestClock();
1184 mock_clock
->SetNow(base::Time::Now().LocalMidnight() +
1185 base::TimeDelta::FromHours(12));
1186 policy
->SetClockForTesting(scoped_ptr
<base::Clock
>(mock_clock
));
1188 // Record some actions
1189 scoped_refptr
<Action
> action
= new Action("deleteextensiondata",
1191 Action::ACTION_DOM_ACCESS
,
1193 action
->mutable_args()->AppendString("vamoose");
1194 action
->set_page_title("Google");
1195 action
->set_arg_url(GURL("http://www.google.com"));
1196 policy
->ProcessAction(action
);
1197 policy
->ProcessAction(action
);
1198 policy
->ProcessAction(action
);
1200 scoped_refptr
<Action
> action2
= new Action("dontdelete",
1202 Action::ACTION_DOM_ACCESS
,
1204 action
->mutable_args()->AppendString("vamoose");
1205 action
->set_page_title("Google");
1206 action
->set_arg_url(GURL("http://www.google.com"));
1207 policy
->ProcessAction(action2
);
1210 policy
->RemoveExtensionData("deleteextensiondata");
1212 CheckReadFilteredData(
1214 "deleteextensiondata",
1221 &CountingPolicyTest::RetrieveActions_FetchFilteredActions0
));
1223 CheckReadFilteredData(
1232 &CountingPolicyTest::RetrieveActions_FetchFilteredActions1
));
1236 TEST_F(CountingPolicyTest
, DeleteDatabase
) {
1237 CountingPolicy
* policy
= new CountingPolicy(profile_
.get());
1239 // Disable row expiration for this test by setting a time before any actions
1241 policy
->set_retention_time(base::TimeDelta::FromDays(14));
1243 // Use a mock clock to ensure that events are not recorded on the wrong day
1244 // when the test is run close to local midnight. Note: Ownership is passed
1245 // to the policy, but we still keep a pointer locally. The policy will take
1246 // care of destruction; this is safe since the policy outlives all our
1247 // accesses to the mock clock.
1248 base::SimpleTestClock
* mock_clock
= new base::SimpleTestClock();
1249 mock_clock
->SetNow(base::Time::Now().LocalMidnight() +
1250 base::TimeDelta::FromHours(12));
1251 policy
->SetClockForTesting(scoped_ptr
<base::Clock
>(mock_clock
));
1253 // Record some actions
1254 scoped_refptr
<Action
> action
=
1256 mock_clock
->Now() - base::TimeDelta::FromMinutes(40),
1257 Action::ACTION_API_CALL
,
1259 action
->mutable_args()->AppendString("woof");
1260 policy
->ProcessAction(action
);
1262 action
= new Action("punky",
1263 mock_clock
->Now() - base::TimeDelta::FromMinutes(30),
1264 Action::ACTION_API_CALL
,
1266 action
->mutable_args()->AppendString("meow");
1267 policy
->ProcessAction(action
);
1269 action
= new Action("punky",
1270 mock_clock
->Now() - base::TimeDelta::FromMinutes(20),
1271 Action::ACTION_API_CALL
,
1272 "extension.sendMessage");
1273 action
->mutable_args()->AppendString("not");
1274 action
->mutable_args()->AppendString("stripped");
1275 policy
->ProcessAction(action
);
1278 new Action("punky", mock_clock
->Now(), Action::ACTION_DOM_ACCESS
, "lets");
1279 action
->mutable_args()->AppendString("vamoose");
1280 action
->set_page_url(GURL("http://www.google.com"));
1281 policy
->ProcessAction(action
);
1283 action
= new Action(
1284 "scoobydoo", mock_clock
->Now(), Action::ACTION_DOM_ACCESS
, "lets");
1285 action
->mutable_args()->AppendString("vamoose");
1286 action
->set_page_url(GURL("http://www.google.com"));
1287 policy
->ProcessAction(action
);
1293 base::Bind(&CountingPolicyTest::Arguments_GetTodaysActions
));
1295 policy
->DeleteDatabase();
1297 CheckReadFilteredData(
1306 &CountingPolicyTest::RetrieveActions_FetchFilteredActions0
));
1308 // The following code tests that the caches of url and string tables were
1309 // cleared by the deletion above.
1310 // https://code.google.com/p/chromium/issues/detail?id=341674.
1312 new Action("punky", mock_clock
->Now(), Action::ACTION_DOM_ACCESS
, "lets");
1313 action
->mutable_args()->AppendString("vamoose");
1314 action
->set_page_url(GURL("http://www.google.com"));
1315 policy
->ProcessAction(action
);
1321 base::Bind(&CountingPolicyTest::Arguments_GetSinglesAction
));
1323 policy
->DeleteDatabase();
1325 CheckReadFilteredData(
1334 &CountingPolicyTest::RetrieveActions_FetchFilteredActions0
));
1339 // Tests that duplicate rows in the activity log database are handled properly
1340 // when updating counts.
1341 TEST_F(CountingPolicyTest
, DuplicateRows
) {
1342 CountingPolicy
* policy
= new CountingPolicy(profile_
.get());
1344 base::SimpleTestClock
* mock_clock
= new base::SimpleTestClock();
1345 mock_clock
->SetNow(base::Time::Now().LocalMidnight() +
1346 base::TimeDelta::FromHours(12));
1347 policy
->SetClockForTesting(scoped_ptr
<base::Clock
>(mock_clock
));
1349 // Record two actions with distinct URLs.
1350 scoped_refptr
<Action
> action
;
1351 action
= new Action(
1352 "punky", mock_clock
->Now(), Action::ACTION_API_CALL
, "brewster");
1353 action
->set_page_url(GURL("http://www.google.com"));
1354 policy
->ProcessAction(action
);
1356 action
= new Action(
1357 "punky", mock_clock
->Now(), Action::ACTION_API_CALL
, "brewster");
1358 action
->set_page_url(GURL("http://www.google.co.uk"));
1359 policy
->ProcessAction(action
);
1361 // Manipulate the database to clear the URLs, so that we end up with
1363 std::vector
<GURL
> no_url_restrictions
;
1364 policy
->RemoveURLs(no_url_restrictions
);
1366 // Record one more action, with no URL. This should increment the count on
1367 // one, and exactly one, of the existing rows.
1368 action
= new Action(
1369 "punky", mock_clock
->Now(), Action::ACTION_API_CALL
, "brewster");
1370 policy
->ProcessAction(action
);
1376 base::Bind(&CountingPolicyTest::CheckDuplicates
));
1380 TEST_F(CountingPolicyTest
, RemoveActions
) {
1381 ActivityLogDatabasePolicy
* policy
= new CountingPolicy(profile_
.get());
1384 std::vector
<int64
> action_ids
;
1387 policy
, action_ids
, base::Bind(&CountingPolicyTest::NoActionsDeleted
));
1389 action_ids
.push_back(-1);
1390 action_ids
.push_back(-10);
1391 action_ids
.push_back(0);
1392 action_ids
.push_back(5);
1393 action_ids
.push_back(10);
1395 policy
, action_ids
, base::Bind(&CountingPolicyTest::NoActionsDeleted
));
1398 for (int i
= 0; i
< 50; i
++) {
1399 action_ids
.push_back(i
+ 3);
1402 policy
, action_ids
, base::Bind(&CountingPolicyTest::NoActionsDeleted
));
1405 // CheckRemoveActions pushes two actions to the Activity Log database with IDs
1407 action_ids
.push_back(1);
1408 action_ids
.push_back(2);
1410 policy
, action_ids
, base::Bind(&CountingPolicyTest::AllActionsDeleted
));
1413 action_ids
.push_back(1);
1415 policy
, action_ids
, base::Bind(&CountingPolicyTest::Action1Deleted
));
1418 action_ids
.push_back(2);
1420 policy
, action_ids
, base::Bind(&CountingPolicyTest::Action2Deleted
));
1426 } // namespace extensions