Rewrite 'pull-os-versions' script in Javascript to add support for reporting os revis...
[WebKit.git] / Websites / perf.webkit.org / server-tests / tools-buildbot-triggerable-tests.js
1 'use strict';
2
3 const assert = require('assert');
4
5 const BuildbotTriggerable = require('../tools/js/buildbot-triggerable.js').BuildbotTriggerable;
6 const MockData = require('./resources/mock-data.js');
7 const MockRemoteAPI = require('../unit-tests/resources/mock-remote-api.js').MockRemoteAPI;
8 const TestServer = require('./resources/test-server.js');
9 const prepareServerTest = require('./resources/common-operations.js').prepareServerTest;
10 const MockLogger = require('./resources/mock-logger.js').MockLogger;
11
12 describe('BuildbotTriggerable', function () {
13     prepareServerTest(this);
14
15     beforeEach(function () {
16         MockData.resetV3Models();
17         MockRemoteAPI.reset('http://build.webkit.org');
18     });
19
20     describe('syncOnce', () => {
21         it('should schedule the next build request when there are no pending builds', () => {
22             const db = TestServer.database();
23             let syncPromise;
24             return MockData.addMockData(db, ['completed', 'running', 'pending', 'pending']).then(() => {
25                 return Manifest.fetch();
26             }).then(() => {
27                 const config = MockData.mockTestSyncConfigWithSingleBuilder();
28                 const logger = new MockLogger;
29                 const slaveInfo = {name: 'sync-slave', password: 'password'};
30                 const triggerable = new BuildbotTriggerable(config, TestServer.remoteAPI(), MockRemoteAPI, slaveInfo, logger);
31                 syncPromise = triggerable.syncOnce();
32                 return MockRemoteAPI.waitForRequest();
33             }).then(() => {
34                 assert.equal(BuildRequest.all().length, 4);
35                 assert.equal(BuildRequest.findById(700).status(), 'completed');
36                 assert.equal(BuildRequest.findById(701).status(), 'running');
37                 assert.equal(BuildRequest.findById(702).status(), 'pending');
38                 assert.equal(BuildRequest.findById(703).status(), 'pending');
39                 assert.equal(MockRemoteAPI.requests[0].method, 'GET');
40                 assert.equal(MockRemoteAPI.requests[0].url, '/json/builders/some-builder-1/pendingBuilds');
41                 MockRemoteAPI.requests[0].resolve([]);
42                 return MockRemoteAPI.waitForRequest();
43             }).then(() => {
44                 assert.equal(MockRemoteAPI.requests[1].method, 'GET');
45                 assert.equal(MockRemoteAPI.requests[1].url, '/json/builders/some-builder-1/builds/?select=-1&select=-2');
46                 MockRemoteAPI.requests[1].resolve({[-1]: MockData.runningBuild(), [-2]: MockData.finishedBuild()});
47                 return MockRemoteAPI.waitForRequest();
48             }).then(() => {
49                 assert.equal(MockRemoteAPI.requests[2].method, 'POST');
50                 assert.equal(MockRemoteAPI.requests[2].url, '/builders/some-builder-1/force');
51                 assert.deepEqual(MockRemoteAPI.requests[2].data, {'wk': '191622', 'os': '10.11 15A284', 'build-request-id': '702'});
52                 MockRemoteAPI.requests[2].resolve('OK');
53                 return MockRemoteAPI.waitForRequest();
54             }).then(() => {
55                 assert.equal(MockRemoteAPI.requests[3].method, 'GET');
56                 assert.equal(MockRemoteAPI.requests[3].url, '/json/builders/some-builder-1/pendingBuilds');
57                 MockRemoteAPI.requests[3].resolve([MockData.pendingBuild()])
58                 return MockRemoteAPI.waitForRequest();
59             }).then(() => {
60                 assert.equal(MockRemoteAPI.requests[4].method, 'GET');
61                 assert.equal(MockRemoteAPI.requests[4].url, '/json/builders/some-builder-1/builds/?select=-1&select=-2');
62                 MockRemoteAPI.requests[4].resolve({[-1]: MockData.runningBuild(), [-2]: MockData.finishedBuild()});
63                 return syncPromise;
64             }).then(() => {
65                 return BuildRequest.fetchForTriggerable(MockData.mockTestSyncConfigWithSingleBuilder().triggerableName);
66             }).then(() => {
67                 assert.equal(BuildRequest.all().length, 4);
68                 assert.equal(BuildRequest.findById(700).status(), 'completed');
69                 assert.equal(BuildRequest.findById(701).status(), 'running');
70                 assert.equal(BuildRequest.findById(702).status(), 'scheduled');
71                 assert.equal(BuildRequest.findById(703).status(), 'pending');
72             });
73         });
74
75         it('should not schedule the next build request when there is a pending build', () => {
76             const db = TestServer.database();
77             let syncPromise;
78             return MockData.addMockData(db, ['completed', 'running', 'pending', 'pending']).then(() => {
79                 return Manifest.fetch();
80             }).then(() => {
81                 let config = MockData.mockTestSyncConfigWithSingleBuilder();
82                 let logger = new MockLogger;
83                 let slaveInfo = {name: 'sync-slave', password: 'password'};
84                 let triggerable = new BuildbotTriggerable(config, TestServer.remoteAPI(), MockRemoteAPI, slaveInfo, logger);
85                 syncPromise = triggerable.syncOnce();
86                 return MockRemoteAPI.waitForRequest();
87             }).then(() => {
88                 assert.equal(MockRemoteAPI.requests[0].method, 'GET');
89                 assert.equal(MockRemoteAPI.requests[0].url, '/json/builders/some-builder-1/pendingBuilds');
90                 MockRemoteAPI.requests[0].resolve([MockData.pendingBuild()]);
91                 return MockRemoteAPI.waitForRequest();
92             }).then(() => {
93                 assert.equal(MockRemoteAPI.requests[1].method, 'GET');
94                 assert.equal(MockRemoteAPI.requests[1].url, '/json/builders/some-builder-1/builds/?select=-1&select=-2');
95                 MockRemoteAPI.requests[1].resolve({[-1]: MockData.runningBuild(), [-2]: MockData.finishedBuild()});
96                 return MockRemoteAPI.waitForRequest();
97             }).then(() => {
98                 assert.equal(MockRemoteAPI.requests[2].method, 'GET');
99                 assert.equal(MockRemoteAPI.requests[2].url, '/json/builders/some-builder-1/pendingBuilds');
100                 MockRemoteAPI.requests[2].resolve([MockData.pendingBuild()])
101                 return MockRemoteAPI.waitForRequest();
102             }).then(() => {
103                 assert.equal(MockRemoteAPI.requests[3].method, 'GET');
104                 assert.equal(MockRemoteAPI.requests[3].url, '/json/builders/some-builder-1/builds/?select=-1&select=-2');
105                 MockRemoteAPI.requests[3].resolve({[-1]: MockData.runningBuild(), [-2]: MockData.finishedBuild()});
106                 return syncPromise;
107             }).then(() => {
108                 assert.equal(BuildRequest.all().length, 4);
109                 assert.equal(BuildRequest.findById(700).status(), 'completed');
110                 assert.equal(BuildRequest.findById(701).status(), 'running');
111                 assert.equal(BuildRequest.findById(702).status(), 'pending');
112                 assert.equal(BuildRequest.findById(703).status(), 'pending');
113                 return BuildRequest.fetchForTriggerable(MockData.mockTestSyncConfigWithSingleBuilder().triggerableName);
114             }).then(() => {
115                 assert.equal(BuildRequest.all().length, 4);
116                 assert.equal(BuildRequest.findById(700).status(), 'completed');
117                 assert.equal(BuildRequest.findById(701).status(), 'running');
118                 assert.equal(BuildRequest.findById(702).status(), 'scheduled');
119                 assert.equal(BuildRequest.findById(703).status(), 'pending');
120             });
121         });
122
123         it('should schedule the build request on a builder without a pending build if it\'s the first request in the group', () => {
124             const db = TestServer.database();
125             let syncPromise;
126             return MockData.addMockData(db, ['pending', 'pending', 'pending', 'pending']).then(() => {
127                 return Manifest.fetch();
128             }).then(() => {
129                 const config = MockData.mockTestSyncConfigWithTwoBuilders();
130                 const logger = new MockLogger;
131                 const slaveInfo = {name: 'sync-slave', password: 'password'};
132                 const triggerable = new BuildbotTriggerable(config, TestServer.remoteAPI(), MockRemoteAPI, slaveInfo, logger);
133                 syncPromise = triggerable.syncOnce();
134                 return MockRemoteAPI.waitForRequest();
135             }).then(() => {
136                 assert.equal(MockRemoteAPI.requests.length, 2);
137                 assert.equal(MockRemoteAPI.requests[0].method, 'GET');
138                 assert.equal(MockRemoteAPI.requests[0].url, '/json/builders/some-builder-1/pendingBuilds');
139                 MockRemoteAPI.requests[0].resolve([MockData.pendingBuild({buildRequestId: 999})]);
140                 assert.equal(MockRemoteAPI.requests[1].method, 'GET');
141                 assert.equal(MockRemoteAPI.requests[1].url, '/json/builders/some%20builder%202/pendingBuilds');
142                 MockRemoteAPI.requests[1].resolve([]);
143                 return MockRemoteAPI.waitForRequest();
144             }).then(() => {
145                 assert.equal(MockRemoteAPI.requests.length, 4);
146                 assert.equal(MockRemoteAPI.requests[2].method, 'GET');
147                 assert.equal(MockRemoteAPI.requests[2].url, '/json/builders/some-builder-1/builds/?select=-1&select=-2');
148                 MockRemoteAPI.requests[2].resolve({});
149                 assert.equal(MockRemoteAPI.requests[3].method, 'GET');
150                 assert.equal(MockRemoteAPI.requests[3].url, '/json/builders/some%20builder%202/builds/?select=-1&select=-2');
151                 MockRemoteAPI.requests[3].resolve({});
152                 return MockRemoteAPI.waitForRequest();
153             }).then(() => {
154                 assert.equal(MockRemoteAPI.requests.length, 5);
155                 assert.equal(MockRemoteAPI.requests[4].method, 'POST');
156                 assert.equal(MockRemoteAPI.requests[4].url, '/builders/some%20builder%202/force');
157                 assert.deepEqual(MockRemoteAPI.requests[4].data, {'wk': '191622', 'os': '10.11 15A284', 'build-request-id': '700'});
158                 MockRemoteAPI.requests[4].resolve('OK');
159                 return MockRemoteAPI.waitForRequest();
160             }).then(() => {
161                 assert.equal(MockRemoteAPI.requests.length, 7);
162                 assert.equal(MockRemoteAPI.requests[5].method, 'GET');
163                 assert.equal(MockRemoteAPI.requests[5].url, '/json/builders/some-builder-1/pendingBuilds');
164                 MockRemoteAPI.requests[5].resolve([MockData.pendingBuild({buildRequestId: 999})]);
165                 assert.equal(MockRemoteAPI.requests[6].method, 'GET');
166                 assert.equal(MockRemoteAPI.requests[6].url, '/json/builders/some%20builder%202/pendingBuilds');
167                 MockRemoteAPI.requests[6].resolve([MockData.pendingBuild({builder: 'some builder 2', buildRequestId: 700})]);
168                 return MockRemoteAPI.waitForRequest();
169             }).then(() => {
170                 assert.equal(MockRemoteAPI.requests.length, 9);
171                 assert.equal(MockRemoteAPI.requests[7].method, 'GET');
172                 assert.equal(MockRemoteAPI.requests[7].url, '/json/builders/some-builder-1/builds/?select=-1&select=-2');
173                 MockRemoteAPI.requests[7].resolve({});
174                 assert.equal(MockRemoteAPI.requests[8].method, 'GET');
175                 assert.equal(MockRemoteAPI.requests[8].url, '/json/builders/some%20builder%202/builds/?select=-1&select=-2');
176                 MockRemoteAPI.requests[8].resolve({});
177                 return syncPromise;
178             }).then(() => {
179                 assert.equal(BuildRequest.all().length, 4);
180                 assert.equal(BuildRequest.findById(700).status(), 'pending');
181                 assert.equal(BuildRequest.findById(700).statusUrl(), null);
182                 assert.equal(BuildRequest.findById(701).status(), 'pending');
183                 assert.equal(BuildRequest.findById(701).statusUrl(), null);
184                 assert.equal(BuildRequest.findById(702).status(), 'pending');
185                 assert.equal(BuildRequest.findById(702).statusUrl(), null);
186                 assert.equal(BuildRequest.findById(703).status(), 'pending');
187                 assert.equal(BuildRequest.findById(703).statusUrl(), null);
188                 return BuildRequest.fetchForTriggerable(MockData.mockTestSyncConfigWithTwoBuilders().triggerableName);
189             }).then(() => {
190                 assert.equal(BuildRequest.all().length, 4);
191                 assert.equal(BuildRequest.findById(700).status(), 'scheduled');
192                 assert.equal(BuildRequest.findById(700).statusUrl(), 'http://build.webkit.org/builders/some%20builder%202/');
193                 assert.equal(BuildRequest.findById(701).status(), 'pending');
194                 assert.equal(BuildRequest.findById(701).statusUrl(), null);
195                 assert.equal(BuildRequest.findById(702).status(), 'pending');
196                 assert.equal(BuildRequest.findById(702).statusUrl(), null);
197                 assert.equal(BuildRequest.findById(703).status(), 'pending');
198                 assert.equal(BuildRequest.findById(703).statusUrl(), null);
199             });
200         });
201
202         it('should not schedule a build request on a different builder than the one the first build request is pending', () => {
203             const db = TestServer.database();
204             let syncPromise;
205             return MockData.addMockData(db, ['pending', 'pending', 'pending', 'pending']).then(() => {
206                 return Manifest.fetch();
207             }).then(() => {
208                 let config = MockData.mockTestSyncConfigWithTwoBuilders();
209                 let logger = new MockLogger;
210                 let slaveInfo = {name: 'sync-slave', password: 'password'};
211                 let triggerable = new BuildbotTriggerable(config, TestServer.remoteAPI(), MockRemoteAPI, slaveInfo, logger);
212                 syncPromise = triggerable.syncOnce();
213                 return MockRemoteAPI.waitForRequest();
214             }).then(() => {
215                 assert.equal(MockRemoteAPI.requests.length, 2);
216                 assert.equal(MockRemoteAPI.requests[0].method, 'GET');
217                 assert.equal(MockRemoteAPI.requests[0].url, '/json/builders/some-builder-1/pendingBuilds');
218                 MockRemoteAPI.requests[0].resolve([MockData.pendingBuild({buildRequestId: 700})]);
219                 assert.equal(MockRemoteAPI.requests[1].method, 'GET');
220                 assert.equal(MockRemoteAPI.requests[1].url, '/json/builders/some%20builder%202/pendingBuilds');
221                 MockRemoteAPI.requests[1].resolve([]);
222                 return MockRemoteAPI.waitForRequest();
223             }).then(() => {
224                 assert.equal(MockRemoteAPI.requests.length, 4);
225                 assert.equal(MockRemoteAPI.requests[2].method, 'GET');
226                 assert.equal(MockRemoteAPI.requests[2].url, '/json/builders/some-builder-1/builds/?select=-1&select=-2');
227                 MockRemoteAPI.requests[2].resolve({});
228                 assert.equal(MockRemoteAPI.requests[3].method, 'GET');
229                 assert.equal(MockRemoteAPI.requests[3].url, '/json/builders/some%20builder%202/builds/?select=-1&select=-2');
230                 MockRemoteAPI.requests[3].resolve({});
231                 return MockRemoteAPI.waitForRequest();
232             }).then(() => {
233                 assert.equal(MockRemoteAPI.requests.length, 6);
234                 assert.equal(MockRemoteAPI.requests[4].method, 'GET');
235                 assert.equal(MockRemoteAPI.requests[4].url, '/json/builders/some-builder-1/pendingBuilds');
236                 MockRemoteAPI.requests[4].resolve([MockData.pendingBuild({buildRequestId: 700})]);
237                 assert.equal(MockRemoteAPI.requests[5].method, 'GET');
238                 assert.equal(MockRemoteAPI.requests[5].url, '/json/builders/some%20builder%202/pendingBuilds');
239                 MockRemoteAPI.requests[5].resolve([]);
240                 return MockRemoteAPI.waitForRequest();
241             }).then(() => {
242                 assert.equal(MockRemoteAPI.requests.length, 8);
243                 assert.equal(MockRemoteAPI.requests[6].method, 'GET');
244                 assert.equal(MockRemoteAPI.requests[6].url, '/json/builders/some-builder-1/builds/?select=-1&select=-2');
245                 MockRemoteAPI.requests[6].resolve({});
246                 assert.equal(MockRemoteAPI.requests[7].method, 'GET');
247                 assert.equal(MockRemoteAPI.requests[7].url, '/json/builders/some%20builder%202/builds/?select=-1&select=-2');
248                 MockRemoteAPI.requests[7].resolve({});
249                 return syncPromise;
250             }).then(() => {
251                 assert.equal(BuildRequest.all().length, 4);
252                 assert.equal(BuildRequest.findById(700).status(), 'pending');
253                 assert.equal(BuildRequest.findById(700).statusUrl(), null);
254                 assert.equal(BuildRequest.findById(701).status(), 'pending');
255                 assert.equal(BuildRequest.findById(701).statusUrl(), null);
256                 assert.equal(BuildRequest.findById(702).status(), 'pending');
257                 assert.equal(BuildRequest.findById(702).statusUrl(), null);
258                 assert.equal(BuildRequest.findById(703).status(), 'pending');
259                 assert.equal(BuildRequest.findById(703).statusUrl(), null);
260                 return BuildRequest.fetchForTriggerable(MockData.mockTestSyncConfigWithTwoBuilders().triggerableName);
261             }).then(() => {
262                 assert.equal(BuildRequest.all().length, 4);
263                 assert.equal(BuildRequest.findById(700).status(), 'scheduled');
264                 assert.equal(BuildRequest.findById(700).statusUrl(), 'http://build.webkit.org/builders/some-builder-1/');
265                 assert.equal(BuildRequest.findById(701).status(), 'pending');
266                 assert.equal(BuildRequest.findById(701).statusUrl(), null);
267                 assert.equal(BuildRequest.findById(702).status(), 'pending');
268                 assert.equal(BuildRequest.findById(702).statusUrl(), null);
269                 assert.equal(BuildRequest.findById(703).status(), 'pending');
270                 assert.equal(BuildRequest.findById(703).statusUrl(), null);
271             });
272         });
273
274         it('should update the status of a pending build and schedule a new build if the pending build had started running', () => {
275             const db = TestServer.database();
276             let syncPromise;
277             return MockData.addMockData(db, ['pending', 'pending', 'pending', 'pending']).then(() => {
278                 return Manifest.fetch();
279             }).then(() => {
280                 const config = MockData.mockTestSyncConfigWithTwoBuilders();
281                 const logger = new MockLogger;
282                 const slaveInfo = {name: 'sync-slave', password: 'password'};
283                 const triggerable = new BuildbotTriggerable(config, TestServer.remoteAPI(), MockRemoteAPI, slaveInfo, logger);
284                 syncPromise = triggerable.syncOnce();
285                 return MockRemoteAPI.waitForRequest();
286             }).then(() => {
287                 assert.equal(MockRemoteAPI.requests.length, 2);
288                 assert.equal(MockRemoteAPI.requests[0].method, 'GET');
289                 assert.equal(MockRemoteAPI.requests[0].url, '/json/builders/some-builder-1/pendingBuilds');
290                 MockRemoteAPI.requests[0].resolve([]);
291                 assert.equal(MockRemoteAPI.requests[1].method, 'GET');
292                 assert.equal(MockRemoteAPI.requests[1].url, '/json/builders/some%20builder%202/pendingBuilds');
293                 MockRemoteAPI.requests[1].resolve([]);
294                 return MockRemoteAPI.waitForRequest();
295             }).then(() => {
296                 assert.equal(MockRemoteAPI.requests.length, 4);
297                 assert.equal(MockRemoteAPI.requests[2].method, 'GET');
298                 assert.equal(MockRemoteAPI.requests[2].url, '/json/builders/some-builder-1/builds/?select=-1&select=-2');
299                 MockRemoteAPI.requests[2].resolve({[-1]: MockData.runningBuild({buildRequestId: 701}), [-2]: MockData.finishedBuild({buildRequestId: 700})});
300                 assert.equal(MockRemoteAPI.requests[3].method, 'GET');
301                 assert.equal(MockRemoteAPI.requests[3].url, '/json/builders/some%20builder%202/builds/?select=-1&select=-2');
302                 MockRemoteAPI.requests[3].resolve({});
303                 return MockRemoteAPI.waitForRequest();
304             }).then(() => {
305                 assert.equal(MockRemoteAPI.requests.length, 5);
306                 assert.equal(MockRemoteAPI.requests[4].method, 'POST');
307                 assert.equal(MockRemoteAPI.requests[4].url, '/builders/some-builder-1/force');
308                 assert.deepEqual(MockRemoteAPI.requests[4].data, {'wk': '191622', 'os': '10.11 15A284', 'build-request-id': '702'});
309                 MockRemoteAPI.requests[4].resolve('OK');
310                 return MockRemoteAPI.waitForRequest();
311             }).then(() => {
312                 assert.equal(MockRemoteAPI.requests.length, 7);
313                 assert.equal(MockRemoteAPI.requests[5].method, 'GET');
314                 assert.equal(MockRemoteAPI.requests[5].url, '/json/builders/some-builder-1/pendingBuilds');
315                 MockRemoteAPI.requests[5].resolve([MockData.pendingBuild({buildRequestId: 702})]);
316                 assert.equal(MockRemoteAPI.requests[6].method, 'GET');
317                 assert.equal(MockRemoteAPI.requests[6].url, '/json/builders/some%20builder%202/pendingBuilds');
318                 MockRemoteAPI.requests[6].resolve([]);
319                 return MockRemoteAPI.waitForRequest();
320             }).then(() => {
321                 assert.equal(MockRemoteAPI.requests.length, 9);
322                 assert.equal(MockRemoteAPI.requests[7].method, 'GET');
323                 assert.equal(MockRemoteAPI.requests[7].url, '/json/builders/some-builder-1/builds/?select=-1&select=-2');
324                 MockRemoteAPI.requests[7].resolve({[-1]: MockData.runningBuild({buildRequestId: 701}), [-2]: MockData.finishedBuild({buildRequestId: 700})});
325                 assert.equal(MockRemoteAPI.requests[8].method, 'GET');
326                 assert.equal(MockRemoteAPI.requests[8].url, '/json/builders/some%20builder%202/builds/?select=-1&select=-2');
327                 MockRemoteAPI.requests[8].resolve({});
328                 return syncPromise;
329             }).then(() => {
330                 assert.equal(BuildRequest.all().length, 4);
331                 assert.equal(BuildRequest.findById(700).status(), 'pending');
332                 assert.equal(BuildRequest.findById(700).statusUrl(), null);
333                 assert.equal(BuildRequest.findById(701).status(), 'pending');
334                 assert.equal(BuildRequest.findById(701).statusUrl(), null);
335                 assert.equal(BuildRequest.findById(702).status(), 'pending');
336                 assert.equal(BuildRequest.findById(702).statusUrl(), null);
337                 assert.equal(BuildRequest.findById(703).status(), 'pending');
338                 assert.equal(BuildRequest.findById(703).statusUrl(), null);
339                 return BuildRequest.fetchForTriggerable(MockData.mockTestSyncConfigWithTwoBuilders().triggerableName);
340             }).then(() => {
341                 assert.equal(BuildRequest.all().length, 4);
342                 assert.equal(BuildRequest.findById(700).status(), 'failed');
343                 assert.equal(BuildRequest.findById(700).statusUrl(), 'http://build.webkit.org/builders/some-builder-1/builds/123');
344                 assert.equal(BuildRequest.findById(701).status(), 'running');
345                 assert.equal(BuildRequest.findById(701).statusUrl(), 'http://build.webkit.org/builders/some-builder-1/builds/124');
346                 assert.equal(BuildRequest.findById(702).status(), 'scheduled');
347                 assert.equal(BuildRequest.findById(702).statusUrl(), 'http://build.webkit.org/builders/some-builder-1/');
348                 assert.equal(BuildRequest.findById(703).status(), 'pending');
349                 assert.equal(BuildRequest.findById(703).statusUrl(), null);
350             });
351         });
352
353         it('should update the status of a scheduled build if the pending build had started running', () => {
354             const db = TestServer.database();
355             let syncPromise;
356             return MockData.addMockData(db, ['scheduled', 'pending', 'pending', 'pending']).then(() => {
357                 return Manifest.fetch();
358             }).then(() => {
359                 let config = MockData.mockTestSyncConfigWithSingleBuilder();
360                 let logger = new MockLogger;
361                 let slaveInfo = {name: 'sync-slave', password: 'password'};
362                 let triggerable = new BuildbotTriggerable(config, TestServer.remoteAPI(), MockRemoteAPI, slaveInfo, logger);
363                 syncPromise = triggerable.syncOnce();
364                 return MockRemoteAPI.waitForRequest();
365             }).then(() => {
366                 assert.equal(MockRemoteAPI.requests.length, 1);
367                 assert.equal(MockRemoteAPI.requests[0].method, 'GET');
368                 assert.equal(MockRemoteAPI.requests[0].url, '/json/builders/some-builder-1/pendingBuilds');
369                 MockRemoteAPI.requests[0].resolve([MockData.pendingBuild({buildRequestId: 700})]);
370                 return MockRemoteAPI.waitForRequest();
371             }).then(() => {
372                 assert.equal(MockRemoteAPI.requests.length, 2);
373                 assert.equal(MockRemoteAPI.requests[1].method, 'GET');
374                 assert.equal(MockRemoteAPI.requests[1].url, '/json/builders/some-builder-1/builds/?select=-1&select=-2');
375                 MockRemoteAPI.requests[1].resolve({});
376                 return MockRemoteAPI.waitForRequest();
377             }).then(() => {
378                 assert.equal(MockRemoteAPI.requests.length, 3);
379                 assert.equal(MockRemoteAPI.requests[2].method, 'GET');
380                 assert.equal(MockRemoteAPI.requests[2].url, '/json/builders/some-builder-1/pendingBuilds');
381                 MockRemoteAPI.requests[2].resolve([]);
382                 return MockRemoteAPI.waitForRequest();
383             }).then(() => {
384                 assert.equal(MockRemoteAPI.requests.length, 4);
385                 assert.equal(MockRemoteAPI.requests[3].method, 'GET');
386                 assert.equal(MockRemoteAPI.requests[3].url, '/json/builders/some-builder-1/builds/?select=-1&select=-2');
387                 MockRemoteAPI.requests[3].resolve({[-1]: MockData.runningBuild({buildRequestId: 700})});
388                 return syncPromise;
389             }).then(() => {
390                 assert.equal(BuildRequest.all().length, 4);
391                 assert.equal(BuildRequest.findById(700).status(), 'scheduled');
392                 assert.equal(BuildRequest.findById(700).statusUrl(), null);
393                 assert.equal(BuildRequest.findById(701).status(), 'pending');
394                 assert.equal(BuildRequest.findById(701).statusUrl(), null);
395                 assert.equal(BuildRequest.findById(702).status(), 'pending');
396                 assert.equal(BuildRequest.findById(702).statusUrl(), null);
397                 assert.equal(BuildRequest.findById(703).status(), 'pending');
398                 assert.equal(BuildRequest.findById(703).statusUrl(), null);
399                 return BuildRequest.fetchForTriggerable(MockData.mockTestSyncConfigWithTwoBuilders().triggerableName);
400             }).then(() => {
401                 assert.equal(BuildRequest.all().length, 4);
402                 assert.equal(BuildRequest.findById(700).status(), 'running');
403                 assert.equal(BuildRequest.findById(700).statusUrl(), 'http://build.webkit.org/builders/some-builder-1/builds/124');
404                 assert.equal(BuildRequest.findById(701).status(), 'pending');
405                 assert.equal(BuildRequest.findById(701).statusUrl(), null);
406                 assert.equal(BuildRequest.findById(702).status(), 'pending');
407                 assert.equal(BuildRequest.findById(702).statusUrl(), null);
408                 assert.equal(BuildRequest.findById(703).status(), 'pending');
409                 assert.equal(BuildRequest.findById(703).statusUrl(), null);
410             });
411         });
412
413         it('should schedule a build request on a builder without pending builds if the request belongs to a new test group', () => {
414             const db = TestServer.database();
415             let syncPromise;
416             return Promise.all([
417                 MockData.addMockData(db, ['completed', 'pending', 'pending', 'pending']),
418                 MockData.addAnotherMockTestGroup(db, ['pending', 'pending', 'pending', 'pending'])
419             ]).then(() => {
420                 return Manifest.fetch();
421             }).then(() => {
422                 const config = MockData.mockTestSyncConfigWithTwoBuilders();
423                 const logger = new MockLogger;
424                 const slaveInfo = {name: 'sync-slave', password: 'password'};
425                 const triggerable = new BuildbotTriggerable(config, TestServer.remoteAPI(), MockRemoteAPI, slaveInfo, logger);
426                 syncPromise = triggerable.syncOnce();
427                 return MockRemoteAPI.waitForRequest();
428             }).then(() => {
429                 assert.equal(MockRemoteAPI.requests.length, 2);
430                 assert.equal(MockRemoteAPI.requests[0].method, 'GET');
431                 assert.equal(MockRemoteAPI.requests[0].url, '/json/builders/some-builder-1/pendingBuilds');
432                 MockRemoteAPI.requests[0].resolve([MockData.pendingBuild({buildRequestId: 702})]);
433                 assert.equal(MockRemoteAPI.requests[1].method, 'GET');
434                 assert.equal(MockRemoteAPI.requests[1].url, '/json/builders/some%20builder%202/pendingBuilds');
435                 MockRemoteAPI.requests[1].resolve([]);
436                 return MockRemoteAPI.waitForRequest();
437             }).then(() => {
438                 assert.equal(MockRemoteAPI.requests.length, 4);
439                 assert.equal(MockRemoteAPI.requests[2].method, 'GET');
440                 assert.equal(MockRemoteAPI.requests[2].url, '/json/builders/some-builder-1/builds/?select=-1&select=-2');
441                 MockRemoteAPI.requests[2].resolve({[-1]: MockData.runningBuild({buildRequestId: 701}), [-2]: MockData.finishedBuild({buildRequestId: 700})});
442                 assert.equal(MockRemoteAPI.requests[3].method, 'GET');
443                 assert.equal(MockRemoteAPI.requests[3].url, '/json/builders/some%20builder%202/builds/?select=-1&select=-2');
444                 MockRemoteAPI.requests[3].resolve({});
445                 return MockRemoteAPI.waitForRequest();
446             }).then(() => {
447                 assert.equal(MockRemoteAPI.requests.length, 5);
448                 assert.equal(MockRemoteAPI.requests[4].method, 'POST');
449                 assert.equal(MockRemoteAPI.requests[4].url, '/builders/some%20builder%202/force');
450                 assert.deepEqual(MockRemoteAPI.requests[4].data, {'wk': '191622', 'os': '10.11 15A284', 'build-request-id': '710'});
451                 MockRemoteAPI.requests[4].resolve('OK');
452                 return MockRemoteAPI.waitForRequest();
453             }).then(() => {
454                 assert.equal(MockRemoteAPI.requests.length, 7);
455                 assert.equal(MockRemoteAPI.requests[5].method, 'GET');
456                 assert.equal(MockRemoteAPI.requests[5].url, '/json/builders/some-builder-1/pendingBuilds');
457                 MockRemoteAPI.requests[5].resolve([MockData.pendingBuild({buildRequestId: 702})]);
458                 assert.equal(MockRemoteAPI.requests[6].method, 'GET');
459                 assert.equal(MockRemoteAPI.requests[6].url, '/json/builders/some%20builder%202/pendingBuilds');
460                 MockRemoteAPI.requests[6].resolve([MockData.pendingBuild({builder: 'some builder 2', buildRequestId: 710})]);
461                 return MockRemoteAPI.waitForRequest();
462             }).then(() => {
463                 assert.equal(MockRemoteAPI.requests.length, 9);
464                 assert.equal(MockRemoteAPI.requests[7].method, 'GET');
465                 assert.equal(MockRemoteAPI.requests[7].url, '/json/builders/some-builder-1/builds/?select=-1&select=-2');
466                 MockRemoteAPI.requests[7].resolve({[-1]: MockData.runningBuild({buildRequestId: 701}), [-2]: MockData.finishedBuild({buildRequestId: 700})});
467                 assert.equal(MockRemoteAPI.requests[8].method, 'GET');
468                 assert.equal(MockRemoteAPI.requests[8].url, '/json/builders/some%20builder%202/builds/?select=-1&select=-2');
469                 MockRemoteAPI.requests[8].resolve({});
470                 return syncPromise;
471             }).then(() => {
472                 assert.equal(BuildRequest.all().length, 8);
473                 assert.equal(BuildRequest.findById(700).status(), 'completed');
474                 assert.equal(BuildRequest.findById(700).statusUrl(), null);
475                 assert.equal(BuildRequest.findById(701).status(), 'pending');
476                 assert.equal(BuildRequest.findById(701).statusUrl(), null);
477                 assert.equal(BuildRequest.findById(702).status(), 'pending');
478                 assert.equal(BuildRequest.findById(702).statusUrl(), null);
479                 assert.equal(BuildRequest.findById(703).status(), 'pending');
480                 assert.equal(BuildRequest.findById(703).statusUrl(), null);
481                 assert.equal(BuildRequest.findById(710).status(), 'pending');
482                 assert.equal(BuildRequest.findById(710).statusUrl(), null);
483                 assert.equal(BuildRequest.findById(711).status(), 'pending');
484                 assert.equal(BuildRequest.findById(711).statusUrl(), null);
485                 assert.equal(BuildRequest.findById(712).status(), 'pending');
486                 assert.equal(BuildRequest.findById(712).statusUrl(), null);
487                 assert.equal(BuildRequest.findById(713).status(), 'pending');
488                 assert.equal(BuildRequest.findById(713).statusUrl(), null);
489                 return BuildRequest.fetchForTriggerable(MockData.mockTestSyncConfigWithTwoBuilders().triggerableName);
490             }).then(() => {
491                 assert.equal(BuildRequest.all().length, 8);
492                 assert.equal(BuildRequest.findById(700).status(), 'completed');
493                 assert.equal(BuildRequest.findById(700).statusUrl(), 'http://build.webkit.org/builders/some-builder-1/builds/123');
494                 assert.equal(BuildRequest.findById(701).status(), 'running');
495                 assert.equal(BuildRequest.findById(701).statusUrl(), 'http://build.webkit.org/builders/some-builder-1/builds/124');
496                 assert.equal(BuildRequest.findById(702).status(), 'scheduled');
497                 assert.equal(BuildRequest.findById(702).statusUrl(), 'http://build.webkit.org/builders/some-builder-1/');
498                 assert.equal(BuildRequest.findById(703).status(), 'pending');
499                 assert.equal(BuildRequest.findById(703).statusUrl(), null);
500                 assert.equal(BuildRequest.findById(710).status(), 'scheduled');
501                 assert.equal(BuildRequest.findById(710).statusUrl(), 'http://build.webkit.org/builders/some%20builder%202/');
502                 assert.equal(BuildRequest.findById(711).status(), 'pending');
503                 assert.equal(BuildRequest.findById(711).statusUrl(), null);
504                 assert.equal(BuildRequest.findById(712).status(), 'pending');
505                 assert.equal(BuildRequest.findById(712).statusUrl(), null);
506                 assert.equal(BuildRequest.findById(713).status(), 'pending');
507                 assert.equal(BuildRequest.findById(713).statusUrl(), null);
508             });
509         });
510
511         it('should schedule a build request on the same scheduler the first request had ran', () => {
512             const db = TestServer.database();
513             let syncPromise;
514             return Promise.all([
515                 MockData.addMockData(db, ['running', 'pending', 'pending', 'pending']),
516                 MockData.addAnotherMockTestGroup(db, ['running', 'pending', 'pending', 'pending'])
517             ]).then(() => {
518                 return Manifest.fetch();
519             }).then(() => {
520                 const config = MockData.mockTestSyncConfigWithTwoBuilders();
521                 const logger = new MockLogger;
522                 const slaveInfo = {name: 'sync-slave', password: 'password'};
523                 const triggerable = new BuildbotTriggerable(config, TestServer.remoteAPI(), MockRemoteAPI, slaveInfo, logger);
524                 syncPromise = triggerable.syncOnce();
525                 return MockRemoteAPI.waitForRequest();
526             }).then(() => {
527                 assert.equal(MockRemoteAPI.requests.length, 2);
528                 assert.equal(MockRemoteAPI.requests[0].method, 'GET');
529                 assert.equal(MockRemoteAPI.requests[0].url, '/json/builders/some-builder-1/pendingBuilds');
530                 MockRemoteAPI.requests[0].resolve([]);
531                 assert.equal(MockRemoteAPI.requests[1].method, 'GET');
532                 assert.equal(MockRemoteAPI.requests[1].url, '/json/builders/some%20builder%202/pendingBuilds');
533                 MockRemoteAPI.requests[1].resolve([]);
534                 return MockRemoteAPI.waitForRequest();
535             }).then(() => {
536                 assert.equal(MockRemoteAPI.requests.length, 4);
537                 assert.equal(MockRemoteAPI.requests[2].method, 'GET');
538                 assert.equal(MockRemoteAPI.requests[2].url, '/json/builders/some-builder-1/builds/?select=-1&select=-2');
539                 MockRemoteAPI.requests[2].resolve({[-1]: MockData.runningBuild({buildRequestId: 710})});
540                 assert.equal(MockRemoteAPI.requests[3].method, 'GET');
541                 assert.equal(MockRemoteAPI.requests[3].url, '/json/builders/some%20builder%202/builds/?select=-1&select=-2');
542                 MockRemoteAPI.requests[3].resolve({[-1]: MockData.runningBuild({builder: 'some builder 2', buildRequestId: 700})});
543                 return MockRemoteAPI.waitForRequest();
544             }).then(() => {
545                 assert.equal(MockRemoteAPI.requests.length, 6);
546                 assert.equal(MockRemoteAPI.requests[4].method, 'POST');
547                 assert.equal(MockRemoteAPI.requests[4].url, '/builders/some%20builder%202/force');
548                 assert.deepEqual(MockRemoteAPI.requests[4].data, {'wk': '192736', 'os': '10.11 15A284', 'build-request-id': '701'});
549                 MockRemoteAPI.requests[4].resolve('OK');
550                 assert.equal(MockRemoteAPI.requests[5].method, 'POST');
551                 assert.equal(MockRemoteAPI.requests[5].url, '/builders/some-builder-1/force');
552                 assert.deepEqual(MockRemoteAPI.requests[5].data, {'wk': '192736', 'os': '10.11 15A284', 'build-request-id': '711'});
553                 MockRemoteAPI.requests[5].resolve('OK');
554                 return MockRemoteAPI.waitForRequest();
555             }).then(() => {
556                 assert.equal(MockRemoteAPI.requests.length, 8);
557                 assert.equal(MockRemoteAPI.requests[6].method, 'GET');
558                 assert.equal(MockRemoteAPI.requests[6].url, '/json/builders/some-builder-1/pendingBuilds');
559                 MockRemoteAPI.requests[6].resolve([MockData.pendingBuild({buildRequestId: 711})]);
560                 assert.equal(MockRemoteAPI.requests[7].method, 'GET');
561                 assert.equal(MockRemoteAPI.requests[7].url, '/json/builders/some%20builder%202/pendingBuilds');
562                 MockRemoteAPI.requests[7].resolve([MockData.pendingBuild({builder: 'some builder 2',buildRequestId: 701})]);
563                 return MockRemoteAPI.waitForRequest();
564             }).then(() => {
565                 assert.equal(MockRemoteAPI.requests.length, 10);
566                 assert.equal(MockRemoteAPI.requests[8].method, 'GET');
567                 assert.equal(MockRemoteAPI.requests[8].url, '/json/builders/some-builder-1/builds/?select=-1&select=-2');
568                 MockRemoteAPI.requests[8].resolve({[-1]: MockData.runningBuild({buildRequestId: 710})});
569                 assert.equal(MockRemoteAPI.requests[9].method, 'GET');
570                 assert.equal(MockRemoteAPI.requests[9].url, '/json/builders/some%20builder%202/builds/?select=-1&select=-2');
571                 MockRemoteAPI.requests[9].resolve({[-1]: MockData.runningBuild({builder: 'some builder 2', buildRequestId: 700})});
572                 return syncPromise;
573             }).then(() => {
574                 assert.equal(BuildRequest.all().length, 8);
575                 assert.equal(BuildRequest.findById(700).status(), 'running');
576                 assert.equal(BuildRequest.findById(700).statusUrl(), null);
577                 assert.equal(BuildRequest.findById(701).status(), 'pending');
578                 assert.equal(BuildRequest.findById(701).statusUrl(), null);
579                 assert.equal(BuildRequest.findById(702).status(), 'pending');
580                 assert.equal(BuildRequest.findById(702).statusUrl(), null);
581                 assert.equal(BuildRequest.findById(703).status(), 'pending');
582                 assert.equal(BuildRequest.findById(703).statusUrl(), null);
583                 assert.equal(BuildRequest.findById(710).status(), 'running');
584                 assert.equal(BuildRequest.findById(710).statusUrl(), null);
585                 assert.equal(BuildRequest.findById(711).status(), 'pending');
586                 assert.equal(BuildRequest.findById(711).statusUrl(), null);
587                 assert.equal(BuildRequest.findById(712).status(), 'pending');
588                 assert.equal(BuildRequest.findById(712).statusUrl(), null);
589                 assert.equal(BuildRequest.findById(713).status(), 'pending');
590                 assert.equal(BuildRequest.findById(713).statusUrl(), null);
591                 return BuildRequest.fetchForTriggerable(MockData.mockTestSyncConfigWithTwoBuilders().triggerableName);
592             }).then(() => {
593                 assert.equal(BuildRequest.all().length, 8);
594                 assert.equal(BuildRequest.findById(700).status(), 'running');
595                 assert.equal(BuildRequest.findById(700).statusUrl(), 'http://build.webkit.org/builders/some%20builder%202/builds/124');
596                 assert.equal(BuildRequest.findById(701).status(), 'scheduled');
597                 assert.equal(BuildRequest.findById(701).statusUrl(), 'http://build.webkit.org/builders/some%20builder%202/');
598                 assert.equal(BuildRequest.findById(702).status(), 'pending');
599                 assert.equal(BuildRequest.findById(702).statusUrl(), null);
600                 assert.equal(BuildRequest.findById(703).status(), 'pending');
601                 assert.equal(BuildRequest.findById(703).statusUrl(), null);
602                 assert.equal(BuildRequest.findById(710).status(), 'running');
603                 assert.equal(BuildRequest.findById(710).statusUrl(), 'http://build.webkit.org/builders/some-builder-1/builds/124');
604                 assert.equal(BuildRequest.findById(711).status(), 'scheduled');
605                 assert.equal(BuildRequest.findById(711).statusUrl(), 'http://build.webkit.org/builders/some-builder-1/');
606                 assert.equal(BuildRequest.findById(712).status(), 'pending');
607                 assert.equal(BuildRequest.findById(712).statusUrl(), null);
608                 assert.equal(BuildRequest.findById(713).status(), 'pending');
609                 assert.equal(BuildRequest.findById(713).statusUrl(), null);
610             });
611         });
612
613         it('should recover from multiple test groups running simultenously', () => {
614             const db = TestServer.database();
615             let syncPromise;
616             return Promise.all([
617                 MockData.addMockData(db, ['completed', 'pending', 'pending', 'pending']),
618                 MockData.addAnotherMockTestGroup(db, ['completed', 'pending', 'pending', 'pending'])
619             ]).then(() => {
620                 return Manifest.fetch();
621             }).then(() => {
622                 const config = MockData.mockTestSyncConfigWithSingleBuilder();
623                 const logger = new MockLogger;
624                 const slaveInfo = {name: 'sync-slave', password: 'password'};
625                 const triggerable = new BuildbotTriggerable(config, TestServer.remoteAPI(), MockRemoteAPI, slaveInfo, logger);
626                 syncPromise = triggerable.syncOnce();
627                 return MockRemoteAPI.waitForRequest();
628             }).then(() => {
629                 assert.equal(MockRemoteAPI.requests.length, 1);
630                 assert.equal(MockRemoteAPI.requests[0].method, 'GET');
631                 assert.equal(MockRemoteAPI.requests[0].url, '/json/builders/some-builder-1/pendingBuilds');
632                 MockRemoteAPI.requests[0].resolve([MockData.pendingBuild({buildRequestId: 711})]);
633                 return MockRemoteAPI.waitForRequest();
634             }).then(() => {
635                 assert.equal(MockRemoteAPI.requests.length, 2);
636                 assert.equal(MockRemoteAPI.requests[1].method, 'GET');
637                 assert.equal(MockRemoteAPI.requests[1].url, '/json/builders/some-builder-1/builds/?select=-1&select=-2');
638                 MockRemoteAPI.requests[1].resolve({[-1]: MockData.runningBuild({buildRequestId: 700}), [-2]: MockData.finishedBuild({buildRequestId: 710})});
639                 return MockRemoteAPI.waitForRequest();
640             }).then(() => {
641                 assert.equal(MockRemoteAPI.requests.length, 3);
642                 assert.equal(MockRemoteAPI.requests[2].method, 'GET');
643                 assert.equal(MockRemoteAPI.requests[2].url, '/json/builders/some-builder-1/pendingBuilds');
644                 MockRemoteAPI.requests[2].resolve([MockData.pendingBuild({buildRequestId: 701})]);
645                 return MockRemoteAPI.waitForRequest();
646             }).then(() => {
647                 assert.equal(MockRemoteAPI.requests.length, 4);
648                 assert.equal(MockRemoteAPI.requests[3].method, 'GET');
649                 assert.equal(MockRemoteAPI.requests[3].url, '/json/builders/some-builder-1/builds/?select=-1&select=-2');
650                 MockRemoteAPI.requests[3].resolve({[-1]: MockData.runningBuild({buildRequestId: 700}), [-2]: MockData.finishedBuild({buildRequestId: 710})});
651                 return syncPromise;
652             }).then(() => {
653                 assert.equal(BuildRequest.all().length, 8);
654                 assert.equal(BuildRequest.findById(700).status(), 'completed');
655                 assert.equal(BuildRequest.findById(700).statusUrl(), null);
656                 assert.equal(BuildRequest.findById(701).status(), 'pending');
657                 assert.equal(BuildRequest.findById(701).statusUrl(), null);
658                 assert.equal(BuildRequest.findById(702).status(), 'pending');
659                 assert.equal(BuildRequest.findById(702).statusUrl(), null);
660                 assert.equal(BuildRequest.findById(703).status(), 'pending');
661                 assert.equal(BuildRequest.findById(703).statusUrl(), null);
662                 assert.equal(BuildRequest.findById(710).status(), 'completed');
663                 assert.equal(BuildRequest.findById(710).statusUrl(), null);
664                 assert.equal(BuildRequest.findById(711).status(), 'pending');
665                 assert.equal(BuildRequest.findById(711).statusUrl(), null);
666                 assert.equal(BuildRequest.findById(712).status(), 'pending');
667                 assert.equal(BuildRequest.findById(712).statusUrl(), null);
668                 assert.equal(BuildRequest.findById(713).status(), 'pending');
669                 assert.equal(BuildRequest.findById(713).statusUrl(), null);
670                 return BuildRequest.fetchForTriggerable(MockData.mockTestSyncConfigWithTwoBuilders().triggerableName);
671             }).then(() => {
672                 assert.equal(BuildRequest.all().length, 8);
673                 assert.equal(BuildRequest.findById(700).status(), 'completed');
674                 assert.equal(BuildRequest.findById(700).statusUrl(), 'http://build.webkit.org/builders/some-builder-1/builds/124');
675                 assert.equal(BuildRequest.findById(701).status(), 'scheduled');
676                 assert.equal(BuildRequest.findById(701).statusUrl(), 'http://build.webkit.org/builders/some-builder-1/');
677                 assert.equal(BuildRequest.findById(702).status(), 'pending');
678                 assert.equal(BuildRequest.findById(702).statusUrl(), null);
679                 assert.equal(BuildRequest.findById(703).status(), 'pending');
680                 assert.equal(BuildRequest.findById(703).statusUrl(), null);
681                 assert.equal(BuildRequest.findById(710).status(), 'completed');
682                 assert.equal(BuildRequest.findById(710).statusUrl(), 'http://build.webkit.org/builders/some-builder-1/builds/123');
683                 assert.equal(BuildRequest.findById(711).status(), 'pending');
684                 assert.equal(BuildRequest.findById(711).statusUrl(), null);
685                 assert.equal(BuildRequest.findById(712).status(), 'pending');
686                 assert.equal(BuildRequest.findById(712).statusUrl(), null);
687                 assert.equal(BuildRequest.findById(713).status(), 'pending');
688                 assert.equal(BuildRequest.findById(713).statusUrl(), null);
689             });
690         });
691
692         it('should recover from missing failed build request', () => {
693             const db = TestServer.database();
694             let syncPromise;
695             return MockData.addMockData(db, ['failed', 'pending', 'pending', 'pending']).then(() => {
696                 return Manifest.fetch();
697             }).then(() => {
698                 const config = MockData.mockTestSyncConfigWithSingleBuilder();
699                 const logger = new MockLogger;
700                 const slaveInfo = {name: 'sync-slave', password: 'password'};
701                 const triggerable = new BuildbotTriggerable(config, TestServer.remoteAPI(), MockRemoteAPI, slaveInfo, logger);
702                 syncPromise = triggerable.syncOnce();
703                 return MockRemoteAPI.waitForRequest();
704             }).then(() => {
705                 assert.equal(MockRemoteAPI.requests.length, 1);
706                 assert.equal(MockRemoteAPI.requests[0].method, 'GET');
707                 assert.equal(MockRemoteAPI.requests[0].url, '/json/builders/some-builder-1/pendingBuilds');
708                 MockRemoteAPI.requests[0].resolve([]);
709                 return MockRemoteAPI.waitForRequest();
710             }).then(() => {
711                 assert.equal(MockRemoteAPI.requests.length, 2);
712                 assert.equal(MockRemoteAPI.requests[1].method, 'GET');
713                 assert.equal(MockRemoteAPI.requests[1].url, '/json/builders/some-builder-1/builds/?select=-1&select=-2');
714                 MockRemoteAPI.requests[1].resolve({});
715                 return MockRemoteAPI.waitForRequest();
716             }).then(() => {
717                 assert.equal(MockRemoteAPI.requests.length, 3);
718                 assert.equal(MockRemoteAPI.requests[2].method, 'POST');
719                 assert.equal(MockRemoteAPI.requests[2].url, '/builders/some-builder-1/force');
720                 assert.deepEqual(MockRemoteAPI.requests[2].data, {'wk': '192736', 'os': '10.11 15A284', 'build-request-id': '701'});
721                 MockRemoteAPI.requests[2].resolve('OK');
722                 return MockRemoteAPI.waitForRequest();
723             }).then(() => {
724                 assert.equal(MockRemoteAPI.requests.length, 4);
725                 assert.equal(MockRemoteAPI.requests[3].method, 'GET');
726                 assert.equal(MockRemoteAPI.requests[3].url, '/json/builders/some-builder-1/pendingBuilds');
727                 MockRemoteAPI.requests[3].resolve([MockData.pendingBuild({buildRequestId: 701})]);
728                 return MockRemoteAPI.waitForRequest();
729             }).then(() => {
730                 assert.equal(MockRemoteAPI.requests.length, 5);
731                 assert.equal(MockRemoteAPI.requests[4].method, 'GET');
732                 assert.equal(MockRemoteAPI.requests[4].url, '/json/builders/some-builder-1/builds/?select=-1&select=-2');
733                 MockRemoteAPI.requests[4].resolve({});
734                 return syncPromise;
735             }).then(() => {
736                 assert.equal(BuildRequest.all().length, 4);
737                 assert.equal(BuildRequest.findById(700).status(), 'failed');
738                 assert.equal(BuildRequest.findById(700).statusUrl(), null);
739                 assert.equal(BuildRequest.findById(701).status(), 'pending');
740                 assert.equal(BuildRequest.findById(701).statusUrl(), null);
741                 assert.equal(BuildRequest.findById(702).status(), 'pending');
742                 assert.equal(BuildRequest.findById(702).statusUrl(), null);
743                 assert.equal(BuildRequest.findById(703).status(), 'pending');
744                 assert.equal(BuildRequest.findById(703).statusUrl(), null);
745                 return BuildRequest.fetchForTriggerable(MockData.mockTestSyncConfigWithTwoBuilders().triggerableName);
746             }).then(() => {
747                 assert.equal(BuildRequest.all().length, 4);
748                 assert.equal(BuildRequest.findById(700).status(), 'failed');
749                 assert.equal(BuildRequest.findById(700).statusUrl(), null);
750                 assert.equal(BuildRequest.findById(701).status(), 'scheduled');
751                 assert.equal(BuildRequest.findById(701).statusUrl(), 'http://build.webkit.org/builders/some-builder-1/');
752                 assert.equal(BuildRequest.findById(702).status(), 'pending');
753                 assert.equal(BuildRequest.findById(702).statusUrl(), null);
754                 assert.equal(BuildRequest.findById(703).status(), 'pending');
755                 assert.equal(BuildRequest.findById(703).statusUrl(), null);
756             });
757         });
758
759         it('should update the status of a supposedly scheduled build that went missing', () => {
760             const db = TestServer.database();
761             let syncPromise;
762             return MockData.addMockData(db, ['scheduled', 'pending', 'pending', 'pending']).then(() => {
763                 return Manifest.fetch();
764             }).then(() => {
765                 const config = MockData.mockTestSyncConfigWithSingleBuilder();
766                 const logger = new MockLogger;
767                 const slaveInfo = {name: 'sync-slave', password: 'password'};
768                 const triggerable = new BuildbotTriggerable(config, TestServer.remoteAPI(), MockRemoteAPI, slaveInfo, logger);
769                 syncPromise = triggerable.syncOnce();
770                 return MockRemoteAPI.waitForRequest();
771             }).then(() => {
772                 assert.equal(MockRemoteAPI.requests.length, 1);
773                 assert.equal(MockRemoteAPI.requests[0].method, 'GET');
774                 assert.equal(MockRemoteAPI.requests[0].url, '/json/builders/some-builder-1/pendingBuilds');
775                 MockRemoteAPI.requests[0].resolve([]);
776                 return MockRemoteAPI.waitForRequest();
777             }).then(() => {
778                 assert.equal(MockRemoteAPI.requests.length, 2);
779                 assert.equal(MockRemoteAPI.requests[1].method, 'GET');
780                 assert.equal(MockRemoteAPI.requests[1].url, '/json/builders/some-builder-1/builds/?select=-1&select=-2');
781                 MockRemoteAPI.requests[1].resolve({});
782                 return MockRemoteAPI.waitForRequest();
783             }).then(() => {
784                 assert.equal(MockRemoteAPI.requests.length, 3);
785                 assert.equal(MockRemoteAPI.requests[2].method, 'GET');
786                 assert.equal(MockRemoteAPI.requests[2].url, '/json/builders/some-builder-1/pendingBuilds');
787                 MockRemoteAPI.requests[2].resolve([]);
788                 return MockRemoteAPI.waitForRequest();
789             }).then(() => {
790                 assert.equal(MockRemoteAPI.requests.length, 4);
791                 assert.equal(MockRemoteAPI.requests[3].method, 'GET');
792                 assert.equal(MockRemoteAPI.requests[3].url, '/json/builders/some-builder-1/builds/?select=-1&select=-2');
793                 MockRemoteAPI.requests[3].resolve({});
794                 return syncPromise;
795             }).then(() => {
796                 assert.equal(BuildRequest.all().length, 4);
797                 assert.equal(BuildRequest.findById(700).status(), 'scheduled');
798                 assert.equal(BuildRequest.findById(701).status(), 'pending');
799                 assert.equal(BuildRequest.findById(702).status(), 'pending');
800                 assert.equal(BuildRequest.findById(703).status(), 'pending');
801                 return BuildRequest.fetchForTriggerable(MockData.mockTestSyncConfigWithTwoBuilders().triggerableName);
802             }).then(() => {
803                 assert.equal(BuildRequest.all().length, 4);
804                 assert.equal(BuildRequest.findById(700).status(), 'failed');
805                 assert.equal(BuildRequest.findById(701).status(), 'pending');
806                 assert.equal(BuildRequest.findById(702).status(), 'pending');
807                 assert.equal(BuildRequest.findById(703).status(), 'pending');
808             });
809         });
810
811         it('should schedule a build request of an user created test group before ones created by automatic change detection', () => {
812             const db = TestServer.database();
813             let syncPromise;
814             return Promise.all([
815                 MockData.addMockData(db, ['pending', 'pending', 'pending', 'pending']),
816                 MockData.addAnotherMockTestGroup(db, ['pending', 'pending', 'pending', 'pending'], 'rniwa'),
817             ]).then(() => {
818                 return Manifest.fetch();
819             }).then(() => {
820                 const config = MockData.mockTestSyncConfigWithSingleBuilder();
821                 const logger = new MockLogger;
822                 const slaveInfo = {name: 'sync-slave', password: 'password'};
823                 const triggerable = new BuildbotTriggerable(config, TestServer.remoteAPI(), MockRemoteAPI, slaveInfo, logger);
824                 syncPromise = triggerable.syncOnce();
825                 return MockRemoteAPI.waitForRequest();
826             }).then(() => {
827                 assert.equal(MockRemoteAPI.requests.length, 1);
828                 assert.equal(MockRemoteAPI.requests[0].method, 'GET');
829                 assert.equal(MockRemoteAPI.requests[0].url, '/json/builders/some-builder-1/pendingBuilds');
830                 MockRemoteAPI.requests[0].resolve([]);
831                 return MockRemoteAPI.waitForRequest();
832             }).then(() => {
833                 assert.equal(MockRemoteAPI.requests.length, 2);
834                 assert.equal(MockRemoteAPI.requests[1].method, 'GET');
835                 assert.equal(MockRemoteAPI.requests[1].url, '/json/builders/some-builder-1/builds/?select=-1&select=-2');
836                 MockRemoteAPI.requests[1].resolve({});
837                 return MockRemoteAPI.waitForRequest();
838             }).then(() => {
839                 assert.equal(MockRemoteAPI.requests.length, 3);
840                 assert.equal(MockRemoteAPI.requests[2].method, 'POST');
841                 assert.equal(MockRemoteAPI.requests[2].url, '/builders/some-builder-1/force');
842                 assert.deepEqual(MockRemoteAPI.requests[2].data, {'wk': '191622', 'os': '10.11 15A284', 'build-request-id': '710'});
843                 MockRemoteAPI.requests[2].resolve('OK');
844             });
845         });
846     });
847
848     describe('updateTriggerables', () => {
849         it('should update available triggerables', () => {
850             const db = TestServer.database();
851             return MockData.addMockData(db).then(() => {
852                 return Manifest.fetch();
853             }).then(() => {
854                 return db.selectAll('triggerable_configurations', 'test');
855             }).then((configurations) => {
856                 assert.equal(configurations.length, 0);
857                 assert.equal(Triggerable.all().length, 1);
858
859                 let triggerable = Triggerable.all()[0];
860                 assert.equal(triggerable.name(), 'build-webkit');
861                 assert.deepEqual(triggerable.acceptedRepositories(), []);
862
863                 let test = Test.findById(MockData.someTestId());
864                 let platform = Platform.findById(MockData.somePlatformId());
865                 assert.equal(Triggerable.findByTestConfiguration(test, platform), null);
866
867                 let config = MockData.mockTestSyncConfigWithSingleBuilder();
868                 let logger = new MockLogger;
869                 let slaveInfo = {name: 'sync-slave', password: 'password'};
870                 let buildbotTriggerable = new BuildbotTriggerable(config, TestServer.remoteAPI(), MockRemoteAPI, slaveInfo, logger);
871                 return buildbotTriggerable.updateTriggerable();
872             }).then(() => {
873                 MockData.resetV3Models();
874                 assert.equal(Triggerable.all().length, 0);
875                 return TestServer.remoteAPI().getJSON('/api/manifest');
876             }).then((manifestContent) => {
877                 Manifest._didFetchManifest(manifestContent);
878                 return db.selectAll('triggerable_configurations', 'test');
879             }).then((configurations) => {
880                 assert.equal(configurations.length, 1);
881                 assert.equal(configurations[0].test, MockData.someTestId());
882                 assert.equal(configurations[0].platform, MockData.somePlatformId());
883
884                 assert.equal(Triggerable.all().length, 1);
885
886                 let test = Test.findById(MockData.someTestId());
887                 let platform = Platform.findById(MockData.somePlatformId());
888                 let triggerable = Triggerable.findByTestConfiguration(test, platform);
889                 assert.equal(triggerable.name(), 'build-webkit');
890             });
891         });
892     });
893
894 });