Home | History | Annotate | Download | only in about_tracing
      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