REGRESSION(r230960): Browser tests under TimeSeriesChart fetchMeasurementSets all...
[WebKit-https.git] / Websites / perf.webkit.org / unit-tests / measurement-set-tests.js
1 'use strict';
2
3 const assert = require('assert');
4 if (!assert.almostEqual)
5     assert.almostEqual = require('./resources/almost-equal.js');
6 require('../tools/js/v3-models.js');
7 const BrowserPrivilegedAPI = require('../public/v3/privileged-api.js').PrivilegedAPI;
8 const MockRemoteAPI = require('./resources/mock-remote-api.js').MockRemoteAPI;
9 const MockModels = require('./resources/mock-v3-models.js').MockModels;
10
11 describe('MeasurementSet', () => {
12     MockModels.inject();
13     const requests = MockRemoteAPI.inject(null, BrowserPrivilegedAPI);
14
15     beforeEach(() => {
16         MeasurementSet._set = null;
17     });
18
19     function waitForMeasurementSet()
20     {
21         return new Promise((resolve) => setTimeout(resolve, 0));
22     }
23
24     describe('findSet', () => {
25         it('should create a new MeasurementSet for a new pair of platform and matric', () => {
26             assert.notEqual(MeasurementSet.findSet(1, 1, 3000), MeasurementSet.findSet(1, 2, 3000));
27             assert.notEqual(MeasurementSet.findSet(1, 1, 3000), MeasurementSet.findSet(2, 1, 3000));
28         });
29
30         it('should not create a new MeasurementSet when the same pair of platform and matric are requested', () => {
31             assert.equal(MeasurementSet.findSet(1, 1), MeasurementSet.findSet(1, 1));
32         });
33     });
34
35     describe('findClusters', () => {
36
37         it('should return clusters that exist', () => {
38             const set = MeasurementSet.findSet(1, 1, 1467852503940);
39             let callCount = 0;
40             const promise = set.fetchBetween(1465084800000, 1470268800000, () => {
41                 callCount++;
42             });
43             assert.equal(requests.length, 1);
44             assert.equal(requests[0].url, '/data/measurement-set-1-1.json');
45
46             requests[0].resolve({
47                 'clusterStart': 946684800000,
48                 'clusterSize': 5184000000,
49                 'formatMap': [],
50                 'configurations': {current: []},
51                 'startTime': 1465084800000,
52                 'endTime': 1470268800000,
53                 'lastModified': 1467852503940,
54                 'clusterCount': 5,
55                 'status': 'OK'});
56
57             return promise.then(() => {
58                 assert.deepEqual(set.findClusters(0, Date.now()), [1449532800000, 1454716800000, 1459900800000, 1465084800000, 1470268800000]);
59             });
60         });
61
62     });
63
64     describe('fetchBetween', () => {
65         it('should always request the cached primary cluster first', () => {
66             const set = MeasurementSet.findSet(1, 1, 3000);
67             let callCount = 0;
68             set.fetchBetween(1000, 2000, () => callCount++);
69             assert.equal(requests.length, 1);
70             assert.equal(requests[0].url, '/data/measurement-set-1-1.json');
71             assert.equal(callCount, 0);
72         });
73
74         it('should not request the cached primary cluster twice', () => {
75             const set = MeasurementSet.findSet(1, 1, 3000);
76             let callCount = 0;
77             set.fetchBetween(1000, 2000, () => callCount++);
78             assert.equal(requests.length, 1);
79             assert.equal(callCount, 0);
80             assert.equal(requests[0].url, '/data/measurement-set-1-1.json');
81             set.fetchBetween(2000, 3000, () => callCount++);
82             assert.equal(requests.length, 1);
83             assert.equal(callCount, 0);
84         });
85
86         it('should invoke the callback when the requested range is in the cached primary cluster', () => {
87             const set = MeasurementSet.findSet(1, 1, 3000);
88             let callCount = 0;
89             const promise = set.fetchBetween(2000, 3000, () => callCount++);
90             assert.equal(requests.length, 1);
91             assert.equal(requests[0].url, '/data/measurement-set-1-1.json');
92
93             requests[0].resolve({
94                 'clusterStart': 1000,
95                 'clusterSize': 1000,
96                 'formatMap': [],
97                 'configurations': {current: []},
98                 'startTime': 2000,
99                 'endTime': 3000,
100                 'lastModified': 3000,
101                 'clusterCount': 2,
102                 'status': 'OK'});
103
104             return promise.then(() => {
105                 assert.equal(callCount, 1);
106                 assert.equal(requests.length, 1);
107             });
108         });
109
110         it('should invoke the callback and fetch a secondary cluster when the cached primary cluster is within the requested range', () => {
111             const set = MeasurementSet.findSet(1, 1, 3000);
112             let callCount = 0;
113             const promise = set.fetchBetween(1000, 3000, () => callCount++);
114             assert.equal(requests.length, 1);
115             assert.equal(requests[0].url, '/data/measurement-set-1-1.json');
116
117             requests[0].resolve({
118                 'clusterStart': 1000,
119                 'clusterSize': 1000,
120                 'formatMap': [],
121                 'configurations': {current: []},
122                 'startTime': 2000,
123                 'endTime': 3000,
124                 'lastModified': 3000,
125                 'clusterCount': 2,
126                 'status': 'OK'});
127
128             return waitForMeasurementSet().then(() => {
129                 assert.equal(callCount, 1);
130                 assert.equal(requests.length, 2);
131                 assert.equal(requests[1].url, '/data/measurement-set-1-1-2000.json');
132             });
133         });
134
135         it('should request additional secondary clusters as requested', () => {
136             const set = MeasurementSet.findSet(1, 1, 5000);
137             let callCountForWaitingCallback = 0;
138             set.fetchBetween(2000, 3000, () => callCountForWaitingCallback++);
139             assert.equal(requests.length, 1);
140             assert.equal(requests[0].url, '/data/measurement-set-1-1.json');
141
142             requests[0].resolve({
143                 'clusterStart': 1000,
144                 'clusterSize': 1000,
145                 'formatMap': [],
146                 'configurations': {current: []},
147                 'startTime': 4000,
148                 'endTime': 5000,
149                 'lastModified': 5000,
150                 'clusterCount': 4,
151                 'status': 'OK'});
152
153             let callCount = 0;
154             return waitForMeasurementSet().then(() => {
155                 assert.equal(requests.length, 2);
156                 assert.equal(requests[1].url, '/data/measurement-set-1-1-3000.json');
157
158                 set.fetchBetween(0, 7000, () => callCount++);
159
160                 return waitForMeasurementSet();
161             }).then(() => {
162                 assert.equal(callCountForWaitingCallback, 0);
163                 assert.equal(callCount, 1);
164                 assert.equal(requests.length, 4);
165                 assert.equal(requests[2].url, '/data/measurement-set-1-1-2000.json');
166                 assert.equal(requests[3].url, '/data/measurement-set-1-1-4000.json');
167             });
168         });
169
170         it('should request secondary clusters which forms a superset of the requested range', () => {
171             const set = MeasurementSet.findSet(1, 1, 5000);
172             let callCount = 0;
173             const promise = set.fetchBetween(2707, 4207, () => callCount++);
174             assert.equal(requests.length, 1);
175             assert.equal(requests[0].url, '/data/measurement-set-1-1.json');
176
177             requests[0].resolve({
178                 'clusterStart': 1000,
179                 'clusterSize': 1000,
180                 'formatMap': [],
181                 'configurations': {current: []},
182                 'startTime': 4000,
183                 'endTime': 5000,
184                 'lastModified': 5000,
185                 'clusterCount': 3,
186                 'status': 'OK'});
187
188             return waitForMeasurementSet().then(() => {
189                 assert.equal(requests.length, 3);
190                 assert.equal(requests[1].url, '/data/measurement-set-1-1-3000.json');
191                 assert.equal(requests[2].url, '/data/measurement-set-1-1-4000.json');
192                 assert.equal(callCount, 1); // 4000-4207
193             });
194         });
195
196         it('should not request secondary clusters that are not requested', () => {
197             const set = MeasurementSet.findSet(1, 1, 5000);
198             let callCountForWaitingCallback = 0;
199             set.fetchBetween(3200, 3700, () => callCountForWaitingCallback++);
200             assert.equal(requests.length, 1);
201             assert.equal(requests[0].url, '/data/measurement-set-1-1.json');
202
203             requests[0].resolve({
204                 'clusterStart': 1000,
205                 'clusterSize': 1000,
206                 'formatMap': [],
207                 'configurations': {current: []},
208                 'startTime': 4000,
209                 'endTime': 5000,
210                 'lastModified': 5000,
211                 'clusterCount': 4,
212                 'status': 'OK'});
213
214             let callCount = 0;
215             return waitForMeasurementSet().then(() => {
216                 assert.equal(requests.length, 2);
217                 assert.equal(requests[1].url, '/data/measurement-set-1-1-4000.json');
218                 set.fetchBetween(1207, 1293, () => callCount++);
219                 return waitForMeasurementSet();
220             }).then(() => {
221                 assert.equal(callCountForWaitingCallback, 0);
222                 assert.equal(callCount, 0);
223                 assert.equal(requests.length, 3);
224                 assert.equal(requests[2].url, '/data/measurement-set-1-1-2000.json');
225                 set.fetchBetween(1964, 3401, () => callCount++);
226                 return waitForMeasurementSet();
227             }).then(() => {
228                 assert.equal(callCountForWaitingCallback, 0);
229                 assert.equal(callCount, 0);
230                 assert.equal(requests.length, 4);
231                 assert.equal(requests[3].url, '/data/measurement-set-1-1-3000.json');
232             });
233         });
234
235         it('should not request a cluster before the very first cluster', () => {
236             const set = MeasurementSet.findSet(1, 1, 5000);
237             let callCount = 0;
238             set.fetchBetween(0, 3000, () => callCount++);
239             assert.equal(requests.length, 1);
240             assert.equal(requests[0].url, '/data/measurement-set-1-1.json');
241
242             requests[0].resolve({
243                 'clusterStart': 2000,
244                 'clusterSize': 1000,
245                 'formatMap': [],
246                 'configurations': {current: []},
247                 'startTime': 2000,
248                 'endTime': 3000,
249                 'lastModified': 5000,
250                 'clusterCount': 1,
251                 'status': 'OK'});
252
253             return waitForMeasurementSet().then(() => {
254                 assert.equal(requests.length, 1);
255                 assert.equal(callCount, 1);
256             });
257         });
258
259         it('should invoke the callback when the fetching of the primray cluster fails', () => {
260             const set = MeasurementSet.findSet(1, 1, 3000);
261             let callCount = 0;
262             let rejected = false;
263             set.fetchBetween(1000, 3000, () => callCount++).catch(() => rejected = true);
264             assert.equal(requests.length, 1);
265             assert.equal(requests[0].url, '/data/measurement-set-1-1.json');
266
267             requests[0].reject(500);
268
269             return waitForMeasurementSet().then(() => {
270                 assert.equal(callCount, 1);
271                 assert.equal(requests.length, 1);
272                 assert(rejected);
273             });
274         });
275
276         it('should request the uncached primary cluster when the cached cluster is outdated', () => {
277             const set = MeasurementSet.findSet(1, 1, 3005);
278             let callCount = 0;
279             set.fetchBetween(1000, 2000, () => callCount++);
280             assert.equal(requests.length, 1);
281             assert.equal(requests[0].url, '/data/measurement-set-1-1.json');
282
283             requests[0].resolve({
284                 'clusterStart': 1000,
285                 'clusterSize': 1000,
286                 'formatMap': [],
287                 'configurations': {current: []},
288                 'startTime': 2000,
289                 'endTime': 3000,
290                 'lastModified': 3000,
291                 'clusterCount': 2,
292                 'status': 'OK'});
293
294             return waitForMeasurementSet().then(() => {
295                 assert.equal(callCount, 0);
296                 assert.equal(requests.length, 2);
297                 assert.equal(requests[1].url, '/api/measurement-set?platform=1&metric=1');
298             });
299         });
300
301         it('should request the uncached primary cluster when the cached cluster is 404', () => {
302             const set = MeasurementSet.findSet(1, 1, 3005);
303             let callCount = 0;
304             set.fetchBetween(1000, 2000, () => callCount++);
305             assert.equal(requests.length, 1);
306             assert.equal(requests[0].url, '/data/measurement-set-1-1.json');
307
308             requests[0].reject(404);
309
310             return waitForMeasurementSet().then(() => {
311                 assert.equal(callCount, 0);
312                 assert.equal(requests.length, 2);
313                 assert.equal(requests[1].url, '/api/measurement-set?platform=1&metric=1');
314             });
315         });
316
317         it('should request the uncached primary cluster when noCache is true', () => {
318             const set = MeasurementSet.findSet(1, 1, 3000);
319             let callCount = 0;
320             set.fetchBetween(1000, 3000, () => callCount++);
321             assert.equal(requests.length, 1);
322             assert.equal(requests[0].url, '/data/measurement-set-1-1.json');
323
324             requests[0].resolve({
325                 'clusterStart': 1000,
326                 'clusterSize': 1000,
327                 'formatMap': [],
328                 'configurations': {current: []},
329                 'startTime': 2000,
330                 'endTime': 3000,
331                 'lastModified': 3000,
332                 'clusterCount': 2,
333                 'status': 'OK'});
334
335             let noCacheFetchCount = 0;
336             return waitForMeasurementSet().then(() => {
337                 assert.equal(callCount, 1);
338                 assert.equal(noCacheFetchCount, 0);
339                 assert.equal(set._sortedClusters.length, 1);
340                 assert.equal(requests.length, 2);
341                 assert.equal(requests[1].url, '/data/measurement-set-1-1-2000.json');
342
343                 requests[1].resolve({
344                     'clusterStart': 1000,
345                     'clusterSize': 1000,
346                     'formatMap': [],
347                     'configurations': {current: []},
348                     'startTime': 1000,
349                     'endTime': 2000,
350                     'lastModified': 3000,
351                     'clusterCount': 2,
352                     'status': 'OK'});
353
354                 set.fetchBetween(1000, 3000, () => noCacheFetchCount++, true /* noCache */);
355
356                 return waitForMeasurementSet();
357             }).then(() => {
358                 assert.equal(callCount, 2);
359                 assert.equal(noCacheFetchCount, 0);
360                 assert.equal(set._sortedClusters.length, 2);
361                 assert.equal(requests.length, 3);
362                 assert.equal(requests[2].url, '/api/measurement-set?platform=1&metric=1');
363
364                 requests[2].resolve({
365                     'clusterStart': 1000,
366                     'clusterSize': 1000,
367                     'formatMap': [],
368                     'configurations': {current: []},
369                     'startTime': 2000,
370                     'endTime': 3000,
371                     'lastModified': 3000,
372                     'clusterCount': 2,
373                     'status': 'OK'});
374
375                 return waitForMeasurementSet();
376             }).then(() => {
377                 assert.equal(callCount, 2);
378                 assert.equal(noCacheFetchCount, 1);
379                 assert.equal(set._sortedClusters.length, 2);
380                 assert.equal(requests.length, 4);
381                 assert.equal(requests[3].url, '/data/measurement-set-1-1-2000.json');
382
383                 requests[3].resolve({
384                     'clusterStart': 1000,
385                     'clusterSize': 1000,
386                     'formatMap': [],
387                     'configurations': {current: []},
388                     'startTime': 1000,
389                     'endTime': 2000,
390                     'lastModified': 3000,
391                     'clusterCount': 2,
392                     'status': 'OK'});
393
394                 return waitForMeasurementSet();
395             }).then(() => {
396                 assert.equal(callCount, 3);
397                 assert.equal(noCacheFetchCount, 2);
398                 assert.equal(set._sortedClusters.length, 2);
399                 assert.equal(requests.length, 4);
400             });
401         });
402
403         it('should not request the primary cluster twice when multiple clients request it but should invoke all callbacks', () => {
404             const set = MeasurementSet.findSet(1, 1, 3000);
405             let callCount = 0;
406             set.fetchBetween(2000, 3000, () => callCount++);
407             assert.equal(requests.length, 1);
408             assert.equal(requests[0].url, '/data/measurement-set-1-1.json');
409
410             let alternativeCallCount = 0;
411             set.fetchBetween(2000, 3000, () => alternativeCallCount++);
412
413             requests[0].resolve({
414                 'clusterStart': 1000,
415                 'clusterSize': 1000,
416                 'formatMap': [],
417                 'configurations': {current: []},
418                 'startTime': 2000,
419                 'endTime': 3000,
420                 'lastModified': 3000,
421                 'clusterCount': 2,
422                 'status': 'OK'});
423
424             return waitForMeasurementSet().then(() => {
425                 assert.equal(callCount, 1);
426                 assert.equal(alternativeCallCount, 1);
427                 assert.equal(requests.length, 1);
428             });
429         });
430
431         it('should invoke callback for each secondary clusters that are fetched or rejected', () => {
432             const set = MeasurementSet.findSet(1, 1, 5000);
433             let callCountFor4000 = 0;
434             set.fetchBetween(3200, 3700, () => callCountFor4000++);
435             assert.equal(requests.length, 1);
436             assert.equal(requests[0].url, '/data/measurement-set-1-1.json');
437
438             requests[0].resolve({
439                 'clusterStart': 1000,
440                 'clusterSize': 1000,
441                 'formatMap': [],
442                 'configurations': {current: []},
443                 'startTime': 4000,
444                 'endTime': 5000,
445                 'lastModified': 5000,
446                 'clusterCount': 4,
447                 'status': 'OK'});
448
449             let callCountFor4000To5000 = 0;
450             let callCountFor2000 = 0;
451             let callCountFor2000To4000 = 0;
452             return waitForMeasurementSet().then(() => {
453                 assert.equal(callCountFor4000, 0);
454                 assert.equal(requests.length, 2);
455                 assert.equal(requests[1].url, '/data/measurement-set-1-1-4000.json');
456
457                 set.fetchBetween(3708, 4800, () => callCountFor4000To5000++);
458                 return waitForMeasurementSet();
459             }).then(() => {
460                 assert.equal(callCountFor4000To5000, 1);
461                 assert.equal(requests.length, 2);
462
463                 set.fetchBetween(1207, 1293, () => callCountFor2000++);
464                 return waitForMeasurementSet();
465             }).then(() => {
466                 assert.equal(callCountFor2000, 0);
467                 assert.equal(requests.length, 3);
468                 assert.equal(requests[2].url, '/data/measurement-set-1-1-2000.json');
469
470                 requests[2].resolve({
471                     'formatMap': [],
472                     'configurations': {current: []},
473                     'startTime': 1000,
474                     'endTime': 2000,
475                     'lastModified': 5000,
476                     'status': 'OK'});
477                 return waitForMeasurementSet();
478             }).then(() => {
479                 assert.equal(requests.length, 3);
480                 assert.equal(callCountFor4000, 0);
481                 assert.equal(callCountFor4000To5000, 1);
482                 assert.equal(callCountFor2000, 1);
483
484                 set.fetchBetween(1964, 3401, () => { callCountFor2000To4000++; });
485                 return waitForMeasurementSet();
486             }).then(() => {
487                 assert.equal(callCountFor2000To4000, 1);
488                 assert.equal(requests.length, 4);
489                 assert.equal(requests[3].url, '/data/measurement-set-1-1-3000.json');
490
491                 requests[3].resolve({
492                     'formatMap': [],
493                     'configurations': {current: []},
494                     'startTime': 2000,
495                     'endTime': 3000,
496                     'lastModified': 5000,
497                     'status': 'OK'});
498                 return waitForMeasurementSet();
499             }).then(() => {
500                 assert.equal(callCountFor4000, 0);
501                 assert.equal(callCountFor4000To5000, 1);
502                 assert.equal(callCountFor2000, 1);
503                 assert.equal(callCountFor2000To4000, 2);
504                 assert.equal(requests.length, 4);
505
506                 requests[1].resolve({
507                     'formatMap': [],
508                     'configurations': {current: []},
509                     'startTime': 3000,
510                     'endTime': 4000,
511                     'lastModified': 5000,
512                     'status': 'OK'});
513                 return waitForMeasurementSet();
514             }).then(() => {
515                 assert.equal(callCountFor4000, 1);
516                 assert.equal(callCountFor4000To5000, 2);
517                 assert.equal(callCountFor2000, 1);
518                 assert.equal(callCountFor2000To4000, 3);
519                 assert.equal(requests.length, 4);
520             });
521         });
522
523     });
524
525     describe('hasFetchedRange', () => {
526
527         it('should return false when no clusters had been fetched', () => {
528             var set = MeasurementSet.findSet(1, 1, 3000);
529             assert(!set.hasFetchedRange(2000, 3000));
530         });
531
532         it('should return true when a single cluster contains the entire range', () => {
533             const set = MeasurementSet.findSet(1, 1, 3000);
534             const promise = set.fetchBetween(2000, 3000);
535             assert.equal(requests.length, 1);
536             assert.equal(requests[0].url, '/data/measurement-set-1-1.json');
537
538             requests[0].resolve({
539                 'clusterStart': 1000,
540                 'clusterSize': 1000,
541                 'formatMap': [],
542                 'configurations': {current: []},
543                 'startTime': 2000,
544                 'endTime': 3000,
545                 'lastModified': 3000,
546                 'clusterCount': 2,
547                 'status': 'OK'});
548
549             return promise.then(() => {
550                 assert(set.hasFetchedRange(2001, 2999));
551                 assert(set.hasFetchedRange(2000, 3000));
552             });
553         });
554
555         it('should return false when the range starts before the fetched cluster', () => {
556             const set = MeasurementSet.findSet(1, 1, 3000);
557             const promise = set.fetchBetween(2000, 3000);
558             assert.equal(requests.length, 1);
559             assert.equal(requests[0].url, '/data/measurement-set-1-1.json');
560
561             requests[0].resolve({
562                 'clusterStart': 1000,
563                 'clusterSize': 1000,
564                 'formatMap': [],
565                 'configurations': {current: []},
566                 'startTime': 2000,
567                 'endTime': 3000,
568                 'lastModified': 3000,
569                 'clusterCount': 2,
570                 'status': 'OK'});
571
572             return promise.then(() => {
573                 assert(!set.hasFetchedRange(1500, 3000));
574             });
575         });
576
577         it('should return false when the range ends after the fetched cluster', () => {
578             const set = MeasurementSet.findSet(1, 1, 5000);
579             const promise = set.fetchBetween(2000, 3000);
580             assert.equal(requests.length, 1);
581             assert.equal(requests[0].url, '/data/measurement-set-1-1.json');
582
583             requests[0].resolve({
584                 'clusterStart': 1000,
585                 'clusterSize': 1000,
586                 'formatMap': [],
587                 'configurations': {current: []},
588                 'startTime': 4000,
589                 'endTime': 5000,
590                 'lastModified': 5000,
591                 'clusterCount': 3,
592                 'status': 'OK'});
593
594             return waitForMeasurementSet().then(() => {
595                 assert.equal(requests.length, 2);
596                 assert.equal(requests[1].url, '/data/measurement-set-1-1-3000.json');
597                 requests[1].resolve({
598                     'clusterStart': 1000,
599                     'clusterSize': 1000,
600                     'formatMap': [],
601                     'configurations': {current: []},
602                     'startTime': 2000,
603                     'endTime': 3000,
604                     'lastModified': 5000,
605                     'clusterCount': 3,
606                     'status': 'OK'});
607             }).then(() => {
608                 assert(!set.hasFetchedRange(2500, 3500));
609             });
610         });
611
612         it('should return true when the range is within two fetched clusters', () => {
613             const set = MeasurementSet.findSet(1, 1, 5000);
614             set.fetchBetween(2000, 3000);
615             assert.equal(requests.length, 1);
616             assert.equal(requests[0].url, '/data/measurement-set-1-1.json');
617
618             requests[0].resolve({
619                 'clusterStart': 1000,
620                 'clusterSize': 1000,
621                 'formatMap': [],
622                 'configurations': {current: []},
623                 'startTime': 3000,
624                 'endTime': 4000,
625                 'lastModified': 5000,
626                 'clusterCount': 2,
627                 'status': 'OK'});
628
629             return waitForMeasurementSet().then(() => {
630                 assert.equal(requests.length, 2);
631                 assert.equal(requests[1].url, '/data/measurement-set-1-1-3000.json');
632                 requests[1].resolve({
633                     'clusterStart': 1000,
634                     'clusterSize': 1000,
635                     'formatMap': [],
636                     'configurations': {current: []},
637                     'startTime': 2000,
638                     'endTime': 3000,
639                     'lastModified': 5000,
640                     'clusterCount': 2,
641                     'status': 'OK'});                
642             }).then(() => {
643                 assert(set.hasFetchedRange(2500, 3500));
644             });
645         });
646
647         it('should return false when there is a cluster missing in the range', () => {
648             const set = MeasurementSet.findSet(1, 1, 5000);
649             set.fetchBetween(2000, 5000);
650             assert.equal(requests.length, 1);
651             assert.equal(requests[0].url, '/data/measurement-set-1-1.json');
652
653             requests[0].resolve({
654                 'clusterStart': 1000,
655                 'clusterSize': 1000,
656                 'formatMap': [],
657                 'configurations': {current: []},
658                 'startTime': 4000,
659                 'endTime': 5000,
660                 'lastModified': 5000,
661                 'clusterCount': 4,
662                 'status': 'OK'});
663
664             return waitForMeasurementSet().then(() => {
665                 assert.equal(requests.length, 3);
666                 assert.equal(requests[1].url, '/data/measurement-set-1-1-3000.json');
667                 assert.equal(requests[2].url, '/data/measurement-set-1-1-4000.json');
668                 requests[1].resolve({
669                     'clusterStart': 1000,
670                     'clusterSize': 1000,
671                     'formatMap': [],
672                     'configurations': {current: []},
673                     'startTime': 2000,
674                     'endTime': 3000,
675                     'lastModified': 5000,
676                     'clusterCount': 2,
677                     'status': 'OK'});
678             }).then(() => {
679                 assert(!set.hasFetchedRange(2500, 4500));
680                 assert(set.hasFetchedRange(2100, 2300));
681                 assert(set.hasFetchedRange(4000, 4800));
682             });
683         });
684
685         it('should return true even when the range extends beyond the primary cluster', () => {
686             const set = MeasurementSet.findSet(1, 1, 3000);
687             const promise = set.fetchBetween(2000, 3000);
688             assert.equal(requests.length, 1);
689             assert.equal(requests[0].url, '/data/measurement-set-1-1.json');
690
691             requests[0].resolve({
692                 'clusterStart': 1000,
693                 'clusterSize': 1000,
694                 'formatMap': [],
695                 'configurations': {current: []},
696                 'startTime': 2000,
697                 'endTime': 3000,
698                 'lastModified': 3000,
699                 'clusterCount': 2,
700                 'status': 'OK'});
701
702             return promise.then(() => {
703                 assert(set.hasFetchedRange(2001, 5000));
704             });
705         });
706
707     });
708
709     describe('fetchedTimeSeries', () => {
710
711         // Data from https://perf.webkit.org/v3/#/charts?paneList=((15-769))&since=1476426488465
712         const sampleCluster = {
713             "clusterStart": 946684800000,
714             "clusterSize": 5184000000,
715             "configurations": {
716                 "current": [
717                     [
718                         26530031, 135.26375, 80, 10821.1, 1481628.13, false,
719                         [ [27173, 1, "210096", null, 1482398562950] ],
720                         1482398562950, 52999, 1482413222311, "10877", 7
721                     ],
722                     [
723                         26530779, 153.2675, 80, 12261.4, 1991987.4, true, // changed to true.
724                         [ [27174,1,"210097", null, 1482424870729] ],
725                         1482424870729, 53000, 1482424992735, "10878", 7
726                     ],
727                     [
728                         26532275, 134.2725, 80, 10741.8, 1458311.88, false,
729                         [ [ 27176, 1, "210102", null, 1482431464371 ] ],
730                         1482431464371, 53002, 1482436041865, "10879", 7
731                     ],
732                     [
733                         26547226, 150.9625, 80, 12077, 1908614.94, false,
734                         [ [ 27195, 1, "210168", null, 1482852412735 ] ],
735                         1482852412735, 53022, 1482852452143, "10902", 7
736                     ],
737                     [
738                         26559915, 141.72, 80, 11337.6, 1633126.8, false,
739                         [ [ 27211, 1, "210222", null, 1483347732051 ] ],
740                         1483347732051, 53039, 1483347926429, "10924", 7
741                     ],
742                     [
743                         26564388, 138.13125, 80, 11050.5, 1551157.93, false,
744                         [ [ 27217, 1, "210231", null, 1483412171531 ] ],
745                         1483412171531, 53045, 1483415426049, "10930", 7
746                     ],
747                     [
748                         26568867, 144.16, 80, 11532.8, 1694941.1, false,
749                         [ [ 27222, 1, "210240", null, 1483469584347 ] ],
750                         1483469584347, 53051, 1483469642993, "10935", 7
751                     ]
752                 ]
753             },
754             "formatMap": [
755                 "id", "mean", "iterationCount", "sum", "squareSum", "markedOutlier",
756                 "revisions",
757                 "commitTime", "build", "buildTime", "buildNumber", "builder"
758             ],
759             "startTime": 1480636800000,
760             "endTime": 1485820800000,
761             "lastModified": 1484105738736,
762             "clusterCount": 1,
763             "elapsedTime": 56.421995162964,
764             "status": "OK"
765         };
766
767         let builder;
768         let webkit;
769         beforeEach(() => {
770             builder = new Builder(7, {name: 'EFL Linux 64-bit Release WK2 (Perf)', buildUrl: 'http://build.webkit.org/builders/$builderName/$buildNumber'});
771             webkit = new Repository(1, {name: 'WebKit', url: 'http://trac.webkit.org/changeset/$1'});
772         });
773
774         function fetchSampleCluster() {
775             const set = MeasurementSet.findSet(15, 769, 1484105738736);
776             const promise = set.fetchBetween(1476426488465, 1484203801573);
777             assert.equal(requests.length, 1);
778             assert.equal(requests[0].url, '/data/measurement-set-15-769.json');
779
780             requests[0].resolve(sampleCluster);
781
782             return waitForMeasurementSet().then(() => { return set; })
783         }
784
785         it('should include all data points from the fetched cluster when includeOutliers is true', () => {
786             let points;
787             return fetchSampleCluster().then((set) => {
788                 const includeOutliers = true;
789                 const extendToFuture = false;
790                 const fullSeries = set.fetchedTimeSeries('current', includeOutliers, extendToFuture);
791                 assert.equal(fullSeries.length(), 7);
792
793                 points = new Array(7);
794                 for (let i = 0; i < 7; i++)
795                     points[i] = fullSeries.findPointByIndex(i);
796             }).then(() => {
797                 const point = points[0];
798                 assert.equal(point.id, 26530031);
799
800                 const commitTime = 1482398562950;
801                 const commitSet = point.commitSet();
802                 assert.equal(point.commitSet(), commitSet);
803                 assert.deepEqual(commitSet.repositories(), [webkit]);
804                 assert.equal(commitSet.revisionForRepository(webkit), '210096');
805                 const commit = commitSet.commitForRepository(webkit);
806                 assert.equal(commit.repository(), webkit);
807                 assert.equal(+commit.time(), commitTime);
808                 assert.equal(commit.author(), null);
809                 assert.equal(commit.revision(), '210096');
810                 assert.equal(commit.message(), null);
811                 assert.equal(commit.url(), 'http://trac.webkit.org/changeset/210096');
812                 assert.equal(commit.label(), 'r210096');
813                 assert.equal(commit.title(), 'WebKit at r210096');
814                 assert.equal(commitSet.latestCommitTime(), commitTime);
815
816                 const build = point.build();
817                 assert.equal(point.build(), build);
818                 assert.equal(build.builder(), builder);
819                 assert.equal(build.buildNumber(), 10877);
820                 const buildTime = build.buildTime();
821                 assert(buildTime instanceof Date);
822                 assert.equal(+buildTime, 1482413222311);
823
824                 assert.equal(point.time, commitTime);
825                 assert.equal(point.value, 135.26375);
826                 assert.equal(point.sum, 10821.1);
827                 assert.equal(point.squareSum, 1481628.13);
828                 assert.equal(point.iterationCount, 80);
829                 assert.equal(point.markedOutlier, false);
830             }).then(() => {
831                 const point = points[1];
832                 assert.equal(point.id, 26530779);
833
834                 const commitTime = 1482424870729;
835                 const commitSet = point.commitSet();
836                 assert.equal(commitSet.revisionForRepository(webkit), '210097');
837                 const commit = commitSet.commitForRepository(webkit);
838                 assert.equal(+commit.time(), commitTime);
839                 assert.equal(commit.revision(), '210097');
840                 assert.equal(commitSet.latestCommitTime(), commitTime);
841
842                 const build = point.build();
843                 assert.equal(build.builder(), builder);
844                 assert.equal(build.buildNumber(), 10878);
845                 assert.equal(+build.buildTime(), 1482424992735);
846
847                 assert.equal(point.time, commitTime);
848                 assert.equal(point.value, 153.2675);
849                 assert.equal(point.sum, 12261.4);
850                 assert.equal(point.squareSum, 1991987.4);
851                 assert.equal(point.iterationCount, 80);
852                 assert.equal(point.markedOutlier, true);
853             }).then(() => {
854                 assert.equal(points[2].id, 26532275);
855                 assert.equal(points[2].commitSet().revisionForRepository(webkit), '210102');
856                 assert.equal(+points[2].build().buildTime(), 1482436041865);
857                 assert.equal(points[2].build().buildNumber(), 10879);
858                 assert.equal(points[2].time, 1482431464371);
859                 assert.equal(points[2].value, 134.2725);
860
861                 assert.equal(points[3].id, 26547226);
862                 assert.equal(points[3].commitSet().revisionForRepository(webkit), '210168');
863                 assert.equal(+points[3].build().buildTime(), 1482852452143);
864                 assert.equal(points[3].build().buildNumber(), 10902);
865                 assert.equal(points[3].time, 1482852412735);
866                 assert.equal(points[3].value, 150.9625);
867
868                 assert.equal(points[4].id, 26559915);
869                 assert.equal(points[4].commitSet().revisionForRepository(webkit), '210222');
870                 assert.equal(+points[4].build().buildTime(), 1483347926429);
871                 assert.equal(points[4].build().buildNumber(), 10924);
872                 assert.equal(points[4].time, 1483347732051);
873                 assert.equal(points[4].value, 141.72);
874
875                 assert.equal(points[5].id, 26564388);
876                 assert.equal(points[5].commitSet().revisionForRepository(webkit), '210231');
877                 assert.equal(+points[5].build().buildTime(), 1483415426049);
878                 assert.equal(points[5].build().buildNumber(), 10930);
879                 assert.equal(points[5].time, 1483412171531);
880                 assert.equal(points[5].value, 138.13125);
881
882                 assert.equal(points[6].id, 26568867);
883                 assert.equal(points[6].commitSet().revisionForRepository(webkit), '210240');
884                 assert.equal(+points[6].build().buildTime(), 1483469642993);
885                 assert.equal(points[6].build().buildNumber(), 10935);
886                 assert.equal(points[6].time, 1483469584347);
887                 assert.equal(points[6].value, 144.16);
888             });
889         });
890
891         it('should include all data points from the fetched cluster when includeOutliers is false', () => {
892             return fetchSampleCluster().then((set) => {
893                 const includeOutliers = false;
894                 const extendToFuture = false;
895                 const fullSeries = set.fetchedTimeSeries('current', includeOutliers, extendToFuture);
896                 assert.equal(fullSeries.length(), 6);
897
898                 const points = new Array(6);
899                 for (let i = 0; i < 6; i++)
900                     points[i] = fullSeries.findPointByIndex(i);
901
902                 assert.equal(points[0].id, 26530031);
903                 assert.equal(points[0].commitSet().revisionForRepository(webkit), '210096');
904                 assert.equal(+points[0].build().buildTime(), 1482413222311);
905                 assert.equal(points[0].build().buildNumber(), 10877);
906                 assert.equal(points[0].time, 1482398562950);
907                 assert.equal(points[0].value, 135.26375);
908
909                 assert.equal(points[1].id, 26532275);
910                 assert.equal(points[1].commitSet().revisionForRepository(webkit), '210102');
911                 assert.equal(+points[1].build().buildTime(), 1482436041865);
912                 assert.equal(points[1].build().buildNumber(), 10879);
913                 assert.equal(points[1].time, 1482431464371);
914                 assert.equal(points[1].value, 134.2725);
915
916                 assert.equal(points[2].id, 26547226);
917                 assert.equal(points[2].commitSet().revisionForRepository(webkit), '210168');
918                 assert.equal(+points[2].build().buildTime(), 1482852452143);
919                 assert.equal(points[2].build().buildNumber(), 10902);
920                 assert.equal(points[2].time, 1482852412735);
921                 assert.equal(points[2].value, 150.9625);
922
923                 assert.equal(points[3].id, 26559915);
924                 assert.equal(points[3].commitSet().revisionForRepository(webkit), '210222');
925                 assert.equal(+points[3].build().buildTime(), 1483347926429);
926                 assert.equal(points[3].build().buildNumber(), 10924);
927                 assert.equal(points[3].time, 1483347732051);
928                 assert.equal(points[3].value, 141.72);
929
930                 assert.equal(points[4].id, 26564388);
931                 assert.equal(points[4].commitSet().revisionForRepository(webkit), '210231');
932                 assert.equal(+points[4].build().buildTime(), 1483415426049);
933                 assert.equal(points[4].build().buildNumber(), 10930);
934                 assert.equal(points[4].time, 1483412171531);
935                 assert.equal(points[4].value, 138.13125);
936
937                 assert.equal(points[5].id, 26568867);
938                 assert.equal(points[5].commitSet().revisionForRepository(webkit), '210240');
939                 assert.equal(+points[5].build().buildTime(), 1483469642993);
940                 assert.equal(points[5].build().buildNumber(), 10935);
941                 assert.equal(points[5].time, 1483469584347);
942                 assert.equal(points[5].value, 144.16);
943             });
944         });
945
946     });
947
948     describe('fetchSegmentation', () => {
949
950         var simpleSegmentableValues = [
951             1546.5603, 1548.1536, 1563.5452, 1539.7823, 1546.4184, 1548.9299, 1532.5444, 1546.2800, 1547.1760, 1551.3507,
952             1548.3277, 1544.7673, 1542.7157, 1538.1700, 1538.0948, 1543.0364, 1537.9737, 1542.2611, 1543.9685, 1546.4901,
953             1544.4080, 1540.8671, 1537.3353, 1549.4331, 1541.4436, 1544.1299, 1550.1770, 1553.1872, 1549.3417, 1542.3788,
954             1543.5094, 1541.7905, 1537.6625, 1547.3840, 1538.5185, 1549.6764, 1556.6138, 1552.0476, 1541.7629, 1544.7006,
955             /* segments changes here */
956             1587.1390, 1594.5451, 1586.2430, 1596.7310, 1548.1423
957         ];
958
959         function makeSampleRuns(values, startRunId, startTime, timeIncrement)
960         {
961             var runId = startRunId;
962             var buildId = 3400;
963             var buildNumber = 1;
964             var makeRun = function (value, commitTime) {
965                 return [runId++, value, 1, value, value, false, [], commitTime, commitTime + 10, buildId++, buildNumber++, MockModels.builder.id()];
966             }
967
968             timeIncrement = Math.floor(timeIncrement);
969             var runs = values.map(function (value, index) { return makeRun(value, startTime + index * timeIncrement); })
970             
971             return runs;
972         }
973
974         it('should be able to segment a single cluster', () => {
975             const set = MeasurementSet.findSet(1, 1, 5000);
976             const promise = set.fetchBetween(4000, 5000);
977             assert.equal(requests.length, 1);
978             assert.equal(requests[0].url, '/data/measurement-set-1-1.json');
979
980             requests[0].resolve({
981                 'clusterStart': 1000,
982                 'clusterSize': 1000,
983                 'formatMap': ['id', 'mean', 'iterationCount', 'sum', 'squareSum', 'markedOutlier', 'revisions', 'commitTime', 'build', 'buildTime', 'buildNumber', 'builder'],
984                 'configurations': {current: makeSampleRuns(simpleSegmentableValues, 6400, 4000, 1000 / 50)},
985                 'startTime': 4000,
986                 'endTime': 5000,
987                 'lastModified': 5000,
988                 'clusterCount': 4,
989                 'status': 'OK'});
990
991             var timeSeries;
992             assert.equal(set.fetchedTimeSeries('current', false, false).length(), 0);
993             return waitForMeasurementSet().then(() => {
994                 timeSeries = set.fetchedTimeSeries('current', false, false);
995                 assert.equal(timeSeries.length(), 45);
996                 assert.equal(timeSeries.firstPoint().time, 4000);
997                 assert.equal(timeSeries.lastPoint().time, 4880);
998                 return set.fetchSegmentation('segmentTimeSeriesByMaximizingSchwarzCriterion', [], 'current', false);
999             }).then((segmentation) => {
1000                 assert.equal(segmentation.length, 4);
1001
1002                 assert.equal(segmentation[0].time, 4000);
1003                 assert.almostEqual(segmentation[0].value, 1545.082);
1004                 assert.equal(segmentation[0].value, segmentation[1].value);
1005                 assert.equal(segmentation[1].time, timeSeries.findPointByIndex(39).time);
1006
1007                 assert.equal(segmentation[2].time, timeSeries.findPointByIndex(39).time);
1008                 assert.almostEqual(segmentation[2].value, 1581.872);
1009                 assert.equal(segmentation[2].value, segmentation[3].value);
1010                 assert.equal(segmentation[3].time, 4880);
1011             });
1012         });
1013
1014         it('should be able to segment two clusters', () => {
1015             const set = MeasurementSet.findSet(1, 1, 5000);
1016             const promise = set.fetchBetween(3000, 5000);
1017             assert.equal(requests.length, 1);
1018             assert.equal(requests[0].url, '/data/measurement-set-1-1.json');
1019
1020             requests[0].resolve({
1021                 'clusterStart': 1000,
1022                 'clusterSize': 1000,
1023                 'formatMap': ['id', 'mean', 'iterationCount', 'sum', 'squareSum', 'markedOutlier', 'revisions', 'commitTime', 'build', 'buildTime', 'buildNumber', 'builder'],
1024                 'configurations': {current: makeSampleRuns(simpleSegmentableValues.slice(30), 6400, 4000, 1000 / 30)},
1025                 'startTime': 4000,
1026                 'endTime': 5000,
1027                 'lastModified': 5000,
1028                 'clusterCount': 4,
1029                 'status': 'OK'});
1030
1031             return waitForMeasurementSet().then(() => {
1032                 assert.equal(requests.length, 2);
1033                 assert.equal(requests[1].url, '/data/measurement-set-1-1-4000.json');
1034                 return set.fetchSegmentation('segmentTimeSeriesByMaximizingSchwarzCriterion', [], 'current', false);
1035             }).then((segmentation) => {
1036                 const timeSeries = set.fetchedTimeSeries('current', false, false);
1037                 assert.equal(timeSeries.length(), 15);
1038                 assert.equal(timeSeries.firstPoint().time, 4000);
1039                 assert.equal(timeSeries.lastPoint().time, 4462);
1040
1041                 assert.equal(segmentation.length, 4);
1042                 assert.equal(segmentation[0].time, timeSeries.firstPoint().time);
1043                 assert.almostEqual(segmentation[0].value, 1545.441);
1044                 assert.equal(segmentation[0].value, segmentation[1].value);
1045                 assert.equal(segmentation[1].time, timeSeries.findPointByIndex(9).time);
1046
1047                 assert.equal(segmentation[2].time, timeSeries.findPointByIndex(9).time);
1048                 assert.almostEqual(segmentation[2].value, 1581.872);
1049                 assert.equal(segmentation[2].value, segmentation[3].value);
1050                 assert.equal(segmentation[3].time, timeSeries.lastPoint().time);
1051
1052                 requests[1].resolve({
1053                     'clusterStart': 1000,
1054                     'clusterSize': 1000,
1055                     'formatMap': ['id', 'mean', 'iterationCount', 'sum', 'squareSum', 'markedOutlier', 'revisions', 'commitTime', 'build', 'buildTime', 'buildNumber', 'builder'],
1056                     'configurations': {current: makeSampleRuns(simpleSegmentableValues.slice(0, 30), 6500, 3000, 1000 / 30)},
1057                     'startTime': 3000,
1058                     'endTime': 4000,
1059                     'lastModified': 5000,
1060                     'clusterCount': 4,
1061                     'status': 'OK'});
1062                 return waitForMeasurementSet();
1063             }).then(() => {
1064                 return set.fetchSegmentation('segmentTimeSeriesByMaximizingSchwarzCriterion', [], 'current', false);
1065             }).then((segmentation) => {
1066                 var timeSeries = set.fetchedTimeSeries('current', false, false);
1067                 assert.equal(timeSeries.length(), 45);
1068                 assert.equal(timeSeries.firstPoint().time, 3000);
1069                 assert.equal(timeSeries.lastPoint().time, 4462);
1070                 assert.equal(segmentation.length, 4);
1071
1072                 assert.equal(segmentation[0].time, timeSeries.firstPoint().time);
1073                 assert.almostEqual(segmentation[0].value, 1545.082);
1074                 assert.equal(segmentation[0].value, segmentation[1].value);
1075                 assert.equal(segmentation[1].time, timeSeries.findPointByIndex(39).time);
1076
1077                 assert.equal(segmentation[2].time, timeSeries.findPointByIndex(39).time);
1078                 assert.almostEqual(segmentation[2].value, 1581.872);
1079                 assert.equal(segmentation[2].value, segmentation[3].value);
1080                 assert.equal(segmentation[3].time, timeSeries.lastPoint().time);
1081             });
1082         });
1083
1084     });
1085 });