Add UI for A/B testing on owned commits.
[WebKit-https.git] / Websites / perf.webkit.org / unit-tests / commit-set-tests.js
1 "use strict";
2
3 const assert = require('assert');
4 require('../tools/js/v3-models.js');
5 const MockModels = require('./resources/mock-v3-models.js').MockModels;
6 const MockRemoteAPI = require('../unit-tests/resources/mock-remote-api.js').MockRemoteAPI;
7
8 function createPatch()
9 {
10     return new UploadedFile(453, {'createdAt': new Date('2017-05-01T19:16:53Z'), 'filename': 'patch.dat', 'extension': '.dat', 'author': 'some user',
11         size: 534637, sha256: '169463c8125e07c577110fe144ecd63942eb9472d438fc0014f474245e5df8a1'});
12 }
13
14 function createRoot()
15 {
16     return new UploadedFile(456, {'createdAt': new Date('2017-05-01T21:03:27Z'), 'filename': 'root.dat', 'extension': '.dat', 'author': 'some user',
17         size: 16452234, sha256: '03eed7a8494ab8794c44b7d4308e55448fc56f4d6c175809ba968f78f656d58d'});
18 }
19
20 function customCommitSetWithoutOwnedCommit()
21 {
22     const customCommitSet = new CustomCommitSet;
23     customCommitSet.setRevisionForRepository(MockModels.osx, '10.11.4 15E65');
24     customCommitSet.setRevisionForRepository(MockModels.webkit, '200805');
25     return customCommitSet;
26 }
27
28 function customCommitSetWithOwnedCommit()
29 {
30     const customCommitSet = new CustomCommitSet;
31     customCommitSet.setRevisionForRepository(MockModels.osx, '10.11.4 15E65');
32     customCommitSet.setRevisionForRepository(MockModels.ownerRepository, 'OwnerRepository-r0');
33     customCommitSet.setRevisionForRepository(MockModels.ownedRepository, 'OwnedRepository-r0', null, 'OwnerRepository-r0');
34     return customCommitSet;
35 }
36
37 function customCommitSetWithPatch()
38 {
39     const customCommitSet = new CustomCommitSet;
40     const patch = createPatch();
41     customCommitSet.setRevisionForRepository(MockModels.osx, '10.11.4 15E65');
42     customCommitSet.setRevisionForRepository(MockModels.webkit, '200805', patch);
43     return customCommitSet;
44 }
45
46 function customCommitSetWithOwnedRepositoryHasSameNameAsNotOwnedRepository()
47 {
48     const customCommitSet = new CustomCommitSet;
49     customCommitSet.setRevisionForRepository(MockModels.osx, '10.11.4 15E65');
50     customCommitSet.setRevisionForRepository(MockModels.webkit, '200805');
51     customCommitSet.setRevisionForRepository(MockModels.ownedWebkit, 'owned-200805', null, '10.11.4 15E65');
52     return customCommitSet;
53 }
54
55 function ownerCommit()
56 {
57     return new CommitLog(5, {
58         repository: MockModels.ownerRepository,
59         revision: 'owner-commit-0',
60         ownsCommits: true,
61         time: null,
62     });
63 }
64
65 function partialOwnerCommit()
66 {
67     return new CommitLog(5, {
68         repository: MockModels.ownerRepository,
69         revision: 'owner-commit-0',
70         ownsCommits: null,
71         time: +(new Date('2016-05-13T00:55:57.841344Z')),
72     });
73 }
74
75 function ownedCommit()
76 {
77     return new CommitLog(6, {
78         repository: MockModels.ownedRepository,
79         revision: 'owned-commit-0',
80         ownsCommits: null,
81         time: 1456932774000
82     });
83 }
84
85 function webkitCommit()
86 {
87     return new CommitLog(2017, {
88         repository: MockModels.webkit,
89         revision: 'webkit-commit-0',
90         ownsCommits: false,
91         time: 1456932773000
92     });
93 }
94
95 describe('IntermediateCommitSet', () => {
96     MockRemoteAPI.inject();
97     MockModels.inject();
98
99     describe('setCommitForRepository', () => {
100         it('should allow set commit for owner repository', () => {
101             const commitSet = new IntermediateCommitSet(new CommitSet);
102             const commit = ownerCommit();
103             commitSet.setCommitForRepository(MockModels.ownerRepository, commit);
104             assert.equal(commit, commitSet.commitForRepository(MockModels.ownerRepository));
105         });
106
107         it('should allow set commit for owned repository', () => {
108             const commitSet = new IntermediateCommitSet(new CommitSet);
109             const commit = ownerCommit();
110
111             const fetchingPromise = commit.fetchOwnedCommits();
112             const requests = MockRemoteAPI.requests;
113             assert.equal(requests.length, 1);
114             assert.equal(requests[0].url, '../api/commits/111/owned-commits?owner-revision=owner-commit-0');
115             assert.equal(requests[0].method, 'GET');
116
117             requests[0].resolve({commits: [{
118                 id: 233,
119                 repository: MockModels.ownedRepository.id(),
120                 revision: '6f8b0dbbda95a440503b88db1dd03dad3a7b07fb',
121                 time: +(new Date('2016-05-13T00:55:57.841344Z')),
122             }]});
123
124             return fetchingPromise.then(() => {
125                 const ownedCommit = commit.ownedCommits()[0];
126                 commitSet.setCommitForRepository(MockModels.ownerRepository, commit);
127                 commitSet.setCommitForRepository(MockModels.ownedRepository, ownedCommit);
128                 assert.equal(commit, commitSet.commitForRepository(MockModels.ownerRepository));
129                 assert.equal(ownedCommit, commitSet.commitForRepository(MockModels.ownedRepository));
130                 assert.deepEqual(commitSet.repositories(), [MockModels.ownerRepository, MockModels.ownedRepository]);
131             });
132         });
133     });
134
135     describe('fetchCommitLogs', () => {
136
137         it('should fetch CommitLog object with owned commits information',  () => {
138             const commit = partialOwnerCommit();
139             assert.equal(commit.ownsCommits(), null);
140             const owned = ownedCommit();
141
142             const commitSet = CommitSet.ensureSingleton('53246456', {revisionItems: [{commit}, {commit: owned, ownerCommit: commit}]});
143             const intermediateCommitSet =new IntermediateCommitSet(commitSet);
144             const fetchingPromise = intermediateCommitSet.fetchCommitLogs();
145
146             const requests = MockRemoteAPI.requests;
147             assert.equal(requests.length, 2);
148             assert.equal(requests[0].url, '/api/commits/111/owner-commit-0');
149             assert.equal(requests[0].method, 'GET');
150             assert.equal(requests[1].url, '/api/commits/112/owned-commit-0');
151             assert.equal(requests[1].method, 'GET');
152
153             requests[0].resolve({commits: [{
154                 id: 5,
155                 repository: MockModels.ownerRepository,
156                 revision: 'owner-commit-0',
157                 ownsCommits: true,
158                 time: +(new Date('2016-05-13T00:55:57.841344Z')),
159             }]});
160             requests[1].resolve({commits: [{
161                 id: 6,
162                 repository: MockModels.ownedRepository,
163                 revision: 'owned-commit-0',
164                 ownsCommits: false,
165                 time: 1456932774000,
166             }]});
167
168             return MockRemoteAPI.waitForRequest().then(() => {
169                 assert.equal(requests.length, 3);
170                 assert.equal(requests[2].url, '../api/commits/111/owned-commits?owner-revision=owner-commit-0');
171                 assert.equal(requests[2].method, 'GET');
172
173                 requests[2].resolve({commits: [{
174                     id: 6,
175                     repository: MockModels.ownedRepository.id(),
176                     revision: 'owned-commit-0',
177                     ownsCommits: false,
178                     time: 1456932774000,
179                 }]});
180                 return fetchingPromise;
181             }).then(() => {
182                 assert(commit.ownsCommits());
183                 assert.equal(commit.ownedCommits().length, 1);
184                 assert.equal(commit.ownedCommits()[0], owned);
185                 assert.equal(owned.ownerCommit(), commit);
186                 assert.equal(owned.repository(), MockModels.ownedRepository);
187                 assert.equal(intermediateCommitSet.commitForRepository(MockModels.ownedRepository), owned);
188                 assert.equal(intermediateCommitSet.ownerCommitForRepository(MockModels.ownedRepository), commit);
189                 assert.deepEqual(intermediateCommitSet.repositories(), [MockModels.ownerRepository, MockModels.ownedRepository]);
190             });
191         });
192     });
193
194     describe('updateRevisionForOwnerRepository', () => {
195
196         it('should update CommitSet based on the latest invocation', () => {
197             const commitSet = new IntermediateCommitSet(new CommitSet);
198             const firstUpdatePromise = commitSet.updateRevisionForOwnerRepository(MockModels.webkit, 'webkit-commit-0');
199             const secondUpdatePromise = commitSet.updateRevisionForOwnerRepository(MockModels.webkit, 'webkit-commit-1');
200             const requests = MockRemoteAPI.requests;
201
202             assert(requests.length, 2);
203             assert.equal(requests[0].url, '/api/commits/11/webkit-commit-0');
204             assert.equal(requests[0].method, 'GET');
205             assert.equal(requests[1].url, '/api/commits/11/webkit-commit-1');
206             assert.equal(requests[1].method, 'GET');
207
208             requests[1].resolve({commits: [{
209                 id: 2018,
210                 repository: MockModels.webkit.id(),
211                 revision: 'webkit-commit-1',
212                 ownsCommits: false,
213                 time: 1456932774000,
214             }]});
215
216             let commit = null;
217             return secondUpdatePromise.then(() => {
218                 commit = commitSet.commitForRepository(MockModels.webkit);
219
220                 requests[0].resolve({commits: [{
221                     id: 2017,
222                     repository: MockModels.webkit.id(),
223                     revision: 'webkit-commit-0',
224                     ownsCommits: false,
225                     time: 1456932773000,
226                 }]});
227
228                 assert.equal(commit.revision(), 'webkit-commit-1');
229                 assert.equal(commit.id(), 2018);
230
231                 return firstUpdatePromise;
232             }).then(() => {
233                 const currentCommit = commitSet.commitForRepository(MockModels.webkit);
234                 assert.equal(commit, currentCommit);
235             });
236         });
237
238     });
239
240     describe('removeCommitForRepository', () => {
241         it('should remove owned commits when owner commit is removed', () => {
242             const commitSet = new IntermediateCommitSet(new CommitSet);
243             const commit = ownerCommit();
244
245             const fetchingPromise = commit.fetchOwnedCommits();
246             const requests = MockRemoteAPI.requests;
247             assert.equal(requests.length, 1);
248             assert.equal(requests[0].url, '../api/commits/111/owned-commits?owner-revision=owner-commit-0');
249             assert.equal(requests[0].method, 'GET');
250
251             requests[0].resolve({commits: [{
252                 id: 233,
253                 repository: MockModels.ownedRepository.id(),
254                 revision: '6f8b0dbbda95a440503b88db1dd03dad3a7b07fb',
255                 ownsCommits: true
256             }]});
257
258             return fetchingPromise.then(() => {
259                 commitSet.setCommitForRepository(MockModels.ownerRepository, commit);
260                 commitSet.setCommitForRepository(MockModels.ownedRepository, commit.ownedCommits()[0]);
261                 commitSet.removeCommitForRepository(MockModels.ownerRepository);
262                 assert.deepEqual(commitSet.repositories(), []);
263             });
264         });
265
266         it('should not remove owner commits when owned commit is removed', () => {
267             const commitSet = new IntermediateCommitSet(new CommitSet);
268             const commit = ownerCommit();
269
270             const fetchingPromise = commit.fetchOwnedCommits();
271             const requests = MockRemoteAPI.requests;
272             assert.equal(requests.length, 1);
273             assert.equal(requests[0].url, '../api/commits/111/owned-commits?owner-revision=owner-commit-0');
274             assert.equal(requests[0].method, 'GET');
275
276             requests[0].resolve({commits: [{
277                 id: 233,
278                 repository: MockModels.ownedRepository.id(),
279                 revision: '6f8b0dbbda95a440503b88db1dd03dad3a7b07fb',
280                 time: +(new Date('2016-05-13T00:55:57.841344Z')),
281             }]});
282
283             return fetchingPromise.then(() => {
284                 commitSet.setCommitForRepository(MockModels.ownerRepository, commit);
285                 commitSet.setCommitForRepository(MockModels.ownedRepository, commit.ownedCommits()[0]);
286                 commitSet.removeCommitForRepository(MockModels.ownedRepository);
287                 assert.deepEqual(commitSet.repositories(), [MockModels.ownerRepository]);
288             });
289         });
290
291         it('should not update commit set for repository if removeCommitForRepository called before updateRevisionForOwnerRepository finishes', () => {
292             const commitSet = new IntermediateCommitSet(new CommitSet);
293             const commit = webkitCommit();
294             commitSet.setCommitForRepository(MockModels.webkit, commit);
295             const updatePromise = commitSet.updateRevisionForOwnerRepository(MockModels.webkit, 'webkit-commit-1');
296
297             commitSet.removeCommitForRepository(MockModels.webkit);
298
299             const requests = MockRemoteAPI.requests;
300             assert.equal(requests[0].url, '/api/commits/11/webkit-commit-1');
301             assert.equal(requests[0].method, 'GET');
302
303             requests[0].resolve({commits: [{
304                 id: 2018,
305                 repository: MockModels.webkit.id(),
306                 revision: 'webkit-commit-1',
307                 ownsCommits: false,
308                 time: 1456932774000,
309             }]});
310
311             return updatePromise.then(() => {
312                 assert.deepEqual(commitSet.repositories(), []);
313                 assert(!commitSet.commitForRepository(MockModels.webkit));
314             });
315         });
316
317     });
318
319 });
320
321 describe('CustomCommitSet', () => {
322     MockModels.inject();
323
324     describe('Test custom commit set without owned commit', () => {
325         it('should have right revision for a given repository', () => {
326             const commitSet = customCommitSetWithoutOwnedCommit();
327             assert.equal(commitSet.revisionForRepository(MockModels.osx), '10.11.4 15E65');
328             assert.equal(commitSet.revisionForRepository(MockModels.webkit), '200805');
329         });
330
331         it('should have no patch for any repository', () => {
332             const commitSet = customCommitSetWithoutOwnedCommit();
333             assert.equal(commitSet.patchForRepository(MockModels.osx), null);
334             assert.equal(commitSet.patchForRepository(MockModels.webkit), null);
335         });
336
337         it('should have no owner revision for a given repository', () => {
338             const commitSet = customCommitSetWithoutOwnedCommit();
339             assert.equal(commitSet.ownerRevisionForRepository(MockModels.osx), null);
340             assert.equal(commitSet.ownerRevisionForRepository(MockModels.webkit), null);
341         });
342
343         it('should return all repositories in it', () => {
344             const commitSet = customCommitSetWithoutOwnedCommit();
345             assert.deepEqual(commitSet.repositories(), [MockModels.osx, MockModels.webkit]);
346         });
347
348         it('should return only top level repositories', () => {
349             const commitSet = customCommitSetWithoutOwnedCommit();
350             assert.deepEqual(commitSet.topLevelRepositories(), [MockModels.osx, MockModels.webkit]);
351         });
352     });
353
354     describe('Test custom commit set with owned commit', () => {
355         it('should have right revision for a given repository', () => {
356             const commitSet = customCommitSetWithOwnedCommit();
357             assert.equal(commitSet.revisionForRepository(MockModels.osx), '10.11.4 15E65');
358             assert.equal(commitSet.revisionForRepository(MockModels.ownerRepository), 'OwnerRepository-r0');
359             assert.equal(commitSet.revisionForRepository(MockModels.ownedRepository), 'OwnedRepository-r0');
360         });
361
362         it('should have no patch for any repository', () => {
363             const commitSet = customCommitSetWithOwnedCommit();
364             assert.equal(commitSet.patchForRepository(MockModels.osx), null);
365             assert.equal(commitSet.patchForRepository(MockModels.ownerRepository), null);
366             assert.equal(commitSet.patchForRepository(MockModels.ownedRepository), null);
367         });
368
369         it('should have right owner revision for an owned repository', () => {
370             const commitSet = customCommitSetWithOwnedCommit();
371             assert.equal(commitSet.ownerRevisionForRepository(MockModels.osx), null);
372             assert.equal(commitSet.ownerRevisionForRepository(MockModels.ownerRepository), null);
373             assert.equal(commitSet.ownerRevisionForRepository(MockModels.ownedRepository), 'OwnerRepository-r0');
374         });
375
376         it('should return all repositories in it', () => {
377             const commitSet = customCommitSetWithOwnedCommit();
378             assert.deepEqual(commitSet.repositories(), [MockModels.osx, MockModels.ownerRepository, MockModels.ownedRepository]);
379         });
380
381         it('should return only top level repositories', () => {
382             const commitSet = customCommitSetWithOwnedCommit();
383             assert.deepEqual(commitSet.topLevelRepositories(), [MockModels.osx, MockModels.ownerRepository]);
384         });
385     });
386
387     describe('Test custom commit set with patch', () => {
388         it('should have right revision for a given repository', () => {
389             const commitSet = customCommitSetWithPatch();
390             assert.equal(commitSet.revisionForRepository(MockModels.osx), '10.11.4 15E65');
391             assert.equal(commitSet.revisionForRepository(MockModels.webkit), '200805');
392         });
393
394         it('should have a patch for a repository with patch specified', () => {
395             const commitSet = customCommitSetWithPatch();
396             assert.equal(commitSet.patchForRepository(MockModels.osx), null);
397             assert.deepEqual(commitSet.patchForRepository(MockModels.webkit), createPatch());
398         });
399
400         it('should have no owner revision for a given repository', () => {
401             const commitSet = customCommitSetWithPatch();
402             assert.equal(commitSet.ownerRevisionForRepository(MockModels.osx), null);
403             assert.equal(commitSet.ownerRevisionForRepository(MockModels.webkit), null);
404         });
405
406         it('should return all repositories in it', () => {
407             const commitSet = customCommitSetWithPatch();
408             assert.deepEqual(commitSet.repositories(), [MockModels.osx, MockModels.webkit]);
409         });
410
411         it('should return only top level repositories', () => {
412             const commitSet = customCommitSetWithPatch();
413             assert.deepEqual(commitSet.topLevelRepositories(), [MockModels.osx, MockModels.webkit]);
414         });
415     });
416
417     describe('Test custom commit set with owned repository has same name as non-owned repository',  () => {
418         it('should have right revision for a given repository', () => {
419             const commitSet = customCommitSetWithOwnedRepositoryHasSameNameAsNotOwnedRepository();
420             assert.equal(commitSet.revisionForRepository(MockModels.osx), '10.11.4 15E65');
421             assert.equal(commitSet.revisionForRepository(MockModels.webkit), '200805');
422             assert.equal(commitSet.revisionForRepository(MockModels.ownedWebkit), 'owned-200805');
423         });
424
425         it('should have no patch for any repository', () => {
426             const commitSet = customCommitSetWithOwnedRepositoryHasSameNameAsNotOwnedRepository();
427             assert.equal(commitSet.patchForRepository(MockModels.osx), null);
428             assert.equal(commitSet.patchForRepository(MockModels.webkit), null);
429             assert.equal(commitSet.patchForRepository(MockModels.ownedWebkit), null);
430         });
431
432         it('should have right owner revision for an owned repository', () => {
433             const commitSet = customCommitSetWithOwnedRepositoryHasSameNameAsNotOwnedRepository();
434             assert.equal(commitSet.ownerRevisionForRepository(MockModels.osx), null);
435             assert.equal(commitSet.ownerRevisionForRepository(MockModels.webkit), null);
436             assert.equal(commitSet.ownerRevisionForRepository(MockModels.ownedWebkit), '10.11.4 15E65');
437         });
438
439         it('should return all repositories in it', () => {
440             const commitSet = customCommitSetWithOwnedRepositoryHasSameNameAsNotOwnedRepository();
441             assert.deepEqual(commitSet.repositories(), [MockModels.osx, MockModels.webkit, MockModels.ownedWebkit]);
442         });
443
444         it('should return only top level repositories', () => {
445             const commitSet = customCommitSetWithOwnedRepositoryHasSameNameAsNotOwnedRepository();
446             assert.deepEqual(commitSet.topLevelRepositories(), [MockModels.osx, MockModels.webkit]);
447         });
448     });
449
450     describe('Test custom commit set equality function', () => {
451         it('should be equal to same custom commit set', () => {
452             assert.deepEqual(customCommitSetWithoutOwnedCommit(), customCommitSetWithoutOwnedCommit());
453             assert.deepEqual(customCommitSetWithOwnedCommit(), customCommitSetWithOwnedCommit());
454             assert.deepEqual(customCommitSetWithPatch(), customCommitSetWithPatch());
455             assert.deepEqual(customCommitSetWithOwnedRepositoryHasSameNameAsNotOwnedRepository(),
456                 customCommitSetWithOwnedRepositoryHasSameNameAsNotOwnedRepository());
457         });
458
459         it('should not be equal even if non-owned revisions are the same', () => {
460             const commitSet0 = customCommitSetWithoutOwnedCommit();
461             const commitSet1 = customCommitSetWithOwnedRepositoryHasSameNameAsNotOwnedRepository();
462             assert.equal(commitSet0.equals(commitSet1), false);
463         });
464     });
465
466     describe('Test custom commit set custom root operations', () => {
467         it('should return empty custom roots if no custom root specified', () => {
468             assert.deepEqual(customCommitSetWithoutOwnedCommit().customRoots(), []);
469         });
470
471         it('should return root if root is added into commit set', () => {
472             const commitSet = customCommitSetWithoutOwnedCommit();
473             commitSet.addCustomRoot(createRoot());
474             assert.deepEqual(commitSet.customRoots(), [createRoot()]);
475         });
476     });
477 });