Don't shouldn't create a request to build a patch if there is no patch to build
[WebKit-https.git] / Websites / perf.webkit.org / server-tests / privileged-api-create-test-group-tests.js
1 'use strict';
2
3 const assert = require('assert');
4
5 const MockData = require('./resources/mock-data.js');
6 const TestServer = require('./resources/test-server.js');
7 const TemporaryFile = require('./resources/temporary-file.js').TemporaryFile;
8 const addSlaveForReport = require('./resources/common-operations.js').addSlaveForReport;
9 const prepareServerTest = require('./resources/common-operations.js').prepareServerTest;
10
11 function createAnalysisTask(name)
12 {
13     const reportWithRevision = [{
14         "buildNumber": "124",
15         "buildTime": "2015-10-27T15:34:51",
16         "revisions": {
17             "WebKit": {
18                 "revision": "191622",
19                 "timestamp": '2015-10-27T11:36:56.878473Z',
20             },
21             "macOS": {
22                 "revision": "15A284",
23             }
24         },
25         "builderName": "someBuilder",
26         "slaveName": "someSlave",
27         "slavePassword": "somePassword",
28         "platform": "some platform",
29         "tests": {
30             "some test": {
31                 "metrics": {
32                     "Time": ["Arithmetic"],
33                 },
34                 "tests": {
35                     "test1": {
36                         "metrics": {"Time": { "current": [11] }},
37                     }
38                 }
39             },
40         }}];
41
42     const anotherReportWithRevision = [{
43         "buildNumber": "125",
44         "buildTime": "2015-10-27T17:27:41",
45         "revisions": {
46             "WebKit": {
47                 "revision": "191623",
48                 "timestamp": '2015-10-27T16:38:10.768995Z',
49             },
50             "macOS": {
51                 "revision": "15A284",
52             }
53         },
54         "builderName": "someBuilder",
55         "slaveName": "someSlave",
56         "slavePassword": "somePassword",
57         "platform": "some platform",
58         "tests": {
59             "some test": {
60                 "metrics": {
61                     "Time": ["Arithmetic"],
62                 },
63                 "tests": {
64                     "test1": {
65                         "metrics": {"Time": { "current": [12] }},
66                     }
67                 }
68             },
69         }}];
70
71     const db = TestServer.database();
72     const remote = TestServer.remoteAPI();
73     return addSlaveForReport(reportWithRevision[0]).then(() => {
74         return remote.postJSON('/api/report/', reportWithRevision);
75     }).then(() => {
76         return remote.postJSON('/api/report/', anotherReportWithRevision);
77     }).then((result) => {
78         return Manifest.fetch();
79     }).then(() => {
80         const test = Test.findByPath(['some test', 'test1']);
81         const platform = Platform.findByName('some platform');
82         return db.selectFirstRow('test_configurations', {metric: test.metrics()[0].id(), platform: platform.id()});
83     }).then((configRow) => {
84         return db.selectRows('test_runs', {config: configRow['id']});
85     }).then((testRuns) => {
86         assert.equal(testRuns.length, 2);
87         return PrivilegedAPI.sendRequest('create-analysis-task', {
88             name: name,
89             startRun: testRuns[0]['id'],
90             endRun: testRuns[1]['id'],
91         });
92     }).then((content) => content['taskId']);
93 }
94
95 function addTriggerableAndCreateTask(name)
96 {
97     const report = {
98         'slaveName': 'anotherSlave',
99         'slavePassword': 'anotherPassword',
100         'triggerable': 'build-webkit',
101         'configurations': [
102             {test: MockData.someTestId(), platform: MockData.somePlatformId()},
103             {test: MockData.someTestId(), platform: MockData.otherPlatformId()},
104         ],
105         'repositoryGroups': [
106             {name: 'os-only', acceptsRoot: true, repositories: [
107                 {repository: MockData.macosRepositoryId(), acceptsPatch: false},
108             ]},
109             {name: 'webkit-only', acceptsRoot: true, repositories: [
110                 {repository: MockData.webkitRepositoryId(), acceptsPatch: true},
111             ]},
112             {name: 'system-and-webkit', acceptsRoot: true, repositories: [
113                 {repository: MockData.macosRepositoryId(), acceptsPatch: false},
114                 {repository: MockData.webkitRepositoryId(), acceptsPatch: true}
115             ]},
116         ]
117     };
118     return MockData.addMockData(TestServer.database()).then(() => {
119         return addSlaveForReport(report);
120     }).then(() => {
121         return TestServer.remoteAPI().postJSON('/api/update-triggerable/', report);
122     }).then(() => {
123         return createAnalysisTask(name);
124     });
125 }
126
127 describe('/privileged-api/create-test-group', function () {
128     prepareServerTest(this);
129     TemporaryFile.inject();
130
131     it('should return "InvalidName" on an empty request', () => {
132         return PrivilegedAPI.sendRequest('create-test-group', {}).then((content) => {
133             assert(false, 'should never be reached');
134         }, (error) => {
135             assert.equal(error, 'InvalidName');
136         });
137     });
138
139     it('should return "InvalidTask" when task is not specified', () => {
140         return PrivilegedAPI.sendRequest('create-test-group', {name: 'test', commitSets: [[1]]}).then((content) => {
141             assert(false, 'should never be reached');
142         }, (error) => {
143             assert.equal(error, 'InvalidTask');
144         });
145     });
146
147     it('should return "InvalidTask" when task is not a valid integer', () => {
148         return PrivilegedAPI.sendRequest('create-test-group', {name: 'test', task: 'foo', commitSets: [[1]]}).then((content) => {
149             assert(false, 'should never be reached');
150         }, (error) => {
151             assert.equal(error, 'InvalidTask');
152         });
153     });
154
155     it('should return "InvalidCommitSets" when commit sets are not specified', () => {
156         return PrivilegedAPI.sendRequest('create-test-group', {name: 'test', task: 1, repetitionCount: 1}).then((content) => {
157             assert(false, 'should never be reached');
158         }, (error) => {
159             assert.equal(error, 'InvalidCommitSets');
160         });
161     });
162
163     it('should return "InvalidCommitSets" when commit sets is empty', () => {
164         return PrivilegedAPI.sendRequest('create-test-group', {name: 'test', task: 1, repetitionCount: 1, commitSets: {}}).then((content) => {
165             assert(false, 'should never be reached');
166         }, (error) => {
167             assert.equal(error, 'InvalidCommitSets');
168         });
169     });
170
171     it('should return "InvalidTask" when there is no matching task', () => {
172         return PrivilegedAPI.sendRequest('create-test-group', {name: 'test', task: 1, repetitionCount: 1, commitSets: {'WebKit': []}}).then((content) => {
173             assert(false, 'should never be reached');
174         }, (error) => {
175             assert.equal(error, 'InvalidTask');
176         });
177     });
178
179     it('should return "InvalidRepetitionCount" when repetitionCount is not a valid integer', () => {
180         return PrivilegedAPI.sendRequest('create-test-group', {name: 'test', task: 1, repetitionCount: 'foo', commitSets: {'WebKit': []}}).then((content) => {
181             assert(false, 'should never be reached');
182         }, (error) => {
183             assert.equal(error, 'InvalidRepetitionCount');
184         });
185     });
186
187     it('should return "InvalidRepetitionCount" when repetitionCount is a negative integer', () => {
188         return PrivilegedAPI.sendRequest('create-test-group', {name: 'test', task: 1, repetitionCount: -5, commitSets: {'WebKit': []}}).then((content) => {
189             assert(false, 'should never be reached');
190         }, (error) => {
191             assert.equal(error, 'InvalidRepetitionCount');
192         });
193     });
194
195     it('should return "InvalidTask" when there is no matching task', () => {
196         return PrivilegedAPI.sendRequest('create-test-group', {name: 'test', task: 1, commitSets: {'WebKit': []}}).then((content) => {
197             assert(false, 'should never be reached');
198         }, (error) => {
199             assert.equal(error, 'InvalidTask');
200         });
201     });
202
203     it('should return "TriggerableNotFoundForTask" when there is no matching triggerable', () => {
204         return createAnalysisTask('some task').then((taskId) => {
205             return PrivilegedAPI.sendRequest('create-test-group', {name: 'test', task: taskId, commitSets: {'WebKit': []}}).then((content) => {
206                 assert(false, 'should never be reached');
207             }, (error) => {
208                 assert.equal(error, 'TriggerableNotFoundForTask');
209             });
210         });
211     });
212
213     it('should return "InvalidCommitSets" when each repository specifies zero revisions', () => {
214         return addTriggerableAndCreateTask('some task').then((taskId) => {
215             return PrivilegedAPI.sendRequest('create-test-group', {name: 'test', task: taskId, commitSets: {'WebKit': []}}).then((content) => {
216                 assert(false, 'should never be reached');
217             }, (error) => {
218                 assert.equal(error, 'InvalidCommitSets');
219             });
220         });
221     });
222
223     it('should return "InvalidRevisionSets" when a revision set is empty', () => {
224         return addTriggerableAndCreateTask('some task').then((taskId) => {
225             const webkit = Repository.all().find((repository) => repository.name() == 'WebKit');
226             return PrivilegedAPI.sendRequest('create-test-group', {name: 'test', task: taskId, revisionSets: [{[webkit.id()]: {revision: '191622'}}, {}]}).then((content) => {
227                 assert(false, 'should never be reached');
228             }, (error) => {
229                 assert.equal(error, 'InvalidRevisionSets');
230             });
231         });
232     });
233
234     it('should return "InvalidRevisionSets" when the number of revision sets is less than two', () => {
235         return addTriggerableAndCreateTask('some task').then((taskId) => {
236             const webkit = Repository.all().find((repository) => repository.name() == 'WebKit');
237             return PrivilegedAPI.sendRequest('create-test-group', {name: 'test', task: taskId, revisionSets: [{[webkit.id()]: {revision: '191622'}}]}).then((content) => {
238                 assert(false, 'should never be reached');
239             }, (error) => {
240                 assert.equal(error, 'InvalidRevisionSets');
241             });
242         });
243     });
244
245     it('should return "RepositoryNotFound" when commit sets contains an invalid repository', () => {
246         return addTriggerableAndCreateTask('some task').then((taskId) => {
247             return PrivilegedAPI.sendRequest('create-test-group', {name: 'test', task: taskId, commitSets: {'Foo': []}}).then((content) => {
248                 assert(false, 'should never be reached');
249             }, (error) => {
250                 assert.equal(error, 'RepositoryNotFound');
251             });
252         });
253     });
254
255     it('should return "RevisionNotFound" when commit sets contains an invalid revision', () => {
256         return addTriggerableAndCreateTask('some task').then((taskId) => {
257             return PrivilegedAPI.sendRequest('create-test-group', {name: 'test', task: taskId, commitSets: {'WebKit': ['1']}}).then((content) => {
258                 assert(false, 'should never be reached');
259             }, (error) => {
260                 assert.equal(error, 'RevisionNotFound');
261             });
262         });
263     });
264
265     it('should return "RevisionNotFound" when revision sets contains an invalid revision', () => {
266         return addTriggerableAndCreateTask('some task').then((taskId) => {
267             const webkit = Repository.all().find((repository) => repository.name() == 'WebKit');
268             const revisionSets = [{[webkit.id()]: {revision: '191622'}}, {[webkit.id()]: {revision: '1'}}];
269             return PrivilegedAPI.sendRequest('create-test-group', {name: 'test', task: taskId, revisionSets}).then((content) => {
270                 assert(false, 'should never be reached');
271             }, (error) => {
272                 assert.equal(error, 'RevisionNotFound');
273             });
274         });
275     });
276
277     it('should return "InvalidUploadedFile" when revision sets contains an invalid file ID', () => {
278         return addTriggerableAndCreateTask('some task').then((taskId) => {
279             const webkit = Repository.all().find((repository) => repository.name() == 'WebKit');
280             const revisionSets = [{[webkit.id()]: {revision: '191622'}, 'customRoots': ['1']}, {[webkit.id()]: {revision: '1'}}];
281             return PrivilegedAPI.sendRequest('create-test-group', {name: 'test', task: taskId, revisionSets}).then((content) => {
282                 assert(false, 'should never be reached');
283             }, (error) => {
284                 assert.equal(error, 'InvalidUploadedFile');
285             });
286         });
287     });
288
289     it('should return "InvalidRepository" when a revision set uses a repository name instead of a repository id', () => {
290         return addTriggerableAndCreateTask('some task').then((taskId) => {
291             const revisionSets = [{'WebKit': {revision: '191622'}}, {}];
292             return PrivilegedAPI.sendRequest('create-test-group', {name: 'test', task: taskId, revisionSets}).then((content) => {
293                 assert(false, 'should never be reached');
294             }, (error) => {
295                 assert.equal(error, 'InvalidRepository');
296             });
297         });
298     });
299
300     it('should return "InvalidCommitSets" when commit sets contains an inconsistent number of revisions', () => {
301         return addTriggerableAndCreateTask('some task').then((taskId) => {
302             return PrivilegedAPI.sendRequest('create-test-group', {name: 'test', task: taskId, commitSets: {'WebKit': ['191622', '191623'], 'macOS': ['15A284']}}).then((content) => {
303                 assert(false, 'should never be reached');
304             }, (error) => {
305                 assert.equal(error, 'InvalidCommitSets');
306             });
307         });
308     });
309
310     it('should return "DuplicateTestGroupName" when there is already a test group of the same name', () => {
311         return addTriggerableAndCreateTask('some task').then((taskId) => {
312             const commitSets = {'WebKit': ['191622', '191623']};
313             return PrivilegedAPI.sendRequest('create-test-group', {name: 'test', task: taskId, commitSets}).then((content) => {
314                 assert(content['testGroupId']);
315                 return PrivilegedAPI.sendRequest('create-test-group', {name: 'test', task: taskId, commitSets});
316             }).then(() => {
317                 assert(false, 'should never be reached');
318             }, (error) => {
319                 assert.equal(error, 'DuplicateTestGroupName');
320             });
321         });
322     });
323
324     it('should create a test group from commitSets with the repetition count of one when repetitionCount is omitted', () => {
325         return addTriggerableAndCreateTask('some task').then((taskId) => {
326             let insertedGroupId;
327             return PrivilegedAPI.sendRequest('create-test-group', {name: 'test', task: taskId, commitSets: {'macOS': ['15A284', '15A284'], 'WebKit': ['191622', '191623']}}).then((content) => {
328                 insertedGroupId = content['testGroupId'];
329                 return TestGroup.fetchForTask(taskId, true);
330             }).then((testGroups) => {
331                 assert.equal(testGroups.length, 1);
332                 const group = testGroups[0];
333                 assert.equal(group.id(), insertedGroupId);
334                 assert.equal(group.repetitionCount(), 1);
335                 const requests = group.buildRequests();
336                 assert.equal(requests.length, 2);
337
338                 const macos = Repository.findById(MockData.macosRepositoryId());
339                 const webkit = Repository.findById(MockData.webkitRepositoryId());
340                 const set0 = requests[0].commitSet();
341                 const set1 = requests[1].commitSet();
342                 assert.deepEqual(Repository.sortByNamePreferringOnesWithURL(set0.repositories()), [webkit, macos]);
343                 assert.deepEqual(Repository.sortByNamePreferringOnesWithURL(set1.repositories()), [webkit, macos]);
344                 assert.equal(set0.revisionForRepository(macos), '15A284');
345                 assert.equal(set0.revisionForRepository(webkit), '191622');
346                 assert.equal(set1.revisionForRepository(macos), '15A284');
347                 assert.equal(set1.revisionForRepository(webkit), '191623');
348
349                 const repositoryGroup = requests[0].repositoryGroup();
350                 assert.equal(repositoryGroup.name(), 'system-and-webkit');
351                 assert.equal(requests[1].repositoryGroup(), repositoryGroup);
352                 assert(repositoryGroup.accepts(set0));
353                 assert(repositoryGroup.accepts(set1));
354             });
355         });
356     });
357
358     it('should create a test group from revisionSets with the repetition count of one when repetitionCount is omitted', () => {
359         let webkit;
360         return addTriggerableAndCreateTask('some task').then((taskId) => {
361             const webkit = Repository.findById(MockData.webkitRepositoryId());
362             const revisionSets = [{[webkit.id()]: {revision: '191622'}}, {[webkit.id()]: {revision: '191623'}}];
363             const params = {name: 'test', task: taskId, revisionSets};
364             let insertedGroupId;
365             return PrivilegedAPI.sendRequest('create-test-group', params).then((content) => {
366                 insertedGroupId = content['testGroupId'];
367                 return TestGroup.fetchForTask(taskId, true);
368             }).then((testGroups) => {
369                 assert.equal(testGroups.length, 1);
370                 const group = testGroups[0];
371                 assert.equal(group.id(), insertedGroupId);
372                 assert.equal(group.repetitionCount(), 1);
373                 const requests = group.buildRequests();
374                 assert.equal(requests.length, 2);
375
376                 const set0 = requests[0].commitSet();
377                 const set1 = requests[1].commitSet();
378                 assert.deepEqual(set0.repositories(), [webkit]);
379                 assert.deepEqual(set1.repositories(), [webkit]);
380                 assert.equal(set0.revisionForRepository(webkit), '191622');
381                 assert.equal(set1.revisionForRepository(webkit), '191623');
382
383                 const repositoryGroup = requests[0].repositoryGroup();
384                 assert.equal(repositoryGroup.name(), 'webkit-only');
385                 assert.equal(repositoryGroup, requests[1].repositoryGroup());
386                 assert(repositoryGroup.accepts(set0));
387                 assert(repositoryGroup.accepts(set1));
388             });
389         });
390     });
391
392     it('should create a test group with the repetition count of two with two repositories', () => {
393         return addTriggerableAndCreateTask('some task').then((taskId) => {
394             let insertedGroupId;
395             return PrivilegedAPI.sendRequest('create-test-group', {name: 'test', task: taskId, repetitionCount: 2,
396                 commitSets: {'WebKit': ['191622', '191623'], 'macOS': ['15A284', '15A284']}}).then((content) => {
397                 insertedGroupId = content['testGroupId'];
398                 return TestGroup.fetchForTask(taskId, true);
399             }).then((testGroups) => {
400                 assert.equal(testGroups.length, 1);
401                 const group = testGroups[0];
402                 assert.equal(group.id(), insertedGroupId);
403                 assert.equal(group.repetitionCount(), 2);
404                 const requests = group.buildRequests();
405                 assert.equal(requests.length, 4);
406                 const webkit = Repository.all().filter((repository) => repository.name() == 'WebKit')[0];
407                 const macos = Repository.all().filter((repository) => repository.name() == 'macOS')[0];
408
409                 const set0 = requests[0].commitSet();
410                 const set1 = requests[1].commitSet();
411                 assert.equal(requests[2].commitSet(), set0);
412                 assert.equal(requests[3].commitSet(), set1);
413                 assert.deepEqual(Repository.sortByNamePreferringOnesWithURL(set0.repositories()), [webkit, macos]);
414                 assert.deepEqual(Repository.sortByNamePreferringOnesWithURL(set1.repositories()), [webkit, macos]);
415                 assert.equal(set0.revisionForRepository(webkit), '191622');
416                 assert.equal(set0.revisionForRepository(macos), '15A284');
417                 assert.equal(set1.revisionForRepository(webkit), '191623');
418                 assert.equal(set1.revisionForRepository(macos), '15A284');
419                 assert.equal(set0.commitForRepository(macos), set1.commitForRepository(macos));
420
421                 const repositoryGroup = requests[0].repositoryGroup();
422                 assert.equal(repositoryGroup.name(), 'system-and-webkit');
423                 assert.equal(requests[1].repositoryGroup(), repositoryGroup);
424                 assert.equal(requests[2].repositoryGroup(), repositoryGroup);
425                 assert.equal(requests[3].repositoryGroup(), repositoryGroup);
426                 assert(repositoryGroup.accepts(set0));
427                 assert(repositoryGroup.accepts(set1));
428             });
429         });
430     });
431
432     it('should create a test group using different repository groups if needed', () => {
433         let webkit;
434         let macos;
435         return addTriggerableAndCreateTask('some task').then((taskId) => {
436             webkit = Repository.findById(MockData.webkitRepositoryId());
437             macos = Repository.findById(MockData.macosRepositoryId());
438             const revisionSets = [{[macos.id()]: {revision: '15A284'}, [webkit.id()]: {revision: '191622'}},
439                 {[webkit.id()]: {revision: '191623'}}];
440             const params = {name: 'test', task: taskId, repetitionCount: 2, revisionSets};
441             let insertedGroupId;
442             return PrivilegedAPI.sendRequest('create-test-group', params).then((content) => {
443                 insertedGroupId = content['testGroupId'];
444                 return TestGroup.fetchForTask(taskId, true);
445             }).then((testGroups) => {
446                 assert.equal(testGroups.length, 1);
447                 const group = testGroups[0];
448                 assert.equal(group.id(), insertedGroupId);
449                 assert.equal(group.repetitionCount(), 2);
450                 const requests = group.buildRequests();
451                 assert.equal(requests.length, 4);
452
453                 const set0 = requests[0].commitSet();
454                 const set1 = requests[1].commitSet();
455                 assert.deepEqual(Repository.sortByNamePreferringOnesWithURL(set0.repositories()), [webkit, macos]);
456                 assert.deepEqual(set1.repositories(), [webkit]);
457                 assert.equal(set0.revisionForRepository(webkit), '191622');
458                 assert.equal(set0.revisionForRepository(macos), '15A284');
459                 assert.equal(set1.revisionForRepository(webkit), '191623');
460                 assert.equal(set1.revisionForRepository(macos), null);
461
462                 const repositoryGroup0 = requests[0].repositoryGroup();
463                 assert.equal(repositoryGroup0.name(), 'system-and-webkit');
464                 assert.equal(repositoryGroup0, requests[2].repositoryGroup());
465                 assert(repositoryGroup0.accepts(set0));
466                 assert(!repositoryGroup0.accepts(set1));
467
468                 const repositoryGroup1 = requests[1].repositoryGroup();
469                 assert.equal(repositoryGroup1.name(), 'webkit-only');
470                 assert.equal(repositoryGroup1, requests[3].repositoryGroup());
471                 assert(!repositoryGroup1.accepts(set0));
472                 assert(repositoryGroup1.accepts(set1));
473             });
474         });
475     });
476
477     it('should create a test group with a custom root', () => {
478         return addTriggerableAndCreateTask('some task').then((taskId) => {
479             let insertedGroupId;
480             const webkit = Repository.all().filter((repository) => repository.name() == 'WebKit')[0];
481             const macos = Repository.all().filter((repository) => repository.name() == 'macOS')[0];
482             let uploadedFile;
483             return TemporaryFile.makeTemporaryFile('some.dat', 'some content').then((stream) => {
484                 return PrivilegedAPI.sendRequest('upload-file', {newFile: stream}, {useFormData: true});
485             }).then((response) => {
486                 uploadedFile = response['uploadedFile'];
487                 const revisionSets = [{[webkit.id()]: {revision: '191622'}, [macos.id()]: {revision: '15A284'}},
488                     {[webkit.id()]: {revision: '191622'}, [macos.id()]: {revision: '15A284'}, 'customRoots': [uploadedFile['id']]}];
489                 return PrivilegedAPI.sendRequest('create-test-group', {name: 'test', task: taskId, repetitionCount: 2, revisionSets}).then((content) => {
490                     insertedGroupId = content['testGroupId'];
491                     return TestGroup.fetchForTask(taskId, true);
492                 });
493             }).then((testGroups) => {
494                 assert.equal(testGroups.length, 1);
495                 const group = testGroups[0];
496                 assert.equal(group.id(), insertedGroupId);
497                 assert.equal(group.repetitionCount(), 2);
498                 const requests = group.buildRequests();
499                 assert.equal(requests.length, 4);
500
501                 const set0 = requests[0].commitSet();
502                 const set1 = requests[1].commitSet();
503                 assert.equal(requests[2].commitSet(), set0);
504                 assert.equal(requests[3].commitSet(), set1);
505                 assert.deepEqual(Repository.sortByNamePreferringOnesWithURL(set0.repositories()), [webkit, macos]);
506                 assert.deepEqual(set0.customRoots(), []);
507                 assert.deepEqual(Repository.sortByNamePreferringOnesWithURL(set1.repositories()), [webkit, macos]);
508                 assert.deepEqual(set1.customRoots(), [UploadedFile.ensureSingleton(uploadedFile['id'], uploadedFile)]);
509                 assert.equal(set0.revisionForRepository(webkit), '191622');
510                 assert.equal(set0.revisionForRepository(webkit), set1.revisionForRepository(webkit));
511                 assert.equal(set0.commitForRepository(webkit), set1.commitForRepository(webkit));
512                 assert.equal(set0.revisionForRepository(macos), '15A284');
513                 assert.equal(set0.commitForRepository(macos), set1.commitForRepository(macos));
514                 assert.equal(set0.revisionForRepository(macos), set1.revisionForRepository(macos));
515                 assert(!set0.equals(set1));
516             });
517         });
518     });
519
520     it('should create a test group with a patch', () => {
521         let taskId;
522         let webkit;
523         let macos;
524         let insertedGroupId;
525         let uploadedFile;
526         return addTriggerableAndCreateTask('some task').then((id) => taskId = id).then(() => {
527             webkit = Repository.all().filter((repository) => repository.name() == 'WebKit')[0];
528             macos = Repository.all().filter((repository) => repository.name() == 'macOS')[0];
529             return TemporaryFile.makeTemporaryFile('some.dat', 'some content');
530         }).then((stream) => {
531             return PrivilegedAPI.sendRequest('upload-file', {newFile: stream}, {useFormData: true});
532         }).then((response) => {
533             const rawFile = response['uploadedFile'];
534             uploadedFile = UploadedFile.ensureSingleton(rawFile.id, rawFile);
535             const revisionSets = [{[webkit.id()]: {revision: '191622', patch: uploadedFile.id()}, [macos.id()]: {revision: '15A284'}},
536                 {[webkit.id()]: {revision: '191622'}, [macos.id()]: {revision: '15A284'}}];
537             return PrivilegedAPI.sendRequest('create-test-group', {name: 'test', task: taskId, repetitionCount: 2, revisionSets});
538         }).then((content) => {
539             insertedGroupId = content['testGroupId'];
540             return TestGroup.fetchForTask(taskId, true);
541         }).then((testGroups) => {
542             assert.equal(testGroups.length, 1);
543             const group = testGroups[0];
544             assert.equal(group.id(), insertedGroupId);
545             assert.equal(group.repetitionCount(), 2);
546             assert.equal(group.test(), Test.findById(MockData.someTestId()));
547             assert.equal(group.platform(), Platform.findById(MockData.somePlatformId()));
548             const requests = group.buildRequests();
549             assert.equal(requests.length, 6);
550
551             assert.equal(requests[0].isBuild(), true);
552             assert.equal(requests[1].isBuild(), true);
553             assert.equal(requests[2].isBuild(), false);
554             assert.equal(requests[3].isBuild(), false);
555             assert.equal(requests[4].isBuild(), false);
556             assert.equal(requests[5].isBuild(), false);
557
558             assert.equal(requests[0].isTest(), false);
559             assert.equal(requests[1].isTest(), false);
560             assert.equal(requests[2].isTest(), true);
561             assert.equal(requests[3].isTest(), true);
562             assert.equal(requests[4].isTest(), true);
563             assert.equal(requests[5].isTest(), true);
564
565             const set0 = requests[0].commitSet();
566             const set1 = requests[1].commitSet();
567             assert.equal(requests[2].commitSet(), set0);
568             assert.equal(requests[3].commitSet(), set1);
569             assert.equal(requests[4].commitSet(), set0);
570             assert.equal(requests[5].commitSet(), set1);
571             assert.deepEqual(Repository.sortByNamePreferringOnesWithURL(set0.repositories()), [webkit, macos]);
572             assert.deepEqual(set0.customRoots(), []);
573             assert.deepEqual(Repository.sortByNamePreferringOnesWithURL(set1.repositories()), [webkit, macos]);
574             assert.deepEqual(set1.customRoots(), []);
575             assert.equal(set0.revisionForRepository(webkit), '191622');
576             assert.equal(set0.revisionForRepository(webkit), set1.revisionForRepository(webkit));
577             assert.equal(set0.commitForRepository(webkit), set1.commitForRepository(webkit));
578             assert.equal(set0.patchForRepository(webkit), uploadedFile);
579             assert.equal(set1.patchForRepository(webkit), null);
580             assert.equal(set0.revisionForRepository(macos), '15A284');
581             assert.equal(set0.revisionForRepository(macos), set1.revisionForRepository(macos));
582             assert.equal(set0.commitForRepository(macos), set1.commitForRepository(macos));
583             assert.equal(set0.patchForRepository(macos), null);
584             assert.equal(set1.patchForRepository(macos), null);
585             assert(!set0.equals(set1));
586         });
587     });
588
589     it('should not create a build request to build a patch when the commit set does not have a patch', () => {
590         let taskId;
591         let webkit;
592         let macos;
593         let insertedGroupId;
594         let uploadedFile;
595         return addTriggerableAndCreateTask('some task').then((id) => taskId = id).then(() => {
596             webkit = Repository.all().filter((repository) => repository.name() == 'WebKit')[0];
597             macos = Repository.all().filter((repository) => repository.name() == 'macOS')[0];
598             return TemporaryFile.makeTemporaryFile('some.dat', 'some content');
599         }).then((stream) => {
600             return PrivilegedAPI.sendRequest('upload-file', {newFile: stream}, {useFormData: true});
601         }).then((response) => {
602             const rawFile = response['uploadedFile'];
603             uploadedFile = UploadedFile.ensureSingleton(rawFile.id, rawFile);
604             const revisionSets = [{[macos.id()]: {revision: '15A284'}},
605                 {[webkit.id()]: {revision: '191622', patch: uploadedFile.id()}, [macos.id()]: {revision: '15A284'}}];
606             return PrivilegedAPI.sendRequest('create-test-group', {name: 'test', task: taskId, repetitionCount: 2, revisionSets});
607         }).then((content) => {
608             insertedGroupId = content['testGroupId'];
609             return TestGroup.fetchForTask(taskId, true);
610         }).then((testGroups) => {
611             assert.equal(testGroups.length, 1);
612             const group = testGroups[0];
613             assert.equal(group.id(), insertedGroupId);
614             assert.equal(group.repetitionCount(), 2);
615             assert.equal(group.test(), Test.findById(MockData.someTestId()));
616             assert.equal(group.platform(), Platform.findById(MockData.somePlatformId()));
617             const requests = group.buildRequests();
618             assert.equal(requests.length, 5);
619
620             assert.equal(requests[0].isBuild(), true);
621             assert.equal(requests[1].isBuild(), false);
622             assert.equal(requests[2].isBuild(), false);
623             assert.equal(requests[3].isBuild(), false);
624             assert.equal(requests[4].isBuild(), false);
625
626             assert.equal(requests[0].isTest(), false);
627             assert.equal(requests[1].isTest(), true);
628             assert.equal(requests[2].isTest(), true);
629             assert.equal(requests[3].isTest(), true);
630             assert.equal(requests[4].isTest(), true);
631
632             const set0 = requests[0].commitSet();
633             const set1 = requests[1].commitSet();
634             assert.equal(requests[2].commitSet(), set0);
635             assert.equal(requests[3].commitSet(), set1);
636             assert.equal(requests[4].commitSet(), set0);
637             assert.deepEqual(Repository.sortByNamePreferringOnesWithURL(set0.repositories()), [webkit, macos]);
638             assert.deepEqual(set0.customRoots(), []);
639             assert.deepEqual(Repository.sortByNamePreferringOnesWithURL(set1.repositories()), [macos]);
640             assert.deepEqual(set1.customRoots(), []);
641             assert.equal(set0.revisionForRepository(webkit), '191622');
642             assert.equal(set1.revisionForRepository(webkit), null);
643             assert.equal(set0.patchForRepository(webkit), uploadedFile);
644             assert.equal(set0.revisionForRepository(macos), '15A284');
645             assert.equal(set0.revisionForRepository(macos), set1.revisionForRepository(macos));
646             assert.equal(set0.commitForRepository(macos), set1.commitForRepository(macos));
647             assert.equal(set0.patchForRepository(macos), null);
648             assert.equal(set1.patchForRepository(macos), null);
649             assert(!set0.equals(set1));
650         });
651     });
652
653     it('should return "PatchNotAccepted" when a patch is specified for a repository that does not accept a patch', () => {
654         let taskId;
655         let webkit;
656         let macos;
657         let insertedGroupId;
658         let uploadedFile;
659         return addTriggerableAndCreateTask('some task').then((id) => taskId = id).then(() => {
660             webkit = Repository.all().filter((repository) => repository.name() == 'WebKit')[0];
661             macos = Repository.all().filter((repository) => repository.name() == 'macOS')[0];
662             return TemporaryFile.makeTemporaryFile('some.dat', 'some content');
663         }).then((stream) => {
664             return PrivilegedAPI.sendRequest('upload-file', {newFile: stream}, {useFormData: true});
665         }).then((response) => {
666             const rawFile = response['uploadedFile'];
667             uploadedFile = UploadedFile.ensureSingleton(rawFile.id, rawFile);
668             const revisionSets = [{[webkit.id()]: {revision: '191622'}, [macos.id()]: {revision: '15A284', patch: uploadedFile.id()}},
669                 {[webkit.id()]: {revision: '191622'}, [macos.id()]: {revision: '15A284'}}];
670             return PrivilegedAPI.sendRequest('create-test-group', {name: 'test', task: taskId, repetitionCount: 2, revisionSets});
671         }).then(() => {
672             assert(false, 'should never be reached');
673         }, (error) => {
674             assert.equal(error, 'PatchNotAccepted');
675         });
676     });
677
678     it('should create a test group with an analysis task', () => {
679         let insertedGroupId;
680         let webkit;
681         return addTriggerableAndCreateTask('some task').then(() => {
682             webkit = Repository.all().filter((repository) => repository.name() == 'WebKit')[0];
683             const revisionSets = [{[webkit.id()]: {revision: '191622'}}, {[webkit.id()]: {revision: '191623'}}];
684             return PrivilegedAPI.sendRequest('create-test-group',
685                 {name: 'test', taskName: 'other task', platform: MockData.somePlatformId(), test: MockData.someTestId(), revisionSets});
686         }).then((result) => {
687             insertedGroupId = result['testGroupId'];
688             return Promise.all([AnalysisTask.fetchById(result['taskId']), TestGroup.fetchForTask(result['taskId'], true)]);
689         }).then((result) => {
690             const [analysisTask, testGroups] = result;
691
692             assert.equal(analysisTask.name(), 'other task');
693
694             assert.equal(testGroups.length, 1);
695             const group = testGroups[0];
696             assert.equal(group.id(), insertedGroupId);
697             assert.equal(group.repetitionCount(), 1);
698             const requests = group.buildRequests();
699             assert.equal(requests.length, 2);
700
701             const set0 = requests[0].commitSet();
702             const set1 = requests[1].commitSet();
703             assert.deepEqual(set0.repositories(), [webkit]);
704             assert.deepEqual(set0.customRoots(), []);
705             assert.deepEqual(set1.repositories(), [webkit]);
706             assert.deepEqual(set1.customRoots(), []);
707             assert.equal(set0.revisionForRepository(webkit), '191622');
708             assert.equal(set1.revisionForRepository(webkit), '191623');
709         });
710     });
711
712     it('should create a custom test group for an existing custom analysis task', () => {
713         let firstResult;
714         let secondResult;
715         let webkit;
716         let test = MockData.someTestId();
717         return addTriggerableAndCreateTask('some task').then(() => {
718             webkit = Repository.all().filter((repository) => repository.name() == 'WebKit')[0];
719             const revisionSets = [{[webkit.id()]: {revision: '191622'}}, {[webkit.id()]: {revision: '191623'}}];
720             return PrivilegedAPI.sendRequest('create-test-group',
721                 {name: 'test1', taskName: 'other task', platform: MockData.somePlatformId(), test, revisionSets});
722         }).then((result) => {
723             firstResult = result;
724             const revisionSets = [{[webkit.id()]: {revision: '191622'}}, {[webkit.id()]: {revision: '192736'}}];
725             return PrivilegedAPI.sendRequest('create-test-group',
726                 {name: 'test2', task: result['taskId'], platform: MockData.otherPlatformId(), test, revisionSets, repetitionCount: 2});
727         }).then((result) => {
728             secondResult = result;
729             assert.equal(firstResult['taskId'], secondResult['taskId']);
730             return Promise.all([AnalysisTask.fetchById(result['taskId']), TestGroup.fetchForTask(result['taskId'], true)]);
731         }).then((result) => {
732             const [analysisTask, testGroups] = result;
733
734             assert.equal(analysisTask.name(), 'other task');
735
736             assert.equal(testGroups.length, 2);
737             TestGroup.sortByName(testGroups);
738
739             assert.equal(testGroups[0].name(), 'test1');
740             assert.equal(testGroups[0].repetitionCount(), 1);
741             let requests = testGroups[0].buildRequests();
742             assert.equal(requests.length, 2);
743             let set0 = requests[0].commitSet();
744             let set1 = requests[1].commitSet();
745             assert.deepEqual(set0.repositories(), [webkit]);
746             assert.deepEqual(set0.customRoots(), []);
747             assert.deepEqual(set1.repositories(), [webkit]);
748             assert.deepEqual(set1.customRoots(), []);
749             assert.equal(set0.revisionForRepository(webkit), '191622');
750             assert.equal(set1.revisionForRepository(webkit), '191623');
751
752             assert.equal(testGroups[1].name(), 'test2');
753             assert.equal(testGroups[1].repetitionCount(), 2);
754             requests = testGroups[1].buildRequests();
755             assert.equal(requests.length, 4);
756             set0 = requests[0].commitSet();
757             set1 = requests[1].commitSet();
758             assert.deepEqual(requests[2].commitSet(), set0);
759             assert.deepEqual(requests[3].commitSet(), set1);
760             assert.deepEqual(set0.repositories(), [webkit]);
761             assert.deepEqual(set0.customRoots(), []);
762             assert.deepEqual(set1.repositories(), [webkit]);
763             assert.deepEqual(set1.customRoots(), []);
764             assert.equal(set0.revisionForRepository(webkit), '191622');
765             assert.equal(set1.revisionForRepository(webkit), '192736');
766         });
767     });
768 });