1 // Copyright (c) 2012 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/command_line.h"
6 #include "base/memory/scoped_ptr.h"
7 #include "base/message_loop/message_loop.h"
8 #include "base/run_loop.h"
9 #include "base/synchronization/waitable_event.h"
10 #include "chrome/browser/extensions/activity_log/activity_action_constants.h"
11 #include "chrome/browser/extensions/activity_log/activity_log.h"
12 #include "chrome/browser/extensions/extension_service.h"
13 #include "chrome/browser/extensions/test_extension_system.h"
14 #include "chrome/browser/prerender/prerender_handle.h"
15 #include "chrome/browser/prerender/prerender_manager.h"
16 #include "chrome/browser/prerender/prerender_manager_factory.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/browser/web_contents.h"
22 #include "content/public/test/test_browser_thread_bundle.h"
23 #include "extensions/browser/extension_registry.h"
24 #include "extensions/browser/uninstall_reason.h"
25 #include "extensions/common/dom_action_types.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"
38 const char kExtensionId
[] = "abc";
40 const char* const kUrlApiCalls
[] = {
41 "HTMLButtonElement.formAction", "HTMLEmbedElement.src",
42 "HTMLFormElement.action", "HTMLFrameElement.src",
43 "HTMLHtmlElement.manifest", "HTMLIFrameElement.src",
44 "HTMLImageElement.longDesc", "HTMLImageElement.src",
45 "HTMLImageElement.lowsrc", "HTMLInputElement.formAction",
46 "HTMLInputElement.src", "HTMLLinkElement.href",
47 "HTMLMediaElement.src", "HTMLMediaElement.currentSrc",
48 "HTMLModElement.cite", "HTMLObjectElement.data",
49 "HTMLQuoteElement.cite", "HTMLScriptElement.src",
50 "HTMLSourceElement.src", "HTMLTrackElement.src",
51 "HTMLVideoElement.poster"};
55 namespace extensions
{
57 class ActivityLogTest
: public ChromeRenderViewHostTestHarness
{
59 void SetUp() override
{
60 ChromeRenderViewHostTestHarness::SetUp();
61 #if defined OS_CHROMEOS
62 test_user_manager_
.reset(new chromeos::ScopedTestUserManager());
64 base::CommandLine
command_line(base::CommandLine::NO_PROGRAM
);
65 base::CommandLine::ForCurrentProcess()->AppendSwitch(
66 switches::kEnableExtensionActivityLogging
);
67 base::CommandLine::ForCurrentProcess()->AppendSwitch(
68 switches::kEnableExtensionActivityLogTesting
);
69 extension_service_
= static_cast<TestExtensionSystem
*>(
70 ExtensionSystem::Get(profile()))->CreateExtensionService
71 (&command_line
, base::FilePath(), false);
72 base::RunLoop().RunUntilIdle();
75 void TearDown() override
{
76 #if defined OS_CHROMEOS
77 test_user_manager_
.reset();
79 base::RunLoop().RunUntilIdle();
80 ChromeRenderViewHostTestHarness::TearDown();
83 static void RetrieveActions_LogAndFetchActions0(
84 scoped_ptr
<std::vector
<scoped_refptr
<Action
> > > i
) {
85 ASSERT_EQ(0, static_cast<int>(i
->size()));
88 static void RetrieveActions_LogAndFetchActions2(
89 scoped_ptr
<std::vector
<scoped_refptr
<Action
> > > i
) {
90 ASSERT_EQ(2, static_cast<int>(i
->size()));
93 void SetPolicy(bool log_arguments
) {
94 ActivityLog
* activity_log
= ActivityLog::GetInstance(profile());
96 activity_log
->SetDatabasePolicy(ActivityLogPolicy::POLICY_FULLSTREAM
);
98 activity_log
->SetDatabasePolicy(ActivityLogPolicy::POLICY_COUNTS
);
101 bool GetDatabaseEnabled() {
102 ActivityLog
* activity_log
= ActivityLog::GetInstance(profile());
103 return activity_log
->IsDatabaseEnabled();
106 bool GetWatchdogActive() {
107 ActivityLog
* activity_log
= ActivityLog::GetInstance(profile());
108 return activity_log
->IsWatchdogAppActive();
111 static void Arguments_Prerender(
112 scoped_ptr
<std::vector
<scoped_refptr
<Action
> > > i
) {
113 ASSERT_EQ(1U, i
->size());
114 scoped_refptr
<Action
> last
= i
->front();
116 ASSERT_EQ("odlameecjipmbmbejkplpemijjgpljce", last
->extension_id());
117 ASSERT_EQ(Action::ACTION_CONTENT_SCRIPT
, last
->action_type());
118 ASSERT_EQ("[\"script\"]",
119 ActivityLogPolicy::Util::Serialize(last
->args()));
120 ASSERT_EQ("http://www.google.com/", last
->SerializePageUrl());
121 ASSERT_EQ("{\"prerender\":true}",
122 ActivityLogPolicy::Util::Serialize(last
->other()));
123 ASSERT_EQ("", last
->api_name());
124 ASSERT_EQ("", last
->page_title());
125 ASSERT_EQ("", last
->SerializeArgUrl());
128 static void RetrieveActions_ArgUrlExtraction(
129 scoped_ptr
<std::vector
<scoped_refptr
<Action
> > > i
) {
130 const base::DictionaryValue
* other
= NULL
;
133 ASSERT_EQ(4U, i
->size());
134 scoped_refptr
<Action
> action
= i
->at(0);
135 ASSERT_EQ("XMLHttpRequest.open", action
->api_name());
136 ASSERT_EQ("[\"POST\",\"\\u003Carg_url>\"]",
137 ActivityLogPolicy::Util::Serialize(action
->args()));
138 ASSERT_EQ("http://api.google.com/", action
->arg_url().spec());
139 // Test that the dom_verb field was changed to XHR (from METHOD). This
140 // could be tested on all retrieved XHR actions but it would be redundant,
141 // so just test once.
142 other
= action
->other();
144 ASSERT_TRUE(other
->GetInteger(activity_log_constants::kActionDomVerb
,
146 ASSERT_EQ(DomActionType::XHR
, dom_verb
);
149 ASSERT_EQ("XMLHttpRequest.open", action
->api_name());
150 ASSERT_EQ("[\"POST\",\"\\u003Carg_url>\"]",
151 ActivityLogPolicy::Util::Serialize(action
->args()));
152 ASSERT_EQ("http://www.google.com/api/", action
->arg_url().spec());
155 ASSERT_EQ("XMLHttpRequest.open", action
->api_name());
156 ASSERT_EQ("[\"POST\",\"/api/\"]",
157 ActivityLogPolicy::Util::Serialize(action
->args()));
158 ASSERT_FALSE(action
->arg_url().is_valid());
161 ASSERT_EQ("windows.create", action
->api_name());
162 ASSERT_EQ("[{\"url\":\"\\u003Carg_url>\"}]",
163 ActivityLogPolicy::Util::Serialize(action
->args()));
164 ASSERT_EQ("http://www.google.co.uk/", action
->arg_url().spec());
167 static void RetrieveActions_ArgUrlApiCalls(
168 scoped_ptr
<std::vector
<scoped_refptr
<Action
> > > actions
) {
169 size_t api_calls_size
= arraysize(kUrlApiCalls
);
170 const base::DictionaryValue
* other
= NULL
;
173 ASSERT_EQ(api_calls_size
, actions
->size());
175 for (size_t i
= 0; i
< actions
->size(); i
++) {
176 scoped_refptr
<Action
> action
= actions
->at(i
);
177 ASSERT_EQ(kExtensionId
, action
->extension_id());
178 ASSERT_EQ(Action::ACTION_DOM_ACCESS
, action
->action_type());
179 ASSERT_EQ(kUrlApiCalls
[i
], action
->api_name());
180 ASSERT_EQ("[\"\\u003Carg_url>\"]",
181 ActivityLogPolicy::Util::Serialize(action
->args()));
182 ASSERT_EQ("http://www.google.co.uk/", action
->arg_url().spec());
183 other
= action
->other();
186 other
->GetInteger(activity_log_constants::kActionDomVerb
, &dom_verb
));
187 ASSERT_EQ(DomActionType::SETTER
, dom_verb
);
191 ExtensionService
* extension_service_
;
193 #if defined OS_CHROMEOS
194 chromeos::ScopedTestDeviceSettingsService test_device_settings_service_
;
195 chromeos::ScopedTestCrosSettings test_cros_settings_
;
196 scoped_ptr
<chromeos::ScopedTestUserManager
> test_user_manager_
;
200 TEST_F(ActivityLogTest
, Construct
) {
201 ASSERT_TRUE(GetDatabaseEnabled());
202 ASSERT_FALSE(GetWatchdogActive());
205 TEST_F(ActivityLogTest
, LogAndFetchActions
) {
206 ActivityLog
* activity_log
= ActivityLog::GetInstance(profile());
207 scoped_ptr
<base::ListValue
> args(new base::ListValue());
208 ASSERT_TRUE(GetDatabaseEnabled());
210 // Write some API calls
211 scoped_refptr
<Action
> action
= new Action(kExtensionId
,
213 Action::ACTION_API_CALL
,
215 activity_log
->LogAction(action
);
216 action
= new Action(kExtensionId
,
218 Action::ACTION_DOM_ACCESS
,
220 action
->set_page_url(GURL("http://www.google.com"));
221 activity_log
->LogAction(action
);
223 activity_log
->GetFilteredActions(
230 base::Bind(ActivityLogTest::RetrieveActions_LogAndFetchActions2
));
233 TEST_F(ActivityLogTest
, LogPrerender
) {
234 scoped_refptr
<const Extension
> extension
=
236 .SetManifest(DictionaryBuilder()
237 .Set("name", "Test extension")
238 .Set("version", "1.0.0")
239 .Set("manifest_version", 2))
241 extension_service_
->AddExtension(extension
.get());
242 ActivityLog
* activity_log
= ActivityLog::GetInstance(profile());
243 ASSERT_TRUE(GetDatabaseEnabled());
244 GURL
url("http://www.google.com");
246 prerender::PrerenderManager
* prerender_manager
=
247 prerender::PrerenderManagerFactory::GetForProfile(
248 Profile::FromBrowserContext(profile()));
250 const gfx::Size
kSize(640, 480);
251 scoped_ptr
<prerender::PrerenderHandle
> prerender_handle(
252 prerender_manager
->AddPrerenderFromLocalPredictor(
254 web_contents()->GetController().GetDefaultSessionStorageNamespace(),
257 const std::vector
<content::WebContents
*> contentses
=
258 prerender_manager
->GetAllPrerenderingContents();
259 ASSERT_EQ(1U, contentses
.size());
260 content::WebContents
*contents
= contentses
[0];
261 ASSERT_TRUE(prerender_manager
->IsWebContentsPrerendering(contents
, NULL
));
263 ScriptExecutionObserver::ExecutingScriptsMap executing_scripts
;
264 executing_scripts
[extension
->id()].insert("script");
266 static_cast<ScriptExecutionObserver
*>(activity_log
)
267 ->OnScriptsExecuted(contents
, executing_scripts
, url
);
269 activity_log
->GetFilteredActions(
276 base::Bind(ActivityLogTest::Arguments_Prerender
));
278 prerender_manager
->CancelAllPrerenders();
281 TEST_F(ActivityLogTest
, ArgUrlExtraction
) {
282 ActivityLog
* activity_log
= ActivityLog::GetInstance(profile());
283 scoped_ptr
<base::ListValue
> args(new base::ListValue());
285 base::Time now
= base::Time::Now();
287 // Submit a DOM API call which should have its URL extracted into the arg_url
289 scoped_refptr
<Action
> action
= new Action(kExtensionId
,
291 Action::ACTION_DOM_ACCESS
,
292 "XMLHttpRequest.open");
293 action
->set_page_url(GURL("http://www.google.com/"));
294 action
->mutable_args()->AppendString("POST");
295 action
->mutable_args()->AppendString("http://api.google.com/");
296 action
->mutable_other()->SetInteger(activity_log_constants::kActionDomVerb
,
297 DomActionType::METHOD
);
298 activity_log
->LogAction(action
);
300 // Submit a DOM API call with a relative URL in the argument, which should be
301 // resolved relative to the page URL.
302 action
= new Action(kExtensionId
,
303 now
- base::TimeDelta::FromSeconds(1),
304 Action::ACTION_DOM_ACCESS
,
305 "XMLHttpRequest.open");
306 action
->set_page_url(GURL("http://www.google.com/"));
307 action
->mutable_args()->AppendString("POST");
308 action
->mutable_args()->AppendString("/api/");
309 action
->mutable_other()->SetInteger(activity_log_constants::kActionDomVerb
,
310 DomActionType::METHOD
);
311 activity_log
->LogAction(action
);
313 // Submit a DOM API call with a relative URL but no base page URL against
315 action
= new Action(kExtensionId
,
316 now
- base::TimeDelta::FromSeconds(2),
317 Action::ACTION_DOM_ACCESS
,
318 "XMLHttpRequest.open");
319 action
->mutable_args()->AppendString("POST");
320 action
->mutable_args()->AppendString("/api/");
321 action
->mutable_other()->SetInteger(activity_log_constants::kActionDomVerb
,
322 DomActionType::METHOD
);
323 activity_log
->LogAction(action
);
325 // Submit an API call with an embedded URL.
326 action
= new Action(kExtensionId
,
327 now
- base::TimeDelta::FromSeconds(3),
328 Action::ACTION_API_CALL
,
332 .Append(DictionaryBuilder().Set("url", "http://www.google.co.uk"))
334 activity_log
->LogAction(action
);
336 activity_log
->GetFilteredActions(
343 base::Bind(ActivityLogTest::RetrieveActions_ArgUrlExtraction
));
346 TEST_F(ActivityLogTest
, UninstalledExtension
) {
347 scoped_refptr
<const Extension
> extension
=
349 .SetManifest(DictionaryBuilder()
350 .Set("name", "Test extension")
351 .Set("version", "1.0.0")
352 .Set("manifest_version", 2))
355 ActivityLog
* activity_log
= ActivityLog::GetInstance(profile());
356 scoped_ptr
<base::ListValue
> args(new base::ListValue());
357 ASSERT_TRUE(GetDatabaseEnabled());
359 // Write some API calls
360 scoped_refptr
<Action
> action
= new Action(extension
->id(),
362 Action::ACTION_API_CALL
,
364 activity_log
->LogAction(action
);
365 action
= new Action(extension
->id(),
367 Action::ACTION_DOM_ACCESS
,
369 action
->set_page_url(GURL("http://www.google.com"));
371 activity_log
->OnExtensionUninstalled(
372 NULL
, extension
.get(), extensions::UNINSTALL_REASON_FOR_TESTING
);
373 activity_log
->GetFilteredActions(
380 base::Bind(ActivityLogTest::RetrieveActions_LogAndFetchActions0
));
383 TEST_F(ActivityLogTest
, ArgUrlApiCalls
) {
384 ActivityLog
* activity_log
= ActivityLog::GetInstance(profile());
385 scoped_ptr
<base::ListValue
> args(new base::ListValue());
386 base::Time now
= base::Time::Now();
387 int api_calls_size
= arraysize(kUrlApiCalls
);
388 scoped_refptr
<Action
> action
;
390 for (int i
= 0; i
< api_calls_size
; i
++) {
391 action
= new Action(kExtensionId
,
392 now
- base::TimeDelta::FromSeconds(i
),
393 Action::ACTION_DOM_ACCESS
,
395 action
->mutable_args()->AppendString("http://www.google.co.uk");
396 action
->mutable_other()->SetInteger(activity_log_constants::kActionDomVerb
,
397 DomActionType::SETTER
);
398 activity_log
->LogAction(action
);
401 activity_log
->GetFilteredActions(
408 base::Bind(ActivityLogTest::RetrieveActions_ArgUrlApiCalls
));
411 } // namespace extensions