activity_log_unittest.cc revision eb525c5499e34cc9c4b825d6d9e75bb07cc06ace
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.
4
5#include "base/command_line.h"
6#include "base/memory/scoped_ptr.h"
7#include "base/message_loop.h"
8#include "base/run_loop.h"
9#include "base/synchronization/waitable_event.h"
10#include "chrome/browser/extensions/activity_log/activity_log.h"
11#include "chrome/browser/extensions/activity_log/dom_actions.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/common/extensions/dom_action_types.h"
20#include "chrome/common/extensions/extension_builder.h"
21#include "chrome/test/base/chrome_render_view_host_test_harness.h"
22#include "chrome/test/base/testing_profile.h"
23#include "content/public/test/test_browser_thread_bundle.h"
24#include "sql/statement.h"
25#include "testing/gtest/include/gtest/gtest.h"
26
27#if defined(OS_CHROMEOS)
28#include "chrome/browser/chromeos/login/user_manager.h"
29#include "chrome/browser/chromeos/settings/cros_settings.h"
30#include "chrome/browser/chromeos/settings/device_settings_service.h"
31#endif
32
33namespace {
34
35const char kExtensionId[] = "abc";
36
37}  // namespace
38
39namespace extensions {
40
41class ActivityLogTest : public testing::Test {
42 protected:
43  ActivityLogTest()
44      : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP),
45        saved_cmdline_(CommandLine::NO_PROGRAM) {
46#if defined OS_CHROMEOS
47    test_user_manager_.reset(new chromeos::ScopedTestUserManager());
48#endif
49    CommandLine command_line(CommandLine::NO_PROGRAM);
50    saved_cmdline_ = *CommandLine::ForCurrentProcess();
51    profile_.reset(new TestingProfile());
52    CommandLine::ForCurrentProcess()->AppendSwitch(
53        switches::kEnableExtensionActivityLogging);
54    CommandLine::ForCurrentProcess()->AppendSwitch(
55        switches::kEnableExtensionActivityLogTesting);
56    extension_service_ = static_cast<TestExtensionSystem*>(
57        ExtensionSystem::Get(profile_.get()))->CreateExtensionService
58            (&command_line, base::FilePath(), false);
59    ActivityLog::RecomputeLoggingIsEnabled(false);
60  }
61
62  virtual ~ActivityLogTest() {
63#if defined OS_CHROMEOS
64    test_user_manager_.reset();
65#endif
66    base::RunLoop().RunUntilIdle();
67    profile_.reset(NULL);
68    base::RunLoop().RunUntilIdle();
69    // Restore the original command line and undo the affects of SetUp().
70    *CommandLine::ForCurrentProcess() = saved_cmdline_;
71    ActivityLog::RecomputeLoggingIsEnabled(false);
72  }
73
74  static void RetrieveActions_LogAndFetchActions(
75      scoped_ptr<std::vector<scoped_refptr<Action> > > i) {
76    ASSERT_EQ(2, static_cast<int>(i->size()));
77  }
78
79  static void RetrieveActions_LogAndFetchPathActions(
80      scoped_ptr<std::vector<scoped_refptr<Action> > > i) {
81    std::string args;
82    ASSERT_EQ(1U, i->size());
83    scoped_refptr<Action> last = i->front();
84    if (CommandLine::ForCurrentProcess()->HasSwitch(
85        switches::kEnableExtensionActivityLogTesting))
86      args = "Injected scripts () onto "
87              "http://www.google.com/foo?bar extra";
88    else
89      args = "Injected scripts () onto "
90              "http://www.google.com/foo extra";
91    ASSERT_EQ(args, last->PrintForDebug());
92  }
93
94  static void Arguments_Missing(
95      scoped_ptr<std::vector<scoped_refptr<Action> > > i) {
96    scoped_refptr<Action> last = i->front();
97    std::string id(kExtensionId);
98    std::string noargs = "ID: " + id + ", CATEGORY: "
99        "call, API: tabs.testMethod, ARGS: ";
100    ASSERT_EQ(noargs, last->PrintForDebug());
101  }
102
103  static void Arguments_Present(
104      scoped_ptr<std::vector<scoped_refptr<Action> > > i) {
105    scoped_refptr<Action> last = i->front();
106    std::string id(kExtensionId);
107    std::string args = "ID: " + id + ", CATEGORY: "
108        "call, API: extension.connect, ARGS: \"hello\", \"world\"";
109    ASSERT_EQ(args, last->PrintForDebug());
110  }
111
112 protected:
113  scoped_ptr<TestingProfile> profile_;
114  ExtensionService* extension_service_;
115
116  content::TestBrowserThreadBundle thread_bundle_;
117
118  // Used to preserve a copy of the original command line.
119  // The test framework will do this itself as well. However, by then,
120  // it is too late to call ActivityLog::RecomputeLoggingIsEnabled() in
121  // TearDown().
122  CommandLine saved_cmdline_;
123
124#if defined OS_CHROMEOS
125  chromeos::ScopedTestDeviceSettingsService test_device_settings_service_;
126  chromeos::ScopedTestCrosSettings test_cros_settings_;
127  scoped_ptr<chromeos::ScopedTestUserManager> test_user_manager_;
128#endif
129};
130
131class RenderViewActivityLogTest : public ChromeRenderViewHostTestHarness {
132 protected:
133  RenderViewActivityLogTest() : saved_cmdline_(CommandLine::NO_PROGRAM) {}
134
135  virtual void SetUp() OVERRIDE {
136    ChromeRenderViewHostTestHarness::SetUp();
137#if defined OS_CHROMEOS
138    test_user_manager_.reset(new chromeos::ScopedTestUserManager());
139#endif
140    CommandLine command_line(CommandLine::NO_PROGRAM);
141    saved_cmdline_ = *CommandLine::ForCurrentProcess();
142    CommandLine::ForCurrentProcess()->AppendSwitch(
143        switches::kEnableExtensionActivityLogging);
144    CommandLine::ForCurrentProcess()->AppendSwitch(
145        switches::kEnableExtensionActivityLogTesting);
146    ActivityLog::RecomputeLoggingIsEnabled(false);
147    extension_service_ = static_cast<TestExtensionSystem*>(
148        ExtensionSystem::Get(profile()))->CreateExtensionService(
149            &command_line, base::FilePath(), false);
150  }
151
152  virtual void TearDown() OVERRIDE {
153#if defined OS_CHROMEOS
154    test_user_manager_.reset();
155#endif
156    ChromeRenderViewHostTestHarness::TearDown();
157    *CommandLine::ForCurrentProcess() = saved_cmdline_;
158    ActivityLog::RecomputeLoggingIsEnabled(false);
159  }
160
161  static void Arguments_Prerender(
162      scoped_ptr<std::vector<scoped_refptr<Action> > > i) {
163    ASSERT_EQ(1U, i->size());
164    scoped_refptr<Action> last = i->front();
165    std::string args = "Injected scripts (\"script \") "
166        "onto http://www.google.com/ (prerender)";
167    ASSERT_EQ(args, last->PrintForDebug());
168  }
169
170  ExtensionService* extension_service_;
171  // Used to preserve a copy of the original command line.
172  // The test framework will do this itself as well. However, by then,
173  // it is too late to call ActivityLog::RecomputeLoggingIsEnabled() in
174  // TearDown().
175  CommandLine saved_cmdline_;
176
177 private:
178#if defined OS_CHROMEOS
179  chromeos::ScopedTestDeviceSettingsService test_device_settings_service_;
180  chromeos::ScopedTestCrosSettings test_cros_settings_;
181  scoped_ptr<chromeos::ScopedTestUserManager> test_user_manager_;
182#endif
183};
184
185TEST_F(ActivityLogTest, Enabled) {
186  ASSERT_TRUE(ActivityLog::IsLogEnabledOnAnyProfile());
187}
188
189TEST_F(ActivityLogTest, Construct) {
190  ActivityLog* activity_log = ActivityLog::GetInstance(profile_.get());
191  scoped_ptr<base::ListValue> args(new base::ListValue());
192  ASSERT_TRUE(activity_log->IsLogEnabled());
193  activity_log->LogAPIAction(
194      kExtensionId, std::string("tabs.testMethod"), args.get(), std::string());
195}
196
197TEST_F(ActivityLogTest, LogAndFetchActions) {
198  ActivityLog* activity_log = ActivityLog::GetInstance(profile_.get());
199  scoped_ptr<base::ListValue> args(new base::ListValue());
200  ASSERT_TRUE(activity_log->IsLogEnabled());
201
202  // Write some API calls
203  activity_log->LogAPIAction(
204      kExtensionId, std::string("tabs.testMethod"), args.get(), std::string());
205  activity_log->LogDOMAction(kExtensionId,
206                             GURL("http://www.google.com"),
207                             string16(),
208                             std::string("document.write"),
209                             args.get(),
210                             DomActionType::METHOD,
211                             std::string("extra"));
212  activity_log->GetActions(
213      kExtensionId,
214      0,
215      base::Bind(ActivityLogTest::RetrieveActions_LogAndFetchActions));
216}
217
218TEST_F(ActivityLogTest, LogAndFetchPathActions) {
219  ActivityLog* activity_log = ActivityLog::GetInstance(profile_.get());
220  scoped_ptr<base::ListValue> args(new base::ListValue());
221  ASSERT_TRUE(activity_log->IsLogEnabled());
222
223  activity_log->LogDOMAction(kExtensionId,
224                             GURL("http://www.google.com/foo?bar"),
225                             string16(),
226                             std::string("document.write"),
227                             args.get(),
228                             DomActionType::INSERTED,
229                             std::string("extra"));
230  activity_log->GetActions(
231      kExtensionId,
232      0,
233      base::Bind(ActivityLogTest::RetrieveActions_LogAndFetchPathActions));
234}
235
236TEST_F(ActivityLogTest, LogWithoutArguments) {
237  ActivityLog* activity_log = ActivityLog::GetInstance(profile_.get());
238  activity_log->SetArgumentLoggingForTesting(false);
239  ASSERT_TRUE(activity_log->IsLogEnabled());
240  activity_log->SetDefaultPolicy(ActivityLogPolicy::POLICY_NOARGS);
241  scoped_ptr<base::ListValue> args(new base::ListValue());
242  args->Set(0, new base::StringValue("hello"));
243  args->Set(1, new base::StringValue("world"));
244  activity_log->LogAPIAction(
245      kExtensionId, std::string("tabs.testMethod"), args.get(), std::string());
246  activity_log->GetActions(
247      kExtensionId, 0, base::Bind(ActivityLogTest::Arguments_Missing));
248}
249
250TEST_F(ActivityLogTest, LogWithArguments) {
251  ActivityLog* activity_log = ActivityLog::GetInstance(profile_.get());
252  activity_log->SetDefaultPolicy(ActivityLogPolicy::POLICY_FULLSTREAM);
253  ASSERT_TRUE(activity_log->IsLogEnabled());
254
255  scoped_ptr<base::ListValue> args(new base::ListValue());
256  args->Set(0, new base::StringValue("hello"));
257  args->Set(1, new base::StringValue("world"));
258  activity_log->LogAPIAction(kExtensionId,
259                             std::string("extension.connect"),
260                             args.get(),
261                             std::string());
262  activity_log->GetActions(
263      kExtensionId, 0, base::Bind(ActivityLogTest::Arguments_Present));
264}
265
266TEST_F(RenderViewActivityLogTest, LogPrerender) {
267  scoped_refptr<const Extension> extension =
268      ExtensionBuilder()
269          .SetManifest(DictionaryBuilder()
270                       .Set("name", "Test extension")
271                       .Set("version", "1.0.0")
272                       .Set("manifest_version", 2))
273          .Build();
274  extension_service_->AddExtension(extension.get());
275  ActivityLog* activity_log = ActivityLog::GetInstance(profile());
276  activity_log->SetDefaultPolicy(ActivityLogPolicy::POLICY_FULLSTREAM);
277  ASSERT_TRUE(activity_log->IsLogEnabled());
278  GURL url("http://www.google.com");
279
280  prerender::PrerenderManager* prerender_manager =
281      prerender::PrerenderManagerFactory::GetForProfile(
282          Profile::FromBrowserContext(profile()));
283
284  const gfx::Size kSize(640, 480);
285  scoped_ptr<prerender::PrerenderHandle> prerender_handle(
286      prerender_manager->AddPrerenderFromLocalPredictor(
287          url,
288          web_contents()->GetController().GetDefaultSessionStorageNamespace(),
289          kSize));
290
291  const std::vector<content::WebContents*> contentses =
292      prerender_manager->GetAllPrerenderingContents();
293  ASSERT_EQ(1U, contentses.size());
294  content::WebContents *contents = contentses[0];
295  ASSERT_TRUE(prerender_manager->IsWebContentsPrerendering(contents, NULL));
296
297  TabHelper::ScriptExecutionObserver::ExecutingScriptsMap executing_scripts;
298  executing_scripts[extension->id()].insert("script");
299
300  static_cast<TabHelper::ScriptExecutionObserver*>(activity_log)->
301      OnScriptsExecuted(contents, executing_scripts, 0, url);
302
303  activity_log->GetActions(
304      extension->id(), 0, base::Bind(
305          RenderViewActivityLogTest::Arguments_Prerender));
306
307  prerender_manager->CancelAllPrerenders();
308}
309
310}  // namespace extensions
311
312