Home | History | Annotate | Download | only in activity_log
      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/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"
     29 
     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"
     34 #endif
     35 
     36 namespace {
     37 
     38 const char kExtensionId[] = "abc";
     39 
     40 const char* 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"};
     52 
     53 }  // namespace
     54 
     55 namespace extensions {
     56 
     57 class ActivityLogTest : public ChromeRenderViewHostTestHarness {
     58  protected:
     59   virtual void SetUp() OVERRIDE {
     60     ChromeRenderViewHostTestHarness::SetUp();
     61 #if defined OS_CHROMEOS
     62     test_user_manager_.reset(new chromeos::ScopedTestUserManager());
     63 #endif
     64     CommandLine command_line(CommandLine::NO_PROGRAM);
     65     CommandLine::ForCurrentProcess()->AppendSwitch(
     66         switches::kEnableExtensionActivityLogging);
     67     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();
     73   }
     74 
     75   virtual void TearDown() OVERRIDE {
     76 #if defined OS_CHROMEOS
     77     test_user_manager_.reset();
     78 #endif
     79     base::RunLoop().RunUntilIdle();
     80     ChromeRenderViewHostTestHarness::TearDown();
     81   }
     82 
     83   static void RetrieveActions_LogAndFetchActions0(
     84       scoped_ptr<std::vector<scoped_refptr<Action> > > i) {
     85     ASSERT_EQ(0, static_cast<int>(i->size()));
     86   }
     87 
     88   static void RetrieveActions_LogAndFetchActions2(
     89       scoped_ptr<std::vector<scoped_refptr<Action> > > i) {
     90     ASSERT_EQ(2, static_cast<int>(i->size()));
     91   }
     92 
     93   void SetPolicy(bool log_arguments) {
     94     ActivityLog* activity_log = ActivityLog::GetInstance(profile());
     95     if (log_arguments)
     96       activity_log->SetDatabasePolicy(ActivityLogPolicy::POLICY_FULLSTREAM);
     97     else
     98       activity_log->SetDatabasePolicy(ActivityLogPolicy::POLICY_COUNTS);
     99   }
    100 
    101   bool GetDatabaseEnabled() {
    102     ActivityLog* activity_log = ActivityLog::GetInstance(profile());
    103     return activity_log->IsDatabaseEnabled();
    104   }
    105 
    106   bool GetWatchdogActive() {
    107     ActivityLog* activity_log = ActivityLog::GetInstance(profile());
    108     return activity_log->IsWatchdogAppActive();
    109   }
    110 
    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();
    115 
    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());
    126   }
    127 
    128   static void RetrieveActions_ArgUrlExtraction(
    129       scoped_ptr<std::vector<scoped_refptr<Action> > > i) {
    130     const base::DictionaryValue* other = NULL;
    131     int dom_verb = -1;
    132 
    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();
    143     ASSERT_TRUE(other);
    144     ASSERT_TRUE(other->GetInteger(activity_log_constants::kActionDomVerb,
    145                                   &dom_verb));
    146     ASSERT_EQ(DomActionType::XHR, dom_verb);
    147 
    148     action = i->at(1);
    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());
    153 
    154     action = i->at(2);
    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());
    159 
    160     action = i->at(3);
    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());
    165   }
    166 
    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;
    171     int dom_verb = -1;
    172 
    173     ASSERT_EQ(api_calls_size, actions->size());
    174 
    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();
    184       ASSERT_TRUE(other);
    185       ASSERT_TRUE(
    186           other->GetInteger(activity_log_constants::kActionDomVerb, &dom_verb));
    187       ASSERT_EQ(DomActionType::SETTER, dom_verb);
    188     }
    189   }
    190 
    191   ExtensionService* extension_service_;
    192 
    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_;
    197 #endif
    198 };
    199 
    200 TEST_F(ActivityLogTest, Construct) {
    201   ASSERT_TRUE(GetDatabaseEnabled());
    202   ASSERT_FALSE(GetWatchdogActive());
    203 }
    204 
    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());
    209 
    210   // Write some API calls
    211   scoped_refptr<Action> action = new Action(kExtensionId,
    212                                             base::Time::Now(),
    213                                             Action::ACTION_API_CALL,
    214                                             "tabs.testMethod");
    215   activity_log->LogAction(action);
    216   action = new Action(kExtensionId,
    217                       base::Time::Now(),
    218                       Action::ACTION_DOM_ACCESS,
    219                       "document.write");
    220   action->set_page_url(GURL("http://www.google.com"));
    221   activity_log->LogAction(action);
    222 
    223   activity_log->GetFilteredActions(
    224       kExtensionId,
    225       Action::ACTION_ANY,
    226       "",
    227       "",
    228       "",
    229       0,
    230       base::Bind(ActivityLogTest::RetrieveActions_LogAndFetchActions2));
    231 }
    232 
    233 TEST_F(ActivityLogTest, LogPrerender) {
    234   scoped_refptr<const Extension> extension =
    235       ExtensionBuilder()
    236           .SetManifest(DictionaryBuilder()
    237                        .Set("name", "Test extension")
    238                        .Set("version", "1.0.0")
    239                        .Set("manifest_version", 2))
    240           .Build();
    241   extension_service_->AddExtension(extension.get());
    242   ActivityLog* activity_log = ActivityLog::GetInstance(profile());
    243   ASSERT_TRUE(GetDatabaseEnabled());
    244   GURL url("http://www.google.com");
    245 
    246   prerender::PrerenderManager* prerender_manager =
    247       prerender::PrerenderManagerFactory::GetForProfile(
    248           Profile::FromBrowserContext(profile()));
    249 
    250   prerender_manager->OnCookieStoreLoaded();
    251 
    252   const gfx::Size kSize(640, 480);
    253   scoped_ptr<prerender::PrerenderHandle> prerender_handle(
    254       prerender_manager->AddPrerenderFromLocalPredictor(
    255           url,
    256           web_contents()->GetController().GetDefaultSessionStorageNamespace(),
    257           kSize));
    258 
    259   const std::vector<content::WebContents*> contentses =
    260       prerender_manager->GetAllPrerenderingContents();
    261   ASSERT_EQ(1U, contentses.size());
    262   content::WebContents *contents = contentses[0];
    263   ASSERT_TRUE(prerender_manager->IsWebContentsPrerendering(contents, NULL));
    264 
    265   ScriptExecutionObserver::ExecutingScriptsMap executing_scripts;
    266   executing_scripts[extension->id()].insert("script");
    267 
    268   static_cast<ScriptExecutionObserver*>(activity_log)
    269       ->OnScriptsExecuted(contents, executing_scripts, url);
    270 
    271   activity_log->GetFilteredActions(
    272       extension->id(),
    273       Action::ACTION_ANY,
    274       "",
    275       "",
    276       "",
    277       0,
    278       base::Bind(ActivityLogTest::Arguments_Prerender));
    279 
    280   prerender_manager->CancelAllPrerenders();
    281 }
    282 
    283 TEST_F(ActivityLogTest, ArgUrlExtraction) {
    284   ActivityLog* activity_log = ActivityLog::GetInstance(profile());
    285   scoped_ptr<base::ListValue> args(new base::ListValue());
    286 
    287   base::Time now = base::Time::Now();
    288 
    289   // Submit a DOM API call which should have its URL extracted into the arg_url
    290   // field.
    291   scoped_refptr<Action> action = new Action(kExtensionId,
    292                                             now,
    293                                             Action::ACTION_DOM_ACCESS,
    294                                             "XMLHttpRequest.open");
    295   action->set_page_url(GURL("http://www.google.com/"));
    296   action->mutable_args()->AppendString("POST");
    297   action->mutable_args()->AppendString("http://api.google.com/");
    298   action->mutable_other()->SetInteger(activity_log_constants::kActionDomVerb,
    299                                       DomActionType::METHOD);
    300   activity_log->LogAction(action);
    301 
    302   // Submit a DOM API call with a relative URL in the argument, which should be
    303   // resolved relative to the page URL.
    304   action = new Action(kExtensionId,
    305                       now - base::TimeDelta::FromSeconds(1),
    306                       Action::ACTION_DOM_ACCESS,
    307                       "XMLHttpRequest.open");
    308   action->set_page_url(GURL("http://www.google.com/"));
    309   action->mutable_args()->AppendString("POST");
    310   action->mutable_args()->AppendString("/api/");
    311   action->mutable_other()->SetInteger(activity_log_constants::kActionDomVerb,
    312                                       DomActionType::METHOD);
    313   activity_log->LogAction(action);
    314 
    315   // Submit a DOM API call with a relative URL but no base page URL against
    316   // which to resolve.
    317   action = new Action(kExtensionId,
    318                       now - base::TimeDelta::FromSeconds(2),
    319                       Action::ACTION_DOM_ACCESS,
    320                       "XMLHttpRequest.open");
    321   action->mutable_args()->AppendString("POST");
    322   action->mutable_args()->AppendString("/api/");
    323   action->mutable_other()->SetInteger(activity_log_constants::kActionDomVerb,
    324                                       DomActionType::METHOD);
    325   activity_log->LogAction(action);
    326 
    327   // Submit an API call with an embedded URL.
    328   action = new Action(kExtensionId,
    329                       now - base::TimeDelta::FromSeconds(3),
    330                       Action::ACTION_API_CALL,
    331                       "windows.create");
    332   action->set_args(
    333       ListBuilder()
    334           .Append(DictionaryBuilder().Set("url", "http://www.google.co.uk"))
    335           .Build());
    336   activity_log->LogAction(action);
    337 
    338   activity_log->GetFilteredActions(
    339       kExtensionId,
    340       Action::ACTION_ANY,
    341       "",
    342       "",
    343       "",
    344       -1,
    345       base::Bind(ActivityLogTest::RetrieveActions_ArgUrlExtraction));
    346 }
    347 
    348 TEST_F(ActivityLogTest, UninstalledExtension) {
    349   scoped_refptr<const Extension> extension =
    350       ExtensionBuilder()
    351           .SetManifest(DictionaryBuilder()
    352                        .Set("name", "Test extension")
    353                        .Set("version", "1.0.0")
    354                        .Set("manifest_version", 2))
    355           .Build();
    356 
    357   ActivityLog* activity_log = ActivityLog::GetInstance(profile());
    358   scoped_ptr<base::ListValue> args(new base::ListValue());
    359   ASSERT_TRUE(GetDatabaseEnabled());
    360 
    361   // Write some API calls
    362   scoped_refptr<Action> action = new Action(extension->id(),
    363                                             base::Time::Now(),
    364                                             Action::ACTION_API_CALL,
    365                                             "tabs.testMethod");
    366   activity_log->LogAction(action);
    367   action = new Action(extension->id(),
    368                       base::Time::Now(),
    369                       Action::ACTION_DOM_ACCESS,
    370                       "document.write");
    371   action->set_page_url(GURL("http://www.google.com"));
    372 
    373   activity_log->OnExtensionUninstalled(
    374       NULL, extension.get(), extensions::UNINSTALL_REASON_FOR_TESTING);
    375   activity_log->GetFilteredActions(
    376       extension->id(),
    377       Action::ACTION_ANY,
    378       "",
    379       "",
    380       "",
    381       -1,
    382       base::Bind(ActivityLogTest::RetrieveActions_LogAndFetchActions0));
    383 }
    384 
    385 TEST_F(ActivityLogTest, ArgUrlApiCalls) {
    386   ActivityLog* activity_log = ActivityLog::GetInstance(profile());
    387   scoped_ptr<base::ListValue> args(new base::ListValue());
    388   base::Time now = base::Time::Now();
    389   int api_calls_size = arraysize(kUrlApiCalls);
    390   scoped_refptr<Action> action;
    391 
    392   for (int i = 0; i < api_calls_size; i++) {
    393     action = new Action(kExtensionId,
    394                         now - base::TimeDelta::FromSeconds(i),
    395                         Action::ACTION_DOM_ACCESS,
    396                         kUrlApiCalls[i]);
    397     action->mutable_args()->AppendString("http://www.google.co.uk");
    398     action->mutable_other()->SetInteger(activity_log_constants::kActionDomVerb,
    399                                         DomActionType::SETTER);
    400     activity_log->LogAction(action);
    401   }
    402 
    403   activity_log->GetFilteredActions(
    404       kExtensionId,
    405       Action::ACTION_ANY,
    406       "",
    407       "",
    408       "",
    409       -1,
    410       base::Bind(ActivityLogTest::RetrieveActions_ArgUrlApiCalls));
    411 }
    412 
    413 }  // namespace extensions
    414