Add a model for parsing buildbot JSON with unit tests
[WebKit-https.git] / Websites / perf.webkit.org / unit-tests / buildbot-syncer-tests.js
1 'use strict';
2
3 let assert = require('assert');
4
5 require('./resources/mock-remote-api.js');
6 require('../tools/js/v3-models.js');
7 require('./resources/mock-v3-models.js');
8
9 let BuildbotBuildEntry = require('../tools/js/buildbot-syncer.js').BuildbotBuildEntry;
10 let BuildbotSyncer = require('../tools/js/buildbot-syncer.js').BuildbotSyncer;
11
12 function sampleiOSConfig()
13 {
14     return {
15         'shared':
16             {
17                 'arguments': {
18                     'desired_image': {'root': 'iOS'},
19                     'roots_dict': {'rootsExcluding': ['iOS']}
20                 },
21                 'slaveArgument': 'slavename',
22                 'buildRequestArgument': 'build_request_id'
23             },
24         'types': {
25             'speedometer': {
26                 'test': ['Speedometer'],
27                 'arguments': {'test_name': 'speedometer'}
28             },
29             'jetstream': {
30                 'test': ['JetStream'],
31                 'arguments': {'test_name': 'jetstream'}
32             },
33             "dromaeo-dom": {
34                 "test": ["Dromaeo", "DOM Core Tests"],
35                 "arguments": {"tests": "dromaeo-dom"}
36             },
37         },
38         'builders': {
39             'iPhone-bench': {
40                 'builder': 'ABTest-iPhone-RunBenchmark-Tests',
41                 'arguments': { 'forcescheduler': 'ABTest-iPhone-RunBenchmark-Tests-ForceScheduler' }
42             },
43             'iPad-bench': {
44                 'builder': 'ABTest-iPad-RunBenchmark-Tests',
45                 'arguments': { 'forcescheduler': 'ABTest-iPad-RunBenchmark-Tests-ForceScheduler' }
46             }
47         },
48         'configurations': [
49             {'type': 'speedometer', 'builder': 'iPhone-bench', 'platform': 'iPhone'},
50             {'type': 'jetstream', 'builder': 'iPhone-bench', 'platform': 'iPhone'},
51             {'type': 'dromaeo-dom', 'builder': 'iPhone-bench', 'platform': 'iPhone'},
52
53             {'type': 'speedometer', 'builder': 'iPad-bench', 'platform': 'iPad'},
54             {'type': 'jetstream', 'builder': 'iPad-bench', 'platform': 'iPad'},
55         ]
56     };
57 }
58
59 let sampleRootSetData = {
60     'WebKit': {
61         'id': '111127',
62         'time': 1456955807334,
63         'repository': 'WebKit',
64         'revision': '197463',
65     },
66     'Shared': {
67         'id': '111237',
68         'time': 1456931874000,
69         'repository': 'Shared',
70         'revision': '80229',
71     }
72 };
73
74 function createSampleBuildRequest()
75 {
76     let rootSet = RootSet.ensureSingleton('4197', {roots: [
77         {'id': '111127', 'time': 1456955807334, 'repository': webkit, 'revision': '197463'},
78         {'id': '111237', 'time': 1456931874000, 'repository': sharedRepository, 'revision': '80229'},
79         {'id': '88930', 'time': 0, 'repository': ios, 'revision': '13A452'},
80     ]});
81
82     let request = BuildRequest.ensureSingleton('16733', {'rootSet': rootSet, 'status': 'pending'});
83     return request;
84 }
85
86 let samplePendingBuilds = [
87     {
88         'builderName': 'ABTest-iPad-RunBenchmark-Tests',
89         'builds': [],
90         'properties': [
91             ['build_request_id', '16733', 'Force Build Form'],
92             ['desired_image', '13A452', 'Force Build Form'],
93             ['owner', '<unknown>', 'Force Build Form'],
94             ['test_name', 'speedometer', 'Force Build Form'],
95             ['reason', 'force build','Force Build Form'],
96             [
97                 'roots_dict',
98                 JSON.stringify(sampleRootSetData),
99                 'Force Build Form'
100             ],
101             ['scheduler', 'ABTest-iPad-Performance-Tests-ForceScheduler', 'Scheduler']
102         ],
103         'source': {
104             'branch': '',
105             'changes': [],
106             'codebase': 'compiler-rt',
107             'hasPatch': false,
108             'project': '',
109             'repository': '',
110             'revision': ''
111         },
112         'submittedAt': 1458704983
113     }
114 ];
115
116 describe('BuildbotSyncer', function () {
117     describe('fetchPendingBuilds', function () {
118         BuildbotSyncer.fetchPendingBuilds
119     });
120
121     describe('_loadConfig', function () {
122
123         function smallConfiguration()
124         {
125             return {
126                 'builder': 'some builder',
127                 'platform': 'some platform',
128                 'test': ['some test'],
129                 'arguments': {},
130                 'buildRequestArgument': 'id'};
131         }
132
133         it('should create BuildbotSyncer objects for a configuration that specify all required options', function () {
134             let syncers = BuildbotSyncer._loadConfig('http://build.webkit.org/', {'configurations': [smallConfiguration()]});
135             assert.equal(syncers.length, 1);
136         });
137
138         it('should throw when some required options are missing', function () {
139             assert.throws(function () {
140                 let config = smallConfiguration();
141                 delete config['builder'];
142                 BuildbotSyncer._loadConfig('http://build.webkit.org/', {'configurations': [config]});
143             }, 'builder should be a required option');
144             assert.throws(function () {
145                 let config = smallConfiguration();
146                 delete config['platform'];
147                 BuildbotSyncer._loadConfig('http://build.webkit.org/', {'configurations': [config]});
148             }, 'platform should be a required option');
149             assert.throws(function () {
150                 let config = smallConfiguration();
151                 delete config['test'];
152                 BuildbotSyncer._loadConfig('http://build.webkit.org/', {'configurations': [config]});
153             }, 'test should be a required option');
154             assert.throws(function () {
155                 let config = smallConfiguration();
156                 delete config['arguments'];
157                 BuildbotSyncer._loadConfig('http://build.webkit.org/', {'configurations': [config]});
158             });
159             assert.throws(function () {
160                 let config = smallConfiguration();
161                 delete config['buildRequestArgument'];
162                 BuildbotSyncer._loadConfig('http://build.webkit.org/', {'configurations': [config]});
163             });
164         });
165
166         it('should throw when a test name is not an array of strings', function () {
167             assert.throws(function () {
168                 let config = smallConfiguration();
169                 config.test = 'some test';
170                 BuildbotSyncer._loadConfig('http://build.webkit.org/', {'configurations': [config]});
171             });
172             assert.throws(function () {
173                 let config = smallConfiguration();
174                 config.test = [1];
175                 BuildbotSyncer._loadConfig('http://build.webkit.org/', {'configurations': [config]});
176             });
177         });
178
179         it('should throw when arguments is not an object', function () {
180             assert.throws(function () {
181                 let config = smallConfiguration();
182                 config.arguments = 'hello';
183                 BuildbotSyncer._loadConfig('http://build.webkit.org/', {'configurations': [config]});
184             });
185         });
186
187         it('should throw when arguments\'s values are malformed', function () {
188             assert.throws(function () {
189                 let config = smallConfiguration();
190                 config.arguments = {'some': {'root': 'some root', 'rootsExcluding': ['other root']}};
191                 BuildbotSyncer._loadConfig('http://build.webkit.org/', {'configurations': [config]});
192             });
193             assert.throws(function () {
194                 let config = smallConfiguration();
195                 config.arguments = {'some': {'otherKey': 'some root'}};
196                 BuildbotSyncer._loadConfig('http://build.webkit.org/', {'configurations': [config]});
197             });
198             assert.throws(function () {
199                 let config = smallConfiguration();
200                 config.arguments = {'some': {'root': ['a', 'b']}};
201                 BuildbotSyncer._loadConfig('http://build.webkit.org/', {'configurations': [config]});
202             });
203             assert.throws(function () {
204                 let config = smallConfiguration();
205                 config.arguments = {'some': {'root': 1}};
206                 BuildbotSyncer._loadConfig('http://build.webkit.org/', {'configurations': [config]});
207             });
208             assert.throws(function () {
209                 let config = smallConfiguration();
210                 config.arguments = {'some': {'rootsExcluding': 'a'}};
211                 BuildbotSyncer._loadConfig('http://build.webkit.org/', {'configurations': [config]});
212             });
213             assert.throws(function () {
214                 let config = smallConfiguration();
215                 config.arguments = {'some': {'rootsExcluding': [1]}};
216                 BuildbotSyncer._loadConfig('http://build.webkit.org/', {'configurations': [config]});
217             });
218         });
219
220         it('should create BuildbotSyncer objects for valid configurations', function () {
221             let syncers = BuildbotSyncer._loadConfig('http://build.webkit.org/', sampleiOSConfig());
222             assert.equal(syncers.length, 5);
223             assert.ok(syncers[0] instanceof BuildbotSyncer);
224             assert.ok(syncers[1] instanceof BuildbotSyncer);
225             assert.ok(syncers[2] instanceof BuildbotSyncer);
226             assert.ok(syncers[3] instanceof BuildbotSyncer);
227             assert.ok(syncers[4] instanceof BuildbotSyncer);
228         });
229
230         it('should parse builder names correctly', function () {
231             let syncers = BuildbotSyncer._loadConfig('http://build.webkit.org/', sampleiOSConfig());
232             assert.equal(syncers[0].builderName(), 'ABTest-iPhone-RunBenchmark-Tests');
233             assert.equal(syncers[1].builderName(), 'ABTest-iPhone-RunBenchmark-Tests');
234             assert.equal(syncers[2].builderName(), 'ABTest-iPhone-RunBenchmark-Tests');
235             assert.equal(syncers[3].builderName(), 'ABTest-iPad-RunBenchmark-Tests');
236             assert.equal(syncers[4].builderName(), 'ABTest-iPad-RunBenchmark-Tests');
237         });
238
239         it('should parse platform names correctly', function () {
240             let syncers = BuildbotSyncer._loadConfig('http://build.webkit.org/', sampleiOSConfig());
241             assert.equal(syncers[0].platformName(), 'iPhone');
242             assert.equal(syncers[1].platformName(), 'iPhone');
243             assert.equal(syncers[2].platformName(), 'iPhone');
244             assert.equal(syncers[3].platformName(), 'iPad');
245             assert.equal(syncers[4].platformName(), 'iPad');
246         });
247
248         it('should parse test names correctly', function () {
249             let syncers = BuildbotSyncer._loadConfig('http://build.webkit.org/', sampleiOSConfig());
250             assert.deepEqual(syncers[0].testPath(), ['Speedometer']);
251             assert.deepEqual(syncers[1].testPath(), ['JetStream']);
252             assert.deepEqual(syncers[2].testPath(), ['Dromaeo', 'DOM Core Tests']);
253             assert.deepEqual(syncers[3].testPath(), ['Speedometer']);
254             assert.deepEqual(syncers[4].testPath(), ['JetStream']);
255         });
256     });
257
258     describe('_propertiesForBuildRequest', function () {
259         it('should include all properties specified in a given configuration', function () {
260             let syncers = BuildbotSyncer._loadConfig('http://build.webkit.org/', sampleiOSConfig());
261             let properties = syncers[0]._propertiesForBuildRequest(createSampleBuildRequest());
262             assert.deepEqual(Object.keys(properties), ['desired_image', 'roots_dict', 'test_name', 'forcescheduler', 'build_request_id']);
263         });
264
265         it('should preserve non-parametric property values', function () {
266             let syncers = BuildbotSyncer._loadConfig('http://build.webkit.org/', sampleiOSConfig());
267             let properties = syncers[0]._propertiesForBuildRequest(createSampleBuildRequest());
268             assert.equal(properties['test_name'], 'speedometer');
269             assert.equal(properties['forcescheduler'], 'ABTest-iPhone-RunBenchmark-Tests-ForceScheduler');
270
271             properties = syncers[1]._propertiesForBuildRequest(createSampleBuildRequest());
272             assert.equal(properties['test_name'], 'jetstream');
273             assert.equal(properties['forcescheduler'], 'ABTest-iPhone-RunBenchmark-Tests-ForceScheduler');
274         });
275
276         it('should resolve "root"', function () {
277             let syncers = BuildbotSyncer._loadConfig('http://build.webkit.org/', sampleiOSConfig());
278             let properties = syncers[0]._propertiesForBuildRequest(createSampleBuildRequest());
279             assert.equal(properties['desired_image'], '13A452');
280         });
281
282         it('should resolve "rootsExcluding"', function () {
283             let syncers = BuildbotSyncer._loadConfig('http://build.webkit.org/', sampleiOSConfig());
284             let properties = syncers[0]._propertiesForBuildRequest(createSampleBuildRequest());
285             assert.equal(properties['roots_dict'], JSON.stringify(sampleRootSetData));
286         });
287
288         it('should set the property for the build request id', function () {
289             let syncers = BuildbotSyncer._loadConfig('http://build.webkit.org/', sampleiOSConfig());
290             let properties = syncers[0]._propertiesForBuildRequest(createSampleBuildRequest());
291             assert.equal(properties['build_request_id'], createSampleBuildRequest().id());
292         });
293     });
294
295 });