网络测试指南

本文档旨在介绍 necko 中使用的不同测试类型。目标读者是 necko 团队的新成员。

Necko 测试类型

本节仅介绍 netwerk/test 文件夹下的测试。

还有一些与 necko 相关的 web-platform-tests。我们通常不会编写新的 web-platform-tests。但是,我们确实有很多用于 XHR、Fetch 和 WebSocket 的 web-platform-tests

运行 Necko xpcshell-tests

  • 本地

    运行所有 xpcshell-tests

    ./mach xpcshell-test netwerk/test/unit
    

    请注意,xpcshell-tests 是并行运行的,有时为了调试,我们希望按顺序运行它们。

    ./mach xpcshell-test --sequential netwerk/test/unit
    

    运行单个测试

    ./mach xpcshell-test netwerk/test/unit/test_http3.js
    

    启用套接字进程运行

    ./mach xpcshell-test --setpref="network.http.network_access_on_socket_process.enabled=true" netwerk/test/unit/test_http3.js
    

    我们通常使用 HTTP Logging 调试网络问题。要在运行测试时启用日志记录

    MOZ_LOG=nsHttp:5 ./mach xpcshell-test netwerk/test/unit/test_http3.js
    
  • 远程

    首先,我们需要了解 模糊选择器,这是我们用于选择在 try 上运行哪些测试的工具。如果您已经知道您的代码更改可以通过 necko xpcshell-tests 覆盖,您可以使用以下命令在 try 上运行 netwerk/test/unit 中的所有测试。

    ./mach try fuzzy netwerk/test/unit
    

    在 try 上运行单个测试

    ./mach try fuzzy netwerk/test/unit/test_http3.js
    

    有时我们希望在启用日志记录的情况下调试 try 上失败的测试

    ./mach try fuzzy --env "MOZ_LOG=nsHttp:5,nsHostResolver:5" netwerk/tesst/unit/test_http3.js
    

    请注意,在 try 上运行文件夹中的所有测试时启用日志记录通常不是一个好主意,因为原始日志文件可能非常大。如果文件大小超过 try 上的限制,则日志文件可能不可用。如果您代码更改过于通用或不确定要运行哪些测试,则可以使用 自动选择器 让它为您选择测试。

调试间歇性测试失败

try 上有很多间歇性故障(通常无法在本地重现)。调试这些故障可能非常烦人和耗时。以下是一些帮助您更有效地调试间歇性故障的一般准则。

  • 确定故障是否由您的代码更改引起。

    • 尝试在本地重现间歇性故障。这是最直接的方法。在本地调试时添加 --verify 标志也很有用(有关更多详细信息,请参阅此 文档)。

    • 我们可以检查 try 上的故障摘要,看看此测试故障是否已提交 Bug。如果是,则很可能这不是由您的代码更改引起的。

    • 重新触发失败的测试几次,看看它是否通过。这可以通过单击 Push Health 按钮轻松完成。

    • 查找当前其他提交中发生的类似故障。这可以通过以下方式完成

    click on failing job -> read failure summary -> find similar ones by other authors in similar jobs
    
    • 要重新运行失败的测试套件更多次,您可以将 rebuild 选项添加到 ./mach try 中。例如,以下命令允许在 try 上运行 20 次 necko xpcshell-tests。

    ./mach try fuzzy netwerk/test/unit --rebuild 20
    
  • 如果我们确实需要调试间歇性测试失败,请首先参阅此 文档 获取一些一般提示。不幸的是,没有简单的方法可以调试它。可以先尝试隔离失败的测试,并在 try 上启用 HTTP logging 以收集日志以供进一步分析。

编写 Necko XPCShell 测试

最典型的 necko xpcsehll-test 形式是创建 HTTP 服务器,并通过让服务器返回一些特定响应(例如,103 Early Hint)来测试您的代码。本文档仅介绍如何编写此类测试。

  • 服务器端代码

    bug 1756557 之后,可以在测试代码中创建 nodejs HTTP 服务器。通过重用 nodejs 提供的 HTTP 模块,这节省了我们编写服务器端代码的时间。创建简单 HTTP 服务器的代码如下所示

    let server = new NodeHTTPServer();
    await server.start();
    registerCleanupFunction(async () => {
      await server.stop();
    });
    await server.registerPathHandler("/test", (req, resp) => {
      resp.writeHead(200);
      resp.end("done");
    });
    

    我们还可以通过将 NodeHTTPServer 替换为 NodeHTTP2Server 并添加服务器证书来轻松创建 HTTP/2 服务器。

    let certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
      Ci.nsIX509CertDB
    );
    addCertFromFile(certdb, "http2-ca.pem", "CTu,u,u");
    let server = new NodeHTTP2Server();
    
  • 客户端代码

    推荐的方法是创建并打开 HTTP 通道,并使用 Promise 异步处理响应。代码如下所示

    function makeChan(uri) {
      let chan = NetUtil.newChannel({
        uri,
        loadUsingSystemPrincipal: true,
      }).QueryInterface(Ci.nsIHttpChannel);
      chan.loadFlags = Ci.nsIChannel.LOAD_INITIAL_DOCUMENT_URI;
      return chan;
    }
    let chan = makeChan(`https://127.0.0.1:${server.port()}/test`);
    let req = await new Promise(resolve => {
      chan.asyncOpen(new ChannelListener(resolve, null, CL_ALLOW_UNKNOWN_CL));
    });
    

    将所有内容放在一起的代码如下所示

    add_task(async function test_http() {
      let server = new NodeHTTPServer();
      await server.start();
      registerCleanupFunction(async () => {
        await server.stop();
      });
      await server.registerPathHandler("/test", (req, resp) => {
        resp.writeHead(200);
        resp.end("done");
      });
      let chan = makeChan(`https://127.0.0.1:${server.port()}/test`);
      let req = await new Promise(resolve => {
        chan.asyncOpen(new ChannelListener(resolve, null, CL_ALLOW_UNKNOWN_CL));
      });
      equal(req.status, Cr.NS_OK);
      equal(req.QueryInterface(Ci.nsIHttpChannel).responseStatus, 200);
      equal(req.QueryInterface(Ci.nsIHttpChannel).protocolVersion, "http/1.1");
    });