Backed out changeset b71c8c052463 (bug 1943846) for causing mass failures. CLOSED...
[gecko.git] / netwerk / test / unit / test_dns_retry.js
blob477586126efeb63c798db5de4676e776f5ba02bf
1 "use strict";
3 const { HttpServer } = ChromeUtils.importESModule(
4 "resource://testing-common/httpd.sys.mjs"
5 );
6 trr_test_setup();
7 let httpServerIPv4 = new HttpServer();
8 let httpServerIPv6 = new HttpServer();
9 let trrServer;
10 let testpath = "/simple";
11 let httpbody = "0123456789";
12 let CC_IPV4 = "example_cc_ipv4.com";
13 let CC_IPV6 = "example_cc_ipv6.com";
14 Services.prefs.clearUserPref("network.dns.native-is-localhost");
16 ChromeUtils.defineLazyGetter(this, "URL_CC_IPV4", function () {
17 return `http://${CC_IPV4}:${httpServerIPv4.identity.primaryPort}${testpath}`;
18 });
19 ChromeUtils.defineLazyGetter(this, "URL_CC_IPV6", function () {
20 return `http://${CC_IPV6}:${httpServerIPv6.identity.primaryPort}${testpath}`;
21 });
22 ChromeUtils.defineLazyGetter(this, "URL6a", function () {
23 return `http://example6a.com:${httpServerIPv6.identity.primaryPort}${testpath}`;
24 });
25 ChromeUtils.defineLazyGetter(this, "URL6b", function () {
26 return `http://example6b.com:${httpServerIPv6.identity.primaryPort}${testpath}`;
27 });
29 const ncs = Cc[
30 "@mozilla.org/network/network-connectivity-service;1"
31 ].getService(Ci.nsINetworkConnectivityService);
32 const { TestUtils } = ChromeUtils.importESModule(
33 "resource://testing-common/TestUtils.sys.mjs"
36 registerCleanupFunction(async () => {
37 Services.prefs.clearUserPref("network.http.speculative-parallel-limit");
38 Services.prefs.clearUserPref("network.captive-portal-service.testMode");
39 Services.prefs.clearUserPref("network.connectivity-service.IPv6.url");
40 Services.prefs.clearUserPref("network.connectivity-service.IPv4.url");
41 Services.prefs.clearUserPref("network.dns.localDomains");
43 trr_clear_prefs();
44 await httpServerIPv4.stop();
45 await httpServerIPv6.stop();
46 await trrServer.stop();
47 });
49 function makeChan(url) {
50 let chan = NetUtil.newChannel({
51 uri: url,
52 loadUsingSystemPrincipal: true,
53 }).QueryInterface(Ci.nsIHttpChannel);
54 chan.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE;
55 chan.loadFlags |= Ci.nsIRequest.INHIBIT_CACHING;
56 chan.setTRRMode(Ci.nsIRequest.TRR_DEFAULT_MODE);
57 return chan;
60 function serverHandler(metadata, response) {
61 response.setHeader("Content-Type", "text/plain", false);
62 response.bodyOutputStream.write(httpbody, httpbody.length);
65 add_task(async function test_setup() {
66 httpServerIPv4.registerPathHandler(testpath, serverHandler);
67 httpServerIPv4.start(-1);
68 httpServerIPv6.registerPathHandler(testpath, serverHandler);
69 httpServerIPv6.start_ipv6(-1);
70 Services.prefs.setCharPref(
71 "network.dns.localDomains",
72 `foo.example.com, ${CC_IPV4}, ${CC_IPV6}`
75 trrServer = new TRRServer();
76 await trrServer.start();
78 if (mozinfo.socketprocess_networking) {
79 Services.dns; // Needed to trigger socket process.
80 await TestUtils.waitForCondition(() => Services.io.socketProcessLaunched);
83 Services.prefs.setIntPref("network.trr.mode", 3);
84 Services.prefs.setCharPref(
85 "network.trr.uri",
86 `https://foo.example.com:${trrServer.port()}/dns-query`
89 await registerDoHAnswers(true, true);
90 });
92 async function registerDoHAnswers(ipv4, ipv6) {
93 let hosts = ["example6a.com", "example6b.com"];
94 for (const host of hosts) {
95 let ipv4answers = [];
96 if (ipv4) {
97 ipv4answers = [
99 name: host,
100 ttl: 55,
101 type: "A",
102 flush: false,
103 data: "127.0.0.1",
107 await trrServer.registerDoHAnswers(host, "A", {
108 answers: ipv4answers,
111 let ipv6answers = [];
112 if (ipv6) {
113 ipv6answers = [
115 name: host,
116 ttl: 55,
117 type: "AAAA",
118 flush: false,
119 data: "::1",
124 await trrServer.registerDoHAnswers(host, "AAAA", {
125 answers: ipv6answers,
129 Services.dns.clearCache(true);
132 let StatusCounter = function () {
133 this._statusCount = {};
135 StatusCounter.prototype = {
136 QueryInterface: ChromeUtils.generateQI([
137 "nsIInterfaceRequestor",
138 "nsIProgressEventSink",
141 getInterface(iid) {
142 return this.QueryInterface(iid);
145 onProgress() {},
146 onStatus(request, status) {
147 this._statusCount[status] = 1 + (this._statusCount[status] || 0);
151 let HttpListener = function (finish, succeeded) {
152 this.finish = finish;
153 this.succeeded = succeeded;
156 HttpListener.prototype = {
157 onStartRequest: function testOnStartRequest() {},
159 onDataAvailable: function testOnDataAvailable(request, stream, off, cnt) {
160 read_stream(stream, cnt);
163 onStopRequest: function testOnStopRequest(request, status) {
164 equal(this.succeeded, status == Cr.NS_OK);
165 this.finish();
169 function promiseObserverNotification(aTopic, matchFunc) {
170 return new Promise(resolve => {
171 Services.obs.addObserver(function observe(subject, topic, data) {
172 let matches = typeof matchFunc != "function" || matchFunc(subject, data);
173 if (!matches) {
174 return;
176 Services.obs.removeObserver(observe, topic);
177 resolve({ subject, data });
178 }, aTopic);
182 async function make_request(uri, check_events, succeeded) {
183 let chan = makeChan(uri);
184 let statusCounter = new StatusCounter();
185 chan.notificationCallbacks = statusCounter;
186 await new Promise(resolve =>
187 chan.asyncOpen(new HttpListener(resolve, succeeded))
190 if (check_events) {
191 equal(
192 statusCounter._statusCount[0x4b000b] || 0,
194 "Expecting only one instance of NS_NET_STATUS_RESOLVED_HOST"
196 equal(
197 statusCounter._statusCount[0x4b0007] || 0,
199 "Expecting only one instance of NS_NET_STATUS_CONNECTING_TO"
204 async function setup_connectivity(ipv6, ipv4) {
205 Services.prefs.setBoolPref("network.captive-portal-service.testMode", true);
207 if (ipv6) {
208 Services.prefs.setCharPref(
209 "network.connectivity-service.IPv6.url",
210 URL_CC_IPV6 + testpath
212 } else {
213 Services.prefs.setCharPref(
214 "network.connectivity-service.IPv6.url",
215 "http://donotexist.example.com"
219 if (ipv4) {
220 Services.prefs.setCharPref(
221 "network.connectivity-service.IPv4.url",
222 URL_CC_IPV4 + testpath
224 } else {
225 Services.prefs.setCharPref(
226 "network.connectivity-service.IPv4.url",
227 "http://donotexist.example.com"
231 let topic = "network:connectivity-service:ip-checks-complete";
232 if (mozinfo.socketprocess_networking) {
233 topic += "-from-socket-process";
235 let observerNotification = promiseObserverNotification(topic);
236 ncs.recheckIPConnectivity();
237 await observerNotification;
239 if (!ipv6) {
240 equal(
241 ncs.IPv6,
242 Ci.nsINetworkConnectivityService.NOT_AVAILABLE,
243 "Check IPv6 support"
245 } else {
246 equal(ncs.IPv6, Ci.nsINetworkConnectivityService.OK, "Check IPv6 support");
249 if (!ipv4) {
250 equal(
251 ncs.IPv4,
252 Ci.nsINetworkConnectivityService.NOT_AVAILABLE,
253 "Check IPv4 support"
255 } else {
256 equal(ncs.IPv4, Ci.nsINetworkConnectivityService.OK, "Check IPv4 support");
260 // This test that we retry to connect using IPv4 when IPv6 connecivity is not
261 // present, but a ConnectionEntry have IPv6 prefered set.
262 // Speculative connections are disabled.
263 add_task(async function test_prefer_address_version_fail_trr3_1() {
264 Services.prefs.setIntPref("network.http.speculative-parallel-limit", 0);
265 await registerDoHAnswers(true, true);
267 // Make a request to setup the address version preference to a ConnectionEntry.
268 await make_request(URL6a, true, true);
270 // connect again using the address version preference from the ConnectionEntry.
271 await make_request(URL6a, true, true);
273 // Make IPv6 connectivity check fail
274 await setup_connectivity(false, true);
276 Services.dns.clearCache(true);
278 // This will succeed as we query both DNS records
279 await make_request(URL6a, true, true);
281 // Now make the DNS server only return IPv4 records
282 await registerDoHAnswers(true, false);
283 // This will fail, because the server is not lisenting to IPv4 address as well,
284 // We should still get NS_NET_STATUS_RESOLVED_HOST and
285 // NS_NET_STATUS_CONNECTING_TO notification.
286 await make_request(URL6a, true, false);
288 // Make IPv6 connectivity check succeed again
289 await setup_connectivity(true, true);
292 // This test that we retry to connect using IPv4 when IPv6 connecivity is not
293 // present, but a ConnectionEntry have IPv6 prefered set.
294 // Speculative connections are enabled.
295 add_task(async function test_prefer_address_version_fail_trr3_2() {
296 Services.prefs.setIntPref("network.http.speculative-parallel-limit", 6);
297 await registerDoHAnswers(true, true);
299 // Make a request to setup the address version preference to a ConnectionEntry.
300 await make_request(URL6b, false, true);
302 // connect again using the address version preference from the ConnectionEntry.
303 await make_request(URL6b, false, true);
305 // Make IPv6 connectivity check fail
306 await setup_connectivity(false, true);
308 Services.dns.clearCache(true);
310 // This will succeed as we query both DNS records
311 await make_request(URL6b, false, true);
313 // Now make the DNS server only return IPv4 records
314 await registerDoHAnswers(true, false);
315 // This will fail, because the server is not lisenting to IPv4 address as well,
316 // We should still get NS_NET_STATUS_RESOLVED_HOST and
317 // NS_NET_STATUS_CONNECTING_TO notification.
318 await make_request(URL6b, true, false);