Escape builder names in url* and pathFor* methods of BuildbotSyncer
[WebKit-https.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 update the status of a supposedly scheduled build that went missing', function (done) {
549             let db = TestServer.database();
550             let syncPromise;
551             db.connect().then(function () {
552                 return MockData.addMockData(db, ['scheduled', 'pending', 'pending', 'pending']);
553             }).then(function () {
554                 return Manifest.fetch();
555             }).then(function () {
556                 let config = MockData.mockTestSyncConfigWithSingleBuilder();
557                 let logger = new MockLogger;
558                 let slaveInfo = {name: 'sync-slave', password: 'password'};
559                 let triggerable = new BuildbotTriggerable(config, TestServer.remoteAPI(), MockRemoteAPI, slaveInfo, logger);
560                 syncPromise = triggerable.syncOnce();
561                 syncPromise.catch(done);
562                 return MockRemoteAPI.waitForRequest();
563             }).then(function () {
564                 assert.equal(MockRemoteAPI.requests.length, 1);
565                 assert.equal(MockRemoteAPI.requests[0].method, 'GET');
566                 assert.equal(MockRemoteAPI.requests[0].url, '/json/builders/some-builder-1/pendingBuilds');
567                 MockRemoteAPI.requests[0].resolve([]);
568                 return MockRemoteAPI.waitForRequest();
569             }).then(function () {
570                 assert.equal(MockRemoteAPI.requests.length, 2);
571                 assert.equal(MockRemoteAPI.requests[1].method, 'GET');
572                 assert.equal(MockRemoteAPI.requests[1].url, '/json/builders/some-builder-1/builds/?select=-1&select=-2');
573                 MockRemoteAPI.requests[1].resolve({});
574                 return MockRemoteAPI.waitForRequest();
575             }).then(function () {
576                 assert.equal(MockRemoteAPI.requests.length, 3);
577                 assert.equal(MockRemoteAPI.requests[2].method, 'GET');
578                 assert.equal(MockRemoteAPI.requests[2].url, '/json/builders/some-builder-1/pendingBuilds');
579                 MockRemoteAPI.requests[2].resolve([]);
580                 return MockRemoteAPI.waitForRequest();
581             }).then(function () {
582                 assert.equal(MockRemoteAPI.requests.length, 4);
583                 assert.equal(MockRemoteAPI.requests[3].method, 'GET');
584                 assert.equal(MockRemoteAPI.requests[3].url, '/json/builders/some-builder-1/builds/?select=-1&select=-2');
585                 MockRemoteAPI.requests[3].resolve({});
586                 return syncPromise;
587             }).then(function () {
588                 assert.equal(BuildRequest.all().length, 4);
589                 assert.equal(BuildRequest.findById(700).status(), 'scheduled');
590                 assert.equal(BuildRequest.findById(701).status(), 'pending');
591                 assert.equal(BuildRequest.findById(702).status(), 'pending');
592                 assert.equal(BuildRequest.findById(703).status(), 'pending');
593                 return BuildRequest.fetchForTriggerable(MockData.mockTestSyncConfigWithTwoBuilders().triggerableName);
594             }).then(function () {
595                 assert.equal(BuildRequest.all().length, 4);
596                 assert.equal(BuildRequest.findById(700).status(), 'failed');
597                 assert.equal(BuildRequest.findById(701).status(), 'pending');
598                 assert.equal(BuildRequest.findById(702).status(), 'pending');
599                 assert.equal(BuildRequest.findById(703).status(), 'pending');
600                 done();
601             }).catch(done);
602         });
603
604         it('should schedule a build request of an user created test group before ones created by automatic change detection', function (done) {
605             let db = TestServer.database();
606             let syncPromise;
607             db.connect().then(function () {
608                 return Promise.all([
609                     MockData.addMockData(db, ['pending', 'pending', 'pending', 'pending']),
610                     MockData.addAnotherMockTestGroup(db, ['pending', 'pending', 'pending', 'pending'], 'rniwa'),
611                 ]);
612             }).then(function () {
613                 return Manifest.fetch();
614             }).then(function () {
615                 let config = MockData.mockTestSyncConfigWithSingleBuilder();
616                 let logger = new MockLogger;
617                 let slaveInfo = {name: 'sync-slave', password: 'password'};
618                 let triggerable = new BuildbotTriggerable(config, TestServer.remoteAPI(), MockRemoteAPI, slaveInfo, logger);
619                 syncPromise = triggerable.syncOnce();
620                 syncPromise.catch(done);
621                 return MockRemoteAPI.waitForRequest();
622             }).then(function () {
623                 assert.equal(MockRemoteAPI.requests.length, 1);
624                 assert.equal(MockRemoteAPI.requests[0].method, 'GET');
625                 assert.equal(MockRemoteAPI.requests[0].url, '/json/builders/some-builder-1/pendingBuilds');
626                 MockRemoteAPI.requests[0].resolve([]);
627                 return MockRemoteAPI.waitForRequest();
628             }).then(function () {
629                 assert.equal(MockRemoteAPI.requests.length, 2);
630                 assert.equal(MockRemoteAPI.requests[1].method, 'GET');
631                 assert.equal(MockRemoteAPI.requests[1].url, '/json/builders/some-builder-1/builds/?select=-1&select=-2');
632                 MockRemoteAPI.requests[1].resolve({});
633                 return MockRemoteAPI.waitForRequest();
634             }).then(function () {
635                 assert.equal(MockRemoteAPI.requests.length, 3);
636                 assert.equal(MockRemoteAPI.requests[2].method, 'POST');
637                 assert.equal(MockRemoteAPI.requests[2].url, '/builders/some-builder-1/force');
638                 assert.deepEqual(MockRemoteAPI.requests[2].data, {'wk': '191622', 'os': '10.11 15A284', 'build-request-id': '710'});
639                 MockRemoteAPI.requests[2].resolve('OK');
640                 done();
641             }).catch(done);
642         });
643     });
644 });