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