{
  system ? builtins.currentSystem,
  config ? { },
  pkgs ? import ../.. { inherit system config; },
  systemdStage1,
}:

import ../make-test-python.nix (
  { lib, ... }:

  {
    name = "initrd-network-openvpn";

    nodes =
      let

        # Inlining of the shared secret for the
        # OpenVPN server and client
        secretblock = ''
          secret [inline]
          <secret>
          ${lib.readFile ./shared.key}
          </secret>
        '';

      in
      {

        # Minimal test case to check a successful boot, even with invalid config
        minimalboot =
          { ... }:
          {
            boot.initrd.systemd.enable = systemdStage1;
            boot.initrd.network = {
              enable = true;
              openvpn = {
                enable = true;
                configuration = builtins.toFile "initrd.ovpn" "";
              };
            };
          };

        # initrd VPN client
        ovpnclient =
          { ... }:
          {
            virtualisation.useBootLoader = true;
            virtualisation.vlans = [ 1 ];

            boot.initrd = {
              systemd.enable = systemdStage1;
              systemd.extraBin.nc = "${pkgs.busybox}/bin/nc";
              systemd.services.nc = {
                requiredBy = [ "initrd.target" ];
                after = [ "network.target" ];
                serviceConfig = {
                  ExecStart = "/bin/nc -p 1234 -lke /bin/echo TESTVALUE";
                  Type = "oneshot";
                };
              };

              # This command does not fork to keep the VM in the state where
              # only the initramfs is loaded
              preLVMCommands = lib.mkIf (!systemdStage1) ''
                /bin/nc -p 1234 -lke /bin/echo TESTVALUE
              '';

              network = {
                enable = true;

                # Work around udhcpc only getting a lease on eth0
                postCommands = lib.mkIf (!systemdStage1) ''
                  /bin/ip addr add 192.168.1.2/24 dev eth1
                '';

                # Example configuration for OpenVPN
                # This is the main reason for this test
                openvpn = {
                  enable = true;
                  configuration = "${./initrd.ovpn}";
                };
              };
            };
          };

        # VPN server and gateway for ovpnclient between vlan 1 and 2
        ovpnserver =
          { ... }:
          {
            virtualisation.vlans = [
              1
              2
            ];

            # Enable NAT and forward port 12345 to port 1234
            networking.nat = {
              enable = true;
              internalInterfaces = [ "tun0" ];
              externalInterface = "eth2";
              forwardPorts = [
                {
                  destination = "10.8.0.2:1234";
                  sourcePort = 12345;
                }
              ];
            };

            # Trust tun0 and allow the VPN Server to be reached
            networking.firewall = {
              trustedInterfaces = [ "tun0" ];
              allowedUDPPorts = [ 1194 ];
            };

            # Minimal OpenVPN server configuration
            services.openvpn.servers.testserver = {
              config = ''
                dev tun0
                ifconfig 10.8.0.1 10.8.0.2
                cipher AES-256-CBC
                ${secretblock}
              '';
            };
          };

        # Client that resides in the "external" VLAN
        testclient =
          { ... }:
          {
            virtualisation.vlans = [ 2 ];
          };
      };

    testScript = ''
      # Minimal test case, checks whether enabling (with invalid config) harms
      # the boot process
      with subtest("Check for successful boot with broken openvpn config"):
          minimalboot.start()
          # If we get to multi-user.target, we booted successfully
          minimalboot.wait_for_unit("multi-user.target")
          minimalboot.shutdown()

      # Elaborated test case where the ovpnclient (where this module is used)
      # can be reached by testclient only over ovpnserver.
      # This is an indirect test for success.
      with subtest("Check for connection from initrd VPN client, config as file"):
          ovpnserver.start()
          testclient.start()
          ovpnclient.start()

          # Wait until the OpenVPN Server is available
          ovpnserver.wait_for_unit("openvpn-testserver.service")
          ovpnserver.succeed("ping -c 1 10.8.0.1")

          # Wait for the client to connect
          ovpnserver.wait_until_succeeds("ping -c 1 10.8.0.2")

          # Wait until the testclient has network
          testclient.wait_for_unit("network.target")

          # Check that ovpnclient is reachable over vlan 1
          ovpnserver.succeed("nc -w 2 192.168.1.2 1234 | grep -q TESTVALUE")

          # Check that ovpnclient is reachable over tun0
          ovpnserver.succeed("nc -w 2 10.8.0.2 1234 | grep -q TESTVALUE")

          # Check that ovpnclient is reachable from testclient over the gateway
          testclient.succeed("nc -w 2 192.168.2.3 12345 | grep -q TESTVALUE")
    '';
  }
)
