Use 'owned commit' instead of 'sub commit' whenever refers to a commit owned by anoth...
[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();
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     describe('OSBuilderFetcher._computeOrder', () => {
99         it('should calculate the right order for a given valid revision', () => {
100             const fetcher = new OSBuildFetcher();
101             assert.equal(fetcher._computeOrder('Sierra16D32'), 1603003200);
102             assert.equal(fetcher._computeOrder('16D321'), 1603032100);
103             assert.equal(fetcher._computeOrder('16d321'), 1603032100);
104             assert.equal(fetcher._computeOrder('16D321z'), 1603032126);
105             assert.equal(fetcher._computeOrder('16d321Z'), 1603032126);
106             assert.equal(fetcher._computeOrder('10.12.3 16D32'), 1603003200);
107             assert.equal(fetcher._computeOrder('10.12.3 Sierra16D32'), 1603003200);
108         });
109
110         it('should throw assertion error when given a invalid revision', () => {
111             const fetcher = new OSBuildFetcher();
112             assert.throws(() => fetcher._computeOrder('invalid'), (error) => error.name == 'AssertionError');
113             assert.throws(() => fetcher._computeOrder(''), (error) => error.name == 'AssertionError');
114             assert.throws(() => fetcher._computeOrder('16'), (error) => error.name == 'AssertionError');
115             assert.throws(() => fetcher._computeOrder('16D'), (error) => error.name == 'AssertionError');
116             assert.throws(() => fetcher._computeOrder('123'), (error) => error.name == 'AssertionError');
117             assert.throws(() => fetcher._computeOrder('D123'), (error) => error.name == 'AssertionError');
118             assert.throws(() => fetcher._computeOrder('123z'), (error) => error.name == 'AssertionError');
119             assert.throws(() => fetcher._computeOrder('16[163'), (error) => error.name == 'AssertionError');
120             assert.throws(() => fetcher._computeOrder('16D163['), (error) => error.name == 'AssertionError');
121         })
122     });
123
124     describe('OSBuilderFetcher._commitsForAvailableBuilds', () => {
125         it('should only return commits whose orders are higher than specified order', () => {
126             const logger = new MockLogger;
127             const fetchter = new OSBuildFetcher(null, null, null, MockSubprocess, logger);
128             const waitForInvocationPromise = MockSubprocess.waitForInvocation();
129             const fetchCommitsPromise = fetchter._commitsForAvailableBuilds('OSX', ['list', 'build1'], '^\\.*$', 1604000000);
130
131             return waitForInvocationPromise.then(() => {
132                 assert.equal(MockSubprocess.invocations.length, 1);
133                 assert.deepEqual(MockSubprocess.invocations[0].command, ['list', 'build1']);
134                 MockSubprocess.invocations[0].resolve('16D321\n16E321z\n\n16F321');
135                 return fetchCommitsPromise;
136             }).then((results) => {
137                 assert.equal(results.length, 2);
138                 assert.deepEqual(results[0], {repository: 'OSX', order: 1604032126, revision: '16E321z'});
139                 assert.deepEqual(results[1], {repository: 'OSX', order: 1605032100, revision: '16F321'});
140             });
141         });
142     });
143
144     describe('OSBuildFetcher._addOwnedCommitsForBuild', () => {
145         it('should add owned-commit info for commits', () => {
146             const logger = new MockLogger;
147             const fetchter = new OSBuildFetcher(null, null, null, MockSubprocess, logger);
148             const waitForInvocationPromise = MockSubprocess.waitForInvocation();
149             const addownedCommitPromise = fetchter._addOwnedCommitsForBuild([osxCommit, anotherOSXCommit], ['ownedCommit', 'for', 'revision']);
150
151             return waitForInvocationPromise.then(() => {
152                 assert.equal(MockSubprocess.invocations.length, 1);
153                 assert.deepEqual(MockSubprocess.invocations[0].command, ['ownedCommit', 'for', 'revision', 'Sierra16D32']);
154                 MockSubprocess.invocations[0].resolve(JSON.stringify(ownedCommitWithWebKit));
155                 MockSubprocess.reset();
156                 return MockSubprocess.waitForInvocation();
157             }).then(() => {
158                 assert.equal(MockSubprocess.invocations.length, 1);
159                 assert.deepEqual(MockSubprocess.invocations[0].command, ['ownedCommit', 'for', 'revision', 'Sierra16E32']);
160                 MockSubprocess.invocations[0].resolve(JSON.stringify(anotherownedCommitWithWebKit));
161                 return addownedCommitPromise;
162             }).then((results) => {
163                 assert.equal(results.length, 2);
164                 assert.equal(results[0]['repository'], osxCommit['repository']);
165                 assert.equal(results[0]['revision'], osxCommit['revision']);
166                 assert.deepEqual(results[0]['ownedCommits'], ownedCommitWithWebKit);
167                 assert.equal(results[1]['repository'], anotherOSXCommit['repository']);
168                 assert.equal(results[1]['revision'], anotherOSXCommit['revision']);
169                 assert.deepEqual(results[1]['ownedCommits'], anotherownedCommitWithWebKit);
170             });
171         });
172
173         it('should fail if the command to get owned-commit info fails', () => {
174             const logger = new MockLogger;
175             const fetchter = new OSBuildFetcher(null, null, null, MockSubprocess, logger);
176             const waitForInvocationPromise = MockSubprocess.waitForInvocation();
177             const addownedCommitPromise = fetchter._addOwnedCommitsForBuild([osxCommit], ['ownedCommit', 'for', 'revision'])
178
179             return waitForInvocationPromise.then(() => {
180                 assert.equal(MockSubprocess.invocations.length, 1);
181                 assert.deepEqual(MockSubprocess.invocations[0].command, ['ownedCommit', 'for', 'revision', 'Sierra16D32']);
182                 MockSubprocess.invocations[0].reject('Failed getting owned-commit');
183
184                 return addownedCommitPromise.then(() => {
185                     assert(false, 'should never be reached');
186                 }, (error_output) => {
187                     assert(error_output);
188                     assert.equal(error_output, 'Failed getting owned-commit');
189                 });
190             });
191         });
192
193
194         it('should fail if entries in owned-commits does not contain revision', () => {
195             const logger = new MockLogger;
196             const fetchter = new OSBuildFetcher(null, null, null, MockSubprocess, logger);
197             const waitForInvocationPromise = MockSubprocess.waitForInvocation();
198             const addownedCommitPromise = fetchter._addOwnedCommitsForBuild([osxCommit], ['ownedCommit', 'for', 'revision'])
199
200             return waitForInvocationPromise.then(() => {
201                 assert.equal(MockSubprocess.invocations.length, 1);
202                 assert.deepEqual(MockSubprocess.invocations[0].command, ['ownedCommit', 'for', 'revision', 'Sierra16D32']);
203                 MockSubprocess.invocations[0].resolve('{"WebKit":{"RandomKey": "RandomValue"}}');
204
205                 return addownedCommitPromise.then(() => {
206                     assert(false, 'should never be reached');
207                 }, (error_output) => {
208                     assert(error_output);
209                     assert.equal(error_output.name, 'AssertionError');
210                 });
211             });
212         })
213     })
214
215     describe('OSBuildFetcher.fetchAndReportNewBuilds', () => {
216         const invocations = MockSubprocess.invocations;
217
218         beforeEach(function () {
219             TestServer.database().connect({keepAlive: true});
220         });
221
222         afterEach(function () {
223             TestServer.database().disconnect();
224         });
225
226         it('should report all build commits with owned-commits', () => {
227             const logger = new MockLogger;
228             const fetchter = new OSBuildFetcher(config, TestServer.remoteAPI(), slaveAuth, MockSubprocess, logger);
229             const db = TestServer.database();
230             let fetchAndReportPromise = null;
231             let fetchAvailableBuildsPromise = null;
232
233             return addSlaveForReport(emptyReport).then(() => {
234                 return Promise.all([
235                     db.insert('repositories', {'id': 10, 'name': 'OSX'}),
236                     db.insert('commits', {'repository': 10, 'revision': 'Sierra16D67', 'order': 1603006700, 'reported': true}),
237                     db.insert('commits', {'repository': 10, 'revision': 'Sierra16D68', 'order': 1603006800, 'reported': true}),
238                     db.insert('commits', {'repository': 10, 'revision': 'Sierra16D69', 'order': 1603006900, 'reported': false}),
239                     db.insert('commits', {'repository': 10, 'revision': 'Sierra16E32', 'order': 1604003200, 'reported': true}),
240                     db.insert('commits', {'repository': 10, 'revision': 'Sierra16E33', 'order': 1604003300, 'reported': true}),
241                     db.insert('commits', {'repository': 10, 'revision': 'Sierra16E33g', 'order': 1604003307, 'reported': true})]);
242             }).then(() => {
243                 return TestServer.remoteAPI().getJSON('/api/commits/OSX/last-reported?from=1603000000&to=1603099900');
244             }).then((result) => {
245                 assert.equal(result['commits'].length, 1);
246                 assert.equal(result['commits'][0]['revision'], 'Sierra16D68');
247                 assert.equal(result['commits'][0]['order'], 1603006800);
248                 return TestServer.remoteAPI().getJSON('/api/commits/OSX/last-reported?from=1604000000&to=1604099900');
249             }).then((result) => {
250                 assert.equal(result['commits'].length, 1);
251                 assert.equal(result['commits'][0]['revision'], 'Sierra16E33g');
252                 assert.equal(result['commits'][0]['order'], 1604003307);
253                 const waitForInvocationPromise = MockSubprocess.waitForInvocation();
254                 fetchAvailableBuildsPromise = fetchter._fetchAvailableBuilds();
255                 return waitForInvocationPromise;
256             }).then(() => {
257                 assert.equal(invocations.length, 1);
258                 assert.deepEqual(invocations[0].command, ['list', 'all osx 16Dxx builds']);
259                 invocations[0].resolve('\n\nSierra16D68\nSierra16D69\n');
260                 return MockSubprocess.resetAndWaitForInvocation();
261             }).then(() => {
262                 assert.equal(invocations.length, 1);
263                 assert.deepEqual(invocations[0].command, ['list', 'ownedCommit', 'for', 'revision', 'Sierra16D69']);
264                 invocations[0].resolve(JSON.stringify(ownedCommitWithWebKit));
265                 return MockSubprocess.resetAndWaitForInvocation();
266             }).then(() => {
267                 assert.equal(invocations.length, 1);
268                 assert.deepEqual(invocations[0].command, ['list', 'all osx 16Exx builds']);
269                 invocations[0].resolve('\n\nSierra16E32\nSierra16E33\nSierra16E33h\nSierra16E34');
270                 return MockSubprocess.resetAndWaitForInvocation();
271             }).then(() => {
272                 assert.equal(invocations.length, 1);
273                 assert.deepEqual(invocations[0].command, ['list', 'ownedCommit', 'for', 'revision', 'Sierra16E33h']);
274                 invocations[0].resolve(JSON.stringify(anotherownedCommitWithWebKit));
275                 return MockSubprocess.resetAndWaitForInvocation();
276             }).then(() => {
277                 assert.equal(invocations.length, 1);
278                 assert.deepEqual(invocations[0].command, ['list', 'ownedCommit', 'for', 'revision', 'Sierra16E34']);
279                 invocations[0].resolve(JSON.stringify(anotherownedCommitWithWebKitAndJavaScriptCore));
280                 return fetchAvailableBuildsPromise;
281             }).then((results) => {
282                 assert.equal(results.length, 3);
283                 MockSubprocess.reset();
284                 fetchAndReportPromise = fetchter.fetchAndReportNewBuilds();
285                 return MockSubprocess.waitForInvocation();
286             }).then(() => {
287                 assert.equal(invocations.length, 1);
288                 assert.deepEqual(invocations[0].command, ['list', 'all osx 16Dxx builds']);
289                 invocations[0].resolve('\n\nSierra16D68\nSierra16D69\n');
290                 return MockSubprocess.resetAndWaitForInvocation();
291             }).then(() => {
292                 assert.equal(invocations.length, 1);
293                 assert.deepEqual(invocations[0].command, ['list', 'ownedCommit', 'for', 'revision', 'Sierra16D69']);
294                 invocations[0].resolve(JSON.stringify(ownedCommitWithWebKit));
295                 return MockSubprocess.resetAndWaitForInvocation();
296             }).then(() => {
297                 assert.equal(invocations.length, 1);
298                 assert.deepEqual(invocations[0].command, ['list', 'all osx 16Exx builds']);
299                 invocations[0].resolve('\n\nSierra16E32\nSierra16E33\nSierra16E33h\nSierra16E34');
300                 return MockSubprocess.resetAndWaitForInvocation();
301             }).then(() => {
302                 assert.equal(invocations.length, 1);
303                 assert.deepEqual(invocations[0].command, ['list', 'ownedCommit', 'for', 'revision', 'Sierra16E33h']);
304                 invocations[0].resolve(JSON.stringify(anotherownedCommitWithWebKit));
305                 return MockSubprocess.resetAndWaitForInvocation();
306             }).then(() => {
307                 assert.equal(invocations.length, 1);
308                 invocations[0].resolve(JSON.stringify(anotherownedCommitWithWebKitAndJavaScriptCore));
309                 assert.deepEqual(invocations[0].command, ['list', 'ownedCommit', 'for', 'revision', 'Sierra16E34']);
310
311                 return fetchAndReportPromise;
312             }).then((result) => {
313                 assert.equal(result['status'], 'OK');
314                 return Promise.all([
315                     db.selectRows('repositories', {'name': 'WebKit'}),
316                     db.selectRows('repositories', {'name': 'JavaScriptCore'}),
317                     db.selectRows('commits', {'revision': 'Sierra16D69'}),
318                     db.selectRows('commits', {'revision': 'Sierra16E33h'}),
319                     db.selectRows('commits', {'revision': 'Sierra16E34'})]);
320             }).then((results) => {
321                 const webkitRepository = results[0];
322                 const jscRepository = results[1];
323                 const osxCommit16D69 = results[2];
324                 const osxCommit16E33h = results[3];
325                 const osxCommit16E34 = results[4];
326
327                 assert.equal(webkitRepository.length, 1);
328                 assert.equal(webkitRepository[0]['owner'], 10);
329                 assert.equal(jscRepository.length, 1)
330                 assert.equal(jscRepository[0]['owner'], 10);
331
332                 assert.equal(osxCommit16D69.length, 1);
333                 assert.equal(osxCommit16D69[0]['repository'], 10);
334                 assert.equal(osxCommit16D69[0]['order'], 1603006900);
335
336                 assert.equal(osxCommit16E33h.length, 1);
337                 assert.equal(osxCommit16E33h[0]['repository'], 10);
338                 assert.equal(osxCommit16E33h[0]['order'], 1604003308);
339
340                 assert.equal(osxCommit16E34.length, 1);
341                 assert.equal(osxCommit16E34[0]['repository'], 10);
342                 assert.equal(osxCommit16E34[0]['order'], 1604003400);
343
344                 return TestServer.remoteAPI().getJSON('/api/commits/OSX/last-reported?from=1603000000&to=1603099900');
345             }).then((result) => {
346                 assert.equal(result['commits'].length, 1);
347                 assert.equal(result['commits'][0]['revision'], 'Sierra16D69');
348                 assert.equal(result['commits'][0]['order'], 1603006900);
349
350                 return TestServer.remoteAPI().getJSON('/api/commits/OSX/last-reported?from=1604000000&to=1604099900');
351             }).then((result) => {
352                 assert.equal(result['commits'].length, 1);
353                 assert.equal(result['commits'][0]['revision'], 'Sierra16E34');
354                 assert.equal(result['commits'][0]['order'], 1604003400);
355             });
356         });
357
358         it('should report commits without owned-commits if "ownedCommitCommand" is not specified in config', () => {
359             const logger = new MockLogger;
360             const fetchter = new OSBuildFetcher(configWithoutownedCommitCommand, TestServer.remoteAPI(), slaveAuth, MockSubprocess, logger);
361             const db = TestServer.database();
362             let fetchAndReportPromise = null;
363             let fetchAvailableBuildsPromise = null;
364
365             return addSlaveForReport(emptyReport).then(() => {
366                 return Promise.all([
367                     db.insert('repositories', {'id': 10, 'name': 'OSX'}),
368                     db.insert('commits', {'repository': 10, 'revision': 'Sierra16D67', 'order': 1603006700, 'reported': true}),
369                     db.insert('commits', {'repository': 10, 'revision': 'Sierra16D68', 'order': 1603006800, 'reported': true}),
370                     db.insert('commits', {'repository': 10, 'revision': 'Sierra16D69', 'order': 1603006900, 'reported': false}),
371                     db.insert('commits', {'repository': 10, 'revision': 'Sierra16E32', 'order': 1604003200, 'reported': true}),
372                     db.insert('commits', {'repository': 10, 'revision': 'Sierra16E33', 'order': 1604003300, 'reported': true}),
373                     db.insert('commits', {'repository': 10, 'revision': 'Sierra16E33g', 'order': 1604003307, 'reported': true})]);
374             }).then(() => {
375                 return TestServer.remoteAPI().getJSON('/api/commits/OSX/last-reported?from=1603000000&to=1603099900');
376             }).then((result) => {
377                 assert.equal(result['commits'].length, 1);
378                 assert.equal(result['commits'][0]['revision'], 'Sierra16D68');
379                 assert.equal(result['commits'][0]['order'], 1603006800);
380
381                 return TestServer.remoteAPI().getJSON('/api/commits/OSX/last-reported?from=1604000000&to=1604099900');
382             }).then((result) => {
383                 assert.equal(result['commits'].length, 1);
384                 assert.equal(result['commits'][0]['revision'], 'Sierra16E33g');
385                 assert.equal(result['commits'][0]['order'], 1604003307);
386                 const waitForInvocationPromise = MockSubprocess.waitForInvocation();
387                 fetchAndReportPromise = fetchter.fetchAndReportNewBuilds();
388                 return waitForInvocationPromise;
389             }).then(() => {
390                 assert.equal(invocations.length, 1);
391                 assert.deepEqual(invocations[0].command, ['list', 'all osx 16Dxx builds']);
392                 invocations[0].resolve('\n\nSierra16D68\nSierra16D69\n');
393                 return MockSubprocess.resetAndWaitForInvocation();
394             }).then(() => {
395                 assert.equal(invocations.length, 1);
396                 assert.deepEqual(invocations[0].command, ['list', 'all osx 16Exx builds']);
397                 invocations[0].resolve('\n\nSierra16E32\nSierra16E33\nSierra16E33h\nSierra16E34');
398                 return fetchAndReportPromise;
399             }).then((result) => {
400                 assert.equal(result['status'], 'OK');
401                 return Promise.all([
402                     db.selectRows('repositories', {'name': 'WebKit'}),
403                     db.selectRows('repositories', {'name': 'JavaScriptCore'}),
404                     db.selectRows('commits', {'revision': 'Sierra16D69'}),
405                     db.selectRows('commits', {'revision': 'Sierra16E33h'}),
406                     db.selectRows('commits', {'revision': 'Sierra16E34'})]);
407             }).then((results) => {
408                 const webkitRepository = results[0];
409                 const jscRepository = results[1];
410                 const osxCommit16D69 = results[2];
411                 const osxCommit16E33h = results[3];
412                 const osxCommit16E34 = results[4];
413
414                 assert.equal(webkitRepository.length, 0);
415                 assert.equal(jscRepository.length, 0)
416
417                 assert.equal(osxCommit16D69.length, 1);
418                 assert.equal(osxCommit16D69[0]['repository'], 10);
419                 assert.equal(osxCommit16D69[0]['order'], 1603006900);
420
421                 assert.equal(osxCommit16E33h.length, 1);
422                 assert.equal(osxCommit16E33h[0]['repository'], 10);
423                 assert.equal(osxCommit16E33h[0]['order'], 1604003308);
424
425                 assert.equal(osxCommit16E34.length, 1);
426                 assert.equal(osxCommit16E34[0]['repository'], 10);
427                 assert.equal(osxCommit16E34[0]['order'], 1604003400);
428
429                 return TestServer.remoteAPI().getJSON('/api/commits/OSX/last-reported?from=1603000000&to=1603099900');
430             }).then((result) => {
431                 assert.equal(result['commits'].length, 1);
432                 assert.equal(result['commits'][0]['revision'], 'Sierra16D69');
433                 assert.equal(result['commits'][0]['order'], 1603006900);
434
435                 return TestServer.remoteAPI().getJSON('/api/commits/OSX/last-reported?from=1604000000&to=1604099900');
436             }).then((result) => {
437                 assert.equal(result['commits'].length, 1);
438                 assert.equal(result['commits'][0]['revision'], 'Sierra16E34');
439                 assert.equal(result['commits'][0]['order'], 1604003400);
440             });
441         });
442
443         it('should stop reporting if any custom command fails', () => {
444             const logger = new MockLogger;
445             const fetchter = new OSBuildFetcher(config, TestServer.remoteAPI(), slaveAuth, MockSubprocess, logger);
446             const db = TestServer.database();
447             let fetchAndReportPromise = null;
448
449             return addSlaveForReport(emptyReport).then(() => {
450                 return Promise.all([
451                     db.insert('repositories', {'id': 10, 'name': 'OSX'}),
452                     db.insert('commits', {'repository': 10, 'revision': 'Sierra16D67', 'order': 1603006700, 'reported': true}),
453                     db.insert('commits', {'repository': 10, 'revision': 'Sierra16D68', 'order': 1603006800, 'reported': true}),
454                     db.insert('commits', {'repository': 10, 'revision': 'Sierra16D69', 'order': 1603006900, 'reported': false}),
455                     db.insert('commits', {'repository': 10, 'revision': 'Sierra16E32', 'order': 1604003200, 'reported': true}),
456                     db.insert('commits', {'repository': 10, 'revision': 'Sierra16E33', 'order': 1604003300, 'reported': true}),
457                     db.insert('commits', {'repository': 10, 'revision': 'Sierra16E33g', 'order': 1604003307, 'reported': true})]);
458             }).then(() => {
459                 return TestServer.remoteAPI().getJSON('/api/commits/OSX/last-reported?from=1603000000&to=1603099900');
460             }).then((result) => {
461                 assert.equal(result['commits'].length, 1);
462                 assert.equal(result['commits'][0]['revision'], 'Sierra16D68');
463                 assert.equal(result['commits'][0]['order'], 1603006800);
464
465                 return TestServer.remoteAPI().getJSON('/api/commits/OSX/last-reported?from=1604000000&to=1604099900');
466             }).then((result) => {
467                 assert.equal(result['commits'].length, 1);
468                 assert.equal(result['commits'][0]['revision'], 'Sierra16E33g');
469                 assert.equal(result['commits'][0]['order'], 1604003307);
470
471                 const waitForInvocationPromise = MockSubprocess.waitForInvocation();
472                 fetchAndReportPromise = fetchter.fetchAndReportNewBuilds();
473                 return waitForInvocationPromise;
474             }).then(() => {
475                 assert.equal(invocations.length, 1);
476                 assert.deepEqual(invocations[0].command, ['list', 'all osx 16Dxx builds']);
477                 invocations[0].resolve('\n\nSierra16D68\nSierra16D69\n');
478                 return MockSubprocess.resetAndWaitForInvocation();
479             }).then(() => {
480                 assert.equal(invocations.length, 1);
481                 assert.deepEqual(invocations[0].command, ['list', 'ownedCommit', 'for', 'revision', 'Sierra16D69']);
482                 MockSubprocess.invocations[0].resolve(JSON.stringify(ownedCommitWithWebKit));
483                 return MockSubprocess.resetAndWaitForInvocation();
484             }).then(() => {
485                 assert.equal(invocations.length, 1);
486                 assert.deepEqual(invocations[0].command, ['list', 'all osx 16Exx builds']);
487                 invocations[0].resolve('\n\nSierra16E32\nSierra16E33\nSierra16E33h\nSierra16E34');
488                 return MockSubprocess.resetAndWaitForInvocation();
489             }).then(() => {
490                 assert.deepEqual(invocations[0].command, ['list', 'ownedCommit', 'for', 'revision', 'Sierra16E33h']);
491                 invocations[0].resolve(JSON.stringify(anotherownedCommitWithWebKit));
492                 return MockSubprocess.resetAndWaitForInvocation();
493             }).then(() => {
494                 assert.equal(invocations.length, 1);
495                 assert.deepEqual(invocations[0].command, ['list', 'ownedCommit', 'for', 'revision', 'Sierra16E34']);
496                 invocations[0].reject('Command failed');
497                 return fetchAndReportPromise.then(() => {
498                     assert(false, 'should never be reached');
499                 }, (error_output) => {
500                     assert(error_output);
501                     assert.equal(error_output, 'Command failed');
502                 });
503             }).then(() => {
504                 return TestServer.remoteAPI().getJSON('/api/commits/OSX/last-reported?from=1603000000&to=1603099900');
505             }).then((result) => {
506                 assert.equal(result['commits'].length, 1);
507                 assert.equal(result['commits'][0]['revision'], 'Sierra16D68');
508                 assert.equal(result['commits'][0]['order'], 1603006800);
509
510                 return TestServer.remoteAPI().getJSON('/api/commits/OSX/last-reported?from=1604000000&to=1604099900');
511             }).then((result) => {
512                 assert.equal(result['commits'].length, 1);
513                 assert.equal(result['commits'][0]['revision'], 'Sierra16E33g');
514                 assert.equal(result['commits'][0]['order'], 1604003307);
515             });
516         })
517     })
518 });