about summary refs log tree commit diff
path: root/nixos/tests/custom-ca.nix
diff options
context:
space:
mode:
authorScott Worley <scottworley@scottworley.com>2022-03-30 01:26:31 -0700
committerrnhmjoj <rnhmjoj@inventati.org>2022-04-27 20:50:53 +0200
commit3f676b98049a2dc890023aac02758c604e160b8d (patch)
tree83601bd8532ab11785b61e20fc211c8f9da32328 /nixos/tests/custom-ca.nix
parent1a4307af6dfcdc3b097f03a26feec9181920381d (diff)
nixos/tests/custom-ca: Split
Run each browser check as a separate NixOS test.

This fixes a problem in which one browser starts up before the previous
browser is finished exiting, exhausting a resource and causing a
spurious test failure.

As a bonus, splitting the test
  * Gives more signal about exactly what's broken in the pass/fail status,
  * Makes it easier to quickly diagnose test failures,
  * Makes development iteration faster,
  * Allows concurrent test execution, which makes the test finish sooner
    when parallel builds are enabled.
  * Would allow each browser's test to be included in its nixpkgs
    passthru.tests, if desired (not done in this commit).

Reviewed-by: rnhmjoj <rnhmjoj@inventati.org>
Diffstat (limited to 'nixos/tests/custom-ca.nix')
-rw-r--r--nixos/tests/custom-ca.nix192
1 files changed, 102 insertions, 90 deletions
diff --git a/nixos/tests/custom-ca.nix b/nixos/tests/custom-ca.nix
index 60c6c82223a93..91d80dc0dea16 100644
--- a/nixos/tests/custom-ca.nix
+++ b/nixos/tests/custom-ca.nix
@@ -1,9 +1,14 @@
 # Checks that `security.pki` options are working in curl and the main browser
-# engines: Gecko (via Firefox), Chromium, QtWebEngine (Falkon) and WebKitGTK
-# (via Midori). The test checks that certificates issued by a custom trusted
-# CA are accepted but those from an unknown CA are rejected.
+# engines: Gecko (via Firefox), Chromium, QtWebEngine (via qutebrowser) and
+# WebKitGTK (via Midori). The test checks that certificates issued by a custom
+# trusted CA are accepted but those from an unknown CA are rejected.
 
-import ./make-test-python.nix ({ pkgs, lib, ... }:
+{ system ? builtins.currentSystem,
+  config ? {},
+  pkgs ? import ../.. { inherit system config; }
+}:
+
+with import ../lib/testing-python.nix { inherit system pkgs; };
 
 let
   makeCert = { caName, domain }: pkgs.runCommand "example-cert"
@@ -68,24 +73,8 @@ let
       domain = "bad.example.com";
     };
 
-in
-
-{
-  name = "custom-ca";
-  meta.maintainers = with lib.maintainers; [ rnhmjoj ];
-
-  enableOCR = true;
-
-  nodes.machine = { pkgs, ... }:
-    { imports = [ ./common/user-account.nix ./common/x11.nix ];
-
-      # chromium-based browsers refuse to run as root
-      test-support.displayManager.auto.user = "alice";
-
-      # browsers may hang with the default memory
-      virtualisation.memorySize = 600;
-
-      networking.hosts."127.0.0.1" = [ "good.example.com" "bad.example.com" ];
+  webserverConfig =
+    { networking.hosts."127.0.0.1" = [ "good.example.com" "bad.example.com" ];
       security.pki.certificateFiles = [ "${example-good-cert}/ca.crt" ];
 
       services.nginx.enable = true;
@@ -107,73 +96,96 @@ in
             return 200 'It does not work!';
           '';
         };
-
-      environment.systemPackages = with pkgs; [
-        xdotool
-        firefox
-        chromium
-        qutebrowser
-        midori
-      ];
     };
 
-  testScript = ''
-    from typing import Tuple
-    def execute_as(user: str, cmd: str) -> Tuple[int, str]:
-        """
-        Run a shell command as a specific user.
-        """
-        return machine.execute(f"sudo -u {user} {cmd}")
-
-
-    def wait_for_window_as(user: str, cls: str) -> None:
-        """
-        Wait until a X11 window of a given user appears.
-        """
-
-        def window_is_visible(last_try: bool) -> bool:
-            ret, stdout = execute_as(user, f"xdotool search --onlyvisible --class {cls}")
-            if last_try:
-                machine.log(f"Last chance to match {cls} on the window list")
-            return ret == 0
-
-        with machine.nested("Waiting for a window to appear"):
-            retry(window_is_visible)
-
-
-    machine.start()
-
-    with subtest("Good certificate is trusted in curl"):
-        machine.wait_for_unit("nginx")
-        machine.wait_for_open_port(443)
-        machine.succeed("curl -fv https://good.example.com")
-
-    with subtest("Unknown CA is untrusted in curl"):
-        machine.fail("curl -fv https://bad.example.com")
-
-    browsers = {
-      "firefox": "Security Risk",
-      "chromium": "not private",
-      "qutebrowser -T": "Certificate error",
-      "midori": "Security"
-    }
-
-    machine.wait_for_x()
-    for command, error in browsers.items():
-        browser = command.split()[0]
-        with subtest("Good certificate is trusted in " + browser):
-            execute_as(
-                "alice", f"{command} https://good.example.com >&2 &"
-            )
-            wait_for_window_as("alice", browser)
-            machine.wait_for_text("It works!")
-            machine.screenshot("good" + browser)
-            execute_as("alice", "xdotool key ctrl+w")  # close tab
-
-        with subtest("Unknown CA is untrusted in " + browser):
-            execute_as("alice", f"{command} https://bad.example.com >&2 &")
-            machine.wait_for_text(error)
-            machine.screenshot("bad" + browser)
-            machine.succeed("pkill -f " + browser)
-  '';
-})
+  curlTest = makeTest {
+    name = "custom-ca-curl";
+    meta.maintainers = with lib.maintainers; [ rnhmjoj ];
+    nodes.machine = { ... }: webserverConfig;
+    testScript = ''
+        with subtest("Good certificate is trusted in curl"):
+            machine.wait_for_unit("nginx")
+            machine.wait_for_open_port(443)
+            machine.succeed("curl -fv https://good.example.com")
+
+        with subtest("Unknown CA is untrusted in curl"):
+            machine.fail("curl -fv https://bad.example.com")
+    '';
+  };
+
+  mkBrowserTest = browser: testParams: makeTest {
+    name = "custom-ca-${browser}";
+    meta.maintainers = with lib.maintainers; [ rnhmjoj ];
+
+    enableOCR = true;
+
+    nodes.machine = { pkgs, ... }:
+      { imports =
+          [ ./common/user-account.nix
+            ./common/x11.nix
+            webserverConfig
+          ];
+
+        # chromium-based browsers refuse to run as root
+        test-support.displayManager.auto.user = "alice";
+
+        # browsers may hang with the default memory
+        virtualisation.memorySize = 600;
+
+        environment.systemPackages = [ pkgs.xdotool pkgs.${browser} ];
+      };
+
+    testScript = ''
+      from typing import Tuple
+      def execute_as(user: str, cmd: str) -> Tuple[int, str]:
+          """
+          Run a shell command as a specific user.
+          """
+          return machine.execute(f"sudo -u {user} {cmd}")
+
+
+      def wait_for_window_as(user: str, cls: str) -> None:
+          """
+          Wait until a X11 window of a given user appears.
+          """
+
+          def window_is_visible(last_try: bool) -> bool:
+              ret, stdout = execute_as(user, f"xdotool search --onlyvisible --class {cls}")
+              if last_try:
+                  machine.log(f"Last chance to match {cls} on the window list")
+              return ret == 0
+
+          with machine.nested("Waiting for a window to appear"):
+              retry(window_is_visible)
+
+
+      machine.start()
+      machine.wait_for_x()
+
+      command = "${browser} ${testParams.args or ""}"
+      with subtest("Good certificate is trusted in ${browser}"):
+          execute_as(
+              "alice", f"{command} https://good.example.com >&2 &"
+          )
+          wait_for_window_as("alice", "${browser}")
+          machine.wait_for_text("It works!")
+          machine.screenshot("good${browser}")
+          execute_as("alice", "xdotool key ctrl+w")  # close tab
+
+      with subtest("Unknown CA is untrusted in ${browser}"):
+          execute_as("alice", f"{command} https://bad.example.com >&2 &")
+          machine.wait_for_text("${testParams.error}")
+          machine.screenshot("bad${browser}")
+    '';
+  };
+
+in
+
+{
+  curl = curlTest;
+} // pkgs.lib.mapAttrs mkBrowserTest {
+  firefox = { error = "Security Risk"; };
+  chromium = { error = "not private"; };
+  qutebrowser = { args = "-T"; error = "Certificate error"; };
+  midori = { error = "Security"; };
+}