Home | History | Annotate | Download | only in importer
      1 <!DOCTYPE html>
      2 <html>
      3 <!--
      4 Copyright (c) 2012 The Chromium Authors. All rights reserved.
      5 Use of this source code is governed by a BSD-style license that can be
      6 found in the LICENSE file.
      7 -->
      8 <head>
      9 <title>TraceEventImporter tests</title>
     10 <script src="../base.js"></script>
     11 <script>
     12   base.require('unittest');
     13   base.require('test_utils');
     14   base.require('importer.trace_event_importer');
     15 </script>
     16 </head>
     17 <body>
     18 <script>
     19 'use strict';
     20 
     21 var findSliceNamed = test_utils.findSliceNamed;
     22 
     23 function testCanImportEmpty() {
     24   self.assertFalse(tracing.importer.TraceEventImporter.canImport([]));
     25   self.assertFalse(tracing.importer.TraceEventImporter.canImport(''));
     26 }
     27 
     28 function testBasicSingleThreadNonnestedParsing() {
     29   var events = [
     30     {name: 'a', args: {}, pid: 52, ts: 520, cat: 'foo', tid: 53, ph: 'B'},
     31     {name: 'a', args: {}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'},
     32     {name: 'b', args: {}, pid: 52, ts: 629, cat: 'bar', tid: 53, ph: 'B'},
     33     {name: 'b', args: {}, pid: 52, ts: 631, cat: 'bar', tid: 53, ph: 'E'}
     34   ];
     35 
     36   var m = new tracing.Model(events);
     37   assertEquals(1, m.numProcesses);
     38   var p = m.processes[52];
     39   assertNotUndefined(p);
     40 
     41   assertEquals(1, p.numThreads);
     42   var t = p.threads[53];
     43   assertNotUndefined(t);
     44   assertEquals(2, t.slices.length);
     45   assertEquals(53, t.tid);
     46   var slice = t.slices[0];
     47   assertEquals('a', slice.title);
     48   assertEquals('foo', slice.category);
     49   assertEquals(0, slice.start);
     50   assertAlmostEquals((560 - 520) / 1000, slice.duration);
     51   assertEquals(0, slice.subSlices.length);
     52 
     53   slice = t.slices[1];
     54   assertEquals('b', slice.title);
     55   assertEquals('bar', slice.category);
     56   assertAlmostEquals((629 - 520) / 1000, slice.start);
     57   assertAlmostEquals((631 - 629) / 1000, slice.duration);
     58   assertEquals(0, slice.subSlices.length);
     59 }
     60 
     61 function testArgumentDupeCreatesNonFailingImportError() {
     62   var events = [
     63     {name: 'a', args: {'x': 1}, pid: 1, ts: 520, cat: 'foo', tid: 1, ph: 'B'},
     64     {name: 'a', args: {'x': 2}, pid: 1, ts: 560, cat: 'foo', tid: 1, ph: 'E'}
     65   ];
     66 
     67   var m = new tracing.Model(events);
     68   var t = m.processes[1].threads[1];
     69   var sA = findSliceNamed(t.slices, 'a');
     70 
     71   assertEquals(2, sA.args.x);
     72   assertEquals(m.importErrors.length, 1);
     73 }
     74 
     75 function testCategoryBeginEndMismatchPrefersBegin() {
     76   var events = [
     77     {name: 'a', args: {}, pid: 52, ts: 520, cat: 'foo', tid: 53, ph: 'B'},
     78     {name: 'a', args: {}, pid: 52, ts: 560, cat: 'bar', tid: 53, ph: 'E'}
     79   ];
     80 
     81   var m = new tracing.Model(events);
     82   assertEquals(1, m.numProcesses);
     83   var p = m.processes[52];
     84   assertNotUndefined(p);
     85 
     86   assertEquals(1, p.numThreads);
     87   var t = p.threads[53];
     88   assertNotUndefined(t);
     89   assertEquals(1, t.slices.length);
     90   assertEquals(53, t.tid);
     91   var slice = t.slices[0];
     92   assertEquals('a', slice.title);
     93   assertEquals('foo', slice.category);
     94 }
     95 
     96 function testNestedParsing() {
     97   var events = [
     98     {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'},
     99     {name: 'b', args: {}, pid: 1, ts: 2, cat: 'bar', tid: 1, ph: 'B'},
    100     {name: 'b', args: {}, pid: 1, ts: 3, cat: 'bar', tid: 1, ph: 'E'},
    101     {name: 'a', args: {}, pid: 1, ts: 4, cat: 'foo', tid: 1, ph: 'E'}
    102   ];
    103   var m = new tracing.Model(events, false);
    104   var t = m.processes[1].threads[1];
    105 
    106   var sA = findSliceNamed(t.slices, 'a');
    107   var sB = findSliceNamed(t.slices, 'b');
    108 
    109   assertEquals('a', sA.title);
    110   assertEquals('foo', sA.category);
    111   assertEquals(0.001, sA.start);
    112   assertEquals(0.003, sA.duration);
    113 
    114   assertEquals('b', sB.title);
    115   assertEquals('bar', sB.category);
    116   assertEquals(0.002, sB.start);
    117   assertEquals(0.001, sB.duration);
    118 }
    119 
    120 function testAutoclosing() {
    121   var events = [
    122     // Slice that doesn't finish.
    123     {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'},
    124 
    125     // Slice that does finish to give an 'end time' to make autoclosing work.
    126     {name: 'b', args: {}, pid: 1, ts: 1, cat: 'bar', tid: 2, ph: 'B'},
    127     {name: 'b', args: {}, pid: 1, ts: 2, cat: 'bar', tid: 2, ph: 'E'}
    128   ];
    129   var m = new tracing.Model(events);
    130   var p = m.processes[1];
    131   var t = p.threads[1];
    132   var slice = t.slices[0];
    133   assertEquals('a', slice.title);
    134   assertEquals('foo', slice.category);
    135   assertTrue(slice.didNotFinish);
    136   assertEquals(0, slice.start);
    137   assertEquals((2 - 1) / 1000, slice.duration);
    138 }
    139 
    140 function testAutoclosingLoneBegin() {
    141   var events = [
    142     // Slice that doesn't finish.
    143     {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'}
    144   ];
    145   var m = new tracing.Model(events);
    146   var p = m.processes[1];
    147   var t = p.threads[1];
    148   var slice = t.slices[0];
    149   assertEquals('a', slice.title);
    150   assertEquals('foo', slice.category);
    151   assertTrue(slice.didNotFinish);
    152   assertEquals(0, slice.start);
    153   assertEquals(0, slice.duration);
    154 }
    155 
    156 function testAutoclosingWithSubTasks() {
    157   var events = [
    158     {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'},
    159     {name: 'b1', args: {}, pid: 1, ts: 2, cat: 'foo', tid: 1, ph: 'B'},
    160     {name: 'b1', args: {}, pid: 1, ts: 3, cat: 'foo', tid: 1, ph: 'E'},
    161     {name: 'b2', args: {}, pid: 1, ts: 3, cat: 'foo', tid: 1, ph: 'B'}
    162   ];
    163   var m = new tracing.Model(events, false);
    164   var t = m.processes[1].threads[1];
    165 
    166   var sA = findSliceNamed(t.slices, 'a');
    167   var sB1 = findSliceNamed(t.slices, 'b1');
    168   var sB2 = findSliceNamed(t.slices, 'b2');
    169 
    170   assertEquals(0.003, sA.end);
    171   assertEquals(0.003, sB1.end);
    172   assertEquals(0.003, sB2.end);
    173 }
    174 
    175 function testAutoclosingWithEventsOutsideBounds() {
    176   var events = [
    177     // Slice that begins before min and ends after max of the other threads.
    178     {name: 'a', args: {}, pid: 1, ts: 0, cat: 'foo', tid: 1, ph: 'B'},
    179     {name: 'b', args: {}, pid: 1, ts: 3, cat: 'foo', tid: 1, ph: 'B'},
    180 
    181     // Slice that does finish to give an 'end time' to establish a basis
    182     {name: 'c', args: {}, pid: 1, ts: 1, cat: 'bar', tid: 2, ph: 'B'},
    183     {name: 'c', args: {}, pid: 1, ts: 2, cat: 'bar', tid: 2, ph: 'E'}
    184   ];
    185   var m = new tracing.Model(events, false);
    186   var p = m.processes[1];
    187   var t = p.threads[1];
    188   assertEquals(2, t.slices.length);
    189 
    190   var slice = findSliceNamed(t.slices, 'a');
    191   assertEquals('a', slice.title);
    192   assertEquals('foo', slice.category);
    193   assertEquals(0, slice.start);
    194   assertEquals(0.003, slice.duration);
    195 
    196   var t2 = p.threads[2];
    197   var slice2 = findSliceNamed(t2.slices, 'c');
    198   assertEquals('c', slice2.title);
    199   assertEquals('bar', slice2.category);
    200   assertEquals(0.001, slice2.start);
    201   assertEquals(0.001, slice2.duration);
    202 
    203   assertEquals(0.000, m.bounds.min);
    204   assertEquals(0.003, m.bounds.max);
    205 }
    206 
    207 function testNestedAutoclosing() {
    208   var events = [
    209     // Tasks that don't finish.
    210     {name: 'a1', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'},
    211     {name: 'a2', args: {}, pid: 1, ts: 1.5, cat: 'foo', tid: 1, ph: 'B'},
    212 
    213     // Slice that does finish to give an 'end time' to make autoclosing work.
    214     {name: 'b', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 2, ph: 'B'},
    215     {name: 'b', args: {}, pid: 1, ts: 2, cat: 'foo', tid: 2, ph: 'E'}
    216   ];
    217   var m = new tracing.Model(events, false);
    218   var t1 = m.processes[1].threads[1];
    219   var t2 = m.processes[1].threads[2];
    220 
    221   var sA1 = findSliceNamed(t1.slices, 'a1');
    222   var sA2 = findSliceNamed(t1.slices, 'a2');
    223   var sB = findSliceNamed(t2.slices, 'b');
    224 
    225   assertEquals(0.002, sA1.end);
    226   assertEquals(0.002, sA2.end);
    227 }
    228 
    229 function testTaskColoring() {
    230   // The test below depends on hashing of 'a' != 'b'. Fail early if that
    231   // assumption is incorrect.
    232   assertNotEquals(tracing.getStringHash('a'), tracing.getStringHash('b'));
    233 
    234   var events = [
    235     {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'},
    236     {name: 'a', args: {}, pid: 1, ts: 2, cat: 'foo', tid: 1, ph: 'E'},
    237     {name: 'b', args: {}, pid: 1, ts: 3, cat: 'bar', tid: 1, ph: 'B'},
    238     {name: 'b', args: {}, pid: 1, ts: 4, cat: 'bar', tid: 1, ph: 'E'},
    239     {name: 'a', args: {}, pid: 1, ts: 5, cat: 'baz', tid: 1, ph: 'B'},
    240     {name: 'a', args: {}, pid: 1, ts: 6, cat: 'baz', tid: 1, ph: 'E'}
    241   ];
    242   var m = new tracing.Model(events);
    243   var p = m.processes[1];
    244   var t = p.threads[1];
    245   var a1 = t.slices[0];
    246   assertEquals('a', a1.title);
    247   assertEquals('foo', a1.category);
    248   var b = t.slices[1];
    249   assertEquals('b', b.title);
    250   assertEquals('bar', b.category);
    251   assertNotEquals(a1.colorId, b.colorId);
    252   var a2 = t.slices[2];
    253   assertEquals('a', a2.title);
    254   assertEquals('baz', a2.category);
    255   assertEquals(a1.colorId, a2.colorId);
    256 }
    257 
    258 function testMultipleThreadParsing() {
    259   var events = [
    260     {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'},
    261     {name: 'a', args: {}, pid: 1, ts: 2, cat: 'foo', tid: 1, ph: 'E'},
    262     {name: 'b', args: {}, pid: 1, ts: 3, cat: 'bar', tid: 2, ph: 'B'},
    263     {name: 'b', args: {}, pid: 1, ts: 4, cat: 'bar', tid: 2, ph: 'E'}
    264   ];
    265   var m = new tracing.Model(events);
    266   assertEquals(1, m.numProcesses);
    267   var p = m.processes[1];
    268   assertNotUndefined(p);
    269 
    270   assertEquals(2, p.numThreads);
    271 
    272   // Check thread 1.
    273   var t = p.threads[1];
    274   assertNotUndefined(t);
    275   assertEquals(1, t.slices.length);
    276   assertEquals(1, t.tid);
    277 
    278   var slice = t.slices[0];
    279   assertEquals('a', slice.title);
    280   assertEquals('foo', slice.category);
    281   assertEquals(0, slice.start);
    282   assertEquals((2 - 1) / 1000, slice.duration);
    283   assertEquals(0, slice.subSlices.length);
    284 
    285   // Check thread 2.
    286   var t = p.threads[2];
    287   assertNotUndefined(t);
    288   assertEquals(1, t.slices.length);
    289   assertEquals(2, t.tid);
    290 
    291   slice = t.slices[0];
    292   assertEquals('b', slice.title);
    293   assertEquals('bar', slice.category);
    294   assertEquals((3 - 1) / 1000, slice.start);
    295   assertEquals((4 - 3) / 1000, slice.duration);
    296   assertEquals(0, slice.subSlices.length);
    297 }
    298 
    299 function testMultiplePidParsing() {
    300   var events = [
    301     {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'},
    302     {name: 'a', args: {}, pid: 1, ts: 2, cat: 'foo', tid: 1, ph: 'E'},
    303     {name: 'b', args: {}, pid: 2, ts: 3, cat: 'bar', tid: 2, ph: 'B'},
    304     {name: 'b', args: {}, pid: 2, ts: 4, cat: 'bar', tid: 2, ph: 'E'}
    305   ];
    306   var m = new tracing.Model(events);
    307   assertEquals(2, m.numProcesses);
    308   var p = m.processes[1];
    309   assertNotUndefined(p);
    310 
    311   assertEquals(1, p.numThreads);
    312 
    313   // Check process 1 thread 1.
    314   var t = p.threads[1];
    315   assertNotUndefined(t);
    316   assertEquals(1, t.slices.length);
    317   assertEquals(1, t.tid);
    318 
    319   var slice = t.slices[0];
    320   assertEquals('a', slice.title);
    321   assertEquals('foo', slice.category);
    322   assertEquals(0, slice.start);
    323   assertEquals((2 - 1) / 1000, slice.duration);
    324   assertEquals(0, slice.subSlices.length);
    325 
    326   // Check process 2 thread 2.
    327   var p = m.processes[2];
    328   assertNotUndefined(p);
    329   assertEquals(1, p.numThreads);
    330   var t = p.threads[2];
    331   assertNotUndefined(t);
    332   assertEquals(1, t.slices.length);
    333   assertEquals(2, t.tid);
    334 
    335   slice = t.slices[0];
    336   assertEquals('b', slice.title);
    337   assertEquals('bar', slice.category);
    338   assertEquals((3 - 1) / 1000, slice.start);
    339   assertEquals((4 - 3) / 1000, slice.duration);
    340   assertEquals(0, slice.subSlices.length);
    341 
    342   // Check getAllThreads.
    343   assertArrayEquals([m.processes[1].threads[1], m.processes[2].threads[2]],
    344                     m.getAllThreads());
    345 }
    346 
    347 // Thread names.
    348 function testThreadNames() {
    349   var events = [
    350     {name: 'thread_name', args: {name: 'Thread 1'},
    351       pid: 1, ts: 0, tid: 1, ph: 'M'},
    352     {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'},
    353     {name: 'a', args: {}, pid: 1, ts: 2, cat: 'foo', tid: 1, ph: 'E'},
    354     {name: 'b', args: {}, pid: 2, ts: 3, cat: 'foo', tid: 2, ph: 'B'},
    355     {name: 'b', args: {}, pid: 2, ts: 4, cat: 'foo', tid: 2, ph: 'E'},
    356     {name: 'thread_name', args: {name: 'Thread 2'},
    357       pid: 2, ts: 0, tid: 2, ph: 'M'}
    358   ];
    359   var m = new tracing.Model(events);
    360   assertEquals('Thread 1', m.processes[1].threads[1].name);
    361   assertEquals('Thread 2', m.processes[2].threads[2].name);
    362 }
    363 
    364 function testParsingWhenEndComesFirst() {
    365   var events = [
    366     {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'E'},
    367     {name: 'a', args: {}, pid: 1, ts: 4, cat: 'foo', tid: 1, ph: 'B'},
    368     {name: 'a', args: {}, pid: 1, ts: 5, cat: 'foo', tid: 1, ph: 'E'}
    369   ];
    370   var m = new tracing.Model(events, false);
    371   var p = m.processes[1];
    372   var t = p.threads[1];
    373   assertEquals(1, t.slices.length);
    374   assertEquals('a', t.slices[0].title);
    375   assertEquals('foo', t.slices[0].category);
    376   assertEquals(0.004, t.slices[0].start);
    377   assertEquals(0.001, t.slices[0].duration);
    378   assertEquals(1, m.importErrors.length);
    379 }
    380 
    381 function testImmediateParsing() {
    382   var events = [
    383     // Need to include immediates inside a task so the timeline
    384     // recentering/zeroing doesn't clobber their timestamp.
    385     {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'},
    386     {name: 'immediate', args: {}, pid: 1, ts: 2, cat: 'bar', tid: 1, ph: 'I'},
    387     {name: 'slower', args: {}, pid: 1, ts: 4, cat: 'baz', tid: 1, ph: 'i'},
    388     {name: 'a', args: {}, pid: 1, ts: 4, cat: 'foo', tid: 1, ph: 'E'}
    389   ];
    390   var m = new tracing.Model(events, false);
    391   var p = m.processes[1];
    392   var t = p.threads[1];
    393   assertEquals(3, t.slices.length);
    394   assertEquals(0.002, t.slices[0].start);
    395   assertEquals(0, t.slices[0].duration);
    396   assertEquals(0.004, t.slices[1].start);
    397   assertEquals(0.001, t.slices[2].start);
    398   assertEquals(0.003, t.slices[2].duration);
    399 
    400   var slice = findSliceNamed(t.slices, 'a');
    401   assertEquals('a', slice.title);
    402   assertEquals('foo', slice.category);
    403   assertEquals(0.003, slice.duration);
    404 
    405   var immed = findSliceNamed(t.slices, 'immediate');
    406   assertEquals('immediate', immed.title);
    407   assertEquals('bar', immed.category);
    408   assertEquals(0.002, immed.start);
    409   assertEquals(0, immed.duration);
    410   assertEquals(0, immed.subSlices.length);
    411 
    412   var slower = findSliceNamed(t.slices, 'slower');
    413   assertEquals('slower', slower.title);
    414   assertEquals('baz', slower.category);
    415   assertEquals(0.004, slower.start);
    416   assertEquals(0, slower.duration);
    417   assertEquals(0, slower.subSlices.length);
    418 }
    419 
    420 function testSimpleCounter() {
    421   var events = [
    422     {name: 'ctr', args: {'value': 0}, pid: 1, ts: 0, cat: 'foo', tid: 1,
    423      ph: 'C'},
    424     {name: 'ctr', args: {'value': 10}, pid: 1, ts: 10, cat: 'foo', tid: 1,
    425      ph: 'C'},
    426     {name: 'ctr', args: {'value': 0}, pid: 1, ts: 20, cat: 'foo', tid: 1,
    427      ph: 'C'}
    428 
    429   ];
    430   var m = new tracing.Model(events);
    431   var p = m.processes[1];
    432   var ctr = m.processes[1].counters['foo.ctr'];
    433 
    434   assertEquals('ctr', ctr.name);
    435   assertEquals('foo', ctr.category);
    436   assertEquals(3, ctr.numSamples);
    437   assertEquals(1, ctr.numSeries);
    438 
    439   assertArrayEquals(['value'], ctr.seriesNames);
    440   assertArrayEquals([tracing.getStringColorId('ctr.value')], ctr.seriesColors);
    441   assertArrayEquals([0, 0.01, 0.02], ctr.timestamps);
    442   assertArrayEquals([0, 10, 0], ctr.samples);
    443   assertArrayEquals([0, 10, 0], ctr.totals);
    444   assertEquals(10, ctr.maxTotal);
    445 }
    446 
    447 function testInstanceCounter() {
    448   var events = [
    449     {name: 'ctr', args: {'value': 0}, pid: 1, ts: 0, cat: 'foo', tid: 1,
    450      ph: 'C', id: 0},
    451     {name: 'ctr', args: {'value': 10}, pid: 1, ts: 10, cat: 'foo', tid: 1,
    452      ph: 'C', id: 0},
    453     {name: 'ctr', args: {'value': 10}, pid: 1, ts: 10, cat: 'foo', tid: 1,
    454      ph: 'C', id: 1},
    455     {name: 'ctr', args: {'value': 20}, pid: 1, ts: 15, cat: 'foo', tid: 1,
    456      ph: 'C', id: 1},
    457     {name: 'ctr', args: {'value': 30}, pid: 1, ts: 18, cat: 'foo', tid: 1,
    458      ph: 'C', id: 1},
    459     {name: 'ctr', args: {'value': 40}, pid: 1, ts: 20, cat: 'bar', tid: 1,
    460      ph: 'C', id: 2}
    461   ];
    462   var m = new tracing.Model(events);
    463   var p = m.processes[1];
    464   var ctr = m.processes[1].counters['foo.ctr[0]'];
    465   assertEquals('ctr[0]', ctr.name);
    466   assertEquals('foo', ctr.category);
    467   assertEquals(2, ctr.numSamples);
    468   assertEquals(1, ctr.numSeries);
    469   assertArrayEquals([0, 0.01], ctr.timestamps);
    470   assertArrayEquals([0, 10], ctr.samples);
    471 
    472   var ctr = m.processes[1].counters['foo.ctr[1]'];
    473   assertEquals('ctr[1]', ctr.name);
    474   assertEquals('foo', ctr.category);
    475   assertEquals(3, ctr.numSamples);
    476   assertEquals(1, ctr.numSeries);
    477   assertArrayEquals([0.01, 0.015, 0.018], ctr.timestamps);
    478   assertArrayEquals([10, 20, 30], ctr.samples);
    479 
    480   var ctr = m.processes[1].counters['bar.ctr[2]'];
    481   assertEquals('ctr[2]', ctr.name);
    482   assertEquals('bar', ctr.category);
    483   assertEquals(1, ctr.numSamples);
    484   assertEquals(1, ctr.numSeries);
    485   assertArrayEquals([0.02], ctr.timestamps);
    486   assertArrayEquals([40], ctr.samples);
    487 }
    488 
    489 function testMultiCounterUpdateBounds() {
    490   var ctr = new tracing.model.Counter(undefined, 'testBasicCounter',
    491       '', 'testBasicCounter');
    492   ctr.seriesNames = ['value1', 'value2'];
    493   ctr.seriesColors = ['testBasicCounter.value1', 'testBasicCounter.value2'];
    494   ctr.timestamps = [0, 1, 2, 3, 4, 5, 6, 7];
    495   ctr.samples = [0, 0,
    496                  1, 0,
    497                  1, 1,
    498                  2, 1.1,
    499                  3, 0,
    500                  1, 7,
    501                  3, 0,
    502                  3.1, 0.5];
    503   ctr.updateBounds();
    504   assertEquals(0, ctr.bounds.min);
    505   assertEquals(7, ctr.bounds.max);
    506   assertEquals(8, ctr.maxTotal);
    507   assertArrayEquals([0, 0,
    508                      1, 1,
    509                      1, 2,
    510                      2, 3.1,
    511                      3, 3,
    512                      1, 8,
    513                      3, 3,
    514                      3.1, 3.6], ctr.totals);
    515 }
    516 
    517 function testMultiCounter() {
    518   var events = [
    519     {name: 'ctr', args: {'value1': 0, 'value2': 7}, pid: 1, ts: 0, cat: 'foo',
    520      tid: 1, ph: 'C'},
    521     {name: 'ctr', args: {'value1': 10, 'value2': 4}, pid: 1, ts: 10, cat: 'foo',
    522      tid: 1, ph: 'C'},
    523     {name: 'ctr', args: {'value1': 0, 'value2': 1 }, pid: 1, ts: 20, cat: 'foo',
    524      tid: 1, ph: 'C'}
    525   ];
    526   var m = new tracing.Model(events);
    527   var p = m.processes[1];
    528   var ctr = m.processes[1].counters['foo.ctr'];
    529   assertEquals('ctr', ctr.name);
    530 
    531   assertEquals('ctr', ctr.name);
    532   assertEquals('foo', ctr.category);
    533   assertEquals(3, ctr.numSamples);
    534   assertEquals(2, ctr.numSeries);
    535 
    536   assertArrayEquals(['value1', 'value2'], ctr.seriesNames);
    537   assertArrayEquals([tracing.getStringColorId('ctr.value1'),
    538                      tracing.getStringColorId('ctr.value2')],
    539                     ctr.seriesColors);
    540   assertArrayEquals([0, 0.01, 0.02], ctr.timestamps);
    541   assertArrayEquals([0, 7,
    542                      10, 4,
    543                      0, 1], ctr.samples);
    544   assertArrayEquals([0, 7,
    545                      10, 14,
    546                      0, 1], ctr.totals);
    547   assertEquals(14, ctr.maxTotal);
    548 }
    549 
    550 function testImportObjectInsteadOfArray() {
    551   var events = { traceEvents: [
    552     {name: 'a', args: {}, pid: 52, ts: 524, cat: 'foo', tid: 53, ph: 'B'},
    553     {name: 'a', args: {}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'}
    554   ] };
    555 
    556   var m = new tracing.Model(events);
    557   assertEquals(1, m.numProcesses);
    558 }
    559 
    560 function testImportString() {
    561   var events = [
    562     {name: 'a', args: {}, pid: 52, ts: 524, cat: 'foo', tid: 53, ph: 'B'},
    563     {name: 'a', args: {}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'}
    564   ];
    565 
    566   var m = new tracing.Model(JSON.stringify(events));
    567   assertEquals(1, m.numProcesses);
    568 }
    569 
    570 function testImportStringWithTrailingNewLine() {
    571   var events = [
    572     {name: 'a', args: {}, pid: 52, ts: 524, cat: 'foo', tid: 53, ph: 'B'},
    573     {name: 'a', args: {}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'}
    574   ];
    575 
    576   var m = new tracing.Model(JSON.stringify(events) + '\n');
    577   assertEquals(1, m.numProcesses);
    578 }
    579 
    580 function testImportStringWithMissingCloseSquareBracket() {
    581   var events = [
    582     {name: 'a', args: {}, pid: 52, ts: 524, cat: 'foo', tid: 53, ph: 'B'},
    583     {name: 'a', args: {}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'}
    584   ];
    585 
    586   var tmp = JSON.stringify(events);
    587   assertEquals(']', tmp[tmp.length - 1]);
    588 
    589   // Drop off the trailing ]
    590   var dropped = tmp.substring(0, tmp.length - 1);
    591   var m = new tracing.Model(dropped);
    592   assertEquals(1, m.numProcesses);
    593 }
    594 
    595 function testImportStringWithEndingCommaButMissingCloseSquareBracket() {
    596   var lines = [
    597     '[',
    598     '{"name": "a", "args": {}, "pid": 52, "ts": 524, "cat": "foo", "tid": 53, "ph": "B"},',
    599     '{"name": "a", "args": {}, "pid": 52, "ts": 560, "cat": "foo", "tid": 53, "ph": "E"},'
    600     ]
    601   var text = lines.join('\n');
    602 
    603   var m = new tracing.Model(text);
    604   assertEquals(1, m.numProcesses);
    605   assertEquals(1, m.processes[52].threads[53].slices.length);
    606 }
    607 
    608 function testImportStringWithMissingCloseSquareBracketAndNewline() {
    609   var events = [
    610     {name: 'a', args: {}, pid: 52, ts: 524, cat: 'foo', tid: 53, ph: 'B'},
    611     {name: 'a', args: {}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'}
    612   ];
    613 
    614   var tmp = JSON.stringify(events);
    615   assertEquals(']', tmp[tmp.length - 1]);
    616 
    617   // Drop off the trailing ] and add a newline
    618   var dropped = tmp.substring(0, tmp.length - 1);
    619   var m = new tracing.Model(dropped + '\n');
    620   assertEquals(1, m.numProcesses);
    621 }
    622 
    623 function testImportStringWithEndingCommaButMissingCloseSquareBracketCRLF() {
    624   var lines = [
    625     '[',
    626     '{"name": "a", "args": {}, "pid": 52, "ts": 524, "cat": "foo", "tid": 53, "ph": "B"},',
    627     '{"name": "a", "args": {}, "pid": 52, "ts": 560, "cat": "foo", "tid": 53, "ph": "E"},'
    628     ]
    629   var text = lines.join('\r\n');
    630 
    631   var m = new tracing.Model(text);
    632   assertEquals(1, m.numProcesses);
    633   assertEquals(1, m.processes[52].threads[53].slices.length);
    634 }
    635 
    636 function testImportOldFormat() {
    637   var lines = [
    638     '[',
    639     '{"cat":"a","pid":9,"tid":8,"ts":194,"ph":"E","name":"I","args":{}},',
    640     '{"cat":"b","pid":9,"tid":8,"ts":194,"ph":"B","name":"I","args":{}}',
    641     ']'
    642     ];
    643   var text = lines.join('\n');
    644   var m = new tracing.Model(text);
    645   assertEquals(1, m.numProcesses);
    646   assertEquals(1, m.processes[9].threads[8].slices.length);
    647 }
    648 
    649 function testStartFinishOneSliceOneThread() {
    650   var events = [
    651     // Time is intentionally out of order.
    652     {name: 'a', args: {}, pid: 52, ts: 560, cat: 'cat', tid: 53,
    653        ph: 'F', id: 72},
    654     {name: 'a', pid: 52, ts: 524, cat: 'cat', tid: 53,
    655        ph: 'S', id: 72, args: {'foo': 'bar'}}
    656   ];
    657 
    658   var m = new tracing.Model(events);
    659   var t = m.processes[52].threads[53];
    660   assertNotUndefined(t);
    661   assertEquals(1, t.asyncSlices.slices.length);
    662   assertEquals('a', t.asyncSlices.slices[0].title);
    663   assertEquals('cat', t.asyncSlices.slices[0].category);
    664   assertEquals(72, t.asyncSlices.slices[0].id);
    665   assertEquals('bar', t.asyncSlices.slices[0].args.foo);
    666   assertEquals(0, t.asyncSlices.slices[0].start);
    667   assertAlmostEquals((60 - 24) / 1000, t.asyncSlices.slices[0].duration);
    668   assertEquals(t, t.asyncSlices.slices[0].startThread);
    669   assertEquals(t, t.asyncSlices.slices[0].endThread);
    670 }
    671 
    672 function testEndArgsAddedToSlice() {
    673   var events = [
    674     {name: 'a', args: {x: 1}, pid: 52, ts: 520, cat: 'foo', tid: 53, ph: 'B'},
    675     {name: 'a', args: {y: 2}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'}
    676   ];
    677 
    678   var m = new tracing.Model(events);
    679   assertEquals(1, m.numProcesses);
    680   var p = m.processes[52];
    681   assertNotUndefined(p);
    682 
    683   assertEquals(1, p.numThreads);
    684   var t = p.threads[53];
    685   assertNotUndefined(t);
    686   assertEquals(1, t.slices.length);
    687   assertEquals(53, t.tid);
    688   var slice = t.slices[0];
    689   assertEquals('a', slice.title);
    690   assertEquals('foo', slice.category);
    691   assertEquals(0, slice.start);
    692   assertEquals(0, slice.subSlices.length);
    693   assertEquals(1, slice.args['x']);
    694   assertEquals(2, slice.args['y']);
    695 }
    696 
    697 function testEndArgOverrwritesOriginalArgValueIfDuplicated() {
    698   var events = [
    699     {name: 'b', args: {z: 3}, pid: 52, ts: 629, cat: 'foo', tid: 53, ph: 'B'},
    700     {name: 'b', args: {z: 4}, pid: 52, ts: 631, cat: 'foo', tid: 53, ph: 'E'}
    701   ];
    702 
    703   var m = new tracing.Model(events);
    704   assertEquals(1, m.numProcesses);
    705   var p = m.processes[52];
    706   assertNotUndefined(p);
    707 
    708   assertEquals(1, p.numThreads);
    709   var t = p.threads[53];
    710   assertNotUndefined(t);
    711   var slice = t.slices[0];
    712   assertEquals('b', slice.title);
    713   assertEquals('foo', slice.category);
    714   assertEquals(0, slice.start);
    715   assertEquals(0, slice.subSlices.length);
    716   assertEquals(4, slice.args['z']);
    717 }
    718 
    719 function testAsyncEndArgsAddedToSlice() {
    720   var events = [
    721     // Time is intentionally out of order.
    722     {name: 'c', args: {y: 2}, pid: 52, ts: 560, cat: 'foo', tid: 53,
    723        ph: 'F', id: 72},
    724     {name: 'c', args: {x: 1}, pid: 52, ts: 524, cat: 'foo', tid: 53,
    725        ph: 'S', id: 72}
    726   ];
    727 
    728   var m = new tracing.Model(events);
    729   var t = m.processes[52].threads[53];
    730   assertNotUndefined(t);
    731   assertEquals(1, t.asyncSlices.slices.length);
    732   var parentSlice = t.asyncSlices.slices[0];
    733   assertEquals('c', parentSlice.title);
    734   assertEquals('foo', parentSlice.category);
    735 
    736   assertNotUndefined(parentSlice.subSlices);
    737   assertEquals(1, parentSlice.subSlices.length);
    738   var subSlice = parentSlice.subSlices[0];
    739   assertEquals(1, subSlice.args['x']);
    740   assertEquals(2, subSlice.args['y']);
    741 }
    742 
    743 function testAsyncEndArgOverrwritesOriginalArgValueIfDuplicated() {
    744   var events = [
    745     // Time is intentionally out of order.
    746     {name: 'd', args: {z: 4}, pid: 52, ts: 560, cat: 'foo', tid: 53,
    747        ph: 'F', id: 72},
    748     {name: 'd', args: {z: 3}, pid: 52, ts: 524, cat: 'foo', tid: 53,
    749        ph: 'S', id: 72}
    750   ];
    751 
    752   var m = new tracing.Model(events);
    753   var t = m.processes[52].threads[53];
    754   assertNotUndefined(t);
    755   assertEquals(1, t.asyncSlices.slices.length);
    756   var parentSlice = t.asyncSlices.slices[0];
    757   assertEquals('d', parentSlice.title);
    758   assertEquals('foo', parentSlice.category);
    759 
    760   assertNotUndefined(parentSlice.subSlices);
    761   assertEquals(1, parentSlice.subSlices.length);
    762   var subSlice = parentSlice.subSlices[0];
    763   assertEquals(4, subSlice.args['z']);
    764 }
    765 
    766 function testAsyncStepsInOneThread() {
    767   var events = [
    768     // Time is intentionally out of order.
    769     {name: 'a', args: {z: 3}, pid: 52, ts: 560, cat: 'foo', tid: 53,
    770        ph: 'F', id: 72},
    771     {name: 'a', args: {step: 's1', y: 2}, pid: 52, ts: 548, cat: 'foo', tid: 53,
    772        ph: 'T', id: 72},
    773     {name: 'a', args: {x: 1}, pid: 52, ts: 524, cat: 'foo', tid: 53,
    774        ph: 'S', id: 72}
    775   ];
    776 
    777   var m = new tracing.Model(events);
    778   var t = m.processes[52].threads[53];
    779   assertNotUndefined(t);
    780   assertEquals(1, t.asyncSlices.slices.length);
    781   var parentSlice = t.asyncSlices.slices[0];
    782   assertEquals('a', parentSlice.title);
    783   assertEquals('foo', parentSlice.category);
    784   assertEquals(0, parentSlice.start);
    785 
    786   assertNotUndefined(parentSlice.subSlices);
    787   assertEquals(2, parentSlice.subSlices.length);
    788   var subSlice = parentSlice.subSlices[0];
    789   assertEquals('a', subSlice.title);
    790   assertEquals('foo', subSlice.category);
    791   assertEquals(0, subSlice.start);
    792   assertAlmostEquals((548 - 524) / 1000, subSlice.duration);
    793   assertEquals(1, subSlice.args['x']);
    794 
    795   var subSlice = parentSlice.subSlices[1];
    796   assertEquals('a:s1', subSlice.title);
    797   assertEquals('foo', subSlice.category);
    798   assertAlmostEquals((548 - 524) / 1000, subSlice.start);
    799   assertAlmostEquals((560 - 548) / 1000, subSlice.duration);
    800   assertEquals(2, subSlice.args['y']);
    801   assertEquals(3, subSlice.args['z']);
    802 }
    803 
    804 function testAsyncStepsMissingStart() {
    805   var events = [
    806     // Time is intentionally out of order.
    807     {name: 'a', args: {z: 3}, pid: 52, ts: 560, cat: 'foo', tid: 53,
    808        ph: 'F', id: 72},
    809     {name: 'a', args: {step: 's1', y: 2}, pid: 52, ts: 548, cat: 'foo', tid: 53,
    810        ph: 'T', id: 72}
    811   ];
    812 
    813   var m = new tracing.Model(events);
    814   var t = m.processes[52].threads[53];
    815   assertUndefined(t);
    816 }
    817 
    818 function testAsyncStepsMissingFinish() {
    819   var events = [
    820     // Time is intentionally out of order.
    821     {name: 'a', args: {step: 's1', y: 2}, pid: 52, ts: 548, cat: 'foo', tid: 53,
    822        ph: 'T', id: 72},
    823     {name: 'a', args: {z: 3}, pid: 52, ts: 560, cat: 'foo', tid: 53,
    824        ph: 'S', id: 72}
    825   ];
    826 
    827   var m = new tracing.Model(events);
    828   var t = m.processes[52].threads[53];
    829   assertUndefined(t);
    830 }
    831 
    832 function testImportSamples() {
    833   var events = [
    834     {name: 'a', args: {}, pid: 52, ts: 548, cat: 'test', tid: 53, ph: 'P'},
    835     {name: 'b', args: {}, pid: 52, ts: 548, cat: 'test', tid: 53, ph: 'P'},
    836     {name: 'c', args: {}, pid: 52, ts: 558, cat: 'test', tid: 53, ph: 'P'}
    837   ];
    838   var m = new tracing.Model(events);
    839   var p = m.processes[52];
    840   assertNotUndefined(p);
    841   var t = p.threads[53];
    842   assertNotUndefined(t);
    843   assertEquals(3, t.samples_.length);
    844   assertEquals(0.0, t.samples_[0].start);
    845   assertEquals(0.0, t.samples_[1].start);
    846   assertApproxEquals(0.01, t.samples_[2].start);
    847   assertEquals('a', t.samples_[0].title);
    848   assertEquals('b', t.samples_[1].title);
    849   assertEquals('c', t.samples_[2].title);
    850   assertEquals(0, m.importErrors.length);
    851 }
    852 
    853 function testImportSamplesMissingArgs() {
    854   var events = [
    855     {name: 'a', pid: 52, ts: 548, cat: 'test', tid: 53, ph: 'P'},
    856     {name: 'b', pid: 52, ts: 548, cat: 'test', tid: 53, ph: 'P'},
    857     {name: 'c', pid: 52, ts: 549, cat: 'test', tid: 53, ph: 'P'}
    858   ];
    859   var m = new tracing.Model(events);
    860   var p = m.processes[52];
    861   assertNotUndefined(p);
    862   var t = p.threads[53];
    863   assertNotUndefined(t);
    864   assertNotUndefined(t);
    865   assertEquals(3, t.samples_.length);
    866   assertEquals(0, m.importErrors.length);
    867 }
    868 
    869 
    870 // TODO(nduca): one slice, two threads
    871 // TODO(nduca): one slice, two pids
    872 </script>
    873 </body>
    874 </html>
    875