| OLD | NEW |
| (Empty) |
| 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/files/file_path.h" | |
| 7 #include "base/logging.h" | |
| 8 #include "base/path_service.h" | |
| 9 #include "base/strings/string_number_conversions.h" | |
| 10 #include "base/threading/sequenced_worker_pool.h" | |
| 11 #include "chrome/browser/browser_process.h" | |
| 12 #include "chrome/browser/chrome_notification_types.h" | |
| 13 #include "chrome/browser/extensions/extension_browsertest.h" | |
| 14 #include "chrome/browser/extensions/extension_service.h" | |
| 15 #include "chrome/browser/performance_monitor/constants.h" | |
| 16 #include "chrome/browser/performance_monitor/database.h" | |
| 17 #include "chrome/browser/performance_monitor/metric.h" | |
| 18 #include "chrome/browser/performance_monitor/performance_monitor.h" | |
| 19 #include "chrome/browser/prefs/session_startup_pref.h" | |
| 20 #include "chrome/browser/profiles/profile.h" | |
| 21 #include "chrome/browser/profiles/profile_manager.h" | |
| 22 #include "chrome/browser/sessions/session_service.h" | |
| 23 #include "chrome/browser/sessions/session_service_factory.h" | |
| 24 #include "chrome/browser/sessions/session_service_test_helper.h" | |
| 25 #include "chrome/browser/ui/browser.h" | |
| 26 #include "chrome/browser/ui/browser_commands.h" | |
| 27 #include "chrome/browser/ui/browser_navigator.h" | |
| 28 #include "chrome/browser/ui/browser_window.h" | |
| 29 #include "chrome/browser/ui/host_desktop.h" | |
| 30 #include "chrome/browser/ui/tabs/tab_strip_model.h" | |
| 31 #include "chrome/common/chrome_constants.h" | |
| 32 #include "chrome/common/chrome_paths.h" | |
| 33 #include "chrome/common/chrome_switches.h" | |
| 34 #include "chrome/common/chrome_version_info.h" | |
| 35 #include "chrome/common/url_constants.h" | |
| 36 #include "chrome/test/base/ui_test_utils.h" | |
| 37 #include "content/public/browser/notification_registrar.h" | |
| 38 #include "content/public/browser/notification_service.h" | |
| 39 #include "content/public/common/page_transition_types.h" | |
| 40 #include "content/public/test/browser_test_utils.h" | |
| 41 #include "content/public/test/test_navigation_observer.h" | |
| 42 #include "content/public/test/test_utils.h" | |
| 43 #include "extensions/browser/extension_registry.h" | |
| 44 #include "extensions/browser/extension_system.h" | |
| 45 #include "extensions/common/extension.h" | |
| 46 | |
| 47 #if defined(OS_CHROMEOS) | |
| 48 #include "chrome/browser/chromeos/profiles/profile_helper.h" | |
| 49 #include "chromeos/chromeos_switches.h" | |
| 50 #include "components/user_manager/user_manager.h" | |
| 51 #endif | |
| 52 | |
| 53 #if defined(OS_MACOSX) | |
| 54 #include "base/mac/scoped_nsautorelease_pool.h" | |
| 55 #endif | |
| 56 | |
| 57 using extensions::Extension; | |
| 58 | |
| 59 namespace performance_monitor { | |
| 60 | |
| 61 namespace { | |
| 62 | |
| 63 const base::TimeDelta kMaxStartupTime = base::TimeDelta::FromMinutes(3); | |
| 64 | |
| 65 #if defined(OS_CHROMEOS) | |
| 66 // User account email and directory hash for secondary account for multi-profile | |
| 67 // sensitive test cases. | |
| 68 const char kSecondProfileAccount[] = "profile2@test.com"; | |
| 69 const char kSecondProfileHash[] = "profile2"; | |
| 70 #endif | |
| 71 | |
| 72 // Helper struct to store the information of an extension; this is needed if the | |
| 73 // pointer to the extension ever becomes invalid (e.g., if we uninstall the | |
| 74 // extension). | |
| 75 struct ExtensionBasicInfo { | |
| 76 // Empty constructor for stl-container-happiness. | |
| 77 ExtensionBasicInfo() { | |
| 78 } | |
| 79 explicit ExtensionBasicInfo(const Extension* extension) | |
| 80 : description(extension->description()), | |
| 81 id(extension->id()), | |
| 82 name(extension->name()), | |
| 83 url(extension->url().spec()), | |
| 84 version(extension->VersionString()), | |
| 85 location(extension->location()) { | |
| 86 } | |
| 87 | |
| 88 std::string description; | |
| 89 std::string id; | |
| 90 std::string name; | |
| 91 std::string url; | |
| 92 std::string version; | |
| 93 extensions::Manifest::Location location; | |
| 94 }; | |
| 95 | |
| 96 // Compare the fields of |extension| to those in |value|; this is a check to | |
| 97 // make sure the extension data was recorded properly in the event. | |
| 98 void ValidateExtensionInfo(const ExtensionBasicInfo extension, | |
| 99 const base::DictionaryValue* value) { | |
| 100 std::string extension_description; | |
| 101 std::string extension_id; | |
| 102 std::string extension_name; | |
| 103 std::string extension_url; | |
| 104 std::string extension_version; | |
| 105 int extension_location; | |
| 106 | |
| 107 ASSERT_TRUE(value->GetString("extensionDescription", | |
| 108 &extension_description)); | |
| 109 ASSERT_EQ(extension.description, extension_description); | |
| 110 ASSERT_TRUE(value->GetString("extensionId", &extension_id)); | |
| 111 ASSERT_EQ(extension.id, extension_id); | |
| 112 ASSERT_TRUE(value->GetString("extensionName", &extension_name)); | |
| 113 ASSERT_EQ(extension.name, extension_name); | |
| 114 ASSERT_TRUE(value->GetString("extensionUrl", &extension_url)); | |
| 115 ASSERT_EQ(extension.url, extension_url); | |
| 116 ASSERT_TRUE(value->GetString("extensionVersion", &extension_version)); | |
| 117 ASSERT_EQ(extension.version, extension_version); | |
| 118 ASSERT_TRUE(value->GetInteger("extensionLocation", &extension_location)); | |
| 119 ASSERT_EQ(extension.location, extension_location); | |
| 120 } | |
| 121 | |
| 122 // Verify that a particular event has the proper type. | |
| 123 void CheckEventType(int expected_event_type, const linked_ptr<Event>& event) { | |
| 124 int event_type = -1; | |
| 125 ASSERT_TRUE(event->data()->GetInteger("eventType", &event_type)); | |
| 126 ASSERT_EQ(expected_event_type, event_type); | |
| 127 ASSERT_EQ(expected_event_type, event->type()); | |
| 128 } | |
| 129 | |
| 130 // Verify that we received the proper number of events, checking the type of | |
| 131 // each one. | |
| 132 void CheckEventTypes(const std::vector<int>& expected_event_types, | |
| 133 const Database::EventVector& events) { | |
| 134 ASSERT_EQ(expected_event_types.size(), events.size()); | |
| 135 | |
| 136 for (size_t i = 0; i < expected_event_types.size(); ++i) | |
| 137 CheckEventType(expected_event_types[i], events[i]); | |
| 138 } | |
| 139 | |
| 140 // Check that we received the proper number of events, that each event is of the | |
| 141 // proper type, and that each event recorded the proper information about the | |
| 142 // extension. | |
| 143 void CheckExtensionEvents( | |
| 144 const std::vector<int>& expected_event_types, | |
| 145 const Database::EventVector& events, | |
| 146 const std::vector<ExtensionBasicInfo>& extension_infos) { | |
| 147 CheckEventTypes(expected_event_types, events); | |
| 148 | |
| 149 for (size_t i = 0; i < expected_event_types.size(); ++i) { | |
| 150 ValidateExtensionInfo(extension_infos[i], events[i]->data()); | |
| 151 int event_type; | |
| 152 ASSERT_TRUE(events[i]->data()->GetInteger("eventType", &event_type)); | |
| 153 ASSERT_EQ(expected_event_types[i], event_type); | |
| 154 } | |
| 155 } | |
| 156 | |
| 157 } // namespace | |
| 158 | |
| 159 class PerformanceMonitorBrowserTest : public ExtensionBrowserTest { | |
| 160 public: | |
| 161 virtual void SetUpOnMainThread() OVERRIDE { | |
| 162 CHECK(db_dir_.CreateUniqueTempDir()); | |
| 163 performance_monitor_ = PerformanceMonitor::GetInstance(); | |
| 164 performance_monitor_->SetDatabasePath(db_dir_.path()); | |
| 165 | |
| 166 // PerformanceMonitor's initialization process involves a significant | |
| 167 // amount of thread-hopping between the UI thread and the background thread. | |
| 168 // If we begin the tests prior to full initialization, we cannot predict | |
| 169 // the behavior or mock synchronicity as we must. Wait for initialization | |
| 170 // to complete fully before proceeding with the test. | |
| 171 content::WindowedNotificationObserver windowed_observer( | |
| 172 chrome::NOTIFICATION_PERFORMANCE_MONITOR_INITIALIZED, | |
| 173 content::NotificationService::AllSources()); | |
| 174 | |
| 175 // We stop the timer in charge of doing timed collections so that we can | |
| 176 // enforce when, and how many times, we do these collections. | |
| 177 performance_monitor_->disable_timer_autostart_for_testing_ = true; | |
| 178 // Force metrics to be stored, regardless of switches used. | |
| 179 performance_monitor_->database_logging_enabled_ = true; | |
| 180 performance_monitor_->Initialize(); | |
| 181 | |
| 182 windowed_observer.Wait(); | |
| 183 } | |
| 184 | |
| 185 // A handle for gathering statistics from the database, which must be done on | |
| 186 // the background thread. Since we are testing, we can mock synchronicity with | |
| 187 // FlushForTesting(). | |
| 188 void GatherStatistics() { | |
| 189 performance_monitor_->next_collection_time_ = base::Time::Now(); | |
| 190 performance_monitor_->GatherMetricsMapOnUIThread(); | |
| 191 | |
| 192 RunAllPendingInMessageLoop(content::BrowserThread::IO); | |
| 193 content::BrowserThread::GetBlockingPool()->FlushForTesting(); | |
| 194 } | |
| 195 | |
| 196 void GetEventsOnBackgroundThread(Database::EventVector* events) { | |
| 197 // base::Time is potentially flaky in that there is no guarantee that it | |
| 198 // won't actually decrease between successive calls. If we call GetEvents | |
| 199 // and the Database uses base::Time::Now() and gets a lesser time, then it | |
| 200 // will return 0 events. Thus, we use a time that is guaranteed to be in the | |
| 201 // future (for at least the next couple hundred thousand years). | |
| 202 *events = performance_monitor_->database()->GetEvents( | |
| 203 base::Time(), base::Time::FromInternalValue(kint64max)); | |
| 204 } | |
| 205 | |
| 206 // A handle for getting the events from the database, which must be done on | |
| 207 // the background thread. Since we are testing, we can mock synchronicity | |
| 208 // with FlushForTesting(). | |
| 209 Database::EventVector GetEvents() { | |
| 210 // Ensure that any event insertions happen prior to getting events in order | |
| 211 // to avoid race conditions. | |
| 212 content::BrowserThread::GetBlockingPool()->FlushForTesting(); | |
| 213 content::RunAllPendingInMessageLoop(); | |
| 214 | |
| 215 Database::EventVector events; | |
| 216 content::BrowserThread::PostBlockingPoolSequencedTask( | |
| 217 Database::kDatabaseSequenceToken, | |
| 218 FROM_HERE, | |
| 219 base::Bind(&PerformanceMonitorBrowserTest::GetEventsOnBackgroundThread, | |
| 220 base::Unretained(this), | |
| 221 &events)); | |
| 222 | |
| 223 content::BrowserThread::GetBlockingPool()->FlushForTesting(); | |
| 224 return events; | |
| 225 } | |
| 226 | |
| 227 void GetStatsOnBackgroundThread(Database::MetricVector* metrics, | |
| 228 MetricType type) { | |
| 229 *metrics = *performance_monitor_->database()->GetStatsForActivityAndMetric( | |
| 230 type, base::Time(), base::Time::FromInternalValue(kint64max)); | |
| 231 } | |
| 232 | |
| 233 // A handle for getting statistics from the database (see previous comments on | |
| 234 // GetEvents() and GetEventsOnBackgroundThread). | |
| 235 Database::MetricVector GetStats(MetricType type) { | |
| 236 content::BrowserThread::GetBlockingPool()->FlushForTesting(); | |
| 237 content::RunAllPendingInMessageLoop(); | |
| 238 | |
| 239 Database::MetricVector metrics; | |
| 240 content::BrowserThread::PostBlockingPoolSequencedTask( | |
| 241 Database::kDatabaseSequenceToken, | |
| 242 FROM_HERE, | |
| 243 base::Bind(&PerformanceMonitorBrowserTest::GetStatsOnBackgroundThread, | |
| 244 base::Unretained(this), | |
| 245 &metrics, | |
| 246 type)); | |
| 247 | |
| 248 content::BrowserThread::GetBlockingPool()->FlushForTesting(); | |
| 249 return metrics; | |
| 250 } | |
| 251 | |
| 252 // A handle for inserting a state value into the database, which must be done | |
| 253 // on the background thread. This is useful for mocking up a scenario in which | |
| 254 // the database has prior data stored. We mock synchronicity with | |
| 255 // FlushForTesting(). | |
| 256 void AddStateValue(const std::string& key, const std::string& value) { | |
| 257 content::BrowserThread::PostBlockingPoolSequencedTask( | |
| 258 Database::kDatabaseSequenceToken, | |
| 259 FROM_HERE, | |
| 260 base::Bind(base::IgnoreResult(&Database::AddStateValue), | |
| 261 base::Unretained(performance_monitor()->database()), | |
| 262 key, | |
| 263 value)); | |
| 264 | |
| 265 content::BrowserThread::GetBlockingPool()->FlushForTesting(); | |
| 266 } | |
| 267 | |
| 268 // A handle for PerformanceMonitor::CheckForVersionUpdateOnBackgroundThread(); | |
| 269 // we mock synchronicity with FlushForTesting(). | |
| 270 void CheckForVersionUpdate() { | |
| 271 content::BrowserThread::PostBlockingPoolSequencedTask( | |
| 272 Database::kDatabaseSequenceToken, | |
| 273 FROM_HERE, | |
| 274 base::Bind(&PerformanceMonitor::CheckForVersionUpdateOnBackgroundThread, | |
| 275 base::Unretained(performance_monitor()))); | |
| 276 | |
| 277 content::BrowserThread::GetBlockingPool()->FlushForTesting(); | |
| 278 } | |
| 279 | |
| 280 PerformanceMonitor* performance_monitor() const { | |
| 281 return performance_monitor_; | |
| 282 } | |
| 283 | |
| 284 protected: | |
| 285 base::ScopedTempDir db_dir_; | |
| 286 PerformanceMonitor* performance_monitor_; | |
| 287 }; | |
| 288 | |
| 289 class PerformanceMonitorUncleanExitBrowserTest | |
| 290 : public PerformanceMonitorBrowserTest, | |
| 291 public testing::WithParamInterface<bool> { | |
| 292 public: | |
| 293 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { | |
| 294 PerformanceMonitorBrowserTest::SetUpCommandLine(command_line); | |
| 295 #if defined(OS_CHROMEOS) | |
| 296 command_line->AppendSwitch( | |
| 297 chromeos::switches::kIgnoreUserProfileMappingForTests); | |
| 298 #endif | |
| 299 } | |
| 300 | |
| 301 virtual bool SetUpUserDataDirectory() OVERRIDE { | |
| 302 base::FilePath user_data_directory; | |
| 303 PathService::Get(chrome::DIR_USER_DATA, &user_data_directory); | |
| 304 | |
| 305 // On CrOS, if we are "logged in" with the --login-profile switch, | |
| 306 // the default profile will be different. We check if we are logged in, and, | |
| 307 // if we are, we use that profile name instead. (Note: trybots will | |
| 308 // typically be logged in with 'user'.) | |
| 309 #if defined(OS_CHROMEOS) | |
| 310 const CommandLine command_line = *CommandLine::ForCurrentProcess(); | |
| 311 if (command_line.HasSwitch(chromeos::switches::kLoginProfile)) { | |
| 312 first_profile_name_ = | |
| 313 command_line.GetSwitchValueASCII(chromeos::switches::kLoginProfile); | |
| 314 } else { | |
| 315 first_profile_name_ = chrome::kInitialProfile; | |
| 316 } | |
| 317 #else | |
| 318 first_profile_name_ = chrome::kInitialProfile; | |
| 319 #endif | |
| 320 | |
| 321 base::FilePath first_profile = | |
| 322 user_data_directory.AppendASCII(first_profile_name_); | |
| 323 CHECK(base::CreateDirectory(first_profile)); | |
| 324 | |
| 325 base::FilePath stock_prefs_file; | |
| 326 PathService::Get(chrome::DIR_TEST_DATA, &stock_prefs_file); | |
| 327 stock_prefs_file = stock_prefs_file.AppendASCII("performance_monitor") | |
| 328 .AppendASCII("unclean_exit_prefs"); | |
| 329 CHECK(base::PathExists(stock_prefs_file)); | |
| 330 | |
| 331 base::FilePath first_profile_prefs_file = | |
| 332 first_profile.Append(chrome::kPreferencesFilename); | |
| 333 CHECK(base::CopyFile(stock_prefs_file, first_profile_prefs_file)); | |
| 334 CHECK(base::PathExists(first_profile_prefs_file)); | |
| 335 | |
| 336 second_profile_name_ = | |
| 337 std::string(chrome::kMultiProfileDirPrefix) | |
| 338 .append(base::IntToString(1)); | |
| 339 #if defined(OS_CHROMEOS) | |
| 340 if (GetParam()) { | |
| 341 second_profile_name_ = chromeos::ProfileHelper::GetUserProfileDir( | |
| 342 kSecondProfileHash).BaseName().value(); | |
| 343 } | |
| 344 #endif | |
| 345 | |
| 346 base::FilePath second_profile = | |
| 347 user_data_directory.AppendASCII(second_profile_name_); | |
| 348 CHECK(base::CreateDirectory(second_profile)); | |
| 349 | |
| 350 base::FilePath second_profile_prefs_file = | |
| 351 second_profile.Append(chrome::kPreferencesFilename); | |
| 352 CHECK(base::CopyFile(stock_prefs_file, second_profile_prefs_file)); | |
| 353 CHECK(base::PathExists(second_profile_prefs_file)); | |
| 354 | |
| 355 return true; | |
| 356 } | |
| 357 | |
| 358 #if defined(OS_CHROMEOS) | |
| 359 virtual void AddSecondUserAccount() { | |
| 360 // Add second user account for multi-profile test. | |
| 361 if (GetParam()) { | |
| 362 user_manager::UserManager::Get()->UserLoggedIn( | |
| 363 kSecondProfileAccount, kSecondProfileHash, false); | |
| 364 } | |
| 365 } | |
| 366 #endif | |
| 367 | |
| 368 protected: | |
| 369 std::string first_profile_name_; | |
| 370 std::string second_profile_name_; | |
| 371 }; | |
| 372 | |
| 373 class PerformanceMonitorSessionRestoreBrowserTest | |
| 374 : public PerformanceMonitorBrowserTest { | |
| 375 public: | |
| 376 virtual void SetUpOnMainThread() OVERRIDE { | |
| 377 SessionStartupPref pref(SessionStartupPref::LAST); | |
| 378 SessionStartupPref::SetStartupPref(browser()->profile(), pref); | |
| 379 #if defined(OS_CHROMEOS) || defined (OS_MACOSX) | |
| 380 // Undo the effect of kBrowserAliveWithNoWindows in defaults.cc so that we | |
| 381 // can get these test to work without quitting. | |
| 382 SessionServiceTestHelper helper( | |
| 383 SessionServiceFactory::GetForProfile(browser()->profile())); | |
| 384 helper.SetForceBrowserNotAliveWithNoWindows(true); | |
| 385 helper.ReleaseService(); | |
| 386 #endif | |
| 387 | |
| 388 PerformanceMonitorBrowserTest::SetUpOnMainThread(); | |
| 389 } | |
| 390 | |
| 391 Browser* QuitBrowserAndRestore(Browser* browser, int expected_tab_count) { | |
| 392 Profile* profile = browser->profile(); | |
| 393 | |
| 394 // Close the browser. | |
| 395 g_browser_process->AddRefModule(); | |
| 396 content::WindowedNotificationObserver observer( | |
| 397 chrome::NOTIFICATION_BROWSER_CLOSED, | |
| 398 content::NotificationService::AllSources()); | |
| 399 browser->window()->Close(); | |
| 400 #if defined(OS_MACOSX) | |
| 401 // BrowserWindowController depends on the auto release pool being recycled | |
| 402 // in the message loop to delete itself, which frees the Browser object | |
| 403 // which fires this event. | |
| 404 AutoreleasePool()->Recycle(); | |
| 405 #endif | |
| 406 observer.Wait(); | |
| 407 | |
| 408 // Create a new window, which should trigger session restore. | |
| 409 content::TestNavigationObserver restore_observer(NULL, expected_tab_count); | |
| 410 restore_observer.StartWatchingNewWebContents(); | |
| 411 ui_test_utils::BrowserAddedObserver window_observer; | |
| 412 chrome::NewEmptyWindow(profile, chrome::GetActiveDesktop()); | |
| 413 Browser* new_browser = window_observer.WaitForSingleNewBrowser(); | |
| 414 restore_observer.Wait(); | |
| 415 g_browser_process->ReleaseModule(); | |
| 416 | |
| 417 return new_browser; | |
| 418 } | |
| 419 }; | |
| 420 | |
| 421 // Test that PerformanceMonitor will correctly record an extension installation | |
| 422 // event. | |
| 423 IN_PROC_BROWSER_TEST_F(PerformanceMonitorBrowserTest, InstallExtensionEvent) { | |
| 424 base::FilePath extension_path; | |
| 425 PathService::Get(chrome::DIR_TEST_DATA, &extension_path); | |
| 426 extension_path = extension_path.AppendASCII("performance_monitor") | |
| 427 .AppendASCII("extensions") | |
| 428 .AppendASCII("simple_extension_v1"); | |
| 429 const Extension* extension = LoadExtension(extension_path); | |
| 430 | |
| 431 std::vector<ExtensionBasicInfo> extension_infos; | |
| 432 extension_infos.push_back(ExtensionBasicInfo(extension)); | |
| 433 | |
| 434 std::vector<int> expected_event_types; | |
| 435 expected_event_types.push_back(EVENT_EXTENSION_INSTALL); | |
| 436 | |
| 437 Database::EventVector events = GetEvents(); | |
| 438 CheckExtensionEvents(expected_event_types, events, extension_infos); | |
| 439 } | |
| 440 | |
| 441 // Test that PerformanceMonitor will correctly record events as an extension is | |
| 442 // disabled and enabled. | |
| 443 // Test is falky, see http://crbug.com/157980 | |
| 444 IN_PROC_BROWSER_TEST_F(PerformanceMonitorBrowserTest, | |
| 445 DISABLED_DisableAndEnableExtensionEvent) { | |
| 446 const int kNumEvents = 3; | |
| 447 | |
| 448 base::FilePath extension_path; | |
| 449 PathService::Get(chrome::DIR_TEST_DATA, &extension_path); | |
| 450 extension_path = extension_path.AppendASCII("performance_monitor") | |
| 451 .AppendASCII("extensions") | |
| 452 .AppendASCII("simple_extension_v1"); | |
| 453 const Extension* extension = LoadExtension(extension_path); | |
| 454 | |
| 455 DisableExtension(extension->id()); | |
| 456 EnableExtension(extension->id()); | |
| 457 | |
| 458 std::vector<ExtensionBasicInfo> extension_infos; | |
| 459 // There will be three events in all, each pertaining to the same extension: | |
| 460 // Extension Install | |
| 461 // Extension Disable | |
| 462 // Extension Enable | |
| 463 for (int i = 0; i < kNumEvents; ++i) | |
| 464 extension_infos.push_back(ExtensionBasicInfo(extension)); | |
| 465 | |
| 466 std::vector<int> expected_event_types; | |
| 467 expected_event_types.push_back(EVENT_EXTENSION_INSTALL); | |
| 468 expected_event_types.push_back(EVENT_EXTENSION_DISABLE); | |
| 469 expected_event_types.push_back(EVENT_EXTENSION_ENABLE); | |
| 470 | |
| 471 Database::EventVector events = GetEvents(); | |
| 472 CheckExtensionEvents(expected_event_types, events, extension_infos); | |
| 473 } | |
| 474 | |
| 475 // Test that PerformanceMonitor correctly records an extension update event. | |
| 476 IN_PROC_BROWSER_TEST_F(PerformanceMonitorBrowserTest, UpdateExtensionEvent) { | |
| 477 base::ScopedTempDir temp_dir; | |
| 478 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); | |
| 479 | |
| 480 base::FilePath test_data_dir; | |
| 481 PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir); | |
| 482 test_data_dir = test_data_dir.AppendASCII("performance_monitor") | |
| 483 .AppendASCII("extensions"); | |
| 484 | |
| 485 // We need two versions of the same extension. | |
| 486 base::FilePath pem_path = test_data_dir.AppendASCII("simple_extension.pem"); | |
| 487 base::FilePath path_v1_ = PackExtensionWithOptions( | |
| 488 test_data_dir.AppendASCII("simple_extension_v1"), | |
| 489 temp_dir.path().AppendASCII("simple_extension1.crx"), | |
| 490 pem_path, | |
| 491 base::FilePath()); | |
| 492 base::FilePath path_v2_ = PackExtensionWithOptions( | |
| 493 test_data_dir.AppendASCII("simple_extension_v2"), | |
| 494 temp_dir.path().AppendASCII("simple_extension2.crx"), | |
| 495 pem_path, | |
| 496 base::FilePath()); | |
| 497 | |
| 498 const extensions::Extension* extension = InstallExtension(path_v1_, 1); | |
| 499 | |
| 500 std::vector<ExtensionBasicInfo> extension_infos; | |
| 501 extension_infos.push_back(ExtensionBasicInfo(extension)); | |
| 502 | |
| 503 ExtensionService* extension_service = extensions::ExtensionSystem::Get( | |
| 504 browser()->profile())->extension_service(); | |
| 505 | |
| 506 extensions::CrxInstaller* crx_installer = NULL; | |
| 507 | |
| 508 // Create an observer to wait for the update to finish. | |
| 509 content::WindowedNotificationObserver windowed_observer( | |
| 510 extensions::NOTIFICATION_CRX_INSTALLER_DONE, | |
| 511 content::Source<extensions::CrxInstaller>(crx_installer)); | |
| 512 ASSERT_TRUE(extension_service->UpdateExtension( | |
| 513 extension->id(), path_v2_, true, &crx_installer)); | |
| 514 windowed_observer.Wait(); | |
| 515 | |
| 516 extension = extensions::ExtensionRegistry::Get( | |
| 517 browser()->profile())->enabled_extensions().GetByID( | |
| 518 extension_infos[0].id); | |
| 519 | |
| 520 // The total series of events for this process will be: | |
| 521 // Extension Install - install version 1 | |
| 522 // Extension Install - install version 2 | |
| 523 // Extension Update - signal the udate to version 2 | |
| 524 // We push back the corresponding ExtensionBasicInfos. | |
| 525 extension_infos.push_back(ExtensionBasicInfo(extension)); | |
| 526 extension_infos.push_back(extension_infos[1]); | |
| 527 | |
| 528 std::vector<int> expected_event_types; | |
| 529 expected_event_types.push_back(EVENT_EXTENSION_INSTALL); | |
| 530 expected_event_types.push_back(EVENT_EXTENSION_INSTALL); | |
| 531 expected_event_types.push_back(EVENT_EXTENSION_UPDATE); | |
| 532 | |
| 533 Database::EventVector events = GetEvents(); | |
| 534 | |
| 535 CheckExtensionEvents(expected_event_types, events, extension_infos); | |
| 536 } | |
| 537 | |
| 538 IN_PROC_BROWSER_TEST_F(PerformanceMonitorBrowserTest, UninstallExtensionEvent) { | |
| 539 const int kNumEvents = 2; | |
| 540 base::FilePath extension_path; | |
| 541 PathService::Get(chrome::DIR_TEST_DATA, &extension_path); | |
| 542 extension_path = extension_path.AppendASCII("performance_monitor") | |
| 543 .AppendASCII("extensions") | |
| 544 .AppendASCII("simple_extension_v1"); | |
| 545 const Extension* extension = LoadExtension(extension_path); | |
| 546 | |
| 547 std::vector<ExtensionBasicInfo> extension_infos; | |
| 548 // There will be two events, both pertaining to the same extension: | |
| 549 // Extension Install | |
| 550 // Extension Uninstall | |
| 551 for (int i = 0; i < kNumEvents; ++i) | |
| 552 extension_infos.push_back(ExtensionBasicInfo(extension)); | |
| 553 | |
| 554 UninstallExtension(extension->id()); | |
| 555 | |
| 556 std::vector<int> expected_event_types; | |
| 557 expected_event_types.push_back(EVENT_EXTENSION_INSTALL); | |
| 558 expected_event_types.push_back(EVENT_EXTENSION_UNINSTALL); | |
| 559 | |
| 560 Database::EventVector events = GetEvents(); | |
| 561 | |
| 562 CheckExtensionEvents(expected_event_types, events, extension_infos); | |
| 563 } | |
| 564 | |
| 565 IN_PROC_BROWSER_TEST_F(PerformanceMonitorBrowserTest, NewVersionEvent) { | |
| 566 const char kOldVersion[] = "0.0"; | |
| 567 | |
| 568 // The version in the database right now will be the current version of chrome | |
| 569 // (gathered at initialization of PerformanceMonitor). Replace this with an | |
| 570 // older version so an event is generated. | |
| 571 AddStateValue(kStateChromeVersion, kOldVersion); | |
| 572 | |
| 573 CheckForVersionUpdate(); | |
| 574 | |
| 575 chrome::VersionInfo version; | |
| 576 ASSERT_TRUE(version.is_valid()); | |
| 577 std::string version_string = version.Version(); | |
| 578 | |
| 579 Database::EventVector events = GetEvents(); | |
| 580 ASSERT_EQ(1u, events.size()); | |
| 581 ASSERT_EQ(EVENT_CHROME_UPDATE, events[0]->type()); | |
| 582 | |
| 583 const base::DictionaryValue* value; | |
| 584 ASSERT_TRUE(events[0]->data()->GetAsDictionary(&value)); | |
| 585 | |
| 586 std::string previous_version; | |
| 587 std::string current_version; | |
| 588 | |
| 589 ASSERT_TRUE(value->GetString("previousVersion", &previous_version)); | |
| 590 ASSERT_EQ(kOldVersion, previous_version); | |
| 591 ASSERT_TRUE(value->GetString("currentVersion", ¤t_version)); | |
| 592 ASSERT_EQ(version_string, current_version); | |
| 593 } | |
| 594 | |
| 595 // crbug.com/160502 | |
| 596 IN_PROC_BROWSER_TEST_F(PerformanceMonitorBrowserTest, | |
| 597 DISABLED_GatherStatistics) { | |
| 598 GatherStatistics(); | |
| 599 | |
| 600 // No stats should be recorded for this CPUUsage because this was the first | |
| 601 // call to GatherStatistics. | |
| 602 Database::MetricVector stats = GetStats(METRIC_CPU_USAGE); | |
| 603 ASSERT_EQ(0u, stats.size()); | |
| 604 | |
| 605 stats = GetStats(METRIC_PRIVATE_MEMORY_USAGE); | |
| 606 ASSERT_EQ(1u, stats.size()); | |
| 607 EXPECT_GT(stats[0].value, 0); | |
| 608 | |
| 609 stats = GetStats(METRIC_SHARED_MEMORY_USAGE); | |
| 610 ASSERT_EQ(1u, stats.size()); | |
| 611 EXPECT_GT(stats[0].value, 0); | |
| 612 | |
| 613 // Open new tabs to incur CPU usage. | |
| 614 for (int i = 0; i < 10; ++i) { | |
| 615 chrome::NavigateParams params( | |
| 616 browser(), ui_test_utils::GetTestUrl( | |
| 617 base::FilePath(base::FilePath::kCurrentDirectory), | |
| 618 base::FilePath(FILE_PATH_LITERAL("title1.html"))), | |
| 619 content::PAGE_TRANSITION_LINK); | |
| 620 params.disposition = NEW_BACKGROUND_TAB; | |
| 621 ui_test_utils::NavigateToURL(¶ms); | |
| 622 } | |
| 623 GatherStatistics(); | |
| 624 | |
| 625 // One CPUUsage stat should exist now. | |
| 626 stats = GetStats(METRIC_CPU_USAGE); | |
| 627 ASSERT_EQ(1u, stats.size()); | |
| 628 EXPECT_GT(stats[0].value, 0); | |
| 629 | |
| 630 stats = GetStats(METRIC_PRIVATE_MEMORY_USAGE); | |
| 631 ASSERT_EQ(2u, stats.size()); | |
| 632 EXPECT_GT(stats[1].value, 0); | |
| 633 | |
| 634 stats = GetStats(METRIC_SHARED_MEMORY_USAGE); | |
| 635 ASSERT_EQ(2u, stats.size()); | |
| 636 EXPECT_GT(stats[1].value, 0); | |
| 637 } | |
| 638 | |
| 639 // Disabled on other platforms because of flakiness: http://crbug.com/159172. | |
| 640 #if !defined(OS_WIN) | |
| 641 // Disabled on Windows due to a bug where Windows will return a normal exit | |
| 642 // code in the testing environment, even if the process died (this is not the | |
| 643 // case when hand-testing). This code can be traced to MSDN functions in | |
| 644 // base::GetTerminationStatus(), so there's not much we can do. | |
| 645 IN_PROC_BROWSER_TEST_F(PerformanceMonitorBrowserTest, | |
| 646 DISABLED_RendererKilledEvent) { | |
| 647 content::CrashTab(browser()->tab_strip_model()->GetActiveWebContents()); | |
| 648 | |
| 649 Database::EventVector events = GetEvents(); | |
| 650 | |
| 651 ASSERT_EQ(1u, events.size()); | |
| 652 CheckEventType(EVENT_RENDERER_KILLED, events[0]); | |
| 653 | |
| 654 // Check the url - since we never went anywhere, this should be about:blank. | |
| 655 std::string url; | |
| 656 ASSERT_TRUE(events[0]->data()->GetString("url", &url)); | |
| 657 ASSERT_EQ("about:blank", url); | |
| 658 } | |
| 659 #endif // !defined(OS_WIN) | |
| 660 | |
| 661 // TODO(jam): http://crbug.com/350550 | |
| 662 #if !(defined(OS_CHROMEOS) && defined(ADDRESS_SANITIZER)) | |
| 663 IN_PROC_BROWSER_TEST_F(PerformanceMonitorBrowserTest, RendererCrashEvent) { | |
| 664 content::RenderProcessHostWatcher observer( | |
| 665 browser()->tab_strip_model()->GetActiveWebContents(), | |
| 666 content::RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); | |
| 667 | |
| 668 ui_test_utils::NavigateToURL(browser(), GURL(content::kChromeUICrashURL)); | |
| 669 | |
| 670 observer.Wait(); | |
| 671 | |
| 672 Database::EventVector events = GetEvents(); | |
| 673 ASSERT_EQ(1u, events.size()); | |
| 674 | |
| 675 CheckEventType(EVENT_RENDERER_CRASH, events[0]); | |
| 676 | |
| 677 std::string url; | |
| 678 ASSERT_TRUE(events[0]->data()->GetString("url", &url)); | |
| 679 ASSERT_EQ("chrome://crash/", url); | |
| 680 } | |
| 681 #endif | |
| 682 | |
| 683 IN_PROC_BROWSER_TEST_P(PerformanceMonitorUncleanExitBrowserTest, | |
| 684 OneProfileUncleanExit) { | |
| 685 // Initialize the database value (if there's no value in the database, it | |
| 686 // can't determine the last active time of the profile, and doesn't insert | |
| 687 // the event). | |
| 688 const std::string time = "12985807272597591"; | |
| 689 AddStateValue(kStateProfilePrefix + first_profile_name_, time); | |
| 690 | |
| 691 performance_monitor()->CheckForUncleanExits(); | |
| 692 content::RunAllPendingInMessageLoop(); | |
| 693 | |
| 694 Database::EventVector events = GetEvents(); | |
| 695 | |
| 696 const size_t kNumEvents = 1; | |
| 697 ASSERT_EQ(kNumEvents, events.size()); | |
| 698 | |
| 699 CheckEventType(EVENT_UNCLEAN_EXIT, events[0]); | |
| 700 | |
| 701 std::string event_profile; | |
| 702 ASSERT_TRUE(events[0]->data()->GetString("profileName", &event_profile)); | |
| 703 ASSERT_EQ(first_profile_name_, event_profile); | |
| 704 } | |
| 705 | |
| 706 IN_PROC_BROWSER_TEST_P(PerformanceMonitorUncleanExitBrowserTest, | |
| 707 TwoProfileUncleanExit) { | |
| 708 #if defined(OS_CHROMEOS) | |
| 709 AddSecondUserAccount(); | |
| 710 #endif | |
| 711 | |
| 712 base::FilePath second_profile_path; | |
| 713 PathService::Get(chrome::DIR_USER_DATA, &second_profile_path); | |
| 714 second_profile_path = second_profile_path.AppendASCII(second_profile_name_); | |
| 715 | |
| 716 const std::string time1 = "12985807272597591"; | |
| 717 const std::string time2 = "12985807272599918"; | |
| 718 | |
| 719 // Initialize the database. | |
| 720 AddStateValue(kStateProfilePrefix + first_profile_name_, time1); | |
| 721 AddStateValue(kStateProfilePrefix + second_profile_name_, time2); | |
| 722 | |
| 723 performance_monitor()->CheckForUncleanExits(); | |
| 724 content::RunAllPendingInMessageLoop(); | |
| 725 | |
| 726 // Load the second profile, which has also exited uncleanly. Note that since | |
| 727 // the second profile is new, component extensions will be installed as part | |
| 728 // of the browser startup for that profile, generating extra events. | |
| 729 g_browser_process->profile_manager()->GetProfile(second_profile_path); | |
| 730 content::RunAllPendingInMessageLoop(); | |
| 731 | |
| 732 Database::EventVector events = GetEvents(); | |
| 733 | |
| 734 const size_t kNumUncleanExitEvents = 2; | |
| 735 size_t num_unclean_exit_events = 0; | |
| 736 for (size_t i = 0; i < events.size(); ++i) { | |
| 737 int event_type = -1; | |
| 738 if (events[i]->data()->GetInteger("eventType", &event_type) && | |
| 739 event_type == EVENT_EXTENSION_INSTALL) { | |
| 740 continue; | |
| 741 } | |
| 742 CheckEventType(EVENT_UNCLEAN_EXIT, events[i]); | |
| 743 ++num_unclean_exit_events; | |
| 744 } | |
| 745 ASSERT_EQ(kNumUncleanExitEvents, num_unclean_exit_events); | |
| 746 | |
| 747 std::string event_profile; | |
| 748 ASSERT_TRUE(events[0]->data()->GetString("profileName", &event_profile)); | |
| 749 ASSERT_EQ(first_profile_name_, event_profile); | |
| 750 | |
| 751 ASSERT_TRUE(events[1]->data()->GetString("profileName", &event_profile)); | |
| 752 ASSERT_EQ(second_profile_name_, event_profile); | |
| 753 } | |
| 754 | |
| 755 IN_PROC_BROWSER_TEST_F(PerformanceMonitorBrowserTest, StartupTime) { | |
| 756 Database::MetricVector metrics = GetStats(METRIC_TEST_STARTUP_TIME); | |
| 757 | |
| 758 ASSERT_EQ(1u, metrics.size()); | |
| 759 ASSERT_LT(metrics[0].value, kMaxStartupTime.ToInternalValue()); | |
| 760 } | |
| 761 | |
| 762 IN_PROC_BROWSER_TEST_F(PerformanceMonitorSessionRestoreBrowserTest, | |
| 763 StartupWithSessionRestore) { | |
| 764 ui_test_utils::NavigateToURL( | |
| 765 browser(), ui_test_utils::GetTestUrl( | |
| 766 base::FilePath(base::FilePath::kCurrentDirectory), | |
| 767 base::FilePath(FILE_PATH_LITERAL("title1.html")))); | |
| 768 | |
| 769 QuitBrowserAndRestore(browser(), 1); | |
| 770 | |
| 771 Database::MetricVector metrics = GetStats(METRIC_TEST_STARTUP_TIME); | |
| 772 ASSERT_EQ(1u, metrics.size()); | |
| 773 ASSERT_LT(metrics[0].value, kMaxStartupTime.ToInternalValue()); | |
| 774 | |
| 775 metrics = GetStats(METRIC_SESSION_RESTORE_TIME); | |
| 776 ASSERT_EQ(1u, metrics.size()); | |
| 777 ASSERT_LT(metrics[0].value, kMaxStartupTime.ToInternalValue()); | |
| 778 } | |
| 779 | |
| 780 IN_PROC_BROWSER_TEST_F(PerformanceMonitorBrowserTest, PageLoadTime) { | |
| 781 const base::TimeDelta kMaxLoadTime = base::TimeDelta::FromSeconds(30); | |
| 782 | |
| 783 ui_test_utils::NavigateToURL( | |
| 784 browser(), ui_test_utils::GetTestUrl( | |
| 785 base::FilePath(base::FilePath::kCurrentDirectory), | |
| 786 base::FilePath(FILE_PATH_LITERAL("title1.html")))); | |
| 787 | |
| 788 ui_test_utils::NavigateToURL( | |
| 789 browser(), ui_test_utils::GetTestUrl( | |
| 790 base::FilePath(base::FilePath::kCurrentDirectory), | |
| 791 base::FilePath(FILE_PATH_LITERAL("title1.html")))); | |
| 792 | |
| 793 Database::MetricVector metrics = GetStats(METRIC_PAGE_LOAD_TIME); | |
| 794 | |
| 795 ASSERT_EQ(2u, metrics.size()); | |
| 796 ASSERT_LT(metrics[0].value, kMaxLoadTime.ToInternalValue()); | |
| 797 ASSERT_LT(metrics[1].value, kMaxLoadTime.ToInternalValue()); | |
| 798 } | |
| 799 | |
| 800 IN_PROC_BROWSER_TEST_F(PerformanceMonitorBrowserTest, NetworkBytesRead) { | |
| 801 base::FilePath test_dir; | |
| 802 PathService::Get(chrome::DIR_TEST_DATA, &test_dir); | |
| 803 | |
| 804 int64 page1_size = 0; | |
| 805 ASSERT_TRUE(base::GetFileSize(test_dir.AppendASCII("title1.html"), | |
| 806 &page1_size)); | |
| 807 | |
| 808 int64 page2_size = 0; | |
| 809 ASSERT_TRUE(base::GetFileSize(test_dir.AppendASCII("title2.html"), | |
| 810 &page2_size)); | |
| 811 | |
| 812 ASSERT_TRUE(test_server()->Start()); | |
| 813 | |
| 814 ui_test_utils::NavigateToURL( | |
| 815 browser(), | |
| 816 test_server()->GetURL(std::string("files/").append("title1.html"))); | |
| 817 | |
| 818 GatherStatistics(); | |
| 819 | |
| 820 Database::MetricVector metrics = GetStats(METRIC_NETWORK_BYTES_READ); | |
| 821 ASSERT_EQ(1u, metrics.size()); | |
| 822 // Since these pages are read over the "network" (actually the test_server), | |
| 823 // some extraneous information is carried along, and the best check we can do | |
| 824 // is for greater than or equal to. | |
| 825 EXPECT_GE(metrics[0].value, page1_size); | |
| 826 | |
| 827 ui_test_utils::NavigateToURL( | |
| 828 browser(), | |
| 829 test_server()->GetURL(std::string("files/").append("title2.html"))); | |
| 830 | |
| 831 GatherStatistics(); | |
| 832 | |
| 833 metrics = GetStats(METRIC_NETWORK_BYTES_READ); | |
| 834 ASSERT_EQ(2u, metrics.size()); | |
| 835 EXPECT_GE(metrics[1].value, page1_size + page2_size); | |
| 836 } | |
| 837 | |
| 838 INSTANTIATE_TEST_CASE_P(PerformanceMonitorUncleanExitBrowserTestInstantiation, | |
| 839 PerformanceMonitorUncleanExitBrowserTest, | |
| 840 testing::Bool()); | |
| 841 | |
| 842 } // namespace performance_monitor | |
| OLD | NEW |