tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

head_telemetry.js (5510B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
      4 */
      5 
      6 "use strict";
      7 
      8 const { TelemetryTestUtils } = ChromeUtils.importESModule(
      9  "resource://testing-common/TelemetryTestUtils.sys.mjs"
     10 );
     11 
     12 var HandshakeTelemetryHelpers = {
     13  HISTOGRAMS: ["SSL_HANDSHAKE_RESULT", "SSL_TIME_UNTIL_READY"],
     14  FLAVORS: ["", "_FIRST_TRY", "_CONSERVATIVE", "_ECH", "_ECH_GREASE"],
     15 
     16  /**
     17   * Prints the Histogram to console.
     18   *
     19   * @param {*} name The identifier of the Histogram.
     20   */
     21  dumpHistogram(name) {
     22    let values = Services.telemetry.getHistogramById(name).snapshot().values;
     23    dump(`${name}: ${JSON.stringify(values)}\n`);
     24  },
     25 
     26  /**
     27   * Counts the number of entries in the histogram, ignoring the bucket value.
     28   * e.g. {0: 1, 1: 2, 3: 3} has 6 entries.
     29   *
     30   * @param {object} histObject The histogram to count the entries of.
     31   * @returns The count of the number of entries in the histogram.
     32   */
     33  countHistogramEntries(histObject) {
     34    Assert.ok(
     35      !mozinfo.socketprocess_networking,
     36      "Histograms don't populate on network process"
     37    );
     38    let count = 0;
     39    let m = histObject.snapshot().values;
     40    for (let k in m) {
     41      count += m[k];
     42    }
     43    return count;
     44  },
     45 
     46  /**
     47   * Assert that the histogram index is the right value. It expects that
     48   * other indexes are all zero.
     49   *
     50   * @param {object} histogram The histogram to check.
     51   * @param {number} index The index to check against the expected value.
     52   * @param {number} expected The expected value of the index.
     53   */
     54  assertHistogramMap(histogram, expectedEntries) {
     55    Assert.ok(
     56      !mozinfo.socketprocess_networking,
     57      "Histograms don't populate on network process"
     58    );
     59    let snapshot = JSON.parse(JSON.stringify(histogram));
     60    for (let [Tk, Tv] of expectedEntries.entries()) {
     61      let found = false;
     62      for (let [i, val] of Object.entries(snapshot.values)) {
     63        if (i == Tk) {
     64          found = true;
     65          Assert.equal(val, Tv, `expected counts should match at index ${i}`);
     66          snapshot.values[i] = 0; // Reset the value
     67        }
     68      }
     69      Assert.ok(found, `Should have found an entry at index ${Tk}`);
     70    }
     71    for (let k in snapshot.values) {
     72      Assert.equal(
     73        snapshot.values[k],
     74        0,
     75        `Should NOT have found an entry at index ${k} of value ${snapshot.values[k]}`
     76      );
     77    }
     78  },
     79 
     80  /**
     81   * Generates the pairwise concatonation of histograms and flavors.
     82   *
     83   * @param {Array} histogramList A subset of HISTOGRAMS.
     84   * @param {Array} flavorList  A subset of FLAVORS.
     85   * @returns {Array} Valid TLS Histogram identifiers
     86   */
     87  getHistogramNames(histogramList, flavorList) {
     88    let output = [];
     89    for (let h of histogramList) {
     90      Assert.ok(this.HISTOGRAMS.includes(h), "Histogram name valid");
     91      for (let f of flavorList) {
     92        Assert.ok(this.FLAVORS.includes(f), "Histogram flavor valid");
     93        output.push(h.concat(f));
     94      }
     95    }
     96    return output;
     97  },
     98 
     99  /**
    100   * getHistogramNames but mapped to Histogram objects.
    101   */
    102  getHistograms(histogramList, flavorList) {
    103    return this.getHistogramNames(histogramList, flavorList).map(x =>
    104      Services.telemetry.getHistogramById(x)
    105    );
    106  },
    107 
    108  /**
    109   * Clears TLS Handshake Histograms.
    110   */
    111  resetHistograms() {
    112    let allHistograms = this.getHistograms(this.HISTOGRAMS, this.FLAVORS);
    113    for (let h of allHistograms) {
    114      h.clear();
    115    }
    116  },
    117 
    118  /**
    119   * Checks that all TLS Handshake Histograms of a particular flavor have
    120   * exactly resultCount entries for the resultCode and no other entries.
    121   *
    122   * @param {Array} flavors An array of strings corresponding to which types
    123   *                        of histograms should have entries. See
    124   *                        HandshakeTelemetryHelpers.FLAVORS.
    125   * @param {number} resultCode The expected result code, see sslerr.h. 0 is success, all others are errors.
    126   * @param {number} resultCount The number of handshake results expected.
    127   */
    128  checkEntry(flavors, resultCode, resultCount) {
    129    Assert.ok(
    130      !mozinfo.socketprocess_networking,
    131      "Histograms don't populate on network process"
    132    );
    133    // SSL_HANDSHAKE_RESULT_{FLAVOR}
    134    for (let h of this.getHistograms(["SSL_HANDSHAKE_RESULT"], flavors)) {
    135      TelemetryTestUtils.assertHistogram(h, resultCode, resultCount);
    136    }
    137 
    138    // SSL_TIME_UNTIL_READY_{FLAVOR} should only contain values if we expected success.
    139    if (resultCode === 0) {
    140      for (let h of this.getHistograms(["SSL_TIME_UNTIL_READY"], flavors)) {
    141        Assert.strictEqual(
    142          this.countHistogramEntries(h),
    143          resultCount,
    144          "Timing entry count correct"
    145        );
    146      }
    147    } else {
    148      for (let h of this.getHistograms(["SSL_TIME_UNTIL_READY"], flavors)) {
    149        Assert.strictEqual(
    150          this.countHistogramEntries(h),
    151          0,
    152          "No timing entries expected"
    153        );
    154      }
    155    }
    156  },
    157 
    158  checkSuccess(flavors, resultCount = 1) {
    159    this.checkEntry(flavors, 0, resultCount);
    160  },
    161 
    162  checkEmpty(flavors) {
    163    for (let h of this.getHistogramNames(this.HISTOGRAMS, flavors)) {
    164      let hObj = Services.telemetry.getHistogramById(h);
    165      Assert.strictEqual(
    166        this.countHistogramEntries(hObj),
    167        0,
    168        `No entries expected in ${h.name}. Contents: ${JSON.stringify(
    169          hObj.snapshot()
    170        )}`
    171      );
    172    }
    173  },
    174 };