OSBuildFetcher should respect maxRevision while finding OS builds to report.
[WebKit.git] / Websites / perf.webkit.org / server-tests / tools-os-build-fetcher-tests.js
1 'use strict';
2
3 const assert = require('assert');
4
5 const OSBuildFetcher = require('../tools/js/os-build-fetcher.js').OSBuildFetcher;
6 const MockRemoteAPI = require('../unit-tests/resources/mock-remote-api.js').MockRemoteAPI;
7 const TestServer = require('./resources/test-server.js');
8 const addSlaveForReport = require('./resources/common-operations.js').addSlaveForReport;
9 const prepareServerTest = require('./resources/common-operations.js').prepareServerTest;
10 const MockSubprocess = require('./resources/mock-subprocess.js').MockSubprocess;
11 const MockLogger = require('./resources/mock-logger.js').MockLogger;
12
13
14 describe('OSBuildFetcher', function() {
15     this.timeout(5000);
16     TestServer.inject('node');
17
18     beforeEach(function () {
19         MockRemoteAPI.reset('http://build.webkit.org');
20         MockSubprocess.reset();
21     });
22
23     const emptyReport = {
24         'slaveName': 'someSlave',
25         'slavePassword': 'somePassword',
26     };
27
28     const slaveAuth = {
29         'name': 'someSlave',
30         'password': 'somePassword'
31     };
32
33     const ownedCommitWithWebKit = {
34         'WebKit': {'revision': '141978'}
35     };
36
37     const anotherownedCommitWithWebKit = {
38         'WebKit': {'revision': '141999'}
39     };
40
41     const anotherownedCommitWithWebKitAndJavaScriptCore = {
42         'WebKit': {'revision': '142000'},
43         'JavaScriptCore': {'revision': '142000'}
44     };
45
46     const osxCommit = {
47         'repository': 'OSX',
48         'revision': 'Sierra16D32',
49         'order': 1603003200
50     };
51
52     const anotherOSXCommit = {
53         'repository': 'OSX',
54         'revision': 'Sierra16E32',
55         'order': 1603003200
56     };
57
58
59     const config = {
60         'name': 'OSX',
61         'customCommands': [
62             {
63                 'command': ['list', 'all osx 16Dxx builds'],
64                 'ownedCommitCommand': ['list', 'ownedCommit', 'for', 'revision'],
65                 'linesToIgnore': '^\\.*$',
66                 'minRevision': 'Sierra16D0',
67                 'maxRevision': 'Sierra16D999'
68             },
69             {
70                 'command': ['list', 'all osx 16Exx builds'],
71                 'ownedCommitCommand': ['list', 'ownedCommit', 'for', 'revision'],
72                 'linesToIgnore': '^\\.*$',
73                 'minRevision': 'Sierra16E0',
74                 'maxRevision': 'Sierra16E999'
75             }
76         ]
77     };
78
79
80     const configWithoutOwnedCommitCommand = {
81         'name': 'OSX',
82         'customCommands': [
83             {
84                 'command': ['list', 'all osx 16Dxx builds'],
85                 'linesToIgnore': '^\\.*$',
86                 'minRevision': 'Sierra16D0',
87                 'maxRevision': 'Sierra16D999'
88             },
89             {
90                 'command': ['list', 'all osx 16Exx builds'],
91                 'linesToIgnore': '^\\.*$',
92                 'minRevision': 'Sierra16E0',
93                 'maxRevision': 'Sierra16E999'
94             }
95         ]
96     };
97
98     const configTrackingOneOS = {
99         'name': 'OSX',
100         'customCommands': [
101             {
102                 'command': ['list', 'all osx 16Dxx builds'],
103                 'linesToIgnore': '^\\.*$',
104                 'minRevision': 'Sierra16D100',
105                 'maxRevision': 'Sierra16D999'
106             }
107         ]
108     };
109
110     describe('OSBuilderFetcher._computeOrder', () => {
111         it('should calculate the right order for a given valid revision', () => {
112             const fetcher = new OSBuildFetcher({});
113             assert.equal(fetcher._computeOrder('Sierra16D32'), 1603003200);
114             assert.equal(fetcher._computeOrder('16D321'), 1603032100);
115             assert.equal(fetcher._computeOrder('16d321'), 1603032100);
116             assert.equal(fetcher._computeOrder('16D321z'), 1603032126);
117             assert.equal(fetcher._computeOrder('16d321Z'), 1603032126);
118             assert.equal(fetcher._computeOrder('10.12.3 16D32'), 1603003200);
119             assert.equal(fetcher._computeOrder('10.12.3 Sierra16D32'), 1603003200);
120         });
121
122         it('should throw assertion error when given a invalid revision', () => {
123             const fetcher = new OSBuildFetcher({});
124             assert.throws(() => fetcher._computeOrder('invalid'), 'AssertionError [ERR_ASSERTION]');
125             assert.throws(() => fetcher._computeOrder(''), 'AssertionError [ERR_ASSERTION]');
126             assert.throws(() => fetcher._computeOrder('16'), 'AssertionError [ERR_ASSERTION]');
127             assert.throws(() => fetcher._computeOrder('16D'), 'AssertionError [ERR_ASSERTION]');
128             assert.throws(() => fetcher._computeOrder('123'), 'AssertionError [ERR_ASSERTION]');
129             assert.throws(() => fetcher._computeOrder('D123'), 'AssertionError [ERR_ASSERTION]');
130             assert.throws(() => fetcher._computeOrder('123z'), 'AssertionError [ERR_ASSERTION]');
131             assert.throws(() => fetcher._computeOrder('16[163'), 'AssertionError [ERR_ASSERTION]');
132             assert.throws(() => fetcher._computeOrder('16D163['), 'AssertionError [ERR_ASSERTION]');
133         })
134     });
135
136     describe('OSBuilderFetcher._commitsForAvailableBuilds', () => {
137         it('should only return commits whose orders are higher than specified order', () => {
138             const logger = new MockLogger;
139             const fetcher = new OSBuildFetcher({}, null, null, MockSubprocess, logger);
140             const waitForInvocationPromise = MockSubprocess.waitForInvocation();
141             const fetchCommitsPromise = fetcher._commitsForAvailableBuilds('OSX', ['list', 'build1'], '^\\.*$', 1604000000, 1606000000);
142
143             return waitForInvocationPromise.then(() => {
144                 assert.equal(MockSubprocess.invocations.length, 1);
145                 assert.deepEqual(MockSubprocess.invocations[0].command, ['list', 'build1']);
146                 MockSubprocess.invocations[0].resolve('16D321\n16E321z\n\n16F321');
147                 return fetchCommitsPromise;
148             }).then((results) => {
149                 assert.equal(results.length, 2);
150                 assert.deepEqual(results[0], {repository: 'OSX', order: 1604032126, revision: '16E321z'});
151                 assert.deepEqual(results[1], {repository: 'OSX', order: 1605032100, revision: '16F321'});
152             });
153         });
154
155         it('should only return commits whose orders are higher than minOrder and lower than the maxOrder', () => {
156             const logger = new MockLogger;
157             const fetcher = new OSBuildFetcher({}, null, null, MockSubprocess, logger);
158             const waitForInvocationPromise = MockSubprocess.waitForInvocation();
159             const fetchCommitsPromise = fetcher._commitsForAvailableBuilds('OSX', ['list', 'build1'], '^\\.*$', 1604000000, 1605000000);
160
161             return waitForInvocationPromise.then(() => {
162                 assert.equal(MockSubprocess.invocations.length, 1);
163                 assert.deepEqual(MockSubprocess.invocations[0].command, ['list', 'build1']);
164                 MockSubprocess.invocations[0].resolve('16D321\n16E321z\n\n16F321');
165                 return fetchCommitsPromise;
166             }).then((results) => {
167                 assert.equal(results.length, 1);
168                 assert.deepEqual(results[0], {repository: 'OSX', order: 1604032126, revision: '16E321z'});
169             });
170         });
171     });
172
173     describe('OSBuildFetcher._addOwnedCommitsForBuild', () => {
174         it('should add owned-commit info for commits', () => {
175             const logger = new MockLogger;
176             const fetcher = new OSBuildFetcher({}, null, null, MockSubprocess, logger);
177             const waitForInvocationPromise = MockSubprocess.waitForInvocation();
178             const addownedCommitPromise = fetcher._addOwnedCommitsForBuild([osxCommit, anotherOSXCommit], ['ownedCommit', 'for', 'revision']);
179
180             return waitForInvocationPromise.then(() => {
181                 assert.equal(MockSubprocess.invocations.length, 1);
182                 assert.deepEqual(MockSubprocess.invocations[0].command, ['ownedCommit', 'for', 'revision', 'Sierra16D32']);
183                 MockSubprocess.invocations[0].resolve(JSON.stringify(ownedCommitWithWebKit));
184                 MockSubprocess.reset();
185                 return MockSubprocess.waitForInvocation();
186             }).then(() => {
187                 assert.equal(MockSubprocess.invocations.length, 1);
188                 assert.deepEqual(MockSubprocess.invocations[0].command, ['ownedCommit', 'for', 'revision', 'Sierra16E32']);
189                 MockSubprocess.invocations[0].resolve(JSON.stringify(anotherownedCommitWithWebKit));
190                 return addownedCommitPromise;
191             }).then((results) => {
192                 assert.equal(results.length, 2);
193                 assert.equal(results[0]['repository'], osxCommit['repository']);
194                 assert.equal(results[0]['revision'], osxCommit['revision']);
195                 assert.deepEqual(results[0]['ownedCommits'], ownedCommitWithWebKit);
196                 assert.equal(results[1]['repository'], anotherOSXCommit['repository']);
197                 assert.equal(results[1]['revision'], anotherOSXCommit['revision']);
198                 assert.deepEqual(results[1]['ownedCommits'], anotherownedCommitWithWebKit);
199             });
200         });
201
202         it('should fail if the command to get owned-commit info fails', () => {
203             const logger = new MockLogger;
204             const fetcher = new OSBuildFetcher({}, null, null, MockSubprocess, logger);
205             const waitForInvocationPromise = MockSubprocess.waitForInvocation();
206             const addownedCommitPromise = fetcher._addOwnedCommitsForBuild([osxCommit], ['ownedCommit', 'for', 'revision'])
207
208             return waitForInvocationPromise.then(() => {
209                 assert.equal(MockSubprocess.invocations.length, 1);
210                 assert.deepEqual(MockSubprocess.invocations[0].command, ['ownedCommit', 'for', 'revision', 'Sierra16D32']);
211                 MockSubprocess.invocations[0].reject('Failed getting owned-commit');
212
213                 return addownedCommitPromise.then(() => {
214                     assert(false, 'should never be reached');
215                 }, (error_output) => {
216                     assert(error_output);
217                     assert.equal(error_output, 'Failed getting owned-commit');
218                 });
219             });
220         });
221
222
223         it('should fail if entries in owned-commits does not contain revision', () => {
224             const logger = new MockLogger;
225             const fetcher = new OSBuildFetcher({}, null, null, MockSubprocess, logger);
226             const waitForInvocationPromise = MockSubprocess.waitForInvocation();
227             const addownedCommitPromise = fetcher._addOwnedCommitsForBuild([osxCommit], ['ownedCommit', 'for', 'revision'])
228
229             return waitForInvocationPromise.then(() => {
230                 assert.equal(MockSubprocess.invocations.length, 1);
231                 assert.deepEqual(MockSubprocess.invocations[0].command, ['ownedCommit', 'for', 'revision', 'Sierra16D32']);
232                 MockSubprocess.invocations[0].resolve('{"WebKit":{"RandomKey": "RandomValue"}}');
233
234                 return addownedCommitPromise.then(() => {
235                     assert(false, 'should never be reached');
236                 }, (error_output) => {
237                     assert(error_output);
238                     assert.equal(error_output.name, 'AssertionError [ERR_ASSERTION]');
239                 });
240             });
241         })
242     })
243
244     describe('OSBuildFetcher.fetchAndReportNewBuilds', () => {
245         const invocations = MockSubprocess.invocations;
246
247         beforeEach(function () {
248             TestServer.database().connect({keepAlive: true});
249         });
250
251         afterEach(function () {
252             TestServer.database().disconnect();
253         });
254
255         it('should report all build commits with owned-commits', () => {
256             const logger = new MockLogger;
257             const fetcher = new OSBuildFetcher(config, TestServer.remoteAPI(), slaveAuth, MockSubprocess, logger);
258             const db = TestServer.database();
259             let fetchAndReportPromise = null;
260             let fetchAvailableBuildsPromise = null;
261
262             return addSlaveForReport(emptyReport).then(() => {
263                 return Promise.all([
264                     db.insert('repositories', {'id': 10, 'name': 'OSX'}),
265                     db.insert('commits', {'repository': 10, 'revision': 'Sierra16D67', 'order': 1603006700, 'reported': true}),
266                     db.insert('commits', {'repository': 10, 'revision': 'Sierra16D68', 'order': 1603006800, 'reported': true}),
267                     db.insert('commits', {'repository': 10, 'revision': 'Sierra16D69', 'order': 1603006900, 'reported': false}),
268                     db.insert('commits', {'repository': 10, 'revision': 'Sierra16E32', 'order': 1604003200, 'reported': true}),
269                     db.insert('commits', {'repository': 10, 'revision': 'Sierra16E33', 'order': 1604003300, 'reported': true}),
270                     db.insert('commits', {'repository': 10, 'revision': 'Sierra16E33g', 'order': 1604003307, 'reported': true})]);
271             }).then(() => {
272                 return TestServer.remoteAPI().getJSON('/api/commits/OSX/last-reported?from=1603000000&to=1603099900');
273             }).then((result) => {
274                 assert.equal(result['commits'].length, 1);
275                 assert.equal(result['commits'][0]['revision'], 'Sierra16D68');
276                 assert.equal(result['commits'][0]['order'], 1603006800);
277                 return TestServer.remoteAPI().getJSON('/api/commits/OSX/last-reported?from=1604000000&to=1604099900');
278             }).then((result) => {
279                 assert.equal(result['commits'].length, 1);
280                 assert.equal(result['commits'][0]['revision'], 'Sierra16E33g');
281                 assert.equal(result['commits'][0]['order'], 1604003307);
282                 const waitForInvocationPromise = MockSubprocess.waitForInvocation();
283                 fetchAvailableBuildsPromise = fetcher._fetchAvailableBuilds();
284                 return waitForInvocationPromise;
285             }).then(() => {
286                 assert.equal(invocations.length, 1);
287                 assert.deepEqual(invocations[0].command, ['list', 'all osx 16Dxx builds']);
288                 invocations[0].resolve('\n\nSierra16D68\nSierra16D69\n');
289                 return MockSubprocess.resetAndWaitForInvocation();
290             }).then(() => {
291                 assert.equal(invocations.length, 1);
292                 assert.deepEqual(invocations[0].command, ['list', 'ownedCommit', 'for', 'revision', 'Sierra16D69']);
293                 invocations[0].resolve(JSON.stringify(ownedCommitWithWebKit));
294                 return MockSubprocess.resetAndWaitForInvocation();
295             }).then(() => {
296                 assert.equal(invocations.length, 1);
297                 assert.deepEqual(invocations[0].command, ['list', 'all osx 16Exx builds']);
298                 invocations[0].resolve('\n\nSierra16E32\nSierra16E33\nSierra16E33h\nSierra16E34');
299                 return MockSubprocess.resetAndWaitForInvocation();
300             }).then(() => {
301                 assert.equal(invocations.length, 1);
302                 assert.deepEqual(invocations[0].command, ['list', 'ownedCommit', 'for', 'revision', 'Sierra16E33h']);
303                 invocations[0].resolve(JSON.stringify(anotherownedCommitWithWebKit));
304                 return MockSubprocess.resetAndWaitForInvocation();
305             }).then(() => {
306                 assert.equal(invocations.length, 1);
307                 assert.deepEqual(invocations[0].command, ['list', 'ownedCommit', 'for', 'revision', 'Sierra16E34']);
308                 invocations[0].resolve(JSON.stringify(anotherownedCommitWithWebKitAndJavaScriptCore));
309                 return fetchAvailableBuildsPromise;
310             }).then((results) => {
311                 assert.equal(results.length, 3);
312                 MockSubprocess.reset();
313                 fetchAndReportPromise = fetcher.fetchAndReportNewBuilds();
314                 return MockSubprocess.waitForInvocation();
315             }).then(() => {
316                 assert.equal(invocations.length, 1);
317                 assert.deepEqual(invocations[0].command, ['list', 'all osx 16Dxx builds']);
318                 invocations[0].resolve('\n\nSierra16D68\nSierra16D69\n');
319                 return MockSubprocess.resetAndWaitForInvocation();
320             }).then(() => {
321                 assert.equal(invocations.length, 1);
322                 assert.deepEqual(invocations[0].command, ['list', 'ownedCommit', 'for', 'revision', 'Sierra16D69']);
323                 invocations[0].resolve(JSON.stringify(ownedCommitWithWebKit));
324                 return MockSubprocess.resetAndWaitForInvocation();
325             }).then(() => {
326                 assert.equal(invocations.length, 1);
327                 assert.deepEqual(invocations[0].command, ['list', 'all osx 16Exx builds']);
328                 invocations[0].resolve('\n\nSierra16E32\nSierra16E33\nSierra16E33h\nSierra16E34');
329                 return MockSubprocess.resetAndWaitForInvocation();
330             }).then(() => {
331                 assert.equal(invocations.length, 1);
332                 assert.deepEqual(invocations[0].command, ['list', 'ownedCommit', 'for', 'revision', 'Sierra16E33h']);
333                 invocations[0].resolve(JSON.stringify(anotherownedCommitWithWebKit));
334                 return MockSubprocess.resetAndWaitForInvocation();
335             }).then(() => {
336                 assert.equal(invocations.length, 1);
337                 invocations[0].resolve(JSON.stringify(anotherownedCommitWithWebKitAndJavaScriptCore));
338                 assert.deepEqual(invocations[0].command, ['list', 'ownedCommit', 'for', 'revision', 'Sierra16E34']);
339
340                 return fetchAndReportPromise;
341             }).then((result) => {
342                 assert.equal(result['status'], 'OK');
343                 return Promise.all([
344                     db.selectRows('repositories', {'name': 'WebKit'}),
345                     db.selectRows('repositories', {'name': 'JavaScriptCore'}),
346                     db.selectRows('commits', {'revision': 'Sierra16D69'}),
347                     db.selectRows('commits', {'revision': 'Sierra16E33h'}),
348                     db.selectRows('commits', {'revision': 'Sierra16E34'})]);
349             }).then((results) => {
350                 const webkitRepository = results[0];
351                 const jscRepository = results[1];
352                 const osxCommit16D69 = results[2];
353                 const osxCommit16E33h = results[3];
354                 const osxCommit16E34 = results[4];
355
356                 assert.equal(webkitRepository.length, 1);
357                 assert.equal(webkitRepository[0]['owner'], 10);
358                 assert.equal(jscRepository.length, 1);
359                 assert.equal(jscRepository[0]['owner'], 10);
360
361                 assert.equal(osxCommit16D69.length, 1);
362                 assert.equal(osxCommit16D69[0]['repository'], 10);
363                 assert.equal(osxCommit16D69[0]['order'], 1603006900);
364
365                 assert.equal(osxCommit16E33h.length, 1);
366                 assert.equal(osxCommit16E33h[0]['repository'], 10);
367                 assert.equal(osxCommit16E33h[0]['order'], 1604003308);
368
369                 assert.equal(osxCommit16E34.length, 1);
370                 assert.equal(osxCommit16E34[0]['repository'], 10);
371                 assert.equal(osxCommit16E34[0]['order'], 1604003400);
372
373                 return TestServer.remoteAPI().getJSON('/api/commits/OSX/last-reported?from=1603000000&to=1603099900');
374             }).then((result) => {
375                 assert.equal(result['commits'].length, 1);
376                 assert.equal(result['commits'][0]['revision'], 'Sierra16D69');
377                 assert.equal(result['commits'][0]['order'], 1603006900);
378
379                 return TestServer.remoteAPI().getJSON('/api/commits/OSX/last-reported?from=1604000000&to=1604099900');
380             }).then((result) => {
381                 assert.equal(result['commits'].length, 1);
382                 assert.equal(result['commits'][0]['revision'], 'Sierra16E34');
383                 assert.equal(result['commits'][0]['order'], 1604003400);
384             });
385         });
386
387         it('should report commits without owned-commits if "ownedCommitCommand" is not specified in config', async () => {
388
389             const logger = new MockLogger;
390             const fetcher = new OSBuildFetcher(configWithoutOwnedCommitCommand, TestServer.remoteAPI(), slaveAuth, MockSubprocess, logger);
391             const db = TestServer.database();
392
393             await addSlaveForReport(emptyReport);
394             await Promise.all([
395                 db.insert('repositories', {'id': 10, 'name': 'OSX'}),
396                 db.insert('commits', {'repository': 10, 'revision': 'Sierra16D67', 'order': 1603006700, 'reported': true}),
397                 db.insert('commits', {'repository': 10, 'revision': 'Sierra16D68', 'order': 1603006800, 'reported': true}),
398                 db.insert('commits', {'repository': 10, 'revision': 'Sierra16D69', 'order': 1603006900, 'reported': false}),
399                 db.insert('commits', {'repository': 10, 'revision': 'Sierra16E32', 'order': 1604003200, 'reported': true}),
400                 db.insert('commits', {'repository': 10, 'revision': 'Sierra16E33', 'order': 1604003300, 'reported': true}),
401                 db.insert('commits', {'repository': 10, 'revision': 'Sierra16E33g', 'order': 1604003307, 'reported': true})]);
402
403             let result = await TestServer.remoteAPI().getJSON('/api/commits/OSX/last-reported?from=1603000000&to=1603099900');
404             assert.equal(result['commits'].length, 1);
405             assert.equal(result['commits'][0]['revision'], 'Sierra16D68');
406             assert.equal(result['commits'][0]['order'], 1603006800);
407
408             result = await TestServer.remoteAPI().getJSON('/api/commits/OSX/last-reported?from=1604000000&to=1604099900');
409             assert.equal(result['commits'].length, 1);
410             assert.equal(result['commits'][0]['revision'], 'Sierra16E33g');
411             assert.equal(result['commits'][0]['order'], 1604003307);
412
413             const waitForInvocationPromise = MockSubprocess.waitForInvocation();
414             const fetchAndReportPromise = fetcher.fetchAndReportNewBuilds();
415             await waitForInvocationPromise;
416             assert.equal(invocations.length, 1);
417             assert.deepEqual(invocations[0].command, ['list', 'all osx 16Dxx builds']);
418             invocations[0].resolve('\n\nSierra16D68\nSierra16D69');
419
420             await MockSubprocess.resetAndWaitForInvocation();
421             assert.equal(invocations.length, 1);
422             assert.deepEqual(invocations[0].command, ['list', 'all osx 16Exx builds']);
423             invocations[0].resolve('\n\nSierra16E32\nSierra16E33\nSierra16E33h\nSierra16E34');
424
425             result = await fetchAndReportPromise;
426             assert.equal(result['status'], 'OK');
427             const results = await Promise.all([
428                 db.selectRows('repositories', {'name': 'WebKit'}),
429                 db.selectRows('repositories', {'name': 'JavaScriptCore'}),
430                 db.selectRows('commits', {'revision': 'Sierra16D69'}),
431                 db.selectRows('commits', {'revision': 'Sierra16E33h'}),
432                 db.selectRows('commits', {'revision': 'Sierra16E34'})]);
433
434             const webkitRepository = results[0];
435             const jscRepository = results[1];
436             const osxCommit16D69 = results[2];
437             const osxCommit16E33h = results[3];
438             const osxCommit16E34 = results[4];
439
440             assert.equal(webkitRepository.length, 0);
441             assert.equal(jscRepository.length, 0);
442
443             assert.equal(osxCommit16D69.length, 1);
444             assert.equal(osxCommit16D69[0]['repository'], 10);
445             assert.equal(osxCommit16D69[0]['order'], 1603006900);
446
447             assert.equal(osxCommit16E33h.length, 1);
448             assert.equal(osxCommit16E33h[0]['repository'], 10);
449             assert.equal(osxCommit16E33h[0]['order'], 1604003308);
450
451             assert.equal(osxCommit16E34.length, 1);
452             assert.equal(osxCommit16E34[0]['repository'], 10);
453             assert.equal(osxCommit16E34[0]['order'], 1604003400);
454
455             result = await TestServer.remoteAPI().getJSON('/api/commits/OSX/last-reported?from=1603000000&to=1603099900');
456             assert.equal(result['commits'].length, 1);
457             assert.equal(result['commits'][0]['revision'], 'Sierra16D69');
458             assert.equal(result['commits'][0]['order'], 1603006900);
459
460             result = await TestServer.remoteAPI().getJSON('/api/commits/OSX/last-reported?from=1604000000&to=1604099900');
461             assert.equal(result['commits'].length, 1);
462             assert.equal(result['commits'][0]['revision'], 'Sierra16E34');
463             assert.equal(result['commits'][0]['order'], 1604003400);
464         });
465
466         it('should report commits within specified revision range', async () => {
467             const logger = new MockLogger;
468             const fetcher = new OSBuildFetcher(configWithoutOwnedCommitCommand, TestServer.remoteAPI(), slaveAuth, MockSubprocess, logger);
469             const db = TestServer.database();
470
471             await addSlaveForReport(emptyReport);
472             await Promise.all([
473                 db.insert('repositories', {'id': 10, 'name': 'OSX'}),
474                 db.insert('commits', {'repository': 10, 'revision': 'Sierra16D67', 'order': 1603006700, 'reported': true}),
475                 db.insert('commits', {'repository': 10, 'revision': 'Sierra16D68', 'order': 1603006800, 'reported': true}),
476                 db.insert('commits', {'repository': 10, 'revision': 'Sierra16D69', 'order': 1603006900, 'reported': false}),
477                 db.insert('commits', {'repository': 10, 'revision': 'Sierra16E32', 'order': 1604003200, 'reported': true}),
478                 db.insert('commits', {'repository': 10, 'revision': 'Sierra16E33', 'order': 1604003300, 'reported': true}),
479                 db.insert('commits', {'repository': 10, 'revision': 'Sierra16E33g', 'order': 1604003307, 'reported': true})]);
480
481             let result = await TestServer.remoteAPI().getJSON('/api/commits/OSX/last-reported?from=1603000000&to=1603099900');
482             assert.equal(result['commits'].length, 1);
483             assert.equal(result['commits'][0]['revision'], 'Sierra16D68');
484             assert.equal(result['commits'][0]['order'], 1603006800);
485
486             result = await TestServer.remoteAPI().getJSON('/api/commits/OSX/last-reported?from=1604000000&to=1604099900');
487             assert.equal(result['commits'].length, 1);
488             assert.equal(result['commits'][0]['revision'], 'Sierra16E33g');
489             assert.equal(result['commits'][0]['order'], 1604003307);
490             const waitForInvocationPromise = MockSubprocess.waitForInvocation();
491             const fetchAndReportPromise = fetcher.fetchAndReportNewBuilds();
492
493             await waitForInvocationPromise;
494             assert.equal(invocations.length, 1);
495             assert.deepEqual(invocations[0].command, ['list', 'all osx 16Dxx builds']);
496             invocations[0].resolve('\n\nSierra16D68\nSierra16D69\nSierra16D10000');
497
498             await MockSubprocess.resetAndWaitForInvocation();
499             assert.equal(invocations.length, 1);
500             assert.deepEqual(invocations[0].command, ['list', 'all osx 16Exx builds']);
501             invocations[0].resolve('\n\nSierra16E32\nSierra16E33\nSierra16E33h\nSierra16E34\nSierra16E10000');
502
503             result = await fetchAndReportPromise;
504             assert.equal(result['status'], 'OK');
505             const results = await Promise.all([
506                 db.selectRows('repositories', {'name': 'WebKit'}),
507                 db.selectRows('repositories', {'name': 'JavaScriptCore'}),
508                 db.selectRows('commits', {'revision': 'Sierra16D69'}),
509                 db.selectRows('commits', {'revision': 'Sierra16E33h'}),
510                 db.selectRows('commits', {'revision': 'Sierra16E34'})]);
511
512             const webkitRepository = results[0];
513             const jscRepository = results[1];
514             const osxCommit16D69 = results[2];
515             const osxCommit16E33h = results[3];
516             const osxCommit16E34 = results[4];
517
518             assert.equal(webkitRepository.length, 0);
519             assert.equal(jscRepository.length, 0);
520
521             assert.equal(osxCommit16D69.length, 1);
522             assert.equal(osxCommit16D69[0]['repository'], 10);
523             assert.equal(osxCommit16D69[0]['order'], 1603006900);
524
525             assert.equal(osxCommit16E33h.length, 1);
526             assert.equal(osxCommit16E33h[0]['repository'], 10);
527             assert.equal(osxCommit16E33h[0]['order'], 1604003308);
528
529             assert.equal(osxCommit16E34.length, 1);
530             assert.equal(osxCommit16E34[0]['repository'], 10);
531             assert.equal(osxCommit16E34[0]['order'], 1604003400);
532
533             result = await TestServer.remoteAPI().getJSON('/api/commits/OSX/last-reported?from=1603000000&to=1603099900');
534             assert.equal(result['commits'].length, 1);
535             assert.equal(result['commits'][0]['revision'], 'Sierra16D69');
536             assert.equal(result['commits'][0]['order'], 1603006900);
537
538             result = await TestServer.remoteAPI().getJSON('/api/commits/OSX/last-reported?from=1604000000&to=1604099900');
539             assert.equal(result['commits'].length, 1);
540             assert.equal(result['commits'][0]['revision'], 'Sierra16E34');
541             assert.equal(result['commits'][0]['order'], 1604003400);
542         });
543
544         it('should use "last-reported" order + 1 as "minOrder"', async () => {
545             const logger = new MockLogger;
546             const fetcher = new OSBuildFetcher(configTrackingOneOS, TestServer.remoteAPI(), slaveAuth, MockSubprocess, logger);
547             const db = TestServer.database();
548
549             await addSlaveForReport(emptyReport);
550             await db.insert('repositories', {'id': 10, 'name': 'OSX'});
551             await db.insert('commits', {'repository': 10, 'revision': 'Sierra16D100', 'order': 1603010000, 'reported': true});
552
553             let result = await TestServer.remoteAPI().getJSON('/api/commits/OSX/last-reported?from=1603010000&to=1603099900');
554             assert.equal(result['commits'].length, 1);
555             assert.equal(result['commits'][0]['revision'], 'Sierra16D100');
556             assert.equal(result['commits'][0]['order'], 1603010000);
557
558             const waitForInvocationPromise = MockSubprocess.waitForInvocation();
559             const fetchAndReportPromise = fetcher.fetchAndReportNewBuilds();
560             await waitForInvocationPromise;
561             assert.equal(invocations.length, 1);
562             assert.deepEqual(invocations[0].command, ['list', 'all osx 16Dxx builds']);
563             invocations[0].resolve('\n\nSierra16D68\nSierra16D69\nSierra16D100\nSierra16D100a\n');
564
565             result = await fetchAndReportPromise;
566             assert.equal(result['status'], 'OK');
567             const results = await Promise.all([
568                 db.selectRows('repositories', {'name': 'WebKit'}),
569                 db.selectRows('repositories', {'name': 'JavaScriptCore'}),
570                 db.selectRows('commits', {'revision': 'Sierra16D69'}),
571                 db.selectRows('commits', {'revision': 'Sierra16D100a'})]);
572
573             const webkitRepository = results[0];
574             const jscRepository = results[1];
575             const osxCommit16D69 = results[2];
576             const osxCommit16D100a = results[3];
577
578             assert.equal(webkitRepository.length, 0);
579             assert.equal(jscRepository.length, 0);
580
581             assert.equal(osxCommit16D69.length, 0);
582
583             assert.equal(osxCommit16D100a.length, 1);
584             assert.equal(osxCommit16D100a[0]['repository'], 10);
585             assert.equal(osxCommit16D100a[0]['order'], 1603010001);
586
587             result = await TestServer.remoteAPI().getJSON('/api/commits/OSX/last-reported?from=1603010000&to=1603099900');
588             assert.equal(result['commits'].length, 1);
589             assert.equal(result['commits'][0]['revision'], 'Sierra16D100a');
590             assert.equal(result['commits'][0]['order'], 1603010001);
591         });
592
593         it('should use minRevision in the config if there is no commit', async () => {
594             const logger = new MockLogger;
595             const fetcher = new OSBuildFetcher(configTrackingOneOS, TestServer.remoteAPI(), slaveAuth, MockSubprocess, logger);
596             const db = TestServer.database();
597
598             await addSlaveForReport(emptyReport);
599             await db.insert('repositories', {'id': 10, 'name': 'OSX'});
600
601             let result = await TestServer.remoteAPI().getJSON('/api/commits/OSX/last-reported?from=1603010000&to=1603099900');
602             assert.equal(result['commits'].length, 0);
603
604             const waitForInvocationPromise = MockSubprocess.waitForInvocation();
605             const fetchAndReportPromise = fetcher.fetchAndReportNewBuilds();
606             await waitForInvocationPromise;
607             assert.equal(invocations.length, 1);
608             assert.deepEqual(invocations[0].command, ['list', 'all osx 16Dxx builds']);
609             invocations[0].resolve('\n\nSierra16D68\nSierra16D69\nSierra16D100\nSierra16D101\n');
610
611             result = await fetchAndReportPromise;
612             assert.equal(result['status'], 'OK');
613             const results = await Promise.all([
614                 db.selectRows('repositories', {'name': 'WebKit'}),
615                 db.selectRows('repositories', {'name': 'JavaScriptCore'}),
616                 db.selectRows('commits', {'revision': 'Sierra16D69'}),
617                 db.selectRows('commits', {'revision': 'Sierra16D100'}),
618                 db.selectRows('commits', {'revision': 'Sierra16D101'})]);
619
620             const webkitRepository = results[0];
621             const jscRepository = results[1];
622             const osxCommit16D69 = results[2];
623             const osxCommit16D100 = results[3];
624             const osxCommit16D101 = results[4];
625
626             assert.equal(webkitRepository.length, 0);
627             assert.equal(jscRepository.length, 0);
628
629             assert.equal(osxCommit16D69.length, 0);
630
631             assert.equal(osxCommit16D100.length, 1);
632             assert.equal(osxCommit16D100[0]['repository'], 10);
633             assert.equal(osxCommit16D100[0]['order'], 1603010000);
634
635             assert.equal(osxCommit16D101.length, 1);
636             assert.equal(osxCommit16D101[0]['repository'], 10);
637             assert.equal(osxCommit16D101[0]['order'], 1603010100);
638
639             result = await TestServer.remoteAPI().getJSON('/api/commits/OSX/last-reported?from=1603010000&to=1603099900');
640             assert.equal(result['commits'].length, 1);
641             assert.equal(result['commits'][0]['revision'], 'Sierra16D101');
642             assert.equal(result['commits'][0]['order'], 1603010100);
643         });
644
645         it('should stop reporting if any custom command fails', () => {
646             const logger = new MockLogger;
647             const fetcher = new OSBuildFetcher(config, TestServer.remoteAPI(), slaveAuth, MockSubprocess, logger);
648             const db = TestServer.database();
649             let fetchAndReportPromise = null;
650
651             return addSlaveForReport(emptyReport).then(() => {
652                 return Promise.all([
653                     db.insert('repositories', {'id': 10, 'name': 'OSX'}),
654                     db.insert('commits', {'repository': 10, 'revision': 'Sierra16D67', 'order': 1603006700, 'reported': true}),
655                     db.insert('commits', {'repository': 10, 'revision': 'Sierra16D68', 'order': 1603006800, 'reported': true}),
656                     db.insert('commits', {'repository': 10, 'revision': 'Sierra16D69', 'order': 1603006900, 'reported': false}),
657                     db.insert('commits', {'repository': 10, 'revision': 'Sierra16E32', 'order': 1604003200, 'reported': true}),
658                     db.insert('commits', {'repository': 10, 'revision': 'Sierra16E33', 'order': 1604003300, 'reported': true}),
659                     db.insert('commits', {'repository': 10, 'revision': 'Sierra16E33g', 'order': 1604003307, 'reported': true})]);
660             }).then(() => {
661                 return TestServer.remoteAPI().getJSON('/api/commits/OSX/last-reported?from=1603000000&to=1603099900');
662             }).then((result) => {
663                 assert.equal(result['commits'].length, 1);
664                 assert.equal(result['commits'][0]['revision'], 'Sierra16D68');
665                 assert.equal(result['commits'][0]['order'], 1603006800);
666
667                 return TestServer.remoteAPI().getJSON('/api/commits/OSX/last-reported?from=1604000000&to=1604099900');
668             }).then((result) => {
669                 assert.equal(result['commits'].length, 1);
670                 assert.equal(result['commits'][0]['revision'], 'Sierra16E33g');
671                 assert.equal(result['commits'][0]['order'], 1604003307);
672
673                 const waitForInvocationPromise = MockSubprocess.waitForInvocation();
674                 fetchAndReportPromise = fetcher.fetchAndReportNewBuilds();
675                 return waitForInvocationPromise;
676             }).then(() => {
677                 assert.equal(invocations.length, 1);
678                 assert.deepEqual(invocations[0].command, ['list', 'all osx 16Dxx builds']);
679                 invocations[0].resolve('\n\nSierra16D68\nSierra16D69\n');
680                 return MockSubprocess.resetAndWaitForInvocation();
681             }).then(() => {
682                 assert.equal(invocations.length, 1);
683                 assert.deepEqual(invocations[0].command, ['list', 'ownedCommit', 'for', 'revision', 'Sierra16D69']);
684                 MockSubprocess.invocations[0].resolve(JSON.stringify(ownedCommitWithWebKit));
685                 return MockSubprocess.resetAndWaitForInvocation();
686             }).then(() => {
687                 assert.equal(invocations.length, 1);
688                 assert.deepEqual(invocations[0].command, ['list', 'all osx 16Exx builds']);
689                 invocations[0].resolve('\n\nSierra16E32\nSierra16E33\nSierra16E33h\nSierra16E34');
690                 return MockSubprocess.resetAndWaitForInvocation();
691             }).then(() => {
692                 assert.deepEqual(invocations[0].command, ['list', 'ownedCommit', 'for', 'revision', 'Sierra16E33h']);
693                 invocations[0].resolve(JSON.stringify(anotherownedCommitWithWebKit));
694                 return MockSubprocess.resetAndWaitForInvocation();
695             }).then(() => {
696                 assert.equal(invocations.length, 1);
697                 assert.deepEqual(invocations[0].command, ['list', 'ownedCommit', 'for', 'revision', 'Sierra16E34']);
698                 invocations[0].reject('Command failed');
699                 return fetchAndReportPromise.then(() => {
700                     assert(false, 'should never be reached');
701                 }, (error_output) => {
702                     assert(error_output);
703                     assert.equal(error_output, 'Command failed');
704                 });
705             }).then(() => {
706                 return TestServer.remoteAPI().getJSON('/api/commits/OSX/last-reported?from=1603000000&to=1603099900');
707             }).then((result) => {
708                 assert.equal(result['commits'].length, 1);
709                 assert.equal(result['commits'][0]['revision'], 'Sierra16D68');
710                 assert.equal(result['commits'][0]['order'], 1603006800);
711
712                 return TestServer.remoteAPI().getJSON('/api/commits/OSX/last-reported?from=1604000000&to=1604099900');
713             }).then((result) => {
714                 assert.equal(result['commits'].length, 1);
715                 assert.equal(result['commits'][0]['revision'], 'Sierra16E33g');
716                 assert.equal(result['commits'][0]['order'], 1604003307);
717             });
718         })
719     })
720 });