summaryrefslogtreecommitdiffstats
path: root/browser/components/doh/test/unit/test_LookupAggregator.js
blob: c2050a8ca872f016db9f7b544a9a96732b799ef5 (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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
/* Any copyright is dedicated to the Public Domain.
 * http://creativecommons.org/publicdomain/zero/1.0/
 */

"use strict";

const { setTimeout } = ChromeUtils.importESModule(
  "resource://gre/modules/Timer.sys.mjs"
);

add_task(setup);

async function helper_SuccessfulLookupAggregator(
  networkUnstable = false,
  captivePortal = false
) {
  let deferred = PromiseUtils.defer();
  let aggregator = new LookupAggregator(() => deferred.resolve(), trrList);
  // The aggregator's domain list should correctly reflect our set
  // prefs for number of random subdomains (2) and the list of
  // popular domains.
  Assert.equal(aggregator.domains[0], null);
  Assert.equal(aggregator.domains[1], null);
  Assert.equal(aggregator.domains[2], "foo.example.com.");
  Assert.equal(aggregator.domains[3], "bar.example.com.");
  Assert.equal(aggregator.totalLookups, 8); // 2 TRRs * 4 domains.

  if (networkUnstable) {
    aggregator.markUnstableNetwork();
  }
  if (captivePortal) {
    aggregator.markCaptivePortal();
  }
  aggregator.run();
  await deferred.promise;
  Assert.ok(!aggregator.aborted);
  Assert.equal(aggregator.networkUnstable, networkUnstable);
  Assert.equal(aggregator.captivePortal, captivePortal);
  Assert.equal(aggregator.results.length, aggregator.totalLookups);

  let events = Services.telemetry.snapshotEvents(
    Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS,
    true
  ).parent;
  Assert.ok(events);
  events = events.filter(e => e[1] == "security.doh.trrPerformance");
  Assert.equal(events.length, aggregator.totalLookups);

  for (let event of events) {
    info(JSON.stringify(event));
    Assert.equal(event[1], "security.doh.trrPerformance");
    Assert.equal(event[2], "resolved");
    Assert.equal(event[3], "record");
    Assert.equal(event[4], "success");
  }

  // We only need to check the payload of each event from here on.
  events = events.map(e => e[5]);

  for (let trr of [trrServer1, trrServer2]) {
    // There should be two results for random subdomains.
    let results = aggregator.results.filter(r => {
      return r.trr == trr && r.domain.endsWith(".firefox-dns-perf-test.net.");
    });
    Assert.equal(results.length, 2);

    for (let result of results) {
      Assert.ok(result.domain.endsWith(".firefox-dns-perf-test.net."));
      Assert.equal(result.trr, trr);
      Assert.ok(Components.isSuccessCode(result.status));
      Assert.greater(result.time, 0);
      Assert.equal(result.retryCount, 1);

      let matchingEvents = events.filter(
        e => e.domain == result.domain && e.trr == result.trr
      );
      Assert.equal(matchingEvents.length, 1);
      let e = matchingEvents.pop();
      for (let key of Object.keys(result)) {
        Assert.equal(e[key], result[key].toString());
      }
      Assert.equal(e.networkUnstable, networkUnstable.toString());
      Assert.equal(e.captivePortal, captivePortal.toString());
    }

    // There should be two results for the popular domains.
    results = aggregator.results.filter(r => {
      return r.trr == trr && !r.domain.endsWith(".firefox-dns-perf-test.net.");
    });
    Assert.equal(results.length, 2);

    Assert.ok(
      [results[0].domain, results[1].domain].includes("foo.example.com.")
    );
    Assert.ok(
      [results[0].domain, results[1].domain].includes("bar.example.com.")
    );
    for (let result of results) {
      Assert.equal(result.trr, trr);
      Assert.equal(result.status, Cr.NS_OK);
      Assert.greater(result.time, 0);
      Assert.equal(result.retryCount, 1);

      let matchingEvents = events.filter(
        e => e.domain == result.domain && e.trr == result.trr
      );
      Assert.equal(matchingEvents.length, 1);
      let e = matchingEvents.pop();
      for (let key of Object.keys(result)) {
        Assert.equal(e[key], result[key].toString());
      }
      Assert.equal(e.networkUnstable, networkUnstable.toString());
      Assert.equal(e.captivePortal, captivePortal.toString());
    }
  }

  Services.telemetry.clearEvents();
}

add_task(async function test_SuccessfulLookupAggregator() {
  await helper_SuccessfulLookupAggregator(false, false);
  await helper_SuccessfulLookupAggregator(false, true);
  await helper_SuccessfulLookupAggregator(true, false);
  await helper_SuccessfulLookupAggregator(true, true);
});

add_task(async function test_AbortedLookupAggregator() {
  let deferred = PromiseUtils.defer();
  let aggregator = new LookupAggregator(() => deferred.resolve(), trrList);
  // The aggregator's domain list should correctly reflect our set
  // prefs for number of random subdomains (2) and the list of
  // popular domains.
  Assert.equal(aggregator.domains[0], null);
  Assert.equal(aggregator.domains[1], null);
  Assert.equal(aggregator.domains[2], "foo.example.com.");
  Assert.equal(aggregator.domains[3], "bar.example.com.");
  Assert.equal(aggregator.totalLookups, 8); // 2 TRRs * 4 domains.

  // The aggregator should never call the onComplete callback. To test
  // this, race the deferred promise with a 3 second timeout. The timeout
  // should win, since the deferred promise should never resolve.
  let timeoutPromise = new Promise(resolve => {
    // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
    setTimeout(() => resolve("timeout"), 3000);
  });
  aggregator.run();
  aggregator.abort();
  let winner = await Promise.race([deferred.promise, timeoutPromise]);
  Assert.equal(winner, "timeout");
  Assert.ok(aggregator.aborted);
  Assert.ok(!aggregator.networkUnstable);
  Assert.ok(!aggregator.captivePortal);

  // Ensure we send no telemetry for an aborted run!
  let events = Services.telemetry.snapshotEvents(
    Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS,
    true
  ).parent;
  Assert.ok(
    !events || !events.filter(e => e[1] == "security.doh.trrPerformance").length
  );
});