Chromium Code Reviews| Index: chrome/browser/performance_monitor/performance_monitor_browsertest.cc |
| diff --git a/chrome/browser/performance_monitor/performance_monitor_browsertest.cc b/chrome/browser/performance_monitor/performance_monitor_browsertest.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..9c2b43d4915a4519410a80d4da6d86054265e2e4 |
| --- /dev/null |
| +++ b/chrome/browser/performance_monitor/performance_monitor_browsertest.cc |
| @@ -0,0 +1,280 @@ |
| +// Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "chrome/test/base/in_process_browser_test.h" |
| + |
| +#include "base/file_path.h" |
| +#include "base/logging.h" |
| +#include "base/path_service.h" |
| +#include "base/threading/sequenced_worker_pool.h" |
| +#include "chrome/browser/performance_monitor/database.h" |
| +#include "chrome/browser/performance_monitor/performance_monitor.h" |
| +#include "chrome/browser/extensions/extension_browsertest.h" |
| +#include "chrome/browser/extensions/extension_service.h" |
| +#include "chrome/browser/extensions/unpacked_installer.h" |
| +#include "chrome/browser/profiles/profile.h" |
| +#include "chrome/browser/ui/browser.h" |
| +#include "chrome/common/chrome_notification_types.h" |
| +#include "chrome/common/chrome_paths.h" |
| +#include "chrome/common/extensions/extension.h" |
| +#include "chrome/test/base/ui_test_utils.h" |
| +#include "content/public/browser/notification_registrar.h" |
| +#include "content/public/browser/notification_service.h" |
| + |
| +using extensions::Extension; |
| +using performance_monitor::Event; |
| + |
| +namespace { |
| + |
| +// Helper struct to store the information of an extension; this is needed if the |
| +// pointer to the extension ever becomes invalid (e.g., if we uninstall the |
| +// extension). |
| +struct ExtensionBasicInfo { |
| + // Empty constructor for stl-container-happiness. |
| + ExtensionBasicInfo() { |
| + } |
| + explicit ExtensionBasicInfo(const Extension* extension) |
| + : description(extension->description()), |
| + id(extension->id()), |
| + name(extension->name()), |
| + url(extension->url().spec()), |
| + version(extension->VersionString()), |
| + location(extension->location()) { |
| + } |
| + |
| + std::string description; |
| + std::string id; |
| + std::string name; |
| + std::string url; |
| + std::string version; |
| + Extension::Location location; |
| +}; |
| + |
| +// Compare the fields of |extension| to those in |value|; this is a check to |
| +// make sure the extension data was recorded properly in the event. |
| +void ValidateExtensionInfo(const ExtensionBasicInfo extension, |
| + const DictionaryValue* value) { |
| + std::string extension_description; |
| + std::string extension_id; |
| + std::string extension_name; |
| + std::string extension_url; |
| + std::string extension_version; |
| + int extension_location; |
| + |
| + ASSERT_TRUE(value->GetString("extension_description", |
| + &extension_description)); |
| + ASSERT_EQ(extension.description, extension_description); |
| + ASSERT_TRUE(value->GetString("extension_id", &extension_id)); |
| + ASSERT_EQ(extension.id, extension_id); |
| + ASSERT_TRUE(value->GetString("extension_name", &extension_name)); |
| + ASSERT_EQ(extension.name, extension_name); |
| + ASSERT_TRUE(value->GetString("extension_url", &extension_url)); |
| + ASSERT_EQ(extension.url, extension_url); |
| + ASSERT_TRUE(value->GetString("extension_version", &extension_version)); |
| + ASSERT_EQ(extension.version, extension_version); |
| + ASSERT_TRUE(value->GetInteger("extension_location", &extension_location)); |
| + ASSERT_EQ(extension.location, extension_location); |
| +} |
| + |
| +// Check that we received the proper number of events, that each event is of the |
| +// proper type, and that each event recorded the proper information about the |
| +// extension. |
| +void CheckExtensionEvents(std::vector<int> expected_event_types, |
| + std::vector<ExtensionBasicInfo> extension_infos, |
| + const std::vector<linked_ptr<Event> >& events) { |
| + ASSERT_EQ(expected_event_types.size(), events.size()); |
| + |
| + for (size_t i = 0; i < expected_event_types.size(); ++i) { |
| + const base::DictionaryValue* value; |
| + ASSERT_TRUE(events[i]->data()->GetAsDictionary(&value)); |
|
Yoyo Zhou
2012/06/27 19:59:25
data() is already a DictionaryValue, so you don't
Devlin
2012/06/27 21:04:06
Whoops, forgot we changed this...
Done.
|
| + ValidateExtensionInfo(extension_infos[i], value); |
| + int event_type; |
| + ASSERT_TRUE(value->GetInteger("type", &event_type)); |
| + ASSERT_EQ(expected_event_types[i], event_type); |
| + } |
| +} |
| + |
| +} // namespace |
| + |
| +namespace performance_monitor { |
| + |
| +// The main class to test PerformanceMonitor; since much of the information in |
| +// PerformanceMonitor comes from extensions, we extend ExtensionBrowserTest. |
|
Yoyo Zhou
2012/06/27 19:59:25
nit: This is exactly what ExtensionBrowserTest is
Devlin
2012/06/27 21:04:06
Done.
|
| +class PerformanceMonitorBrowserTest : public ExtensionBrowserTest { |
| + public: |
| + virtual void SetUpOnMainThread() { |
| + CHECK(db_dir_.CreateUniqueTempDir()); |
| + performance_monitor_ = PerformanceMonitor::GetInstance(); |
| + performance_monitor_->SetDatabasePath(db_dir_.path()); |
| + performance_monitor_->Start(); |
| + |
| + // Wait for DB to finish setting up. |
| + content::BrowserThread::GetBlockingPool()->FlushForTesting(); |
| + } |
| + |
| + void GetEventsOnBackgroundThread(std::vector<linked_ptr<Event> >* events) { |
| + *events = performance_monitor_->database()->GetEvents(); |
| + } |
| + |
| + // A handle for getting the events from the database, which must be done on |
| + // the background thread. Since we are testing, and can mock synchronicity |
|
Yoyo Zhou
2012/06/27 19:59:25
nit: s/and/we/
Devlin
2012/06/27 21:04:06
Done.
|
| + // with FlushForTesting(). |
| + std::vector<linked_ptr<Event> > GetEvents() { |
| + std::vector<linked_ptr<Event> > events; |
| + content::BrowserThread::PostBlockingPoolSequencedTask( |
| + Database::kDatabaseSequenceToken, |
| + FROM_HERE, |
| + base::Bind(&PerformanceMonitorBrowserTest::GetEventsOnBackgroundThread, |
| + base::Unretained(this), |
| + &events)); |
| + |
| + content::BrowserThread::GetBlockingPool()->FlushForTesting(); |
| + return events; |
| + } |
| + |
| + PerformanceMonitor* performance_monitor() const { |
| + return performance_monitor_; |
| + } |
| + |
| + protected: |
| + ScopedTempDir db_dir_; |
| + PerformanceMonitor* performance_monitor_; |
|
Yoyo Zhou
2012/06/27 19:59:25
This is leaked. Use a scoped_ptr.
Devlin
2012/06/27 21:04:06
I could be wrong, but my understanding is as follo
Yoyo Zhou
2012/06/27 21:55:51
Whoops, I wasn't reading carefully enough. It shou
|
| +}; |
| + |
| +// Test that PerformanceMonitor will correctly record an extension installation |
| +// event. |
| +IN_PROC_BROWSER_TEST_F(PerformanceMonitorBrowserTest, InstallExtensionEvent) { |
| + FilePath extension_path; |
| + PathService::Get(chrome::DIR_TEST_DATA, &extension_path); |
| + extension_path = extension_path.AppendASCII("performance_monitor") |
| + .AppendASCII("extensions") |
| + .AppendASCII("simple_extension_v1"); |
| + const Extension* extension = LoadExtension(extension_path); |
| + |
| + std::vector<ExtensionBasicInfo> extension_infos; |
| + extension_infos.push_back(ExtensionBasicInfo(extension)); |
| + |
| + std::vector<int> expected_event_types; |
| + expected_event_types.push_back(EVENT_EXTENSION_INSTALL); |
| + |
| + std::vector<linked_ptr<Event> > events = GetEvents(); |
| + CheckExtensionEvents(expected_event_types, extension_infos, events); |
| +} |
| + |
| +// Test that PerformanceMonitor will correctly record events as an extension is |
| +// disabled and enabled. |
| +IN_PROC_BROWSER_TEST_F(PerformanceMonitorBrowserTest, |
| + DisableAndEnableExtensionEvent) { |
| + const int kNumEvents = 3; |
| + |
| + FilePath extension_path; |
| + PathService::Get(chrome::DIR_TEST_DATA, &extension_path); |
| + extension_path = extension_path.AppendASCII("performance_monitor") |
| + .AppendASCII("extensions") |
| + .AppendASCII("simple_extension_v1"); |
| + const Extension* extension = LoadExtension(extension_path); |
| + |
| + DisableExtension(extension->id()); |
| + EnableExtension(extension->id()); |
| + |
| + std::vector<ExtensionBasicInfo> extension_infos; |
| + // There will be three events in all, each pertaining to the same extension: |
| + // Extension Install |
| + // Extension Disable (Unload) |
| + // Extension Enable |
| + for (int i = 0; i < kNumEvents; ++i) |
| + extension_infos.push_back(ExtensionBasicInfo(extension)); |
| + |
| + std::vector<int> expected_event_types; |
| + expected_event_types.push_back(EVENT_EXTENSION_INSTALL); |
| + expected_event_types.push_back(EVENT_EXTENSION_UNLOAD); |
| + expected_event_types.push_back(EVENT_EXTENSION_ENABLE); |
| + |
| + std::vector<linked_ptr<Event> > events = GetEvents(); |
| + CheckExtensionEvents(expected_event_types, extension_infos, events); |
| + |
| + // There will be an additional field on the Disable event: Unload Reason. |
|
Yoyo Zhou
2012/06/27 19:59:25
the Unload event
Devlin
2012/06/27 21:04:06
Done.
|
| + const base::DictionaryValue* value; |
| + int unload_reason = 0; |
| + ASSERT_TRUE(events[1]->data()->GetAsDictionary(&value)); |
|
Yoyo Zhou
2012/06/27 19:59:25
ditto
Devlin
2012/06/27 21:04:06
Done.
|
| + ASSERT_TRUE(value->GetInteger("unload_reason", &unload_reason)); |
| + ASSERT_EQ(extension_misc::UNLOAD_REASON_DISABLE, unload_reason); |
| +} |
| + |
| +// Test that PerformanceMonitor correctly records an extension update event. |
| +IN_PROC_BROWSER_TEST_F(PerformanceMonitorBrowserTest, UpdateExtensionEvent) { |
| + ScopedTempDir temp_dir; |
| + ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); |
| + |
| + FilePath test_data_dir; |
| + PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir); |
| + test_data_dir = test_data_dir.AppendASCII("performance_monitor") |
| + .AppendASCII("extensions"); |
| + |
| + // We need two versions of the same extension. |
| + FilePath pem_path = test_data_dir.AppendASCII("simple_extension.pem"); |
| + FilePath path_v1_ = PackExtensionWithOptions( |
| + test_data_dir.AppendASCII("simple_extension_v1"), |
| + temp_dir.path().AppendASCII("simple_extension1.crx"), |
| + pem_path, |
| + FilePath()); |
| + FilePath path_v2_ = PackExtensionWithOptions( |
| + test_data_dir.AppendASCII("simple_extension_v2"), |
| + temp_dir.path().AppendASCII("simple_extension2.crx"), |
| + pem_path, |
| + FilePath()); |
| + |
| + const extensions::Extension* extension = InstallExtension(path_v1_, 1); |
| + |
| + std::vector<ExtensionBasicInfo> extension_infos; |
|
Yoyo Zhou
2012/06/27 19:59:25
Move this down to where the rest of extension_info
Devlin
2012/06/27 21:04:06
Can't :( InstallExtension returns an Extension*;
|
| + extension_infos.push_back(ExtensionBasicInfo(extension)); |
| + |
| + ExtensionService* extension_service = |
| + browser()->profile()->GetExtensionService(); |
| + |
| + CrxInstaller* crx_installer = NULL; |
| + |
| + ASSERT_TRUE(extension_service-> |
| + UpdateExtension(extension->id(), path_v2_, GURL(), &crx_installer)); |
| + |
| + // Observe implementation in ExtensionBrowserTest; this will exit the loop |
| + // upon receipt of the notification. |
| + content::NotificationRegistrar registrar; |
|
Yoyo Zhou
2012/06/27 19:59:25
You probably want something like WindowedNotificat
Devlin
2012/06/27 21:04:06
Ooooh, fancy. Didn't know about that. Thanks :)
|
| + registrar.Add(this, chrome::NOTIFICATION_CRX_INSTALLER_DONE, |
| + content::Source<CrxInstaller>(crx_installer)); |
| + |
| + ui_test_utils::RunMessageLoop(); |
| + |
| + extension = extension_service->GetExtensionById( |
| + extension_infos[0].id, false); // don't include disabled extensions. |
| + |
| + // The total series of events for this process will be: |
| + // Extension Install - install version 1 |
| + // Extension Install - install version 2 |
| + // Extension Unload - disable version 1 |
| + // Extension Update - signal the udate to version 2 |
| + // We push back the corresponding ExtensionBasicInfos. |
| + extension_infos.push_back(ExtensionBasicInfo(extension)); |
| + extension_infos.push_back(extension_infos[0]); |
| + extension_infos.push_back(extension_infos[1]); |
| + |
| + std::vector<int> expected_event_types; |
| + expected_event_types.push_back(EVENT_EXTENSION_INSTALL); |
| + expected_event_types.push_back(EVENT_EXTENSION_INSTALL); |
| + expected_event_types.push_back(EVENT_EXTENSION_UNLOAD); |
| + expected_event_types.push_back(EVENT_EXTENSION_UPDATE); |
| + |
| + std::vector<linked_ptr<Event> > events = GetEvents(); |
| + |
| + CheckExtensionEvents(expected_event_types, extension_infos, events); |
| + |
| + // There will be an additional field: The unload reason. |
| + const base::DictionaryValue* value; |
| + int unload_reason = 0; |
| + ASSERT_TRUE(events[2]->data()->GetAsDictionary(&value)); |
|
Yoyo Zhou
2012/06/27 19:59:25
ditto
Devlin
2012/06/27 21:04:06
Done.
|
| + ASSERT_TRUE(value->GetInteger("unload_reason", &unload_reason)); |
| + ASSERT_EQ(extension_misc::UNLOAD_REASON_UPDATE, unload_reason); |
| +} |
| + |
| +} // namespace performance_monitor |