fix(benchpress): make code compile and unit tests green again

This commit is contained in:
Tobias Bosch 2016-08-26 16:34:08 -07:00
parent db280fc67e
commit 1ef122988e
71 changed files with 704 additions and 998 deletions

View File

@ -41,6 +41,7 @@ module.exports = function(config) {
'dist/all/@angular/**/e2e_test/**', 'dist/all/@angular/**/e2e_test/**',
'dist/all/@angular/router/**', 'dist/all/@angular/router/**',
'dist/all/@angular/compiler-cli/**', 'dist/all/@angular/compiler-cli/**',
'dist/all/@angular/benchpress/**',
'dist/all/angular1_router.js', 'dist/all/angular1_router.js',
'dist/all/@angular/platform-browser/testing/e2e_util.js' 'dist/all/@angular/platform-browser/testing/e2e_util.js'
], ],

View File

@ -1,6 +0,0 @@
Benchpress - a framework for e2e performance tests
=========
The sources for this package are in the main [Angular2](https://github.com/angular/angular) repo. Please file issues and pull requests against that repo.
License: Apache MIT 2.0

View File

@ -1,8 +0,0 @@
Benchpress - a framework for e2e performance tests
=========
The sources for this package are in the main [Angular2](https://github.com/angular/angular) repo. Please file issues and pull requests against that repo.
See [this project](https://github.com/angular/benchpress-tree) for an example.
License: Apache MIT 2.0

View File

@ -3,6 +3,10 @@
Benchpress is a framework for e2e performance tests. Benchpress is a framework for e2e performance tests.
See [here for an example project](https://github.com/angular/benchpress-tree). See [here for an example project](https://github.com/angular/benchpress-tree).
The sources for this package are in the main [Angular2](https://github.com/angular/angular) repo. Please file issues and pull requests against that repo.
License: Apache MIT 2.0
# Why? # Why?
There are so called "micro benchmarks" that essentially use a stop watch in the browser to measure time There are so called "micro benchmarks" that essentially use a stop watch in the browser to measure time
@ -158,7 +162,7 @@ runner.sample({
```` ````
When looking into the DevTools Timeline, we see a marker as well: When looking into the DevTools Timeline, we see a marker as well:
![Marked Timeline](marked_timeline.png) ![Marked Timeline](docs/marked_timeline.png)
### Custom Metrics Without Using `console.time` ### Custom Metrics Without Using `console.time`
@ -185,8 +189,8 @@ describe('home page load', function() {
userMetrics: { userMetrics: {
timeToBootstrap: 'The time in milliseconds to bootstrap' timeToBootstrap: 'The time in milliseconds to bootstrap'
}, },
bindings: [ providers: [
bind(RegressionSlopeValidator.METRIC).toValue('timeToBootstrap') {provide: RegressionSlopeValidator.METRIC, useValue: 'timeToBootstrap'}
] ]
}).then(done); }).then(done);
}); });
@ -208,9 +212,9 @@ Benchpress can also measure the "smoothness" of scrolling and animations. In ord
To collect these metrics, you need to execute `console.time('frameCapture')` and `console.timeEnd('frameCapture')` either in your benchmark application or in you benchmark driver via webdriver. The metrics mentioned above will only be collected between those two calls and it is recommended to wrap the time/timeEnd calls as closely as possible around the action you want to evaluate to get accurate measurements. To collect these metrics, you need to execute `console.time('frameCapture')` and `console.timeEnd('frameCapture')` either in your benchmark application or in you benchmark driver via webdriver. The metrics mentioned above will only be collected between those two calls and it is recommended to wrap the time/timeEnd calls as closely as possible around the action you want to evaluate to get accurate measurements.
In addition to that, one extra binding needs to be passed to benchpress in tests that want to collect these metrics: In addition to that, one extra provider needs to be passed to benchpress in tests that want to collect these metrics:
benchpress.sample(providers: [bp.bind(bp.Options.CAPTURE_FRAMES).toValue(true)], ... ) benchpress.sample(providers: [{provide: bp.Options.CAPTURE_FRAMES, useValue: true}], ... )
# Requests Metrics # Requests Metrics
@ -222,8 +226,8 @@ Benchpress can also record the number of requests sent and count the received "e
To collect these metrics, you need the following corresponding extra providers: To collect these metrics, you need the following corresponding extra providers:
benchpress.sample(providers: [ benchpress.sample(providers: [
bp.bind(bp.Options.RECEIVED_DATA).toValue(true), {provide: bp.Options.RECEIVED_DATA, useValue: true},
bp.bind(bp.Options.REQUEST_COUNT).toValue(true) {provide: bp.Options.REQUEST_COUNT, useValue: true}
], ... ) ], ... )
# Best practices # Best practices
@ -256,7 +260,7 @@ To collect these metrics, you need the following corresponding extra providers:
# Detailed overview # Detailed overview
![Overview](overview.png) ![Overview](docs/overview.png)
Definitions: Definitions:

View File

@ -1,3 +0,0 @@
export './common.dart';
export './src/webdriver/async_webdriver_adapter.dart'
show AsyncWebDriverAdapter;

View File

@ -1,33 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Options} from './common';
export * from './common';
export {SeleniumWebDriverAdapter} from './src/webdriver/selenium_webdriver_adapter';
var fs = require('fs');
// TODO(tbosch): right now we bind the `writeFile` method
// in benchpres/benchpress.es6. This does not work for Dart,
// find another way...
// Note: Can't do the `require` call in a facade as it can't be loaded into the browser
// for our unit tests via karma.
Options.DEFAULT_PROVIDERS.push({provide: Options.WRITE_FILE, useValue: writeFile});
function writeFile(filename, content): Promise<any> {
return new Promise(function(resolve, reject) {
fs.writeFile(filename, content, (error) => {
if (error) {
reject(error);
} else {
resolve();
}
});
});
}

View File

@ -1,30 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
export {Injector, OpaqueToken, ReflectiveInjector} from '@angular/core/src/di';
export {Options} from './src/common_options';
export {MeasureValues} from './src/measure_values';
export {Metric} from './src/metric';
export {MultiMetric} from './src/metric/multi_metric';
export {PerflogMetric} from './src/metric/perflog_metric';
export {UserMetric} from './src/metric/user_metric';
export {Reporter} from './src/reporter';
export {ConsoleReporter} from './src/reporter/console_reporter';
export {JsonFileReporter} from './src/reporter/json_file_reporter';
export {MultiReporter} from './src/reporter/multi_reporter';
export {Runner} from './src/runner';
export {SampleDescription} from './src/sample_description';
export {SampleState, Sampler} from './src/sampler';
export {Validator} from './src/validator';
export {RegressionSlopeValidator} from './src/validator/regression_slope_validator';
export {SizeValidator} from './src/validator/size_validator';
export {WebDriverAdapter} from './src/web_driver_adapter';
export {PerfLogFeatures, WebDriverExtension} from './src/web_driver_extension';
export {ChromeDriverExtension} from './src/webdriver/chrome_driver_extension';
export {FirefoxDriverExtension} from './src/webdriver/firefox_driver_extension';
export {IOsDriverExtension} from './src/webdriver/ios_driver_extension';

View File

@ -1,3 +0,0 @@
library benchpress.index;
//no dart implementation

View File

@ -6,9 +6,29 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
require('reflect-metadata'); // Must be imported first, because angular2 decorators throws on load.
require('core-js'); import 'reflect-metadata';
module.exports = require('./benchpress.js');
// when bundling benchpress to one file, this is used export {Injector, OpaqueToken, Provider, ReflectiveInjector} from '@angular/core';
// for getting exports out of browserify's scope. export {Options} from './src/common_options';
(<any>global).__benchpressExports = module.exports; export {MeasureValues} from './src/measure_values';
export {Metric} from './src/metric';
export {MultiMetric} from './src/metric/multi_metric';
export {PerflogMetric} from './src/metric/perflog_metric';
export {UserMetric} from './src/metric/user_metric';
export {Reporter} from './src/reporter';
export {ConsoleReporter} from './src/reporter/console_reporter';
export {JsonFileReporter} from './src/reporter/json_file_reporter';
export {MultiReporter} from './src/reporter/multi_reporter';
export {Runner} from './src/runner';
export {SampleDescription} from './src/sample_description';
export {SampleState, Sampler} from './src/sampler';
export {Validator} from './src/validator';
export {RegressionSlopeValidator} from './src/validator/regression_slope_validator';
export {SizeValidator} from './src/validator/size_validator';
export {WebDriverAdapter} from './src/web_driver_adapter';
export {PerfLogEvent, PerfLogFeatures, WebDriverExtension} from './src/web_driver_extension';
export {ChromeDriverExtension} from './src/webdriver/chrome_driver_extension';
export {FirefoxDriverExtension} from './src/webdriver/firefox_driver_extension';
export {IOsDriverExtension} from './src/webdriver/ios_driver_extension';
export {SeleniumWebDriverAdapter} from './src/webdriver/selenium_webdriver_adapter';

View File

@ -1,23 +1,33 @@
{ {
"name": "benchpress", "name": "@angular/benchpress",
"version": "<%= packageJson.version %>", "version": "0.0.0-PLACEHOLDER",
"description": "Benchpress - a framework for e2e performance tests", "description": "Benchpress - a framework for e2e performance tests",
"homepage": "<%= packageJson.homepage %>", "main": "index.js",
"bugs": "<%= packageJson.bugs %>", "typings": "index.d.ts",
"main" : "./index.js",
"contributors": <%= JSON.stringify(packageJson.contributors) %>,
"license": "<%= packageJson.license %>",
"repository": <%= JSON.stringify(packageJson.repository) %>,
"dependencies": { "dependencies": {
"angular2": "<%= packageJson.version %>", "@angular/core": "0.0.0-PLACEHOLDER",
"core-js": "<%= packageJson.dependencies['core-js'] %>", "reflect-metadata": "^0.1.2",
"reflect-metadata": "<%= packageJson.dependencies['reflect-metadata'] %>", "rxjs": "5.0.0-beta.11"
"rxjs": "<%= packageJson.dependencies['rxjs'] %>",
"selenium-webdriver": "<%= packageJson.dependencies['selenium-webdriver'] %>",
"zone.js": "<%= packageJson.dependencies['zone.js'] %>"
}, },
"optionalDependencies": { "optionalDependencies": {
"jpm": "<%= packageJson.devDependencies.jpm %>", "jpm": "1.1.4",
"firefox-profile": "<%= packageJson.devDependencies['firefox-profile'] %>" "firefox-profile": "0.4.0",
} "selenium-webdriver": "3.0.0-beta-2"
},
"repository": {
"type": "git",
"url": "https://github.com/angular/angular.git"
},
"keywords": [
"angular",
"benchmarks"
],
"contributors": [
"Tobias Bosch <tbosch@google.com> (https://angular.io/)"
],
"license": "MIT",
"bugs": {
"url": "https://github.com/angular/angular/issues"
},
"homepage": "https://github.com/angular/angular/tree/master/modules/@angular/compiler-cli"
} }

View File

@ -1,22 +0,0 @@
name: benchpress
version: <%= packageJson.version %>
authors:
<%= Object.keys(packageJson.contributors).map(function(name) {
return '- '+name+' <'+packageJson.contributors[name]+'>';
}).join('\n') %>
description: Benchpress - a framework for e2e performance tests
homepage: <%= packageJson.homepage %>
environment:
sdk: '>=1.10.0 <2.0.0'
dependencies:
angular2: '^<%= packageJson.version %>'
stack_trace: '^1.1.1'
webdriver: '^0.9.0'
dev_dependencies:
guinness2: '0.0.4'
quiver: '^0.21.4'
test: '^0.12.10'
dependency_overrides:
angular2:
path: ../angular2
matcher: '0.12.0+1'

View File

@ -6,63 +6,50 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {OpaqueToken} from '@angular/core/src/di'; import {OpaqueToken} from '@angular/core';
import {DateWrapper} from '@angular/facade/src/lang'; import * as fs from 'fs';
import {DateWrapper} from './facade/lang';
export class Options { export class Options {
static get DEFAULT_PROVIDERS(): any[] { return _DEFAULT_PROVIDERS; } static SAMPLE_ID = new OpaqueToken('Options.sampleId');
// TODO(tbosch): use static initializer when our transpiler supports it static DEFAULT_DESCRIPTION = new OpaqueToken('Options.defaultDescription');
static get SAMPLE_ID() { return _SAMPLE_ID; } static SAMPLE_DESCRIPTION = new OpaqueToken('Options.sampleDescription');
// TODO(tbosch): use static initializer when our transpiler supports it static FORCE_GC = new OpaqueToken('Options.forceGc');
static get DEFAULT_DESCRIPTION() { return _DEFAULT_DESCRIPTION; } static NO_PREPARE = () => true;
// TODO(tbosch): use static initializer when our transpiler supports it static PREPARE = new OpaqueToken('Options.prepare');
static get SAMPLE_DESCRIPTION() { return _SAMPLE_DESCRIPTION; } static EXECUTE = new OpaqueToken('Options.execute');
// TODO(tbosch): use static initializer when our transpiler supports it static CAPABILITIES = new OpaqueToken('Options.capabilities');
static get FORCE_GC() { return _FORCE_GC; } static USER_AGENT = new OpaqueToken('Options.userAgent');
// TODO(tbosch): use static initializer when our transpiler supports it static MICRO_METRICS = new OpaqueToken('Options.microMetrics');
static get PREPARE() { return _PREPARE; } static USER_METRICS = new OpaqueToken('Options.userMetrics');
// TODO(tbosch): use static initializer when our transpiler supports it static NOW = new OpaqueToken('Options.now');
static get EXECUTE() { return _EXECUTE; } static WRITE_FILE = new OpaqueToken('Options.writeFile');
// TODO(tbosch): use static initializer when our transpiler supports it static RECEIVED_DATA = new OpaqueToken('Options.receivedData');
static get CAPABILITIES() { return _CAPABILITIES; } static REQUEST_COUNT = new OpaqueToken('Options.requestCount');
// TODO(tbosch): use static initializer when our transpiler supports it static CAPTURE_FRAMES = new OpaqueToken('Options.frameCapture');
static get USER_AGENT() { return _USER_AGENT; } static DEFAULT_PROVIDERS = [
// TODO(tbosch): use static initializer when our transpiler supports it {provide: Options.DEFAULT_DESCRIPTION, useValue: {}},
static get NOW() { return _NOW; } {provide: Options.SAMPLE_DESCRIPTION, useValue: {}},
// TODO(tbosch): use static values when our transpiler supports them {provide: Options.FORCE_GC, useValue: false},
static get WRITE_FILE() { return _WRITE_FILE; } {provide: Options.PREPARE, useValue: Options.NO_PREPARE},
// TODO(tbosch): use static values when our transpiler supports them {provide: Options.MICRO_METRICS, useValue: {}}, {provide: Options.USER_METRICS, useValue: {}},
static get MICRO_METRICS() { return _MICRO_METRICS; } {provide: Options.NOW, useValue: () => DateWrapper.now()},
// TODO(tbosch): use static values when our transpiler supports them {provide: Options.RECEIVED_DATA, useValue: false},
static get USER_METRICS() { return _USER_METRICS; } {provide: Options.REQUEST_COUNT, useValue: false},
// TODO(tbosch): use static values when our transpiler supports them {provide: Options.CAPTURE_FRAMES, useValue: false},
static get RECEIVED_DATA() { return _RECEIVED_DATA; } {provide: Options.WRITE_FILE, useValue: writeFile}
// TODO(tbosch): use static values when our transpiler supports them ];
static get REQUEST_COUNT() { return _REQUEST_COUNT; }
// TODO(tbosch): use static values when our transpiler supports them
static get CAPTURE_FRAMES() { return _CAPTURE_FRAMES; }
} }
var _SAMPLE_ID = new OpaqueToken('Options.sampleId'); function writeFile(filename: string, content: string): Promise<any> {
var _DEFAULT_DESCRIPTION = new OpaqueToken('Options.defaultDescription'); return new Promise(function(resolve, reject) {
var _SAMPLE_DESCRIPTION = new OpaqueToken('Options.sampleDescription'); fs.writeFile(filename, content, (error) => {
var _FORCE_GC = new OpaqueToken('Options.forceGc'); if (error) {
var _PREPARE = new OpaqueToken('Options.prepare'); reject(error);
var _EXECUTE = new OpaqueToken('Options.execute'); } else {
var _CAPABILITIES = new OpaqueToken('Options.capabilities'); resolve();
var _USER_AGENT = new OpaqueToken('Options.userAgent'); }
var _MICRO_METRICS = new OpaqueToken('Options.microMetrics'); });
var _USER_METRICS = new OpaqueToken('Options.userMetrics'); });
var _NOW = new OpaqueToken('Options.now'); }
var _WRITE_FILE = new OpaqueToken('Options.writeFile');
var _RECEIVED_DATA = new OpaqueToken('Options.receivedData');
var _REQUEST_COUNT = new OpaqueToken('Options.requestCount');
var _CAPTURE_FRAMES = new OpaqueToken('Options.frameCapture');
var _DEFAULT_PROVIDERS = [
{provide: _DEFAULT_DESCRIPTION, useValue: {}}, {provide: _SAMPLE_DESCRIPTION, useValue: {}},
{provide: _FORCE_GC, useValue: false}, {provide: _PREPARE, useValue: false},
{provide: _MICRO_METRICS, useValue: {}}, {provide: _USER_METRICS, useValue: {}},
{provide: _NOW, useValue: () => DateWrapper.now()}, {provide: _RECEIVED_DATA, useValue: false},
{provide: _REQUEST_COUNT, useValue: false}, {provide: _CAPTURE_FRAMES, useValue: false}
];

View File

@ -0,0 +1 @@
../../facade/src

View File

@ -6,8 +6,8 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
declare var exportFunction; declare var exportFunction: any;
declare var unsafeWindow; declare var unsafeWindow: any;
exportFunction(function() { exportFunction(function() {
var curTime = unsafeWindow.performance.now(); var curTime = unsafeWindow.performance.now();
@ -18,7 +18,7 @@ exportFunction(function() {
(<any>self).port.emit('stopProfiler'); (<any>self).port.emit('stopProfiler');
}, unsafeWindow, {defineAs: 'stopProfiler'}); }, unsafeWindow, {defineAs: 'stopProfiler'});
exportFunction(function(cb) { exportFunction(function(cb: Function) {
(<any>self).port.once('perfProfile', cb); (<any>self).port.once('perfProfile', cb);
(<any>self).port.emit('getProfile'); (<any>self).port.emit('getProfile');
}, unsafeWindow, {defineAs: 'getProfile'}); }, unsafeWindow, {defineAs: 'getProfile'});
@ -27,12 +27,12 @@ exportFunction(function() {
(<any>self).port.emit('forceGC'); (<any>self).port.emit('forceGC');
}, unsafeWindow, {defineAs: 'forceGC'}); }, unsafeWindow, {defineAs: 'forceGC'});
exportFunction(function(name) { exportFunction(function(name: string) {
var curTime = unsafeWindow.performance.now(); var curTime = unsafeWindow.performance.now();
(<any>self).port.emit('markStart', name, curTime); (<any>self).port.emit('markStart', name, curTime);
}, unsafeWindow, {defineAs: 'markStart'}); }, unsafeWindow, {defineAs: 'markStart'});
exportFunction(function(name) { exportFunction(function(name: string) {
var curTime = unsafeWindow.performance.now(); var curTime = unsafeWindow.performance.now();
(<any>self).port.emit('markEnd', name, curTime); (<any>self).port.emit('markEnd', name, curTime);
}, unsafeWindow, {defineAs: 'markEnd'}); }, unsafeWindow, {defineAs: 'markEnd'});

View File

@ -1,3 +0,0 @@
library benchpress.src.firefox_extension.lib.main;
//no dart implementation

View File

@ -11,13 +11,13 @@ var os = Cc['@mozilla.org/observer-service;1'].getService(Ci.nsIObserverService)
var ParserUtil = require('./parser_util'); var ParserUtil = require('./parser_util');
class Profiler { class Profiler {
private _profiler; private _profiler: any;
private _markerEvents: any[]; private _markerEvents: any[];
private _profilerStartTime: number; private _profilerStartTime: number;
constructor() { this._profiler = Cc['@mozilla.org/tools/profiler;1'].getService(Ci.nsIProfiler); } constructor() { this._profiler = Cc['@mozilla.org/tools/profiler;1'].getService(Ci.nsIProfiler); }
start(entries, interval, features, timeStarted) { start(entries: any, interval: any, features: any, timeStarted: any) {
this._profiler.StartProfiler(entries, interval, features, features.length); this._profiler.StartProfiler(entries, interval, features, features.length);
this._profilerStartTime = timeStarted; this._profilerStartTime = timeStarted;
this._markerEvents = []; this._markerEvents = [];
@ -29,7 +29,9 @@ class Profiler {
var profileData = this._profiler.getProfileData(); var profileData = this._profiler.getProfileData();
var perfEvents = ParserUtil.convertPerfProfileToEvents(profileData); var perfEvents = ParserUtil.convertPerfProfileToEvents(profileData);
perfEvents = this._mergeMarkerEvents(perfEvents); perfEvents = this._mergeMarkerEvents(perfEvents);
perfEvents.sort(function(event1, event2) { return event1.ts - event2.ts; }); // Sort by ts perfEvents.sort(function(event1: any, event2: any) {
return event1.ts - event2.ts;
}); // Sort by ts
return perfEvents; return perfEvents;
} }
@ -59,16 +61,18 @@ var profiler = new Profiler();
mod.PageMod({ mod.PageMod({
include: ['*'], include: ['*'],
contentScriptFile: data.url('installed_script.js'), contentScriptFile: data.url('installed_script.js'),
onAttach: worker => { onAttach: (worker: any) => {
worker.port.on( worker.port.on(
'startProfiler', 'startProfiler',
(timeStarted) => profiler.start( (timeStarted: any) => profiler.start(
/* = profiler memory */ 3000000, 0.1, ['leaf', 'js', 'stackwalk', 'gc'], timeStarted)); /* = profiler memory */ 3000000, 0.1, ['leaf', 'js', 'stackwalk', 'gc'], timeStarted));
worker.port.on('stopProfiler', () => profiler.stop()); worker.port.on('stopProfiler', () => profiler.stop());
worker.port.on( worker.port.on(
'getProfile', () => worker.port.emit('perfProfile', profiler.getProfilePerfEvents())); 'getProfile', () => worker.port.emit('perfProfile', profiler.getProfilePerfEvents()));
worker.port.on('forceGC', forceGC); worker.port.on('forceGC', forceGC);
worker.port.on('markStart', (name, timeStarted) => profiler.addStartEvent(name, timeStarted)); worker.port.on(
worker.port.on('markEnd', (name, timeEnded) => profiler.addEndEvent(name, timeEnded)); 'markStart', (name: string, timeStarted: any) => profiler.addStartEvent(name, timeStarted));
worker.port.on(
'markEnd', (name: string, timeEnded: any) => profiler.addEndEvent(name, timeEnded));
} }
}); });

View File

@ -1,3 +0,0 @@
library benchpress.src.firefox_extension.lib.parser_util;
//no dart implementation

View File

@ -13,10 +13,10 @@
*/ */
export function convertPerfProfileToEvents(perfProfile: any): any[] { export function convertPerfProfileToEvents(perfProfile: any): any[] {
var inProgressEvents = new Map(); // map from event name to start time var inProgressEvents = new Map(); // map from event name to start time
var finishedEvents = []; // Event[] finished events var finishedEvents: {[key: string]: any}[] = []; // Event[] finished events
var addFinishedEvent = function(eventName, startTime, endTime) { var addFinishedEvent = function(eventName: string, startTime: number, endTime: number) {
var categorizedEventName = categorizeEvent(eventName); var categorizedEventName = categorizeEvent(eventName);
var args = undefined; var args: {[key: string]: any} = undefined;
if (categorizedEventName == 'gc') { if (categorizedEventName == 'gc') {
// TODO: We cannot measure heap size at the moment // TODO: We cannot measure heap size at the moment
args = {usedHeapSize: 0}; args = {usedHeapSize: 0};
@ -42,7 +42,9 @@ export function convertPerfProfileToEvents(perfProfile: any): any[] {
// Add all the frames into a set so it's easier/faster to find the set // Add all the frames into a set so it's easier/faster to find the set
// differences // differences
var sampleFrames = new Set(); var sampleFrames = new Set();
sample.frames.forEach(function(frame) { sampleFrames.add(frame.location); }); sample.frames.forEach(function(frame: {[key: string]: any}) {
sampleFrames.add(frame['location']);
});
// If an event is in the inProgressEvents map, but not in the current sample, // If an event is in the inProgressEvents map, but not in the current sample,
// then it must have just finished. We add this event to the finishedEvents // then it must have just finished. We add this event to the finishedEvents
@ -73,7 +75,7 @@ export function convertPerfProfileToEvents(perfProfile: any): any[] {
}); });
// Remove all the unknown categories. // Remove all the unknown categories.
return finishedEvents.filter(function(event) { return event.name != 'unknown'; }); return finishedEvents.filter(function(event) { return event['name'] != 'unknown'; });
} }
// TODO: this is most likely not exhaustive. // TODO: this is most likely not exhaustive.

View File

@ -1,3 +0,0 @@
library benchpress.src.firefox_extension.lib.test_helper;
//no dart implementation

View File

@ -13,7 +13,7 @@ var pathUtil = require('path');
var PERF_ADDON_PACKAGE_JSON_DIR = '..'; var PERF_ADDON_PACKAGE_JSON_DIR = '..';
exports.getAbsolutePath = function(path) { exports.getAbsolutePath = function(path: string) {
var normalizedPath = pathUtil.normalize(path); var normalizedPath = pathUtil.normalize(path);
if (pathUtil.resolve(normalizedPath) == normalizedPath) { if (pathUtil.resolve(normalizedPath) == normalizedPath) {
// Already absolute path // Already absolute path
@ -23,12 +23,12 @@ exports.getAbsolutePath = function(path) {
} }
}; };
exports.getFirefoxProfile = function(extensionPath) { exports.getFirefoxProfile = function(extensionPath: string) {
var deferred = q.defer(); var deferred = q.defer();
var firefoxProfile = new FirefoxProfile(); var firefoxProfile = new FirefoxProfile();
firefoxProfile.addExtensions([extensionPath], () => { firefoxProfile.addExtensions([extensionPath], () => {
firefoxProfile.encoded(encodedProfile => { firefoxProfile.encoded((encodedProfile: any) => {
var multiCapabilities = [{browserName: 'firefox', firefox_profile: encodedProfile}]; var multiCapabilities = [{browserName: 'firefox', firefox_profile: encodedProfile}];
deferred.resolve(multiCapabilities); deferred.resolve(multiCapabilities);
}); });
@ -44,7 +44,7 @@ exports.getFirefoxProfileWithExtension = function() {
var savedCwd = process.cwd(); var savedCwd = process.cwd();
process.chdir(absPackageJsonDir); process.chdir(absPackageJsonDir);
return jpm(packageJson).then(xpiPath => { return jpm(packageJson).then((xpiPath: string) => {
process.chdir(savedCwd); process.chdir(savedCwd);
return exports.getFirefoxProfile(xpiPath); return exports.getFirefoxProfile(xpiPath);
}); });

View File

@ -6,8 +6,8 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {Map} from '@angular/facade/src/collection'; import {Map} from './facade/collection';
import {Date, DateWrapper} from '@angular/facade/src/lang'; import {Date, DateWrapper} from './facade/lang';
export class MeasureValues { export class MeasureValues {
constructor( constructor(

View File

@ -11,10 +11,6 @@
* A metric is measures values * A metric is measures values
*/ */
export abstract class Metric { export abstract class Metric {
static bindTo(delegateToken): any[] {
return [{provide: Metric, useFactory: (delegate) => delegate, deps: [delegateToken]}];
}
/** /**
* Starts measuring * Starts measuring
*/ */
@ -31,5 +27,5 @@ export abstract class Metric {
* Describes the metrics provided by this metric implementation. * Describes the metrics provided by this metric implementation.
* (e.g. units, ...) * (e.g. units, ...)
*/ */
describe(): {[key: string]: any} { throw new Error('NYI'); } describe(): {[key: string]: string} { throw new Error('NYI'); }
} }

View File

@ -6,20 +6,24 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {Injector, OpaqueToken} from '@angular/core/src/di'; import {Injector, OpaqueToken} from '@angular/core';
import {StringMapWrapper} from '@angular/facade/src/collection'; import {StringMapWrapper} from '../facade/collection';
import {Metric} from '../metric'; import {Metric} from '../metric';
export class MultiMetric extends Metric { export class MultiMetric extends Metric {
static createBindings(childTokens: any[]): any[] { static provideWith(childTokens: any[]): any[] {
return [ return [
{ {
provide: _CHILDREN, provide: _CHILDREN,
useFactory: (injector: Injector) => childTokens.map(token => injector.get(token)), useFactory: (injector: Injector) => childTokens.map(token => injector.get(token)),
deps: [Injector] deps: [Injector]
}, },
{provide: MultiMetric, useFactory: children => new MultiMetric(children), deps: [_CHILDREN]} {
provide: MultiMetric,
useFactory: (children: Metric[]) => new MultiMetric(children),
deps: [_CHILDREN]
}
]; ];
} }
@ -52,7 +56,7 @@ export class MultiMetric extends Metric {
} }
function mergeStringMaps(maps: {[key: string]: string}[]): {[key: string]: string} { function mergeStringMaps(maps: {[key: string]: string}[]): {[key: string]: string} {
var result = {}; var result: {[key: string]: string} = {};
maps.forEach( maps.forEach(
map => { StringMapWrapper.forEach(map, (value, prop) => { result[prop] = value; }); }); map => { StringMapWrapper.forEach(map, (value, prop) => { result[prop] = value; }); });
return result; return result;

View File

@ -6,52 +6,45 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {OpaqueToken} from '@angular/core/src/di'; import {Inject, Injectable, OpaqueToken} from '@angular/core';
import {ListWrapper, StringMapWrapper} from '@angular/facade/src/collection';
import {Math, NumberWrapper, StringWrapper, isBlank, isPresent} from '@angular/facade/src/lang';
import {Options} from '../common_options'; import {Options} from '../common_options';
import {ListWrapper, StringMapWrapper} from '../facade/collection';
import {Math, NumberWrapper, StringWrapper, isBlank, isPresent} from '../facade/lang';
import {Metric} from '../metric'; import {Metric} from '../metric';
import {PerfLogFeatures, WebDriverExtension} from '../web_driver_extension'; import {PerfLogEvent, PerfLogFeatures, WebDriverExtension} from '../web_driver_extension';
/** /**
* A metric that reads out the performance log * A metric that reads out the performance log
*/ */
@Injectable()
export class PerflogMetric extends Metric { export class PerflogMetric extends Metric {
// TODO(tbosch): use static values when our transpiler supports them static SET_TIMEOUT = new OpaqueToken('PerflogMetric.setTimeout');
static get PROVIDERS(): any[] { return _PROVIDERS; } static PROVIDERS = [
// TODO(tbosch): use static values when our transpiler supports them PerflogMetric, {
static get SET_TIMEOUT(): OpaqueToken { return _SET_TIMEOUT; } provide: PerflogMetric.SET_TIMEOUT,
useValue: (fn: Function, millis: number) => <any>setTimeout(fn, millis)
}
];
/** @internal */ private _remainingEvents: PerfLogEvent[];
private _remainingEvents: Array<{[key: string]: any}>;
/** @internal */
private _measureCount: number; private _measureCount: number;
/** @internal */
private _perfLogFeatures: PerfLogFeatures; private _perfLogFeatures: PerfLogFeatures;
/** /**
* @param driverExtension * @param driverExtension
* @param setTimeout * @param setTimeout
* @param microMetrics Name and description of metrics provided via console.time / console.timeEnd * @param microMetrics Name and description of metrics provided via console.time / console.timeEnd
**/ **/
constructor( constructor(
/** @internal */
private _driverExtension: WebDriverExtension, private _driverExtension: WebDriverExtension,
/** @internal */ @Inject(PerflogMetric.SET_TIMEOUT) private _setTimeout: Function,
private _setTimeout: Function, @Inject(Options.MICRO_METRICS) private _microMetrics: {[key: string]: string},
/** @internal */ @Inject(Options.FORCE_GC) private _forceGc: boolean,
private _microMetrics: {[key: string]: any}, @Inject(Options.CAPTURE_FRAMES) private _captureFrames: boolean,
/** @internal */ @Inject(Options.RECEIVED_DATA) private _receivedData: boolean,
private _forceGc: boolean, @Inject(Options.REQUEST_COUNT) private _requestCount: boolean) {
/** @internal */
private _captureFrames: boolean,
/** @internal */
private _receivedData: boolean,
/** @internal */
private _requestCount: boolean) {
super(); super();
this._remainingEvents = []; this._remainingEvents = [];
@ -64,8 +57,8 @@ export class PerflogMetric extends Metric {
} }
} }
describe(): {[key: string]: any} { describe(): {[key: string]: string} {
var res = { var res: {[key: string]: any} = {
'scriptTime': 'script execution time in ms, including gc and render', 'scriptTime': 'script execution time in ms, including gc and render',
'pureScriptTime': 'script execution time in ms, without gc nor render' 'pureScriptTime': 'script execution time in ms, without gc nor render'
}; };
@ -115,7 +108,7 @@ export class PerflogMetric extends Metric {
return resultPromise.then((_) => this._beginMeasure()); return resultPromise.then((_) => this._beginMeasure());
} }
endMeasure(restart: boolean): Promise<{[key: string]: any}> { endMeasure(restart: boolean): Promise<{[key: string]: number}> {
if (this._forceGc) { if (this._forceGc) {
return this._endPlainMeasureAndMeasureForceGc(restart); return this._endPlainMeasureAndMeasureForceGc(restart);
} else { } else {
@ -140,21 +133,19 @@ export class PerflogMetric extends Metric {
}); });
} }
/** @internal */
private _beginMeasure(): Promise<any> { private _beginMeasure(): Promise<any> {
return this._driverExtension.timeBegin(this._markName(this._measureCount++)); return this._driverExtension.timeBegin(this._markName(this._measureCount++));
} }
/** @internal */ private _endMeasure(restart: boolean): Promise<{[key: string]: number}> {
private _endMeasure(restart: boolean): Promise<{[key: string]: any}> {
var markName = this._markName(this._measureCount - 1); var markName = this._markName(this._measureCount - 1);
var nextMarkName = restart ? this._markName(this._measureCount++) : null; var nextMarkName = restart ? this._markName(this._measureCount++) : null;
return this._driverExtension.timeEnd(markName, nextMarkName) return this._driverExtension.timeEnd(markName, nextMarkName)
.then((_) => this._readUntilEndMark(markName)); .then((_) => this._readUntilEndMark(markName));
} }
/** @internal */ private _readUntilEndMark(
private _readUntilEndMark(markName: string, loopCount: number = 0, startEvent = null) { markName: string, loopCount: number = 0, startEvent: PerfLogEvent = null) {
if (loopCount > _MAX_RETRY_COUNT) { if (loopCount > _MAX_RETRY_COUNT) {
throw new Error(`Tried too often to get the ending mark: ${loopCount}`); throw new Error(`Tried too often to get the ending mark: ${loopCount}`);
} }
@ -172,17 +163,16 @@ export class PerflogMetric extends Metric {
}); });
} }
/** @internal */ private _addEvents(events: PerfLogEvent[]) {
private _addEvents(events: {[key: string]: string}[]) {
var needSort = false; var needSort = false;
events.forEach(event => { events.forEach(event => {
if (StringWrapper.equals(event['ph'], 'X')) { if (StringWrapper.equals(event['ph'], 'X')) {
needSort = true; needSort = true;
var startEvent = {}; var startEvent: PerfLogEvent = {};
var endEvent = {}; var endEvent: PerfLogEvent = {};
StringMapWrapper.forEach(event, (value, prop) => { StringMapWrapper.forEach(event, (value, prop) => {
startEvent[prop] = value; (<any>startEvent)[prop] = value;
endEvent[prop] = value; (<any>endEvent)[prop] = value;
}); });
startEvent['ph'] = 'B'; startEvent['ph'] = 'B';
endEvent['ph'] = 'E'; endEvent['ph'] = 'E';
@ -202,9 +192,8 @@ export class PerflogMetric extends Metric {
} }
} }
/** @internal */ private _aggregateEvents(events: PerfLogEvent[], markName: string): {[key: string]: number} {
private _aggregateEvents(events: Array<{[key: string]: any}>, markName): {[key: string]: any} { var result: {[key: string]: number} = {'scriptTime': 0, 'pureScriptTime': 0};
var result = {'scriptTime': 0, 'pureScriptTime': 0};
if (this._perfLogFeatures.gc) { if (this._perfLogFeatures.gc) {
result['gcTime'] = 0; result['gcTime'] = 0;
result['majorGcTime'] = 0; result['majorGcTime'] = 0;
@ -227,17 +216,17 @@ export class PerflogMetric extends Metric {
result['requestCount'] = 0; result['requestCount'] = 0;
} }
var markStartEvent = null; var markStartEvent: PerfLogEvent = null;
var markEndEvent = null; var markEndEvent: PerfLogEvent = null;
var gcTimeInScript = 0; var gcTimeInScript = 0;
var renderTimeInScript = 0; var renderTimeInScript = 0;
var frameTimestamps = []; var frameTimestamps: number[] = [];
var frameTimes = []; var frameTimes: number[] = [];
var frameCaptureStartEvent = null; var frameCaptureStartEvent: PerfLogEvent = null;
var frameCaptureEndEvent = null; var frameCaptureEndEvent: PerfLogEvent = null;
var intervalStarts: {[key: string]: any} = {}; var intervalStarts: {[key: string]: PerfLogEvent} = {};
var intervalStartCount: {[key: string]: number} = {}; var intervalStartCount: {[key: string]: number} = {};
events.forEach((event) => { events.forEach((event) => {
var ph = event['ph']; var ph = event['ph'];
@ -337,7 +326,7 @@ export class PerflogMetric extends Metric {
} else if (StringWrapper.equals(name, 'script')) { } else if (StringWrapper.equals(name, 'script')) {
result['scriptTime'] += duration; result['scriptTime'] += duration;
} else if (isPresent(this._microMetrics[name])) { } else if (isPresent(this._microMetrics[name])) {
result[name] += duration / microIterations; (<any>result)[name] += duration / microIterations;
} }
} }
} }
@ -362,8 +351,7 @@ export class PerflogMetric extends Metric {
return result; return result;
} }
/** @internal */ private _addFrameMetrics(result: {[key: string]: number}, frameTimes: any[]) {
private _addFrameMetrics(result: {[key: string]: any}, frameTimes: any[]) {
result['frameTime.mean'] = frameTimes.reduce((a, b) => a + b, 0) / frameTimes.length; result['frameTime.mean'] = frameTimes.reduce((a, b) => a + b, 0) / frameTimes.length;
var firstFrame = frameTimes[0]; var firstFrame = frameTimes[0];
result['frameTime.worst'] = frameTimes.reduce((a, b) => a > b ? a : b, firstFrame); result['frameTime.worst'] = frameTimes.reduce((a, b) => a > b ? a : b, firstFrame);
@ -372,32 +360,14 @@ export class PerflogMetric extends Metric {
frameTimes.filter(t => t < _FRAME_TIME_SMOOTH_THRESHOLD).length / frameTimes.length; frameTimes.filter(t => t < _FRAME_TIME_SMOOTH_THRESHOLD).length / frameTimes.length;
} }
/** @internal */ private _markName(index: number) { return `${_MARK_NAME_PREFIX}${index}`; }
private _markName(index) { return `${_MARK_NAME_PREFIX}${index}`; }
} }
var _MICRO_ITERATIONS_REGEX = /(.+)\*(\d+)$/; var _MICRO_ITERATIONS_REGEX = /(.+)\*(\d+)$/;
var _MAX_RETRY_COUNT = 20; var _MAX_RETRY_COUNT = 20;
var _MARK_NAME_PREFIX = 'benchpress'; var _MARK_NAME_PREFIX = 'benchpress';
var _SET_TIMEOUT = new OpaqueToken('PerflogMetric.setTimeout');
var _MARK_NAME_FRAME_CAPUTRE = 'frameCapture'; var _MARK_NAME_FRAME_CAPUTRE = 'frameCapture';
// using 17ms as a somewhat looser threshold, instead of 16.6666ms // using 17ms as a somewhat looser threshold, instead of 16.6666ms
var _FRAME_TIME_SMOOTH_THRESHOLD = 17; var _FRAME_TIME_SMOOTH_THRESHOLD = 17;
var _PROVIDERS = [
{
provide: PerflogMetric,
useFactory: (driverExtension, setTimeout, microMetrics, forceGc, captureFrames, receivedData,
requestCount) =>
new PerflogMetric(
driverExtension, setTimeout, microMetrics, forceGc, captureFrames,
receivedData, requestCount),
deps: [
WebDriverExtension, _SET_TIMEOUT, Options.MICRO_METRICS, Options.FORCE_GC,
Options.CAPTURE_FRAMES, Options.RECEIVED_DATA, Options.REQUEST_COUNT
]
},
{provide: _SET_TIMEOUT, useValue: (fn, millis) => <any>setTimeout(fn, millis)}
];

View File

@ -6,19 +6,21 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {OpaqueToken, Provider} from '@angular/core'; import {Inject, Injectable, OpaqueToken, Provider} from '@angular/core';
import {StringMapWrapper} from '@angular/facade/src/collection';
import {isNumber} from '@angular/facade/src/lang';
import {Options} from '../common_options'; import {Options} from '../common_options';
import {StringMapWrapper} from '../facade/collection';
import {isNumber} from '../facade/lang';
import {Metric} from '../metric'; import {Metric} from '../metric';
import {WebDriverAdapter} from '../web_driver_adapter'; import {WebDriverAdapter} from '../web_driver_adapter';
@Injectable()
export class UserMetric extends Metric { export class UserMetric extends Metric {
// TODO(tbosch): use static values when our transpiler supports them static PROVIDERS = [UserMetric];
static get PROVIDERS(): Provider[] { return _PROVIDERS; }
constructor(private _userMetrics: {[key: string]: string}, private _wdAdapter: WebDriverAdapter) { constructor(
@Inject(Options.USER_METRICS) private _userMetrics: {[key: string]: string},
private _wdAdapter: WebDriverAdapter) {
super(); super();
} }
@ -67,9 +69,3 @@ export class UserMetric extends Metric {
*/ */
describe(): {[key: string]: any} { return this._userMetrics; } describe(): {[key: string]: any} { return this._userMetrics; }
} }
var _PROVIDERS: Provider[] = [{
provide: UserMetric,
useFactory: (userMetrics, wdAdapter) => new UserMetric(userMetrics, wdAdapter),
deps: [Options.USER_METRICS, WebDriverAdapter]
}];

View File

@ -12,10 +12,6 @@ import {MeasureValues} from './measure_values';
* A reporter reports measure values and the valid sample. * A reporter reports measure values and the valid sample.
*/ */
export abstract class Reporter { export abstract class Reporter {
static bindTo(delegateToken): any[] {
return [{provide: Reporter, useFactory: (delegate) => delegate, deps: [delegateToken]}];
}
reportMeasureValues(values: MeasureValues): Promise<any> { throw new Error('NYI'); } reportMeasureValues(values: MeasureValues): Promise<any> { throw new Error('NYI'); }
reportSample(completeSample: MeasureValues[], validSample: MeasureValues[]): Promise<any> { reportSample(completeSample: MeasureValues[], validSample: MeasureValues[]): Promise<any> {

View File

@ -6,11 +6,11 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {OpaqueToken} from '@angular/core/src/di'; import {Inject, Injectable, OpaqueToken} from '@angular/core';
import {ListWrapper, StringMapWrapper} from '@angular/facade/src/collection';
import {NumberWrapper, isBlank, isPresent, print} from '@angular/facade/src/lang';
import {Math} from '@angular/facade/src/math';
import {ListWrapper, StringMapWrapper} from '../facade/collection';
import {NumberWrapper, isBlank, isPresent, print} from '../facade/lang';
import {Math} from '../facade/math';
import {MeasureValues} from '../measure_values'; import {MeasureValues} from '../measure_values';
import {Reporter} from '../reporter'; import {Reporter} from '../reporter';
import {SampleDescription} from '../sample_description'; import {SampleDescription} from '../sample_description';
@ -20,17 +20,16 @@ import {Statistic} from '../statistic';
/** /**
* A reporter for the console * A reporter for the console
*/ */
@Injectable()
export class ConsoleReporter extends Reporter { export class ConsoleReporter extends Reporter {
// TODO(tbosch): use static values when our transpiler supports them static PRINT = new OpaqueToken('ConsoleReporter.print');
static get PRINT(): OpaqueToken { return _PRINT; } static COLUMN_WIDTH = new OpaqueToken('ConsoleReporter.columnWidth');
// TODO(tbosch): use static values when our transpiler supports them static PROVIDERS = [
static get COLUMN_WIDTH(): OpaqueToken { return _COLUMN_WIDTH; } ConsoleReporter, {provide: ConsoleReporter.COLUMN_WIDTH, useValue: 18},
// TODO(tbosch): use static values when our transpiler supports them {provide: ConsoleReporter.PRINT, useValue: print}
static get PROVIDERS(): any[] { return _PROVIDERS; } ];
private static _lpad(value: string, columnWidth: number, fill = ' ') {
/** @internal */
private static _lpad(value, columnWidth, fill = ' ') {
var result = ''; var result = '';
for (var i = 0; i < columnWidth - value.length; i++) { for (var i = 0; i < columnWidth - value.length; i++) {
result += fill; result += fill;
@ -38,28 +37,27 @@ export class ConsoleReporter extends Reporter {
return result + value; return result + value;
} }
/** @internal */ private static _formatNum(n: number) { return NumberWrapper.toFixed(n, 2); }
private static _formatNum(n) { return NumberWrapper.toFixed(n, 2); }
/** @internal */ private static _sortedProps(obj: {[key: string]: any}) {
private static _sortedProps(obj) { var props: string[] = [];
var props = [];
StringMapWrapper.forEach(obj, (value, prop) => props.push(prop)); StringMapWrapper.forEach(obj, (value, prop) => props.push(prop));
props.sort(); props.sort();
return props; return props;
} }
/** @internal */
private _metricNames: string[]; private _metricNames: string[];
constructor(private _columnWidth: number, sampleDescription, private _print: Function) { constructor(
@Inject(ConsoleReporter.COLUMN_WIDTH) private _columnWidth: number,
sampleDescription: SampleDescription,
@Inject(ConsoleReporter.PRINT) private _print: Function) {
super(); super();
this._metricNames = ConsoleReporter._sortedProps(sampleDescription.metrics); this._metricNames = ConsoleReporter._sortedProps(sampleDescription.metrics);
this._printDescription(sampleDescription); this._printDescription(sampleDescription);
} }
/** @internal */ private _printDescription(sampleDescription: SampleDescription) {
private _printDescription(sampleDescription) {
this._print(`BENCHMARK ${sampleDescription.id}`); this._print(`BENCHMARK ${sampleDescription.id}`);
this._print('Description:'); this._print('Description:');
var props = ConsoleReporter._sortedProps(sampleDescription.description); var props = ConsoleReporter._sortedProps(sampleDescription.description);
@ -96,21 +94,8 @@ export class ConsoleReporter extends Reporter {
return Promise.resolve(null); return Promise.resolve(null);
} }
/** @internal */
private _printStringRow(parts: any[], fill = ' ') { private _printStringRow(parts: any[], fill = ' ') {
this._print( this._print(
parts.map(part => ConsoleReporter._lpad(part, this._columnWidth, fill)).join(' | ')); parts.map(part => ConsoleReporter._lpad(part, this._columnWidth, fill)).join(' | '));
} }
} }
var _PRINT = new OpaqueToken('ConsoleReporter.print');
var _COLUMN_WIDTH = new OpaqueToken('ConsoleReporter.columnWidth');
var _PROVIDERS = [
{
provide: ConsoleReporter,
useFactory: (columnWidth, sampleDescription, print) =>
new ConsoleReporter(columnWidth, sampleDescription, print),
deps: [_COLUMN_WIDTH, SampleDescription, _PRINT]
},
{provide: _COLUMN_WIDTH, useValue: 18}, {provide: _PRINT, useValue: print}
];

View File

@ -6,39 +6,29 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {OpaqueToken} from '@angular/core/src/di'; import {Inject, Injectable, OpaqueToken} from '@angular/core';
import {DateWrapper, Json, isBlank, isPresent} from '@angular/facade/src/lang';
import {Options} from '../common_options'; import {Options} from '../common_options';
import {DateWrapper, Json, isBlank, isPresent} from '../facade/lang';
import {MeasureValues} from '../measure_values'; import {MeasureValues} from '../measure_values';
import {Reporter} from '../reporter'; import {Reporter} from '../reporter';
import {SampleDescription} from '../sample_description'; import {SampleDescription} from '../sample_description';
/** /**
* A reporter that writes results into a json file. * A reporter that writes results into a json file.
*/ */
@Injectable()
export class JsonFileReporter extends Reporter { export class JsonFileReporter extends Reporter {
// TODO(tbosch): use static values when our transpiler supports them static PATH = new OpaqueToken('JsonFileReporter.path');
static get PATH(): OpaqueToken { return _PATH; } static PROVIDERS = [JsonFileReporter, {provide: JsonFileReporter.PATH, useValue: '.'}];
// TODO(tbosch): use static values when our transpiler supports them
static get PROVIDERS(): any[] { return _PROVIDERS; }
/** @internal */ constructor(
private _writeFile: Function; private _description: SampleDescription, @Inject(JsonFileReporter.PATH) private _path: string,
/** @internal */ @Inject(Options.WRITE_FILE) private _writeFile: Function,
private _path: string; @Inject(Options.NOW) private _now: Function) {
/** @internal */
private _description: SampleDescription;
/** @internal */
private _now: Function;
constructor(sampleDescription, path, writeFile, now) {
super(); super();
this._description = sampleDescription;
this._path = path;
this._writeFile = writeFile;
this._now = now;
} }
reportMeasureValues(measureValues: MeasureValues): Promise<any> { return Promise.resolve(null); } reportMeasureValues(measureValues: MeasureValues): Promise<any> { return Promise.resolve(null); }
@ -54,14 +44,3 @@ export class JsonFileReporter extends Reporter {
return this._writeFile(filePath, content); return this._writeFile(filePath, content);
} }
} }
var _PATH = new OpaqueToken('JsonFileReporter.path');
var _PROVIDERS = [
{
provide: JsonFileReporter,
useFactory: (sampleDescription, path, writeFile, now) =>
new JsonFileReporter(sampleDescription, path, writeFile, now),
deps: [SampleDescription, _PATH, Options.WRITE_FILE, Options.NOW]
},
{provide: _PATH, useValue: '.'}
];

View File

@ -6,13 +6,13 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {Injector, OpaqueToken} from '@angular/core/src/di'; import {Injector, OpaqueToken} from '@angular/core';
import {MeasureValues} from '../measure_values'; import {MeasureValues} from '../measure_values';
import {Reporter} from '../reporter'; import {Reporter} from '../reporter';
export class MultiReporter extends Reporter { export class MultiReporter extends Reporter {
static createBindings(childTokens: any[]): any[] { static provideWith(childTokens: any[]): any[] {
return [ return [
{ {
provide: _CHILDREN, provide: _CHILDREN,
@ -21,19 +21,13 @@ export class MultiReporter extends Reporter {
}, },
{ {
provide: MultiReporter, provide: MultiReporter,
useFactory: children => new MultiReporter(children), useFactory: (children: Reporter[]) => new MultiReporter(children),
deps: [_CHILDREN] deps: [_CHILDREN]
} }
]; ];
} }
/** @internal */ constructor(private _reporters: Reporter[]) { super(); }
private _reporters: Reporter[];
constructor(reporters) {
super();
this._reporters = reporters;
}
reportMeasureValues(values: MeasureValues): Promise<any[]> { reportMeasureValues(values: MeasureValues): Promise<any[]> {
return Promise.all(this._reporters.map(reporter => reporter.reportMeasureValues(values))); return Promise.all(this._reporters.map(reporter => reporter.reportMeasureValues(values)));

View File

@ -7,9 +7,9 @@
*/ */
import {Provider, ReflectiveInjector} from '@angular/core'; import {Provider, ReflectiveInjector} from '@angular/core';
import {isBlank, isPresent} from '@angular/facade/src/lang';
import {Options} from './common_options'; import {Options} from './common_options';
import {isBlank, isPresent} from './facade/lang';
import {Metric} from './metric'; import {Metric} from './metric';
import {MultiMetric} from './metric/multi_metric'; import {MultiMetric} from './metric/multi_metric';
import {PerflogMetric} from './metric/perflog_metric'; import {PerflogMetric} from './metric/perflog_metric';
@ -29,28 +29,23 @@ import {FirefoxDriverExtension} from './webdriver/firefox_driver_extension';
import {IOsDriverExtension} from './webdriver/ios_driver_extension'; import {IOsDriverExtension} from './webdriver/ios_driver_extension';
/** /**
* The Runner is the main entry point for executing a sample run. * The Runner is the main entry point for executing a sample run.
* It provides defaults, creates the injector and calls the sampler. * It provides defaults, creates the injector and calls the sampler.
*/ */
export class Runner { export class Runner {
private _defaultProviders: Provider[]; constructor(private _defaultProviders: Provider[] = []) {}
constructor(defaultProviders: Provider[] = null) {
if (isBlank(defaultProviders)) {
defaultProviders = [];
}
this._defaultProviders = defaultProviders;
}
sample({id, execute, prepare, microMetrics, providers, userMetrics}: { sample({id, execute, prepare, microMetrics, providers, userMetrics}: {
id: string, id: string,
execute?: any, execute?: Function,
prepare?: any, prepare?: Function,
microMetrics?: any, microMetrics?: {[key: string]: string},
providers?: any, providers?: Provider[],
userMetrics?: any userMetrics?: {[key: string]: string}
}): Promise<SampleState> { }): Promise<SampleState> {
var sampleProviders = [ var sampleProviders: Provider[] = [
_DEFAULT_PROVIDERS, this._defaultProviders, {provide: Options.SAMPLE_ID, useValue: id}, _DEFAULT_PROVIDERS, this._defaultProviders, {provide: Options.SAMPLE_ID, useValue: id},
{provide: Options.EXECUTE, useValue: execute} {provide: Options.EXECUTE, useValue: execute}
]; ];
@ -105,10 +100,11 @@ var _DEFAULT_PROVIDERS = [
PerflogMetric.PROVIDERS, PerflogMetric.PROVIDERS,
UserMetric.PROVIDERS, UserMetric.PROVIDERS,
SampleDescription.PROVIDERS, SampleDescription.PROVIDERS,
MultiReporter.createBindings([ConsoleReporter]), MultiReporter.provideWith([ConsoleReporter]),
MultiMetric.createBindings([PerflogMetric, UserMetric]), MultiMetric.provideWith([PerflogMetric, UserMetric]),
Reporter.bindTo(MultiReporter), {provide: Reporter, useExisting: MultiReporter},
Validator.bindTo(RegressionSlopeValidator), {provide: Validator, useExisting: RegressionSlopeValidator},
WebDriverExtension.bindTo([ChromeDriverExtension, FirefoxDriverExtension, IOsDriverExtension]), WebDriverExtension.provideFirstSupported(
Metric.bindTo(MultiMetric), [ChromeDriverExtension, FirefoxDriverExtension, IOsDriverExtension]),
{provide: Metric, useExisting: MultiMetric},
]; ];

View File

@ -6,9 +6,10 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {StringMapWrapper} from '@angular/facade/src/collection'; import {OpaqueToken} from '@angular/core';
import {Options} from './common_options'; import {Options} from './common_options';
import {StringMapWrapper} from './facade/collection';
import {Metric} from './metric'; import {Metric} from './metric';
import {Validator} from './validator'; import {Validator} from './validator';
@ -17,8 +18,23 @@ import {Validator} from './validator';
* SampleDescription merges all available descriptions about a sample * SampleDescription merges all available descriptions about a sample
*/ */
export class SampleDescription { export class SampleDescription {
// TODO(tbosch): use static values when our transpiler supports them static PROVIDERS = [{
static get PROVIDERS(): any[] { return _PROVIDERS; } provide: SampleDescription,
useFactory:
(metric: Metric, id: string, forceGc: boolean, userAgent: string, validator: Validator,
defaultDesc: {[key: string]: string}, userDesc: {[key: string]: string}) =>
new SampleDescription(
id,
[
{'forceGc': forceGc, 'userAgent': userAgent}, validator.describe(), defaultDesc,
userDesc
],
metric.describe()),
deps: [
Metric, Options.SAMPLE_ID, Options.FORCE_GC, Options.USER_AGENT, Validator,
Options.DEFAULT_DESCRIPTION, Options.SAMPLE_DESCRIPTION
]
}];
description: {[key: string]: any}; description: {[key: string]: any};
constructor( constructor(
@ -32,19 +48,3 @@ export class SampleDescription {
toJson() { return {'id': this.id, 'description': this.description, 'metrics': this.metrics}; } toJson() { return {'id': this.id, 'description': this.description, 'metrics': this.metrics}; }
} }
var _PROVIDERS = [{
provide: SampleDescription,
useFactory: (metric, id, forceGc, userAgent, validator, defaultDesc, userDesc) =>
new SampleDescription(
id,
[
{'forceGc': forceGc, 'userAgent': userAgent}, validator.describe(),
defaultDesc, userDesc
],
metric.describe()),
deps: [
Metric, Options.SAMPLE_ID, Options.FORCE_GC, Options.USER_AGENT, Validator,
Options.DEFAULT_DESCRIPTION, Options.SAMPLE_DESCRIPTION
]
}];

View File

@ -6,9 +6,10 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {Date, DateWrapper, isBlank, isPresent} from '@angular/facade/src/lang'; import {Inject, Injectable, OpaqueToken} from '@angular/core';
import {Options} from './common_options'; import {Options} from './common_options';
import {Date, DateWrapper, isBlank, isPresent} from './facade/lang';
import {MeasureValues} from './measure_values'; import {MeasureValues} from './measure_values';
import {Metric} from './metric'; import {Metric} from './metric';
import {Reporter} from './reporter'; import {Reporter} from './reporter';
@ -24,46 +25,18 @@ import {WebDriverAdapter} from './web_driver_adapter';
* 4. reports the new data to the reporter * 4. reports the new data to the reporter
* 5. loop until there is a valid sample * 5. loop until there is a valid sample
*/ */
@Injectable()
export class Sampler { export class Sampler {
// TODO(tbosch): use static values when our transpiler supports them static PROVIDERS = [Sampler];
static get PROVIDERS(): any[] { return _PROVIDERS; }
/** @internal */ constructor(
private _driver: WebDriverAdapter; private _driver: WebDriverAdapter, private _metric: Metric, private _reporter: Reporter,
/** @internal */ private _validator: Validator, @Inject(Options.PREPARE) private _prepare: Function,
private _metric: Metric; @Inject(Options.EXECUTE) private _execute: Function,
/** @internal */ @Inject(Options.NOW) private _now: Function) {}
private _reporter: Reporter;
/** @internal */
private _validator: Validator;
/** @internal */
private _prepare: Function;
/** @internal */
private _execute: Function;
/** @internal */
private _now: Function;
constructor({driver, metric, reporter, validator, prepare, execute, now}: {
driver?: WebDriverAdapter,
metric?: Metric,
reporter?: Reporter,
validator?: Validator,
prepare?: Function,
execute?: Function,
now?: Function
} = {}) {
this._driver = driver;
this._metric = metric;
this._reporter = reporter;
this._validator = validator;
this._prepare = prepare;
this._execute = execute;
this._now = now;
}
sample(): Promise<SampleState> { sample(): Promise<SampleState> {
var loop; const loop = (lastState: SampleState): Promise<SampleState> => {
loop = (lastState) => {
return this._iterate(lastState).then((newState) => { return this._iterate(lastState).then((newState) => {
if (isPresent(newState.validSample)) { if (isPresent(newState.validSample)) {
return newState; return newState;
@ -75,23 +48,21 @@ export class Sampler {
return loop(new SampleState([], null)); return loop(new SampleState([], null));
} }
/** @internal */ private _iterate(lastState: SampleState): Promise<SampleState> {
private _iterate(lastState): Promise<SampleState> {
var resultPromise: Promise<any>; var resultPromise: Promise<any>;
if (isPresent(this._prepare)) { if (this._prepare !== Options.NO_PREPARE) {
resultPromise = this._driver.waitFor(this._prepare); resultPromise = this._driver.waitFor(this._prepare);
} else { } else {
resultPromise = Promise.resolve(null); resultPromise = Promise.resolve(null);
} }
if (isPresent(this._prepare) || lastState.completeSample.length === 0) { if (this._prepare !== Options.NO_PREPARE || lastState.completeSample.length === 0) {
resultPromise = resultPromise.then((_) => this._metric.beginMeasure()); resultPromise = resultPromise.then((_) => this._metric.beginMeasure());
} }
return resultPromise.then((_) => this._driver.waitFor(this._execute)) return resultPromise.then((_) => this._driver.waitFor(this._execute))
.then((_) => this._metric.endMeasure(isBlank(this._prepare))) .then((_) => this._metric.endMeasure(this._prepare === Options.NO_PREPARE))
.then((measureValues) => this._report(lastState, measureValues)); .then((measureValues) => this._report(lastState, measureValues));
} }
/** @internal */
private _report(state: SampleState, metricValues: {[key: string]: any}): Promise<SampleState> { private _report(state: SampleState, metricValues: {[key: string]: any}): Promise<SampleState> {
var measureValues = new MeasureValues(state.completeSample.length, this._now(), metricValues); var measureValues = new MeasureValues(state.completeSample.length, this._now(), metricValues);
var completeSample = state.completeSample.concat([measureValues]); var completeSample = state.completeSample.concat([measureValues]);
@ -108,22 +79,3 @@ export class Sampler {
export class SampleState { export class SampleState {
constructor(public completeSample: any[], public validSample: any[]) {} constructor(public completeSample: any[], public validSample: any[]) {}
} }
var _PROVIDERS = [{
provide: Sampler,
useFactory: (driver, metric, reporter, validator, prepare, execute, now) => new Sampler({
driver: driver,
reporter: reporter,
validator: validator,
metric: metric,
// TODO(tbosch): DI right now does not support null/undefined objects
// Mostly because the cache would have to be initialized with a
// special null object, which is expensive.
prepare: prepare !== false ? prepare : null,
execute: execute,
now: now
}),
deps: [
WebDriverAdapter, Metric, Reporter, Validator, Options.PREPARE, Options.EXECUTE, Options.NOW
]
}];

View File

@ -6,10 +6,10 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {Math} from '@angular/facade/src/math'; import {Math} from './facade/math';
export class Statistic { export class Statistic {
static calculateCoefficientOfVariation(sample, mean) { static calculateCoefficientOfVariation(sample: number[], mean: number) {
return Statistic.calculateStandardDeviation(sample, mean) / mean * 100; return Statistic.calculateStandardDeviation(sample, mean) / mean * 100;
} }
@ -20,7 +20,7 @@ export class Statistic {
return total / samples.length; return total / samples.length;
} }
static calculateStandardDeviation(samples: number[], mean) { static calculateStandardDeviation(samples: number[], mean: number) {
var deviation = 0; var deviation = 0;
// TODO: use reduce // TODO: use reduce
samples.forEach(x => deviation += Math.pow(x - mean, 2)); samples.forEach(x => deviation += Math.pow(x - mean, 2));

View File

@ -14,10 +14,6 @@ import {MeasureValues} from './measure_values';
* in the correct way. * in the correct way.
*/ */
export abstract class Validator { export abstract class Validator {
static bindTo(delegateToken): any[] {
return [{provide: Validator, useFactory: (delegate) => delegate, deps: [delegateToken]}];
}
/** /**
* Calculates a valid sample out of the complete sample * Calculates a valid sample out of the complete sample
*/ */

View File

@ -6,35 +6,32 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {OpaqueToken} from '@angular/core/src/di'; import {Inject, Injectable, OpaqueToken} from '@angular/core';
import {ListWrapper} from '@angular/facade/src/collection';
import {ListWrapper} from '../facade/collection';
import {MeasureValues} from '../measure_values'; import {MeasureValues} from '../measure_values';
import {Statistic} from '../statistic'; import {Statistic} from '../statistic';
import {Validator} from '../validator'; import {Validator} from '../validator';
/** /**
* A validator that checks the regression slope of a specific metric. * A validator that checks the regression slope of a specific metric.
* Waits for the regression slope to be >=0. * Waits for the regression slope to be >=0.
*/ */
@Injectable()
export class RegressionSlopeValidator extends Validator { export class RegressionSlopeValidator extends Validator {
// TODO(tbosch): use static values when our transpiler supports them static SAMPLE_SIZE = new OpaqueToken('RegressionSlopeValidator.sampleSize');
static get SAMPLE_SIZE(): OpaqueToken { return _SAMPLE_SIZE; } static METRIC = new OpaqueToken('RegressionSlopeValidator.metric');
// TODO(tbosch): use static values when our transpiler supports them static PROVIDERS = [
static get METRIC(): OpaqueToken { return _METRIC; } RegressionSlopeValidator, {provide: RegressionSlopeValidator.SAMPLE_SIZE, useValue: 10},
// TODO(tbosch): use static values when our transpiler supports them {provide: RegressionSlopeValidator.METRIC, useValue: 'scriptTime'}
static get PROVIDERS(): any[] { return _PROVIDERS; } ];
/** @internal */ constructor(
private _sampleSize: number; @Inject(RegressionSlopeValidator.SAMPLE_SIZE) private _sampleSize: number,
/** @internal */ @Inject(RegressionSlopeValidator.METRIC) private _metric: string) {
private _metric: string;
constructor(sampleSize, metric) {
super(); super();
this._sampleSize = sampleSize;
this._metric = metric;
} }
describe(): {[key: string]: any} { describe(): {[key: string]: any} {
@ -45,8 +42,8 @@ export class RegressionSlopeValidator extends Validator {
if (completeSample.length >= this._sampleSize) { if (completeSample.length >= this._sampleSize) {
var latestSample = ListWrapper.slice( var latestSample = ListWrapper.slice(
completeSample, completeSample.length - this._sampleSize, completeSample.length); completeSample, completeSample.length - this._sampleSize, completeSample.length);
var xValues = []; var xValues: number[] = [];
var yValues = []; var yValues: number[] = [];
for (var i = 0; i < latestSample.length; i++) { for (var i = 0; i < latestSample.length; i++) {
// For now, we only use the array index as x value. // For now, we only use the array index as x value.
// TODO(tbosch): think about whether we should use time here instead // TODO(tbosch): think about whether we should use time here instead
@ -61,14 +58,3 @@ export class RegressionSlopeValidator extends Validator {
} }
} }
} }
var _SAMPLE_SIZE = new OpaqueToken('RegressionSlopeValidator.sampleSize');
var _METRIC = new OpaqueToken('RegressionSlopeValidator.metric');
var _PROVIDERS = [
{
provide: RegressionSlopeValidator,
useFactory: (sampleSize, metric) => new RegressionSlopeValidator(sampleSize, metric),
deps: [_SAMPLE_SIZE, _METRIC]
},
{provide: _SAMPLE_SIZE, useValue: 10}, {provide: _METRIC, useValue: 'scriptTime'}
];

View File

@ -6,29 +6,23 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {OpaqueToken} from '@angular/core/src/di'; import {Inject, Injectable, OpaqueToken} from '@angular/core';
import {ListWrapper} from '@angular/facade/src/collection';
import {ListWrapper} from '../facade/collection';
import {MeasureValues} from '../measure_values'; import {MeasureValues} from '../measure_values';
import {Validator} from '../validator'; import {Validator} from '../validator';
/** /**
* A validator that waits for the sample to have a certain size. * A validator that waits for the sample to have a certain size.
*/ */
@Injectable()
export class SizeValidator extends Validator { export class SizeValidator extends Validator {
// TODO(tbosch): use static values when our transpiler supports them static SAMPLE_SIZE = new OpaqueToken('SizeValidator.sampleSize');
static get PROVIDERS(): any[] { return _PROVIDERS; } static PROVIDERS = [SizeValidator, {provide: SizeValidator.SAMPLE_SIZE, useValue: 10}];
// TODO(tbosch): use static values when our transpiler supports them
static get SAMPLE_SIZE() { return _SAMPLE_SIZE; }
/** @internal */ constructor(@Inject(SizeValidator.SAMPLE_SIZE) private _sampleSize: number) { super(); }
private _sampleSize: number;
constructor(size) {
super();
this._sampleSize = size;
}
describe(): {[key: string]: any} { return {'sampleSize': this._sampleSize}; } describe(): {[key: string]: any} { return {'sampleSize': this._sampleSize}; }
@ -41,9 +35,3 @@ export class SizeValidator extends Validator {
} }
} }
} }
var _SAMPLE_SIZE = new OpaqueToken('SizeValidator.sampleSize');
var _PROVIDERS = [
{provide: SizeValidator, useFactory: (size) => new SizeValidator(size), deps: [_SAMPLE_SIZE]},
{provide: _SAMPLE_SIZE, useValue: 10}
];

View File

@ -14,10 +14,6 @@
* Needs one implementation for every supported WebDriver client. * Needs one implementation for every supported WebDriver client.
*/ */
export abstract class WebDriverAdapter { export abstract class WebDriverAdapter {
static bindTo(delegateToken): any[] {
return [{provide: WebDriverAdapter, useFactory: (delegate) => delegate, deps: [delegateToken]}];
}
waitFor(callback: Function): Promise<any> { throw new Error('NYI'); } waitFor(callback: Function): Promise<any> { throw new Error('NYI'); }
executeScript(script: string): Promise<any> { throw new Error('NYI'); } executeScript(script: string): Promise<any> { throw new Error('NYI'); }
executeAsyncScript(script: string): Promise<any> { throw new Error('NYI'); } executeAsyncScript(script: string): Promise<any> { throw new Error('NYI'); }

View File

@ -6,11 +6,20 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {Injector, OpaqueToken} from '@angular/core/src/di'; import {Injector, OpaqueToken} from '@angular/core';
import {isBlank, isPresent} from '@angular/facade/src/lang';
import {Options} from './common_options'; import {Options} from './common_options';
import {isBlank, isPresent} from './facade/lang';
export type PerfLogEvent = {
cat?: string,
ph?: 'X' | 'B' | 'E' | 'b' | 'e',
ts?: number,
dur?: number,
name?: string,
pid?: string,
args?: {encodedDataLength?: number, usedHeapSize?: number, majorGc?: number}
};
/** /**
* A WebDriverExtension implements extended commands of the webdriver protocol * A WebDriverExtension implements extended commands of the webdriver protocol
@ -18,7 +27,7 @@ import {Options} from './common_options';
* Needs one implementation for every supported Browser. * Needs one implementation for every supported Browser.
*/ */
export abstract class WebDriverExtension { export abstract class WebDriverExtension {
static bindTo(childTokens: any[]): any[] { static provideFirstSupported(childTokens: any[]): any[] {
var res = [ var res = [
{ {
provide: _CHILDREN, provide: _CHILDREN,
@ -27,8 +36,8 @@ export abstract class WebDriverExtension {
}, },
{ {
provide: WebDriverExtension, provide: WebDriverExtension,
useFactory: (children: WebDriverExtension[], capabilities) => { useFactory: (children: WebDriverExtension[], capabilities: any) => {
var delegate; var delegate: WebDriverExtension;
children.forEach(extension => { children.forEach(extension => {
if (extension.supports(capabilities)) { if (extension.supports(capabilities)) {
delegate = extension; delegate = extension;
@ -64,7 +73,7 @@ export abstract class WebDriverExtension {
* Based on [Chrome Trace Event * Based on [Chrome Trace Event
*Format](https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/edit) *Format](https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/edit)
**/ **/
readPerfLog(): Promise<any[]> { throw new Error('NYI'); } readPerfLog(): Promise<PerfLogEvent[]> { throw new Error('NYI'); }
perfLogFeatures(): PerfLogFeatures { throw new Error('NYI'); } perfLogFeatures(): PerfLogFeatures { throw new Error('NYI'); }

View File

@ -1,35 +0,0 @@
library benchpress.src.webdriver.async_webdriver_adapter_dart;
import 'dart:async';
import 'package:webdriver/webdriver.dart' show WebDriver, LogEntry;
import '../web_driver_adapter.dart' show WebDriverAdapter;
class AsyncWebDriverAdapter extends WebDriverAdapter {
WebDriver _driver;
AsyncWebDriverAdapter(this._driver);
Future waitFor(Function callback) {
return callback();
}
Future executeScript(String script) {
return _driver.execute(script, const []);
}
Future executeAsyncScript(String script) {
return _driver.executeAsync(script, const []);
}
Future<Map> capabilities() {
return new Future.value(_driver.capabilities);
}
Future<List<Map>> logs(String type) {
return _driver.logs
.get(type)
.map((LogEntry entry) => {'message': entry.message})
.fold(<Map>[], (log, Map entry) {
return log..add(entry);
});
}
}

View File

@ -6,12 +6,14 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {ListWrapper, StringMapWrapper} from '@angular/facade/src/collection'; import {Inject, Injectable} from '@angular/core';
import {Json, NumberWrapper, StringWrapper, isBlank, isPresent} from '@angular/facade/src/lang';
import {Options} from '../common_options'; import {Options} from '../common_options';
import {ListWrapper, StringMapWrapper} from '../facade/collection';
import {NumberWrapper, StringWrapper, isBlank, isPresent} from '../facade/lang';
import {WebDriverAdapter} from '../web_driver_adapter'; import {WebDriverAdapter} from '../web_driver_adapter';
import {PerfLogFeatures, WebDriverExtension} from '../web_driver_extension'; import {PerfLogEvent, PerfLogFeatures, WebDriverExtension} from '../web_driver_extension';
/** /**
@ -21,13 +23,13 @@ import {PerfLogFeatures, WebDriverExtension} from '../web_driver_extension';
* In order to collect the frame rate related metrics, add 'benchmark' * In order to collect the frame rate related metrics, add 'benchmark'
* to the list above. * to the list above.
*/ */
@Injectable()
export class ChromeDriverExtension extends WebDriverExtension { export class ChromeDriverExtension extends WebDriverExtension {
// TODO(tbosch): use static values when our transpiler supports them static PROVIDERS = [ChromeDriverExtension];
static get PROVIDERS(): any[] { return _PROVIDERS; }
private _majorChromeVersion: number; private _majorChromeVersion: number;
constructor(private _driver: WebDriverAdapter, userAgent: string) { constructor(private _driver: WebDriverAdapter, @Inject(Options.USER_AGENT) userAgent: string) {
super(); super();
this._majorChromeVersion = this._parseChromeVersion(userAgent); this._majorChromeVersion = this._parseChromeVersion(userAgent);
} }
@ -63,15 +65,15 @@ export class ChromeDriverExtension extends WebDriverExtension {
// See [Chrome Trace Event // See [Chrome Trace Event
// Format](https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/edit) // Format](https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/edit)
readPerfLog(): Promise<any> { readPerfLog(): Promise<PerfLogEvent[]> {
// TODO(tbosch): Chromedriver bug https://code.google.com/p/chromedriver/issues/detail?id=1098 // TODO(tbosch): Chromedriver bug https://code.google.com/p/chromedriver/issues/detail?id=1098
// Need to execute at least one command so that the browser logs can be read out! // Need to execute at least one command so that the browser logs can be read out!
return this._driver.executeScript('1+1') return this._driver.executeScript('1+1')
.then((_) => this._driver.logs('performance')) .then((_) => this._driver.logs('performance'))
.then((entries) => { .then((entries) => {
var events = []; var events: PerfLogEvent[] = [];
entries.forEach(entry => { entries.forEach(entry => {
var message = Json.parse(entry['message'])['message']; var message = JSON.parse(entry['message'])['message'];
if (StringWrapper.equals(message['method'], 'Tracing.dataCollected')) { if (StringWrapper.equals(message['method'], 'Tracing.dataCollected')) {
events.push(message['params']); events.push(message['params']);
} }
@ -84,8 +86,7 @@ export class ChromeDriverExtension extends WebDriverExtension {
} }
private _convertPerfRecordsToEvents( private _convertPerfRecordsToEvents(
chromeEvents: Array<{[key: string]: any}>, chromeEvents: Array<{[key: string]: any}>, normalizedEvents: PerfLogEvent[] = null) {
normalizedEvents: Array<{[key: string]: any}> = null) {
if (isBlank(normalizedEvents)) { if (isBlank(normalizedEvents)) {
normalizedEvents = []; normalizedEvents = [];
} }
@ -128,7 +129,8 @@ export class ChromeDriverExtension extends WebDriverExtension {
return normalizedEvents; return normalizedEvents;
} }
private _processAsPreChrome45Event(event, categories, majorGCPids) { private _processAsPreChrome45Event(
event: {[key: string]: any}, categories: string[], majorGCPids: {[key: string]: any}) {
var name = event['name']; var name = event['name'];
var args = event['args']; var args = event['args'];
var pid = event['pid']; var pid = event['pid'];
@ -148,7 +150,7 @@ export class ChromeDriverExtension extends WebDriverExtension {
return normalizeEvent(event, {'name': 'render'}); return normalizeEvent(event, {'name': 'render'});
} else if (this._isEvent( } else if (this._isEvent(
categories, name, ['disabled-by-default-devtools.timeline'], 'GCEvent')) { categories, name, ['disabled-by-default-devtools.timeline'], 'GCEvent')) {
var normArgs = { var normArgs: {[key: string]: any} = {
'usedHeapSize': isPresent(args['usedHeapSizeAfter']) ? args['usedHeapSizeAfter'] : 'usedHeapSize': isPresent(args['usedHeapSizeAfter']) ? args['usedHeapSizeAfter'] :
args['usedHeapSizeBefore'] args['usedHeapSizeBefore']
}; };
@ -164,7 +166,7 @@ export class ChromeDriverExtension extends WebDriverExtension {
return null; // nothing useful in this event return null; // nothing useful in this event
} }
private _processAsPostChrome44Event(event, categories) { private _processAsPostChrome44Event(event: {[key: string]: any}, categories: string[]) {
var name = event['name']; var name = event['name'];
var args = event['args']; var args = event['args'];
if (this._isEvent(categories, name, ['devtools.timeline', 'v8'], 'MajorGC')) { if (this._isEvent(categories, name, ['devtools.timeline', 'v8'], 'MajorGC')) {
@ -230,14 +232,14 @@ export class ChromeDriverExtension extends WebDriverExtension {
} }
function normalizeEvent( function normalizeEvent(
chromeEvent: {[key: string]: any}, data: {[key: string]: any}): {[key: string]: any} { chromeEvent: {[key: string]: any}, data: {[key: string]: any}): PerfLogEvent {
var ph = chromeEvent['ph']; var ph = chromeEvent['ph'];
if (StringWrapper.equals(ph, 'S')) { if (StringWrapper.equals(ph, 'S')) {
ph = 'b'; ph = 'b';
} else if (StringWrapper.equals(ph, 'F')) { } else if (StringWrapper.equals(ph, 'F')) {
ph = 'e'; ph = 'e';
} }
var result = var result: {[key: string]: any} =
{'pid': chromeEvent['pid'], 'ph': ph, 'cat': 'timeline', 'ts': chromeEvent['ts'] / 1000}; {'pid': chromeEvent['pid'], 'ph': ph, 'cat': 'timeline', 'ts': chromeEvent['ts'] / 1000};
if (chromeEvent['ph'] === 'X') { if (chromeEvent['ph'] === 'X') {
var dur = chromeEvent['dur']; var dur = chromeEvent['dur'];
@ -249,9 +251,3 @@ function normalizeEvent(
StringMapWrapper.forEach(data, (value, prop) => { result[prop] = value; }); StringMapWrapper.forEach(data, (value, prop) => { result[prop] = value; });
return result; return result;
} }
var _PROVIDERS = [{
provide: ChromeDriverExtension,
useFactory: (driver, userAgent) => new ChromeDriverExtension(driver, userAgent),
deps: [WebDriverAdapter, Options.USER_AGENT]
}];

View File

@ -6,13 +6,15 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {StringWrapper, isPresent} from '@angular/facade/src/lang'; import {Injectable} from '@angular/core';
import {StringWrapper, isPresent} from '../facade/lang';
import {WebDriverAdapter} from '../web_driver_adapter'; import {WebDriverAdapter} from '../web_driver_adapter';
import {PerfLogFeatures, WebDriverExtension} from '../web_driver_extension'; import {PerfLogEvent, PerfLogFeatures, WebDriverExtension} from '../web_driver_extension';
@Injectable()
export class FirefoxDriverExtension extends WebDriverExtension { export class FirefoxDriverExtension extends WebDriverExtension {
static get PROVIDERS(): any[] { return _PROVIDERS; } static PROVIDERS = [FirefoxDriverExtension];
private _profilerStarted: boolean; private _profilerStarted: boolean;
@ -39,7 +41,7 @@ export class FirefoxDriverExtension extends WebDriverExtension {
return this._driver.executeScript(script); return this._driver.executeScript(script);
} }
readPerfLog(): Promise<any> { readPerfLog(): Promise<PerfLogEvent> {
return this._driver.executeAsyncScript('var cb = arguments[0]; window.getProfile(cb);'); return this._driver.executeAsyncScript('var cb = arguments[0]; window.getProfile(cb);');
} }
@ -49,9 +51,3 @@ export class FirefoxDriverExtension extends WebDriverExtension {
return StringWrapper.equals(capabilities['browserName'].toLowerCase(), 'firefox'); return StringWrapper.equals(capabilities['browserName'].toLowerCase(), 'firefox');
} }
} }
var _PROVIDERS = [{
provide: FirefoxDriverExtension,
useFactory: (driver) => new FirefoxDriverExtension(driver),
deps: [WebDriverAdapter]
}];

View File

@ -6,14 +6,15 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {Json, StringWrapper, isBlank, isPresent} from '@angular/facade/src/lang'; import {Injectable} from '@angular/core';
import {StringWrapper, isBlank, isPresent} from '../facade/lang';
import {WebDriverAdapter} from '../web_driver_adapter'; import {WebDriverAdapter} from '../web_driver_adapter';
import {PerfLogFeatures, WebDriverExtension} from '../web_driver_extension'; import {PerfLogEvent, PerfLogFeatures, WebDriverExtension} from '../web_driver_extension';
@Injectable()
export class IOsDriverExtension extends WebDriverExtension { export class IOsDriverExtension extends WebDriverExtension {
// TODO(tbosch): use static values when our transpiler supports them static PROVIDERS = [IOsDriverExtension];
static get PROVIDERS(): any[] { return _PROVIDERS; }
constructor(private _driver: WebDriverAdapter) { super(); } constructor(private _driver: WebDriverAdapter) { super(); }
@ -38,9 +39,9 @@ export class IOsDriverExtension extends WebDriverExtension {
return this._driver.executeScript('1+1') return this._driver.executeScript('1+1')
.then((_) => this._driver.logs('performance')) .then((_) => this._driver.logs('performance'))
.then((entries) => { .then((entries) => {
var records = []; var records: any[] = [];
entries.forEach(entry => { entries.forEach(entry => {
var message = Json.parse(entry['message'])['message']; var message = JSON.parse(entry['message'])['message'];
if (StringWrapper.equals(message['method'], 'Timeline.eventRecorded')) { if (StringWrapper.equals(message['method'], 'Timeline.eventRecorded')) {
records.push(message['params']['record']); records.push(message['params']['record']);
} }
@ -50,12 +51,12 @@ export class IOsDriverExtension extends WebDriverExtension {
} }
/** @internal */ /** @internal */
private _convertPerfRecordsToEvents(records: any[], events: any[] = null) { private _convertPerfRecordsToEvents(records: any[], events: PerfLogEvent[] = null) {
if (isBlank(events)) { if (isBlank(events)) {
events = []; events = [];
} }
records.forEach((record) => { records.forEach((record) => {
var endEvent = null; var endEvent: PerfLogEvent = null;
var type = record['type']; var type = record['type'];
var data = record['data']; var data = record['data'];
var startTime = record['startTime']; var startTime = record['startTime'];
@ -95,8 +96,9 @@ export class IOsDriverExtension extends WebDriverExtension {
} }
} }
function createEvent(ph, name, time, args = null) { function createEvent(
var result = { ph: 'X' | 'B' | 'E' | 'b' | 'e', name: string, time: number, args: any = null) {
var result: PerfLogEvent = {
'cat': 'timeline', 'cat': 'timeline',
'name': name, 'name': name,
'ts': time, 'ts': time,
@ -111,24 +113,18 @@ function createEvent(ph, name, time, args = null) {
return result; return result;
} }
function createStartEvent(name, time, args = null) { function createStartEvent(name: string, time: number, args: any = null) {
return createEvent('B', name, time, args); return createEvent('B', name, time, args);
} }
function createEndEvent(name, time, args = null) { function createEndEvent(name: string, time: number, args: any = null) {
return createEvent('E', name, time, args); return createEvent('E', name, time, args);
} }
function createMarkStartEvent(name, time) { function createMarkStartEvent(name: string, time: number) {
return createEvent('b', name, time); return createEvent('b', name, time);
} }
function createMarkEndEvent(name, time) { function createMarkEndEvent(name: string, time: number) {
return createEvent('e', name, time); return createEvent('e', name, time);
} }
var _PROVIDERS = [{
provide: IOsDriverExtension,
useFactory: (driver) => new IOsDriverExtension(driver),
deps: [WebDriverAdapter]
}];

View File

@ -1,3 +0,0 @@
library benchpress.src.webdriver.selenium_webdriver_adapter;
//no dart implementation

View File

@ -10,18 +10,19 @@ import * as webdriver from 'selenium-webdriver';
import {WebDriverAdapter} from '../web_driver_adapter'; import {WebDriverAdapter} from '../web_driver_adapter';
/** /**
* Adapter for the selenium-webdriver. * Adapter for the selenium-webdriver.
*/ */
export class SeleniumWebDriverAdapter extends WebDriverAdapter { export class SeleniumWebDriverAdapter extends WebDriverAdapter {
static get PROTRACTOR_BINDINGS(): any[] { return _PROTRACTOR_BINDINGS; } static PROTRACTOR_PROVIDERS = [{
provide: WebDriverAdapter,
useFactory: () => new SeleniumWebDriverAdapter((<any>global).browser)
}];
constructor(private _driver: any) { super(); } constructor(private _driver: any) { super(); }
/** @internal */ /** @internal */
private _convertPromise(thenable) { private _convertPromise(thenable: PromiseLike<any>) {
var resolve: (result: any) => void; var resolve: (result: any) => void;
var reject: (error: any) => void; var reject: (error: any) => void;
var promise = new Promise((res, rej) => { var promise = new Promise((res, rej) => {
@ -31,12 +32,11 @@ export class SeleniumWebDriverAdapter extends WebDriverAdapter {
thenable.then( thenable.then(
// selenium-webdriver uses an own Node.js context, // selenium-webdriver uses an own Node.js context,
// so we need to convert data into objects of this context. // so we need to convert data into objects of this context.
// Previously needed for rtts_asserts. (data: any) => resolve(convertToLocalProcess(data)), reject);
(data) => resolve(convertToLocalProcess(data)), reject);
return promise; return promise;
} }
waitFor(callback): Promise<any> { waitFor(callback: () => any): Promise<any> {
return this._convertPromise(this._driver.controlFlow().execute(callback)); return this._convertPromise(this._driver.controlFlow().execute(callback));
} }
@ -50,7 +50,7 @@ export class SeleniumWebDriverAdapter extends WebDriverAdapter {
capabilities(): Promise<any> { capabilities(): Promise<any> {
return this._convertPromise( return this._convertPromise(
this._driver.getCapabilities().then((capsObject) => capsObject.serialize())); this._driver.getCapabilities().then((capsObject: any) => capsObject.serialize()));
} }
logs(type: string): Promise<any> { logs(type: string): Promise<any> {
@ -62,16 +62,10 @@ export class SeleniumWebDriverAdapter extends WebDriverAdapter {
} }
} }
function convertToLocalProcess(data): Object { function convertToLocalProcess(data: any): Object {
var serialized = JSON.stringify(data); var serialized = JSON.stringify(data);
if ('' + serialized === 'undefined') { if ('' + serialized === 'undefined') {
return undefined; return undefined;
} }
return JSON.parse(serialized); return JSON.parse(serialized);
} }
var _PROTRACTOR_BINDINGS = [{
provide: WebDriverAdapter,
useFactory: () => new SeleniumWebDriverAdapter((<any>global).browser),
deps: []
}];

View File

@ -1,3 +0,0 @@
library benchpress.test.firefox_extension.conf;
//empty as we don't have a version for dart

View File

@ -1,3 +0,0 @@
library benchpress.test.firefox_extension.parser_util_spec;
main() {}

View File

@ -6,9 +6,9 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {convertPerfProfileToEvents} from 'benchpress/src/firefox_extension/lib/parser_util'; import {convertPerfProfileToEvents} from '../../src/firefox_extension/lib/parser_util';
function assertEventsEqual(actualEvents, expectedEvents) { function assertEventsEqual(actualEvents: any[], expectedEvents: any[]) {
expect(actualEvents.length == expectedEvents.length); expect(actualEvents.length == expectedEvents.length);
for (var i = 0; i < actualEvents.length; ++i) { for (var i = 0; i < actualEvents.length; ++i) {
var actualEvent = actualEvents[i]; var actualEvent = actualEvents[i];

View File

@ -1,3 +0,0 @@
library benchpress.test.firefox_extension.sample_benchmark;
main() {}

View File

@ -9,7 +9,7 @@
var benchpress = require('../../index.js'); var benchpress = require('../../index.js');
var runner = new benchpress.Runner([ var runner = new benchpress.Runner([
// use protractor as Webdriver client // use protractor as Webdriver client
benchpress.SeleniumWebDriverAdapter.PROTRACTOR_BINDINGS, benchpress.SeleniumWebDriverAdapter.PROTRACTOR_PROVIDERS,
// use RegressionSlopeValidator to validate samples // use RegressionSlopeValidator to validate samples
benchpress.Validator.bindTo(benchpress.RegressionSlopeValidator), benchpress.Validator.bindTo(benchpress.RegressionSlopeValidator),
// use 10 samples to calculate slope regression // use 10 samples to calculate slope regression

View File

@ -1,3 +0,0 @@
library benchpress.test.firefox_extension.spec;
main() {}

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
var assertEventsContainsName = function(events, eventName) { var assertEventsContainsName = function(events: any[], eventName: string) {
var found = false; var found = false;
for (var i = 0; i < events.length; ++i) { for (var i = 0; i < events.length; ++i) {
if (events[i].name == eventName) { if (events[i].name == eventName) {
@ -33,7 +33,7 @@ describe('firefox extension', function() {
browser.executeScript('window.forceGC()'); browser.executeScript('window.forceGC()');
browser.executeAsyncScript('var cb = arguments[0]; window.getProfile(cb);') browser.executeAsyncScript('var cb = arguments[0]; window.getProfile(cb);')
.then(function(profile) { .then(function(profile: any) {
assertEventsContainsName(profile, 'gc'); assertEventsContainsName(profile, 'gc');
assertEventsContainsName(profile, 'script'); assertEventsContainsName(profile, 'script');
}); });

View File

@ -7,28 +7,29 @@
*/ */
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal'; import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {Metric, MultiMetric, ReflectiveInjector} from 'benchpress/common'; import {Metric, MultiMetric, ReflectiveInjector} from '../../index';
export function main() { export function main() {
function createMetric(ids: any[]) { function createMetric(ids: any[]) {
var m = ReflectiveInjector var m = ReflectiveInjector
.resolveAndCreate([ .resolveAndCreate([
ids.map(id => { return {provide: id, useValue: new MockMetric(id)}; }), ids.map(id => { return {provide: id, useValue: new MockMetric(id)}; }),
MultiMetric.createBindings(ids) MultiMetric.provideWith(ids)
]) ])
.get(MultiMetric); .get(MultiMetric);
return Promise.resolve(m); return Promise.resolve(m);
} }
describe('multi metric', () => { describe('multi metric', () => {
it('should merge descriptions', inject([AsyncTestCompleter], (async) => { it('should merge descriptions', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createMetric(['m1', 'm2']).then((m) => { createMetric(['m1', 'm2']).then((m) => {
expect(m.describe()).toEqual({'m1': 'describe', 'm2': 'describe'}); expect(m.describe()).toEqual({'m1': 'describe', 'm2': 'describe'});
async.done(); async.done();
}); });
})); }));
it('should merge all beginMeasure calls', inject([AsyncTestCompleter], (async) => { it('should merge all beginMeasure calls',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createMetric(['m1', 'm2']).then((m) => m.beginMeasure()).then((values) => { createMetric(['m1', 'm2']).then((m) => m.beginMeasure()).then((values) => {
expect(values).toEqual(['m1_beginMeasure', 'm2_beginMeasure']); expect(values).toEqual(['m1_beginMeasure', 'm2_beginMeasure']);
async.done(); async.done();
@ -37,7 +38,7 @@ export function main() {
[false, true].forEach((restartFlag) => { [false, true].forEach((restartFlag) => {
it(`should merge all endMeasure calls for restart=${restartFlag}`, it(`should merge all endMeasure calls for restart=${restartFlag}`,
inject([AsyncTestCompleter], (async) => { inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createMetric(['m1', 'm2']).then((m) => m.endMeasure(restartFlag)).then((values) => { createMetric(['m1', 'm2']).then((m) => m.endMeasure(restartFlag)).then((values) => {
expect(values).toEqual( expect(values).toEqual(
{'m1': {'restart': restartFlag}, 'm2': {'restart': restartFlag}}); {'m1': {'restart': restartFlag}, 'm2': {'restart': restartFlag}});
@ -50,18 +51,12 @@ export function main() {
} }
class MockMetric extends Metric { class MockMetric extends Metric {
/** @internal */ constructor(private _id: string) { super(); }
private _id: string;
constructor(id) {
super();
this._id = id;
}
beginMeasure(): Promise<string> { return Promise.resolve(`${this._id}_beginMeasure`); } beginMeasure(): Promise<string> { return Promise.resolve(`${this._id}_beginMeasure`); }
endMeasure(restart: boolean): Promise<{[key: string]: any}> { endMeasure(restart: boolean): Promise<{[key: string]: any}> {
var result = {}; var result: {[key: string]: any} = {};
result[this._id] = {'restart': restart}; result[this._id] = {'restart': restart};
return Promise.resolve(result); return Promise.resolve(result);
} }

View File

@ -8,10 +8,10 @@
import {Provider} from '@angular/core'; import {Provider} from '@angular/core';
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal'; import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {StringMapWrapper} from '@angular/facade/src/collection';
import {isBlank, isPresent} from '@angular/facade/src/lang';
import {Metric, Options, PerfLogFeatures, PerflogMetric, ReflectiveInjector, WebDriverExtension} from 'benchpress/common';
import {Metric, Options, PerfLogEvent, PerfLogFeatures, PerflogMetric, ReflectiveInjector, WebDriverExtension} from '../../index';
import {StringMapWrapper} from '../../src/facade/collection';
import {isBlank, isPresent} from '../../src/facade/lang';
import {TraceEventFactory} from '../trace_event_factory'; import {TraceEventFactory} from '../trace_event_factory';
export function main() { export function main() {
@ -19,7 +19,7 @@ export function main() {
var eventFactory = new TraceEventFactory('timeline', 'pid0'); var eventFactory = new TraceEventFactory('timeline', 'pid0');
function createMetric( function createMetric(
perfLogs, perfLogFeatures, perfLogs: PerfLogEvent[], perfLogFeatures: PerfLogFeatures,
{microMetrics, forceGc, captureFrames, receivedData, requestCount}: { {microMetrics, forceGc, captureFrames, receivedData, requestCount}: {
microMetrics?: {[key: string]: string}, microMetrics?: {[key: string]: string},
forceGc?: boolean, forceGc?: boolean,
@ -39,7 +39,7 @@ export function main() {
Options.DEFAULT_PROVIDERS, PerflogMetric.PROVIDERS, Options.DEFAULT_PROVIDERS, PerflogMetric.PROVIDERS,
{provide: Options.MICRO_METRICS, useValue: microMetrics}, { {provide: Options.MICRO_METRICS, useValue: microMetrics}, {
provide: PerflogMetric.SET_TIMEOUT, provide: PerflogMetric.SET_TIMEOUT,
useValue: (fn, millis) => { useValue: (fn: Function, millis: number) => {
commandLog.push(['setTimeout', millis]); commandLog.push(['setTimeout', millis]);
fn(); fn();
}, },
@ -66,8 +66,8 @@ export function main() {
describe('perflog metric', () => { describe('perflog metric', () => {
function sortedKeys(stringMap) { function sortedKeys(stringMap: {[key: string]: any}) {
var res = []; var res: string[] = [];
StringMapWrapper.forEach(stringMap, (_, key) => { res.push(key); }); StringMapWrapper.forEach(stringMap, (_, key) => { res.push(key); });
res.sort(); res.sort();
return res; return res;
@ -130,7 +130,8 @@ export function main() {
describe('beginMeasure', () => { describe('beginMeasure', () => {
it('should not force gc and mark the timeline', inject([AsyncTestCompleter], (async) => { it('should not force gc and mark the timeline',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var metric = createMetric([[]], null); var metric = createMetric([[]], null);
metric.beginMeasure().then((_) => { metric.beginMeasure().then((_) => {
expect(commandLog).toEqual([['timeBegin', 'benchpress0']]); expect(commandLog).toEqual([['timeBegin', 'benchpress0']]);
@ -139,7 +140,8 @@ export function main() {
}); });
})); }));
it('should force gc and mark the timeline', inject([AsyncTestCompleter], (async) => { it('should force gc and mark the timeline',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var metric = createMetric([[]], null, {forceGc: true}); var metric = createMetric([[]], null, {forceGc: true});
metric.beginMeasure().then((_) => { metric.beginMeasure().then((_) => {
expect(commandLog).toEqual([['gc'], ['timeBegin', 'benchpress0']]); expect(commandLog).toEqual([['gc'], ['timeBegin', 'benchpress0']]);
@ -153,7 +155,7 @@ export function main() {
describe('endMeasure', () => { describe('endMeasure', () => {
it('should mark and aggregate events in between the marks', it('should mark and aggregate events in between the marks',
inject([AsyncTestCompleter], (async) => { inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var events = [[ var events = [[
eventFactory.markStart('benchpress0', 0), eventFactory.start('script', 4), eventFactory.markStart('benchpress0', 0), eventFactory.start('script', 4),
eventFactory.end('script', 6), eventFactory.markEnd('benchpress0', 10) eventFactory.end('script', 6), eventFactory.markEnd('benchpress0', 10)
@ -169,7 +171,7 @@ export function main() {
}); });
})); }));
it('should restart timing', inject([AsyncTestCompleter], (async) => { it('should restart timing', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var events = [ var events = [
[ [
eventFactory.markStart('benchpress0', 0), eventFactory.markStart('benchpress0', 0),
@ -193,7 +195,7 @@ export function main() {
})); }));
it('should loop and aggregate until the end mark is present', it('should loop and aggregate until the end mark is present',
inject([AsyncTestCompleter], (async) => { inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var events = [ var events = [
[eventFactory.markStart('benchpress0', 0), eventFactory.start('script', 1)], [eventFactory.markStart('benchpress0', 0), eventFactory.start('script', 1)],
[eventFactory.end('script', 2)], [eventFactory.end('script', 2)],
@ -215,7 +217,7 @@ export function main() {
})); }));
it('should store events after the end mark for the next call', it('should store events after the end mark for the next call',
inject([AsyncTestCompleter], (async) => { inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var events = [ var events = [
[ [
eventFactory.markStart('benchpress0', 0), eventFactory.markEnd('benchpress0', 1), eventFactory.markStart('benchpress0', 0), eventFactory.markEnd('benchpress0', 1),
@ -246,7 +248,7 @@ export function main() {
})); }));
describe('with forced gc', () => { describe('with forced gc', () => {
var events; var events: PerfLogEvent[][];
beforeEach(() => { beforeEach(() => {
events = [[ events = [[
eventFactory.markStart('benchpress0', 0), eventFactory.start('script', 4), eventFactory.markStart('benchpress0', 0), eventFactory.start('script', 4),
@ -258,7 +260,7 @@ export function main() {
]]; ]];
}); });
it('should measure forced gc', inject([AsyncTestCompleter], (async) => { it('should measure forced gc', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var metric = createMetric(events, null, {forceGc: true}); var metric = createMetric(events, null, {forceGc: true});
metric.beginMeasure().then((_) => metric.endMeasure(false)).then((data) => { metric.beginMeasure().then((_) => metric.endMeasure(false)).then((data) => {
expect(commandLog).toEqual([ expect(commandLog).toEqual([
@ -272,7 +274,8 @@ export function main() {
}); });
})); }));
it('should restart after the forced gc if needed', inject([AsyncTestCompleter], (async) => { it('should restart after the forced gc if needed',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var metric = createMetric(events, null, {forceGc: true}); var metric = createMetric(events, null, {forceGc: true});
metric.beginMeasure().then((_) => metric.endMeasure(true)).then((data) => { metric.beginMeasure().then((_) => metric.endMeasure(true)).then((data) => {
expect(commandLog[5]).toEqual(['timeEnd', 'benchpress1', 'benchpress2']); expect(commandLog[5]).toEqual(['timeEnd', 'benchpress1', 'benchpress2']);
@ -305,7 +308,8 @@ export function main() {
} }
describe('frame metrics', () => { describe('frame metrics', () => {
it('should calculate mean frame time', inject([AsyncTestCompleter], (async) => { it('should calculate mean frame time',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate( aggregate(
[ [
eventFactory.markStart('frameCapture', 0), eventFactory.instant('frame', 1), eventFactory.markStart('frameCapture', 0), eventFactory.instant('frame', 1),
@ -319,7 +323,8 @@ export function main() {
}); });
})); }));
it('should throw if no start event', inject([AsyncTestCompleter], (async) => { it('should throw if no start event',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate( aggregate(
[eventFactory.instant('frame', 4), eventFactory.markEnd('frameCapture', 5)], [eventFactory.instant('frame', 4), eventFactory.markEnd('frameCapture', 5)],
@ -332,7 +337,8 @@ export function main() {
}); });
})); }));
it('should throw if no end event', inject([AsyncTestCompleter], (async) => { it('should throw if no end event',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate( aggregate(
[eventFactory.markStart('frameCapture', 3), eventFactory.instant('frame', 4)], [eventFactory.markStart('frameCapture', 3), eventFactory.instant('frame', 4)],
@ -343,7 +349,8 @@ export function main() {
}); });
})); }));
it('should throw if trying to capture twice', inject([AsyncTestCompleter], (async) => { it('should throw if trying to capture twice',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate( aggregate(
[ [
@ -360,7 +367,7 @@ export function main() {
})); }));
it('should throw if trying to capture when frame capture is disabled', it('should throw if trying to capture when frame capture is disabled',
inject([AsyncTestCompleter], (async) => { inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate([eventFactory.markStart('frameCapture', 3)]).catch((err) => { aggregate([eventFactory.markStart('frameCapture', 3)]).catch((err) => {
expect(() => { throw err; }) expect(() => { throw err; })
.toThrowError( .toThrowError(
@ -371,7 +378,7 @@ export function main() {
})); }));
it('should throw if frame capture is enabled, but nothing is captured', it('should throw if frame capture is enabled, but nothing is captured',
inject([AsyncTestCompleter], (async) => { inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate([], {captureFrames: true}).catch((err): any => { aggregate([], {captureFrames: true}).catch((err): any => {
expect(() => { throw err; }) expect(() => { throw err; })
.toThrowError( .toThrowError(
@ -380,7 +387,8 @@ export function main() {
}); });
})); }));
it('should calculate best and worst frame time', inject([AsyncTestCompleter], (async) => { it('should calculate best and worst frame time',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate( aggregate(
[ [
eventFactory.markStart('frameCapture', 0), eventFactory.instant('frame', 1), eventFactory.markStart('frameCapture', 0), eventFactory.instant('frame', 1),
@ -397,7 +405,7 @@ export function main() {
})); }));
it('should calculate percentage of smoothness to be good', it('should calculate percentage of smoothness to be good',
inject([AsyncTestCompleter], (async) => { inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate( aggregate(
[ [
eventFactory.markStart('frameCapture', 0), eventFactory.instant('frame', 1), eventFactory.markStart('frameCapture', 0), eventFactory.instant('frame', 1),
@ -412,7 +420,7 @@ export function main() {
})); }));
it('should calculate percentage of smoothness to be bad', it('should calculate percentage of smoothness to be bad',
inject([AsyncTestCompleter], (async) => { inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate( aggregate(
[ [
eventFactory.markStart('frameCapture', 0), eventFactory.instant('frame', 1), eventFactory.markStart('frameCapture', 0), eventFactory.instant('frame', 1),
@ -429,7 +437,8 @@ export function main() {
}); });
it('should report a single interval', inject([AsyncTestCompleter], (async) => { it('should report a single interval',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate([ aggregate([
eventFactory.start('script', 0), eventFactory.end('script', 5) eventFactory.start('script', 0), eventFactory.end('script', 5)
]).then((data) => { ]).then((data) => {
@ -438,7 +447,8 @@ export function main() {
}); });
})); }));
it('should sum up multiple intervals', inject([AsyncTestCompleter], (async) => { it('should sum up multiple intervals',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate([ aggregate([
eventFactory.start('script', 0), eventFactory.end('script', 5), eventFactory.start('script', 0), eventFactory.end('script', 5),
eventFactory.start('script', 10), eventFactory.end('script', 17) eventFactory.start('script', 10), eventFactory.end('script', 17)
@ -448,21 +458,24 @@ export function main() {
}); });
})); }));
it('should ignore not started intervals', inject([AsyncTestCompleter], (async) => { it('should ignore not started intervals',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate([eventFactory.end('script', 10)]).then((data) => { aggregate([eventFactory.end('script', 10)]).then((data) => {
expect(data['scriptTime']).toBe(0); expect(data['scriptTime']).toBe(0);
async.done(); async.done();
}); });
})); }));
it('should ignore not ended intervals', inject([AsyncTestCompleter], (async) => { it('should ignore not ended intervals',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate([eventFactory.start('script', 10)]).then((data) => { aggregate([eventFactory.start('script', 10)]).then((data) => {
expect(data['scriptTime']).toBe(0); expect(data['scriptTime']).toBe(0);
async.done(); async.done();
}); });
})); }));
it('should ignore nested intervals', inject([AsyncTestCompleter], (async) => { it('should ignore nested intervals',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate([ aggregate([
eventFactory.start('script', 0), eventFactory.start('script', 5), eventFactory.start('script', 0), eventFactory.start('script', 5),
eventFactory.end('script', 10), eventFactory.end('script', 17) eventFactory.end('script', 10), eventFactory.end('script', 17)
@ -473,7 +486,7 @@ export function main() {
})); }));
it('should ignore events from different processed as the start mark', it('should ignore events from different processed as the start mark',
inject([AsyncTestCompleter], (async) => { inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var otherProcessEventFactory = new TraceEventFactory('timeline', 'pid1'); var otherProcessEventFactory = new TraceEventFactory('timeline', 'pid1');
var metric = createMetric( var metric = createMetric(
[[ [[
@ -490,7 +503,8 @@ export function main() {
}); });
})); }));
it('should support scriptTime metric', inject([AsyncTestCompleter], (async) => { it('should support scriptTime metric',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate([ aggregate([
eventFactory.start('script', 0), eventFactory.end('script', 5) eventFactory.start('script', 0), eventFactory.end('script', 5)
]).then((data) => { ]).then((data) => {
@ -499,7 +513,8 @@ export function main() {
}); });
})); }));
it('should support renderTime metric', inject([AsyncTestCompleter], (async) => { it('should support renderTime metric',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate([ aggregate([
eventFactory.start('render', 0), eventFactory.end('render', 5) eventFactory.start('render', 0), eventFactory.end('render', 5)
]).then((data) => { ]).then((data) => {
@ -508,7 +523,8 @@ export function main() {
}); });
})); }));
it('should support gcTime/gcAmount metric', inject([AsyncTestCompleter], (async) => { it('should support gcTime/gcAmount metric',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate([ aggregate([
eventFactory.start('gc', 0, {'usedHeapSize': 2500}), eventFactory.start('gc', 0, {'usedHeapSize': 2500}),
eventFactory.end('gc', 5, {'usedHeapSize': 1000}) eventFactory.end('gc', 5, {'usedHeapSize': 1000})
@ -520,7 +536,8 @@ export function main() {
}); });
})); }));
it('should support majorGcTime metric', inject([AsyncTestCompleter], (async) => { it('should support majorGcTime metric',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate([ aggregate([
eventFactory.start('gc', 0, {'usedHeapSize': 2500}), eventFactory.start('gc', 0, {'usedHeapSize': 2500}),
eventFactory.end('gc', 5, {'usedHeapSize': 1000, 'majorGc': true}) eventFactory.end('gc', 5, {'usedHeapSize': 1000, 'majorGc': true})
@ -532,7 +549,7 @@ export function main() {
})); }));
it('should support pureScriptTime = scriptTime-gcTime-renderTime', it('should support pureScriptTime = scriptTime-gcTime-renderTime',
inject([AsyncTestCompleter], (async) => { inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate([ aggregate([
eventFactory.start('script', 0), eventFactory.start('gc', 1, {'usedHeapSize': 1000}), eventFactory.start('script', 0), eventFactory.start('gc', 1, {'usedHeapSize': 1000}),
eventFactory.end('gc', 4, {'usedHeapSize': 0}), eventFactory.start('render', 4), eventFactory.end('gc', 4, {'usedHeapSize': 0}), eventFactory.start('render', 4),
@ -546,7 +563,7 @@ export function main() {
describe('receivedData', () => { describe('receivedData', () => {
it('should report received data since last navigationStart', it('should report received data since last navigationStart',
inject([AsyncTestCompleter], (async) => { inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate( aggregate(
[ [
eventFactory.instant('receivedData', 0, {'encodedDataLength': 1}), eventFactory.instant('receivedData', 0, {'encodedDataLength': 1}),
@ -566,7 +583,7 @@ export function main() {
describe('requestCount', () => { describe('requestCount', () => {
it('should report count of requests sent since last navigationStart', it('should report count of requests sent since last navigationStart',
inject([AsyncTestCompleter], (async) => { inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate( aggregate(
[ [
eventFactory.instant('sendRequest', 0), eventFactory.instant('sendRequest', 0),
@ -585,7 +602,8 @@ export function main() {
describe('microMetrics', () => { describe('microMetrics', () => {
it('should report micro metrics', inject([AsyncTestCompleter], (async) => { it('should report micro metrics',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate( aggregate(
[ [
eventFactory.markStart('mm1', 0), eventFactory.markStart('mm1', 0),
@ -599,7 +617,7 @@ export function main() {
})); }));
it('should ignore micro metrics that were not specified', it('should ignore micro metrics that were not specified',
inject([AsyncTestCompleter], (async) => { inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate([ aggregate([
eventFactory.markStart('mm1', 0), eventFactory.markStart('mm1', 0),
eventFactory.markEnd('mm1', 5), eventFactory.markEnd('mm1', 5),
@ -609,7 +627,8 @@ export function main() {
}); });
})); }));
it('should report micro metric averages', inject([AsyncTestCompleter], (async) => { it('should report micro metric averages',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate( aggregate(
[ [
eventFactory.markStart('mm1*20', 0), eventFactory.markStart('mm1*20', 0),
@ -636,12 +655,12 @@ class MockDriverExtension extends WebDriverExtension {
super(); super();
} }
timeBegin(name): Promise<any> { timeBegin(name: string): Promise<any> {
this._commandLog.push(['timeBegin', name]); this._commandLog.push(['timeBegin', name]);
return Promise.resolve(null); return Promise.resolve(null);
} }
timeEnd(name, restartName): Promise<any> { timeEnd(name: string, restartName: string): Promise<any> {
this._commandLog.push(['timeEnd', name, restartName]); this._commandLog.push(['timeEnd', name, restartName]);
return Promise.resolve(null); return Promise.resolve(null);
} }

View File

@ -8,15 +8,16 @@
import {Provider, ReflectiveInjector} from '@angular/core'; import {Provider, ReflectiveInjector} from '@angular/core';
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal'; import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {StringMapWrapper} from '@angular/facade/src/collection';
import {Json, isBlank, isPresent} from '@angular/facade/src/lang'; import {Injector, Metric, MultiMetric, Options, PerfLogEvent, PerfLogFeatures, PerflogMetric, UserMetric, WebDriverAdapter, WebDriverExtension} from '../../index';
import {Injector, Metric, MultiMetric, Options, PerfLogFeatures, PerflogMetric, UserMetric, WebDriverAdapter, WebDriverExtension} from 'benchpress/common'; import {StringMapWrapper} from '../../src/facade/collection';
import {Json, isBlank, isPresent} from '../../src/facade/lang';
export function main() { export function main() {
var wdAdapter: MockDriverAdapter; var wdAdapter: MockDriverAdapter;
function createMetric( function createMetric(
perfLogs, perfLogFeatures, perfLogs: PerfLogEvent[], perfLogFeatures: PerfLogFeatures,
{userMetrics}: {userMetrics?: {[key: string]: string}} = {}): UserMetric { {userMetrics}: {userMetrics?: {[key: string]: string}} = {}): UserMetric {
if (isBlank(perfLogFeatures)) { if (isBlank(perfLogFeatures)) {
perfLogFeatures = perfLogFeatures =
@ -26,12 +27,12 @@ export function main() {
userMetrics = StringMapWrapper.create(); userMetrics = StringMapWrapper.create();
} }
wdAdapter = new MockDriverAdapter(); wdAdapter = new MockDriverAdapter();
var bindings: Provider[] = [ var providers: Provider[] = [
Options.DEFAULT_PROVIDERS, UserMetric.PROVIDERS, Options.DEFAULT_PROVIDERS, UserMetric.PROVIDERS,
{provide: Options.USER_METRICS, useValue: userMetrics}, {provide: Options.USER_METRICS, useValue: userMetrics},
{provide: WebDriverAdapter, useValue: wdAdapter} {provide: WebDriverAdapter, useValue: wdAdapter}
]; ];
return ReflectiveInjector.resolveAndCreate(bindings).get(UserMetric); return ReflectiveInjector.resolveAndCreate(providers).get(UserMetric);
} }
describe('user metric', () => { describe('user metric', () => {
@ -45,7 +46,7 @@ export function main() {
describe('endMeasure', () => { describe('endMeasure', () => {
it('should stop measuring when all properties have numeric values', it('should stop measuring when all properties have numeric values',
inject([AsyncTestCompleter], (async) => { inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
let metric = createMetric( let metric = createMetric(
[[]], new PerfLogFeatures(), [[]], new PerfLogFeatures(),
{userMetrics: {'loadTime': 'time to load', 'content': 'time to see content'}}); {userMetrics: {'loadTime': 'time to load', 'content': 'time to see content'}});

View File

@ -6,17 +6,24 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {Provider} from '@angular/core';
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal'; import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {Date, DateWrapper, isBlank, isPresent} from '@angular/facade/src/lang';
import {ConsoleReporter, MeasureValues, ReflectiveInjector, Reporter, SampleDescription, SampleState} from 'benchpress/common'; import {ConsoleReporter, MeasureValues, ReflectiveInjector, Reporter, SampleDescription, SampleState} from '../../index';
import {Date, DateWrapper, isBlank, isPresent} from '../../src/facade/lang';
export function main() { export function main() {
describe('console reporter', () => { describe('console reporter', () => {
var reporter; var reporter: ConsoleReporter;
var log: string[]; var log: string[];
function createReporter({columnWidth = null, sampleId = null, descriptions = null, function createReporter(
metrics = null}: {columnWidth?, sampleId?, descriptions?, metrics?}) { {columnWidth = null, sampleId = null, descriptions = null, metrics = null}: {
columnWidth?: number,
sampleId?: string,
descriptions?: {[key: string]: any}[],
metrics?: {[key: string]: any}
}) {
log = []; log = [];
if (isBlank(descriptions)) { if (isBlank(descriptions)) {
descriptions = []; descriptions = [];
@ -24,17 +31,17 @@ export function main() {
if (isBlank(sampleId)) { if (isBlank(sampleId)) {
sampleId = 'null'; sampleId = 'null';
} }
var bindings = [ var providers: Provider[] = [
ConsoleReporter.PROVIDERS, { ConsoleReporter.PROVIDERS, {
provide: SampleDescription, provide: SampleDescription,
useValue: new SampleDescription(sampleId, descriptions, metrics) useValue: new SampleDescription(sampleId, descriptions, metrics)
}, },
{provide: ConsoleReporter.PRINT, useValue: (line) => log.push(line)} {provide: ConsoleReporter.PRINT, useValue: (line: string) => log.push(line)}
]; ];
if (isPresent(columnWidth)) { if (isPresent(columnWidth)) {
bindings.push({provide: ConsoleReporter.COLUMN_WIDTH, useValue: columnWidth}); providers.push({provide: ConsoleReporter.COLUMN_WIDTH, useValue: columnWidth});
} }
reporter = ReflectiveInjector.resolveAndCreate(bindings).get(ConsoleReporter); reporter = ReflectiveInjector.resolveAndCreate(providers).get(ConsoleReporter);
} }
it('should print the sample id, description and table header', () => { it('should print the sample id, description and table header', () => {
@ -82,6 +89,6 @@ export function main() {
}); });
} }
function mv(runIndex, time, values) { function mv(runIndex: number, time: number, values: {[key: string]: number}) {
return new MeasureValues(runIndex, DateWrapper.fromMillis(time), values); return new MeasureValues(runIndex, DateWrapper.fromMillis(time), values);
} }

View File

@ -7,16 +7,21 @@
*/ */
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal'; import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {DateWrapper, Json, isPresent} from '@angular/facade/src/lang';
import {MeasureValues, Options, ReflectiveInjector, SampleDescription} from 'benchpress/common'; import {JsonFileReporter, MeasureValues, Options, ReflectiveInjector, SampleDescription} from '../../index';
import {JsonFileReporter} from 'benchpress/src/reporter/json_file_reporter'; import {DateWrapper, Json, isPresent} from '../../src/facade/lang';
export function main() { export function main() {
describe('file reporter', () => { describe('file reporter', () => {
var loggedFile; var loggedFile: any;
function createReporter({sampleId, descriptions, metrics, path}) { function createReporter({sampleId, descriptions, metrics, path}: {
var bindings = [ sampleId: string,
descriptions: {[key: string]: any}[],
metrics: {[key: string]: string},
path: string
}) {
var providers = [
JsonFileReporter.PROVIDERS, { JsonFileReporter.PROVIDERS, {
provide: SampleDescription, provide: SampleDescription,
useValue: new SampleDescription(sampleId, descriptions, metrics) useValue: new SampleDescription(sampleId, descriptions, metrics)
@ -24,16 +29,17 @@ export function main() {
{provide: JsonFileReporter.PATH, useValue: path}, {provide: JsonFileReporter.PATH, useValue: path},
{provide: Options.NOW, useValue: () => DateWrapper.fromMillis(1234)}, { {provide: Options.NOW, useValue: () => DateWrapper.fromMillis(1234)}, {
provide: Options.WRITE_FILE, provide: Options.WRITE_FILE,
useValue: (filename, content) => { useValue: (filename: string, content: string) => {
loggedFile = {'filename': filename, 'content': content}; loggedFile = {'filename': filename, 'content': content};
return Promise.resolve(null); return Promise.resolve(null);
} }
} }
]; ];
return ReflectiveInjector.resolveAndCreate(bindings).get(JsonFileReporter); return ReflectiveInjector.resolveAndCreate(providers).get(JsonFileReporter);
} }
it('should write all data into a file', inject([AsyncTestCompleter], (async) => { it('should write all data into a file',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createReporter({ createReporter({
sampleId: 'someId', sampleId: 'someId',
descriptions: [{'a': 2}], descriptions: [{'a': 2}],
@ -66,6 +72,6 @@ export function main() {
}); });
} }
function mv(runIndex, time, values) { function mv(runIndex: number, time: number, values: {[key: string]: number}) {
return new MeasureValues(runIndex, DateWrapper.fromMillis(time), values); return new MeasureValues(runIndex, DateWrapper.fromMillis(time), values);
} }

View File

@ -7,15 +7,16 @@
*/ */
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal'; import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {DateWrapper} from '@angular/facade/src/lang';
import {MeasureValues, MultiReporter, ReflectiveInjector, Reporter} from 'benchpress/common'; import {MeasureValues, MultiReporter, ReflectiveInjector, Reporter} from '../../index';
import {DateWrapper} from '../../src/facade/lang';
export function main() { export function main() {
function createReporters(ids: any[]) { function createReporters(ids: any[]) {
var r = ReflectiveInjector var r = ReflectiveInjector
.resolveAndCreate([ .resolveAndCreate([
ids.map(id => { return {provide: id, useValue: new MockReporter(id)}; }), ids.map(id => { return {provide: id, useValue: new MockReporter(id)}; }),
MultiReporter.createBindings(ids) MultiReporter.provideWith(ids)
]) ])
.get(MultiReporter); .get(MultiReporter);
return Promise.resolve(r); return Promise.resolve(r);
@ -23,7 +24,8 @@ export function main() {
describe('multi reporter', () => { describe('multi reporter', () => {
it('should reportMeasureValues to all', inject([AsyncTestCompleter], (async) => { it('should reportMeasureValues to all',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var mv = new MeasureValues(0, DateWrapper.now(), {}); var mv = new MeasureValues(0, DateWrapper.now(), {});
createReporters(['m1', 'm2']).then((r) => r.reportMeasureValues(mv)).then((values) => { createReporters(['m1', 'm2']).then((r) => r.reportMeasureValues(mv)).then((values) => {
@ -32,7 +34,7 @@ export function main() {
}); });
})); }));
it('should reportSample to call', inject([AsyncTestCompleter], (async) => { it('should reportSample to call', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var completeSample = [ var completeSample = [
new MeasureValues(0, DateWrapper.now(), {}), new MeasureValues(1, DateWrapper.now(), {}) new MeasureValues(0, DateWrapper.now(), {}), new MeasureValues(1, DateWrapper.now(), {})
]; ];

View File

@ -7,22 +7,23 @@
*/ */
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal'; import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {isBlank} from '@angular/facade/src/lang';
import {Injector, Metric, Options, ReflectiveInjector, Runner, SampleDescription, SampleState, Sampler, Validator, WebDriverAdapter} from 'benchpress/common'; import {Injector, Metric, Options, ReflectiveInjector, Runner, SampleDescription, SampleState, Sampler, Validator, WebDriverAdapter} from '../index';
import {isBlank} from '../src/facade/lang';
export function main() { export function main() {
describe('runner', () => { describe('runner', () => {
var injector: ReflectiveInjector; var injector: ReflectiveInjector;
var runner; var runner: Runner;
function createRunner(defaultBindings = null): Runner { function createRunner(defaultProviders: any[] = null): Runner {
if (isBlank(defaultBindings)) { if (isBlank(defaultProviders)) {
defaultBindings = []; defaultProviders = [];
} }
runner = new Runner([ runner = new Runner([
defaultBindings, { defaultProviders, {
provide: Sampler, provide: Sampler,
useFactory: (_injector) => { useFactory: (_injector: ReflectiveInjector) => {
injector = _injector; injector = _injector;
return new MockSampler(); return new MockSampler();
}, },
@ -35,7 +36,8 @@ export function main() {
return runner; return runner;
} }
it('should set SampleDescription.id', inject([AsyncTestCompleter], (async) => { it('should set SampleDescription.id',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createRunner() createRunner()
.sample({id: 'someId'}) .sample({id: 'someId'})
.then((_) => injector.get(SampleDescription)) .then((_) => injector.get(SampleDescription))
@ -45,7 +47,8 @@ export function main() {
}); });
})); }));
it('should merge SampleDescription.description', inject([AsyncTestCompleter], (async) => { it('should merge SampleDescription.description',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createRunner([{provide: Options.DEFAULT_DESCRIPTION, useValue: {'a': 1}}]) createRunner([{provide: Options.DEFAULT_DESCRIPTION, useValue: {'a': 1}}])
.sample({ .sample({
id: 'someId', id: 'someId',
@ -61,7 +64,7 @@ export function main() {
})); }));
it('should fill SampleDescription.metrics from the Metric', it('should fill SampleDescription.metrics from the Metric',
inject([AsyncTestCompleter], (async) => { inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createRunner() createRunner()
.sample({id: 'someId'}) .sample({id: 'someId'})
.then((_) => injector.get(SampleDescription)) .then((_) => injector.get(SampleDescription))
@ -72,7 +75,8 @@ export function main() {
}); });
})); }));
it('should bind Options.EXECUTE', inject([AsyncTestCompleter], (async) => { it('should provide Options.EXECUTE',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var execute = () => {}; var execute = () => {};
createRunner().sample({id: 'someId', execute: execute}).then((_) => { createRunner().sample({id: 'someId', execute: execute}).then((_) => {
expect(injector.get(Options.EXECUTE)).toEqual(execute); expect(injector.get(Options.EXECUTE)).toEqual(execute);
@ -80,7 +84,8 @@ export function main() {
}); });
})); }));
it('should bind Options.PREPARE', inject([AsyncTestCompleter], (async) => { it('should provide Options.PREPARE',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var prepare = () => {}; var prepare = () => {};
createRunner().sample({id: 'someId', prepare: prepare}).then((_) => { createRunner().sample({id: 'someId', prepare: prepare}).then((_) => {
expect(injector.get(Options.PREPARE)).toEqual(prepare); expect(injector.get(Options.PREPARE)).toEqual(prepare);
@ -88,14 +93,16 @@ export function main() {
}); });
})); }));
it('should bind Options.MICRO_METRICS', inject([AsyncTestCompleter], (async) => { it('should provide Options.MICRO_METRICS',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createRunner().sample({id: 'someId', microMetrics: {'a': 'b'}}).then((_) => { createRunner().sample({id: 'someId', microMetrics: {'a': 'b'}}).then((_) => {
expect(injector.get(Options.MICRO_METRICS)).toEqual({'a': 'b'}); expect(injector.get(Options.MICRO_METRICS)).toEqual({'a': 'b'});
async.done(); async.done();
}); });
})); }));
it('should overwrite bindings per sample call', inject([AsyncTestCompleter], (async) => { it('should overwrite providers per sample call',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createRunner([{provide: Options.DEFAULT_DESCRIPTION, useValue: {'a': 1}}]) createRunner([{provide: Options.DEFAULT_DESCRIPTION, useValue: {'a': 1}}])
.sample({ .sample({
id: 'someId', id: 'someId',
@ -114,8 +121,8 @@ export function main() {
} }
class MockWebDriverAdapter extends WebDriverAdapter { class MockWebDriverAdapter extends WebDriverAdapter {
executeScript(script): Promise<string> { return Promise.resolve('someUserAgent'); } executeScript(script: string): Promise<string> { return Promise.resolve('someUserAgent'); }
capabilities() { return null; } capabilities(): Promise<Map<string, any>> { return null; }
} }
class MockValidator extends Validator { class MockValidator extends Validator {
@ -129,6 +136,6 @@ class MockMetric extends Metric {
} }
class MockSampler extends Sampler { class MockSampler extends Sampler {
constructor() { super(); } constructor() { super(null, null, null, null, null, null, null); }
sample(): Promise<SampleState> { return Promise.resolve(new SampleState([], [])); } sample(): Promise<SampleState> { return Promise.resolve(new SampleState([], [])); }
} }

View File

@ -7,8 +7,9 @@
*/ */
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal'; import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {Date, DateWrapper, isBlank, isPresent, stringify} from '@angular/facade/src/lang';
import {MeasureValues, Metric, Options, ReflectiveInjector, Reporter, Sampler, Validator, WebDriverAdapter} from 'benchpress/common'; import {MeasureValues, Metric, Options, ReflectiveInjector, Reporter, Sampler, Validator, WebDriverAdapter} from '../index';
import {Date, DateWrapper, isBlank, isPresent, stringify} from '../src/facade/lang';
export function main() { export function main() {
var EMPTY_EXECUTE = () => {}; var EMPTY_EXECUTE = () => {};
@ -48,10 +49,10 @@ export function main() {
} }
it('should call the prepare and execute callbacks using WebDriverAdapter.waitFor', it('should call the prepare and execute callbacks using WebDriverAdapter.waitFor',
inject([AsyncTestCompleter], (async) => { inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var log = []; var log: any[] = [];
var count = 0; var count = 0;
var driver = new MockDriverAdapter([], (callback) => { var driver = new MockDriverAdapter([], (callback: Function) => {
var result = callback(); var result = callback();
log.push(result); log.push(result);
return Promise.resolve(result); return Promise.resolve(result);
@ -71,9 +72,9 @@ export function main() {
})); }));
it('should call prepare, beginMeasure, execute, endMeasure for every iteration', it('should call prepare, beginMeasure, execute, endMeasure for every iteration',
inject([AsyncTestCompleter], (async) => { inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var workCount = 0; var workCount = 0;
var log = []; var log: any[] = [];
createSampler({ createSampler({
metric: createCountingMetric(log), metric: createCountingMetric(log),
validator: createCountingValidator(2), validator: createCountingValidator(2),
@ -96,8 +97,8 @@ export function main() {
})); }));
it('should call execute, endMeasure for every iteration if there is no prepare callback', it('should call execute, endMeasure for every iteration if there is no prepare callback',
inject([AsyncTestCompleter], (async) => { inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var log = []; var log: any[] = [];
var workCount = 0; var workCount = 0;
createSampler({ createSampler({
metric: createCountingMetric(log), metric: createCountingMetric(log),
@ -118,7 +119,7 @@ export function main() {
})); }));
it('should only collect metrics for execute and ignore metrics from prepare', it('should only collect metrics for execute and ignore metrics from prepare',
inject([AsyncTestCompleter], (async) => { inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var scriptTime = 0; var scriptTime = 0;
var iterationCount = 1; var iterationCount = 1;
createSampler({ createSampler({
@ -145,9 +146,9 @@ export function main() {
})); }));
it('should call the validator for every execution and store the valid sample', it('should call the validator for every execution and store the valid sample',
inject([AsyncTestCompleter], (async) => { inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var log = []; var log: any[] = [];
var validSample = [{}]; var validSample = [mv(null, null, {})];
createSampler({ createSampler({
metric: createCountingMetric(), metric: createCountingMetric(),
@ -171,9 +172,10 @@ export function main() {
}); });
})); }));
it('should report the metric values', inject([AsyncTestCompleter], (async) => { it('should report the metric values',
var log = []; inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var validSample = [{}]; var log: any[] = [];
var validSample = [mv(null, null, {})];
createSampler({ createSampler({
validator: createCountingValidator(2, validSample), validator: createCountingValidator(2, validSample),
metric: createCountingMetric(), metric: createCountingMetric(),
@ -201,12 +203,13 @@ export function main() {
}); });
} }
function mv(runIndex, time, values) { function mv(runIndex: number, time: number, values: {[key: string]: number}) {
return new MeasureValues(runIndex, DateWrapper.fromMillis(time), values); return new MeasureValues(runIndex, DateWrapper.fromMillis(time), values);
} }
function createCountingValidator(count, validSample = null, log = null) { function createCountingValidator(
return new MockValidator(log, (completeSample) => { count: number, validSample: MeasureValues[] = null, log: any[] = []) {
return new MockValidator(log, (completeSample: MeasureValues[]) => {
count--; count--;
if (count === 0) { if (count === 0) {
return isPresent(validSample) ? validSample : completeSample; return isPresent(validSample) ? validSample : completeSample;
@ -216,23 +219,13 @@ function createCountingValidator(count, validSample = null, log = null) {
}); });
} }
function createCountingMetric(log = null) { function createCountingMetric(log: any[] = []) {
var scriptTime = 0; var scriptTime = 0;
return new MockMetric(log, () => { return {'script': scriptTime++}; }); return new MockMetric(log, () => { return {'script': scriptTime++}; });
} }
class MockDriverAdapter extends WebDriverAdapter { class MockDriverAdapter extends WebDriverAdapter {
/** @internal */ constructor(private _log: any[] = [], private _waitFor: Function = null) { super(); }
private _log: any[];
private _waitFor: Function;
constructor(log = null, waitFor = null) {
super();
if (isBlank(log)) {
log = [];
}
this._log = log;
this._waitFor = waitFor;
}
waitFor(callback: Function): Promise<any> { waitFor(callback: Function): Promise<any> {
if (isPresent(this._waitFor)) { if (isPresent(this._waitFor)) {
return this._waitFor(callback); return this._waitFor(callback);
@ -244,15 +237,7 @@ class MockDriverAdapter extends WebDriverAdapter {
class MockValidator extends Validator { class MockValidator extends Validator {
/** @internal */ constructor(private _log: any[] = [], private _validate: Function = null) { super(); }
private _log: any[];
constructor(log = null, private _validate: Function = null) {
super();
if (isBlank(log)) {
log = [];
}
this._log = log;
}
validate(completeSample: MeasureValues[]): MeasureValues[] { validate(completeSample: MeasureValues[]): MeasureValues[] {
var stableSample = isPresent(this._validate) ? this._validate(completeSample) : completeSample; var stableSample = isPresent(this._validate) ? this._validate(completeSample) : completeSample;
this._log.push(['validate', completeSample, stableSample]); this._log.push(['validate', completeSample, stableSample]);
@ -261,20 +246,12 @@ class MockValidator extends Validator {
} }
class MockMetric extends Metric { class MockMetric extends Metric {
/** @internal */ constructor(private _log: any[] = [], private _endMeasure: Function = null) { super(); }
private _log: any[];
constructor(log = null, private _endMeasure: Function = null) {
super();
if (isBlank(log)) {
log = [];
}
this._log = log;
}
beginMeasure() { beginMeasure() {
this._log.push(['beginMeasure']); this._log.push(['beginMeasure']);
return Promise.resolve(null); return Promise.resolve(null);
} }
endMeasure(restart) { endMeasure(restart: boolean) {
var measureValues = isPresent(this._endMeasure) ? this._endMeasure() : {}; var measureValues = isPresent(this._endMeasure) ? this._endMeasure() : {};
this._log.push(['endMeasure', restart, measureValues]); this._log.push(['endMeasure', restart, measureValues]);
return Promise.resolve(measureValues); return Promise.resolve(measureValues);
@ -282,20 +259,12 @@ class MockMetric extends Metric {
} }
class MockReporter extends Reporter { class MockReporter extends Reporter {
/** @internal */ constructor(private _log: any[] = []) { super(); }
private _log: any[]; reportMeasureValues(values: MeasureValues): Promise<any> {
constructor(log = null) {
super();
if (isBlank(log)) {
log = [];
}
this._log = log;
}
reportMeasureValues(values): Promise<any> {
this._log.push(['reportMeasureValues', values]); this._log.push(['reportMeasureValues', values]);
return Promise.resolve(null); return Promise.resolve(null);
} }
reportSample(completeSample, validSample): Promise<any> { reportSample(completeSample: MeasureValues[], validSample: MeasureValues[]): Promise<any> {
this._log.push(['reportSample', completeSample, validSample]); this._log.push(['reportSample', completeSample, validSample]);
return Promise.resolve(null); return Promise.resolve(null);
} }

View File

@ -7,7 +7,7 @@
*/ */
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal'; import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {Statistic} from 'benchpress/src/statistic'; import {Statistic} from '../src/statistic';
export function main() { export function main() {
describe('statistic', () => { describe('statistic', () => {

View File

@ -6,36 +6,34 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {isPresent} from '@angular/facade/src/lang'; import {PerfLogEvent} from '../index';
import {isPresent} from '../src/facade/lang';
export class TraceEventFactory { export class TraceEventFactory {
private _cat: string; constructor(private _cat: string, private _pid: string) {}
private _pid;
constructor(cat, pid) { create(ph: any, name: string, time: number, args: any = null) {
this._cat = cat; var res:
this._pid = pid; PerfLogEvent = {'name': name, 'cat': this._cat, 'ph': ph, 'ts': time, 'pid': this._pid};
}
create(ph, name, time, args = null) {
var res = {'name': name, 'cat': this._cat, 'ph': ph, 'ts': time, 'pid': this._pid};
if (isPresent(args)) { if (isPresent(args)) {
res['args'] = args; res['args'] = args;
} }
return res; return res;
} }
markStart(name, time) { return this.create('b', name, time); } markStart(name: string, time: number) { return this.create('b', name, time); }
markEnd(name, time) { return this.create('e', name, time); } markEnd(name: string, time: number) { return this.create('e', name, time); }
start(name, time, args = null) { return this.create('B', name, time, args); } start(name: string, time: number, args: any = null) { return this.create('B', name, time, args); }
end(name, time, args = null) { return this.create('E', name, time, args); } end(name: string, time: number, args: any = null) { return this.create('E', name, time, args); }
instant(name, time, args = null) { return this.create('i', name, time, args); } instant(name: string, time: number, args: any = null) {
return this.create('i', name, time, args);
}
complete(name, time, duration, args = null) { complete(name: string, time: number, duration: number, args: any = null) {
var res = this.create('X', name, time, args); var res = this.create('X', name, time, args);
res['dur'] = duration; res['dur'] = duration;
return res; return res;

View File

@ -7,15 +7,16 @@
*/ */
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal'; import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {ListWrapper} from '@angular/facade/src/collection';
import {Date, DateWrapper} from '@angular/facade/src/lang'; import {MeasureValues, ReflectiveInjector, RegressionSlopeValidator} from '../../index';
import {MeasureValues, ReflectiveInjector, RegressionSlopeValidator} from 'benchpress/common'; import {ListWrapper} from '../../src/facade/collection';
import {Date, DateWrapper} from '../../src/facade/lang';
export function main() { export function main() {
describe('regression slope validator', () => { describe('regression slope validator', () => {
var validator; var validator: RegressionSlopeValidator;
function createValidator({size, metric}) { function createValidator({size, metric}: {size: number, metric: string}) {
validator = ReflectiveInjector validator = ReflectiveInjector
.resolveAndCreate([ .resolveAndCreate([
RegressionSlopeValidator.PROVIDERS, RegressionSlopeValidator.PROVIDERS,
@ -60,6 +61,6 @@ export function main() {
}); });
} }
function mv(runIndex, time, values) { function mv(runIndex: number, time: number, values: {[key: string]: number}) {
return new MeasureValues(runIndex, DateWrapper.fromMillis(time), values); return new MeasureValues(runIndex, DateWrapper.fromMillis(time), values);
} }

View File

@ -7,15 +7,16 @@
*/ */
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal'; import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {ListWrapper} from '@angular/facade/src/collection';
import {Date, DateWrapper} from '@angular/facade/src/lang'; import {MeasureValues, ReflectiveInjector, SizeValidator, Validator} from '../../index';
import {MeasureValues, ReflectiveInjector, SizeValidator, Validator} from 'benchpress/common'; import {ListWrapper} from '../../src/facade/collection';
import {Date, DateWrapper} from '../../src/facade/lang';
export function main() { export function main() {
describe('size validator', () => { describe('size validator', () => {
var validator; var validator: SizeValidator;
function createValidator(size) { function createValidator(size: number) {
validator = validator =
ReflectiveInjector ReflectiveInjector
.resolveAndCreate( .resolveAndCreate(
@ -45,6 +46,6 @@ export function main() {
}); });
} }
function mv(runIndex, time, values) { function mv(runIndex: number, time: number, values: {[key: string]: number}) {
return new MeasureValues(runIndex, DateWrapper.fromMillis(time), values); return new MeasureValues(runIndex, DateWrapper.fromMillis(time), values);
} }

View File

@ -7,17 +7,19 @@
*/ */
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal'; import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {StringWrapper, isPresent} from '@angular/facade/src/lang';
import {Options, ReflectiveInjector, WebDriverExtension} from 'benchpress/common'; import {Options, ReflectiveInjector, WebDriverExtension} from '../index';
import {StringWrapper, isPresent} from '../src/facade/lang';
export function main() { export function main() {
function createExtension(ids: any[], caps) { function createExtension(ids: any[], caps: any) {
return new Promise<any>((res, rej) => { return new Promise<any>((res, rej) => {
try { try {
res(ReflectiveInjector res(ReflectiveInjector
.resolveAndCreate([ .resolveAndCreate([
ids.map((id) => { return {provide: id, useValue: new MockExtension(id)}; }), ids.map((id) => { return {provide: id, useValue: new MockExtension(id)}; }),
{provide: Options.CAPABILITIES, useValue: caps}, WebDriverExtension.bindTo(ids) {provide: Options.CAPABILITIES, useValue: caps},
WebDriverExtension.provideFirstSupported(ids)
]) ])
.get(WebDriverExtension)); .get(WebDriverExtension));
} catch (e) { } catch (e) {
@ -26,17 +28,18 @@ export function main() {
}); });
} }
describe('WebDriverExtension.bindTo', () => { describe('WebDriverExtension.provideFirstSupported', () => {
it('should bind the extension that matches the capabilities', it('should provide the extension that matches the capabilities',
inject([AsyncTestCompleter], (async) => { inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension(['m1', 'm2', 'm3'], {'browser': 'm2'}).then((m) => { createExtension(['m1', 'm2', 'm3'], {'browser': 'm2'}).then((m) => {
expect(m.id).toEqual('m2'); expect(m.id).toEqual('m2');
async.done(); async.done();
}); });
})); }));
it('should throw if there is no match', inject([AsyncTestCompleter], (async) => { it('should throw if there is no match',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension(['m1'], {'browser': 'm2'}).catch((err) => { createExtension(['m1'], {'browser': 'm2'}).catch((err) => {
expect(isPresent(err)).toBe(true); expect(isPresent(err)).toBe(true);
async.done(); async.done();
@ -46,12 +49,7 @@ export function main() {
} }
class MockExtension extends WebDriverExtension { class MockExtension extends WebDriverExtension {
id: string; constructor(public id: string) { super(); }
constructor(id) {
super();
this.id = id;
}
supports(capabilities: {[key: string]: any}): boolean { supports(capabilities: {[key: string]: any}): boolean {
return StringWrapper.equals(capabilities['browser'], this.id); return StringWrapper.equals(capabilities['browser'], this.id);

View File

@ -7,9 +7,9 @@
*/ */
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal'; import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {Json, isBlank} from '@angular/facade/src/lang';
import {ChromeDriverExtension, Options, ReflectiveInjector, WebDriverAdapter, WebDriverExtension} from 'benchpress/common';
import {ChromeDriverExtension, Options, ReflectiveInjector, WebDriverAdapter, WebDriverExtension} from '../../index';
import {Json, isBlank} from '../../src/facade/lang';
import {TraceEventFactory} from '../trace_event_factory'; import {TraceEventFactory} from '../trace_event_factory';
export function main() { export function main() {
@ -19,8 +19,8 @@ export function main() {
var CHROME45_USER_AGENT = var CHROME45_USER_AGENT =
'"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2499.0 Safari/537.36"'; '"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2499.0 Safari/537.36"';
var log; var log: any[];
var extension; var extension: ChromeDriverExtension;
var blinkEvents = new TraceEventFactory('blink.console', 'pid0'); var blinkEvents = new TraceEventFactory('blink.console', 'pid0');
var v8Events = new TraceEventFactory('v8', 'pid0'); var v8Events = new TraceEventFactory('v8', 'pid0');
@ -35,7 +35,7 @@ export function main() {
var normEvents = new TraceEventFactory('timeline', 'pid0'); var normEvents = new TraceEventFactory('timeline', 'pid0');
function createExtension( function createExtension(
perfRecords = null, userAgent = null, perfRecords: any[] = null, userAgent: string = null,
messageMethod = 'Tracing.dataCollected'): WebDriverExtension { messageMethod = 'Tracing.dataCollected'): WebDriverExtension {
if (isBlank(perfRecords)) { if (isBlank(perfRecords)) {
perfRecords = []; perfRecords = [];
@ -56,21 +56,24 @@ export function main() {
return extension; return extension;
} }
it('should force gc via window.gc()', inject([AsyncTestCompleter], (async) => { it('should force gc via window.gc()',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension().gc().then((_) => { createExtension().gc().then((_) => {
expect(log).toEqual([['executeScript', 'window.gc()']]); expect(log).toEqual([['executeScript', 'window.gc()']]);
async.done(); async.done();
}); });
})); }));
it('should mark the timeline via console.time()', inject([AsyncTestCompleter], (async) => { it('should mark the timeline via console.time()',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension().timeBegin('someName').then((_) => { createExtension().timeBegin('someName').then((_) => {
expect(log).toEqual([['executeScript', `console.time('someName');`]]); expect(log).toEqual([['executeScript', `console.time('someName');`]]);
async.done(); async.done();
}); });
})); }));
it('should mark the timeline via console.timeEnd()', inject([AsyncTestCompleter], (async) => { it('should mark the timeline via console.timeEnd()',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension().timeEnd('someName', null).then((_) => { createExtension().timeEnd('someName', null).then((_) => {
expect(log).toEqual([['executeScript', `console.timeEnd('someName');`]]); expect(log).toEqual([['executeScript', `console.timeEnd('someName');`]]);
async.done(); async.done();
@ -78,7 +81,7 @@ export function main() {
})); }));
it('should mark the timeline via console.time() and console.timeEnd()', it('should mark the timeline via console.time() and console.timeEnd()',
inject([AsyncTestCompleter], (async) => { inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension().timeEnd('name1', 'name2').then((_) => { createExtension().timeEnd('name1', 'name2').then((_) => {
expect(log).toEqual( expect(log).toEqual(
[['executeScript', `console.timeEnd('name1');console.time('name2');`]]); [['executeScript', `console.timeEnd('name1');console.time('name2');`]]);
@ -88,7 +91,7 @@ export function main() {
describe('readPerfLog Chrome44', () => { describe('readPerfLog Chrome44', () => {
it('should normalize times to ms and forward ph and pid event properties', it('should normalize times to ms and forward ph and pid event properties',
inject([AsyncTestCompleter], (async) => { inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([chromeTimelineEvents.complete('FunctionCall', 1100, 5500, null)]) createExtension([chromeTimelineEvents.complete('FunctionCall', 1100, 5500, null)])
.readPerfLog() .readPerfLog()
.then((events) => { .then((events) => {
@ -99,8 +102,9 @@ export function main() {
}); });
})); }));
it('should normalize "tdur" to "dur"', inject([AsyncTestCompleter], (async) => { it('should normalize "tdur" to "dur"',
var event = chromeTimelineEvents.create('X', 'FunctionCall', 1100, null); inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var event: any = chromeTimelineEvents.create('X', 'FunctionCall', 1100, null);
event['tdur'] = 5500; event['tdur'] = 5500;
createExtension([event]).readPerfLog().then((events) => { createExtension([event]).readPerfLog().then((events) => {
expect(events).toEqual([ expect(events).toEqual([
@ -110,7 +114,8 @@ export function main() {
}); });
})); }));
it('should report FunctionCall events as "script"', inject([AsyncTestCompleter], (async) => { it('should report FunctionCall events as "script"',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([chromeTimelineEvents.start('FunctionCall', 0)]) createExtension([chromeTimelineEvents.start('FunctionCall', 0)])
.readPerfLog() .readPerfLog()
.then((events) => { .then((events) => {
@ -121,7 +126,7 @@ export function main() {
}); });
})); }));
it('should report gc', inject([AsyncTestCompleter], (async) => { it('should report gc', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([ createExtension([
chromeTimelineEvents.start('GCEvent', 1000, {'usedHeapSizeBefore': 1000}), chromeTimelineEvents.start('GCEvent', 1000, {'usedHeapSizeBefore': 1000}),
chromeTimelineEvents.end('GCEvent', 2000, {'usedHeapSizeAfter': 0}), chromeTimelineEvents.end('GCEvent', 2000, {'usedHeapSizeAfter': 0}),
@ -137,7 +142,7 @@ export function main() {
})); }));
it('should ignore major gc from different processes', it('should ignore major gc from different processes',
inject([AsyncTestCompleter], (async) => { inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([ createExtension([
chromeTimelineEvents.start('GCEvent', 1000, {'usedHeapSizeBefore': 1000}), chromeTimelineEvents.start('GCEvent', 1000, {'usedHeapSizeBefore': 1000}),
v8EventsOtherProcess.start('majorGC', 1100, null), v8EventsOtherProcess.start('majorGC', 1100, null),
@ -154,7 +159,7 @@ export function main() {
}); });
})); }));
it('should report major gc', inject([AsyncTestCompleter], (async) => { it('should report major gc', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([ createExtension([
chromeTimelineEvents.start('GCEvent', 1000, {'usedHeapSizeBefore': 1000}), chromeTimelineEvents.start('GCEvent', 1000, {'usedHeapSizeBefore': 1000}),
v8Events.start('majorGC', 1100, null), v8Events.start('majorGC', 1100, null),
@ -172,7 +177,8 @@ export function main() {
})); }));
['RecalculateStyles', 'Layout', 'UpdateLayerTree', 'Paint'].forEach((recordType) => { ['RecalculateStyles', 'Layout', 'UpdateLayerTree', 'Paint'].forEach((recordType) => {
it(`should report ${recordType} as "render"`, inject([AsyncTestCompleter], (async) => { it(`should report ${recordType} as "render"`,
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([ createExtension([
chromeTimelineEvents.start(recordType, 1234), chromeTimelineEvents.start(recordType, 1234),
chromeTimelineEvents.end(recordType, 2345) chromeTimelineEvents.end(recordType, 2345)
@ -188,7 +194,8 @@ export function main() {
})); }));
}); });
it('should ignore FunctionCalls from webdriver', inject([AsyncTestCompleter], (async) => { it('should ignore FunctionCalls from webdriver',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([chromeTimelineEvents.start( createExtension([chromeTimelineEvents.start(
'FunctionCall', 0, {'data': {'scriptName': 'InjectedScript'}})]) 'FunctionCall', 0, {'data': {'scriptName': 'InjectedScript'}})])
.readPerfLog() .readPerfLog()
@ -203,7 +210,7 @@ export function main() {
describe('readPerfLog Chrome45', () => { describe('readPerfLog Chrome45', () => {
it('should normalize times to ms and forward ph and pid event properties', it('should normalize times to ms and forward ph and pid event properties',
inject([AsyncTestCompleter], (async) => { inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension( createExtension(
[chromeTimelineV8Events.complete('FunctionCall', 1100, 5500, null)], [chromeTimelineV8Events.complete('FunctionCall', 1100, 5500, null)],
CHROME45_USER_AGENT) CHROME45_USER_AGENT)
@ -216,8 +223,9 @@ export function main() {
}); });
})); }));
it('should normalize "tdur" to "dur"', inject([AsyncTestCompleter], (async) => { it('should normalize "tdur" to "dur"',
var event = chromeTimelineV8Events.create('X', 'FunctionCall', 1100, null); inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var event: any = chromeTimelineV8Events.create('X', 'FunctionCall', 1100, null);
event['tdur'] = 5500; event['tdur'] = 5500;
createExtension([event], CHROME45_USER_AGENT).readPerfLog().then((events) => { createExtension([event], CHROME45_USER_AGENT).readPerfLog().then((events) => {
expect(events).toEqual([ expect(events).toEqual([
@ -227,7 +235,8 @@ export function main() {
}); });
})); }));
it('should report FunctionCall events as "script"', inject([AsyncTestCompleter], (async) => { it('should report FunctionCall events as "script"',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([chromeTimelineV8Events.start('FunctionCall', 0)], CHROME45_USER_AGENT) createExtension([chromeTimelineV8Events.start('FunctionCall', 0)], CHROME45_USER_AGENT)
.readPerfLog() .readPerfLog()
.then((events) => { .then((events) => {
@ -238,7 +247,7 @@ export function main() {
}); });
})); }));
it('should report minor gc', inject([AsyncTestCompleter], (async) => { it('should report minor gc', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension( createExtension(
[ [
chromeTimelineV8Events.start('MinorGC', 1000, {'usedHeapSizeBefore': 1000}), chromeTimelineV8Events.start('MinorGC', 1000, {'usedHeapSizeBefore': 1000}),
@ -256,7 +265,7 @@ export function main() {
}); });
})); }));
it('should report major gc', inject([AsyncTestCompleter], (async) => { it('should report major gc', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension( createExtension(
[ [
chromeTimelineV8Events.start('MajorGC', 1000, {'usedHeapSizeBefore': 1000}), chromeTimelineV8Events.start('MajorGC', 1000, {'usedHeapSizeBefore': 1000}),
@ -275,7 +284,8 @@ export function main() {
})); }));
['Layout', 'UpdateLayerTree', 'Paint'].forEach((recordType) => { ['Layout', 'UpdateLayerTree', 'Paint'].forEach((recordType) => {
it(`should report ${recordType} as "render"`, inject([AsyncTestCompleter], (async) => { it(`should report ${recordType} as "render"`,
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension( createExtension(
[ [
chrome45TimelineEvents.start(recordType, 1234), chrome45TimelineEvents.start(recordType, 1234),
@ -293,7 +303,8 @@ export function main() {
})); }));
}); });
it(`should report UpdateLayoutTree as "render"`, inject([AsyncTestCompleter], (async) => { it(`should report UpdateLayoutTree as "render"`,
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension( createExtension(
[ [
chromeBlinkTimelineEvents.start('UpdateLayoutTree', 1234), chromeBlinkTimelineEvents.start('UpdateLayoutTree', 1234),
@ -312,7 +323,8 @@ export function main() {
it('should ignore FunctionCalls from webdriver', inject([AsyncTestCompleter], (async) => { it('should ignore FunctionCalls from webdriver',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([chromeTimelineV8Events.start( createExtension([chromeTimelineV8Events.start(
'FunctionCall', 0, {'data': {'scriptName': 'InjectedScript'}})]) 'FunctionCall', 0, {'data': {'scriptName': 'InjectedScript'}})])
.readPerfLog() .readPerfLog()
@ -323,7 +335,7 @@ export function main() {
})); }));
it('should ignore FunctionCalls with empty scriptName', it('should ignore FunctionCalls with empty scriptName',
inject([AsyncTestCompleter], (async) => { inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension( createExtension(
[chromeTimelineV8Events.start('FunctionCall', 0, {'data': {'scriptName': ''}})]) [chromeTimelineV8Events.start('FunctionCall', 0, {'data': {'scriptName': ''}})])
.readPerfLog() .readPerfLog()
@ -333,7 +345,8 @@ export function main() {
}); });
})); }));
it('should report navigationStart', inject([AsyncTestCompleter], (async) => { it('should report navigationStart',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension( createExtension(
[chromeBlinkUserTimingEvents.start('navigationStart', 1234)], CHROME45_USER_AGENT) [chromeBlinkUserTimingEvents.start('navigationStart', 1234)], CHROME45_USER_AGENT)
.readPerfLog() .readPerfLog()
@ -343,7 +356,7 @@ export function main() {
}); });
})); }));
it('should report receivedData', inject([AsyncTestCompleter], (async) => { it('should report receivedData', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension( createExtension(
[chrome45TimelineEvents.instant( [chrome45TimelineEvents.instant(
'ResourceReceivedData', 1234, {'data': {'encodedDataLength': 987}})], 'ResourceReceivedData', 1234, {'data': {'encodedDataLength': 987}})],
@ -356,7 +369,7 @@ export function main() {
}); });
})); }));
it('should report sendRequest', inject([AsyncTestCompleter], (async) => { it('should report sendRequest', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension( createExtension(
[chrome45TimelineEvents.instant( [chrome45TimelineEvents.instant(
'ResourceSendRequest', 1234, 'ResourceSendRequest', 1234,
@ -374,7 +387,7 @@ export function main() {
describe('readPerfLog (common)', () => { describe('readPerfLog (common)', () => {
it('should execute a dummy script before reading them', it('should execute a dummy script before reading them',
inject([AsyncTestCompleter], (async) => { inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
// TODO(tbosch): This seems to be a bug in ChromeDriver: // TODO(tbosch): This seems to be a bug in ChromeDriver:
// Sometimes it does not report the newest events of the performance log // Sometimes it does not report the newest events of the performance log
// to the WebDriver client unless a script is executed... // to the WebDriver client unless a script is executed...
@ -385,7 +398,8 @@ export function main() {
})); }));
['Rasterize', 'CompositeLayers'].forEach((recordType) => { ['Rasterize', 'CompositeLayers'].forEach((recordType) => {
it(`should report ${recordType} as "render"`, inject([AsyncTestCompleter], (async) => { it(`should report ${recordType} as "render"`,
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension( createExtension(
[ [
chromeTimelineEvents.start(recordType, 1234), chromeTimelineEvents.start(recordType, 1234),
@ -405,7 +419,7 @@ export function main() {
describe('frame metrics', () => { describe('frame metrics', () => {
it('should report ImplThreadRenderingStats as frame event', it('should report ImplThreadRenderingStats as frame event',
inject([AsyncTestCompleter], (async) => { inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([benchmarkEvents.instant( createExtension([benchmarkEvents.instant(
'BenchmarkInstrumentation::ImplThreadRenderingStats', 1100, 'BenchmarkInstrumentation::ImplThreadRenderingStats', 1100,
{'data': {'frame_count': 1}})]) {'data': {'frame_count': 1}})])
@ -419,7 +433,7 @@ export function main() {
})); }));
it('should not report ImplThreadRenderingStats with zero frames', it('should not report ImplThreadRenderingStats with zero frames',
inject([AsyncTestCompleter], (async) => { inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([benchmarkEvents.instant( createExtension([benchmarkEvents.instant(
'BenchmarkInstrumentation::ImplThreadRenderingStats', 1100, 'BenchmarkInstrumentation::ImplThreadRenderingStats', 1100,
{'data': {'frame_count': 0}})]) {'data': {'frame_count': 0}})])
@ -431,7 +445,7 @@ export function main() {
})); }));
it('should throw when ImplThreadRenderingStats contains more than one frame', it('should throw when ImplThreadRenderingStats contains more than one frame',
inject([AsyncTestCompleter], (async) => { inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([benchmarkEvents.instant( createExtension([benchmarkEvents.instant(
'BenchmarkInstrumentation::ImplThreadRenderingStats', 1100, 'BenchmarkInstrumentation::ImplThreadRenderingStats', 1100,
@ -447,7 +461,8 @@ export function main() {
}); });
it('should report begin timestamps', inject([AsyncTestCompleter], (async) => { it('should report begin timestamps',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([blinkEvents.create('S', 'someName', 1000)]) createExtension([blinkEvents.create('S', 'someName', 1000)])
.readPerfLog() .readPerfLog()
.then((events) => { .then((events) => {
@ -456,7 +471,8 @@ export function main() {
}); });
})); }));
it('should report end timestamps', inject([AsyncTestCompleter], (async) => { it('should report end timestamps',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([blinkEvents.create('F', 'someName', 1000)]) createExtension([blinkEvents.create('F', 'someName', 1000)])
.readPerfLog() .readPerfLog()
.then((events) => { .then((events) => {
@ -465,7 +481,8 @@ export function main() {
}); });
})); }));
it('should throw an error on buffer overflow', inject([AsyncTestCompleter], (async) => { it('should throw an error on buffer overflow',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension( createExtension(
[ [
@ -497,12 +514,12 @@ class MockDriverAdapter extends WebDriverAdapter {
super(); super();
} }
executeScript(script) { executeScript(script: string) {
this._log.push(['executeScript', script]); this._log.push(['executeScript', script]);
return Promise.resolve(null); return Promise.resolve(null);
} }
logs(type) { logs(type: string) {
this._log.push(['logs', type]); this._log.push(['logs', type]);
if (type === 'performance') { if (type === 'performance') {
return Promise.resolve(this._events.map((event) => { return Promise.resolve(this._events.map((event) => {

View File

@ -7,19 +7,19 @@
*/ */
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal'; import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {Json, isBlank, isPresent} from '@angular/facade/src/lang';
import {IOsDriverExtension, ReflectiveInjector, WebDriverAdapter, WebDriverExtension} from 'benchpress/common';
import {IOsDriverExtension, ReflectiveInjector, WebDriverAdapter, WebDriverExtension} from '../../index';
import {Json, isBlank, isPresent} from '../../src/facade/lang';
import {TraceEventFactory} from '../trace_event_factory'; import {TraceEventFactory} from '../trace_event_factory';
export function main() { export function main() {
describe('ios driver extension', () => { describe('ios driver extension', () => {
var log; var log: any[];
var extension; var extension: IOsDriverExtension;
var normEvents = new TraceEventFactory('timeline', 'pid0'); var normEvents = new TraceEventFactory('timeline', 'pid0');
function createExtension(perfRecords = null): WebDriverExtension { function createExtension(perfRecords: any[] = null): WebDriverExtension {
if (isBlank(perfRecords)) { if (isBlank(perfRecords)) {
perfRecords = []; perfRecords = [];
} }
@ -38,14 +38,16 @@ export function main() {
expect(() => createExtension().gc()).toThrowError('Force GC is not supported on iOS'); expect(() => createExtension().gc()).toThrowError('Force GC is not supported on iOS');
}); });
it('should mark the timeline via console.time()', inject([AsyncTestCompleter], (async) => { it('should mark the timeline via console.time()',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension().timeBegin('someName').then((_) => { createExtension().timeBegin('someName').then((_) => {
expect(log).toEqual([['executeScript', `console.time('someName');`]]); expect(log).toEqual([['executeScript', `console.time('someName');`]]);
async.done(); async.done();
}); });
})); }));
it('should mark the timeline via console.timeEnd()', inject([AsyncTestCompleter], (async) => { it('should mark the timeline via console.timeEnd()',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension().timeEnd('someName', null).then((_) => { createExtension().timeEnd('someName', null).then((_) => {
expect(log).toEqual([['executeScript', `console.timeEnd('someName');`]]); expect(log).toEqual([['executeScript', `console.timeEnd('someName');`]]);
async.done(); async.done();
@ -53,7 +55,7 @@ export function main() {
})); }));
it('should mark the timeline via console.time() and console.timeEnd()', it('should mark the timeline via console.time() and console.timeEnd()',
inject([AsyncTestCompleter], (async) => { inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension().timeEnd('name1', 'name2').then((_) => { createExtension().timeEnd('name1', 'name2').then((_) => {
expect(log).toEqual( expect(log).toEqual(
[['executeScript', `console.timeEnd('name1');console.time('name2');`]]); [['executeScript', `console.timeEnd('name1');console.time('name2');`]]);
@ -64,7 +66,7 @@ export function main() {
describe('readPerfLog', () => { describe('readPerfLog', () => {
it('should execute a dummy script before reading them', it('should execute a dummy script before reading them',
inject([AsyncTestCompleter], (async) => { inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
// TODO(tbosch): This seems to be a bug in ChromeDriver: // TODO(tbosch): This seems to be a bug in ChromeDriver:
// Sometimes it does not report the newest events of the performance log // Sometimes it does not report the newest events of the performance log
// to the WebDriver client unless a script is executed... // to the WebDriver client unless a script is executed...
@ -74,28 +76,31 @@ export function main() {
}); });
})); }));
it('should report FunctionCall records as "script"', inject([AsyncTestCompleter], (async) => { it('should report FunctionCall records as "script"',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([durationRecord('FunctionCall', 1, 5)]).readPerfLog().then((events) => { createExtension([durationRecord('FunctionCall', 1, 5)]).readPerfLog().then((events) => {
expect(events).toEqual([normEvents.start('script', 1), normEvents.end('script', 5)]); expect(events).toEqual([normEvents.start('script', 1), normEvents.end('script', 5)]);
async.done(); async.done();
}); });
})); }));
it('should ignore FunctionCalls from webdriver', inject([AsyncTestCompleter], (async) => { it('should ignore FunctionCalls from webdriver',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([internalScriptRecord(1, 5)]).readPerfLog().then((events) => { createExtension([internalScriptRecord(1, 5)]).readPerfLog().then((events) => {
expect(events).toEqual([]); expect(events).toEqual([]);
async.done(); async.done();
}); });
})); }));
it('should report begin time', inject([AsyncTestCompleter], (async) => { it('should report begin time', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([timeBeginRecord('someName', 12)]).readPerfLog().then((events) => { createExtension([timeBeginRecord('someName', 12)]).readPerfLog().then((events) => {
expect(events).toEqual([normEvents.markStart('someName', 12)]); expect(events).toEqual([normEvents.markStart('someName', 12)]);
async.done(); async.done();
}); });
})); }));
it('should report end timestamps', inject([AsyncTestCompleter], (async) => { it('should report end timestamps',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([timeEndRecord('someName', 12)]).readPerfLog().then((events) => { createExtension([timeEndRecord('someName', 12)]).readPerfLog().then((events) => {
expect(events).toEqual([normEvents.markEnd('someName', 12)]); expect(events).toEqual([normEvents.markEnd('someName', 12)]);
async.done(); async.done();
@ -104,7 +109,8 @@ export function main() {
['RecalculateStyles', 'Layout', 'UpdateLayerTree', 'Paint', 'Rasterize', 'CompositeLayers'] ['RecalculateStyles', 'Layout', 'UpdateLayerTree', 'Paint', 'Rasterize', 'CompositeLayers']
.forEach((recordType) => { .forEach((recordType) => {
it(`should report ${recordType}`, inject([AsyncTestCompleter], (async) => { it(`should report ${recordType}`,
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([durationRecord(recordType, 0, 1)]) createExtension([durationRecord(recordType, 0, 1)])
.readPerfLog() .readPerfLog()
.then((events) => { .then((events) => {
@ -118,7 +124,7 @@ export function main() {
}); });
it('should walk children', inject([AsyncTestCompleter], (async) => { it('should walk children', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([durationRecord('FunctionCall', 1, 5, [timeBeginRecord('someName', 2)])]) createExtension([durationRecord('FunctionCall', 1, 5, [timeBeginRecord('someName', 2)])])
.readPerfLog() .readPerfLog()
.then((events) => { .then((events) => {
@ -141,22 +147,22 @@ export function main() {
}); });
} }
function timeBeginRecord(name, time) { function timeBeginRecord(name: string, time: number) {
return {'type': 'Time', 'startTime': time, 'data': {'message': name}}; return {'type': 'Time', 'startTime': time, 'data': {'message': name}};
} }
function timeEndRecord(name, time) { function timeEndRecord(name: string, time: number) {
return {'type': 'TimeEnd', 'startTime': time, 'data': {'message': name}}; return {'type': 'TimeEnd', 'startTime': time, 'data': {'message': name}};
} }
function durationRecord(type, startTime, endTime, children = null) { function durationRecord(type: string, startTime: number, endTime: number, children: any[] = null) {
if (isBlank(children)) { if (isBlank(children)) {
children = []; children = [];
} }
return {'type': type, 'startTime': startTime, 'endTime': endTime, 'children': children}; return {'type': type, 'startTime': startTime, 'endTime': endTime, 'children': children};
} }
function internalScriptRecord(startTime, endTime) { function internalScriptRecord(startTime: number, endTime: number) {
return { return {
'type': 'FunctionCall', 'type': 'FunctionCall',
'startTime': startTime, 'startTime': startTime,
@ -168,12 +174,12 @@ function internalScriptRecord(startTime, endTime) {
class MockDriverAdapter extends WebDriverAdapter { class MockDriverAdapter extends WebDriverAdapter {
constructor(private _log: any[], private _perfRecords: any[]) { super(); } constructor(private _log: any[], private _perfRecords: any[]) { super(); }
executeScript(script) { executeScript(script: string) {
this._log.push(['executeScript', script]); this._log.push(['executeScript', script]);
return Promise.resolve(null); return Promise.resolve(null);
} }
logs(type) { logs(type: string) {
this._log.push(['logs', type]); this._log.push(['logs', type]);
if (type === 'performance') { if (type === 'performance') {
return Promise.resolve(this._perfRecords.map(function(record) { return Promise.resolve(this._perfRecords.map(function(record) {

View File

@ -0,0 +1,26 @@
{
"compilerOptions": {
"module": "commonjs",
"target": "es5",
"lib": ["es6", "dom"],
"noImplicitAny": true,
"sourceMap": true,
"baseUrl": ".",
"paths": {
"@angular/core": ["../../../dist/packages-dist/core"]
},
"experimentalDecorators": true,
"rootDir": ".",
"sourceRoot": ".",
"outDir": "../../../dist/packages-dist/benchpress",
"declaration": true
},
"exclude": ["integrationtest"],
"files": [
"index.ts",
"../../../node_modules/@types/node/index.d.ts",
"../../../node_modules/@types/jasmine/index.d.ts",
"../../node_modules/@types/protractor/index.d.ts",
"../../node_modules/@types/selenium-webdriver/index.d.ts"
]
}

View File

@ -1,23 +0,0 @@
{
"compilerOptions": {
"baseUrl": ".",
"declaration": true,
"experimentalDecorators": true,
"module": "commonjs",
"moduleResolution": "node",
"outDir": "../../dist/all/benchpress",
"noImplicitAny": false,
"noFallthroughCasesInSwitch": true,
"paths": {
"selenium-webdriver": ["../../node_modules/@types/selenium-webdriver/index.d.ts"],
"rxjs/*": ["../../node_modules/rxjs/*"],
"@angular/*": ["../../dist/all/@angular/*"],
"benchpress/*": ["./*"]
},
"rootDir": ".",
"inlineSourceMap": true,
"lib": ["es5", "dom", "es2015.promise", "es2015.collection", "es2015.iterable"],
"skipDefaultLibCheck": true,
"target": "es5"
}
}

View File

@ -1,14 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
// This file contains all ambient imports needed to compile the modules/ source code
/// <reference path="../../node_modules/@types/node/index.d.ts" />
/// <reference path="../../node_modules/@types/jasmine/index.d.ts" />
/// <reference path="../../node_modules/@types/protractor/index.d.ts" />
/// <reference path="../../node_modules/@types/selenium-webdriver/index.d.ts" />

View File

@ -28,7 +28,6 @@
"benchmarks/e2e_test/old", "benchmarks/e2e_test/old",
"benchmarks/src/old", "benchmarks/src/old",
"benchmarks_external", "benchmarks_external",
"benchpress",
"payload_tests", "payload_tests",
"rollup-test", "rollup-test",
"@angular/compiler-cli/integrationtest" "@angular/compiler-cli/integrationtest"

View File

@ -72,7 +72,8 @@ if (platform == 'node') {
processOutputEmitterCodeGen, processOutputEmitterCodeGen,
[ [
'node', 'dist/tools/cjs-jasmine', '--', '@angular/**/*_spec.js', 'node', 'dist/tools/cjs-jasmine', '--', '@angular/**/*_spec.js',
'@angular/compiler-cli/test/**/*_spec.js' '@angular/compiler-cli/test/**/*_spec.js',
'@angular/benchpress/test/**/*_spec.js'
] ]
] ]
}, },