332 lines
		
	
	
		
			9.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			332 lines
		
	
	
		
			9.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
import {
 | 
						|
  afterEach,
 | 
						|
  AsyncTestCompleter,
 | 
						|
  beforeEach,
 | 
						|
  ddescribe,
 | 
						|
  describe,
 | 
						|
  expect,
 | 
						|
  iit,
 | 
						|
  inject,
 | 
						|
  it,
 | 
						|
  xit,
 | 
						|
} from 'angular2/test_lib';
 | 
						|
 | 
						|
import { isBlank, isPresent, BaseException, stringify, Date, DateWrapper } from 'angular2/src/facade/lang';
 | 
						|
import { ListWrapper, List } from 'angular2/src/facade/collection';
 | 
						|
import { PromiseWrapper, Promise } from 'angular2/src/facade/async';
 | 
						|
 | 
						|
import {
 | 
						|
  Sampler, WebDriverAdapter,
 | 
						|
  Validator, Metric, Reporter, Browser,
 | 
						|
  bind, Injector, Options, MeasureValues
 | 
						|
} from 'benchpress/common';
 | 
						|
 | 
						|
export function main() {
 | 
						|
  var EMPTY_EXECUTE = () => {};
 | 
						|
 | 
						|
  describe('sampler', () => {
 | 
						|
    var sampler;
 | 
						|
 | 
						|
    function createSampler({
 | 
						|
      driver,
 | 
						|
      metric,
 | 
						|
      reporter,
 | 
						|
      validator,
 | 
						|
      prepare,
 | 
						|
      execute
 | 
						|
    } = {}) {
 | 
						|
      var time = 1000;
 | 
						|
      if (isBlank(metric)) {
 | 
						|
        metric = new MockMetric([]);
 | 
						|
      }
 | 
						|
      if (isBlank(reporter)) {
 | 
						|
        reporter = new MockReporter([]);
 | 
						|
      }
 | 
						|
      if (isBlank(driver)) {
 | 
						|
        driver = new MockDriverAdapter([]);
 | 
						|
      }
 | 
						|
      var bindings = [
 | 
						|
        Options.DEFAULT_BINDINGS,
 | 
						|
        Sampler.BINDINGS,
 | 
						|
        bind(Metric).toValue(metric),
 | 
						|
        bind(Reporter).toValue(reporter),
 | 
						|
        bind(WebDriverAdapter).toValue(driver),
 | 
						|
        bind(Options.EXECUTE).toValue(execute),
 | 
						|
        bind(Validator).toValue(validator),
 | 
						|
        bind(Options.NOW).toValue( () => DateWrapper.fromMillis(time++) )
 | 
						|
      ];
 | 
						|
      if (isPresent(prepare)) {
 | 
						|
        ListWrapper.push(bindings, bind(Options.PREPARE).toValue(prepare));
 | 
						|
      }
 | 
						|
 | 
						|
      sampler = Injector.resolveAndCreate(bindings).get(Sampler);
 | 
						|
    }
 | 
						|
 | 
						|
    it('should call the prepare and execute callbacks using WebDriverAdapter.waitFor', inject([AsyncTestCompleter], (async) => {
 | 
						|
      var log = [];
 | 
						|
      var count = 0;
 | 
						|
      var driver = new MockDriverAdapter([], (callback) => {
 | 
						|
        var result = callback();
 | 
						|
        ListWrapper.push(log, result);
 | 
						|
        return PromiseWrapper.resolve(result);
 | 
						|
      });
 | 
						|
      createSampler({
 | 
						|
        driver: driver,
 | 
						|
        validator: createCountingValidator(2),
 | 
						|
        prepare: () => {
 | 
						|
          return count++;
 | 
						|
        },
 | 
						|
        execute: () => {
 | 
						|
          return count++;
 | 
						|
        }
 | 
						|
      });
 | 
						|
      sampler.sample().then( (_) => {
 | 
						|
        expect(count).toBe(4);
 | 
						|
        expect(log).toEqual([0,1,2,3]);
 | 
						|
        async.done();
 | 
						|
      });
 | 
						|
 | 
						|
    }));
 | 
						|
 | 
						|
    it('should call prepare, beginMeasure, execute, endMeasure for every iteration', inject([AsyncTestCompleter], (async) => {
 | 
						|
      var workCount = 0;
 | 
						|
      var log = [];
 | 
						|
      createSampler({
 | 
						|
        metric: createCountingMetric(log),
 | 
						|
        validator: createCountingValidator(2),
 | 
						|
        prepare: () => {
 | 
						|
          ListWrapper.push(log, `p${workCount++}`);
 | 
						|
        },
 | 
						|
        execute: () => {
 | 
						|
          ListWrapper.push(log, `w${workCount++}`);
 | 
						|
        }
 | 
						|
      });
 | 
						|
      sampler.sample().then( (_) => {
 | 
						|
        expect(log).toEqual([
 | 
						|
          'p0',
 | 
						|
          ['beginMeasure'],
 | 
						|
          'w1',
 | 
						|
          ['endMeasure', false, {'script': 0}],
 | 
						|
          'p2',
 | 
						|
          ['beginMeasure'],
 | 
						|
          'w3',
 | 
						|
          ['endMeasure', false, {'script': 1}],
 | 
						|
        ]);
 | 
						|
        async.done();
 | 
						|
      });
 | 
						|
    }));
 | 
						|
 | 
						|
    it('should call execute, endMeasure for every iteration if there is no prepare callback', inject([AsyncTestCompleter], (async) => {
 | 
						|
      var log = [];
 | 
						|
      var workCount = 0;
 | 
						|
      createSampler({
 | 
						|
        metric: createCountingMetric(log),
 | 
						|
        validator: createCountingValidator(2),
 | 
						|
        execute: () => {
 | 
						|
          ListWrapper.push(log, `w${workCount++}`);
 | 
						|
        },
 | 
						|
        prepare: null
 | 
						|
      });
 | 
						|
      sampler.sample().then( (_) => {
 | 
						|
        expect(log).toEqual([
 | 
						|
          ['beginMeasure'],
 | 
						|
          'w0',
 | 
						|
          ['endMeasure', true, {'script': 0}],
 | 
						|
          'w1',
 | 
						|
          ['endMeasure', true, {'script': 1}],
 | 
						|
        ]);
 | 
						|
        async.done();
 | 
						|
      });
 | 
						|
    }));
 | 
						|
 | 
						|
    it('should only collect metrics for execute and ignore metrics from prepare', inject([AsyncTestCompleter], (async) => {
 | 
						|
      var scriptTime = 0;
 | 
						|
      var iterationCount = 1;
 | 
						|
      createSampler({
 | 
						|
        validator: createCountingValidator(2),
 | 
						|
        metric: new MockMetric([], () => {
 | 
						|
          var result = PromiseWrapper.resolve({'script': scriptTime});
 | 
						|
          scriptTime = 0;
 | 
						|
          return result;
 | 
						|
        }),
 | 
						|
        prepare: () => {
 | 
						|
          scriptTime = 1 * iterationCount;
 | 
						|
        },
 | 
						|
        execute: () => {
 | 
						|
          scriptTime = 10 * iterationCount;
 | 
						|
          iterationCount++;
 | 
						|
        }
 | 
						|
      });
 | 
						|
      sampler.sample().then( (state) => {
 | 
						|
        expect(state.completeSample.length).toBe(2);
 | 
						|
        expect(state.completeSample[0]).toEqual(mv(0, 1000, {'script': 10}));
 | 
						|
        expect(state.completeSample[1]).toEqual(mv(1, 1001, {'script': 20}));
 | 
						|
        async.done();
 | 
						|
      });
 | 
						|
    }));
 | 
						|
 | 
						|
    it('should call the validator for every execution and store the valid sample', inject([AsyncTestCompleter], (async) => {
 | 
						|
      var log = [];
 | 
						|
      var validSample = [{}];
 | 
						|
 | 
						|
      createSampler({
 | 
						|
        metric: createCountingMetric(),
 | 
						|
        validator: createCountingValidator(2, validSample, log),
 | 
						|
        execute: EMPTY_EXECUTE
 | 
						|
      });
 | 
						|
      sampler.sample().then( (state) => {
 | 
						|
        expect(state.validSample).toBe(validSample);
 | 
						|
        // TODO(tbosch): Why does this fail??
 | 
						|
        // expect(log).toEqual([
 | 
						|
        //   ['validate', [{'script': 0}], null],
 | 
						|
        //   ['validate', [{'script': 0}, {'script': 1}], validSample]
 | 
						|
        // ]);
 | 
						|
 | 
						|
        expect(log.length).toBe(2);
 | 
						|
        expect(log[0]).toEqual(
 | 
						|
          ['validate', [mv(0, 1000, {'script': 0})], null]
 | 
						|
        );
 | 
						|
        expect(log[1]).toEqual(
 | 
						|
          ['validate', [mv(0, 1000, {'script': 0}), mv(1, 1001, {'script': 1})], validSample]
 | 
						|
        );
 | 
						|
 | 
						|
        async.done();
 | 
						|
      });
 | 
						|
    }));
 | 
						|
 | 
						|
    it('should report the metric values', inject([AsyncTestCompleter], (async) => {
 | 
						|
      var log = [];
 | 
						|
      var validSample = [{}];
 | 
						|
      createSampler({
 | 
						|
        validator: createCountingValidator(2, validSample),
 | 
						|
        metric: createCountingMetric(),
 | 
						|
        reporter: new MockReporter(log),
 | 
						|
        execute: EMPTY_EXECUTE
 | 
						|
      });
 | 
						|
      sampler.sample().then( (_) => {
 | 
						|
        // TODO(tbosch): Why does this fail??
 | 
						|
        // expect(log).toEqual([
 | 
						|
        //   ['reportMeasureValues', 0, {'script': 0}],
 | 
						|
        //   ['reportMeasureValues', 1, {'script': 1}],
 | 
						|
        //   ['reportSample', [{'script': 0}, {'script': 1}], validSample]
 | 
						|
        // ]);
 | 
						|
        expect(log.length).toBe(3);
 | 
						|
        expect(log[0]).toEqual(
 | 
						|
          ['reportMeasureValues', mv(0, 1000, {'script': 0})]
 | 
						|
        );
 | 
						|
        expect(log[1]).toEqual(
 | 
						|
          ['reportMeasureValues', mv(1, 1001, {'script': 1})]
 | 
						|
        );
 | 
						|
        expect(log[2]).toEqual(
 | 
						|
          ['reportSample', [mv(0, 1000, {'script': 0}), mv(1, 1001, {'script': 1})], validSample]
 | 
						|
        );
 | 
						|
 | 
						|
        async.done();
 | 
						|
      });
 | 
						|
    }));
 | 
						|
 | 
						|
  });
 | 
						|
}
 | 
						|
 | 
						|
function mv(runIndex, time, values) {
 | 
						|
  return new MeasureValues(runIndex, DateWrapper.fromMillis(time), values);
 | 
						|
}
 | 
						|
 | 
						|
function createCountingValidator(count, validSample = null, log = null) {
 | 
						|
  return new MockValidator(log, (completeSample) => {
 | 
						|
    count--;
 | 
						|
    if (count === 0) {
 | 
						|
      return isPresent(validSample) ? validSample : completeSample;
 | 
						|
    } else {
 | 
						|
      return null;
 | 
						|
    }
 | 
						|
  });
 | 
						|
}
 | 
						|
 | 
						|
function createCountingMetric(log = null) {
 | 
						|
  var scriptTime = 0;
 | 
						|
  return new MockMetric(log, () => {
 | 
						|
    return { 'script': scriptTime++ };
 | 
						|
  });
 | 
						|
}
 | 
						|
 | 
						|
class MockDriverAdapter extends WebDriverAdapter {
 | 
						|
  _log:List;
 | 
						|
  _waitFor:Function;
 | 
						|
  constructor(log = null, waitFor = null) {
 | 
						|
    super();
 | 
						|
    if (isBlank(log)) {
 | 
						|
      log = [];
 | 
						|
    }
 | 
						|
    this._log = log;
 | 
						|
    this._waitFor = waitFor;
 | 
						|
  }
 | 
						|
  waitFor(callback:Function):Promise {
 | 
						|
    if (isPresent(this._waitFor)) {
 | 
						|
      return this._waitFor(callback);
 | 
						|
    } else {
 | 
						|
      return PromiseWrapper.resolve(callback());
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
class MockValidator extends Validator {
 | 
						|
  _validate:Function;
 | 
						|
  _log:List;
 | 
						|
  constructor(log = null, validate = null) {
 | 
						|
    super();
 | 
						|
    this._validate = validate;
 | 
						|
    if (isBlank(log)) {
 | 
						|
      log = [];
 | 
						|
    }
 | 
						|
    this._log = log;
 | 
						|
  }
 | 
						|
  validate(completeSample:List<MeasureValues>):List<MeasureValues> {
 | 
						|
    var stableSample = isPresent(this._validate) ? this._validate(completeSample) : completeSample;
 | 
						|
    ListWrapper.push(this._log, ['validate', completeSample, stableSample]);
 | 
						|
    return stableSample;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
class MockMetric extends Metric {
 | 
						|
  _endMeasure:Function;
 | 
						|
  _log:List;
 | 
						|
  constructor(log = null, endMeasure = null) {
 | 
						|
    super();
 | 
						|
    this._endMeasure = endMeasure;
 | 
						|
    if (isBlank(log)) {
 | 
						|
      log = [];
 | 
						|
    }
 | 
						|
    this._log = log;
 | 
						|
  }
 | 
						|
  beginMeasure() {
 | 
						|
    ListWrapper.push(this._log, ['beginMeasure']);
 | 
						|
    return PromiseWrapper.resolve(null);
 | 
						|
  }
 | 
						|
  endMeasure(restart) {
 | 
						|
    var measureValues = isPresent(this._endMeasure) ? this._endMeasure() : {};
 | 
						|
    ListWrapper.push(this._log, ['endMeasure', restart, measureValues]);
 | 
						|
    return PromiseWrapper.resolve(measureValues);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
class MockReporter extends Reporter {
 | 
						|
  _log:List;
 | 
						|
  constructor(log = null) {
 | 
						|
    super();
 | 
						|
    if (isBlank(log)) {
 | 
						|
      log = [];
 | 
						|
    }
 | 
						|
    this._log = log;
 | 
						|
  }
 | 
						|
  reportMeasureValues(values):Promise {
 | 
						|
    ListWrapper.push(this._log, ['reportMeasureValues', values]);
 | 
						|
    return PromiseWrapper.resolve(null);
 | 
						|
  }
 | 
						|
  reportSample(completeSample, validSample):Promise {
 | 
						|
    ListWrapper.push(this._log, ['reportSample', completeSample, validSample]);
 | 
						|
    return PromiseWrapper.resolve(null);
 | 
						|
  }
 | 
						|
}
 |