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