1 // Copyright (c) 2013 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 'use strict'; 6 7 base.require('base.events'); 8 base.require('about_tracing.profiling_view'); 9 base.require('about_tracing.tracing_controller'); 10 base.require('ui.dom_helpers'); 11 12 base.unittest.testSuite('about_tracing.profiling_view', function() { 13 var testDataString = JSON.stringify([ 14 {name: 'a', args: {}, pid: 52, ts: 15000, cat: 'foo', tid: 53, ph: 'B'}, 15 {name: 'a', args: {}, pid: 52, ts: 19000, cat: 'foo', tid: 53, ph: 'E'}, 16 {name: 'b', args: {}, pid: 52, ts: 32000, cat: 'foo', tid: 53, ph: 'B'}, 17 {name: 'b', args: {}, pid: 52, ts: 54000, cat: 'foo', tid: 53, ph: 'E'} 18 ]); 19 20 var systemTraceTestData = [ 21 'systrace.sh-8170 [000] 0.013: sched_switch: ' + 22 'prev_comm=systrace.sh prev_pid=8170 prev_prio=120 ' + 23 'prev_state=x ==> next_comm=kworker/1:0 next_pid=7873 ' + 24 'next_prio=120', 25 ' kworker/1:0-7873 [000] 0.036: sched_switch: ' + 26 'prev_comm=kworker/1:0 prev_pid=7873 prev_prio=120 ' + 27 'prev_state=S ==> next_comm=debugd next_pid=4404 ' + 28 'next_prio=120', 29 ' debugd-4404 [000] 0.070: sched_switch: prev_comm=debugd ' + 30 'prev_pid=4404 prev_prio=120 prev_state=S ==> ' + 31 'next_comm=dbus-daemon next_pid=510 next_prio=120', 32 'systrace.sh-8182 [000] 0.000: tracing_mark_write: ' + 33 'trace_event_clock_sync: parent_ts=0.0' 34 ].join('\n'); 35 36 // This code emulates Chrome's responses to sendFn enough that the real 37 // tracing controller can be used to interactively test the UI. 38 var createSendHandler = function() { 39 var systemTraceRequested = false; 40 var corruptTrace; 41 var tracingController; 42 function send(message, opt_args) { 43 var args = opt_args || []; 44 if (message == 'getKnownCategories') { 45 setTimeout(function() { 46 tracingController.onKnownCategoriesCollected(['a', 'b', 'c']); 47 }, 1); 48 49 } else if (message == 'beginTracing') { 50 systemTraceRequested = opt_args[0]; 51 continuousTraceRequested = opt_args[1]; 52 samplingRequested = opt_args[2]; 53 54 } else if (message == 'beginRequestBufferPercentFull') { 55 setTimeout(function() { 56 tracingController.onRequestBufferPercentFullComplete(0.5); 57 }, 1); 58 59 } else if (message == 'endTracingAsync') { 60 setTimeout(function() { 61 if (systemTraceRequested) { 62 tracingController.onSystemTraceDataCollected(systemTraceTestData); 63 } 64 65 // Strip off [] and add a , 66 var n = testDataString.length - 1; 67 var tmp = testDataString.substr(1, n - 1) + ','; 68 if (corruptTrace) 69 tmp += 'corruption'; 70 tracingController.onEndTracingComplete(tmp); 71 }, 1); 72 73 } else if (message == 'loadTraceFile') { 74 setTimeout(function() { 75 var tmp = testDataString.substr(0); 76 if (corruptTrace) 77 tmp += 'corruption'; 78 tracingController.onLoadTraceFileComplete(tmp); 79 }, 150); 80 81 } else if (message == 'saveTraceFile') { 82 setTimeout(function() { 83 tracingController.onSaveTraceFileComplete(); 84 }, 1); 85 } 86 } 87 88 send.__defineSetter__('tracingController', function(c) { 89 tracingController = c; 90 }); 91 92 send.__defineSetter__('corruptTrace', function(c) { 93 corruptTrace = c; 94 }); 95 return send; 96 }; 97 98 /* 99 * Just enough of the TracingController to support the tests below. 100 */ 101 var FakeTracingController = function() { 102 this.wasBeginTracingCalled = false; 103 this.wasCollectCategoriesCalled = false; 104 this.wasSamplingEnabled = false; 105 }; 106 107 FakeTracingController.prototype = { 108 __proto__: base.EventTarget.prototype, 109 110 get supportsSystemTracing() { 111 return base.isChromeOS; 112 }, 113 114 beginTracing: function(opt_systemTracingEnabled, 115 opt_continuousTracingEnabled, 116 opt_enableSampling, 117 opt_traceCategories) { 118 this.wasBeginTracingCalled = true; 119 this.wasBeginTracingCalledWithSystemTracingEnabled = 120 opt_systemTracingEnabled; 121 this.wasBeginTracingCalledWithContinuousTracingEnabled = 122 opt_continuousTracingEnabled; 123 this.beginTracingCategories = opt_traceCategories; 124 this.wasSamplingEnabled = opt_enableSampling; 125 }, 126 127 collectCategories: function() { 128 this.wasCollectCategoriesCalled = true; 129 }, 130 131 get traceEventData() { 132 if (!this.wasBeginTracingCalled) 133 return undefined; 134 return testDataString; 135 }, 136 137 get systemTraceEvents() { 138 if (!this.wasBeginTracingCalled) 139 return []; 140 if (!this.wasBeginTracingCalledWithSystemTracingEnabled) 141 return []; 142 return systemTraceTestData; 143 }, 144 145 set tracingEnabled(val) { 146 this.isTracingEnabled_ = val; 147 }, 148 149 get isTracingEnabled() { 150 if (this.isTracingEnabled_ === undefined) 151 this.isTracingEnabled_ = false; 152 return this.isTracingEnabled_; 153 } 154 }; 155 156 var recordTestCommon = function() { 157 var view = new about_tracing.ProfilingView(); 158 159 var tracingController = new FakeTracingController(); 160 view.tracingController = tracingController; 161 162 view.querySelector('button.record').click(); 163 assertTrue(tracingController.wasCollectCategoriesCalled); 164 165 var e = new base.Event('categoriesCollected'); 166 e.categories = ['skia', 'gpu']; 167 tracingController.dispatchEvent(e); 168 169 view.recordSelectionDialog_.querySelector( 170 'button.record-categories').click(); 171 172 assertTrue(tracingController.wasBeginTracingCalled); 173 assertEquals(base.isChromeOS, 174 tracingController.wasBeginTracingCalledWithSystemTracingEnabled); 175 176 var e = new base.Event('traceEnded'); 177 e.events = tracingController.traceEventData; 178 tracingController.dispatchEvent(e); 179 180 assertTrue(!!view.timelineView.model); 181 view.detach_(); 182 }; 183 184 test('instantiate', function() { 185 var parent = document.createElement('div'); 186 this.addHTMLOutput(parent); 187 188 var view = new about_tracing.ProfilingView(); 189 parent.appendChild(view); 190 191 var sendHandler = createSendHandler(); 192 var tracingController = new about_tracing.TracingController(sendHandler); 193 sendHandler.tracingController = tracingController; 194 tracingController.supportsSystemTracing_ = true; 195 196 view.tracingController = tracingController; 197 view.focusElement = view; 198 parent.appendChild(ui.createCheckBox(sendHandler, 'corruptTrace', 199 'profilingViewTest.corruptTrace', 200 false, 'Make traces corrupt')); 201 view.detach_(); 202 }); 203 204 test('selectedCategoriesSentToTracing', function() { 205 var view = new about_tracing.ProfilingView(); 206 view.timelineView_.settings.set('cc', true, 'record_categories'); 207 view.timelineView_.settings.set('renderer', false, 'record_categories'); 208 209 var tracingController = new FakeTracingController(this); 210 view.tracingController = tracingController; 211 212 view.querySelector('button.record').click(); 213 assertTrue(tracingController.wasCollectCategoriesCalled); 214 215 var e = new base.Event('categoriesCollected'); 216 e.categories = ['skia', 'gpu', 'cc', 'renderer']; 217 tracingController.dispatchEvent(e); 218 219 assertVisible(view.recordSelectionDialog_); 220 assertVisible(view.recordSelectionDialog_.toolbar); 221 222 view.recordSelectionDialog_.querySelector('input#skia').click(); 223 view.recordSelectionDialog_.querySelector( 224 'button.record-categories').click(); 225 226 var categories = tracingController.beginTracingCategories; 227 // Renderer is disabled in settings, skia is clicked off. 228 assertEquals('-renderer,-skia', categories); 229 230 view.detach_(); 231 }); 232 233 test('badCategories', function() { 234 var view = new about_tracing.ProfilingView(); 235 view.timelineView_.settings.set('foo,bar', false, 'record_categories'); 236 237 var tracingController = new FakeTracingController(this); 238 view.tracingController = tracingController; 239 240 view.querySelector('button.record').click(); 241 assertTrue(tracingController.wasCollectCategoriesCalled); 242 243 var e = new base.Event('categoriesCollected'); 244 e.categories = ['baz,zap', 'gpu']; 245 tracingController.dispatchEvent(e); 246 247 view.recordSelectionDialog_.querySelector( 248 'button.record-categories').click(); 249 250 var inputs = view.recordSelectionDialog_.querySelectorAll('input'); 251 var inputs_length = inputs.length; 252 for (var i = 0; i < inputs_length; ++i) { 253 // Comes from categories and should be split before getting 254 // to the record selection dialog. 255 assertNotEquals('baz,zap', inputs[i].id); 256 } 257 var categories = tracingController.beginTracingCategories; 258 assertEquals('', categories); 259 260 view.detach_(); 261 }); 262 263 test('recordNonCros', function() { 264 var old = base.isChromeOS; 265 base.isChromeOS = false; 266 try { 267 recordTestCommon(); 268 } finally { 269 base.isChromeOS = old; 270 } 271 }); 272 273 test('recordCros', function() { 274 var old = base.isChromeOS; 275 base.isChromeOS = true; 276 try { 277 recordTestCommon(); 278 } finally { 279 base.isChromeOS = old; 280 } 281 }); 282 283 test('recordWithTraceRunning_KeyEvent', function() { 284 var view = new about_tracing.ProfilingView(); 285 var tracingController = new FakeTracingController(); 286 tracingController.tracingEnabled = true; 287 view.tracingController = tracingController; 288 289 var evt = document.createEvent('Event'); 290 evt.initEvent('keypress', 291 true, // canBubbleArg 292 true, // cancelableArg 293 window); // viewArg 294 evt.keyCode = 'r'.charCodeAt(0); 295 296 document.dispatchEvent(evt); 297 assertFalse(tracingController.wasCollectCategoriesCalled); 298 299 view.detach_(); 300 }); 301 302 test('categorySelectionWithTraceRunning_KeyEvent', function() { 303 var view = new about_tracing.ProfilingView(); 304 var tracingController = new FakeTracingController(); 305 view.tracingController = tracingController; 306 view.selectingCategories = true; 307 308 var evt = document.createEvent('Event'); 309 evt.initEvent('keypress', 310 true, // canBubbleArg 311 true, // cancelableArg 312 window); // viewArg 313 evt.keyCode = 'r'.charCodeAt(0); 314 315 document.dispatchEvent(evt); 316 assertFalse(tracingController.wasCollectCategoriesCalled); 317 318 view.detach_(); 319 }); 320 321 test('categorySelectionSetsSelectingCategories', function() { 322 var view = new about_tracing.ProfilingView(); 323 var tracingController = new FakeTracingController(); 324 view.tracingController = tracingController; 325 view.selectingCategories = false; 326 327 view.querySelector('button.record').click(); 328 assertTrue(view.selectingCategories); 329 330 var e = new base.Event('categoriesCollected'); 331 e.categories = ['skia', 'gpu', 'cc', 'renderer']; 332 tracingController.dispatchEvent(e); 333 334 view.recordSelectionDialog_.querySelector( 335 'button.record-categories').click(); 336 337 assertFalse(view.selectingCategories); 338 view.detach_(); 339 }); 340 341 test('categorySelectionResetsSelectingCategoriesOnDialogDismiss', function() { 342 var view = new about_tracing.ProfilingView(); 343 var tracingController = new FakeTracingController(); 344 view.tracingController = tracingController; 345 view.selectingCategories = false; 346 347 view.querySelector('button.record').click(); 348 assertTrue(view.selectingCategories); 349 350 var e = new base.Event('categoriesCollected'); 351 e.categories = ['skia', 'gpu', 'cc', 'renderer']; 352 tracingController.dispatchEvent(e); 353 354 view.recordSelectionDialog_.visible = false; 355 356 assertFalse(view.selectingCategories); 357 view.detach_(); 358 }); 359 360 test('recording_withSamplingEnabled', function() { 361 var view = new about_tracing.ProfilingView(); 362 363 var tracingController = new FakeTracingController(); 364 view.tracingController = tracingController; 365 view.querySelector('button.record').click(); 366 367 var e = new base.Event('categoriesCollected'); 368 e.categories = []; 369 tracingController.dispatchEvent(e); 370 371 view.recordSelectionDialog_.querySelector('.sampling-button').click(); 372 view.recordSelectionDialog_.querySelector( 373 'button.record-categories').click(); 374 375 assertTrue(tracingController.wasBeginTracingCalled); 376 assertTrue(tracingController.wasSamplingEnabled); 377 }); 378 379 test('recording_withSamplingDisabled', function() { 380 var view = new about_tracing.ProfilingView(); 381 382 var tracingController = new FakeTracingController(); 383 view.tracingController = tracingController; 384 view.querySelector('button.record').click(); 385 386 var e = new base.Event('categoriesCollected'); 387 e.categories = []; 388 tracingController.dispatchEvent(e); 389 390 view.recordSelectionDialog_.querySelector( 391 'button.record-categories').click(); 392 393 assertTrue(tracingController.wasBeginTracingCalled); 394 assertFalse(tracingController.wasSamplingEnabled); 395 }); 396 }); 397