From: rniwa@webkit.org Date: Thu, 24 Mar 2016 03:25:10 +0000 (+0000) Subject: Add a model for parsing buildbot JSON with unit tests X-Git-Url: http://git.webkit.org/?p=WebKit-https.git;a=commitdiff_plain;h=3054de4a00628879120e99574972b2ece8447f6a Add a model for parsing buildbot JSON with unit tests https://bugs.webkit.org/show_bug.cgi?id=155814 Reviewed by Joseph Pecoraro. Added BuildbotSyncer and BuildbotBuildEntry classes to parse buildbot JSON files with unit tests. They will be used in the new syncing scripts to improve A/B testing. * public/v3/models/build-request.js: (BuildRequest): * tools/js/buildbot-syncer.js: Added. (BuildbotBuildEntry): Added. (BuildbotBuildEntry.prototype.slaveName): Added. (BuildbotBuildEntry.prototype.buildRequestId): Added. (BuildbotBuildEntry.prototype.isInProgress): Added. (BuildbotSyncer): Added. (BuildbotSyncer.prototype.testPath): Added. (BuildbotSyncer.prototype.builderName): Added. (BuildbotSyncer.prototype.platformName): Added. (BuildbotSyncer.prototype.fetchPendingRequests): Added. (BuildbotSyncer.prototype._propertiesForBuildRequest): Added. (BuildbotSyncer.prototype._revisionSetFromRootSetWithExclusionList): Added. (BuildbotSyncer._loadConfig): Added. (BuildbotSyncer._validateAndMergeConfig): Added. (BuildbotSyncer._validateAndMergeProperties): Added. * tools/js/v3-models.js: Copied from unit-tests/resources/v3-models.js. (beforeEach): Deleted since this only defined inside mocha. * unit-tests/analysis-task-tests.js: * unit-tests/buildbot-syncer-tests.js: Added. (sampleiOSConfig): (createSampleBuildRequest): (.smallConfiguration): * unit-tests/measurement-adaptor-tests.js: * unit-tests/measurement-set-tests.js: * unit-tests/resources/mock-v3-models.js: Renamed from unit-tests/resources/v3-models.js. (beforeEach): * unit-tests/test-groups-tests.js: (sampleTestGroup): git-svn-id: https://svn.webkit.org/repository/webkit/trunk@198614 268f45cc-cd09-0410-ab3c-d52691b4dbfc --- diff --git a/Websites/perf.webkit.org/ChangeLog b/Websites/perf.webkit.org/ChangeLog index bb6ebc2..eb6b4c4 100644 --- a/Websites/perf.webkit.org/ChangeLog +++ b/Websites/perf.webkit.org/ChangeLog @@ -1,3 +1,44 @@ +2016-03-23 Ryosuke Niwa + + Add a model for parsing buildbot JSON with unit tests + https://bugs.webkit.org/show_bug.cgi?id=155814 + + Reviewed by Joseph Pecoraro. + + Added BuildbotSyncer and BuildbotBuildEntry classes to parse buildbot JSON files with unit tests. + They will be used in the new syncing scripts to improve A/B testing. + + * public/v3/models/build-request.js: + (BuildRequest): + * tools/js/buildbot-syncer.js: Added. + (BuildbotBuildEntry): Added. + (BuildbotBuildEntry.prototype.slaveName): Added. + (BuildbotBuildEntry.prototype.buildRequestId): Added. + (BuildbotBuildEntry.prototype.isInProgress): Added. + (BuildbotSyncer): Added. + (BuildbotSyncer.prototype.testPath): Added. + (BuildbotSyncer.prototype.builderName): Added. + (BuildbotSyncer.prototype.platformName): Added. + (BuildbotSyncer.prototype.fetchPendingRequests): Added. + (BuildbotSyncer.prototype._propertiesForBuildRequest): Added. + (BuildbotSyncer.prototype._revisionSetFromRootSetWithExclusionList): Added. + (BuildbotSyncer._loadConfig): Added. + (BuildbotSyncer._validateAndMergeConfig): Added. + (BuildbotSyncer._validateAndMergeProperties): Added. + * tools/js/v3-models.js: Copied from unit-tests/resources/v3-models.js. + (beforeEach): Deleted since this only defined inside mocha. + * unit-tests/analysis-task-tests.js: + * unit-tests/buildbot-syncer-tests.js: Added. + (sampleiOSConfig): + (createSampleBuildRequest): + (.smallConfiguration): + * unit-tests/measurement-adaptor-tests.js: + * unit-tests/measurement-set-tests.js: + * unit-tests/resources/mock-v3-models.js: Renamed from unit-tests/resources/v3-models.js. + (beforeEach): + * unit-tests/test-groups-tests.js: + (sampleTestGroup): + 2016-03-22 Ryosuke Niwa Add unit tests for test-group.js diff --git a/Websites/perf.webkit.org/public/v3/models/build-request.js b/Websites/perf.webkit.org/public/v3/models/build-request.js index 0ac39d5..7077e52 100644 --- a/Websites/perf.webkit.org/public/v3/models/build-request.js +++ b/Websites/perf.webkit.org/public/v3/models/build-request.js @@ -5,9 +5,10 @@ class BuildRequest extends DataModelObject { constructor(id, object) { super(id, object); - console.assert(object.testGroup instanceof TestGroup); + console.assert(!object.testGroup || object.testGroup instanceof TestGroup); this._testGroup = object.testGroup; - this._testGroup.addBuildRequest(this); + if (this._testGroup) + this._testGroup.addBuildRequest(this); this._order = object.order; console.assert(object.rootSet instanceof RootSet); this._rootSet = object.rootSet; diff --git a/Websites/perf.webkit.org/tools/js/buildbot-syncer.js b/Websites/perf.webkit.org/tools/js/buildbot-syncer.js new file mode 100644 index 0000000..7b7b62d --- /dev/null +++ b/Websites/perf.webkit.org/tools/js/buildbot-syncer.js @@ -0,0 +1,216 @@ +'use strict'; + +let assert = require('assert'); + +require('./v3-models.js'); + +class BuildbotBuildEntry { + constructor(syncer, type, rawData) + { + assert.equal(syncer.builderName(), rawData['builderName']); + + this._slaveName = null; + this._buildRequestId = null; + this._isInProgress = 'currentStep' in rawData; + this._buildNumber = rawData['number']; + + for (var propertyTuple of (rawData['properties'] || [])) { + // e.g. ['build_request_id', '16733', 'Force Build Form'] + var name = propertyTuple[0]; + var value = propertyTuple[1]; + if (name == syncer._slavePropertyName) + this._slaveName = value; + else if (name == syncer._buildRequestPropertyName) + this._buildRequestId = value; + } + } + + slaveName() { return this._slaveName; } + buildRequestId() { return this._buildRequestId; } + isInProgress() { return this._isInProgress; } +} + +class BuildbotSyncer { + + constructor(url, object) + { + this._url = url; + this._builderName = object.builder; + this._platformName = object.platform; + this._testPath = object.test; + this._propertiesTemplate = object.properties; + this._slavePropertyName = object.slaveArgument; + this._buildRequestPropertyName = object.buildRequestArgument; + } + + testPath() { return this._testPath } + builderName() { return this._builderName; } + platformName() { return this._platformName; } + + fetchPendingRequests() + { + return RemoteAPI.fetchJSON(`${this._url}/json/builders/${this._name}/pendingBuilds`).then(function (content) { + var requests = []; + for (var entry of content) { + var properties = entry['properties']; + if (!properties) + continue; + for (var propertyTuple of properties) { + // e.g. ['build_request_id', '16733', 'Force Build Form'] + if (propertyTuple[0] == this._buildRequestPropertyName) + requests.push(propertyTuple[1]); + } + } + return requests; + }); + } + + _propertiesForBuildRequest(buildRequest) + { + console.assert(buildRequest instanceof BuildRequest); + + let rootSet = buildRequest.rootSet(); + console.assert(rootSet instanceof RootSet); + + let repositoryByName = {}; + for (let repository of rootSet.repositories()) + repositoryByName[repository.name()] = repository; + + let properties = {}; + for (let key in this._propertiesTemplate) { + let value = this._propertiesTemplate[key]; + if (typeof(value) != 'object') + properties[key] = value; + else if ('root' in value) { + let repositoryName = value['root']; + let repository = repositoryByName[repositoryName]; + assert(repository, '"${repositoryName}" must be specified'); + properties[key] = rootSet.revisionForRepository(repository); + } else if ('rootsExcluding' in value) { + let revisionSet = this._revisionSetFromRootSetWithExclusionList(rootSet, value['rootsExcluding']); + properties[key] = JSON.stringify(revisionSet); + } + } + + properties[this._buildRequestPropertyName] = buildRequest.id(); + + return properties; + } + + _revisionSetFromRootSetWithExclusionList(rootSet, exclusionList) + { + let revisionSet = {}; + for (let repository of rootSet.repositories()) { + if (exclusionList.indexOf(repository.name()) >= 0) + continue; + let commit = rootSet.commitForRepository(repository); + revisionSet[repository.name()] = { + id: commit.id(), + time: +commit.time(), + repository: repository.name(), + revision: commit.revision(), + }; + } + return revisionSet; + } + + static _loadConfig(url, config) + { + let shared = config['shared'] || {}; + let types = config['types'] || {}; + let builders = config['builders'] || {}; + + let syncers = []; + for (let entry of config['configurations']) { + let newConfig = {}; + this._validateAndMergeConfig(newConfig, shared); + + this._validateAndMergeConfig(newConfig, entry); + + let type = entry['type']; + if (type) { + assert(types[type]); + this._validateAndMergeConfig(newConfig, types[type]); + } + + let builder = entry['builder']; + if (builders[builder]) + this._validateAndMergeConfig(newConfig, builders[builder]); + + assert('platform' in newConfig, 'configuration must specify a platform'); + assert('test' in newConfig, 'configuration must specify a test'); + assert('builder' in newConfig, 'configuration must specify a builder'); + assert('properties' in newConfig, 'configuration must specify arguments to post on a builder'); + assert('buildRequestArgument' in newConfig, 'configuration must specify buildRequestArgument'); + syncers.push(new BuildbotSyncer(url, newConfig)); + } + + return syncers; + } + + static _validateAndMergeConfig(config, valuesToMerge) + { + for (let name in valuesToMerge) { + let value = valuesToMerge[name]; + switch (name) { + case 'arguments': + assert.equal(typeof(value), 'object', 'arguments should be a dictionary'); + if (!config['properties']) + config['properties'] = {}; + this._validateAndMergeProperties(config['properties'], value); + break; + case 'test': + assert(value instanceof Array, 'test should be an array'); + assert(value.every(function (part) { return typeof part == 'string'; }), 'test should be an array of strings'); + config[name] = value.slice(); + break; + case 'type': // fallthrough + case 'builder': // fallthrough + case 'platform': // fallthrough + case 'slaveArgument': // fallthrough + case 'buildRequestArgument': + assert.equal(typeof(value), 'string', `${name} should be of string type`); + config[name] = value; + break; + default: + assert(false, `Unrecognized parameter ${name}`); + } + } + } + + static _validateAndMergeProperties(properties, configArguments) + { + for (let name in configArguments) { + let value = configArguments[name]; + if (typeof(value) == 'string') { + properties[name] = value; + continue; + } + assert.equal(typeof(value), 'object', 'A argument value must be either a string or a dictionary'); + + let keys = Object.keys(value); + assert.equal(keys.length, 1, 'arguments value cannot contain more than one key'); + let namedValue = value[keys[0]]; + switch (keys[0]) { + case 'root': + assert.equal(typeof(namedValue), 'string', 'root name must be a string'); + break; + case 'rootsExcluding': + assert(namedValue instanceof Array, 'rootsExcluding must specify an array'); + for (let excludedRootName of namedValue) + assert.equal(typeof(excludedRootName), 'string', 'rootsExcluding must specify an array of strings'); + namedValue = namedValue.slice(); + break; + default: + assert(false, `Unrecognized named argument ${keys[0]}`); + } + properties[name] = {[keys[0]]: namedValue}; + } + } + +} + +if (typeof module != 'undefined') { + module.exports.BuildbotSyncer = BuildbotSyncer; + module.exports.BuildbotBuildEntry = BuildbotBuildEntry; +} diff --git a/Websites/perf.webkit.org/tools/js/v3-models.js b/Websites/perf.webkit.org/tools/js/v3-models.js new file mode 100644 index 0000000..4781cc9 --- /dev/null +++ b/Websites/perf.webkit.org/tools/js/v3-models.js @@ -0,0 +1,30 @@ +'use strict'; + +function importFromV3(file, name) { + const modelsDirectory = '../../public/v3/'; + + global[name] = require(modelsDirectory + file)[name]; +} + +importFromV3('models/data-model.js', 'DataModelObject'); +importFromV3('models/data-model.js', 'LabeledObject'); + +importFromV3('models/analysis-task.js', 'AnalysisTask'); +importFromV3('models/build-request.js', 'BuildRequest'); +importFromV3('models/builder.js', 'Build'); +importFromV3('models/builder.js', 'Builder'); +importFromV3('models/commit-log.js', 'CommitLog'); +importFromV3('models/measurement-adaptor.js', 'MeasurementAdaptor'); +importFromV3('models/measurement-cluster.js', 'MeasurementCluster'); +importFromV3('models/measurement-set.js', 'MeasurementSet'); +importFromV3('models/metric.js', 'Metric'); +importFromV3('models/platform.js', 'Platform'); +importFromV3('models/repository.js', 'Repository'); +importFromV3('models/root-set.js', 'MeasurementRootSet'); +importFromV3('models/root-set.js', 'RootSet'); +importFromV3('models/test.js', 'Test'); +importFromV3('models/test-group.js', 'TestGroup'); + +importFromV3('instrumentation.js', 'Instrumentation'); + +global.Statistics = require('../../public/shared/statistics.js'); diff --git a/Websites/perf.webkit.org/unit-tests/analysis-task-tests.js b/Websites/perf.webkit.org/unit-tests/analysis-task-tests.js index 8c76db9..7a0f35b 100644 --- a/Websites/perf.webkit.org/unit-tests/analysis-task-tests.js +++ b/Websites/perf.webkit.org/unit-tests/analysis-task-tests.js @@ -2,7 +2,8 @@ var assert = require('assert'); -require('./resources/v3-models.js'); +require('../tools/js/v3-models.js'); +require('./resources/mock-v3-models.js'); require('./resources/mock-remote-api.js'); function sampleAnalysisTask() diff --git a/Websites/perf.webkit.org/unit-tests/buildbot-syncer-tests.js b/Websites/perf.webkit.org/unit-tests/buildbot-syncer-tests.js new file mode 100644 index 0000000..1b9bb12 --- /dev/null +++ b/Websites/perf.webkit.org/unit-tests/buildbot-syncer-tests.js @@ -0,0 +1,295 @@ +'use strict'; + +let assert = require('assert'); + +require('./resources/mock-remote-api.js'); +require('../tools/js/v3-models.js'); +require('./resources/mock-v3-models.js'); + +let BuildbotBuildEntry = require('../tools/js/buildbot-syncer.js').BuildbotBuildEntry; +let BuildbotSyncer = require('../tools/js/buildbot-syncer.js').BuildbotSyncer; + +function sampleiOSConfig() +{ + return { + 'shared': + { + 'arguments': { + 'desired_image': {'root': 'iOS'}, + 'roots_dict': {'rootsExcluding': ['iOS']} + }, + 'slaveArgument': 'slavename', + 'buildRequestArgument': 'build_request_id' + }, + 'types': { + 'speedometer': { + 'test': ['Speedometer'], + 'arguments': {'test_name': 'speedometer'} + }, + 'jetstream': { + 'test': ['JetStream'], + 'arguments': {'test_name': 'jetstream'} + }, + "dromaeo-dom": { + "test": ["Dromaeo", "DOM Core Tests"], + "arguments": {"tests": "dromaeo-dom"} + }, + }, + 'builders': { + 'iPhone-bench': { + 'builder': 'ABTest-iPhone-RunBenchmark-Tests', + 'arguments': { 'forcescheduler': 'ABTest-iPhone-RunBenchmark-Tests-ForceScheduler' } + }, + 'iPad-bench': { + 'builder': 'ABTest-iPad-RunBenchmark-Tests', + 'arguments': { 'forcescheduler': 'ABTest-iPad-RunBenchmark-Tests-ForceScheduler' } + } + }, + 'configurations': [ + {'type': 'speedometer', 'builder': 'iPhone-bench', 'platform': 'iPhone'}, + {'type': 'jetstream', 'builder': 'iPhone-bench', 'platform': 'iPhone'}, + {'type': 'dromaeo-dom', 'builder': 'iPhone-bench', 'platform': 'iPhone'}, + + {'type': 'speedometer', 'builder': 'iPad-bench', 'platform': 'iPad'}, + {'type': 'jetstream', 'builder': 'iPad-bench', 'platform': 'iPad'}, + ] + }; +} + +let sampleRootSetData = { + 'WebKit': { + 'id': '111127', + 'time': 1456955807334, + 'repository': 'WebKit', + 'revision': '197463', + }, + 'Shared': { + 'id': '111237', + 'time': 1456931874000, + 'repository': 'Shared', + 'revision': '80229', + } +}; + +function createSampleBuildRequest() +{ + let rootSet = RootSet.ensureSingleton('4197', {roots: [ + {'id': '111127', 'time': 1456955807334, 'repository': webkit, 'revision': '197463'}, + {'id': '111237', 'time': 1456931874000, 'repository': sharedRepository, 'revision': '80229'}, + {'id': '88930', 'time': 0, 'repository': ios, 'revision': '13A452'}, + ]}); + + let request = BuildRequest.ensureSingleton('16733', {'rootSet': rootSet, 'status': 'pending'}); + return request; +} + +let samplePendingBuilds = [ + { + 'builderName': 'ABTest-iPad-RunBenchmark-Tests', + 'builds': [], + 'properties': [ + ['build_request_id', '16733', 'Force Build Form'], + ['desired_image', '13A452', 'Force Build Form'], + ['owner', '', 'Force Build Form'], + ['test_name', 'speedometer', 'Force Build Form'], + ['reason', 'force build','Force Build Form'], + [ + 'roots_dict', + JSON.stringify(sampleRootSetData), + 'Force Build Form' + ], + ['scheduler', 'ABTest-iPad-Performance-Tests-ForceScheduler', 'Scheduler'] + ], + 'source': { + 'branch': '', + 'changes': [], + 'codebase': 'compiler-rt', + 'hasPatch': false, + 'project': '', + 'repository': '', + 'revision': '' + }, + 'submittedAt': 1458704983 + } +]; + +describe('BuildbotSyncer', function () { + describe('fetchPendingBuilds', function () { + BuildbotSyncer.fetchPendingBuilds + }); + + describe('_loadConfig', function () { + + function smallConfiguration() + { + return { + 'builder': 'some builder', + 'platform': 'some platform', + 'test': ['some test'], + 'arguments': {}, + 'buildRequestArgument': 'id'}; + } + + it('should create BuildbotSyncer objects for a configuration that specify all required options', function () { + let syncers = BuildbotSyncer._loadConfig('http://build.webkit.org/', {'configurations': [smallConfiguration()]}); + assert.equal(syncers.length, 1); + }); + + it('should throw when some required options are missing', function () { + assert.throws(function () { + let config = smallConfiguration(); + delete config['builder']; + BuildbotSyncer._loadConfig('http://build.webkit.org/', {'configurations': [config]}); + }, 'builder should be a required option'); + assert.throws(function () { + let config = smallConfiguration(); + delete config['platform']; + BuildbotSyncer._loadConfig('http://build.webkit.org/', {'configurations': [config]}); + }, 'platform should be a required option'); + assert.throws(function () { + let config = smallConfiguration(); + delete config['test']; + BuildbotSyncer._loadConfig('http://build.webkit.org/', {'configurations': [config]}); + }, 'test should be a required option'); + assert.throws(function () { + let config = smallConfiguration(); + delete config['arguments']; + BuildbotSyncer._loadConfig('http://build.webkit.org/', {'configurations': [config]}); + }); + assert.throws(function () { + let config = smallConfiguration(); + delete config['buildRequestArgument']; + BuildbotSyncer._loadConfig('http://build.webkit.org/', {'configurations': [config]}); + }); + }); + + it('should throw when a test name is not an array of strings', function () { + assert.throws(function () { + let config = smallConfiguration(); + config.test = 'some test'; + BuildbotSyncer._loadConfig('http://build.webkit.org/', {'configurations': [config]}); + }); + assert.throws(function () { + let config = smallConfiguration(); + config.test = [1]; + BuildbotSyncer._loadConfig('http://build.webkit.org/', {'configurations': [config]}); + }); + }); + + it('should throw when arguments is not an object', function () { + assert.throws(function () { + let config = smallConfiguration(); + config.arguments = 'hello'; + BuildbotSyncer._loadConfig('http://build.webkit.org/', {'configurations': [config]}); + }); + }); + + it('should throw when arguments\'s values are malformed', function () { + assert.throws(function () { + let config = smallConfiguration(); + config.arguments = {'some': {'root': 'some root', 'rootsExcluding': ['other root']}}; + BuildbotSyncer._loadConfig('http://build.webkit.org/', {'configurations': [config]}); + }); + assert.throws(function () { + let config = smallConfiguration(); + config.arguments = {'some': {'otherKey': 'some root'}}; + BuildbotSyncer._loadConfig('http://build.webkit.org/', {'configurations': [config]}); + }); + assert.throws(function () { + let config = smallConfiguration(); + config.arguments = {'some': {'root': ['a', 'b']}}; + BuildbotSyncer._loadConfig('http://build.webkit.org/', {'configurations': [config]}); + }); + assert.throws(function () { + let config = smallConfiguration(); + config.arguments = {'some': {'root': 1}}; + BuildbotSyncer._loadConfig('http://build.webkit.org/', {'configurations': [config]}); + }); + assert.throws(function () { + let config = smallConfiguration(); + config.arguments = {'some': {'rootsExcluding': 'a'}}; + BuildbotSyncer._loadConfig('http://build.webkit.org/', {'configurations': [config]}); + }); + assert.throws(function () { + let config = smallConfiguration(); + config.arguments = {'some': {'rootsExcluding': [1]}}; + BuildbotSyncer._loadConfig('http://build.webkit.org/', {'configurations': [config]}); + }); + }); + + it('should create BuildbotSyncer objects for valid configurations', function () { + let syncers = BuildbotSyncer._loadConfig('http://build.webkit.org/', sampleiOSConfig()); + assert.equal(syncers.length, 5); + assert.ok(syncers[0] instanceof BuildbotSyncer); + assert.ok(syncers[1] instanceof BuildbotSyncer); + assert.ok(syncers[2] instanceof BuildbotSyncer); + assert.ok(syncers[3] instanceof BuildbotSyncer); + assert.ok(syncers[4] instanceof BuildbotSyncer); + }); + + it('should parse builder names correctly', function () { + let syncers = BuildbotSyncer._loadConfig('http://build.webkit.org/', sampleiOSConfig()); + assert.equal(syncers[0].builderName(), 'ABTest-iPhone-RunBenchmark-Tests'); + assert.equal(syncers[1].builderName(), 'ABTest-iPhone-RunBenchmark-Tests'); + assert.equal(syncers[2].builderName(), 'ABTest-iPhone-RunBenchmark-Tests'); + assert.equal(syncers[3].builderName(), 'ABTest-iPad-RunBenchmark-Tests'); + assert.equal(syncers[4].builderName(), 'ABTest-iPad-RunBenchmark-Tests'); + }); + + it('should parse platform names correctly', function () { + let syncers = BuildbotSyncer._loadConfig('http://build.webkit.org/', sampleiOSConfig()); + assert.equal(syncers[0].platformName(), 'iPhone'); + assert.equal(syncers[1].platformName(), 'iPhone'); + assert.equal(syncers[2].platformName(), 'iPhone'); + assert.equal(syncers[3].platformName(), 'iPad'); + assert.equal(syncers[4].platformName(), 'iPad'); + }); + + it('should parse test names correctly', function () { + let syncers = BuildbotSyncer._loadConfig('http://build.webkit.org/', sampleiOSConfig()); + assert.deepEqual(syncers[0].testPath(), ['Speedometer']); + assert.deepEqual(syncers[1].testPath(), ['JetStream']); + assert.deepEqual(syncers[2].testPath(), ['Dromaeo', 'DOM Core Tests']); + assert.deepEqual(syncers[3].testPath(), ['Speedometer']); + assert.deepEqual(syncers[4].testPath(), ['JetStream']); + }); + }); + + describe('_propertiesForBuildRequest', function () { + it('should include all properties specified in a given configuration', function () { + let syncers = BuildbotSyncer._loadConfig('http://build.webkit.org/', sampleiOSConfig()); + let properties = syncers[0]._propertiesForBuildRequest(createSampleBuildRequest()); + assert.deepEqual(Object.keys(properties), ['desired_image', 'roots_dict', 'test_name', 'forcescheduler', 'build_request_id']); + }); + + it('should preserve non-parametric property values', function () { + let syncers = BuildbotSyncer._loadConfig('http://build.webkit.org/', sampleiOSConfig()); + let properties = syncers[0]._propertiesForBuildRequest(createSampleBuildRequest()); + assert.equal(properties['test_name'], 'speedometer'); + assert.equal(properties['forcescheduler'], 'ABTest-iPhone-RunBenchmark-Tests-ForceScheduler'); + + properties = syncers[1]._propertiesForBuildRequest(createSampleBuildRequest()); + assert.equal(properties['test_name'], 'jetstream'); + assert.equal(properties['forcescheduler'], 'ABTest-iPhone-RunBenchmark-Tests-ForceScheduler'); + }); + + it('should resolve "root"', function () { + let syncers = BuildbotSyncer._loadConfig('http://build.webkit.org/', sampleiOSConfig()); + let properties = syncers[0]._propertiesForBuildRequest(createSampleBuildRequest()); + assert.equal(properties['desired_image'], '13A452'); + }); + + it('should resolve "rootsExcluding"', function () { + let syncers = BuildbotSyncer._loadConfig('http://build.webkit.org/', sampleiOSConfig()); + let properties = syncers[0]._propertiesForBuildRequest(createSampleBuildRequest()); + assert.equal(properties['roots_dict'], JSON.stringify(sampleRootSetData)); + }); + + it('should set the property for the build request id', function () { + let syncers = BuildbotSyncer._loadConfig('http://build.webkit.org/', sampleiOSConfig()); + let properties = syncers[0]._propertiesForBuildRequest(createSampleBuildRequest()); + assert.equal(properties['build_request_id'], createSampleBuildRequest().id()); + }); + }); + +}); \ No newline at end of file diff --git a/Websites/perf.webkit.org/unit-tests/measurement-adaptor-tests.js b/Websites/perf.webkit.org/unit-tests/measurement-adaptor-tests.js index 30a1a32..834a323 100644 --- a/Websites/perf.webkit.org/unit-tests/measurement-adaptor-tests.js +++ b/Websites/perf.webkit.org/unit-tests/measurement-adaptor-tests.js @@ -2,7 +2,8 @@ var assert = require('assert'); -require('./resources/v3-models'); +require('../tools/js/v3-models.js'); +require('./resources/mock-v3-models.js'); var sampleCluster = { 'clusterStart': 946684800000, diff --git a/Websites/perf.webkit.org/unit-tests/measurement-set-tests.js b/Websites/perf.webkit.org/unit-tests/measurement-set-tests.js index 0af1087..efd696a 100644 --- a/Websites/perf.webkit.org/unit-tests/measurement-set-tests.js +++ b/Websites/perf.webkit.org/unit-tests/measurement-set-tests.js @@ -3,7 +3,8 @@ var assert = require('assert'); require('./resources/mock-remote-api.js'); -require('./resources/v3-models.js'); +require('../tools/js/v3-models.js'); +require('./resources/mock-v3-models.js'); describe('MeasurementSet', function () { beforeEach(function () { diff --git a/Websites/perf.webkit.org/unit-tests/resources/mock-v3-models.js b/Websites/perf.webkit.org/unit-tests/resources/mock-v3-models.js new file mode 100644 index 0000000..b814a9e --- /dev/null +++ b/Websites/perf.webkit.org/unit-tests/resources/mock-v3-models.js @@ -0,0 +1,20 @@ +'use strict'; + +beforeEach(function () { + AnalysisTask._fetchAllPromise = null; + AnalysisTask.clearStaticMap(); + CommitLog.clearStaticMap(); + RootSet.clearStaticMap(); + TestGroup.clearStaticMap(); + BuildRequest.clearStaticMap(); + + global.osx = Repository.ensureSingleton(9, {name: 'OS X'}); + global.ios = Repository.ensureSingleton(22, {name: 'iOS'}); + global.webkit = Repository.ensureSingleton(11, {name: 'WebKit', url: 'http://trac.webkit.org/changeset/$1'}); + global.sharedRepository = Repository.ensureSingleton(16, {name: 'Shared'}); + global.builder = new Builder(176, {name: 'WebKit Perf Builder', buildUrl: 'http://build.webkit.org/builders/$builderName/$buildNumber'}); + + global.someTest = Test.ensureSingleton(1928, {name: 'Some test'}); + global.someMetric = Metric.ensureSingleton(2884, {name: 'Some metric', test: someTest}); + global.somePlatform = Platform.ensureSingleton(65, {name: 'Some platform', metrics: [someMetric]}); +}); diff --git a/Websites/perf.webkit.org/unit-tests/test-groups-tests.js b/Websites/perf.webkit.org/unit-tests/test-groups-tests.js index bd67fbba..deff1a6 100644 --- a/Websites/perf.webkit.org/unit-tests/test-groups-tests.js +++ b/Websites/perf.webkit.org/unit-tests/test-groups-tests.js @@ -2,7 +2,8 @@ var assert = require('assert'); -require('./resources/v3-models.js'); +require('../tools/js/v3-models.js'); +require('./resources/mock-v3-models.js'); function sampleTestGroup() { return {