OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2010 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 "chrome/test/base/in_process_browser_test.h" | |
6 | |
7 #include "base/file_path.h" | |
8 #include "base/logging.h" | |
9 #include "base/path_service.h" | |
10 #include "base/threading/sequenced_worker_pool.h" | |
11 #include "chrome/browser/performance_monitor/database.h" | |
12 #include "chrome/browser/performance_monitor/performance_monitor.h" | |
13 #include "chrome/browser/extensions/extension_browsertest.h" | |
14 #include "chrome/browser/extensions/extension_service.h" | |
15 #include "chrome/browser/extensions/unpacked_installer.h" | |
16 #include "chrome/browser/profiles/profile.h" | |
17 #include "chrome/browser/ui/browser.h" | |
18 #include "chrome/common/chrome_notification_types.h" | |
19 #include "chrome/common/chrome_paths.h" | |
20 #include "chrome/common/extensions/extension.h" | |
21 #include "chrome/test/base/ui_test_utils.h" | |
22 #include "content/public/browser/notification_registrar.h" | |
23 #include "content/public/browser/notification_service.h" | |
24 | |
25 using extensions::Extension; | |
26 using performance_monitor::Event; | |
27 | |
28 namespace { | |
29 | |
30 // Helper struct to store the information of an extension; this is needed if the | |
31 // pointer to the extension ever becomes invalid (e.g., if we uninstall the | |
32 // extension). | |
33 struct ExtensionBasicInfo { | |
34 // Empty constructor for stl-container-happiness. | |
35 ExtensionBasicInfo() { | |
36 } | |
37 explicit ExtensionBasicInfo(const Extension* extension) | |
38 : description(extension->description()), | |
39 id(extension->id()), | |
40 name(extension->name()), | |
41 url(extension->url().spec()), | |
42 version(extension->VersionString()), | |
43 location(extension->location()) { | |
44 } | |
45 | |
46 std::string description; | |
47 std::string id; | |
48 std::string name; | |
49 std::string url; | |
50 std::string version; | |
51 Extension::Location location; | |
52 }; | |
53 | |
54 // Compare the fields of |extension| to those in |value|; this is a check to | |
55 // make sure the extension data was recorded properly in the event. | |
56 void ValidateExtensionInfo(const ExtensionBasicInfo extension, | |
57 const DictionaryValue* value) { | |
58 std::string extension_description; | |
59 std::string extension_id; | |
60 std::string extension_name; | |
61 std::string extension_url; | |
62 std::string extension_version; | |
63 int extension_location; | |
64 | |
65 ASSERT_TRUE(value->GetString("extension_description", | |
66 &extension_description)); | |
67 ASSERT_EQ(extension.description, extension_description); | |
68 ASSERT_TRUE(value->GetString("extension_id", &extension_id)); | |
69 ASSERT_EQ(extension.id, extension_id); | |
70 ASSERT_TRUE(value->GetString("extension_name", &extension_name)); | |
71 ASSERT_EQ(extension.name, extension_name); | |
72 ASSERT_TRUE(value->GetString("extension_url", &extension_url)); | |
73 ASSERT_EQ(extension.url, extension_url); | |
74 ASSERT_TRUE(value->GetString("extension_version", &extension_version)); | |
75 ASSERT_EQ(extension.version, extension_version); | |
76 ASSERT_TRUE(value->GetInteger("extension_location", &extension_location)); | |
77 ASSERT_EQ(extension.location, extension_location); | |
78 } | |
79 | |
80 // Check that we received the proper number of events, that each event is of the | |
81 // proper type, and that each event recorded the proper information about the | |
82 // extension. | |
83 void CheckExtensionEvents(std::vector<int> expected_event_types, | |
84 std::vector<ExtensionBasicInfo> extension_infos, | |
85 const std::vector<linked_ptr<Event> >& events) { | |
86 ASSERT_EQ(expected_event_types.size(), events.size()); | |
87 | |
88 for (size_t i = 0; i < expected_event_types.size(); ++i) { | |
89 const base::DictionaryValue* value; | |
90 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.
| |
91 ValidateExtensionInfo(extension_infos[i], value); | |
92 int event_type; | |
93 ASSERT_TRUE(value->GetInteger("type", &event_type)); | |
94 ASSERT_EQ(expected_event_types[i], event_type); | |
95 } | |
96 } | |
97 | |
98 } // namespace | |
99 | |
100 namespace performance_monitor { | |
101 | |
102 // The main class to test PerformanceMonitor; since much of the information in | |
103 // 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.
| |
104 class PerformanceMonitorBrowserTest : public ExtensionBrowserTest { | |
105 public: | |
106 virtual void SetUpOnMainThread() { | |
107 CHECK(db_dir_.CreateUniqueTempDir()); | |
108 performance_monitor_ = PerformanceMonitor::GetInstance(); | |
109 performance_monitor_->SetDatabasePath(db_dir_.path()); | |
110 performance_monitor_->Start(); | |
111 | |
112 // Wait for DB to finish setting up. | |
113 content::BrowserThread::GetBlockingPool()->FlushForTesting(); | |
114 } | |
115 | |
116 void GetEventsOnBackgroundThread(std::vector<linked_ptr<Event> >* events) { | |
117 *events = performance_monitor_->database()->GetEvents(); | |
118 } | |
119 | |
120 // A handle for getting the events from the database, which must be done on | |
121 // 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.
| |
122 // with FlushForTesting(). | |
123 std::vector<linked_ptr<Event> > GetEvents() { | |
124 std::vector<linked_ptr<Event> > events; | |
125 content::BrowserThread::PostBlockingPoolSequencedTask( | |
126 Database::kDatabaseSequenceToken, | |
127 FROM_HERE, | |
128 base::Bind(&PerformanceMonitorBrowserTest::GetEventsOnBackgroundThread, | |
129 base::Unretained(this), | |
130 &events)); | |
131 | |
132 content::BrowserThread::GetBlockingPool()->FlushForTesting(); | |
133 return events; | |
134 } | |
135 | |
136 PerformanceMonitor* performance_monitor() const { | |
137 return performance_monitor_; | |
138 } | |
139 | |
140 protected: | |
141 ScopedTempDir db_dir_; | |
142 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
| |
143 }; | |
144 | |
145 // Test that PerformanceMonitor will correctly record an extension installation | |
146 // event. | |
147 IN_PROC_BROWSER_TEST_F(PerformanceMonitorBrowserTest, InstallExtensionEvent) { | |
148 FilePath extension_path; | |
149 PathService::Get(chrome::DIR_TEST_DATA, &extension_path); | |
150 extension_path = extension_path.AppendASCII("performance_monitor") | |
151 .AppendASCII("extensions") | |
152 .AppendASCII("simple_extension_v1"); | |
153 const Extension* extension = LoadExtension(extension_path); | |
154 | |
155 std::vector<ExtensionBasicInfo> extension_infos; | |
156 extension_infos.push_back(ExtensionBasicInfo(extension)); | |
157 | |
158 std::vector<int> expected_event_types; | |
159 expected_event_types.push_back(EVENT_EXTENSION_INSTALL); | |
160 | |
161 std::vector<linked_ptr<Event> > events = GetEvents(); | |
162 CheckExtensionEvents(expected_event_types, extension_infos, events); | |
163 } | |
164 | |
165 // Test that PerformanceMonitor will correctly record events as an extension is | |
166 // disabled and enabled. | |
167 IN_PROC_BROWSER_TEST_F(PerformanceMonitorBrowserTest, | |
168 DisableAndEnableExtensionEvent) { | |
169 const int kNumEvents = 3; | |
170 | |
171 FilePath extension_path; | |
172 PathService::Get(chrome::DIR_TEST_DATA, &extension_path); | |
173 extension_path = extension_path.AppendASCII("performance_monitor") | |
174 .AppendASCII("extensions") | |
175 .AppendASCII("simple_extension_v1"); | |
176 const Extension* extension = LoadExtension(extension_path); | |
177 | |
178 DisableExtension(extension->id()); | |
179 EnableExtension(extension->id()); | |
180 | |
181 std::vector<ExtensionBasicInfo> extension_infos; | |
182 // There will be three events in all, each pertaining to the same extension: | |
183 // Extension Install | |
184 // Extension Disable (Unload) | |
185 // Extension Enable | |
186 for (int i = 0; i < kNumEvents; ++i) | |
187 extension_infos.push_back(ExtensionBasicInfo(extension)); | |
188 | |
189 std::vector<int> expected_event_types; | |
190 expected_event_types.push_back(EVENT_EXTENSION_INSTALL); | |
191 expected_event_types.push_back(EVENT_EXTENSION_UNLOAD); | |
192 expected_event_types.push_back(EVENT_EXTENSION_ENABLE); | |
193 | |
194 std::vector<linked_ptr<Event> > events = GetEvents(); | |
195 CheckExtensionEvents(expected_event_types, extension_infos, events); | |
196 | |
197 // 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.
| |
198 const base::DictionaryValue* value; | |
199 int unload_reason = 0; | |
200 ASSERT_TRUE(events[1]->data()->GetAsDictionary(&value)); | |
Yoyo Zhou
2012/06/27 19:59:25
ditto
Devlin
2012/06/27 21:04:06
Done.
| |
201 ASSERT_TRUE(value->GetInteger("unload_reason", &unload_reason)); | |
202 ASSERT_EQ(extension_misc::UNLOAD_REASON_DISABLE, unload_reason); | |
203 } | |
204 | |
205 // Test that PerformanceMonitor correctly records an extension update event. | |
206 IN_PROC_BROWSER_TEST_F(PerformanceMonitorBrowserTest, UpdateExtensionEvent) { | |
207 ScopedTempDir temp_dir; | |
208 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); | |
209 | |
210 FilePath test_data_dir; | |
211 PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir); | |
212 test_data_dir = test_data_dir.AppendASCII("performance_monitor") | |
213 .AppendASCII("extensions"); | |
214 | |
215 // We need two versions of the same extension. | |
216 FilePath pem_path = test_data_dir.AppendASCII("simple_extension.pem"); | |
217 FilePath path_v1_ = PackExtensionWithOptions( | |
218 test_data_dir.AppendASCII("simple_extension_v1"), | |
219 temp_dir.path().AppendASCII("simple_extension1.crx"), | |
220 pem_path, | |
221 FilePath()); | |
222 FilePath path_v2_ = PackExtensionWithOptions( | |
223 test_data_dir.AppendASCII("simple_extension_v2"), | |
224 temp_dir.path().AppendASCII("simple_extension2.crx"), | |
225 pem_path, | |
226 FilePath()); | |
227 | |
228 const extensions::Extension* extension = InstallExtension(path_v1_, 1); | |
229 | |
230 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*;
| |
231 extension_infos.push_back(ExtensionBasicInfo(extension)); | |
232 | |
233 ExtensionService* extension_service = | |
234 browser()->profile()->GetExtensionService(); | |
235 | |
236 CrxInstaller* crx_installer = NULL; | |
237 | |
238 ASSERT_TRUE(extension_service-> | |
239 UpdateExtension(extension->id(), path_v2_, GURL(), &crx_installer)); | |
240 | |
241 // Observe implementation in ExtensionBrowserTest; this will exit the loop | |
242 // upon receipt of the notification. | |
243 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 :)
| |
244 registrar.Add(this, chrome::NOTIFICATION_CRX_INSTALLER_DONE, | |
245 content::Source<CrxInstaller>(crx_installer)); | |
246 | |
247 ui_test_utils::RunMessageLoop(); | |
248 | |
249 extension = extension_service->GetExtensionById( | |
250 extension_infos[0].id, false); // don't include disabled extensions. | |
251 | |
252 // The total series of events for this process will be: | |
253 // Extension Install - install version 1 | |
254 // Extension Install - install version 2 | |
255 // Extension Unload - disable version 1 | |
256 // Extension Update - signal the udate to version 2 | |
257 // We push back the corresponding ExtensionBasicInfos. | |
258 extension_infos.push_back(ExtensionBasicInfo(extension)); | |
259 extension_infos.push_back(extension_infos[0]); | |
260 extension_infos.push_back(extension_infos[1]); | |
261 | |
262 std::vector<int> expected_event_types; | |
263 expected_event_types.push_back(EVENT_EXTENSION_INSTALL); | |
264 expected_event_types.push_back(EVENT_EXTENSION_INSTALL); | |
265 expected_event_types.push_back(EVENT_EXTENSION_UNLOAD); | |
266 expected_event_types.push_back(EVENT_EXTENSION_UPDATE); | |
267 | |
268 std::vector<linked_ptr<Event> > events = GetEvents(); | |
269 | |
270 CheckExtensionEvents(expected_event_types, extension_infos, events); | |
271 | |
272 // There will be an additional field: The unload reason. | |
273 const base::DictionaryValue* value; | |
274 int unload_reason = 0; | |
275 ASSERT_TRUE(events[2]->data()->GetAsDictionary(&value)); | |
Yoyo Zhou
2012/06/27 19:59:25
ditto
Devlin
2012/06/27 21:04:06
Done.
| |
276 ASSERT_TRUE(value->GetInteger("unload_reason", &unload_reason)); | |
277 ASSERT_EQ(extension_misc::UNLOAD_REASON_UPDATE, unload_reason); | |
278 } | |
279 | |
280 } // namespace performance_monitor | |
OLD | NEW |