From 64b5ed776680c46dc0286e8feba2a9d071b4c38b Mon Sep 17 00:00:00 2001 From: Jezen Thomas Date: Thu, 13 Feb 2025 18:29:27 +0700 Subject: [PATCH] Add first integrated test with nixosTest VM (wip) This is a first pass at adding integrated tests for keter. This works by spinning up a NixOS virtual machine, running keter as a systemd service on it, and probing it with HTTP requests. --- flake.nix | 2 ++ keter.nix | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ vm.nix | 41 ++++++++++++++++++++++++++++++++ 3 files changed, 114 insertions(+) create mode 100644 keter.nix create mode 100644 vm.nix diff --git a/flake.nix b/flake.nix index 9bbf9e1..71e9e48 100644 --- a/flake.nix +++ b/flake.nix @@ -39,6 +39,8 @@ stylish-haskell.enable = true; }; }; + + integratedTests = pkgs.callPackage ./vm.nix { inherit self; }; }; devShells.default = pkgs.haskellPackages.shellFor { diff --git a/keter.nix b/keter.nix new file mode 100644 index 0000000..bbf5a4a --- /dev/null +++ b/keter.nix @@ -0,0 +1,71 @@ +{ config, lib, pkgs, ... }: + +let + cfg = config.services.keter-ng; + +in +{ + options.services.keter-ng = { + enable = lib.mkEnableOption (lib.mdDoc '' + keter — a web app deployment manager. + ''); + + root = lib.mkOption { + type = lib.types.str; + default = "/opt/keter"; + description = lib.mdDoc "Mutable state folder for keter"; + }; + + package = lib.mkOption { + type = lib.types.package; + default = pkgs.haskellPackages.keter; + defaultText = lib.literalExpression "pkgs.haskellPackages.keter"; + description = lib.mdDoc "The keter package to be used"; + }; + + globalKeterConfig = lib.mkOption { + type = lib.types.str; + default = ""; + description = lib.mdDoc '' + A custom YAML configuration for Keter. This content will be directly + written to the `keter-config.yml` file without modification. See + + for reference. + ''; + }; + }; + + config = lib.mkIf cfg.enable ( + let + incoming = "${cfg.root}/incoming"; + + globalKeterConfigFile = pkgs.writeTextFile { + name = "keter-config.yml"; + text = cfg.globalKeterConfig; + }; + in + { + systemd.services.keter-ng = { + description = "keter app loader"; + script = '' + set -xe + mkdir -p ${incoming} + ${lib.getExe cfg.package} ${globalKeterConfigFile}; + ''; + wantedBy = [ "multi-user.target" "nginx.service" ]; + + serviceConfig = { + Restart = "always"; + RestartSec = "10s"; + }; + + after = [ + "network.target" + "local-fs.target" + "postgresql.service" + ]; + }; + } + ); +} + diff --git a/vm.nix b/vm.nix new file mode 100644 index 0000000..a9243a3 --- /dev/null +++ b/vm.nix @@ -0,0 +1,41 @@ +{ testers, pkgs, self }: + +testers.nixosTest { + name = "vm-test"; + + nodes.server = { ... }: { + + environment.systemPackages = with pkgs; [ httpie ]; + + imports = [ + ./keter.nix + ]; + + nix.settings = { + experimental-features = [ "nix-command" "flakes" ]; + auto-optimise-store = true; + }; + + services.keter-ng = { + enable = true; + package = self.packages.x86_64-linux.keter; + globalKeterConfig = '' + root: /opt/keter + rotate-logs: false + listeners: + - host: "*4" + port: 80 + ''; + }; + + }; + + testScript = '' + server.start() + server.wait_for_unit("keter.service") + + # Verify keter is running + server.wait_for_unit("keter.service") + server.wait_until_succeeds("http --check-status :80", timeout = 10) + ''; +}