// Copyright (c) 2013 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.
'use strict';
base.require('base.events');
base.require('about_tracing.profiling_view');
base.require('about_tracing.tracing_controller');
base.require('ui.dom_helpers');
base.unittest.testSuite('about_tracing.profiling_view', function() {
var testDataString = JSON.stringify([
{name: 'a', args: {}, pid: 52, ts: 15000, cat: 'foo', tid: 53, ph: 'B'},
{name: 'a', args: {}, pid: 52, ts: 19000, cat: 'foo', tid: 53, ph: 'E'},
{name: 'b', args: {}, pid: 52, ts: 32000, cat: 'foo', tid: 53, ph: 'B'},
{name: 'b', args: {}, pid: 52, ts: 54000, cat: 'foo', tid: 53, ph: 'E'}
]);
var systemTraceTestData = [
'systrace.sh-8170 [000] 0.013: sched_switch: ' +
'prev_comm=systrace.sh prev_pid=8170 prev_prio=120 ' +
'prev_state=x ==> next_comm=kworker/1:0 next_pid=7873 ' +
'next_prio=120',
' kworker/1:0-7873 [000] 0.036: sched_switch: ' +
'prev_comm=kworker/1:0 prev_pid=7873 prev_prio=120 ' +
'prev_state=S ==> next_comm=debugd next_pid=4404 ' +
'next_prio=120',
' debugd-4404 [000] 0.070: sched_switch: prev_comm=debugd ' +
'prev_pid=4404 prev_prio=120 prev_state=S ==> ' +
'next_comm=dbus-daemon next_pid=510 next_prio=120',
'systrace.sh-8182 [000] 0.000: tracing_mark_write: ' +
'trace_event_clock_sync: parent_ts=0.0'
].join('\n');
// This code emulates Chrome's responses to sendFn enough that the real
// tracing controller can be used to interactively test the UI.
var createSendHandler = function() {
var systemTraceRequested = false;
var corruptTrace;
var tracingController;
function send(message, opt_args) {
var args = opt_args || [];
if (message == 'getKnownCategories') {
setTimeout(function() {
tracingController.onKnownCategoriesCollected(['a', 'b', 'c']);
}, 1);
} else if (message == 'beginTracing') {
systemTraceRequested = opt_args[0];
continuousTraceRequested = opt_args[1];
samplingRequested = opt_args[2];
} else if (message == 'beginRequestBufferPercentFull') {
setTimeout(function() {
tracingController.onRequestBufferPercentFullComplete(0.5);
}, 1);
} else if (message == 'endTracingAsync') {
setTimeout(function() {
if (systemTraceRequested) {
tracingController.onSystemTraceDataCollected(systemTraceTestData);
}
// Strip off [] and add a ,
var n = testDataString.length - 1;
var tmp = testDataString.substr(1, n - 1) + ',';
if (corruptTrace)
tmp += 'corruption';
tracingController.onEndTracingComplete(tmp);
}, 1);
} else if (message == 'loadTraceFile') {
setTimeout(function() {
var tmp = testDataString.substr(0);
if (corruptTrace)
tmp += 'corruption';
tracingController.onLoadTraceFileComplete(tmp);
}, 150);
} else if (message == 'saveTraceFile') {
setTimeout(function() {
tracingController.onSaveTraceFileComplete();
}, 1);
}
}
send.__defineSetter__('tracingController', function(c) {
tracingController = c;
});
send.__defineSetter__('corruptTrace', function(c) {
corruptTrace = c;
});
return send;
};
/*
* Just enough of the TracingController to support the tests below.
*/
var FakeTracingController = function() {
this.wasBeginTracingCalled = false;
this.wasCollectCategoriesCalled = false;
this.wasSamplingEnabled = false;
};
FakeTracingController.prototype = {
__proto__: base.EventTarget.prototype,
get supportsSystemTracing() {
return base.isChromeOS;
},
beginTracing: function(opt_systemTracingEnabled,
opt_continuousTracingEnabled,
opt_enableSampling,
opt_traceCategories) {
this.wasBeginTracingCalled = true;
this.wasBeginTracingCalledWithSystemTracingEnabled =
opt_systemTracingEnabled;
this.wasBeginTracingCalledWithContinuousTracingEnabled =
opt_continuousTracingEnabled;
this.beginTracingCategories = opt_traceCategories;
this.wasSamplingEnabled = opt_enableSampling;
},
collectCategories: function() {
this.wasCollectCategoriesCalled = true;
},
get traceEventData() {
if (!this.wasBeginTracingCalled)
return undefined;
return testDataString;
},
get systemTraceEvents() {
if (!this.wasBeginTracingCalled)
return [];
if (!this.wasBeginTracingCalledWithSystemTracingEnabled)
return [];
return systemTraceTestData;
},
set tracingEnabled(val) {
this.isTracingEnabled_ = val;
},
get isTracingEnabled() {
if (this.isTracingEnabled_ === undefined)
this.isTracingEnabled_ = false;
return this.isTracingEnabled_;
}
};
var recordTestCommon = function() {
var view = new about_tracing.ProfilingView();
var tracingController = new FakeTracingController();
view.tracingController = tracingController;
view.querySelector('button.record').click();
assertTrue(tracingController.wasCollectCategoriesCalled);
var e = new base.Event('categoriesCollected');
e.categories = ['skia', 'gpu'];
tracingController.dispatchEvent(e);
view.recordSelectionDialog_.querySelector(
'button.record-categories').click();
assertTrue(tracingController.wasBeginTracingCalled);
assertEquals(base.isChromeOS,
tracingController.wasBeginTracingCalledWithSystemTracingEnabled);
var e = new base.Event('traceEnded');
e.events = tracingController.traceEventData;
tracingController.dispatchEvent(e);
assertTrue(!!view.timelineView.model);
view.detach_();
};
test('instantiate', function() {
var parent = document.createElement('div');
this.addHTMLOutput(parent);
var view = new about_tracing.ProfilingView();
parent.appendChild(view);
var sendHandler = createSendHandler();
var tracingController = new about_tracing.TracingController(sendHandler);
sendHandler.tracingController = tracingController;
tracingController.supportsSystemTracing_ = true;
view.tracingController = tracingController;
view.focusElement = view;
parent.appendChild(ui.createCheckBox(sendHandler, 'corruptTrace',
'profilingViewTest.corruptTrace',
false, 'Make traces corrupt'));
view.detach_();
});
test('selectedCategoriesSentToTracing', function() {
var view = new about_tracing.ProfilingView();
view.timelineView_.settings.set('cc', true, 'record_categories');
view.timelineView_.settings.set('renderer', false, 'record_categories');
var tracingController = new FakeTracingController(this);
view.tracingController = tracingController;
view.querySelector('button.record').click();
assertTrue(tracingController.wasCollectCategoriesCalled);
var e = new base.Event('categoriesCollected');
e.categories = ['skia', 'gpu', 'cc', 'renderer'];
tracingController.dispatchEvent(e);
assertVisible(view.recordSelectionDialog_);
assertVisible(view.recordSelectionDialog_.toolbar);
view.recordSelectionDialog_.querySelector('input#skia').click();
view.recordSelectionDialog_.querySelector(
'button.record-categories').click();
var categories = tracingController.beginTracingCategories;
// Renderer is disabled in settings, skia is clicked off.
assertEquals('-renderer,-skia', categories);
view.detach_();
});
test('badCategories', function() {
var view = new about_tracing.ProfilingView();
view.timelineView_.settings.set('foo,bar', false, 'record_categories');
var tracingController = new FakeTracingController(this);
view.tracingController = tracingController;
view.querySelector('button.record').click();
assertTrue(tracingController.wasCollectCategoriesCalled);
var e = new base.Event('categoriesCollected');
e.categories = ['baz,zap', 'gpu'];
tracingController.dispatchEvent(e);
view.recordSelectionDialog_.querySelector(
'button.record-categories').click();
var inputs = view.recordSelectionDialog_.querySelectorAll('input');
var inputs_length = inputs.length;
for (var i = 0; i < inputs_length; ++i) {
// Comes from categories and should be split before getting
// to the record selection dialog.
assertNotEquals('baz,zap', inputs[i].id);
}
var categories = tracingController.beginTracingCategories;
assertEquals('', categories);
view.detach_();
});
test('recordNonCros', function() {
var old = base.isChromeOS;
base.isChromeOS = false;
try {
recordTestCommon();
} finally {
base.isChromeOS = old;
}
});
test('recordCros', function() {
var old = base.isChromeOS;
base.isChromeOS = true;
try {
recordTestCommon();
} finally {
base.isChromeOS = old;
}
});
test('recordWithTraceRunning_KeyEvent', function() {
var view = new about_tracing.ProfilingView();
var tracingController = new FakeTracingController();
tracingController.tracingEnabled = true;
view.tracingController = tracingController;
var evt = document.createEvent('Event');
evt.initEvent('keypress',
true, // canBubbleArg
true, // cancelableArg
window); // viewArg
evt.keyCode = 'r'.charCodeAt(0);
document.dispatchEvent(evt);
assertFalse(tracingController.wasCollectCategoriesCalled);
view.detach_();
});
test('categorySelectionWithTraceRunning_KeyEvent', function() {
var view = new about_tracing.ProfilingView();
var tracingController = new FakeTracingController();
view.tracingController = tracingController;
view.selectingCategories = true;
var evt = document.createEvent('Event');
evt.initEvent('keypress',
true, // canBubbleArg
true, // cancelableArg
window); // viewArg
evt.keyCode = 'r'.charCodeAt(0);
document.dispatchEvent(evt);
assertFalse(tracingController.wasCollectCategoriesCalled);
view.detach_();
});
test('categorySelectionSetsSelectingCategories', function() {
var view = new about_tracing.ProfilingView();
var tracingController = new FakeTracingController();
view.tracingController = tracingController;
view.selectingCategories = false;
view.querySelector('button.record').click();
assertTrue(view.selectingCategories);
var e = new base.Event('categoriesCollected');
e.categories = ['skia', 'gpu', 'cc', 'renderer'];
tracingController.dispatchEvent(e);
view.recordSelectionDialog_.querySelector(
'button.record-categories').click();
assertFalse(view.selectingCategories);
view.detach_();
});
test('categorySelectionResetsSelectingCategoriesOnDialogDismiss', function() {
var view = new about_tracing.ProfilingView();
var tracingController = new FakeTracingController();
view.tracingController = tracingController;
view.selectingCategories = false;
view.querySelector('button.record').click();
assertTrue(view.selectingCategories);
var e = new base.Event('categoriesCollected');
e.categories = ['skia', 'gpu', 'cc', 'renderer'];
tracingController.dispatchEvent(e);
view.recordSelectionDialog_.visible = false;
assertFalse(view.selectingCategories);
view.detach_();
});
test('recording_withSamplingEnabled', function() {
var view = new about_tracing.ProfilingView();
var tracingController = new FakeTracingController();
view.tracingController = tracingController;
view.querySelector('button.record').click();
var e = new base.Event('categoriesCollected');
e.categories = [];
tracingController.dispatchEvent(e);
view.recordSelectionDialog_.querySelector('.sampling-button').click();
view.recordSelectionDialog_.querySelector(
'button.record-categories').click();
assertTrue(tracingController.wasBeginTracingCalled);
assertTrue(tracingController.wasSamplingEnabled);
});
test('recording_withSamplingDisabled', function() {
var view = new about_tracing.ProfilingView();
var tracingController = new FakeTracingController();
view.tracingController = tracingController;
view.querySelector('button.record').click();
var e = new base.Event('categoriesCollected');
e.categories = [];
tracingController.dispatchEvent(e);
view.recordSelectionDialog_.querySelector(
'button.record-categories').click();
assertTrue(tracingController.wasBeginTracingCalled);
assertFalse(tracingController.wasSamplingEnabled);
});
});