Add cache for CommitLog objects to avoid refetching same commit.
[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 BrowserPrivilegedAPI = require('../public/v3/privileged-api.js').PrivilegedAPI;
6 const MockModels = require('./resources/mock-v3-models.js').MockModels;
7 const MockRemoteAPI = require('../unit-tests/resources/mock-remote-api.js').MockRemoteAPI;
8
9 function createPatch()
10 {
11     return UploadedFile.ensureSingleton(453, {'createdAt': new Date('2017-05-01T19:16:53Z'), 'filename': 'patch.dat', 'extension': '.dat', 'author': 'some user',
12         size: 534637, sha256: '169463c8125e07c577110fe144ecd63942eb9472d438fc0014f474245e5df8a1'});
13 }
14
15 function createAnotherPatch()
16 {
17     return UploadedFile.ensureSingleton(454, {'createdAt': new Date('2017-05-01T19:16:53Z'), 'filename': 'patch.dat', 'extension': '.dat', 'author': 'some user',
18         size: 534611, sha256: '169463c8125e07c577110fe144ecd63942eb9472d438fc0014f474245e5dfaaa'});
19 }
20
21 function createRoot()
22 {
23     return UploadedFile.ensureSingleton(456, {'createdAt': new Date('2017-05-01T21:03:27Z'), 'filename': 'root.dat', 'extension': '.dat', 'author': 'some user',
24         size: 16452234, sha256: '03eed7a8494ab8794c44b7d4308e55448fc56f4d6c175809ba968f78f656d58d'});
25 }
26
27 function createAnotherRoot()
28 {
29     return UploadedFile.ensureSingleton(457, {'createdAt': new Date('2017-05-01T21:03:27Z'), 'filename': 'root.dat', 'extension': '.dat', 'author': 'some user',
30         size: 16452111, sha256: '03eed7a8494ab8794c44b7d4308e55448fc56f4d6c175809ba968f78f656dbbb'});
31 }
32
33 function createSharedRoot()
34 {
35     return UploadedFile.ensureSingleton(458, {'createdAt': new Date('2017-05-01T22:03:27Z'), 'filename': 'root.dat', 'extension': '.dat', 'author': 'some user',
36         size: 16452111, sha256: '03eed7a8494ab8794c44b7d4308e55448fc56f4aac175809ba968f78f656dbbb'});
37 }
38
39 function customCommitSetWithoutOwnedCommit()
40 {
41     const customCommitSet = new CustomCommitSet;
42     customCommitSet.setRevisionForRepository(MockModels.osx, '10.11.4 15E65');
43     customCommitSet.setRevisionForRepository(MockModels.webkit, '200805');
44     return customCommitSet;
45 }
46
47 function customCommitSetWithOwnedCommit()
48 {
49     const customCommitSet = new CustomCommitSet;
50     customCommitSet.setRevisionForRepository(MockModels.osx, '10.11.4 15E65');
51     customCommitSet.setRevisionForRepository(MockModels.ownerRepository, 'OwnerRepository-r0');
52     customCommitSet.setRevisionForRepository(MockModels.ownedRepository, 'OwnedRepository-r0', null, 'OwnerRepository-r0');
53     return customCommitSet;
54 }
55
56 function customCommitSetWithPatch()
57 {
58     const customCommitSet = new CustomCommitSet;
59     const patch = createPatch();
60     customCommitSet.setRevisionForRepository(MockModels.osx, '10.11.4 15E65');
61     customCommitSet.setRevisionForRepository(MockModels.webkit, '200805', patch);
62     return customCommitSet;
63 }
64
65 function customCommitSetWithOwnedRepositoryHasSameNameAsNotOwnedRepository()
66 {
67     const customCommitSet = new CustomCommitSet;
68     customCommitSet.setRevisionForRepository(MockModels.osx, '10.11.4 15E65');
69     customCommitSet.setRevisionForRepository(MockModels.webkit, '200805');
70     customCommitSet.setRevisionForRepository(MockModels.ownedWebkit, 'owned-200805', null, '10.11.4 15E65');
71     return customCommitSet;
72 }
73
74 function ownerCommit()
75 {
76     return CommitLog.ensureSingleton(5, {
77         id: 5,
78         repository: MockModels.ownerRepository,
79         revision: 'owner-commit-0',
80         ownsCommits: true,
81         time: null,
82     });
83 }
84
85 function partialOwnerCommit()
86 {
87     return CommitLog.ensureSingleton(5, {
88         id: 5,
89         repository: MockModels.ownerRepository,
90         revision: 'owner-commit-0',
91         ownsCommits: null,
92         time: +(new Date('2016-05-13T00:55:57.841344Z')),
93     });
94 }
95
96 function ownedCommit()
97 {
98     return new CommitLog(6, {
99         id: 6,
100         repository: MockModels.ownedRepository,
101         revision: 'owned-commit-0',
102         ownsCommits: null,
103         time: 1456932774000
104     });
105 }
106
107 function webkitCommit()
108 {
109     return CommitLog.ensureSingleton(2017, {
110         id: 2017,
111         repository: MockModels.webkit,
112         revision: 'webkit-commit-0',
113         ownsCommits: false,
114         time: 1456932773000
115     });
116 }
117
118 function anotherWebKitCommit()
119 {
120     return CommitLog.ensureSingleton(2018, {
121         id: 2018,
122         repository: MockModels.webkit,
123         revision: 'webkit-commit-1',
124         ownsCommits: false,
125         time: 1456932773000
126     });
127 }
128
129 function commitWithSVNRevision()
130 {
131     return CommitLog.ensureSingleton(2019, {
132         id: 2019,
133         repository: MockModels.webkit,
134         revision: '12345',
135         ownsCommits: false,
136         time: 1456932773000
137     });
138 }
139
140 function anotherCommitWithSVNRevision()
141 {
142     return CommitLog.ensureSingleton(2020, {
143         id: 2020,
144         repository: MockModels.webkit,
145         revision: '45678',
146         ownsCommits: false,
147         time: 1456932773000
148     });
149 }
150
151 function commitWithGitRevision()
152 {
153     return CommitLog.ensureSingleton(2021, {
154         id: 2021,
155         repository: MockModels.webkitGit,
156         revision: '13a0590d34f26fda3953c42ff833132a1a6f6f5a',
157         ownsCommits: false,
158         time: 1456932773000
159     });
160 }
161
162 function anotherCommitWithGitRevision()
163 {
164     return CommitLog.ensureSingleton(2022, {
165         id: 2022,
166         repository: MockModels.webkitGit,
167         revision: '2f8dd3321d4f51c04f4e2019428ce9ffe97f1ef1',
168         ownsCommits: false,
169         time: 1456932773000
170     });
171 }
172
173 describe('CommitSet', () => {
174     MockRemoteAPI.inject(null, BrowserPrivilegedAPI);
175     MockModels.inject();
176
177     function oneCommitSet()
178     {
179         return CommitSet.ensureSingleton(1, {
180             revisionItems: [{ commit: webkitCommit(), requiresBuild: false }],
181             customRoots: []
182         });
183     }
184
185     function anotherCommitSet()
186     {
187         return CommitSet.ensureSingleton(2, {
188             revisionItems: [{ commit: webkitCommit(), requiresBuild: false }],
189             customRoots: []
190         });
191     }
192
193     function commitSetWithPatch()
194     {
195         return CommitSet.ensureSingleton(3, {
196             revisionItems: [{ commit: webkitCommit(), requiresBuild: false, patch: createPatch() }],
197             customRoots: []
198         });
199     }
200
201     function commitSetWithAnotherPatch()
202     {
203         return CommitSet.ensureSingleton(4, {
204             revisionItems: [{ commit: webkitCommit(), requiresBuild: false, patch: createAnotherPatch() }],
205             customRoots: []
206         });
207     }
208
209     function commitSetWithRoot()
210     {
211         return CommitSet.ensureSingleton(5, {
212             revisionItems: [{ commit: webkitCommit(), requiresBuild: false }],
213             customRoots: [createRoot()]
214         });
215     }
216
217     function anotherCommitSetWithRoot()
218     {
219         return CommitSet.ensureSingleton(6, {
220             revisionItems: [{ commit: webkitCommit(), requiresBuild: false }],
221             customRoots: [createAnotherRoot()]
222         });
223     }
224
225     function commitSetWithTwoRoots()
226     {
227         return CommitSet.ensureSingleton(7, {
228             revisionItems: [{ commit: webkitCommit(), requiresBuild: false }],
229             customRoots: [createRoot(), createSharedRoot()]
230         });
231     }
232
233     function commitSetWithAnotherWebKitCommit()
234     {
235         return CommitSet.ensureSingleton(8, {
236             revisionItems: [{ commit: anotherWebKitCommit(), requiresBuild: false }],
237             customRoots: []
238         });
239     }
240
241     function commitSetWithAnotherCommitPatchAndRoot()
242     {
243         return CommitSet.ensureSingleton(9, {
244             revisionItems: [{ commit: anotherWebKitCommit(), requiresBuild: true, patch: createPatch()}],
245             customRoots: [createRoot(), createSharedRoot()]
246         });
247     }
248
249     function commitSetWithSVNCommit()
250     {
251         return CommitSet.ensureSingleton(10, {
252             revisionItems: [{ commit: commitWithSVNRevision(), requiresBuild: false }],
253             customRoots: []
254         });
255     }
256
257     function anotherCommitSetWithSVNCommit()
258     {
259         return CommitSet.ensureSingleton(11, {
260             revisionItems: [{ commit: anotherCommitWithSVNRevision(), requiresBuild: false }],
261             customRoots: []
262         });
263     }
264
265     function commitSetWithGitCommit()
266     {
267         return CommitSet.ensureSingleton(12, {
268             revisionItems: [{ commit: commitWithGitRevision(), requiresBuild: false }],
269             customRoots: []
270         });
271     }
272
273     function anotherCommitSetWithGitCommit()
274     {
275         return CommitSet.ensureSingleton(13, {
276             revisionItems: [{ commit: anotherCommitWithGitRevision(), requiresBuild: false }],
277             customRoots: []
278         });
279     }
280
281     function commitSetWithTwoCommits()
282     {
283         return CommitSet.ensureSingleton(14, {
284             revisionItems: [{ commit: commitWithGitRevision(), requiresBuild: false }, { commit: commitWithSVNRevision(), requiresBuild: false }],
285             customRoots: []
286         });
287     }
288
289     function anotherCommitSetWithTwoCommits()
290     {
291         return CommitSet.ensureSingleton(15, {
292             revisionItems: [{ commit: anotherCommitWithGitRevision(), requiresBuild: false }, { commit: anotherCommitWithSVNRevision(), requiresBuild: false }],
293             customRoots: []
294         });
295     }
296
297     function oneMeasurementCommitSet()
298     {
299         return MeasurementCommitSet.ensureSingleton(1, [
300             [2017, 11, 'webkit-commit-0', null, 1456932773000]
301         ]);
302     }
303
304     describe('equals', () => {
305         it('should return false if patches for same repository are different', () => {
306             assert(!commitSetWithPatch().equals(commitSetWithAnotherPatch()));
307             assert(!commitSetWithAnotherPatch().equals(commitSetWithPatch()));
308         });
309
310         it('should return false if patch is only specified in one commit set', () => {
311             assert(!oneCommitSet().equals(commitSetWithPatch()));
312             assert(!commitSetWithPatch().equals(oneCommitSet()));
313         });
314
315         it('should return false if roots for same repository are different', () => {
316             assert(!commitSetWithRoot().equals(anotherCommitSetWithRoot()));
317             assert(!anotherCommitSetWithRoot().equals(commitSetWithRoot()));
318         });
319
320         it('should return false if root is only specified in one commit set', () => {
321             assert(!commitSetWithRoot().equals(oneCommitSet()));
322             assert(!oneCommitSet().equals(commitSetWithRoot()));
323         });
324
325         it('should return true when comparing two identical commit set', () => {
326             assert(oneCommitSet().equals(oneCommitSet()));
327             assert(anotherCommitSet().equals(anotherCommitSet()));
328             assert(commitSetWithPatch().equals(commitSetWithPatch()));
329             assert(commitSetWithAnotherPatch().equals(commitSetWithAnotherPatch()));
330             assert(oneMeasurementCommitSet().equals(oneMeasurementCommitSet()));
331             assert(commitSetWithRoot().equals(commitSetWithRoot()));
332             assert(anotherCommitSetWithRoot().equals(anotherCommitSetWithRoot()));
333         });
334
335         it('should be able to compare between CommitSet and MeasurementCommitSet', () => {
336             assert(oneCommitSet().equals(oneMeasurementCommitSet()));
337             assert(oneMeasurementCommitSet().equals(oneCommitSet()));
338         });
339     });
340
341     describe('containsRootOrPatchOrOwnedCommit', () => {
342         it('should return false if commit does not contain root, patch or owned commit', () => {
343             assert.ok(!oneCommitSet().containsRootOrPatchOrOwnedCommit());
344             assert.ok(!anotherCommitSet().containsRootOrPatchOrOwnedCommit());
345             assert.ok(!commitSetWithAnotherWebKitCommit().containsRootOrPatchOrOwnedCommit());
346             assert.ok(!commitSetWithSVNCommit().containsRootOrPatchOrOwnedCommit());
347             assert.ok(!anotherCommitSetWithSVNCommit().containsRootOrPatchOrOwnedCommit());
348             assert.ok(!commitSetWithGitCommit().containsRootOrPatchOrOwnedCommit());
349             assert.ok(!anotherCommitSetWithGitCommit().containsRootOrPatchOrOwnedCommit());
350             assert.ok(!commitSetWithTwoCommits().containsRootOrPatchOrOwnedCommit());
351             assert.ok(!anotherCommitSetWithTwoCommits().containsRootOrPatchOrOwnedCommit());
352             assert.ok(!oneMeasurementCommitSet().containsRootOrPatchOrOwnedCommit());
353         });
354
355         it('should return true if commit contains root, patch or owned commit', () => {
356             assert.ok(commitSetWithPatch().containsRootOrPatchOrOwnedCommit());
357             assert.ok(commitSetWithAnotherPatch().containsRootOrPatchOrOwnedCommit());
358             assert.ok(commitSetWithRoot().containsRootOrPatchOrOwnedCommit());
359             assert.ok(anotherCommitSetWithRoot().containsRootOrPatchOrOwnedCommit());
360             assert.ok(commitSetWithTwoRoots().containsRootOrPatchOrOwnedCommit());
361             assert.ok(commitSetWithAnotherCommitPatchAndRoot().containsRootOrPatchOrOwnedCommit());
362         });
363     });
364
365     describe('hasSameRepositories', () => {
366         it('should return true if two commit sets have same repositories', () => {
367             assert.ok(oneCommitSet().hasSameRepositories(anotherCommitSet()));
368             assert.ok(commitSetWithGitCommit().hasSameRepositories(anotherCommitSetWithGitCommit()));
369             assert.ok(oneCommitSet().hasSameRepositories(oneCommitSet()));
370         });
371
372         it('should return false if two commit sets have differen repositories', () => {
373             assert.ok(!commitSetWithGitCommit().hasSameRepositories(commitSetWithSVNCommit()));
374             assert.ok(!commitSetWithTwoCommits().hasSameRepositories(commitSetWithGitCommit()));
375         });
376     });
377
378     describe('diff',  () => {
379         it('should describe patch difference', () => {
380             assert.equal(CommitSet.diff(commitSetWithPatch(), commitSetWithAnotherPatch()), 'WebKit: patch.dat - patch.dat (2)');
381         });
382
383         it('should describe root difference', () => {
384             assert.equal(CommitSet.diff(commitSetWithRoot(), anotherCommitSetWithRoot()), 'Roots: root.dat - root.dat (2)');
385             assert.equal(CommitSet.diff(commitSetWithRoot(), commitSetWithTwoRoots()), 'Roots: none - root.dat');
386             assert.equal(CommitSet.diff(commitSetWithTwoRoots(), oneCommitSet()), 'Roots: root.dat, root.dat (2) - none');
387         });
388
389         it('should describe commit difference', () => {
390             assert.equal(CommitSet.diff(oneCommitSet(), commitSetWithAnotherWebKitCommit()), 'WebKit: webkit-commit-0 - webkit-commit-1');
391             assert.equal(CommitSet.diff(commitSetWithSVNCommit(), anotherCommitSetWithSVNCommit()), 'WebKit: r12345-r45678');
392             assert.equal(CommitSet.diff(commitSetWithGitCommit(), anotherCommitSetWithGitCommit()), 'WebKit-Git: 13a0590d..2f8dd332');
393             assert.equal(CommitSet.diff(commitSetWithTwoCommits(), anotherCommitSetWithTwoCommits()), 'WebKit: r12345-r45678 WebKit-Git: 13a0590d..2f8dd332');
394         });
395
396         it('should describe commit root and patch difference', () => {
397             assert.equal(CommitSet.diff(oneCommitSet(), commitSetWithAnotherCommitPatchAndRoot()), 'WebKit: webkit-commit-0 with none - webkit-commit-1 with patch.dat Roots: none - root.dat, root.dat (2)');
398         });
399     });
400
401     describe('revisionSetsFromCommitSets', () => {
402         it('should create revision sets from commit sets', () => {
403             assert.deepEqual(CommitSet.revisionSetsFromCommitSets([oneCommitSet(), commitSetWithRoot(), commitSetWithTwoRoots()]),
404                 [{'11': { revision: 'webkit-commit-0', ownerRevision: null, patch: null}},
405                     {'11': { revision: 'webkit-commit-0', ownerRevision: null, patch: null}, customRoots: [456]},
406                     {'11': { revision: 'webkit-commit-0', ownerRevision: null, patch: null}, customRoots: [456, 458]}]);
407         });
408     });
409 });
410
411 describe('IntermediateCommitSet', () => {
412     MockRemoteAPI.inject(null, BrowserPrivilegedAPI);
413     MockModels.inject();
414
415     describe('setCommitForRepository', () => {
416         it('should allow set commit for owner repository', () => {
417             const commitSet = new IntermediateCommitSet(new CommitSet);
418             const commit = ownerCommit();
419             commitSet.setCommitForRepository(MockModels.ownerRepository, commit);
420             assert.equal(commit, commitSet.commitForRepository(MockModels.ownerRepository));
421         });
422
423         it('should allow set commit for owned repository', () => {
424             const commitSet = new IntermediateCommitSet(new CommitSet);
425             const commit = ownerCommit();
426
427             const fetchingPromise = commit.fetchOwnedCommits();
428             const requests = MockRemoteAPI.requests;
429             assert.equal(requests.length, 1);
430             assert.equal(requests[0].url, '../api/commits/111/owned-commits?owner-revision=owner-commit-0');
431             assert.equal(requests[0].method, 'GET');
432
433             requests[0].resolve({commits: [{
434                 id: 233,
435                 repository: MockModels.ownedRepository.id(),
436                 revision: '6f8b0dbbda95a440503b88db1dd03dad3a7b07fb',
437                 time: +(new Date('2016-05-13T00:55:57.841344Z')),
438             }]});
439
440             return fetchingPromise.then(() => {
441                 const ownedCommit = commit.ownedCommits()[0];
442                 commitSet.setCommitForRepository(MockModels.ownerRepository, commit);
443                 commitSet.setCommitForRepository(MockModels.ownedRepository, ownedCommit);
444                 assert.equal(commit, commitSet.commitForRepository(MockModels.ownerRepository));
445                 assert.equal(ownedCommit, commitSet.commitForRepository(MockModels.ownedRepository));
446                 assert.deepEqual(commitSet.repositories(), [MockModels.ownerRepository, MockModels.ownedRepository]);
447             });
448         });
449     });
450
451     describe('fetchCommitLogs', () => {
452
453         it('should fetch CommitLog object with owned commits information',  () => {
454             const commit = partialOwnerCommit();
455             assert.equal(commit.ownsCommits(), null);
456             const owned = ownedCommit();
457
458             const commitSet = CommitSet.ensureSingleton('53246456', {revisionItems: [{commit}, {commit: owned, ownerCommit: commit}]});
459             const intermediateCommitSet = new IntermediateCommitSet(commitSet);
460             const fetchingPromise = intermediateCommitSet.fetchCommitLogs();
461
462             const requests = MockRemoteAPI.requests;
463             assert.equal(requests.length, 2);
464             assert.equal(requests[0].url, '/api/commits/111/owner-commit-0');
465             assert.equal(requests[0].method, 'GET');
466             assert.equal(requests[1].url, '/api/commits/112/owned-commit-0');
467             assert.equal(requests[1].method, 'GET');
468
469             requests[0].resolve({commits: [{
470                 id: 5,
471                 repository: MockModels.ownerRepository.id(),
472                 revision: 'owner-commit-0',
473                 ownsCommits: true,
474                 time: +(new Date('2016-05-13T00:55:57.841344Z')),
475             }]});
476             requests[1].resolve({commits: [{
477                 id: 6,
478                 repository: MockModels.ownedRepository.id(),
479                 revision: 'owned-commit-0',
480                 ownsCommits: false,
481                 time: 1456932774000,
482             }]});
483
484             return MockRemoteAPI.waitForRequest().then(() => {
485                 assert.equal(requests.length, 3);
486                 assert.equal(requests[2].url, '../api/commits/111/owned-commits?owner-revision=owner-commit-0');
487                 assert.equal(requests[2].method, 'GET');
488
489                 requests[2].resolve({commits: [{
490                     id: 6,
491                     repository: MockModels.ownedRepository.id(),
492                     revision: 'owned-commit-0',
493                     ownsCommits: false,
494                     time: 1456932774000,
495                 }]});
496                 return fetchingPromise;
497             }).then(() => {
498                 assert(commit.ownsCommits());
499                 assert.equal(commit.ownedCommits().length, 1);
500                 assert.equal(commit.ownedCommits()[0], owned);
501                 assert.equal(owned.ownerCommit(), commit);
502                 assert.equal(owned.repository(), MockModels.ownedRepository);
503                 assert.equal(intermediateCommitSet.commitForRepository(MockModels.ownedRepository), owned);
504                 assert.equal(intermediateCommitSet.ownerCommitForRepository(MockModels.ownedRepository), commit);
505                 assert.deepEqual(intermediateCommitSet.repositories(), [MockModels.ownerRepository, MockModels.ownedRepository]);
506             });
507         });
508     });
509
510     describe('updateRevisionForOwnerRepository', () => {
511
512         it('should update CommitSet based on the latest invocation', () => {
513             const commitSet = new IntermediateCommitSet(new CommitSet);
514             const firstUpdatePromise = commitSet.updateRevisionForOwnerRepository(MockModels.webkit, 'webkit-commit-0');
515             const secondUpdatePromise = commitSet.updateRevisionForOwnerRepository(MockModels.webkit, 'webkit-commit-1');
516             const requests = MockRemoteAPI.requests;
517
518             assert(requests.length, 2);
519             assert.equal(requests[0].url, '/api/commits/11/webkit-commit-0');
520             assert.equal(requests[0].method, 'GET');
521             assert.equal(requests[1].url, '/api/commits/11/webkit-commit-1');
522             assert.equal(requests[1].method, 'GET');
523
524             requests[1].resolve({commits: [{
525                 id: 2018,
526                 repository: MockModels.webkit.id(),
527                 revision: 'webkit-commit-1',
528                 ownsCommits: false,
529                 time: 1456932774000,
530             }]});
531
532             let commit = null;
533             return secondUpdatePromise.then(() => {
534                 commit = commitSet.commitForRepository(MockModels.webkit);
535
536                 requests[0].resolve({commits: [{
537                     id: 2017,
538                     repository: MockModels.webkit.id(),
539                     revision: 'webkit-commit-0',
540                     ownsCommits: false,
541                     time: 1456932773000,
542                 }]});
543
544                 assert.equal(commit.revision(), 'webkit-commit-1');
545                 assert.equal(commit.id(), 2018);
546
547                 return firstUpdatePromise;
548             }).then(() => {
549                 const currentCommit = commitSet.commitForRepository(MockModels.webkit);
550                 assert.equal(commit, currentCommit);
551             });
552         });
553
554     });
555
556     describe('removeCommitForRepository', () => {
557         it('should remove owned commits when owner commit is removed', () => {
558             const commitSet = new IntermediateCommitSet(new CommitSet);
559             const commit = ownerCommit();
560
561             const fetchingPromise = commit.fetchOwnedCommits();
562             const requests = MockRemoteAPI.requests;
563             assert.equal(requests.length, 1);
564             assert.equal(requests[0].url, '../api/commits/111/owned-commits?owner-revision=owner-commit-0');
565             assert.equal(requests[0].method, 'GET');
566
567             requests[0].resolve({commits: [{
568                 id: 233,
569                 repository: MockModels.ownedRepository.id(),
570                 revision: '6f8b0dbbda95a440503b88db1dd03dad3a7b07fb',
571                 ownsCommits: true
572             }]});
573
574             return fetchingPromise.then(() => {
575                 commitSet.setCommitForRepository(MockModels.ownerRepository, commit);
576                 commitSet.setCommitForRepository(MockModels.ownedRepository, commit.ownedCommits()[0]);
577                 commitSet.removeCommitForRepository(MockModels.ownerRepository);
578                 assert.deepEqual(commitSet.repositories(), []);
579             });
580         });
581
582         it('should not remove owner commits when owned commit is removed', () => {
583             const commitSet = new IntermediateCommitSet(new CommitSet);
584             const commit = ownerCommit();
585
586             const fetchingPromise = commit.fetchOwnedCommits();
587             const requests = MockRemoteAPI.requests;
588             assert.equal(requests.length, 1);
589             assert.equal(requests[0].url, '../api/commits/111/owned-commits?owner-revision=owner-commit-0');
590             assert.equal(requests[0].method, 'GET');
591
592             requests[0].resolve({commits: [{
593                 id: 233,
594                 repository: MockModels.ownedRepository.id(),
595                 revision: '6f8b0dbbda95a440503b88db1dd03dad3a7b07fb',
596                 time: +(new Date('2016-05-13T00:55:57.841344Z')),
597             }]});
598
599             return fetchingPromise.then(() => {
600                 commitSet.setCommitForRepository(MockModels.ownerRepository, commit);
601                 commitSet.setCommitForRepository(MockModels.ownedRepository, commit.ownedCommits()[0]);
602                 commitSet.removeCommitForRepository(MockModels.ownedRepository);
603                 assert.deepEqual(commitSet.repositories(), [MockModels.ownerRepository]);
604             });
605         });
606
607         it('should not update commit set for repository if removeCommitForRepository called before updateRevisionForOwnerRepository finishes', () => {
608             const commitSet = new IntermediateCommitSet(new CommitSet);
609             const commit = webkitCommit();
610             commitSet.setCommitForRepository(MockModels.webkit, commit);
611             const updatePromise = commitSet.updateRevisionForOwnerRepository(MockModels.webkit, 'webkit-commit-1');
612
613             commitSet.removeCommitForRepository(MockModels.webkit);
614
615             const requests = MockRemoteAPI.requests;
616             assert.equal(requests[0].url, '/api/commits/11/webkit-commit-1');
617             assert.equal(requests[0].method, 'GET');
618
619             requests[0].resolve({commits: [{
620                 id: 2018,
621                 repository: MockModels.webkit.id(),
622                 revision: 'webkit-commit-1',
623                 ownsCommits: false,
624                 time: 1456932774000,
625             }]});
626
627             return updatePromise.then(() => {
628                 assert.deepEqual(commitSet.repositories(), []);
629                 assert(!commitSet.commitForRepository(MockModels.webkit));
630             });
631         });
632
633     });
634
635 });
636
637 describe('CustomCommitSet', () => {
638     MockModels.inject();
639
640     describe('Test custom commit set without owned commit', () => {
641         it('should have right revision for a given repository', () => {
642             const commitSet = customCommitSetWithoutOwnedCommit();
643             assert.equal(commitSet.revisionForRepository(MockModels.osx), '10.11.4 15E65');
644             assert.equal(commitSet.revisionForRepository(MockModels.webkit), '200805');
645         });
646
647         it('should have no patch for any repository', () => {
648             const commitSet = customCommitSetWithoutOwnedCommit();
649             assert.equal(commitSet.patchForRepository(MockModels.osx), null);
650             assert.equal(commitSet.patchForRepository(MockModels.webkit), null);
651         });
652
653         it('should have no owner revision for a given repository', () => {
654             const commitSet = customCommitSetWithoutOwnedCommit();
655             assert.equal(commitSet.ownerRevisionForRepository(MockModels.osx), null);
656             assert.equal(commitSet.ownerRevisionForRepository(MockModels.webkit), null);
657         });
658
659         it('should return all repositories in it', () => {
660             const commitSet = customCommitSetWithoutOwnedCommit();
661             assert.deepEqual(commitSet.repositories(), [MockModels.osx, MockModels.webkit]);
662         });
663
664         it('should return only top level repositories', () => {
665             const commitSet = customCommitSetWithoutOwnedCommit();
666             assert.deepEqual(commitSet.topLevelRepositories(), [MockModels.osx, MockModels.webkit]);
667         });
668     });
669
670     describe('Test custom commit set with owned commit', () => {
671         it('should have right revision for a given repository', () => {
672             const commitSet = customCommitSetWithOwnedCommit();
673             assert.equal(commitSet.revisionForRepository(MockModels.osx), '10.11.4 15E65');
674             assert.equal(commitSet.revisionForRepository(MockModels.ownerRepository), 'OwnerRepository-r0');
675             assert.equal(commitSet.revisionForRepository(MockModels.ownedRepository), 'OwnedRepository-r0');
676         });
677
678         it('should have no patch for any repository', () => {
679             const commitSet = customCommitSetWithOwnedCommit();
680             assert.equal(commitSet.patchForRepository(MockModels.osx), null);
681             assert.equal(commitSet.patchForRepository(MockModels.ownerRepository), null);
682             assert.equal(commitSet.patchForRepository(MockModels.ownedRepository), null);
683         });
684
685         it('should have right owner revision for an owned repository', () => {
686             const commitSet = customCommitSetWithOwnedCommit();
687             assert.equal(commitSet.ownerRevisionForRepository(MockModels.osx), null);
688             assert.equal(commitSet.ownerRevisionForRepository(MockModels.ownerRepository), null);
689             assert.equal(commitSet.ownerRevisionForRepository(MockModels.ownedRepository), 'OwnerRepository-r0');
690         });
691
692         it('should return all repositories in it', () => {
693             const commitSet = customCommitSetWithOwnedCommit();
694             assert.deepEqual(commitSet.repositories(), [MockModels.osx, MockModels.ownerRepository, MockModels.ownedRepository]);
695         });
696
697         it('should return only top level repositories', () => {
698             const commitSet = customCommitSetWithOwnedCommit();
699             assert.deepEqual(commitSet.topLevelRepositories(), [MockModels.osx, MockModels.ownerRepository]);
700         });
701     });
702
703     describe('Test custom commit set with patch', () => {
704         it('should have right revision for a given repository', () => {
705             const commitSet = customCommitSetWithPatch();
706             assert.equal(commitSet.revisionForRepository(MockModels.osx), '10.11.4 15E65');
707             assert.equal(commitSet.revisionForRepository(MockModels.webkit), '200805');
708         });
709
710         it('should have a patch for a repository with patch specified', () => {
711             const commitSet = customCommitSetWithPatch();
712             assert.equal(commitSet.patchForRepository(MockModels.osx), null);
713             assert.deepEqual(commitSet.patchForRepository(MockModels.webkit), createPatch());
714         });
715
716         it('should have no owner revision for a given repository', () => {
717             const commitSet = customCommitSetWithPatch();
718             assert.equal(commitSet.ownerRevisionForRepository(MockModels.osx), null);
719             assert.equal(commitSet.ownerRevisionForRepository(MockModels.webkit), null);
720         });
721
722         it('should return all repositories in it', () => {
723             const commitSet = customCommitSetWithPatch();
724             assert.deepEqual(commitSet.repositories(), [MockModels.osx, MockModels.webkit]);
725         });
726
727         it('should return only top level repositories', () => {
728             const commitSet = customCommitSetWithPatch();
729             assert.deepEqual(commitSet.topLevelRepositories(), [MockModels.osx, MockModels.webkit]);
730         });
731     });
732
733     describe('Test custom commit set with owned repository has same name as non-owned repository',  () => {
734         it('should have right revision for a given repository', () => {
735             const commitSet = customCommitSetWithOwnedRepositoryHasSameNameAsNotOwnedRepository();
736             assert.equal(commitSet.revisionForRepository(MockModels.osx), '10.11.4 15E65');
737             assert.equal(commitSet.revisionForRepository(MockModels.webkit), '200805');
738             assert.equal(commitSet.revisionForRepository(MockModels.ownedWebkit), 'owned-200805');
739         });
740
741         it('should have no patch for any repository', () => {
742             const commitSet = customCommitSetWithOwnedRepositoryHasSameNameAsNotOwnedRepository();
743             assert.equal(commitSet.patchForRepository(MockModels.osx), null);
744             assert.equal(commitSet.patchForRepository(MockModels.webkit), null);
745             assert.equal(commitSet.patchForRepository(MockModels.ownedWebkit), null);
746         });
747
748         it('should have right owner revision for an owned repository', () => {
749             const commitSet = customCommitSetWithOwnedRepositoryHasSameNameAsNotOwnedRepository();
750             assert.equal(commitSet.ownerRevisionForRepository(MockModels.osx), null);
751             assert.equal(commitSet.ownerRevisionForRepository(MockModels.webkit), null);
752             assert.equal(commitSet.ownerRevisionForRepository(MockModels.ownedWebkit), '10.11.4 15E65');
753         });
754
755         it('should return all repositories in it', () => {
756             const commitSet = customCommitSetWithOwnedRepositoryHasSameNameAsNotOwnedRepository();
757             assert.deepEqual(commitSet.repositories(), [MockModels.osx, MockModels.webkit, MockModels.ownedWebkit]);
758         });
759
760         it('should return only top level repositories', () => {
761             const commitSet = customCommitSetWithOwnedRepositoryHasSameNameAsNotOwnedRepository();
762             assert.deepEqual(commitSet.topLevelRepositories(), [MockModels.osx, MockModels.webkit]);
763         });
764     });
765
766     describe('Test custom commit set equality function', () => {
767         it('should be equal to same custom commit set', () => {
768             assert.deepEqual(customCommitSetWithoutOwnedCommit(), customCommitSetWithoutOwnedCommit());
769             assert.deepEqual(customCommitSetWithOwnedCommit(), customCommitSetWithOwnedCommit());
770             assert.deepEqual(customCommitSetWithPatch(), customCommitSetWithPatch());
771             assert.deepEqual(customCommitSetWithOwnedRepositoryHasSameNameAsNotOwnedRepository(),
772                 customCommitSetWithOwnedRepositoryHasSameNameAsNotOwnedRepository());
773         });
774
775         it('should not be equal even if non-owned revisions are the same', () => {
776             const commitSet0 = customCommitSetWithoutOwnedCommit();
777             const commitSet1 = customCommitSetWithOwnedRepositoryHasSameNameAsNotOwnedRepository();
778             assert.equal(commitSet0.equals(commitSet1), false);
779         });
780     });
781
782     describe('Test custom commit set custom root operations', () => {
783         it('should return empty custom roots if no custom root specified', () => {
784             assert.deepEqual(customCommitSetWithoutOwnedCommit().customRoots(), []);
785         });
786
787         it('should return root if root is added into commit set', () => {
788             const commitSet = customCommitSetWithoutOwnedCommit();
789             commitSet.addCustomRoot(createRoot());
790             assert.deepEqual(commitSet.customRoots(), [createRoot()]);
791         });
792     });
793 });