Add sanity check for source origin in WebLoaderStrategy::startPingLoad()
[WebKit-https.git] / Websites / perf.webkit.org / browser-tests / index.html
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="utf-8">
5 <title>In-Browser Tests for Performance Dashboard</title>
6 <link rel="stylesheet" href="../node_modules/mocha/mocha.css">
7 <script src="../node_modules/mocha/mocha.js"></script>
8 <script src="https://cdnjs.cloudflare.com/ajax/libs/expect.js/0.2.0/expect.min.js"></script>
9 <script>
10
11 mocha.setup('bdd');
12
13 </script>
14 <script src="../unit-tests/resources/mock-remote-api.js"></script>
15 </head>
16 <body>
17 <div id="mocha"></div>
18 <script src="component-base-tests.js"></script>
19 <script src="close-button-tests.js"></script>
20 <script src="editable-text-tests.js"></script>
21 <script src="time-series-chart-tests.js"></script>
22 <script src="interactive-time-series-chart-tests.js"></script>
23 <script src="chart-status-evaluator-tests.js"></script>
24 <script src="chart-revision-range-tests.js"></script>
25 <script src="commit-log-viewer-tests.js"></script>
26 <script src="test-group-form-tests.js"></script>
27 <script>
28
29 afterEach(() => {
30     BrowsingContext.cleanup();
31 });
32
33 class BrowsingContext {
34
35     constructor()
36     {
37         let iframe = document.createElement('iframe');
38         document.body.appendChild(iframe);
39         iframe.style.position = 'absolute';
40         iframe.style.left = '0px';
41         iframe.style.top = '0px';
42         BrowsingContext._iframes.push(iframe);
43
44         // Expedite calls to callbacks to make tests go faster.
45         iframe.contentWindow.requestAnimationFrame = (callback) => setTimeout(callback, 0);
46
47         this.iframe = iframe;
48         this.symbols = {};
49         this.global = this.iframe.contentWindow;
50         this.document = this.iframe.contentDocument;
51         this._didLoadMockRemote = false;
52     }
53
54     importScripts(pathList, ...symbolList)
55     {
56         const doc = this.iframe.contentDocument;
57         const global = this.iframe.contentWindow;
58
59         pathList = pathList.map((path) => `../public/v3/${path}`);
60         if (!this._didLoadMockRemote) {
61             this._didLoadMockRemote = true;
62             pathList.unshift('../unit-tests/resources/mock-remote-api.js');
63         }
64
65         return Promise.all(pathList.map((path) => {
66             return new Promise((resolve, reject) => {
67                 let script = doc.createElement('script');
68                 script.addEventListener('load', resolve);
69                 script.addEventListener('error', reject);
70                 script.src = path;
71                 script.async = false;
72                 doc.body.appendChild(script);
73             });
74         })).then(() => {
75             const script = doc.createElement('script');
76             script.textContent = `window.importedSymbols = [${symbolList.join(', ')}];`;
77             global.RemoteAPI = global.MockRemoteAPI;
78             doc.body.appendChild(script);
79
80             const importedSymbols = global.importedSymbols;
81             for (let i = 0; i < symbolList.length; i++)
82                 this.symbols[symbolList[i]] = importedSymbols[i];
83
84             return symbolList.length == 1 ? importedSymbols[0] : importedSymbols;
85         });
86     }
87
88     importScript(path, ...symbols)
89     {
90         return this.importScripts([path], ...symbols);
91     }
92
93     static cleanup()
94     {
95         BrowsingContext._iframes.forEach((iframe) => { iframe.remove(); });
96         BrowsingContext._iframes = [];
97     }
98 }
99 BrowsingContext._iframes = [];
100
101 function waitForComponentsToRender(context)
102 {
103     if (!context._dummyComponent) {
104         const ComponentBase = context.symbols.ComponentBase;
105         context._dummyComponent = class SomeComponent extends ComponentBase {
106             constructor(resolve)
107             {
108                 super();
109                 this._resolve = resolve;
110             }
111             render() { setTimeout(this._resolve, 0); }
112         }
113         ComponentBase.defineElement('dummy-component', context._dummyComponent);
114     }
115     return new Promise((resolve) => {
116         const instance = new context._dummyComponent(resolve);
117         context.document.body.appendChild(instance.element());
118         setTimeout(() => {
119             instance.enqueueToRender();
120         }, 0);
121     });
122 }
123
124 function wait(milliseconds)
125 {
126     return new Promise((resolve) => {
127         setTimeout(resolve, milliseconds);
128     });
129 }
130
131 function canvasImageData(canvas)
132 {
133     return canvas.getContext('2d').getImageData(0, 0, canvas.width, canvas.height);
134 }
135
136 function canvasRefTest(canvas1, canvas2, shouldMatch)
137 {
138     expect(canvas1.offsetWidth).to.be(canvas2.offsetWidth);
139     expect(canvas2.offsetHeight).to.be(canvas2.offsetHeight);
140     const data1 = canvasImageData(canvas1).data;
141     const data2 = canvasImageData(canvas2).data;
142     expect(data1.length).to.be.a('number');
143     expect(data1.length).to.be(data2.length);
144
145     let match = true;
146     for (let i = 0; i < data1.length; i++) {
147         if (data1[i] != data2[i]) {
148             match = false;
149             break;
150         }
151     }
152
153     if (match == shouldMatch)
154         return;
155
156     [canvas1, canvas2].forEach((canvas) => {
157         let image = document.createElement('img');
158         image.src = canvas.toDataURL();
159         image.style.display = 'block';
160         document.body.appendChild(image);
161     });
162
163     throw new Error(shouldMatch ? 'Canvas contents were different' : 'Canvas contents were identical');
164 }
165
166 const CanvasTest = {
167     fillCanvasBeforeRedrawCheck(canvas)
168     {
169         const canvasContext = canvas.getContext('2d');
170         canvasContext.fillStyle = 'white';
171         canvasContext.fillRect(0, 0, canvas.width, canvas.height);
172     },
173
174     hasCanvasBeenRedrawn(canvas)
175     {
176         return canvasImageData(canvas).data.some((value) => value != 255);
177     },
178
179     canvasImageData(canvas) { return canvasImageData(canvas); },
180
181     canvasContainsColor(canvas, color, rect = {})
182     {
183         const content = canvas.getContext('2d').getImageData(rect.x || 0, rect.y || 0, rect.width || canvas.width, rect.height || canvas.height);
184         let found = false;
185         const data = content.data;
186         for (let startOfPixel = 0; startOfPixel < data.length; startOfPixel += 4) {
187             let r = data[startOfPixel];
188             let g = data[startOfPixel + 1];
189             let b = data[startOfPixel + 2];
190             let a = data[startOfPixel + 3];
191             if (r == color.r && g == color.g && b == color.b && (color.a == undefined || a == color.a))
192                 return true;
193         }
194         return false;
195     },
196
197     expectCanvasesMatch(canvas1, canvas2) { return canvasRefTest(canvas1, canvas2, true); },
198     expectCanvasesMismatch(canvas1, canvas2) { return canvasRefTest(canvas1, canvas2, false); },
199 }
200
201 const dayInMilliseconds = 24 * 3600 * 1000;
202
203 function posixTime(string) { return +new Date(string); }
204
205 const ChartTest = {
206     importChartScripts(context)
207     {
208         return context.importScripts([
209             '../shared/statistics.js',
210             'lazily-evaluated-function.js',
211             'instrumentation.js',
212             'models/data-model.js',
213             'models/time-series.js',
214             'models/measurement-set.js',
215             'models/measurement-cluster.js',
216             'models/measurement-adaptor.js',
217             'models/repository.js',
218             'models/platform.js',
219             'models/test.js',
220             'models/metric.js',
221             'models/commit-set.js',
222             'models/commit-log.js',
223             'components/base.js',
224             'components/time-series-chart.js',
225             'components/interactive-time-series-chart.js'],
226             'ComponentBase', 'TimeSeriesChart', 'InteractiveTimeSeriesChart',
227             'Platform', 'Metric', 'Test', 'Repository', 'MeasurementSet', 'MockRemoteAPI').then(() => {
228                 return context.symbols.TimeSeriesChart;
229             })
230     },
231
232     posixTime: posixTime,
233
234     get sampleCluster() { return this.makeSampleCluster(); },
235
236     makeModelObjectsForSampleCluster(context)
237     {
238         const test = context.symbols.Test.ensureSingleton(2, {name: 'Test'});
239         const metric = context.symbols.Metric.ensureSingleton(1, {name: 'Time', test})
240         const platform = context.symbols.Platform.ensureSingleton(1,
241             {name: 'SomePlatform', metrics: [metric], lastModifiedByMetric: [posixTime('2016-01-18T00:00:00Z')]});
242         metric.addPlatform(platform);
243         context.symbols.Repository.ensureSingleton(1, {name: 'SomeApp'});
244         context.symbols.Repository.ensureSingleton(2, {name: 'macOS'});
245     },
246
247     makeSampleCluster(options = {})
248     {
249         const baselineStart = options.baselineIsSmaller ? 30 : 130;
250         const targetStart = options.targetIsBigger ? 120 : 90;
251         return {
252         "clusterStart": posixTime('2016-01-01T00:00:00Z'),
253         "clusterSize": 7 * dayInMilliseconds,
254         "startTime": posixTime('2016-01-01T00:00:00Z'),
255         "endTime": posixTime('2016-01-08T00:00:00Z'),
256         "lastModified": posixTime('2016-01-18T00:00:00Z'),
257         "clusterCount": 1,
258         "status": "OK",
259         "formatMap": [
260             "id", "mean", "iterationCount", "sum", "squareSum", "markedOutlier",
261             "revisions",
262             "commitTime", "build", "buildTime", "buildNumber", "builder"
263         ],
264         "configurations": {
265             "current": [
266                 [
267                     1000, 100, 1, 100, 100 * 100, false,
268                     [ [2000, 1, "4000", posixTime('2016-01-05T17:35:00Z')], [3000, 2, "15B42", 0] ],
269                     posixTime('2016-01-05T17:35:00Z'), 5000, posixTime('2016-01-05T19:23:00Z'), "10", 7
270                 ],
271                 [
272                     1001, 131, 1, 131, 131 * 131, true,
273                     [ [2001, 1, "4001", posixTime('2016-01-05T18:43:01Z')], [3000, 2, "15B42", 0] ],
274                     posixTime('2016-01-05T18:43:01Z'), 5001, posixTime('2016-01-05T20:58:01Z'), "11", 7
275                 ],
276                 [
277                     1002, 122, 1, 122, 122 * 122, false,
278                     [ [2002, 1, "4002", posixTime('2016-01-05T20:01:02Z')], [3000, 2, "15B42", 0] ],
279                     posixTime('2016-01-05T20:01:02Z'), 5002, posixTime('2016-01-05T22:37:02Z'), "12", 7
280                 ],
281                 [
282                     1003, 113, 1, 113, 113 * 113, false,
283                     [ [2003, 1, "4003", posixTime('2016-01-05T23:19:03Z')], [3000, 2, "15B42", 0] ],
284                     posixTime('2016-01-05T23:19:03Z'), 5003, posixTime('2016-01-06T23:19:03Z'), "13", 7
285                 ],
286                 [
287                     1004, 124, 1, 124, 124 * 124, false,
288                     [ [2004, 1, "4004", posixTime('2016-01-06T01:52:04Z')], [3001, 2, "15C50", 0] ],
289                     posixTime('2016-01-06T01:52:04Z'), 5004, posixTime('2016-01-06T02:42:04Z'), "14", 7
290                 ],
291                 [
292                     1005, 115, 1, 115, 115 * 115, true,
293                     [ [2005, 1, "4005", posixTime('2016-01-06T03:22:05Z')], [3001, 2, "15C50", 0] ],
294                     posixTime('2016-01-06T03:22:05Z'), 5005, posixTime('2016-01-06T06:01:05Z'), "15", 7
295                 ],
296                 [
297                     1006, 116, 1, 116, 116 * 116, false,
298                     [ [2006, 1, "4006", posixTime('2016-01-06T05:59:06Z')], [3001, 2, "15C50", 0] ],
299                     posixTime('2016-01-06T05:59:06Z'), 5006, posixTime('2016-01-06T08:34:06Z'), "16", 7
300                 ]
301             ],
302             "baseline": [
303                 [
304                     7000, baselineStart, 1, baselineStart, baselineStart * baselineStart, false,
305                     [ ],
306                     posixTime('2016-01-05T12:00:30Z'), 5030, posixTime('2016-01-05T12:00:30Z'), "30", 7
307                 ],
308                 [
309                     7001, baselineStart + 1, 1, baselineStart + 1, Math.pow(baselineStart + 1, 2), false,
310                     [ ],
311                     posixTime('2016-01-06T00:00:31Z'), 5031, posixTime('2016-01-06T00:00:31Z'), "31", 7
312                 ],
313             ],
314             "target": [
315                 [
316                     8000, targetStart, 1, targetStart, targetStart * targetStart, false,
317                     [ ],
318                     posixTime('2016-01-05T12:00:30Z'), 5030, posixTime('2016-01-05T12:00:30Z'), "90", 7
319                 ],
320                 [
321                     8001, targetStart + 1, 1, targetStart + 1, Math.pow(targetStart + 1, 2), false,
322                     [ ],
323                     posixTime('2016-01-06T00:00:31Z'), 5031, posixTime('2016-01-06T00:00:31Z'), "91", 7
324                 ],
325             ]
326         }};
327     },
328
329     createChartWithSampleCluster(context, sourceList = null, chartOptions = {}, className = 'TimeSeriesChart')
330     {
331         const TimeSeriesChart = context.symbols[className];
332         const MeasurementSet = context.symbols.MeasurementSet;
333
334         if (sourceList == null)
335             sourceList = [{type: 'current'}];
336
337         const sampleCluster = MeasurementSet.findSet(1, 1, 0);
338         for (let source of sourceList) {
339             if (!source.type)
340                 source.type = 'current';
341             source.measurementSet = sampleCluster;
342         }
343
344         const chart = new TimeSeriesChart(sourceList, chartOptions);
345         const element = chart.element();
346         element.style.width = chartOptions.width || '300px';
347         element.style.height = chartOptions.height || '100px';
348         context.document.body.appendChild(element);
349
350         return chart;
351     },
352
353     createInteractiveChartWithSampleCluster(context, sourceList = null, chartOptions = {})
354     {
355         if (sourceList == null)
356             sourceList = [{type: 'current', interactive: true}];
357         return this.createChartWithSampleCluster(context, sourceList, chartOptions, 'InteractiveTimeSeriesChart');
358     },
359
360     respondWithSampleCluster(request, options)
361     {
362         expect(request.url).to.be('../data/measurement-set-1-1.json');
363         expect(request.method).to.be('GET');
364         request.resolve(this.makeSampleCluster(options));
365     },
366 };
367
368 mocha.checkLeaks();
369 mocha.globals(['expect', 'BrowsingContext', 'CanvasTest', 'ChartTest', 'wait', 'waitForComponentsToRender']);
370 mocha.run();
371
372 </script>
373 </body>
374 </html>