Add the support for scheduling a A/B testing with a patch.
[WebKit-https.git] / Websites / perf.webkit.org / server-tests / api-manifest-tests.js
1 'use strict';
2
3 const assert = require('assert');
4
5 require('../tools/js/v3-models.js');
6
7 const MockData = require('./resources/mock-data.js');
8 const TestServer = require('./resources/test-server.js');
9 const prepareServerTest = require('./resources/common-operations.js').prepareServerTest;
10
11 describe('/api/manifest', function () {
12     prepareServerTest(this);
13
14     it("should generate an empty manifest when database is empty", () => {
15         return TestServer.remoteAPI().getJSON('/api/manifest').then((manifest) => {
16             assert.deepEqual(Object.keys(manifest).sort(), ['all', 'bugTrackers', 'builders', 'dashboard', 'dashboards',
17                 'elapsedTime', 'fileUploadSizeLimit', 'metrics', 'repositories', 'siteTitle', 'status', 'summaryPages', 'tests', 'triggerables']);
18
19             assert.equal(typeof(manifest.elapsedTime), 'number');
20             delete manifest.elapsedTime;
21
22             assert.deepStrictEqual(manifest, {
23                 siteTitle: TestServer.testConfig().siteTitle,
24                 all: {},
25                 bugTrackers: {},
26                 builders: {},
27                 dashboard: {},
28                 dashboards: {},
29                 fileUploadSizeLimit: 2097152, // 2MB during testing.
30                 metrics: {},
31                 repositories: {},
32                 tests: {},
33                 triggerables: {},
34                 summaryPages: [],
35                 status: 'OK'
36             });
37         });
38     });
39
40     const bugzillaData = {id: 1, name: 'Bugzilla', bug_url: 'https://webkit.org/b/$number', new_bug_url: 'https://bugs.webkit.org/'};
41     const radarData = {id: 2, name: 'Radar'};
42
43     it("should generate manifest with bug trackers without repositories", () => {
44         return TestServer.database().insert('bug_trackers', bugzillaData).then(() => {
45             return TestServer.remoteAPI().getJSON('/api/manifest');
46         }).then((content) => {
47             assert.deepEqual(content.bugTrackers, {1: {name: 'Bugzilla', bugUrl: 'https://webkit.org/b/$number',
48                 newBugUrl: 'https://bugs.webkit.org/', repositories: null}});
49
50             let manifest = Manifest._didFetchManifest(content);
51             let tracker = BugTracker.findById(1);
52             assert(tracker);
53             assert.equal(tracker.name(), 'Bugzilla');
54             assert.equal(tracker.bugUrl(123), 'https://webkit.org/b/123');
55             assert.equal(tracker.newBugUrl(), 'https://bugs.webkit.org/');
56         });
57     });
58
59     it("should generate manifest with bug trackers and repositories", () => {
60         let db = TestServer.database();
61         return Promise.all([
62             db.insert('bug_trackers', bugzillaData),
63             db.insert('bug_trackers', radarData),
64             db.insert('repositories', {id: 11, name: 'WebKit', url: 'https://trac.webkit.org/$1'}),
65             db.insert('repositories', {id: 9, name: 'macOS'}),
66             db.insert('repositories', {id: 22, name: 'iOS'}),
67             db.insert('tracker_repositories', {tracker: bugzillaData.id, repository: 11}),
68             db.insert('tracker_repositories', {tracker: radarData.id, repository: 9}),
69             db.insert('tracker_repositories', {tracker: radarData.id, repository: 22}),
70         ]).then(() => {
71             return TestServer.remoteAPI().getJSON('/api/manifest');
72         }).then((content) => {
73             let manifest = Manifest._didFetchManifest(content);
74
75             let webkit = Repository.findById(11);
76             assert(webkit);
77             assert.equal(webkit.name(), 'WebKit');
78             assert.equal(webkit.urlForRevision(123), 'https://trac.webkit.org/123');
79
80             let macos = Repository.findById(9);
81             assert(macos);
82             assert.equal(macos.name(), 'macOS');
83
84             let ios = Repository.findById(22);
85             assert(ios);
86             assert.equal(ios.name(), 'iOS');
87
88             let tracker = BugTracker.findById(1);
89             assert(tracker);
90             assert.equal(tracker.name(), 'Bugzilla');
91             assert.equal(tracker.bugUrl(123), 'https://webkit.org/b/123');
92             assert.equal(tracker.newBugUrl(), 'https://bugs.webkit.org/');
93             assert.deepEqual(tracker.repositories(), [webkit]);
94
95             tracker = BugTracker.findById(2);
96             assert(tracker);
97             assert.equal(tracker.name(), 'Radar');
98             assert.deepEqual(Repository.sortByName(tracker.repositories()), [ios, macos]);
99         });
100     });
101
102     it("should generate manifest with repositories and each repository should know its owned repositories", () => {
103         const db = TestServer.database();
104         return Promise.all([
105             db.insert('repositories', {id: 11, name: 'WebKit', url: 'https://trac.webkit.org/$1'}),
106             db.insert('repositories', {id: 9, name: 'OS X'}),
107             db.insert('repositories', {id: 22, name: 'iOS'}),
108             db.insert('repositories', {id: 35, name: 'JavaScriptCore', owner: 9}),
109         ]).then(() => {
110             return TestServer.remoteAPI().getJSON('/api/manifest');
111         }).then((content) => {
112             let manifest = Manifest._didFetchManifest(content);
113
114             let webkit = Repository.findById(11);
115             assert(webkit);
116             assert.equal(webkit.name(), 'WebKit');
117             assert.equal(webkit.urlForRevision(123), 'https://trac.webkit.org/123');
118             assert.equal(webkit.ownedRepositories(), null);
119
120             let osx = Repository.findById(9);
121             assert(osx);
122             assert.equal(osx.name(), 'OS X');
123             assert.deepEqual(osx.ownedRepositories(), [Repository.findById(35)]);
124
125             let ios = Repository.findById(22);
126             assert(ios);
127             assert.equal(ios.name(), 'iOS');
128             assert.equal(ios.ownedRepositories(), null);
129         });
130     });
131
132     it("should generate manifest with builders", () => {
133         let db = TestServer.database();
134         return Promise.all([
135             db.insert('builders', {id: 1, name: 'SomeBuilder', password_hash: 'a',
136                 build_url: 'https://build.webkit.org/builders/$builderName/build/$buildNumber'}),
137             db.insert('builders', {id: 2, name: 'SomeOtherBuilder', password_hash: 'b'})
138         ]).then(() => {
139             return TestServer.remoteAPI().getJSON('/api/manifest');
140         }).then((content) => {
141             assert.deepEqual(content.builders, {
142                 '1': {name: 'SomeBuilder', buildUrl: 'https://build.webkit.org/builders/$builderName/build/$buildNumber'},
143                 '2': {name: 'SomeOtherBuilder', buildUrl: null}
144             });
145
146             let manifest = Manifest._didFetchManifest(content);
147
148             let builder = Builder.findById(1);
149             assert(builder);
150             assert.equal(builder.name(), 'SomeBuilder');
151             assert.equal(builder.urlForBuild(123), 'https://build.webkit.org/builders/SomeBuilder/build/123');
152
153             builder = Builder.findById(2);
154             assert(builder);
155             assert.equal(builder.name(), 'SomeOtherBuilder');
156             assert.equal(builder.urlForBuild(123), null);
157         });
158     });
159
160     it("should generate manifest with tests, metrics, and platforms", () => {
161         let db = TestServer.database();
162         return Promise.all([
163             db.insert('tests', {id: 1, name: 'SomeTest'}),
164             db.insert('tests', {id: 2, name: 'SomeOtherTest'}),
165             db.insert('tests', {id: 3, name: 'ChildTest', parent: 1}),
166             db.insert('tests', {id: 4, name: 'GrandChild', parent: 3}),
167             db.insert('aggregators', {id: 200, name: 'Total'}),
168             db.insert('test_metrics', {id: 5, test: 1, name: 'Time'}),
169             db.insert('test_metrics', {id: 6, test: 2, name: 'Time', aggregator: 200}),
170             db.insert('test_metrics', {id: 7, test: 2, name: 'Malloc', aggregator: 200}),
171             db.insert('test_metrics', {id: 8, test: 3, name: 'Time'}),
172             db.insert('test_metrics', {id: 9, test: 4, name: 'Time'}),
173             db.insert('platforms', {id: 23, name: 'iOS 9 iPhone 5s'}),
174             db.insert('platforms', {id: 46, name: 'Trunk Mavericks'}),
175             db.insert('test_configurations', {id: 101, metric: 5, platform: 46, type: 'current'}),
176             db.insert('test_configurations', {id: 102, metric: 6, platform: 46, type: 'current'}),
177             db.insert('test_configurations', {id: 103, metric: 7, platform: 46, type: 'current'}),
178             db.insert('test_configurations', {id: 104, metric: 8, platform: 46, type: 'current'}),
179             db.insert('test_configurations', {id: 105, metric: 9, platform: 46, type: 'current'}),
180             db.insert('test_configurations', {id: 106, metric: 5, platform: 23, type: 'current'}),
181             db.insert('test_configurations', {id: 107, metric: 5, platform: 23, type: 'baseline'}),
182         ]).then(() => {
183             return TestServer.remoteAPI().getJSON('/api/manifest');
184         }).then((content) => {
185             assert.deepEqual(content.tests, {
186                 "1": {"name": "SomeTest", "parentId": null, "url": null},
187                 "2": {"name": "SomeOtherTest", "parentId": null, "url": null},
188                 "3": {"name": "ChildTest", "parentId": "1", "url": null},
189                 "4": {"name": "GrandChild", "parentId": "3", "url": null},
190             });
191
192             assert.deepEqual(content.metrics, {
193                 '5': {name: 'Time', test: '1', aggregator: null},
194                 '6': {name: 'Time', test: '2', aggregator: 'Total'},
195                 '7': {name: 'Malloc', test: '2', aggregator: 'Total'},
196                 '8': {name: 'Time', test: '3', aggregator: null},
197                 '9': {name: 'Time', test: '4', aggregator: null},
198             });
199
200             let manifest = Manifest._didFetchManifest(content);
201
202             let someTest = Test.findById(1);
203             let someTestMetric = Metric.findById(5);
204             let someOtherTest = Test.findById(2);
205             let someOtherTestTime = Metric.findById(6);
206             let someOtherTestMalloc = Metric.findById(7);
207             let childTest = Test.findById(3);
208             let childTestMetric = Metric.findById(8);
209             let grandChildTest = Test.findById(4);
210             let ios9iphone5s = Platform.findById(23);
211             let mavericks = Platform.findById(46);
212             assert(someTest);
213             assert(someTestMetric);
214             assert(someOtherTest);
215             assert(someOtherTestTime);
216             assert(someOtherTestMalloc);
217             assert(childTest);
218             assert(childTestMetric);
219             assert(grandChildTest);
220             assert(ios9iphone5s);
221             assert(mavericks);
222
223             assert.equal(mavericks.name(), 'Trunk Mavericks');
224             assert(mavericks.hasTest(someTest));
225             assert(mavericks.hasTest(someOtherTest));
226             assert(mavericks.hasTest(childTest));
227             assert(mavericks.hasTest(grandChildTest));
228             assert(mavericks.hasMetric(someTestMetric));
229             assert(mavericks.hasMetric(someOtherTestTime));
230             assert(mavericks.hasMetric(someOtherTestMalloc));
231             assert(mavericks.hasMetric(childTestMetric));
232
233             assert.equal(ios9iphone5s.name(), 'iOS 9 iPhone 5s');
234             assert(ios9iphone5s.hasTest(someTest));
235             assert(!ios9iphone5s.hasTest(someOtherTest));
236             assert(!ios9iphone5s.hasTest(childTest));
237             assert(!ios9iphone5s.hasTest(grandChildTest));
238             assert(ios9iphone5s.hasMetric(someTestMetric));
239             assert(!ios9iphone5s.hasMetric(someOtherTestTime));
240             assert(!ios9iphone5s.hasMetric(someOtherTestMalloc));
241             assert(!ios9iphone5s.hasMetric(childTestMetric));
242
243             assert.equal(someTest.name(), 'SomeTest');
244             assert.equal(someTest.parentTest(), null);
245             assert.deepEqual(someTest.path(), [someTest]);
246             assert(!someTest.onlyContainsSingleMetric());
247             assert.deepEqual(someTest.childTests(), [childTest]);
248             assert.deepEqual(someTest.metrics(), [someTestMetric]);
249
250             assert.equal(someTestMetric.name(), 'Time');
251             assert.equal(someTestMetric.aggregatorName(), null);
252             assert.equal(someTestMetric.label(), 'Time');
253             assert.deepEqual(someTestMetric.childMetrics(), childTest.metrics());
254             assert.equal(someTestMetric.fullName(), 'SomeTest : Time');
255
256             assert.equal(someOtherTest.name(), 'SomeOtherTest');
257             assert.equal(someOtherTest.parentTest(), null);
258             assert.deepEqual(someOtherTest.path(), [someOtherTest]);
259             assert(!someOtherTest.onlyContainsSingleMetric());
260             assert.deepEqual(someOtherTest.childTests(), []);
261             assert.equal(someOtherTest.metrics().length, 2);
262             assert.equal(someOtherTest.metrics()[0].name(), 'Time');
263             assert.equal(someOtherTest.metrics()[0].aggregatorName(), 'Total');
264             assert.equal(someOtherTest.metrics()[0].label(), 'Time : Total');
265             assert.equal(someOtherTest.metrics()[0].childMetrics().length, 0);
266             assert.equal(someOtherTest.metrics()[0].fullName(), 'SomeOtherTest : Time : Total');
267             assert.equal(someOtherTest.metrics()[1].name(), 'Malloc');
268             assert.equal(someOtherTest.metrics()[1].aggregatorName(), 'Total');
269             assert.equal(someOtherTest.metrics()[1].label(), 'Malloc : Total');
270             assert.equal(someOtherTest.metrics()[1].childMetrics().length, 0);
271             assert.equal(someOtherTest.metrics()[1].fullName(), 'SomeOtherTest : Malloc : Total');
272
273             assert.equal(childTest.name(), 'ChildTest');
274             assert.equal(childTest.parentTest(), someTest);
275             assert.deepEqual(childTest.path(), [someTest, childTest]);
276             assert(!childTest.onlyContainsSingleMetric());
277             assert.deepEqual(childTest.childTests(), [grandChildTest]);
278             assert.equal(childTest.metrics().length, 1);
279             assert.equal(childTest.metrics()[0].label(), 'Time');
280             assert.equal(childTest.metrics()[0].fullName(), 'SomeTest \u220B ChildTest : Time');
281
282             assert.equal(grandChildTest.name(), 'GrandChild');
283             assert.equal(grandChildTest.parentTest(), childTest);
284             assert.deepEqual(grandChildTest.path(), [someTest, childTest, grandChildTest]);
285             assert(grandChildTest.onlyContainsSingleMetric());
286             assert.deepEqual(grandChildTest.childTests(), []);
287             assert.equal(grandChildTest.metrics().length, 1);
288             assert.equal(grandChildTest.metrics()[0].label(), 'Time');
289             assert.equal(grandChildTest.metrics()[0].fullName(), 'SomeTest \u220B ChildTest \u220B GrandChild : Time');
290         });
291     });
292
293     it("should generate manifest with triggerables", () => {
294         let db = TestServer.database();
295         return Promise.all([
296             db.insert('repositories', {id: 11, name: 'WebKit', url: 'https://trac.webkit.org/$1'}),
297             db.insert('repositories', {id: 9, name: 'macOS'}),
298             db.insert('repositories', {id: 101, name: 'WebKit', owner: 9, url: 'https://trac.webkit.org/$1'}),
299             db.insert('build_triggerables', {id: 200, name: 'build.webkit.org'}),
300             db.insert('build_triggerables', {id: 201, name: 'ios-build.webkit.org'}),
301             db.insert('build_triggerables', {id: 202, name: 'mac-build.webkit.org', disabled: true}),
302             db.insert('tests', {id: 1, name: 'SomeTest'}),
303             db.insert('tests', {id: 2, name: 'SomeOtherTest'}),
304             db.insert('tests', {id: 3, name: 'ChildTest', parent: 1}),
305             db.insert('platforms', {id: 23, name: 'iOS 9 iPhone 5s'}),
306             db.insert('platforms', {id: 46, name: 'Trunk Mavericks'}),
307             db.insert('platforms', {id: 104, name: 'Trunk Sierra MacBookPro11,2'}),
308             db.insert('test_metrics', {id: 5, test: 1, name: 'Time'}),
309             db.insert('test_metrics', {id: 8, test: 2, name: 'FrameRate'}),
310             db.insert('test_metrics', {id: 9, test: 3, name: 'Time'}),
311             db.insert('test_configurations', {id: 101, metric: 5, platform: 46, type: 'current'}),
312             db.insert('test_configurations', {id: 102, metric: 8, platform: 46, type: 'current'}),
313             db.insert('test_configurations', {id: 103, metric: 9, platform: 46, type: 'current'}),
314             db.insert('test_configurations', {id: 104, metric: 5, platform: 23, type: 'current'}),
315             db.insert('test_configurations', {id: 105, metric: 8, platform: 23, type: 'current'}),
316             db.insert('test_configurations', {id: 106, metric: 9, platform: 23, type: 'current'}),
317             db.insert('test_configurations', {id: 107, metric: 5, platform: 104, type: 'current'}),
318             db.insert('test_configurations', {id: 108, metric: 8, platform: 104, type: 'current'}),
319             db.insert('test_configurations', {id: 109, metric: 9, platform: 104, type: 'current'}),
320             db.insert('triggerable_repository_groups', {id: 300, triggerable: 200, name: 'default'}),
321             db.insert('triggerable_repository_groups', {id: 301, triggerable: 201, name: 'default'}),
322             db.insert('triggerable_repository_groups', {id: 302, triggerable: 202, name: 'system-and-webkit'}),
323             db.insert('triggerable_repository_groups', {id: 312, triggerable: 202, name: 'system-and-roots', accepts_roots: true}),
324             db.insert('triggerable_repositories', {group: 300, repository: 11}),
325             db.insert('triggerable_repositories', {group: 301, repository: 11}),
326             db.insert('triggerable_repositories', {group: 302, repository: 11}),
327             db.insert('triggerable_repositories', {group: 302, repository: 9}),
328             db.insert('triggerable_repositories', {group: 312, repository: 9}),
329             db.insert('triggerable_configurations', {triggerable: 200, test: 1, platform: 46}),
330             db.insert('triggerable_configurations', {triggerable: 200, test: 2, platform: 46}),
331             db.insert('triggerable_configurations', {triggerable: 201, test: 1, platform: 23}),
332             db.insert('triggerable_configurations', {triggerable: 201, test: 2, platform: 23}),
333             db.insert('triggerable_configurations', {triggerable: 202, test: 1, platform: 104}),
334             db.insert('triggerable_configurations', {triggerable: 202, test: 2, platform: 104}),
335         ]).then(() => {
336             return Manifest.fetch();
337         }).then(() => {
338             const webkit = Repository.findById(11);
339             assert.equal(webkit.name(), 'WebKit');
340             assert.equal(webkit.urlForRevision(123), 'https://trac.webkit.org/123');
341
342             const osWebkit1 = Repository.findById(101);
343             assert.equal(osWebkit1.name(), 'WebKit');
344             assert.equal(osWebkit1.ownerId(), 9);
345             assert.equal(osWebkit1.urlForRevision(123), 'https://trac.webkit.org/123');
346
347             const macos = Repository.findById(9);
348             assert.equal(macos.name(), 'macOS');
349
350             const someTest = Test.findById(1);
351             assert.equal(someTest.name(), 'SomeTest');
352
353             const someOtherTest = Test.findById(2);
354             assert.equal(someOtherTest.name(), 'SomeOtherTest');
355
356             const childTest = Test.findById(3);
357             assert.equal(childTest.name(), 'ChildTest');
358
359             const ios9iphone5s = Platform.findById(23);
360             assert.equal(ios9iphone5s.name(), 'iOS 9 iPhone 5s');
361
362             const mavericks = Platform.findById(46);
363             assert.equal(mavericks.name(), 'Trunk Mavericks');
364
365             const sierra = Platform.findById(104);
366             assert.equal(sierra.name(), 'Trunk Sierra MacBookPro11,2');
367
368             assert.equal(Triggerable.all().length, 3);
369
370             const macosTriggerable = Triggerable.findByTestConfiguration(someTest, mavericks);
371             assert.equal(macosTriggerable.name(), 'build.webkit.org');
372
373             assert.equal(Triggerable.findByTestConfiguration(someOtherTest, mavericks), macosTriggerable);
374             assert.equal(Triggerable.findByTestConfiguration(childTest, mavericks), macosTriggerable);
375
376             const iosTriggerable = Triggerable.findByTestConfiguration(someOtherTest, ios9iphone5s);
377             assert.notEqual(iosTriggerable, macosTriggerable);
378             assert.equal(iosTriggerable.name(), 'ios-build.webkit.org');
379
380             assert.equal(Triggerable.findByTestConfiguration(someOtherTest, ios9iphone5s), iosTriggerable);
381             assert.equal(Triggerable.findByTestConfiguration(childTest, ios9iphone5s), iosTriggerable);
382
383             const macTriggerable = Triggerable.findByTestConfiguration(someTest, sierra);
384             assert.equal(macTriggerable.name(), 'mac-build.webkit.org');
385             assert(macTriggerable.acceptsTest(someTest));
386
387             const groups = macTriggerable.repositoryGroups();
388             assert.deepEqual(groups.length, 2);
389             TriggerableRepositoryGroup.sortByName(groups);
390
391             const emptyCustomSet = new CustomCommitSet;
392
393             const customSetWithOSX = new CustomCommitSet;
394             customSetWithOSX.setRevisionForRepository(macos, '10.11 15A284');
395
396             const cusomSetWithOSXAndWebKit = new CustomCommitSet;
397             cusomSetWithOSXAndWebKit.setRevisionForRepository(webkit, '191622');
398             cusomSetWithOSXAndWebKit.setRevisionForRepository(macos, '10.11 15A284');
399
400             const cusomSetWithWebKit = new CustomCommitSet;
401             cusomSetWithWebKit.setRevisionForRepository(webkit, '191622');
402
403             assert.equal(groups[0].name(), 'system-and-roots');
404             assert.equal(groups[0].acceptsCustomRoots(), true);
405             assert.deepEqual(Repository.sortByName(groups[0].repositories()), [macos]);
406             assert.equal(groups[0].accepts(emptyCustomSet), false);
407             assert.equal(groups[0].accepts(customSetWithOSX), true);
408             assert.equal(groups[0].accepts(cusomSetWithOSXAndWebKit), false);
409             assert.equal(groups[0].accepts(cusomSetWithWebKit), false);
410
411             assert.equal(groups[1].name(), 'system-and-webkit');
412             assert.equal(groups[1].acceptsCustomRoots(), false);
413             assert.deepEqual(Repository.sortByName(groups[1].repositories()), [webkit, macos]);
414             assert.equal(groups[1].accepts(emptyCustomSet), false);
415             assert.equal(groups[1].accepts(customSetWithOSX), false);
416             assert.equal(groups[1].accepts(cusomSetWithOSXAndWebKit), true);
417             assert.equal(groups[1].accepts(cusomSetWithWebKit), false);
418         });
419     });
420
421 });