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