Rewrite 'pull-os-versions' script in Javascript to add support for reporting os revis...
[WebKit.git] / Websites / perf.webkit.org / server-tests / api-report-commits-tests.js
1 'use strict';
2
3 const assert = require('assert');
4
5 const TestServer = require('./resources/test-server.js');
6 const addSlaveForReport = require('./resources/common-operations.js').addSlaveForReport;
7 const prepareServerTest = require('./resources/common-operations.js').prepareServerTest;
8
9 describe("/api/report-commits/", function () {
10     prepareServerTest(this);
11
12     const emptyReport = {
13         "slaveName": "someSlave",
14         "slavePassword": "somePassword",
15     };
16     const subversionCommit = {
17         "slaveName": "someSlave",
18         "slavePassword": "somePassword",
19         "commits": [
20             {
21                 "repository": "WebKit",
22                 "revision": "141977",
23                 "time": "2013-02-06T08:55:20.9Z",
24                 "author": {"name": "Commit Queue", "account": "commit-queue@webkit.org"},
25                 "message": "some message",
26             }
27         ],
28     };
29     const subversionInvalidCommit = {
30         "slaveName": "someSlave",
31         "slavePassword": "somePassword",
32         "commits": [
33             {
34                 "repository": "WebKit",
35                 "revision": "_141977",
36                 "time": "2013-02-06T08:55:20.9Z",
37                 "author": {"name": "Commit Queue", "account": "commit-queue@webkit.org"},
38                 "message": "some message",
39             }
40         ],
41     };
42     const subversionTwoCommits = {
43         "slaveName": "someSlave",
44         "slavePassword": "somePassword",
45         "commits": [
46             {
47                 "repository": "WebKit",
48                 "revision": "141977",
49                 "time": "2013-02-06T08:55:20.9Z",
50                 "author": {"name": "Commit Queue", "account": "commit-queue@webkit.org"},
51                 "message": "some message",
52             },
53             {
54                 "repository": "WebKit",
55                 "previousCommit": "141977",
56                 "revision": "141978",
57                 "time": "2013-02-06T09:54:56.0Z",
58                 "author": {"name": "Mikhail Pozdnyakov", "account": "mikhail.pozdnyakov@intel.com"},
59                 "message": "another message",
60             }
61         ]
62     };
63
64     const subversionInvalidPreviousCommit = {
65         "slaveName": "someSlave",
66         "slavePassword": "somePassword",
67         "commits": [
68             {
69                 "repository": "WebKit",
70                 "previousCommit": "99999",
71                 "revision": "12345",
72                 "time": "2013-02-06T08:55:20.9Z",
73                 "author": {"name": "Commit Queue", "account": "commit-queue@webkit.org"},
74                 "message": "some message",
75             }
76         ]
77     }
78
79     it("should reject error when slave name is missing", () => {
80         return TestServer.remoteAPI().postJSON('/api/report-commits/', {}).then((response) => {
81             assert.equal(response['status'], 'MissingSlaveName');
82         });
83     });
84
85     it("should reject when there are no slaves", () => {
86         return TestServer.remoteAPI().postJSON('/api/report-commits/', emptyReport).then((response) => {
87             assert.equal(response['status'], 'SlaveNotFound');
88             return TestServer.database().selectAll('commits');
89         }).then((rows) => {
90             assert.equal(rows.length, 0);
91         });
92     });
93
94     it("should accept an empty report", () => {
95         return addSlaveForReport(emptyReport).then(() => {
96             return TestServer.remoteAPI().postJSON('/api/report-commits/', emptyReport);
97         }).then((response) => {
98             assert.equal(response['status'], 'OK');
99         });
100     });
101
102     it("should add a missing repository", () => {
103         return addSlaveForReport(subversionCommit).then(() => {
104             return TestServer.remoteAPI().postJSON('/api/report-commits/', subversionCommit);
105         }).then((response) => {
106             assert.equal(response['status'], 'OK');
107             return TestServer.database().selectAll('repositories');
108         }).then((rows) => {
109             assert.equal(rows.length, 1);
110             assert.equal(rows[0]['name'], subversionCommit.commits[0]['repository']);
111         });
112     });
113
114     it("should store a commit from a valid slave", () => {
115         return addSlaveForReport(subversionCommit).then(() => {
116             return TestServer.remoteAPI().postJSON('/api/report-commits/', subversionCommit);
117         }).then((response) => {
118             assert.equal(response['status'], 'OK');
119             const db = TestServer.database();
120             return Promise.all([db.selectAll('commits'), db.selectAll('committers')]);
121         }).then((result) => {
122             let commits = result[0];
123             let committers = result[1];
124             let reportedData = subversionCommit.commits[0];
125
126             assert.equal(commits.length, 1);
127             assert.equal(committers.length, 1);
128             assert.equal(commits[0]['revision'], reportedData['revision']);
129             assert.equal(commits[0]['time'].toString(), new Date('2013-02-06 08:55:20.9').toString());
130             assert.equal(commits[0]['message'], reportedData['message']);
131             assert.equal(commits[0]['committer'], committers[0]['id']);
132             assert.equal(committers[0]['name'], reportedData['author']['name']);
133             assert.equal(committers[0]['account'], reportedData['author']['account']);
134         });
135     });
136
137     it("should reject an invalid revision number", () => {
138         return addSlaveForReport(subversionCommit).then(() => {
139             return TestServer.remoteAPI().postJSON('/api/report-commits/', subversionInvalidCommit);
140         }).then((response) => {
141             assert.equal(response['status'], 'InvalidRevision');
142             return TestServer.database().selectAll('commits');
143         }).then((rows) => {
144             assert.equal(rows.length, 0);
145         });
146     });
147
148     it("should store two commits from a valid slave", () => {
149         return addSlaveForReport(subversionTwoCommits).then(() => {
150             return TestServer.remoteAPI().postJSON('/api/report-commits/', subversionTwoCommits);
151         }).then((response) => {
152             assert.equal(response['status'], 'OK');
153             const db = TestServer.database();
154             return Promise.all([db.selectAll('commits'), db.selectAll('committers')]);
155         }).then((result) => {
156             const commits = result[0];
157             const committers = result[1];
158             assert.equal(commits.length, 2);
159             assert.equal(committers.length, 2);
160
161             let reportedData = subversionTwoCommits.commits[0];
162             assert.equal(commits[0]['revision'], reportedData['revision']);
163             assert.equal(commits[0]['time'].toString(), new Date('2013-02-06 08:55:20.9').toString());
164             assert.equal(commits[0]['message'], reportedData['message']);
165             assert.equal(commits[0]['committer'], committers[0]['id']);
166             assert.equal(commits[0]['previous_commit'], null);
167             assert.equal(committers[0]['name'], reportedData['author']['name']);
168             assert.equal(committers[0]['account'], reportedData['author']['account']);
169
170             reportedData = subversionTwoCommits.commits[1];
171             assert.equal(commits[1]['revision'], reportedData['revision']);
172             assert.equal(commits[1]['time'].toString(), new Date('2013-02-06 09:54:56.0').toString());
173             assert.equal(commits[1]['message'], reportedData['message']);
174             assert.equal(commits[1]['committer'], committers[1]['id']);
175             assert.equal(commits[1]['previous_commit'], commits[0]['id']);
176             assert.equal(committers[1]['name'], reportedData['author']['name']);
177             assert.equal(committers[1]['account'], reportedData['author']['account']);
178         });
179     });
180
181     it("should fail if previous commit is invalid", () => {
182         return addSlaveForReport(subversionInvalidPreviousCommit).then(() => {
183             return TestServer.remoteAPI().postJSON('/api/report-commits/', subversionInvalidPreviousCommit);
184         }).then((response) => {
185             assert.equal(response['status'], 'FailedToFindPreviousCommit');
186             return TestServer.database().selectAll('commits');
187         }).then((result) => {
188             assert.equal(result.length, 0);
189         });
190     });
191
192     it("should update an existing commit if there is one", () => {
193         const db = TestServer.database();
194         const reportedData = subversionCommit.commits[0];
195         return addSlaveForReport(subversionCommit).then(() => {
196             return Promise.all([
197                 db.insert('repositories', {'id': 1, 'name': 'WebKit'}),
198                 db.insert('commits', {'repository': 1, 'revision': reportedData['revision'], 'time': reportedData['time']})
199             ]);
200         }).then(() => {
201             return TestServer.remoteAPI().postJSON('/api/report-commits/', subversionCommit);
202         }).then((response) => {
203             assert.equal(response['status'], 'OK');
204             return Promise.all([db.selectAll('commits'), db.selectAll('committers')]);
205         }).then((result) => {
206             const commits = result[0];
207             const committers = result[1];
208
209             assert.equal(commits.length, 1);
210             assert.equal(committers.length, 1);
211             assert.equal(commits[0]['message'], reportedData['message']);
212             assert.equal(commits[0]['committer'], committers[0]['id']);
213             assert.equal(committers[0]['name'], reportedData['author']['name']);
214             assert.equal(committers[0]['account'], reportedData['author']['account']);
215         });
216     });
217
218     it("should not update an unrelated commit", () => {
219         const db = TestServer.database();
220         const firstData = subversionTwoCommits.commits[0];
221         const secondData = subversionTwoCommits.commits[1];
222         return addSlaveForReport(subversionCommit).then(() => {
223             return Promise.all([
224                 db.insert('repositories', {'id': 1, 'name': 'WebKit'}),
225                 db.insert('commits', {'id': 2, 'repository': 1, 'revision': firstData['revision'], 'time': firstData['time']}),
226                 db.insert('commits', {'id': 3, 'repository': 1, 'revision': secondData['revision'], 'time': secondData['time']})
227             ]);
228         }).then(() => {
229             return TestServer.remoteAPI().postJSON('/api/report-commits/', subversionCommit);
230         }).then((response) => {
231             assert.equal(response['status'], 'OK');
232             return Promise.all([db.selectAll('commits'), db.selectAll('committers')]);
233         }).then((result) => {
234             const commits = result[0];
235             const committers = result[1];
236
237             assert.equal(commits.length, 2);
238             assert.equal(committers.length, 1);
239             assert.equal(commits[0]['id'], 2);
240             assert.equal(commits[0]['message'], firstData['message']);
241             assert.equal(commits[0]['committer'], committers[0]['id']);
242             assert.equal(committers[0]['name'], firstData['author']['name']);
243             assert.equal(committers[0]['account'], firstData['author']['account']);
244
245             assert.equal(commits[1]['id'], 3);
246             assert.equal(commits[1]['message'], null);
247             assert.equal(commits[1]['committer'], null);
248         });
249     });
250
251     it("should update an existing committer if there is one", () => {
252         const db = TestServer.database();
253         const author = subversionCommit.commits[0]['author'];
254         return addSlaveForReport(subversionCommit).then(() => {
255             return Promise.all([
256                 db.insert('repositories', {'id': 1, 'name': 'WebKit'}),
257                 db.insert('committers', {'repository': 1, 'account': author['account']}),
258             ]);
259         }).then(() => {
260             return TestServer.remoteAPI().postJSON('/api/report-commits/', subversionCommit);
261         }).then((response) => {
262             assert.equal(response['status'], 'OK');
263             return db.selectAll('committers');
264         }).then((committers) => {
265             assert.equal(committers.length, 1);
266             assert.equal(committers[0]['name'], author['name']);
267             assert.equal(committers[0]['account'], author['account']);
268         });
269     });
270
271     const sameRepositoryNameInSubCommitAndMajorCommit = {
272         "slaveName": "someSlave",
273         "slavePassword": "somePassword",
274         "commits": [
275             {
276                 "repository": "OSX",
277                 "revision": "Sierra16D32",
278                 "order": 1,
279                 "subCommits": {
280                     "WebKit": {
281                         "revision": "141978",
282                         "author": {"name": "Commit Queue", "account": "commit-queue@webkit.org"},
283                         "message": "WebKit Commit",
284                     },
285                     "JavaScriptCore": {
286                         "revision": "141978",
287                         "author": {"name": "Mikhail Pozdnyakov", "account": "mikhail.pozdnyakov@intel.com"},
288                         "message": "JavaScriptCore commit",
289                     }
290                 }
291             },
292             {
293                 "repository": "WebKit",
294                 "revision": "141978",
295                 "author": {"name": "Commit Queue", "account": "commit-queue@webkit.org"},
296                 "message": "WebKit Commit",
297             }
298         ]
299     }
300
301     it("should distinguish between repositories with the same name but with a different owner.", () => {
302         return addSlaveForReport(sameRepositoryNameInSubCommitAndMajorCommit).then(() => {
303             return TestServer.remoteAPI().postJSON('/api/report-commits/', sameRepositoryNameInSubCommitAndMajorCommit);
304         }).then((response) => {
305             assert.equal(response['status'], 'OK');
306             return TestServer.database().selectRows('repositories', {'name': 'WebKit'});
307         }).then((result) => {
308             assert.equal(result.length, 2);
309             let osWebKit = result[0];
310             let webkitRepository = result[1];
311             assert.notEqual(osWebKit.id, webkitRepository.id);
312             assert.equal(osWebKit.name, webkitRepository.name);
313             assert.equal(webkitRepository.owner, null);
314         });
315     });
316
317     const systemVersionCommitWithSubcommits = {
318         "slaveName": "someSlave",
319         "slavePassword": "somePassword",
320         "commits": [
321             {
322                 "repository": "OSX",
323                 "revision": "Sierra16D32",
324                 "order": 1,
325                 "subCommits": {
326                     "WebKit": {
327                         "revision": "141978",
328                         "author": {"name": "Commit Queue", "account": "commit-queue@webkit.org"},
329                         "message": "WebKit Commit",
330                     },
331                     "JavaScriptCore": {
332                         "revision": "141978",
333                         "author": {"name": "Mikhail Pozdnyakov", "account": "mikhail.pozdnyakov@intel.com"},
334                         "message": "JavaScriptCore commit",
335                     }
336                 }
337             }
338         ]
339     }
340
341     it("should accept inserting one commit with some sub commits", () => {
342         const db = TestServer.database();
343         return addSlaveForReport(systemVersionCommitWithSubcommits).then(() => {
344             return TestServer.remoteAPI().postJSON('/api/report-commits/', systemVersionCommitWithSubcommits);
345         }).then((response) => {
346             assert.equal(response['status'], 'OK');
347             return Promise.all([db.selectRows('commits', {'revision': 'Sierra16D32'}),
348                 db.selectRows('commits', {'message': 'WebKit Commit'}),
349                 db.selectRows('commits', {'message': 'JavaScriptCore commit'}),
350                 db.selectRows('repositories', {'name': 'OSX'}),
351                 db.selectRows('repositories', {'name': "WebKit"}),
352                 db.selectRows('repositories', {'name': 'JavaScriptCore'})])
353         }).then((result) => {
354             assert.equal(result.length, 6);
355
356             assert.equal(result[0].length, 1);
357             const osxCommit = result[0][0];
358             assert.notEqual(osxCommit, null);
359
360             assert.equal(result[1].length, 1);
361             const webkitCommit = result[1][0];
362             assert.notEqual(webkitCommit, null);
363
364             assert.equal(result[2].length, 1);
365             const jscCommit = result[2][0];
366             assert.notEqual(jscCommit, null);
367
368             assert.equal(result[3].length, 1);
369             const osxRepository = result[3][0];
370             assert.notEqual(osxRepository, null);
371
372             assert.equal(result[4].length, 1);
373             const webkitRepository = result[4][0];
374             assert.notEqual(webkitRepository, null);
375
376             assert.equal(result[5].length, 1);
377             const jscRepository = result[5][0];
378             assert.notEqual(jscRepository, null);
379
380             assert.equal(osxCommit.repository, osxRepository.id);
381             assert.equal(webkitCommit.repository, webkitRepository.id);
382             assert.equal(jscCommit.repository, jscRepository.id);
383             assert.equal(osxRepository.owner, null);
384             assert.equal(webkitRepository.owner, osxRepository.id);
385             assert.equal(jscRepository.owner, osxRepository.id);
386
387             return Promise.all([db.selectRows('commit_ownerships', {'owner': osxCommit.id, 'owned': webkitCommit.id}, {'sortBy': 'owner'}),
388                 db.selectRows('commit_ownerships', {'owner': osxCommit.id, 'owned': jscCommit.id}, {'sortBy': 'owner'}),
389                 db.selectRows('commits', {'repository': webkitRepository.id})]);
390         }).then((result) => {
391             assert.equal(result.length, 3);
392
393             assert.equal(result[0].length, 1);
394             const ownerCommitForWebKitCommit = result[0][0];
395             assert.notEqual(ownerCommitForWebKitCommit, null);
396
397             assert.equal(result[1].length, 1);
398             const ownerCommitForJSCCommit =  result[1][0];
399             assert.notEqual(ownerCommitForJSCCommit, null);
400
401             assert.equal(result[2].length, 1);
402         });
403     })
404
405     const multipleSystemVersionCommitsWithSubcommits = {
406         "slaveName": "someSlave",
407         "slavePassword": "somePassword",
408         "commits": [
409             {
410                 "repository": "OSX",
411                 "revision": "Sierra16D32",
412                 "order": 2,
413                 "subCommits": {
414                     "WebKit": {
415                         "revision": "141978",
416                         "author": {"name": "Commit Queue", "account": "commit-queue@webkit.org"},
417                         "message": "WebKit Commit",
418                     },
419                     "JavaScriptCore": {
420                         "revision": "141978",
421                         "author": {"name": "Mikhail Pozdnyakov", "account": "mikhail.pozdnyakov@intel.com"},
422                         "message": "JavaScriptCore commit",
423                     }
424                 }
425             },
426             {
427                 "repository": "OSX",
428                 "revision": "Sierra16C67",
429                 "order": 1,
430                 "subCommits": {
431                     "WebKit": {
432                         "revision": "141978",
433                         "author": {"name": "Commit Queue", "account": "commit-queue@webkit.org"},
434                         "message": "WebKit Commit",
435                     },
436                     "JavaScriptCore": {
437                         "revision": "141999",
438                         "author": {"name": "Mikhail Pozdnyakov", "account": "mikhail.pozdnyakov@intel.com"},
439                         "message": "new JavaScriptCore commit",
440                     }
441                 }
442             }
443         ]
444     };
445
446     it("should accept inserting multiple commits with multiple sub-commits", () => {
447         const db = TestServer.database();
448         return addSlaveForReport(multipleSystemVersionCommitsWithSubcommits).then(() => {
449             return TestServer.remoteAPI().postJSON('/api/report-commits/', multipleSystemVersionCommitsWithSubcommits);
450         }).then((response) => {
451             assert.equal(response['status'], 'OK');
452             return Promise.all([db.selectRows('commits', {'revision': 'Sierra16D32'}),
453                 db.selectRows('commits', {'revision': 'Sierra16C67'}),
454                 db.selectRows('commits', {'message': 'WebKit Commit'}),
455                 db.selectRows('commits', {'message': 'JavaScriptCore commit'}),
456                 db.selectRows('commits', {'message': 'new JavaScriptCore commit'}),
457                 db.selectRows('repositories', {'name': 'OSX'}),
458                 db.selectRows('repositories', {'name': "WebKit"}),
459                 db.selectRows('repositories', {'name': 'JavaScriptCore'})])
460         }).then((result) => {
461             assert.equal(result.length, 8);
462
463             assert.equal(result[0].length, 1);
464             const osxCommit0 = result[0][0];
465             assert.notEqual(osxCommit0, null);
466
467             assert.equal(result[1].length, 1);
468             const osxCommit1 = result[1][0];
469             assert.notEqual(osxCommit1, null);
470
471             assert.equal(result[2].length, 1);
472             const webkitCommit = result[2][0];
473             assert.notEqual(webkitCommit, null);
474
475             assert.equal(result[3].length, 1);
476             const jscCommit0 = result[3][0];
477             assert.notEqual(jscCommit0, null);
478
479             assert.equal(result[4].length, 1);
480             const jscCommit1 = result[4][0];
481             assert.notEqual(jscCommit1, null);
482
483             assert.equal(result[5].length, 1)
484             const osxRepository = result[5][0];
485             assert.notEqual(osxRepository, null);
486             assert.equal(osxRepository.owner, null);
487
488             assert.equal(result[6].length, 1)
489             const webkitRepository = result[6][0];
490             assert.equal(webkitRepository.owner, osxRepository.id);
491
492             assert.equal(result[7].length, 1);
493             const jscRepository = result[7][0];
494             assert.equal(jscRepository.owner, osxRepository.id);
495
496             assert.equal(osxCommit0.repository, osxRepository.id);
497             assert.equal(osxCommit1.repository, osxRepository.id);
498             assert.equal(webkitCommit.repository, webkitRepository.id);
499             assert.equal(jscCommit0.repository, jscRepository.id);
500             assert.equal(jscCommit1.repository, jscRepository.id);
501             assert.equal(osxRepository.owner, null);
502             assert.equal(webkitRepository.owner, osxRepository.id);
503             assert.equal(jscRepository.owner, osxRepository.id);
504
505             return Promise.all([db.selectRows('commit_ownerships', {'owner': osxCommit0.id, 'owned': webkitCommit.id}, {'sortBy': 'owner'}),
506                 db.selectRows('commit_ownerships', {'owner': osxCommit1.id, 'owned': webkitCommit.id}, {'sortBy': 'owner'}),
507                 db.selectRows('commit_ownerships', {'owner': osxCommit0.id, 'owned': jscCommit0.id}, {'sortBy': 'owner'}),
508                 db.selectRows('commit_ownerships', {'owner': osxCommit1.id, 'owned': jscCommit1.id}, {'sortBy': 'owner'}),
509                 db.selectRows('commits', {'repository': webkitRepository.id})]);
510         }).then((result) => {
511             assert.equal(result.length, 5);
512
513             assert.equal(result[0].length, 1);
514             const ownerCommitForWebKitCommit0 = result[0][0];
515             assert.notEqual(ownerCommitForWebKitCommit0, null);
516
517             assert.equal(result[1].length, 1);
518             const ownerCommitForWebKitCommit1 = result[1][0];
519             assert.notEqual(ownerCommitForWebKitCommit1, null);
520
521             assert.equal(result[2].length, 1);
522             const ownerCommitForJSCCommit0 = result[2][0];
523             assert.notEqual(ownerCommitForJSCCommit0, null);
524
525             assert.equal(result[3].length, 1);
526             const ownerCommitForJSCCommit1 = result[3][0];
527             assert.notEqual(ownerCommitForJSCCommit1, null);
528
529             assert.equal(result[4].length, 1);
530         });
531     });
532
533     const systemVersionCommitWithEmptySubcommits = {
534         "slaveName": "someSlave",
535         "slavePassword": "somePassword",
536         "commits": [
537             {
538                 "repository": "OSX",
539                 "revision": "Sierra16D32",
540                 "order": 1,
541                 "subCommits": {
542                 }
543             }
544         ]
545     }
546
547     it("should accept inserting one commit with no sub commits", () => {
548         return addSlaveForReport(systemVersionCommitWithEmptySubcommits).then(() => {
549             return TestServer.remoteAPI().postJSON('/api/report-commits/', systemVersionCommitWithEmptySubcommits);
550         }).then((response) => {
551             assert.equal(response['status'], 'OK');
552             const db = TestServer.database();
553             return Promise.all([db.selectAll('commits'), db.selectAll('repositories'), db.selectAll('commit_ownerships', 'owner')]);
554         }).then((result) => {
555             let commits = result[0];
556             let repositories = result[1];
557             let commit_ownerships = result[2];
558             assert.equal(commits.length, 1);
559             assert.equal(repositories.length, 1);
560             assert.equal(commits[0].repository, repositories[0].id);
561             assert.equal(repositories[0].name, 'OSX');
562             assert.equal(commit_ownerships.length, 0);
563         });
564     });
565
566     const systemVersionCommitAndSubcommitWithTimestamp = {
567         "slaveName": "someSlave",
568         "slavePassword": "somePassword",
569         "commits": [
570             {
571                 "repository": "OSX",
572                 "revision": "Sierra16D32",
573                 "order": 1,
574                 "subCommits": {
575                     "WebKit": {
576                         "revision": "141978",
577                         "time": "2013-02-06T08:55:20.9Z",
578                         "author": {"name": "Commit Queue", "account": "commit-queue@webkit.org"},
579                         "message": "WebKit Commit",
580                     }
581                 }
582             }
583         ]
584     }
585
586     it("should reject inserting one commit with sub commits that contains timestamp", () => {
587         return addSlaveForReport(systemVersionCommitAndSubcommitWithTimestamp).then(() => {
588             return TestServer.remoteAPI().postJSON('/api/report-commits/', systemVersionCommitAndSubcommitWithTimestamp);
589         }).then((response) => {
590             assert.equal(response['status'], 'SubCommitShouldNotContainTimestamp');
591         });
592     });
593 });