summaryrefslogtreecommitdiffstats
path: root/dom/tests/browser/browser_performanceAPI.js
blob: 2c28fe3d17fb60a5bc75e26434d4da903ed99f47 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
/**
 * Bug 1369303 - A test for making sure that performance APIs have been correctly
 *   spoofed or disabled.
 */

const TEST_PATH = "http://example.net/browser/" +
                  "dom/tests/browser/";

const PERFORMANCE_TIMINGS = [
  "navigationStart",
  "unloadEventStart",
  "unloadEventEnd",
  "redirectStart",
  "redirectEnd",
  "fetchStart",
  "domainLookupStart",
  "domainLookupEnd",
  "connectStart",
  "connectEnd",
  "requestStart",
  "responseStart",
  "responseEnd",
  "domLoading",
  "domInteractive",
  "domContentLoadedEventStart",
  "domContentLoadedEventEnd",
  "domComplete",
  "loadEventStart",
  "loadEventEnd",
];

let isRounded = (x, expectedPrecision) => {
  let rounded = (Math.floor(x / expectedPrecision) * expectedPrecision);
  // First we do the perfectly normal check that should work just fine
  if (rounded === x || x === 0)
    return true;

  // When we're diving by non-whole numbers, we may not get perfect
  // multiplication/division because of floating points
  if (Math.abs(rounded - x + expectedPrecision) < .0000001) {
    return true;
  } else if (Math.abs(rounded - x) < .0000001) {
    return true;
  }

  // Then we handle the case where you're sub-millisecond and the timer is not
  // We check that the timer is not sub-millisecond by assuming it is not if it
  // returns an even number of milliseconds
  if (expectedPrecision < 1 && Math.round(x) == x) {
    if (Math.round(rounded) == x) {
      return true;
    }
  }

  ok(false, "Looming Test Failure, Additional Debugging Info: Expected Precision: " + expectedPrecision + " Measured Value: " + x +
    " Rounded Vaue: " + rounded + " Fuzzy1: " + Math.abs(rounded - x + expectedPrecision) +
    " Fuzzy 2: " + Math.abs(rounded - x));

  return false;
};

// ================================================================================================
// ================================================================================================
add_task(function* () {
  let tab = yield BrowserTestUtils.openNewForegroundTab(
    gBrowser, TEST_PATH + "dummy.html");

  yield ContentTask.spawn(tab.linkedBrowser, {
      list: PERFORMANCE_TIMINGS,
      precision: 2,
      isRoundedFunc: isRounded.toString()
    }, (data) => {
    let timerlist = data.list;
    let expectedPrecision = data.precision;
    // eslint beleives that isrounded is available in this scope, but if you
    // remove the assignment, you will see it is not
    // eslint-disable-next-line
    let isRounded = eval(data.isRoundedFunc);

    // Check that whether the performance timing API is correctly spoofed.
    for (let time of timerlist) {
      ok(isRounded(content.performance.timing[time], expectedPrecision), `For reduceTimerPrecision(` + expectedPrecision + `), the timing(${time}) is not correctly rounded: ` + content.performance.timing[time]);
    }

    // Try to add some entries.
    content.performance.mark("Test");
    content.performance.mark("Test-End");
    content.performance.measure("Test-Measure", "Test", "Test-End");

    // Check the entries for performance.getEntries/getEntriesByType/getEntriesByName.
    is(content.performance.getEntries().length, 3, "For reduceTimerPrecision, there should be 3 entries for performance.getEntries()");
    for (var i = 0; i < 3; i++) {
      let startTime = content.performance.getEntries()[i].startTime;
      let duration = content.performance.getEntries()[i].duration;
      ok(isRounded(startTime, expectedPrecision), "For reduceTimerPrecision(" + expectedPrecision + "), performance.getEntries(" + i + ").startTime is not rounded: " + startTime);
      ok(isRounded(duration, expectedPrecision), "For reduceTimerPrecision(" + expectedPrecision + "), performance.getEntries(" + i + ").duration is not rounded: " + duration);
    }
    is(content.performance.getEntriesByType("mark").length, 2, "For reduceTimerPrecision, there should be 2 entries for performance.getEntriesByType()");
    is(content.performance.getEntriesByName("Test", "mark").length, 1, "For reduceTimerPrecision, there should be 1 entry for performance.getEntriesByName()");
    content.performance.clearMarks();
    content.performance.clearMeasures();
    content.performance.clearResourceTimings();
  });
  gBrowser.removeTab(tab);
});

// ================================================================================================
// ================================================================================================
add_task(function*() {
  let tab = yield BrowserTestUtils.openNewForegroundTab(
    gBrowser, TEST_PATH + "dummy.html");

  yield ContentTask.spawn(tab.linkedBrowser, {
    list: PERFORMANCE_TIMINGS,
    precision: 2,
    isRoundedFunc: isRounded.toString()
  }, (data) => {
    let expectedPrecision = data.precision;
    let workerCall = data.workerCall;
    return new Promise(resolve => {
      let worker = new content.Worker("file_workerPerformance.js");
      worker.onmessage = function(e) {
        if (e.data.type == "status") {
          ok(e.data.status, e.data.msg);
        } else if (e.data.type == "finish") {
          worker.terminate();
          resolve();
        } else {
          ok(false, "Unknown message type");
          worker.terminate();
          resolve();
        }
      };
    worker.postMessage({precision: expectedPrecision});
    });
  });

  gBrowser.removeTab(tab);
});