3 let assert = require('assert');
5 require('../tools/js/v3-models.js');
6 let MockRemoteAPI = require('./resources/mock-remote-api.js').MockRemoteAPI;
7 let MockModels = require('./resources/mock-v3-models.js').MockModels;
9 let BuildbotBuildEntry = require('../tools/js/buildbot-syncer.js').BuildbotBuildEntry;
10 let BuildbotBuildEntryDeprecated = require('../tools/js/buildbot-syncer.js').BuildbotBuildEntryDeprecated;
11 let BuildbotSyncer = require('../tools/js/buildbot-syncer.js').BuildbotSyncer;
13 function sampleiOSConfig()
16 'slaveArgument': 'slavename',
17 'buildRequestArgument': 'build_request_id',
20 'repositories': {'WebKit': {}, 'iOS': {}},
22 'desired_image': {'revision': 'iOS'},
23 'opensource': {'revision': 'WebKit'},
29 'test': ['Speedometer'],
30 'properties': {'test_name': 'speedometer'}
33 'test': ['JetStream'],
34 'properties': {'test_name': 'jetstream'}
37 'test': ['Dromaeo', 'DOM Core Tests'],
38 'properties': {'tests': 'dromaeo-dom'}
43 'builder': 'ABTest-iPhone-RunBenchmark-Tests',
44 'properties': {'forcescheduler': 'ABTest-iPhone-RunBenchmark-Tests-ForceScheduler'},
45 'slaveList': ['ABTest-iPhone-0'],
48 'builder': 'ABTest-iPad-RunBenchmark-Tests',
49 'properties': {'forcescheduler': 'ABTest-iPad-RunBenchmark-Tests-ForceScheduler'},
50 'slaveList': ['ABTest-iPad-0', 'ABTest-iPad-1'],
53 'builder': 'ABTest-iOS-Builder',
54 'properties': {'forcescheduler': 'ABTest-Builder-ForceScheduler'},
57 'buildConfigurations': [
58 {'builders': ['iOS-builder'], 'platforms': ['iPhone', 'iPad']},
60 'testConfigurations': [
61 {'builders': ['iPhone-bench'], 'types': ['speedometer', 'jetstream', 'dromaeo-dom'], 'platforms': ['iPhone']},
62 {'builders': ['iPad-bench'], 'types': ['speedometer', 'jetstream'], 'platforms': ['iPad']},
67 function sampleiOSConfigWithExpansions()
70 "triggerableName": "build-webkit-ios",
71 "buildRequestArgument": "build-request-id",
72 "repositoryGroups": { },
75 "test": ["PLT-iPhone"],
76 "properties": {"test_name": "plt"}
80 "properties": {"test_name": "plt"}
83 "test": ["Speedometer"],
84 "properties": {"tests": "speedometer"}
89 "builder": "iPhone AB Tests",
90 "properties": {"forcescheduler": "force-iphone-ab-tests"},
93 "builder": "iPhone 2 AB Tests",
94 "properties": {"forcescheduler": "force-iphone-2-ab-tests"},
97 "builder": "iPad AB Tests",
98 "properties": {"forcescheduler": "force-ipad-ab-tests"},
101 "testConfigurations": [
103 "builders": ["iphone", "iphone-2"],
104 "platforms": ["iPhone", "iOS 10 iPhone"],
105 "types": ["iphone-plt", "speedometer"],
108 "builders": ["ipad"],
109 "platforms": ["iPad"],
110 "types": ["ipad-plt", "speedometer"],
116 function smallConfiguration()
119 'buildRequestArgument': 'id',
120 'repositoryGroups': {
122 'repositories': {'iOS': {}, 'WebKit': {}},
124 'os': {'revision': 'iOS'},
125 'wk': {'revision': 'WebKit'}
131 'test': ['Some test'],
136 'builder': 'some builder',
139 'testConfigurations': [{
140 'builders': ['some-builder'],
141 'platforms': ['Some platform'],
142 'types': ['some-test'],
147 function builderNameToIDMap()
150 'some builder' : '100',
151 'ABTest-iPhone-RunBenchmark-Tests': '101',
152 'ABTest-iPad-RunBenchmark-Tests': '102',
153 'ABTest-iOS-Builder': '103',
154 'iPhone AB Tests' : '104',
155 'iPhone 2 AB Tests': '105',
156 'iPad AB Tests': '106'
160 function smallPendingBuild()
163 'builderName': 'some builder',
169 'codebase': 'WebKit',
178 function smallInProgressBuild()
181 'builderName': 'some builder',
190 'codebase': 'WebKit',
199 function smallFinishedBuild()
202 'builderName': 'some builder',
211 'codebase': 'WebKit',
221 function createSampleBuildRequest(platform, test)
223 assert(platform instanceof Platform);
224 assert(test instanceof Test);
226 const webkit197463 = CommitLog.ensureSingleton('111127', {'id': '111127', 'time': 1456955807334, 'repository': MockModels.webkit, 'revision': '197463'});
227 const shared111237 = CommitLog.ensureSingleton('111237', {'id': '111237', 'time': 1456931874000, 'repository': MockModels.sharedRepository, 'revision': '80229'});
228 const ios13A452 = CommitLog.ensureSingleton('88930', {'id': '88930', 'time': 0, 'repository': MockModels.ios, 'revision': '13A452'});
230 const commitSet = CommitSet.ensureSingleton('4197', {customRoots: [], revisionItems: [{commit: webkit197463}, {commit: shared111237}, {commit: ios13A452}]});
232 return BuildRequest.ensureSingleton('16733-' + platform.id(), {'triggerable': MockModels.triggerable,
233 repositoryGroup: MockModels.svnRepositoryGroup,
234 'commitSet': commitSet, 'status': 'pending', 'platform': platform, 'test': test});
237 function createSampleBuildRequestWithPatch(platform, test, order)
239 assert(platform instanceof Platform);
240 assert(!test || test instanceof Test);
242 const webkit197463 = CommitLog.ensureSingleton('111127', {'id': '111127', 'time': 1456955807334, 'repository': MockModels.webkit, 'revision': '197463'});
243 const shared111237 = CommitLog.ensureSingleton('111237', {'id': '111237', 'time': 1456931874000, 'repository': MockModels.sharedRepository, 'revision': '80229'});
244 const ios13A452 = CommitLog.ensureSingleton('88930', {'id': '88930', 'time': 0, 'repository': MockModels.ios, 'revision': '13A452'});
246 const patch = new UploadedFile(453, {'createdAt': new Date('2017-05-01T19:16:53Z'), 'filename': 'patch.dat', 'extension': '.dat', 'author': 'some user',
247 size: 534637, sha256: '169463c8125e07c577110fe144ecd63942eb9472d438fc0014f474245e5df8a1'});
249 const root = new UploadedFile(456, {'createdAt': new Date('2017-05-01T21:03:27Z'), 'filename': 'root.dat', 'extension': '.dat', 'author': 'some user',
250 size: 16452234, sha256: '03eed7a8494ab8794c44b7d4308e55448fc56f4d6c175809ba968f78f656d58d'});
252 const commitSet = CommitSet.ensureSingleton('53246456', {customRoots: [root], revisionItems: [{commit: webkit197463, patch, requiresBuild: true}, {commit: shared111237}, {commit: ios13A452}]});
254 return BuildRequest.ensureSingleton(`6345645376-${order}`, {'triggerable': MockModels.triggerable,
255 repositoryGroup: MockModels.svnRepositoryGroup,
256 'commitSet': commitSet, 'status': 'pending', 'platform': platform, 'test': test, 'order': order});
259 function createSampleBuildRequestWithOwnedCommit(platform, test, order)
261 assert(platform instanceof Platform);
262 assert(!test || test instanceof Test);
264 const webkit197463 = CommitLog.ensureSingleton('111127', {'id': '111127', 'time': 1456955807334, 'repository': MockModels.webkit, 'revision': '197463'});
265 const owner111289 = CommitLog.ensureSingleton('111289', {'id': '111289', 'time': 1456931874000, 'repository': MockModels.ownerRepository, 'revision': 'owner-001'});
266 const owned111222 = CommitLog.ensureSingleton('111222', {'id': '111222', 'time': 1456932774000, 'repository': MockModels.ownedRepository, 'revision': 'owned-002'});
267 const ios13A452 = CommitLog.ensureSingleton('88930', {'id': '88930', 'time': 0, 'repository': MockModels.ios, 'revision': '13A452'});
269 const root = new UploadedFile(456, {'createdAt': new Date('2017-05-01T21:03:27Z'), 'filename': 'root.dat', 'extension': '.dat', 'author': 'some user',
270 size: 16452234, sha256: '03eed7a8494ab8794c44b7d4308e55448fc56f4d6c175809ba968f78f656d58d'});
272 const commitSet = CommitSet.ensureSingleton('53246486', {customRoots: [root], revisionItems: [{commit: webkit197463}, {commit: owner111289}, {commit: owned111222, commitOwner: owner111289, requiresBuild: true}, {commit: ios13A452}]});
274 return BuildRequest.ensureSingleton(`6345645370-${order}`, {'triggerable': MockModels.triggerable,
275 repositoryGroup: MockModels.svnRepositoryWithOwnedRepositoryGroup,
276 'commitSet': commitSet, 'status': 'pending', 'platform': platform, 'test': test, 'order': order});
279 function createSampleBuildRequestWithOwnedCommitAndPatch(platform, test, order)
281 assert(platform instanceof Platform);
282 assert(!test || test instanceof Test);
284 const webkit197463 = CommitLog.ensureSingleton('111127', {'id': '111127', 'time': 1456955807334, 'repository': MockModels.webkit, 'revision': '197463'});
285 const owner111289 = CommitLog.ensureSingleton('111289', {'id': '111289', 'time': 1456931874000, 'repository': MockModels.ownerRepository, 'revision': 'owner-001'});
286 const owned111222 = CommitLog.ensureSingleton('111222', {'id': '111222', 'time': 1456932774000, 'repository': MockModels.ownedRepository, 'revision': 'owned-002'});
287 const ios13A452 = CommitLog.ensureSingleton('88930', {'id': '88930', 'time': 0, 'repository': MockModels.ios, 'revision': '13A452'});
289 const patch = new UploadedFile(453, {'createdAt': new Date('2017-05-01T19:16:53Z'), 'filename': 'patch.dat', 'extension': '.dat', 'author': 'some user',
290 size: 534637, sha256: '169463c8125e07c577110fe144ecd63942eb9472d438fc0014f474245e5df8a1'});
292 const commitSet = CommitSet.ensureSingleton('53246486', {customRoots: [], revisionItems: [{commit: webkit197463, patch, requiresBuild: true}, {commit: owner111289}, {commit: owned111222, commitOwner: owner111289, requiresBuild: true}, {commit: ios13A452}]});
294 return BuildRequest.ensureSingleton(`6345645370-${order}`, {'triggerable': MockModels.triggerable,
295 repositoryGroup: MockModels.svnRepositoryWithOwnedRepositoryGroup,
296 'commitSet': commitSet, 'status': 'pending', 'platform': platform, 'test': test, 'order': order});
299 function samplePendingBuildData(buildRequestId, buildTime, builderId)
302 "builderid": builderId || 102,
303 "buildrequestid": buildRequestId || 16733,
304 "buildsetid": 894720,
307 "claimed_by_masterid": null,
312 "submitted_at": buildTime || 1458704983,
317 function samplePendingBuild(buildRequestId, buildTime, builderName)
320 "buildrequests" : [samplePendingBuildData(buildRequestId, buildTime, builderNameToIDMap()[builderName])]
324 function sampleBuildData(workerName, isComplete, buildRequestId, buildNumber, builderId)
327 "builderid": builderId || 102,
328 "number": buildNumber || 614,
329 "buildrequestid": buildRequestId || 16733,
330 "complete": isComplete,
335 "started_at": 1513725109,
336 "state_string": "building",
339 "platform": ["mac", "Unknown"],
340 "scheduler": ["ABTest-iPad-RunBenchmark-Tests-ForceScheduler", "Scheduler"],
341 "slavename": [workerName || "ABTest-iPad-0", "Worker (deprecated)"],
342 "workername": [workerName || "ABTest-iPad-0", "Worker"
348 function sampleInProgressBuildData(workerName)
350 return sampleBuildData(workerName, false);
353 function sampleInProgressBuild(workerName)
356 "builds": [sampleInProgressBuildData(workerName)]
360 function sampleFinishedBuildData(buildRequestId, workerName, builderName)
362 return sampleBuildData(workerName, true, buildRequestId || 18935, 1755, builderNameToIDMap()[builderName]);
365 function sampleFinishedBuild(buildRequestId, workerName, builderName)
368 "builds": [sampleFinishedBuildData(buildRequestId, workerName, builderName)]
372 function samplePendingBuildDeprecated(buildRequestId, buildTime, slaveName)
375 'builderName': 'ABTest-iPad-RunBenchmark-Tests',
378 ['build_request_id', buildRequestId || '16733', 'Force Build Form'],
379 ['desired_image', '13A452', 'Force Build Form'],
380 ['owner', '<unknown>', 'Force Build Form'],
381 ['test_name', 'speedometer', 'Force Build Form'],
382 ['reason', 'force build','Force Build Form'],
383 ['slavename', slaveName, ''],
384 ['scheduler', 'ABTest-iPad-RunBenchmark-Tests-ForceScheduler', 'Scheduler']
389 'codebase': 'compiler-rt',
395 'submittedAt': buildTime || 1458704983
399 function sampleInProgressBuildDeprecated(slaveName)
403 'builderName': 'ABTest-iPad-RunBenchmark-Tests',
405 'eta': 0.26548067698460565,
406 'expectations': [['output', 845, 1315.0]],
410 'logs': [['stdio', 'https://build.webkit.org/builders/ABTest-iPad-RunBenchmark-Tests/builds/614/steps/Some%20step/logs/stdio']],
412 'results': [null,[]],
416 'times': [1458718657.581628, null],
419 'eta': 6497.991612434387,
420 'logs': [['stdio','https://build.webkit.org/builders/ABTest-iPad-RunBenchmark-Tests/builds/614/steps/shell/logs/stdio']],
423 ['build_request_id', '16733', 'Force Build Form'],
424 ['buildername', 'ABTest-iPad-RunBenchmark-Tests', 'Builder'],
425 ['buildnumber', 614, 'Build'],
426 ['desired_image', '13A452', 'Force Build Form'],
427 ['owner', '<unknown>', 'Force Build Form'],
428 ['reason', 'force build', 'Force Build Form'],
429 ['scheduler', 'ABTest-iPad-RunBenchmark-Tests-ForceScheduler', 'Scheduler'],
430 ['slavename', slaveName || 'ABTest-iPad-0', 'BuildSlave'],
432 'reason': 'A build was forced by \'<unknown>\': force build',
434 'slave': 'ABTest-iPad-0',
435 'sourceStamps': [{'branch': '', 'changes': [], 'codebase': 'compiler-rt', 'hasPatch': false, 'project': '', 'repository': '', 'revision': ''}],
439 'expectations': [['output',2309,2309.0]],
443 'logs': [['stdio', 'https://build.webkit.org/builders/ABTest-iPad-RunBenchmark-Tests/builds/614/steps/shell/logs/stdio']],
444 'name': 'Finished step',
449 'times': [1458718655.419865, 1458718655.453633],
453 'eta': 0.26548067698460565,
454 'expectations': [['output', 845, 1315.0]],
458 'logs': [['stdio', 'https://build.webkit.org/builders/ABTest-iPad-RunBenchmark-Tests/builds/614/steps/Some%20step/logs/stdio']],
460 'results': [null,[]],
464 'times': [1458718657.581628, null],
469 'expectations': [['output', null, null]],
474 'name': 'Some other step',
475 'results': [null, []],
479 'times': [null, null],
484 'times': [1458718655.415821, null]
488 function sampleFinishedBuildDeprecated(buildRequestId, slaveName)
492 'builderName': 'ABTest-iPad-RunBenchmark-Tests',
495 'logs': [['stdio','https://build.webkit.org/builders/ABTest-iPad-RunBenchmark-Tests/builds/1755/steps/shell/logs/stdio']],
498 ['build_request_id', buildRequestId || '18935', 'Force Build Form'],
499 ['buildername', 'ABTest-iPad-RunBenchmark-Tests', 'Builder'],
500 ['buildnumber', 1755, 'Build'],
501 ['desired_image', '13A452', 'Force Build Form'],
502 ['owner', '<unknown>', 'Force Build Form'],
503 ['reason', 'force build', 'Force Build Form'],
504 ['scheduler', 'ABTest-iPad-RunBenchmark-Tests-ForceScheduler', 'Scheduler'],
505 ['slavename', slaveName || 'ABTest-iPad-0', 'BuildSlave'],
507 'reason': 'A build was forced by \'<unknown>\': force build',
509 'slave': 'ABTest-iPad-0',
510 'sourceStamps': [{'branch': '', 'changes': [], 'codebase': 'compiler-rt', 'hasPatch': false, 'project': '', 'repository': '', 'revision': ''}],
514 'expectations': [['output',2309,2309.0]],
518 'logs': [['stdio', 'https://build.webkit.org/builders/ABTest-iPad-RunBenchmark-Tests/builds/614/steps/shell/logs/stdio']],
519 'name': 'Finished step',
524 'times': [1458718655.419865, 1458718655.453633],
529 'expectations': [['output', 845, 1315.0]],
533 'logs': [['stdio', 'https://build.webkit.org/builders/ABTest-iPad-RunBenchmark-Tests/builds/614/steps/Some%20step/logs/stdio']],
535 'results': [null,[]],
539 'times': [1458718657.581628, null],
544 'expectations': [['output', null, null]],
549 'name': 'Some other step',
550 'results': [null, []],
554 'times': [null, null],
559 'times': [1458937478.25837, 1458946147.173785]
563 describe('BuildbotSyncer', () => {
565 let requests = MockRemoteAPI.inject('http://build.webkit.org');
567 describe('_loadConfig', () => {
569 it('should create BuildbotSyncer objects for a configuration that specify all required options', () => {
570 assert.equal(BuildbotSyncer._loadConfig(MockRemoteAPI, smallConfiguration(), builderNameToIDMap()).length, 1);
573 it('should throw when some required options are missing', () => {
574 assert.throws(() => {
575 const config = smallConfiguration();
576 delete config.builders;
577 BuildbotSyncer._loadConfig(MockRemoteAPI, config, builderNameToIDMap());
578 }, /"some-builder" is not a valid builder in the configuration/);
579 assert.throws(() => {
580 const config = smallConfiguration();
582 BuildbotSyncer._loadConfig(MockRemoteAPI, config, builderNameToIDMap());
583 }, /"some-test" is not a valid type in the configuration/);
584 assert.throws(() => {
585 const config = smallConfiguration();
586 delete config.testConfigurations[0].builders;
587 BuildbotSyncer._loadConfig(MockRemoteAPI, config, builderNameToIDMap());
588 }, /The test configuration 1 does not specify "builders" as an array/);
589 assert.throws(() => {
590 const config = smallConfiguration();
591 delete config.testConfigurations[0].platforms;
592 BuildbotSyncer._loadConfig(MockRemoteAPI, config, builderNameToIDMap());
593 }, /The test configuration 1 does not specify "platforms" as an array/);
594 assert.throws(() => {
595 const config = smallConfiguration();
596 delete config.testConfigurations[0].types;
597 BuildbotSyncer._loadConfig(MockRemoteAPI, config, builderNameToIDMap());
598 }, /The test configuration 0 does not specify "types" as an array/);
599 assert.throws(() => {
600 const config = smallConfiguration();
601 delete config.buildRequestArgument;
602 BuildbotSyncer._loadConfig(MockRemoteAPI, config, builderNameToIDMap());
603 }, /buildRequestArgument must specify the name of the property used to store the build request ID/);
606 it('should throw when a test name is not an array of strings', () => {
607 assert.throws(() => {
608 const config = smallConfiguration();
609 config.testConfigurations[0].types = 'some test';
610 BuildbotSyncer._loadConfig(MockRemoteAPI, config, builderNameToIDMap());
611 }, /The test configuration 0 does not specify "types" as an array/);
612 assert.throws(() => {
613 const config = smallConfiguration();
614 config.testConfigurations[0].types = [1];
615 BuildbotSyncer._loadConfig(MockRemoteAPI, config, builderNameToIDMap());
616 }, /"1" is not a valid type in the configuration/);
619 it('should throw when properties is not an object', () => {
620 assert.throws(() => {
621 const config = smallConfiguration();
622 config.builders[Object.keys(config.builders)[0]].properties = 'hello';
623 BuildbotSyncer._loadConfig(MockRemoteAPI, config, builderNameToIDMap());
624 }, /Build properties should be a dictionary/);
625 assert.throws(() => {
626 const config = smallConfiguration();
627 config.types[Object.keys(config.types)[0]].properties = 'hello';
628 BuildbotSyncer._loadConfig(MockRemoteAPI, config, builderNameToIDMap());
629 }, /Build properties should be a dictionary/);
632 it('should throw when testProperties is specifed in a type or a builder', () => {
633 assert.throws(() => {
634 const config = smallConfiguration();
635 const firstType = Object.keys(config.types)[0];
636 config.types[firstType].testProperties = {};
637 BuildbotSyncer._loadConfig(MockRemoteAPI, config, builderNameToIDMap());
638 }, /Unrecognized parameter "testProperties"/);
639 assert.throws(() => {
640 const config = smallConfiguration();
641 const firstBuilder = Object.keys(config.builders)[0];
642 config.builders[firstBuilder].testProperties = {};
643 BuildbotSyncer._loadConfig(MockRemoteAPI, config, builderNameToIDMap());
644 }, /Unrecognized parameter "testProperties"/);
647 it('should throw when buildProperties is specifed in a type or a builder', () => {
648 assert.throws(() => {
649 const config = smallConfiguration();
650 const firstType = Object.keys(config.types)[0];
651 config.types[firstType].buildProperties = {};
652 BuildbotSyncer._loadConfig(MockRemoteAPI, config, builderNameToIDMap());
653 }, /Unrecognized parameter "buildProperties"/);
654 assert.throws(() => {
655 const config = smallConfiguration();
656 const firstBuilder = Object.keys(config.builders)[0];
657 config.builders[firstBuilder].buildProperties = {};
658 BuildbotSyncer._loadConfig(MockRemoteAPI, config, builderNameToIDMap());
659 }, /Unrecognized parameter "buildProperties"/);
662 it('should throw when properties for a type is malformed', () => {
663 const firstType = Object.keys(smallConfiguration().types)[0];
664 assert.throws(() => {
665 const config = smallConfiguration();
666 config.types[firstType].properties = 'hello';
667 BuildbotSyncer._loadConfig(MockRemoteAPI, config, builderNameToIDMap());
668 }, /Build properties should be a dictionary/);
669 assert.throws(() => {
670 const config = smallConfiguration();
671 config.types[firstType].properties = {'some': {'otherKey': 'some root'}};
672 BuildbotSyncer._loadConfig(RemoteAPI, config, builderNameToIDMap());
673 }, /Build properties "some" specifies a non-string value of type "object"/);
674 assert.throws(() => {
675 const config = smallConfiguration();
676 config.types[firstType].properties = {'some': {'otherKey': 'some root'}};
677 BuildbotSyncer._loadConfig(RemoteAPI, config, builderNameToIDMap());
678 }, /Build properties "some" specifies a non-string value of type "object"/);
679 assert.throws(() => {
680 const config = smallConfiguration();
681 config.types[firstType].properties = {'some': {'revision': 'WebKit'}};
682 BuildbotSyncer._loadConfig(RemoteAPI, config, builderNameToIDMap());
683 }, /Build properties "some" specifies a non-string value of type "object"/);
684 assert.throws(() => {
685 const config = smallConfiguration();
686 config.types[firstType].properties = {'some': 1};
687 BuildbotSyncer._loadConfig(RemoteAPI, config, builderNameToIDMap());
688 }, / Build properties "some" specifies a non-string value of type "object"/);
691 it('should throw when properties for a builder is malformed', () => {
692 const firstBuilder = Object.keys(smallConfiguration().builders)[0];
693 assert.throws(() => {
694 const config = smallConfiguration();
695 config.builders[firstBuilder].properties = 'hello';
696 BuildbotSyncer._loadConfig(MockRemoteAPI, config, builderNameToIDMap());
697 }, /Build properties should be a dictionary/);
698 assert.throws(() => {
699 const config = smallConfiguration();
700 config.builders[firstBuilder].properties = {'some': {'otherKey': 'some root'}};
701 BuildbotSyncer._loadConfig(RemoteAPI, config, builderNameToIDMap());
702 }, /Build properties "some" specifies a non-string value of type "object"/);
703 assert.throws(() => {
704 const config = smallConfiguration();
705 config.builders[firstBuilder].properties = {'some': {'otherKey': 'some root'}};
706 BuildbotSyncer._loadConfig(RemoteAPI, config, builderNameToIDMap());
707 }, /Build properties "some" specifies a non-string value of type "object"/);
708 assert.throws(() => {
709 const config = smallConfiguration();
710 config.builders[firstBuilder].properties = {'some': {'revision': 'WebKit'}};
711 BuildbotSyncer._loadConfig(RemoteAPI, config, builderNameToIDMap());
712 }, /Build properties "some" specifies a non-string value of type "object"/);
713 assert.throws(() => {
714 const config = smallConfiguration();
715 config.builders[firstBuilder].properties = {'some': 1};
716 BuildbotSyncer._loadConfig(RemoteAPI, config, builderNameToIDMap());
717 }, /Build properties "some" specifies a non-string value of type "object"/);
720 it('should create BuildbotSyncer objects for valid configurations', () => {
721 let syncers = BuildbotSyncer._loadConfig(RemoteAPI, sampleiOSConfig(), builderNameToIDMap());
722 assert.equal(syncers.length, 3);
723 assert.ok(syncers[0] instanceof BuildbotSyncer);
724 assert.ok(syncers[1] instanceof BuildbotSyncer);
725 assert.ok(syncers[2] instanceof BuildbotSyncer);
728 it('should parse builder names correctly', () => {
729 let syncers = BuildbotSyncer._loadConfig(RemoteAPI, sampleiOSConfig(), builderNameToIDMap());
730 assert.equal(syncers[0].builderName(), 'ABTest-iPhone-RunBenchmark-Tests');
731 assert.equal(syncers[1].builderName(), 'ABTest-iPad-RunBenchmark-Tests');
732 assert.equal(syncers[2].builderName(), 'ABTest-iOS-Builder');
735 it('should parse test configurations with build configurations correctly', () => {
736 let syncers = BuildbotSyncer._loadConfig(RemoteAPI, sampleiOSConfig(), builderNameToIDMap());
738 let configurations = syncers[0].testConfigurations();
739 assert(syncers[0].isTester());
740 assert.equal(configurations.length, 3);
741 assert.equal(configurations[0].platform, MockModels.iphone);
742 assert.equal(configurations[0].test, MockModels.speedometer);
743 assert.equal(configurations[1].platform, MockModels.iphone);
744 assert.equal(configurations[1].test, MockModels.jetstream);
745 assert.equal(configurations[2].platform, MockModels.iphone);
746 assert.equal(configurations[2].test, MockModels.domcore);
747 assert.deepEqual(syncers[0].buildConfigurations(), []);
749 configurations = syncers[1].testConfigurations();
750 assert(syncers[1].isTester());
751 assert.equal(configurations.length, 2);
752 assert.equal(configurations[0].platform, MockModels.ipad);
753 assert.equal(configurations[0].test, MockModels.speedometer);
754 assert.equal(configurations[1].platform, MockModels.ipad);
755 assert.equal(configurations[1].test, MockModels.jetstream);
756 assert.deepEqual(syncers[1].buildConfigurations(), []);
758 assert(!syncers[2].isTester());
759 assert.deepEqual(syncers[2].testConfigurations(), []);
760 configurations = syncers[2].buildConfigurations();
761 assert.equal(configurations.length, 2);
762 assert.equal(configurations[0].platform, MockModels.iphone);
763 assert.equal(configurations[0].test, null);
764 assert.equal(configurations[1].platform, MockModels.ipad);
765 assert.equal(configurations[1].test, null);
768 it('should throw when a build configuration use the same builder as a test configuration', () => {
769 assert.throws(() => {
770 const config = sampleiOSConfig();
771 config.buildConfigurations[0].builders = config.testConfigurations[0].builders;
772 BuildbotSyncer._loadConfig(MockRemoteAPI, config, builderNameToIDMap());
776 it('should parse test configurations with types and platforms expansions correctly', () => {
777 const syncers = BuildbotSyncer._loadConfig(RemoteAPI, sampleiOSConfigWithExpansions(), builderNameToIDMap());
779 assert.equal(syncers.length, 3);
781 let configurations = syncers[0].testConfigurations();
782 assert.equal(configurations.length, 4);
783 assert.equal(configurations[0].platform, MockModels.iphone);
784 assert.equal(configurations[0].test, MockModels.iPhonePLT);
785 assert.equal(configurations[1].platform, MockModels.iphone);
786 assert.equal(configurations[1].test, MockModels.speedometer);
787 assert.equal(configurations[2].platform, MockModels.iOS10iPhone);
788 assert.equal(configurations[2].test, MockModels.iPhonePLT);
789 assert.equal(configurations[3].platform, MockModels.iOS10iPhone);
790 assert.equal(configurations[3].test, MockModels.speedometer);
791 assert.deepEqual(syncers[0].buildConfigurations(), []);
793 configurations = syncers[1].testConfigurations();
794 assert.equal(configurations.length, 4);
795 assert.equal(configurations[0].platform, MockModels.iphone);
796 assert.equal(configurations[0].test, MockModels.iPhonePLT);
797 assert.equal(configurations[1].platform, MockModels.iphone);
798 assert.equal(configurations[1].test, MockModels.speedometer);
799 assert.equal(configurations[2].platform, MockModels.iOS10iPhone);
800 assert.equal(configurations[2].test, MockModels.iPhonePLT);
801 assert.equal(configurations[3].platform, MockModels.iOS10iPhone);
802 assert.equal(configurations[3].test, MockModels.speedometer);
803 assert.deepEqual(syncers[1].buildConfigurations(), []);
805 configurations = syncers[2].testConfigurations();
806 assert.equal(configurations.length, 2);
807 assert.equal(configurations[0].platform, MockModels.ipad);
808 assert.equal(configurations[0].test, MockModels.iPadPLT);
809 assert.equal(configurations[1].platform, MockModels.ipad);
810 assert.equal(configurations[1].test, MockModels.speedometer);
811 assert.deepEqual(syncers[2].buildConfigurations(), []);
814 it('should throw when repositoryGroups is not an object', () => {
815 assert.throws(() => {
816 const config = smallConfiguration();
817 config.repositoryGroups = 1;
818 BuildbotSyncer._loadConfig(MockRemoteAPI, config, builderNameToIDMap());
819 }, /repositoryGroups must specify a dictionary from the name to its definition/);
820 assert.throws(() => {
821 const config = smallConfiguration();
822 config.repositoryGroups = 'hello';
823 BuildbotSyncer._loadConfig(MockRemoteAPI, config, builderNameToIDMap());
824 }, /repositoryGroups must specify a dictionary from the name to its definition/);
827 it('should throw when a repository group does not specify a dictionary of repositories', () => {
828 assert.throws(() => {
829 const config = smallConfiguration();
830 config.repositoryGroups = {'some-group': {testProperties: {}}};
831 BuildbotSyncer._loadConfig(MockRemoteAPI, config, builderNameToIDMap());
832 }, /Repository group "some-group" does not specify a dictionary of repositories/);
833 assert.throws(() => {
834 const config = smallConfiguration();
835 config.repositoryGroups = {'some-group': {repositories: 1}, testProperties: {}};
836 BuildbotSyncer._loadConfig(MockRemoteAPI, config, builderNameToIDMap());
837 }, /Repository group "some-group" does not specify a dictionary of repositories/);
840 it('should throw when a repository group specifies an empty dictionary', () => {
841 assert.throws(() => {
842 const config = smallConfiguration();
843 config.repositoryGroups = {'some-group': {repositories: {}, testProperties: {}}};
844 BuildbotSyncer._loadConfig(MockRemoteAPI, config, builderNameToIDMap());
845 }, /Repository group "some-group" does not specify any repository/);
848 it('should throw when a repository group specifies an invalid repository name', () => {
849 assert.throws(() => {
850 const config = smallConfiguration();
851 config.repositoryGroups = {'some-group': {repositories: {'InvalidRepositoryName': {}}}};
852 BuildbotSyncer._loadConfig(MockRemoteAPI, config, builderNameToIDMap());
853 }, /"InvalidRepositoryName" is not a valid repository name/);
856 it('should throw when a repository group specifies a repository with a non-dictionary value', () => {
857 assert.throws(() => {
858 const config = smallConfiguration();
859 config.repositoryGroups = {'some-group': {repositories: {'WebKit': 1}}};
860 BuildbotSyncer._loadConfig(MockRemoteAPI, config, builderNameToIDMap());
861 }, /"WebKit" specifies a non-dictionary value/);
864 it('should throw when the description of a repository group is not a string', () => {
865 assert.throws(() => {
866 const config = smallConfiguration();
867 config.repositoryGroups = {'some-group': {repositories: {'WebKit': {}}, description: 1}};
868 BuildbotSyncer._loadConfig(MockRemoteAPI, config, builderNameToIDMap());
869 }, /Repository group "some-group" have an invalid description/);
870 assert.throws(() => {
871 const config = smallConfiguration();
872 config.repositoryGroups = {'some-group': {repositories: {'WebKit': {}}, description: [1, 2]}};
873 BuildbotSyncer._loadConfig(MockRemoteAPI, config, builderNameToIDMap());
874 }, /Repository group "some-group" have an invalid description/);
877 it('should throw when a repository group does not specify a dictionary of properties', () => {
878 assert.throws(() => {
879 const config = smallConfiguration();
880 config.repositoryGroups = {'some-group': {repositories: {'WebKit': {}}, testProperties: 1}};
881 BuildbotSyncer._loadConfig(MockRemoteAPI, config, builderNameToIDMap());
882 }, /Repository group "some-group" specifies the test configurations with an invalid type/);
883 assert.throws(() => {
884 const config = smallConfiguration();
885 config.repositoryGroups = {'some-group': {repositories: {'WebKit': {}}, testProperties: 'hello'}};
886 BuildbotSyncer._loadConfig(MockRemoteAPI, config, builderNameToIDMap());
887 }, /Repository group "some-group" specifies the test configurations with an invalid type/);
890 it('should throw when a repository group refers to a non-existent repository in the properties dictionary', () => {
891 assert.throws(() => {
892 const config = smallConfiguration();
893 config.repositoryGroups = {'some-group': {repositories: {'WebKit': {}}, testProperties: {'wk': {revision: 'InvalidRepository'}}}};
894 BuildbotSyncer._loadConfig(MockRemoteAPI, config, builderNameToIDMap());
895 }, /Repository group "some-group" an invalid repository "InvalidRepository"/);
898 it('should throw when a repository group refers to a repository which is not listed in the list of repositories', () => {
899 assert.throws(() => {
900 const config = smallConfiguration();
901 config.repositoryGroups = {'some-group': {repositories: {'WebKit': {}}, testProperties: {'os': {revision: 'iOS'}}}};
902 BuildbotSyncer._loadConfig(MockRemoteAPI, config, builderNameToIDMap());
903 }, /Repository group "some-group" an invalid repository "iOS"/);
904 assert.throws(() => {
905 const config = smallConfiguration();
906 config.repositoryGroups = {'some-group': {
907 repositories: {'WebKit': {acceptsPatch: true}},
908 testProperties: {'wk': {revision: 'WebKit'}, 'install-roots': {'roots': {}}},
909 buildProperties: {'os': {revision: 'iOS'}},
910 acceptsRoots: true}};
911 BuildbotSyncer._loadConfig(MockRemoteAPI, config, builderNameToIDMap());
912 }, /Repository group "some-group" an invalid repository "iOS"/);
915 it('should throw when a repository group refers to a repository in building a patch which does not accept a patch', () => {
916 assert.throws(() => {
917 const config = smallConfiguration();
918 config.repositoryGroups = {'some-group': {
919 repositories: {'WebKit': {acceptsPatch: true}, 'iOS': {}},
920 testProperties: {'wk': {revision: 'WebKit'}, 'ios': {revision: 'iOS'}, 'install-roots': {'roots': {}}},
921 buildProperties: {'wk': {revision: 'WebKit'}, 'ios': {revision: 'iOS'}, 'wk-patch': {patch: 'iOS'}},
922 acceptsRoots: true}};
923 BuildbotSyncer._loadConfig(MockRemoteAPI, config, builderNameToIDMap());
924 }, /Repository group "some-group" specifies a patch for "iOS" but it does not accept a patch/);
927 it('should throw when a repository group specifies a patch without specifying a revision', () => {
928 assert.throws(() => {
929 const config = smallConfiguration();
930 config.repositoryGroups = {'some-group': {
931 repositories: {'WebKit': {acceptsPatch: true}},
932 testProperties: {'wk': {revision: 'WebKit'}, 'install-roots': {'roots': {}}},
933 buildProperties: {'wk-patch': {patch: 'WebKit'}},
934 acceptsRoots: true}};
935 BuildbotSyncer._loadConfig(MockRemoteAPI, config, builderNameToIDMap());
936 }, /Repository group "some-group" specifies a patch for "WebKit" but does not specify a revision/);
939 it('should throw when a repository group does not use a listed repository', () => {
940 assert.throws(() => {
941 const config = smallConfiguration();
942 config.repositoryGroups = {'some-group': {'repositories': {'WebKit': {}}, testProperties: {}}};
943 BuildbotSyncer._loadConfig(MockRemoteAPI, config, builderNameToIDMap());
944 }, /Repository group "some-group" does not use some of the repositories listed in testing/);
945 assert.throws(() => {
946 const config = smallConfiguration();
947 config.repositoryGroups = {'some-group': {
948 repositories: {'WebKit': {acceptsPatch: true}},
949 testProperties: {'wk': {revision: 'WebKit'}, 'install-roots': {'roots': {}}},
951 acceptsRoots: true}};
952 BuildbotSyncer._loadConfig(MockRemoteAPI, config, builderNameToIDMap());
953 }, /Repository group "some-group" does not use some of the repositories listed in building a patch/);
956 it('should throw when a repository group specifies non-boolean value to acceptsRoots', () => {
957 assert.throws(() => {
958 const config = smallConfiguration();
959 config.repositoryGroups = {'some-group': {'repositories': {'WebKit': {}}, 'testProperties': {'webkit': {'revision': 'WebKit'}}, acceptsRoots: 1}};
960 BuildbotSyncer._loadConfig(MockRemoteAPI, config, builderNameToIDMap());
961 }, /Repository group "some-group" contains invalid acceptsRoots value:/);
962 assert.throws(() => {
963 const config = smallConfiguration();
964 config.repositoryGroups = {'some-group': {'repositories': {'WebKit': {}}, 'testProperties': {'webkit': {'revision': 'WebKit'}}, acceptsRoots: []}};
965 BuildbotSyncer._loadConfig(MockRemoteAPI, config, builderNameToIDMap());
966 }, /Repository group "some-group" contains invalid acceptsRoots value:/);
969 it('should throw when a repository group specifies non-boolean value to acceptsPatch', () => {
970 assert.throws(() => {
971 const config = smallConfiguration();
972 config.repositoryGroups = {'some-group': {'repositories': {'WebKit': {acceptsPatch: 1}}, 'testProperties': {'webkit': {'revision': 'WebKit'}}}};
973 BuildbotSyncer._loadConfig(MockRemoteAPI, config, builderNameToIDMap());
974 }, /"WebKit" contains invalid acceptsPatch value:/);
975 assert.throws(() => {
976 const config = smallConfiguration();
977 config.repositoryGroups = {'some-group': {'repositories': {'WebKit': {acceptsPatch: []}}, 'testProperties': {'webkit': {'revision': 'WebKit'}}}};
978 BuildbotSyncer._loadConfig(MockRemoteAPI, config, builderNameToIDMap());
979 }, /"WebKit" contains invalid acceptsPatch value:/);
982 it('should throw when a repository group specifies a patch in testProperties', () => {
983 assert.throws(() => {
984 const config = smallConfiguration();
985 config.repositoryGroups = {'some-group': {'repositories': {'WebKit': {acceptsPatch: true}},
986 'testProperties': {'webkit': {'revision': 'WebKit'}, 'webkit-patch': {'patch': 'WebKit'}}}};
987 BuildbotSyncer._loadConfig(MockRemoteAPI, config, builderNameToIDMap());
988 }, /Repository group "some-group" specifies a patch for "WebKit" in the properties for testing/);
991 it('should throw when a repository group specifies roots in buildProperties', () => {
992 assert.throws(() => {
993 const config = smallConfiguration();
994 config.repositoryGroups = {'some-group': {
995 repositories: {'WebKit': {acceptsPatch: true}},
996 testProperties: {'webkit': {revision: 'WebKit'}, 'install-roots': {'roots': {}}},
997 buildProperties: {'webkit': {revision: 'WebKit'}, 'patch': {patch: 'WebKit'}, 'install-roots': {roots: {}}},
998 acceptsRoots: true}};
999 BuildbotSyncer._loadConfig(MockRemoteAPI, config, builderNameToIDMap());
1000 }, /Repository group "some-group" specifies roots in the properties for building/);
1003 it('should throw when a repository group that does not accept roots specifies roots in testProperties', () => {
1004 assert.throws(() => {
1005 const config = smallConfiguration();
1006 config.repositoryGroups = {'some-group': {
1007 repositories: {'WebKit': {}},
1008 testProperties: {'webkit': {'revision': 'WebKit'}, 'install-roots': {'roots': {}}}}};
1009 BuildbotSyncer._loadConfig(MockRemoteAPI, config, builderNameToIDMap());
1010 }, /Repository group "some-group" specifies roots in a property but it does not accept roots/);
1013 it('should throw when a repository group specifies buildProperties but does not accept roots', () => {
1014 assert.throws(() => {
1015 const config = smallConfiguration();
1016 config.repositoryGroups = {'some-group': {
1017 repositories: {'WebKit': {acceptsPatch: true}},
1018 testProperties: {'webkit': {revision: 'WebKit'}},
1019 buildProperties: {'webkit': {revision: 'WebKit'}, 'webkit-patch': {patch: 'WebKit'}}}};
1020 BuildbotSyncer._loadConfig(MockRemoteAPI, config, builderNameToIDMap());
1021 }, /Repository group "some-group" specifies the properties for building but does not accept roots in testing/);
1024 it('should throw when a repository group specifies buildProperties but does not accept any patch', () => {
1025 assert.throws(() => {
1026 const config = smallConfiguration();
1027 config.repositoryGroups = {'some-group': {
1028 repositories: {'WebKit': {}},
1029 testProperties: {'webkit': {'revision': 'WebKit'}, 'install-roots': {'roots': {}}},
1030 buildProperties: {'webkit': {'revision': 'WebKit'}},
1031 acceptsRoots: true}};
1032 BuildbotSyncer._loadConfig(MockRemoteAPI, config, builderNameToIDMap());
1033 }, /Repository group "some-group" specifies the properties for building but does not accept any patches/);
1036 it('should throw when a repository group accepts roots but does not specify roots in testProperties', () => {
1037 assert.throws(() => {
1038 const config = smallConfiguration();
1039 config.repositoryGroups = {'some-group': {
1040 repositories: {'WebKit': {acceptsPatch: true}},
1041 testProperties: {'webkit': {revision: 'WebKit'}},
1042 buildProperties: {'webkit': {revision: 'WebKit'}, 'webkit-patch': {patch: 'WebKit'}},
1043 acceptsRoots: true}};
1044 BuildbotSyncer._loadConfig(MockRemoteAPI, config, builderNameToIDMap());
1045 }, /Repository group "some-group" accepts roots but does not specify roots in testProperties/);
1049 describe('_propertiesForBuildRequest', () => {
1050 it('should include all properties specified in a given configuration', () => {
1051 const syncers = BuildbotSyncer._loadConfig(RemoteAPI, sampleiOSConfig(), builderNameToIDMap());
1052 const request = createSampleBuildRequest(MockModels.iphone, MockModels.speedometer);
1053 const properties = syncers[0]._propertiesForBuildRequest(request, [request]);
1054 assert.deepEqual(Object.keys(properties).sort(), ['build_request_id', 'desired_image', 'forcescheduler', 'opensource', 'test_name']);
1057 it('should preserve non-parametric property values', () => {
1058 const syncers = BuildbotSyncer._loadConfig(RemoteAPI, sampleiOSConfig(), builderNameToIDMap());
1059 let request = createSampleBuildRequest(MockModels.iphone, MockModels.speedometer);
1060 let properties = syncers[0]._propertiesForBuildRequest(request, [request]);
1061 assert.equal(properties['test_name'], 'speedometer');
1062 assert.equal(properties['forcescheduler'], 'ABTest-iPhone-RunBenchmark-Tests-ForceScheduler');
1064 request = createSampleBuildRequest(MockModels.ipad, MockModels.jetstream);
1065 properties = syncers[1]._propertiesForBuildRequest(request, [request]);
1066 assert.equal(properties['test_name'], 'jetstream');
1067 assert.equal(properties['forcescheduler'], 'ABTest-iPad-RunBenchmark-Tests-ForceScheduler');
1070 it('should resolve "root"', () => {
1071 const syncers = BuildbotSyncer._loadConfig(RemoteAPI, sampleiOSConfig(), builderNameToIDMap());
1072 const request = createSampleBuildRequest(MockModels.iphone, MockModels.speedometer);
1073 const properties = syncers[0]._propertiesForBuildRequest(request, [request]);
1074 assert.equal(properties['desired_image'], '13A452');
1077 it('should resolve "revision"', () => {
1078 const syncers = BuildbotSyncer._loadConfig(RemoteAPI, sampleiOSConfig(), builderNameToIDMap());
1079 const request = createSampleBuildRequest(MockModels.iphone, MockModels.speedometer);
1080 const properties = syncers[0]._propertiesForBuildRequest(request, [request]);
1081 assert.equal(properties['opensource'], '197463');
1084 it('should resolve "patch"', () => {
1085 const config = sampleiOSConfig();
1086 config.repositoryGroups['ios-svn-webkit'] = {
1087 'repositories': {'WebKit': {'acceptsPatch': true}, 'Shared': {}, 'iOS': {}},
1089 'os': {'revision': 'iOS'},
1090 'webkit': {'revision': 'WebKit'},
1091 'shared': {'revision': 'Shared'},
1092 'roots': {'roots': {}},
1094 'buildProperties': {
1095 'webkit': {'revision': 'WebKit'},
1096 'webkit-patch': {'patch': 'WebKit'},
1097 'checkbox': {'ifRepositorySet': ['WebKit'], 'value': 'build-webkit'},
1098 'shared': {'revision': 'Shared'},
1100 'acceptsRoots': true,
1102 const syncers = BuildbotSyncer._loadConfig(RemoteAPI, config, builderNameToIDMap());
1103 const request = createSampleBuildRequestWithPatch(MockModels.iphone, null, -1);
1104 const properties = syncers[2]._propertiesForBuildRequest(request, [request]);
1105 assert.equal(properties['webkit'], '197463');
1106 assert.equal(properties['webkit-patch'], 'http://build.webkit.org/api/uploaded-file/453.dat');
1107 assert.equal(properties['checkbox'], 'build-webkit');
1110 it('should resolve "ifBuilt"', () => {
1111 const config = sampleiOSConfig();
1112 config.repositoryGroups['ios-svn-webkit'] = {
1113 'repositories': {'WebKit': {}, 'Shared': {}, 'iOS': {}},
1115 'os': {'revision': 'iOS'},
1116 'webkit': {'revision': 'WebKit'},
1117 'shared': {'revision': 'Shared'},
1118 'roots': {'roots': {}},
1119 'test-custom-build': {'ifBuilt': [], 'value': ''},
1120 'has-built-patch': {'ifBuilt': [], 'value': 'true'},
1122 'acceptsRoots': true,
1124 const syncers = BuildbotSyncer._loadConfig(RemoteAPI, config, builderNameToIDMap());
1125 const requestToBuild = createSampleBuildRequestWithPatch(MockModels.iphone, null, -1);
1126 const requestToTest = createSampleBuildRequestWithPatch(MockModels.iphone, MockModels.speedometer, 0);
1127 const otherRequestToTest = createSampleBuildRequest(MockModels.iphone, MockModels.speedometer);
1129 let properties = syncers[0]._propertiesForBuildRequest(requestToTest, [requestToTest]);
1130 assert.equal(properties['webkit'], '197463');
1131 assert.equal(properties['roots'], '[{"url":"http://build.webkit.org/api/uploaded-file/456.dat"}]');
1132 assert.equal(properties['test-custom-build'], undefined);
1133 assert.equal(properties['has-built-patch'], undefined);
1135 properties = syncers[0]._propertiesForBuildRequest(requestToTest, [requestToBuild, requestToTest]);
1136 assert.equal(properties['webkit'], '197463');
1137 assert.equal(properties['roots'], '[{"url":"http://build.webkit.org/api/uploaded-file/456.dat"}]');
1138 assert.equal(properties['test-custom-build'], '');
1139 assert.equal(properties['has-built-patch'], 'true');
1141 properties = syncers[0]._propertiesForBuildRequest(otherRequestToTest, [requestToBuild, otherRequestToTest, requestToTest]);
1142 assert.equal(properties['webkit'], '197463');
1143 assert.equal(properties['roots'], undefined);
1144 assert.equal(properties['test-custom-build'], undefined);
1145 assert.equal(properties['has-built-patch'], undefined);
1149 it('should set the value for "ifBuilt" if the repository in the list appears', () => {
1150 const config = sampleiOSConfig();
1151 config.repositoryGroups['ios-svn-webkit'] = {
1152 'repositories': {'WebKit': {'acceptsPatch': true}, 'Shared': {}, 'iOS': {}},
1154 'os': {'revision': 'iOS'},
1155 'webkit': {'revision': 'WebKit'},
1156 'shared': {'revision': 'Shared'},
1157 'roots': {'roots': {}},
1158 'checkbox': {'ifBuilt': ['WebKit'], 'value': 'test-webkit'}
1160 'buildProperties': {
1161 'webkit': {'revision': 'WebKit'},
1162 'webkit-patch': {'patch': 'WebKit'},
1163 'checkbox': {'ifRepositorySet': ['WebKit'], 'value': 'build-webkit'},
1164 'shared': {'revision': 'Shared'},
1166 'acceptsRoots': true,
1168 const syncers = BuildbotSyncer._loadConfig(RemoteAPI, config, builderNameToIDMap());
1169 const requestToBuild = createSampleBuildRequestWithPatch(MockModels.iphone, null, -1);
1170 const requestToTest = createSampleBuildRequestWithPatch(MockModels.iphone, MockModels.speedometer, 0);
1171 const properties = syncers[0]._propertiesForBuildRequest(requestToTest, [requestToBuild, requestToTest]);
1172 assert.equal(properties['webkit'], '197463');
1173 assert.equal(properties['roots'], '[{"url":"http://build.webkit.org/api/uploaded-file/456.dat"}]');
1174 assert.equal(properties['checkbox'], 'test-webkit');
1177 it('should not set the value for "ifBuilt" if no build for the repository in the list appears', () => {
1178 const config = sampleiOSConfig();
1179 config.repositoryGroups['ios-svn-webkit-with-owned-commit'] = {
1180 'repositories': {'WebKit': {'acceptsPatch': true}, 'Owner Repository': {}, 'iOS': {}},
1182 'os': {'revision': 'iOS'},
1183 'webkit': {'revision': 'WebKit'},
1184 'owner-repo': {'revision': 'Owner Repository'},
1185 'roots': {'roots': {}},
1186 'checkbox': {'ifBuilt': ['WebKit'], 'value': 'test-webkit'}
1188 'buildProperties': {
1189 'webkit': {'revision': 'WebKit'},
1190 'webkit-patch': {'patch': 'WebKit'},
1191 'owner-repo': {'revision': 'Owner Repository'},
1192 'checkbox': {'ifRepositorySet': ['WebKit'], 'value': 'build-webkit'},
1193 'owned-commits': {'ownedRevisions': 'Owner Repository'}
1195 'acceptsRoots': true,
1197 const syncers = BuildbotSyncer._loadConfig(RemoteAPI, config, builderNameToIDMap());
1198 const requestToBuild = createSampleBuildRequestWithOwnedCommit(MockModels.iphone, null, -1);
1199 const requestToTest = createSampleBuildRequestWithOwnedCommit(MockModels.iphone, MockModels.speedometer, 0);
1200 const properties = syncers[0]._propertiesForBuildRequest(requestToTest, [requestToBuild, requestToTest]);
1202 assert.equal(properties['webkit'], '197463');
1203 assert.equal(properties['roots'], '[{"url":"http://build.webkit.org/api/uploaded-file/456.dat"}]');
1204 assert.equal(properties['checkbox'], undefined);
1207 it('should resolve "ifRepositorySet" and "requiresBuild"', () => {
1208 const config = sampleiOSConfig();
1209 config.repositoryGroups['ios-svn-webkit-with-owned-commit'] = {
1210 'repositories': {'WebKit': {'acceptsPatch': true}, 'Owner Repository': {}, 'iOS': {}},
1212 'os': {'revision': 'iOS'},
1213 'webkit': {'revision': 'WebKit'},
1214 'owner-repo': {'revision': 'Owner Repository'},
1215 'roots': {'roots': {}},
1217 'buildProperties': {
1218 'webkit': {'revision': 'WebKit'},
1219 'webkit-patch': {'patch': 'WebKit'},
1220 'owner-repo': {'revision': 'Owner Repository'},
1221 'checkbox': {'ifRepositorySet': ['WebKit'], 'value': 'build-webkit'},
1222 'owned-commits': {'ownedRevisions': 'Owner Repository'}
1224 'acceptsRoots': true,
1226 const syncers = BuildbotSyncer._loadConfig(RemoteAPI, config, builderNameToIDMap());
1227 const request = createSampleBuildRequestWithOwnedCommit(MockModels.iphone, null, -1);
1228 const properties = syncers[2]._propertiesForBuildRequest(request, [request]);
1229 assert.equal(properties['webkit'], '197463');
1230 assert.equal(properties['owner-repo'], 'owner-001');
1231 assert.equal(properties['checkbox'], undefined);
1232 assert.deepEqual(JSON.parse(properties['owned-commits']), {'Owner Repository': [{revision: 'owned-002', repository: 'Owned Repository', ownerRevision: 'owner-001'}]});
1235 it('should resolve "patch", "ifRepositorySet" and "requiresBuild"', () => {
1237 const config = sampleiOSConfig();
1238 config.repositoryGroups['ios-svn-webkit-with-owned-commit'] = {
1239 'repositories': {'WebKit': {'acceptsPatch': true}, 'Owner Repository': {}, 'iOS': {}},
1241 'os': {'revision': 'iOS'},
1242 'webkit': {'revision': 'WebKit'},
1243 'owner-repo': {'revision': 'Owner Repository'},
1244 'roots': {'roots': {}},
1246 'buildProperties': {
1247 'webkit': {'revision': 'WebKit'},
1248 'webkit-patch': {'patch': 'WebKit'},
1249 'owner-repo': {'revision': 'Owner Repository'},
1250 'checkbox': {'ifRepositorySet': ['WebKit'], 'value': 'build-webkit'},
1251 'owned-commits': {'ownedRevisions': 'Owner Repository'}
1253 'acceptsRoots': true,
1255 const syncers = BuildbotSyncer._loadConfig(RemoteAPI, config, builderNameToIDMap());
1256 const request = createSampleBuildRequestWithOwnedCommitAndPatch(MockModels.iphone, null, -1);
1257 const properties = syncers[2]._propertiesForBuildRequest(request, [request]);
1258 assert.equal(properties['webkit'], '197463');
1259 assert.equal(properties['owner-repo'], 'owner-001');
1260 assert.equal(properties['checkbox'], 'build-webkit');
1261 assert.equal(properties['webkit-patch'], 'http://build.webkit.org/api/uploaded-file/453.dat');
1262 assert.deepEqual(JSON.parse(properties['owned-commits']), {'Owner Repository': [{revision: 'owned-002', repository: 'Owned Repository', ownerRevision: 'owner-001'}]});
1265 it('should set the property for the build request id', () => {
1266 const syncers = BuildbotSyncer._loadConfig(RemoteAPI, sampleiOSConfig(), builderNameToIDMap());
1267 const request = createSampleBuildRequest(MockModels.iphone, MockModels.speedometer);
1268 const properties = syncers[0]._propertiesForBuildRequest(request, [request]);
1269 assert.equal(properties['build_request_id'], request.id());
1274 describe('BuildbotBuildEntry', () => {
1275 it('should create BuildbotBuildEntry for pending build', () => {
1276 let syncer = BuildbotSyncer._loadConfig(MockRemoteAPI, sampleiOSConfig(), builderNameToIDMap())[1];
1277 const buildbotData = samplePendingBuild();
1278 const pendingEntries = buildbotData.buildrequests.map((entry) => new BuildbotBuildEntry(syncer, entry));
1280 assert.equal(pendingEntries.length, 1);
1281 const entry = pendingEntries[0];
1282 assert.ok(entry instanceof BuildbotBuildEntry);
1283 assert.ok(!entry.buildNumber());
1284 assert.ok(!entry.workerName());
1285 assert.equal(entry.buildRequestId(), 16733);
1286 assert.ok(entry.isPending());
1287 assert.ok(!entry.isInProgress());
1288 assert.ok(!entry.hasFinished());
1289 assert.equal(entry.url(), 'http://build.webkit.org/#/buildrequests/16733');
1292 it('should create BuildbotBuildEntry for in-progress build', () => {
1293 let syncer = BuildbotSyncer._loadConfig(MockRemoteAPI, sampleiOSConfig(), builderNameToIDMap())[1];
1294 const buildbotData = sampleInProgressBuild();
1295 const entries = buildbotData.builds.map((entry) => new BuildbotBuildEntry(syncer, entry));
1297 assert.equal(entries.length, 1);
1298 const entry = entries[0];
1299 assert.ok(entry instanceof BuildbotBuildEntry);
1300 assert.equal(entry.buildNumber(), 614);
1301 assert.equal(entry.workerName(), 'ABTest-iPad-0');
1302 assert.equal(entry.buildRequestId(), 16733);
1303 assert.ok(!entry.isPending());
1304 assert.ok(entry.isInProgress());
1305 assert.ok(!entry.hasFinished());
1306 assert.equal(entry.url(), 'http://build.webkit.org/#/builders/102/builds/614');
1309 it('should create BuildbotBuildEntry for finished build', () => {
1310 let syncer = BuildbotSyncer._loadConfig(MockRemoteAPI, sampleiOSConfig(), builderNameToIDMap())[1];
1311 const buildbotData = sampleFinishedBuild();
1312 const entries = buildbotData.builds.map((entry) => new BuildbotBuildEntry(syncer, entry));
1314 assert.deepEqual(entries.length, 1);
1315 const entry = entries[0];
1316 assert.ok(entry instanceof BuildbotBuildEntry);
1317 assert.equal(entry.buildNumber(), 1755);
1318 assert.equal(entry.workerName(), 'ABTest-iPad-0');
1319 assert.equal(entry.buildRequestId(), 18935);
1320 assert.ok(!entry.isPending());
1321 assert.ok(!entry.isInProgress());
1322 assert.ok(entry.hasFinished());
1323 assert.equal(entry.url(), 'http://build.webkit.org/#/builders/102/builds/1755');
1326 it('should create BuildbotBuildEntry for mix of in-progress and finished builds', () => {
1327 let syncer = BuildbotSyncer._loadConfig(MockRemoteAPI, sampleiOSConfig(), builderNameToIDMap())[1];
1328 const buildbotData = {'builds': [sampleInProgressBuildData(), sampleFinishedBuildData()]};
1329 const entries = buildbotData.builds.map((entry) => new BuildbotBuildEntry(syncer, entry));
1331 assert.deepEqual(entries.length, 2);
1333 let entry = entries[0];
1334 assert.ok(entry instanceof BuildbotBuildEntry);
1335 assert.equal(entry.buildNumber(), 614);
1336 assert.equal(entry.workerName(), 'ABTest-iPad-0');
1337 assert.equal(entry.buildRequestId(), 16733);
1338 assert.ok(!entry.isPending());
1339 assert.ok(entry.isInProgress());
1340 assert.ok(!entry.hasFinished());
1341 assert.equal(entry.url(), 'http://build.webkit.org/#/builders/102/builds/614');
1344 assert.ok(entry instanceof BuildbotBuildEntry);
1345 assert.equal(entry.buildNumber(), 1755);
1346 assert.equal(entry.slaveName(), 'ABTest-iPad-0');
1347 assert.equal(entry.buildRequestId(), 18935);
1348 assert.ok(!entry.isPending());
1349 assert.ok(!entry.isInProgress());
1350 assert.ok(entry.hasFinished());
1351 assert.equal(entry.url(), 'http://build.webkit.org/#/builders/102/builds/1755');
1355 describe('pullBuildbot', () => {
1356 it('should fetch pending builds from the right URL', () => {
1357 let syncer = BuildbotSyncer._loadConfig(MockRemoteAPI, sampleiOSConfig(), builderNameToIDMap())[1];
1358 assert.equal(syncer.builderName(), 'ABTest-iPad-RunBenchmark-Tests');
1359 let expectedURL = '/json/builders/ABTest-iPad-RunBenchmark-Tests/pendingBuilds';
1360 assert.equal(syncer.pathForPendingBuildsJSONDeprecated(), expectedURL);
1361 syncer.pullBuildbot();
1362 assert.equal(requests.length, 1);
1363 assert.equal(requests[0].url, expectedURL);
1366 it('should fetch recent builds once pending builds have been fetched', () => {
1367 let syncer = BuildbotSyncer._loadConfig(MockRemoteAPI, sampleiOSConfig(), builderNameToIDMap())[1];
1368 assert.equal(syncer.builderName(), 'ABTest-iPad-RunBenchmark-Tests');
1370 syncer.pullBuildbot(1);
1371 assert.equal(requests.length, 1);
1372 assert.equal(requests[0].url, '/json/builders/ABTest-iPad-RunBenchmark-Tests/pendingBuilds');
1373 requests[0].resolve([]);
1374 return MockRemoteAPI.waitForRequest().then(() => {
1375 assert.equal(requests.length, 2);
1376 assert.equal(requests[1].url, '/json/builders/ABTest-iPad-RunBenchmark-Tests/builds/?select=-1');
1380 it('should fetch the right number of recent builds', () => {
1381 let syncer = BuildbotSyncer._loadConfig(MockRemoteAPI, sampleiOSConfig(), builderNameToIDMap())[1];
1383 syncer.pullBuildbot(3);
1384 assert.equal(requests.length, 1);
1385 assert.equal(requests[0].url, '/json/builders/ABTest-iPad-RunBenchmark-Tests/pendingBuilds');
1386 requests[0].resolve([]);
1387 return MockRemoteAPI.waitForRequest().then(() => {
1388 assert.equal(requests.length, 2);
1389 assert.equal(requests[1].url, '/json/builders/ABTest-iPad-RunBenchmark-Tests/builds/?select=-1&select=-2&select=-3');
1393 it('should create BuildbotBuildEntry for pending builds', () => {
1394 let syncer = BuildbotSyncer._loadConfig(MockRemoteAPI, sampleiOSConfig(), builderNameToIDMap())[1];
1395 let promise = syncer.pullBuildbot();
1396 requests[0].resolve([samplePendingBuildDeprecated()]);
1397 return promise.then((entries) => {
1398 assert.equal(entries.length, 1);
1399 let entry = entries[0];
1400 assert.ok(entry instanceof BuildbotBuildEntryDeprecated);
1401 assert.ok(!entry.buildNumber());
1402 assert.ok(!entry.slaveName());
1403 assert.equal(entry.buildRequestId(), 16733);
1404 assert.ok(entry.isPending());
1405 assert.ok(!entry.isInProgress());
1406 assert.ok(!entry.hasFinished());
1407 assert.equal(entry.url(), 'http://build.webkit.org/builders/ABTest-iPad-RunBenchmark-Tests/');
1411 it('should create BuildbotBuildEntry for in-progress builds', () => {
1412 let syncer = BuildbotSyncer._loadConfig(MockRemoteAPI, sampleiOSConfig(), builderNameToIDMap())[1];
1414 let promise = syncer.pullBuildbot(1);
1415 assert.equal(requests.length, 1);
1416 requests[0].resolve([]);
1417 return MockRemoteAPI.waitForRequest().then(() => {
1418 assert.equal(requests.length, 2);
1419 requests[1].resolve({[-1]: sampleInProgressBuildDeprecated()});
1421 }).then((entries) => {
1422 assert.equal(entries.length, 1);
1423 let entry = entries[0];
1424 assert.ok(entry instanceof BuildbotBuildEntryDeprecated);
1425 assert.equal(entry.buildNumber(), 614);
1426 assert.equal(entry.slaveName(), 'ABTest-iPad-0');
1427 assert.equal(entry.buildRequestId(), 16733);
1428 assert.ok(!entry.isPending());
1429 assert.ok(entry.isInProgress());
1430 assert.ok(!entry.hasFinished());
1431 assert.equal(entry.url(), 'http://build.webkit.org/builders/ABTest-iPad-RunBenchmark-Tests/builds/614');
1435 it('should create BuildbotBuildEntry for finished builds', () => {
1436 let syncer = BuildbotSyncer._loadConfig(MockRemoteAPI, sampleiOSConfig(), builderNameToIDMap())[1];
1438 let promise = syncer.pullBuildbot(1);
1439 assert.equal(requests.length, 1);
1440 requests[0].resolve([]);
1441 return MockRemoteAPI.waitForRequest().then(() => {
1442 assert.equal(requests.length, 2);
1443 requests[1].resolve({[-1]: sampleFinishedBuildDeprecated()});
1445 }).then((entries) => {
1446 assert.deepEqual(entries.length, 1);
1447 let entry = entries[0];
1448 assert.ok(entry instanceof BuildbotBuildEntryDeprecated);
1449 assert.equal(entry.buildNumber(), 1755);
1450 assert.equal(entry.slaveName(), 'ABTest-iPad-0');
1451 assert.equal(entry.buildRequestId(), 18935);
1452 assert.ok(!entry.isPending());
1453 assert.ok(!entry.isInProgress());
1454 assert.ok(entry.hasFinished());
1455 assert.equal(entry.url(), 'http://build.webkit.org/builders/ABTest-iPad-RunBenchmark-Tests/builds/1755');
1459 it('should create BuildbotBuildEntry for mixed pending, in-progress, finished, and missing builds', () => {
1460 let syncer = BuildbotSyncer._loadConfig(MockRemoteAPI, sampleiOSConfig(), builderNameToIDMap())[1];
1462 let promise = syncer.pullBuildbot(5);
1463 assert.equal(requests.length, 1);
1465 requests[0].resolve([samplePendingBuildDeprecated(123)]);
1467 return MockRemoteAPI.waitForRequest().then(() => {
1468 assert.equal(requests.length, 2);
1469 requests[1].resolve({[-1]: sampleFinishedBuildDeprecated(), [-2]: {'error': 'Not available'}, [-4]: sampleInProgressBuildDeprecated()});
1471 }).then((entries) => {
1472 assert.deepEqual(entries.length, 3);
1474 let entry = entries[0];
1475 assert.ok(entry instanceof BuildbotBuildEntryDeprecated);
1476 assert.equal(entry.buildNumber(), null);
1477 assert.equal(entry.slaveName(), null);
1478 assert.equal(entry.buildRequestId(), 123);
1479 assert.ok(entry.isPending());
1480 assert.ok(!entry.isInProgress());
1481 assert.ok(!entry.hasFinished());
1482 assert.equal(entry.url(), 'http://build.webkit.org/builders/ABTest-iPad-RunBenchmark-Tests/');
1485 assert.ok(entry instanceof BuildbotBuildEntryDeprecated);
1486 assert.equal(entry.buildNumber(), 614);
1487 assert.equal(entry.slaveName(), 'ABTest-iPad-0');
1488 assert.equal(entry.buildRequestId(), 16733);
1489 assert.ok(!entry.isPending());
1490 assert.ok(entry.isInProgress());
1491 assert.ok(!entry.hasFinished());
1492 assert.equal(entry.url(), 'http://build.webkit.org/builders/ABTest-iPad-RunBenchmark-Tests/builds/614');
1495 assert.ok(entry instanceof BuildbotBuildEntryDeprecated);
1496 assert.equal(entry.buildNumber(), 1755);
1497 assert.equal(entry.slaveName(), 'ABTest-iPad-0');
1498 assert.equal(entry.buildRequestId(), 18935);
1499 assert.ok(!entry.isPending());
1500 assert.ok(!entry.isInProgress());
1501 assert.ok(entry.hasFinished());
1502 assert.equal(entry.url(), 'http://build.webkit.org/builders/ABTest-iPad-RunBenchmark-Tests/builds/1755');
1506 it('should sort BuildbotBuildEntry by order', () => {
1507 let syncer = BuildbotSyncer._loadConfig(MockRemoteAPI, sampleiOSConfig(), builderNameToIDMap())[1];
1509 let promise = syncer.pullBuildbot(5);
1510 assert.equal(requests.length, 1);
1512 requests[0].resolve([samplePendingBuildDeprecated(456, 2), samplePendingBuildDeprecated(123, 1)]);
1514 return MockRemoteAPI.waitForRequest().then(() => {
1515 assert.equal(requests.length, 2);
1516 requests[1].resolve({[-3]: sampleFinishedBuildDeprecated(), [-1]: {'error': 'Not available'}, [-2]: sampleInProgressBuildDeprecated()});
1518 }).then((entries) => {
1519 assert.deepEqual(entries.length, 4);
1521 let entry = entries[0];
1522 assert.ok(entry instanceof BuildbotBuildEntryDeprecated);
1523 assert.equal(entry.buildNumber(), null);
1524 assert.equal(entry.slaveName(), null);
1525 assert.equal(entry.buildRequestId(), 123);
1526 assert.ok(entry.isPending());
1527 assert.ok(!entry.isInProgress());
1528 assert.ok(!entry.hasFinished());
1529 assert.equal(entry.url(), 'http://build.webkit.org/builders/ABTest-iPad-RunBenchmark-Tests/');
1532 assert.ok(entry instanceof BuildbotBuildEntryDeprecated);
1533 assert.equal(entry.buildNumber(), null);
1534 assert.equal(entry.slaveName(), null);
1535 assert.equal(entry.buildRequestId(), 456);
1536 assert.ok(entry.isPending());
1537 assert.ok(!entry.isInProgress());
1538 assert.ok(!entry.hasFinished());
1539 assert.equal(entry.url(), 'http://build.webkit.org/builders/ABTest-iPad-RunBenchmark-Tests/');
1542 assert.ok(entry instanceof BuildbotBuildEntryDeprecated);
1543 assert.equal(entry.buildNumber(), 614);
1544 assert.equal(entry.slaveName(), 'ABTest-iPad-0');
1545 assert.equal(entry.buildRequestId(), 16733);
1546 assert.ok(!entry.isPending());
1547 assert.ok(entry.isInProgress());
1548 assert.ok(!entry.hasFinished());
1549 assert.equal(entry.url(), 'http://build.webkit.org/builders/ABTest-iPad-RunBenchmark-Tests/builds/614');
1552 assert.ok(entry instanceof BuildbotBuildEntryDeprecated);
1553 assert.equal(entry.buildNumber(), 1755);
1554 assert.equal(entry.slaveName(), 'ABTest-iPad-0');
1555 assert.equal(entry.buildRequestId(), 18935);
1556 assert.ok(!entry.isPending());
1557 assert.ok(!entry.isInProgress());
1558 assert.ok(entry.hasFinished());
1559 assert.equal(entry.url(), 'http://build.webkit.org/builders/ABTest-iPad-RunBenchmark-Tests/builds/1755');
1563 it('should override BuildbotBuildEntry for pending builds by in-progress builds', () => {
1564 let syncer = BuildbotSyncer._loadConfig(MockRemoteAPI, sampleiOSConfig(), builderNameToIDMap())[1];
1566 let promise = syncer.pullBuildbot(5);
1567 assert.equal(requests.length, 1);
1569 requests[0].resolve([samplePendingBuildDeprecated()]);
1571 return MockRemoteAPI.waitForRequest().then(() => {
1572 assert.equal(requests.length, 2);
1573 requests[1].resolve({[-1]: sampleInProgressBuildDeprecated()});
1575 }).then((entries) => {
1576 assert.equal(entries.length, 1);
1578 let entry = entries[0];
1579 assert.ok(entry instanceof BuildbotBuildEntryDeprecated);
1580 assert.equal(entry.buildNumber(), 614);
1581 assert.equal(entry.slaveName(), 'ABTest-iPad-0');
1582 assert.equal(entry.buildRequestId(), 16733);
1583 assert.ok(!entry.isPending());
1584 assert.ok(entry.isInProgress());
1585 assert.ok(!entry.hasFinished());
1586 assert.equal(entry.url(), 'http://build.webkit.org/builders/ABTest-iPad-RunBenchmark-Tests/builds/614');
1590 it('should override BuildbotBuildEntry for pending builds by finished builds', () => {
1591 let syncer = BuildbotSyncer._loadConfig(MockRemoteAPI, sampleiOSConfig(), builderNameToIDMap())[1];
1593 let promise = syncer.pullBuildbot(5);
1594 assert.equal(requests.length, 1);
1596 requests[0].resolve([samplePendingBuildDeprecated()]);
1598 return MockRemoteAPI.waitForRequest().then(() => {
1599 assert.equal(requests.length, 2);
1600 requests[1].resolve({[-1]: sampleFinishedBuildDeprecated(16733)});
1602 }).then((entries) => {
1603 assert.equal(entries.length, 1);
1605 let entry = entries[0];
1606 assert.ok(entry instanceof BuildbotBuildEntryDeprecated);
1607 assert.equal(entry.buildNumber(), 1755);
1608 assert.equal(entry.slaveName(), 'ABTest-iPad-0');
1609 assert.equal(entry.buildRequestId(), 16733);
1610 assert.ok(!entry.isPending());
1611 assert.ok(!entry.isInProgress());
1612 assert.ok(entry.hasFinished());
1613 assert.equal(entry.url(), 'http://build.webkit.org/builders/ABTest-iPad-RunBenchmark-Tests/builds/1755');
1618 describe('scheduleRequest', () => {
1619 it('should schedule a build request on a specified slave', () => {
1620 let syncer = BuildbotSyncer._loadConfig(MockRemoteAPI, sampleiOSConfig(), builderNameToIDMap())[0];
1622 const waitForRequest = MockRemoteAPI.waitForRequest();
1623 const request = createSampleBuildRequest(MockModels.iphone, MockModels.speedometer);
1624 syncer.scheduleRequest(request, [request], 'some-slave');
1625 return waitForRequest.then(() => {
1626 assert.equal(requests.length, 1);
1627 assert.equal(requests[0].url, '/builders/ABTest-iPhone-RunBenchmark-Tests/force');
1628 assert.equal(requests[0].method, 'POST');
1629 assert.deepEqual(requests[0].data, {
1630 'build_request_id': '16733-' + MockModels.iphone.id(),
1631 'desired_image': '13A452',
1632 "opensource": "197463",
1633 'forcescheduler': 'ABTest-iPhone-RunBenchmark-Tests-ForceScheduler',
1634 'slavename': 'some-slave',
1635 'test_name': 'speedometer'
1641 describe('scheduleRequestInGroupIfAvailable', () => {
1643 function pullBuildbotWithAssertion(syncer, pendingBuilds, inProgressAndFinishedBuilds)
1645 const promise = syncer.pullBuildbot(5);
1646 assert.equal(requests.length, 1);
1647 requests[0].resolve(pendingBuilds);
1648 return MockRemoteAPI.waitForRequest().then(() => {
1649 assert.equal(requests.length, 2);
1650 requests[1].resolve(inProgressAndFinishedBuilds);
1651 requests.length = 0;
1656 it('should schedule a build if builder has no builds if slaveList is not specified', () => {
1657 let syncer = BuildbotSyncer._loadConfig(MockRemoteAPI, smallConfiguration(), builderNameToIDMap())[0];
1659 return pullBuildbotWithAssertion(syncer, [], {}).then(() => {
1660 const request = createSampleBuildRequest(MockModels.somePlatform, MockModels.someTest);
1661 syncer.scheduleRequestInGroupIfAvailable(request, [request]);
1662 assert.equal(requests.length, 1);
1663 assert.equal(requests[0].url, '/builders/some%20builder/force');
1664 assert.equal(requests[0].method, 'POST');
1665 assert.deepEqual(requests[0].data, {id: '16733-' + MockModels.somePlatform.id(), 'os': '13A452', 'wk': '197463'});
1669 it('should schedule a build if builder only has finished builds if slaveList is not specified', () => {
1670 let syncer = BuildbotSyncer._loadConfig(MockRemoteAPI, smallConfiguration(), builderNameToIDMap())[0];
1672 return pullBuildbotWithAssertion(syncer, [], {[-1]: smallFinishedBuild()}).then(() => {
1673 const request = createSampleBuildRequest(MockModels.somePlatform, MockModels.someTest);
1674 syncer.scheduleRequestInGroupIfAvailable(request, [request]);
1675 assert.equal(requests.length, 1);
1676 assert.equal(requests[0].url, '/builders/some%20builder/force');
1677 assert.equal(requests[0].method, 'POST');
1678 assert.deepEqual(requests[0].data, {id: '16733-' + MockModels.somePlatform.id(), 'os': '13A452', 'wk': '197463'});
1682 it('should not schedule a build if builder has a pending build if slaveList is not specified', () => {
1683 let syncer = BuildbotSyncer._loadConfig(MockRemoteAPI, smallConfiguration(), builderNameToIDMap())[0];
1685 return pullBuildbotWithAssertion(syncer, [smallPendingBuild()], {}).then(() => {
1686 syncer.scheduleRequestInGroupIfAvailable(createSampleBuildRequest(MockModels.somePlatform, MockModels.someTest));
1687 assert.equal(requests.length, 0);
1691 it('should schedule a build if builder does not have pending or completed builds on the matching slave', () => {
1692 let syncer = BuildbotSyncer._loadConfig(MockRemoteAPI, sampleiOSConfig(), builderNameToIDMap())[0];
1694 return pullBuildbotWithAssertion(syncer, [], {}).then(() => {
1695 const request = createSampleBuildRequest(MockModels.iphone, MockModels.speedometer);
1696 syncer.scheduleRequestInGroupIfAvailable(request, [request], null);
1697 assert.equal(requests.length, 1);
1698 assert.equal(requests[0].url, '/builders/ABTest-iPhone-RunBenchmark-Tests/force');
1699 assert.equal(requests[0].method, 'POST');
1703 it('should schedule a build if builder only has finished builds on the matching slave', () => {
1704 let syncer = BuildbotSyncer._loadConfig(MockRemoteAPI, sampleiOSConfig(), builderNameToIDMap())[1];
1706 pullBuildbotWithAssertion(syncer, [], {[-1]: sampleFinishedBuildDeprecated()}).then(() => {
1707 const request = createSampleBuildRequest(MockModels.ipad, MockModels.speedometer);
1708 syncer.scheduleRequestInGroupIfAvailable(request, [request], null);
1709 assert.equal(requests.length, 1);
1710 assert.equal(requests[0].url, '/builders/ABTest-iPad-RunBenchmark-Tests/force');
1711 assert.equal(requests[0].method, 'POST');
1715 it('should not schedule a build if builder has a pending build on the maching slave', () => {
1716 let syncer = BuildbotSyncer._loadConfig(MockRemoteAPI, sampleiOSConfig(), builderNameToIDMap())[1];
1718 pullBuildbotWithAssertion(syncer, [samplePendingBuildDeprecated()], {}).then(() => {
1719 const request = createSampleBuildRequest(MockModels.ipad, MockModels.speedometer);
1720 syncer.scheduleRequestInGroupIfAvailable(request, [request], null);
1721 assert.equal(requests.length, 0);
1725 it('should schedule a build if builder only has a pending build on a non-maching slave', () => {
1726 let syncer = BuildbotSyncer._loadConfig(MockRemoteAPI, sampleiOSConfig(), builderNameToIDMap())[1];
1728 return pullBuildbotWithAssertion(syncer, [samplePendingBuildDeprecated(1, 1, 'another-slave')], {}).then(() => {
1729 const request = createSampleBuildRequest(MockModels.ipad, MockModels.speedometer);
1730 syncer.scheduleRequestInGroupIfAvailable(request, [request], null);
1731 assert.equal(requests.length, 1);
1735 it('should schedule a build if builder only has an in-progress build on the matching slave', () => {
1736 let syncer = BuildbotSyncer._loadConfig(MockRemoteAPI, sampleiOSConfig(), builderNameToIDMap())[1];
1738 return pullBuildbotWithAssertion(syncer, [], {[-1]: sampleInProgressBuildDeprecated()}).then(() => {
1739 const request = createSampleBuildRequest(MockModels.ipad, MockModels.speedometer);
1740 syncer.scheduleRequestInGroupIfAvailable(request, [request], null);
1741 assert.equal(requests.length, 1);
1745 it('should schedule a build if builder has an in-progress build on another slave', () => {
1746 let syncer = BuildbotSyncer._loadConfig(MockRemoteAPI, sampleiOSConfig(), builderNameToIDMap())[1];
1748 return pullBuildbotWithAssertion(syncer, [], {[-1]: sampleInProgressBuildDeprecated('other-slave')}).then(() => {
1749 const request = createSampleBuildRequest(MockModels.ipad, MockModels.speedometer);
1750 syncer.scheduleRequestInGroupIfAvailable(request, [request], null);
1751 assert.equal(requests.length, 1);
1755 it('should not schedule a build if the request does not match any configuration', () => {
1756 let syncer = BuildbotSyncer._loadConfig(MockRemoteAPI, sampleiOSConfig(), builderNameToIDMap())[0];
1758 return pullBuildbotWithAssertion(syncer, [], {}).then(() => {
1759 const request = createSampleBuildRequest(MockModels.ipad, MockModels.speedometer);
1760 syncer.scheduleRequestInGroupIfAvailable(request, [request], null);
1761 assert.equal(requests.length, 0);
1765 it('should not schedule a build if a new request had been submitted to the same slave', (done) => {
1766 let syncer = BuildbotSyncer._loadConfig(MockRemoteAPI, sampleiOSConfig(), builderNameToIDMap())[1];
1768 pullBuildbotWithAssertion(syncer, [], {}).then(() => {
1769 let request = createSampleBuildRequest(MockModels.ipad, MockModels.speedometer);
1770 syncer.scheduleRequest(request, [request], 'ABTest-iPad-0');
1771 request = createSampleBuildRequest(MockModels.ipad, MockModels.speedometer);
1772 syncer.scheduleRequest(request, [request], 'ABTest-iPad-1');
1774 assert.equal(requests.length, 2);
1775 const request = createSampleBuildRequest(MockModels.ipad, MockModels.speedometer);
1776 syncer.scheduleRequestInGroupIfAvailable(request, [request], null);
1778 assert.equal(requests.length, 2);
1783 it('should schedule a build if a new request had been submitted to another slave', () => {
1784 let syncer = BuildbotSyncer._loadConfig(MockRemoteAPI, sampleiOSConfig(), builderNameToIDMap())[1];
1786 return pullBuildbotWithAssertion(syncer, [], {}).then(() => {
1787 let request = createSampleBuildRequest(MockModels.ipad, MockModels.speedometer);
1788 syncer.scheduleRequest(request, [request], 'ABTest-iPad-0');
1789 assert.equal(requests.length, 1);
1790 request = createSampleBuildRequest(MockModels.ipad, MockModels.speedometer)
1791 syncer.scheduleRequestInGroupIfAvailable(request, [request], 'ABTest-iPad-1');
1792 assert.equal(requests.length, 2);
1796 it('should not schedule a build if a new request had been submitted to the same builder without slaveList', () => {
1797 let syncer = BuildbotSyncer._loadConfig(MockRemoteAPI, smallConfiguration(), builderNameToIDMap())[0];
1799 return pullBuildbotWithAssertion(syncer, [], {}).then(() => {
1800 let request = createSampleBuildRequest(MockModels.somePlatform, MockModels.someTest);
1801 syncer.scheduleRequest(request, [request], null);
1802 assert.equal(requests.length, 1);
1803 request = createSampleBuildRequest(MockModels.somePlatform, MockModels.someTest);
1804 syncer.scheduleRequestInGroupIfAvailable(request, [request], null);
1805 assert.equal(requests.length, 1);