Bug 1807268 - Re-enable verifyShowClipboardSuggestionsToggleTest UI test r=jajohnson
[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}`
73   );
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);
81   }
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`
87   );
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 = [
98         {
99           name: host,
100           ttl: 55,
101           type: "A",
102           flush: false,
103           data: "127.0.0.1",
104         },
105       ];
106     }
107     await trrServer.registerDoHAnswers(host, "A", {
108       answers: ipv4answers,
109     });
111     let ipv6answers = [];
112     if (ipv6) {
113       ipv6answers = [
114         {
115           name: host,
116           ttl: 55,
117           type: "AAAA",
118           flush: false,
119           data: "::1",
120         },
121       ];
122     }
124     await trrServer.registerDoHAnswers(host, "AAAA", {
125       answers: ipv6answers,
126     });
127   }
129   Services.dns.clearCache(true);
132 let StatusCounter = function () {
133   this._statusCount = {};
135 StatusCounter.prototype = {
136   QueryInterface: ChromeUtils.generateQI([
137     "nsIInterfaceRequestor",
138     "nsIProgressEventSink",
139   ]),
141   getInterface(iid) {
142     return this.QueryInterface(iid);
143   },
145   onProgress() {},
146   onStatus(request, status) {
147     this._statusCount[status] = 1 + (this._statusCount[status] || 0);
148   },
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);
161   },
163   onStopRequest: function testOnStopRequest(request, status) {
164     equal(this.succeeded, status == Cr.NS_OK);
165     this.finish();
166   },
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;
175       }
176       Services.obs.removeObserver(observe, topic);
177       resolve({ subject, data });
178     }, aTopic);
179   });
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))
188   );
190   if (check_events) {
191     equal(
192       statusCounter._statusCount[0x4b000b] || 0,
193       1,
194       "Expecting only one instance of NS_NET_STATUS_RESOLVED_HOST"
195     );
196     equal(
197       statusCounter._statusCount[0x4b0007] || 0,
198       1,
199       "Expecting only one instance of NS_NET_STATUS_CONNECTING_TO"
200     );
201   }
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
211     );
212   } else {
213     Services.prefs.setCharPref(
214       "network.connectivity-service.IPv6.url",
215       "http://donotexist.example.com"
216     );
217   }
219   if (ipv4) {
220     Services.prefs.setCharPref(
221       "network.connectivity-service.IPv4.url",
222       URL_CC_IPV4 + testpath
223     );
224   } else {
225     Services.prefs.setCharPref(
226       "network.connectivity-service.IPv4.url",
227       "http://donotexist.example.com"
228     );
229   }
231   let topic = "network:connectivity-service:ip-checks-complete";
232   if (mozinfo.socketprocess_networking) {
233     topic += "-from-socket-process";
234   }
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"
244     );
245   } else {
246     equal(ncs.IPv6, Ci.nsINetworkConnectivityService.OK, "Check IPv6 support");
247   }
249   if (!ipv4) {
250     equal(
251       ncs.IPv4,
252       Ci.nsINetworkConnectivityService.NOT_AVAILABLE,
253       "Check IPv4 support"
254     );
255   } else {
256     equal(ncs.IPv4, Ci.nsINetworkConnectivityService.OK, "Check IPv4 support");
257   }
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);