Add the support for scheduling a A/B testing with a patch.
[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: 'webkit-only', repositories: [
107                 {repository: MockData.webkitRepositoryId(), acceptsPatch: true}
108             ]},
109             {name: 'system-and-webkit', repositories: [
110                 {repository: MockData.macosRepositoryId(), acceptsPatch: false},
111                 {repository: MockData.webkitRepositoryId(), acceptsPatch: true}
112             ]},
113         ]
114     };
115     return MockData.addMockData(TestServer.database()).then(() => {
116         return addSlaveForReport(report);
117     }).then(() => {
118         return TestServer.remoteAPI().postJSON('/api/update-triggerable/', report);
119     }).then(() => {
120         return createAnalysisTask(name);
121     });
122 }
123
124 describe('/privileged-api/create-test-group', function () {
125     prepareServerTest(this);
126     TemporaryFile.inject();
127
128     it('should return "InvalidName" on an empty request', () => {
129         return PrivilegedAPI.sendRequest('create-test-group', {}).then((content) => {
130             assert(false, 'should never be reached');
131         }, (error) => {
132             assert.equal(error, 'InvalidName');
133         });
134     });
135
136     it('should return "InvalidTask" when task is not specified', () => {
137         return PrivilegedAPI.sendRequest('create-test-group', {name: 'test', commitSets: [[1]]}).then((content) => {
138             assert(false, 'should never be reached');
139         }, (error) => {
140             assert.equal(error, 'InvalidTask');
141         });
142     });
143
144     it('should return "InvalidTask" when task is not a valid integer', () => {
145         return PrivilegedAPI.sendRequest('create-test-group', {name: 'test', task: 'foo', commitSets: [[1]]}).then((content) => {
146             assert(false, 'should never be reached');
147         }, (error) => {
148             assert.equal(error, 'InvalidTask');
149         });
150     });
151
152     it('should return "InvalidCommitSets" when commit sets are not specified', () => {
153         return PrivilegedAPI.sendRequest('create-test-group', {name: 'test', task: 1, repetitionCount: 1}).then((content) => {
154             assert(false, 'should never be reached');
155         }, (error) => {
156             assert.equal(error, 'InvalidCommitSets');
157         });
158     });
159
160     it('should return "InvalidCommitSets" when commit sets is empty', () => {
161         return PrivilegedAPI.sendRequest('create-test-group', {name: 'test', task: 1, repetitionCount: 1, commitSets: {}}).then((content) => {
162             assert(false, 'should never be reached');
163         }, (error) => {
164             assert.equal(error, 'InvalidCommitSets');
165         });
166     });
167
168     it('should return "InvalidTask" when there is no matching task', () => {
169         return PrivilegedAPI.sendRequest('create-test-group', {name: 'test', task: 1, repetitionCount: 1, commitSets: {'WebKit': []}}).then((content) => {
170             assert(false, 'should never be reached');
171         }, (error) => {
172             assert.equal(error, 'InvalidTask');
173         });
174     });
175
176     it('should return "InvalidRepetitionCount" when repetitionCount is not a valid integer', () => {
177         return PrivilegedAPI.sendRequest('create-test-group', {name: 'test', task: 1, repetitionCount: 'foo', commitSets: {'WebKit': []}}).then((content) => {
178             assert(false, 'should never be reached');
179         }, (error) => {
180             assert.equal(error, 'InvalidRepetitionCount');
181         });
182     });
183
184     it('should return "InvalidRepetitionCount" when repetitionCount is a negative integer', () => {
185         return PrivilegedAPI.sendRequest('create-test-group', {name: 'test', task: 1, repetitionCount: -5, commitSets: {'WebKit': []}}).then((content) => {
186             assert(false, 'should never be reached');
187         }, (error) => {
188             assert.equal(error, 'InvalidRepetitionCount');
189         });
190     });
191
192     it('should return "InvalidTask" when there is no matching task', () => {
193         return PrivilegedAPI.sendRequest('create-test-group', {name: 'test', task: 1, commitSets: {'WebKit': []}}).then((content) => {
194             assert(false, 'should never be reached');
195         }, (error) => {
196             assert.equal(error, 'InvalidTask');
197         });
198     });
199
200     it('should return "TriggerableNotFoundForTask" when there is no matching triggerable', () => {
201         return createAnalysisTask('some task').then((taskId) => {
202             return PrivilegedAPI.sendRequest('create-test-group', {name: 'test', task: taskId, commitSets: {'WebKit': []}}).then((content) => {
203                 assert(false, 'should never be reached');
204             }, (error) => {
205                 assert.equal(error, 'TriggerableNotFoundForTask');
206             });
207         });
208     });
209
210     it('should return "InvalidCommitSets" when each repository specifies zero revisions', () => {
211         return addTriggerableAndCreateTask('some task').then((taskId) => {
212             return PrivilegedAPI.sendRequest('create-test-group', {name: 'test', task: taskId, commitSets: {'WebKit': []}}).then((content) => {
213                 assert(false, 'should never be reached');
214             }, (error) => {
215                 assert.equal(error, 'InvalidCommitSets');
216             });
217         });
218     });
219
220     it('should return "InvalidRevisionSets" when a revision set is empty', () => {
221         return addTriggerableAndCreateTask('some task').then((taskId) => {
222             const webkit = Repository.all().find((repository) => repository.name() == 'WebKit');
223             return PrivilegedAPI.sendRequest('create-test-group', {name: 'test', task: taskId, revisionSets: [{[webkit.id()]: {revision: '191622'}}, {}]}).then((content) => {
224                 assert(false, 'should never be reached');
225             }, (error) => {
226                 assert.equal(error, 'InvalidRevisionSets');
227             });
228         });
229     });
230
231     it('should return "InvalidRevisionSets" when the number of revision sets is less than two', () => {
232         return addTriggerableAndCreateTask('some task').then((taskId) => {
233             const webkit = Repository.all().find((repository) => repository.name() == 'WebKit');
234             return PrivilegedAPI.sendRequest('create-test-group', {name: 'test', task: taskId, revisionSets: [{[webkit.id()]: {revision: '191622'}}]}).then((content) => {
235                 assert(false, 'should never be reached');
236             }, (error) => {
237                 assert.equal(error, 'InvalidRevisionSets');
238             });
239         });
240     });
241
242     it('should return "RepositoryNotFound" when commit sets contains an invalid repository', () => {
243         return addTriggerableAndCreateTask('some task').then((taskId) => {
244             return PrivilegedAPI.sendRequest('create-test-group', {name: 'test', task: taskId, commitSets: {'Foo': []}}).then((content) => {
245                 assert(false, 'should never be reached');
246             }, (error) => {
247                 assert.equal(error, 'RepositoryNotFound');
248             });
249         });
250     });
251
252     it('should return "RevisionNotFound" when commit sets contains an invalid revision', () => {
253         return addTriggerableAndCreateTask('some task').then((taskId) => {
254             return PrivilegedAPI.sendRequest('create-test-group', {name: 'test', task: taskId, commitSets: {'WebKit': ['1']}}).then((content) => {
255                 assert(false, 'should never be reached');
256             }, (error) => {
257                 assert.equal(error, 'RevisionNotFound');
258             });
259         });
260     });
261
262     it('should return "RevisionNotFound" when revision sets contains an invalid revision', () => {
263         return addTriggerableAndCreateTask('some task').then((taskId) => {
264             const webkit = Repository.all().find((repository) => repository.name() == 'WebKit');
265             const revisionSets = [{[webkit.id()]: {revision: '191622'}}, {[webkit.id()]: {revision: '1'}}];
266             return PrivilegedAPI.sendRequest('create-test-group', {name: 'test', task: taskId, revisionSets}).then((content) => {
267                 assert(false, 'should never be reached');
268             }, (error) => {
269                 assert.equal(error, 'RevisionNotFound');
270             });
271         });
272     });
273
274     it('should return "InvalidUploadedFile" when revision sets contains an invalid file ID', () => {
275         return addTriggerableAndCreateTask('some task').then((taskId) => {
276             const webkit = Repository.all().find((repository) => repository.name() == 'WebKit');
277             const revisionSets = [{[webkit.id()]: {revision: '191622'}, 'customRoots': ['1']}, {[webkit.id()]: {revision: '1'}}];
278             return PrivilegedAPI.sendRequest('create-test-group', {name: 'test', task: taskId, revisionSets}).then((content) => {
279                 assert(false, 'should never be reached');
280             }, (error) => {
281                 assert.equal(error, 'InvalidUploadedFile');
282             });
283         });
284     });
285
286     it('should return "InvalidRepository" when a revision set uses a repository name instead of a repository id', () => {
287         return addTriggerableAndCreateTask('some task').then((taskId) => {
288             const revisionSets = [{'WebKit': {revision: '191622'}}, {}];
289             return PrivilegedAPI.sendRequest('create-test-group', {name: 'test', task: taskId, revisionSets}).then((content) => {
290                 assert(false, 'should never be reached');
291             }, (error) => {
292                 assert.equal(error, 'InvalidRepository');
293             });
294         });
295     });
296
297     it('should return "InvalidCommitSets" when commit sets contains an inconsistent number of revisions', () => {
298         return addTriggerableAndCreateTask('some task').then((taskId) => {
299             return PrivilegedAPI.sendRequest('create-test-group', {name: 'test', task: taskId, commitSets: {'WebKit': ['191622', '191623'], 'macOS': ['15A284']}}).then((content) => {
300                 assert(false, 'should never be reached');
301             }, (error) => {
302                 assert.equal(error, 'InvalidCommitSets');
303             });
304         });
305     });
306
307     it('should return "DuplicateTestGroupName" when there is already a test group of the same name', () => {
308         return addTriggerableAndCreateTask('some task').then((taskId) => {
309             const commitSets = {'WebKit': ['191622', '191623']};
310             return PrivilegedAPI.sendRequest('create-test-group', {name: 'test', task: taskId, commitSets}).then((content) => {
311                 assert(content['testGroupId']);
312                 return PrivilegedAPI.sendRequest('create-test-group', {name: 'test', task: taskId, commitSets});
313             }).then(() => {
314                 assert(false, 'should never be reached');
315             }, (error) => {
316                 assert.equal(error, 'DuplicateTestGroupName');
317             });
318         });
319     });
320
321     it('should create a test group from commitSets with the repetition count of one when repetitionCount is omitted', () => {
322         return addTriggerableAndCreateTask('some task').then((taskId) => {
323             let insertedGroupId;
324             return PrivilegedAPI.sendRequest('create-test-group', {name: 'test', task: taskId, commitSets: {'macOS': ['15A284', '15A284'], 'WebKit': ['191622', '191623']}}).then((content) => {
325                 insertedGroupId = content['testGroupId'];
326                 return TestGroup.fetchByTask(taskId);
327             }).then((testGroups) => {
328                 assert.equal(testGroups.length, 1);
329                 const group = testGroups[0];
330                 assert.equal(group.id(), insertedGroupId);
331                 assert.equal(group.repetitionCount(), 1);
332                 const requests = group.buildRequests();
333                 assert.equal(requests.length, 2);
334
335                 const macos = Repository.findById(MockData.macosRepositoryId());
336                 const webkit = Repository.findById(MockData.webkitRepositoryId());
337                 const set0 = requests[0].commitSet();
338                 const set1 = requests[1].commitSet();
339                 assert.deepEqual(Repository.sortByNamePreferringOnesWithURL(set0.repositories()), [webkit, macos]);
340                 assert.deepEqual(Repository.sortByNamePreferringOnesWithURL(set1.repositories()), [webkit, macos]);
341                 assert.equal(set0.revisionForRepository(macos), '15A284');
342                 assert.equal(set0.revisionForRepository(webkit), '191622');
343                 assert.equal(set1.revisionForRepository(macos), '15A284');
344                 assert.equal(set1.revisionForRepository(webkit), '191623');
345
346                 const repositoryGroup = requests[0].repositoryGroup();
347                 assert.equal(repositoryGroup.name(), 'system-and-webkit');
348                 assert.equal(requests[1].repositoryGroup(), repositoryGroup);
349                 assert(repositoryGroup.accepts(set0));
350                 assert(repositoryGroup.accepts(set1));
351             });
352         });
353     });
354
355     it('should create a test group from revisionSets with the repetition count of one when repetitionCount is omitted', () => {
356         let webkit;
357         return addTriggerableAndCreateTask('some task').then((taskId) => {
358             const webkit = Repository.findById(MockData.webkitRepositoryId());
359             const revisionSets = [{[webkit.id()]: {revision: '191622'}}, {[webkit.id()]: {revision: '191623'}}];
360             const params = {name: 'test', task: taskId, revisionSets};
361             let insertedGroupId;
362             return PrivilegedAPI.sendRequest('create-test-group', params).then((content) => {
363                 insertedGroupId = content['testGroupId'];
364                 return TestGroup.fetchByTask(taskId);
365             }).then((testGroups) => {
366                 assert.equal(testGroups.length, 1);
367                 const group = testGroups[0];
368                 assert.equal(group.id(), insertedGroupId);
369                 assert.equal(group.repetitionCount(), 1);
370                 const requests = group.buildRequests();
371                 assert.equal(requests.length, 2);
372
373                 const set0 = requests[0].commitSet();
374                 const set1 = requests[1].commitSet();
375                 assert.deepEqual(set0.repositories(), [webkit]);
376                 assert.deepEqual(set1.repositories(), [webkit]);
377                 assert.equal(set0.revisionForRepository(webkit), '191622');
378                 assert.equal(set1.revisionForRepository(webkit), '191623');
379
380                 const repositoryGroup = requests[0].repositoryGroup();
381                 assert.equal(repositoryGroup.name(), 'webkit-only');
382                 assert.equal(repositoryGroup, requests[1].repositoryGroup());
383                 assert(repositoryGroup.accepts(set0));
384                 assert(repositoryGroup.accepts(set1));
385             });
386         });
387     });
388
389     it('should create a test group with the repetition count of two with two repositories', () => {
390         return addTriggerableAndCreateTask('some task').then((taskId) => {
391             let insertedGroupId;
392             return PrivilegedAPI.sendRequest('create-test-group', {name: 'test', task: taskId, repetitionCount: 2,
393                 commitSets: {'WebKit': ['191622', '191623'], 'macOS': ['15A284', '15A284']}}).then((content) => {
394                 insertedGroupId = content['testGroupId'];
395                 return TestGroup.fetchByTask(taskId);
396             }).then((testGroups) => {
397                 assert.equal(testGroups.length, 1);
398                 const group = testGroups[0];
399                 assert.equal(group.id(), insertedGroupId);
400                 assert.equal(group.repetitionCount(), 2);
401                 const requests = group.buildRequests();
402                 assert.equal(requests.length, 4);
403                 const webkit = Repository.all().filter((repository) => repository.name() == 'WebKit')[0];
404                 const macos = Repository.all().filter((repository) => repository.name() == 'macOS')[0];
405
406                 const set0 = requests[0].commitSet();
407                 const set1 = requests[1].commitSet();
408                 assert.equal(requests[2].commitSet(), set0);
409                 assert.equal(requests[3].commitSet(), set1);
410                 assert.deepEqual(Repository.sortByNamePreferringOnesWithURL(set0.repositories()), [webkit, macos]);
411                 assert.deepEqual(Repository.sortByNamePreferringOnesWithURL(set1.repositories()), [webkit, macos]);
412                 assert.equal(set0.revisionForRepository(webkit), '191622');
413                 assert.equal(set0.revisionForRepository(macos), '15A284');
414                 assert.equal(set1.revisionForRepository(webkit), '191623');
415                 assert.equal(set1.revisionForRepository(macos), '15A284');
416                 assert.equal(set0.commitForRepository(macos), set1.commitForRepository(macos));
417
418                 const repositoryGroup = requests[0].repositoryGroup();
419                 assert.equal(repositoryGroup.name(), 'system-and-webkit');
420                 assert.equal(requests[1].repositoryGroup(), repositoryGroup);
421                 assert.equal(requests[2].repositoryGroup(), repositoryGroup);
422                 assert.equal(requests[3].repositoryGroup(), repositoryGroup);
423                 assert(repositoryGroup.accepts(set0));
424                 assert(repositoryGroup.accepts(set1));
425             });
426         });
427     });
428
429     it('should create a test group using different repository groups if needed', () => {
430         let webkit;
431         let macos;
432         return addTriggerableAndCreateTask('some task').then((taskId) => {
433             webkit = Repository.findById(MockData.webkitRepositoryId());
434             macos = Repository.findById(MockData.macosRepositoryId());
435             const revisionSets = [{[macos.id()]: {revision: '15A284'}, [webkit.id()]: {revision: '191622'}},
436                 {[webkit.id()]: {revision: '191623'}}];
437             const params = {name: 'test', task: taskId, repetitionCount: 2, revisionSets};
438             let insertedGroupId;
439             return PrivilegedAPI.sendRequest('create-test-group', params).then((content) => {
440                 insertedGroupId = content['testGroupId'];
441                 return TestGroup.fetchByTask(taskId);
442             }).then((testGroups) => {
443                 assert.equal(testGroups.length, 1);
444                 const group = testGroups[0];
445                 assert.equal(group.id(), insertedGroupId);
446                 assert.equal(group.repetitionCount(), 2);
447                 const requests = group.buildRequests();
448                 assert.equal(requests.length, 4);
449
450                 const set0 = requests[0].commitSet();
451                 const set1 = requests[1].commitSet();
452                 assert.deepEqual(Repository.sortByNamePreferringOnesWithURL(set0.repositories()), [webkit, macos]);
453                 assert.deepEqual(set1.repositories(), [webkit]);
454                 assert.equal(set0.revisionForRepository(webkit), '191622');
455                 assert.equal(set0.revisionForRepository(macos), '15A284');
456                 assert.equal(set1.revisionForRepository(webkit), '191623');
457                 assert.equal(set1.revisionForRepository(macos), null);
458
459                 const repositoryGroup0 = requests[0].repositoryGroup();
460                 assert.equal(repositoryGroup0.name(), 'system-and-webkit');
461                 assert.equal(repositoryGroup0, requests[2].repositoryGroup());
462                 assert(repositoryGroup0.accepts(set0));
463                 assert(!repositoryGroup0.accepts(set1));
464
465                 const repositoryGroup1 = requests[1].repositoryGroup();
466                 assert.equal(repositoryGroup1.name(), 'webkit-only');
467                 assert.equal(repositoryGroup1, requests[3].repositoryGroup());
468                 assert(!repositoryGroup1.accepts(set0));
469                 assert(repositoryGroup1.accepts(set1));
470             });
471         });
472     });
473
474     it('should create a test group with a custom root', () => {
475         return addTriggerableAndCreateTask('some task').then((taskId) => {
476             let insertedGroupId;
477             const webkit = Repository.all().filter((repository) => repository.name() == 'WebKit')[0];
478             const macos = Repository.all().filter((repository) => repository.name() == 'macOS')[0];
479             let uploadedFile;
480             return TemporaryFile.makeTemporaryFile('some.dat', 'some content').then((stream) => {
481                 return PrivilegedAPI.sendRequest('upload-file', {newFile: stream}, {useFormData: true});
482             }).then((response) => {
483                 uploadedFile = response['uploadedFile'];
484                 const revisionSets = [{[webkit.id()]: {revision: '191622'}, [macos.id()]: {revision: '15A284'}},
485                     {[webkit.id()]: {revision: '191622'}, [macos.id()]: {revision: '15A284'}, 'customRoots': [uploadedFile['id']]}];
486                 return PrivilegedAPI.sendRequest('create-test-group', {name: 'test', task: taskId, repetitionCount: 2, revisionSets}).then((content) => {
487                     insertedGroupId = content['testGroupId'];
488                     return TestGroup.fetchByTask(taskId);
489                 });
490             }).then((testGroups) => {
491                 assert.equal(testGroups.length, 1);
492                 const group = testGroups[0];
493                 assert.equal(group.id(), insertedGroupId);
494                 assert.equal(group.repetitionCount(), 2);
495                 const requests = group.buildRequests();
496                 assert.equal(requests.length, 4);
497
498                 const set0 = requests[0].commitSet();
499                 const set1 = requests[1].commitSet();
500                 assert.equal(requests[2].commitSet(), set0);
501                 assert.equal(requests[3].commitSet(), set1);
502                 assert.deepEqual(Repository.sortByNamePreferringOnesWithURL(set0.repositories()), [webkit, macos]);
503                 assert.deepEqual(set0.customRoots(), []);
504                 assert.deepEqual(Repository.sortByNamePreferringOnesWithURL(set1.repositories()), [webkit, macos]);
505                 assert.deepEqual(set1.customRoots(), [UploadedFile.ensureSingleton(uploadedFile['id'], uploadedFile)]);
506                 assert.equal(set0.revisionForRepository(webkit), '191622');
507                 assert.equal(set0.revisionForRepository(webkit), set1.revisionForRepository(webkit));
508                 assert.equal(set0.commitForRepository(webkit), set1.commitForRepository(webkit));
509                 assert.equal(set0.revisionForRepository(macos), '15A284');
510                 assert.equal(set0.commitForRepository(macos), set1.commitForRepository(macos));
511                 assert.equal(set0.revisionForRepository(macos), set1.revisionForRepository(macos));
512                 assert(!set0.equals(set1));
513             });
514         });
515     });
516
517     it('should create a test group with a patch', () => {
518         let taskId;
519         let webkit;
520         let macos;
521         let insertedGroupId;
522         let uploadedFile;
523         return addTriggerableAndCreateTask('some task').then((id) => taskId = id).then(() => {
524             webkit = Repository.all().filter((repository) => repository.name() == 'WebKit')[0];
525             macos = Repository.all().filter((repository) => repository.name() == 'macOS')[0];
526             return TemporaryFile.makeTemporaryFile('some.dat', 'some content');
527         }).then((stream) => {
528             return PrivilegedAPI.sendRequest('upload-file', {newFile: stream}, {useFormData: true});
529         }).then((response) => {
530             const rawFile = response['uploadedFile'];
531             uploadedFile = UploadedFile.ensureSingleton(rawFile.id, rawFile);
532             const revisionSets = [{[webkit.id()]: {revision: '191622', patch: uploadedFile.id()}, [macos.id()]: {revision: '15A284'}},
533                 {[webkit.id()]: {revision: '191622'}, [macos.id()]: {revision: '15A284'}}];
534             return PrivilegedAPI.sendRequest('create-test-group', {name: 'test', task: taskId, repetitionCount: 2, revisionSets});
535         }).then((content) => {
536             insertedGroupId = content['testGroupId'];
537             return TestGroup.fetchByTask(taskId);
538         }).then((testGroups) => {
539             assert.equal(testGroups.length, 1);
540             const group = testGroups[0];
541             assert.equal(group.id(), insertedGroupId);
542             assert.equal(group.repetitionCount(), 2);
543             assert.equal(group.test(), Test.findById(MockData.someTestId()));
544             assert.equal(group.platform(), Platform.findById(MockData.somePlatformId()));
545             const requests = group.buildRequests();
546             assert.equal(requests.length, 6);
547
548             assert.equal(requests[0].isBuild(), true);
549             assert.equal(requests[1].isBuild(), true);
550             assert.equal(requests[2].isBuild(), false);
551             assert.equal(requests[3].isBuild(), false);
552             assert.equal(requests[4].isBuild(), false);
553             assert.equal(requests[5].isBuild(), false);
554
555             assert.equal(requests[0].isTest(), false);
556             assert.equal(requests[1].isTest(), false);
557             assert.equal(requests[2].isTest(), true);
558             assert.equal(requests[3].isTest(), true);
559             assert.equal(requests[4].isTest(), true);
560             assert.equal(requests[5].isTest(), true);
561
562             const set0 = requests[0].commitSet();
563             const set1 = requests[1].commitSet();
564             assert.equal(requests[2].commitSet(), set0);
565             assert.equal(requests[3].commitSet(), set1);
566             assert.equal(requests[4].commitSet(), set0);
567             assert.equal(requests[5].commitSet(), set1);
568             assert.deepEqual(Repository.sortByNamePreferringOnesWithURL(set0.repositories()), [webkit, macos]);
569             assert.deepEqual(set0.customRoots(), []);
570             assert.deepEqual(Repository.sortByNamePreferringOnesWithURL(set1.repositories()), [webkit, macos]);
571             assert.deepEqual(set1.customRoots(), []);
572             assert.equal(set0.revisionForRepository(webkit), '191622');
573             assert.equal(set0.revisionForRepository(webkit), set1.revisionForRepository(webkit));
574             assert.equal(set0.commitForRepository(webkit), set1.commitForRepository(webkit));
575             assert.equal(set0.patchForRepository(webkit), uploadedFile);
576             assert.equal(set1.patchForRepository(webkit), null);
577             assert.equal(set0.revisionForRepository(macos), '15A284');
578             assert.equal(set0.revisionForRepository(macos), set1.revisionForRepository(macos));
579             assert.equal(set0.commitForRepository(macos), set1.commitForRepository(macos));
580             assert.equal(set0.patchForRepository(macos), null);
581             assert.equal(set1.patchForRepository(macos), null);
582             assert(!set0.equals(set1));
583         });
584     });
585
586     it('should return "PatchNotAccepted" when a patch is specified for a repository that does not accept a patch', () => {
587         let taskId;
588         let webkit;
589         let macos;
590         let insertedGroupId;
591         let uploadedFile;
592         return addTriggerableAndCreateTask('some task').then((id) => taskId = id).then(() => {
593             webkit = Repository.all().filter((repository) => repository.name() == 'WebKit')[0];
594             macos = Repository.all().filter((repository) => repository.name() == 'macOS')[0];
595             return TemporaryFile.makeTemporaryFile('some.dat', 'some content');
596         }).then((stream) => {
597             return PrivilegedAPI.sendRequest('upload-file', {newFile: stream}, {useFormData: true});
598         }).then((response) => {
599             const rawFile = response['uploadedFile'];
600             uploadedFile = UploadedFile.ensureSingleton(rawFile.id, rawFile);
601             const revisionSets = [{[webkit.id()]: {revision: '191622'}, [macos.id()]: {revision: '15A284', patch: uploadedFile.id()}},
602                 {[webkit.id()]: {revision: '191622'}, [macos.id()]: {revision: '15A284'}}];
603             return PrivilegedAPI.sendRequest('create-test-group', {name: 'test', task: taskId, repetitionCount: 2, revisionSets});
604         }).then(() => {
605             assert(false, 'should never be reached');
606         }, (error) => {
607             assert.equal(error, 'PatchNotAccepted');
608         });
609     });
610
611     it('should create a test group with an analysis task', () => {
612         let insertedGroupId;
613         let webkit;
614         return addTriggerableAndCreateTask('some task').then(() => {
615             webkit = Repository.all().filter((repository) => repository.name() == 'WebKit')[0];
616             const revisionSets = [{[webkit.id()]: {revision: '191622'}}, {[webkit.id()]: {revision: '191623'}}];
617             return PrivilegedAPI.sendRequest('create-test-group',
618                 {name: 'test', taskName: 'other task', platform: MockData.somePlatformId(), test: MockData.someTestId(), revisionSets});
619         }).then((result) => {
620             insertedGroupId = result['testGroupId'];
621             return Promise.all([AnalysisTask.fetchById(result['taskId']), TestGroup.fetchByTask(result['taskId'])]);
622         }).then((result) => {
623             const [analysisTask, testGroups] = result;
624
625             assert.equal(analysisTask.name(), 'other task');
626
627             assert.equal(testGroups.length, 1);
628             const group = testGroups[0];
629             assert.equal(group.id(), insertedGroupId);
630             assert.equal(group.repetitionCount(), 1);
631             const requests = group.buildRequests();
632             assert.equal(requests.length, 2);
633
634             const set0 = requests[0].commitSet();
635             const set1 = requests[1].commitSet();
636             assert.deepEqual(set0.repositories(), [webkit]);
637             assert.deepEqual(set0.customRoots(), []);
638             assert.deepEqual(set1.repositories(), [webkit]);
639             assert.deepEqual(set1.customRoots(), []);
640             assert.equal(set0.revisionForRepository(webkit), '191622');
641             assert.equal(set1.revisionForRepository(webkit), '191623');
642         });
643     });
644
645     it('should create a custom test group for an existing custom analysis task', () => {
646         let firstResult;
647         let secondResult;
648         let webkit;
649         let test = MockData.someTestId();
650         return addTriggerableAndCreateTask('some task').then(() => {
651             webkit = Repository.all().filter((repository) => repository.name() == 'WebKit')[0];
652             const revisionSets = [{[webkit.id()]: {revision: '191622'}}, {[webkit.id()]: {revision: '191623'}}];
653             return PrivilegedAPI.sendRequest('create-test-group',
654                 {name: 'test1', taskName: 'other task', platform: MockData.somePlatformId(), test, revisionSets});
655         }).then((result) => {
656             firstResult = result;
657             const revisionSets = [{[webkit.id()]: {revision: '191622'}}, {[webkit.id()]: {revision: '192736'}}];
658             return PrivilegedAPI.sendRequest('create-test-group',
659                 {name: 'test2', task: result['taskId'], platform: MockData.otherPlatformId(), test, revisionSets, repetitionCount: 2});
660         }).then((result) => {
661             secondResult = result;
662             assert.equal(firstResult['taskId'], secondResult['taskId']);
663             return Promise.all([AnalysisTask.fetchById(result['taskId']), TestGroup.fetchByTask(result['taskId'])]);
664         }).then((result) => {
665             const [analysisTask, testGroups] = result;
666
667             assert.equal(analysisTask.name(), 'other task');
668
669             assert.equal(testGroups.length, 2);
670             TestGroup.sortByName(testGroups);
671
672             assert.equal(testGroups[0].name(), 'test1');
673             assert.equal(testGroups[0].repetitionCount(), 1);
674             let requests = testGroups[0].buildRequests();
675             assert.equal(requests.length, 2);
676             let set0 = requests[0].commitSet();
677             let set1 = requests[1].commitSet();
678             assert.deepEqual(set0.repositories(), [webkit]);
679             assert.deepEqual(set0.customRoots(), []);
680             assert.deepEqual(set1.repositories(), [webkit]);
681             assert.deepEqual(set1.customRoots(), []);
682             assert.equal(set0.revisionForRepository(webkit), '191622');
683             assert.equal(set1.revisionForRepository(webkit), '191623');
684
685             assert.equal(testGroups[1].name(), 'test2');
686             assert.equal(testGroups[1].repetitionCount(), 2);
687             requests = testGroups[1].buildRequests();
688             assert.equal(requests.length, 4);
689             set0 = requests[0].commitSet();
690             set1 = requests[1].commitSet();
691             assert.deepEqual(requests[2].commitSet(), set0);
692             assert.deepEqual(requests[3].commitSet(), set1);
693             assert.deepEqual(set0.repositories(), [webkit]);
694             assert.deepEqual(set0.customRoots(), []);
695             assert.deepEqual(set1.repositories(), [webkit]);
696             assert.deepEqual(set1.customRoots(), []);
697             assert.equal(set0.revisionForRepository(webkit), '191622');
698             assert.equal(set1.revisionForRepository(webkit), '192736');
699         });
700     });
701 });