tests: exercise both nginx and caddy proxy backends
Parameterizes tests/common.nix and tests/default.nix on proxyServer (default "nginx"), giving flake.nix two nixosConfigurations (test-nginx/test-caddy) and `just build-vm [proxy]` a way to pick between them for interactive testing. The automated nixosTest now boots one node per proxy backend and runs the full assertion suite (factored into check_invoiceninja()) against each, so a regression in either nginx or caddy's config gets caught. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -16,7 +16,8 @@ editing Nix expressions.
|
||||
|
||||
This project uses `just` (see `justfile`) and Nix directly.
|
||||
|
||||
- `just build-vm` — cleans previous artifacts and builds the test VM (`nixosConfigurations.test`) via `nom build`.
|
||||
- `just build-vm [proxy]` — cleans previous artifacts and builds the test VM (`nixosConfigurations.test-<proxy>`)
|
||||
via `nom build`. `proxy` is `nginx` (default) or `caddy`.
|
||||
- `just boot-vm` — boots the built VM (`result/bin/run-nixos-vm`) in the current terminal. Serves Invoice Ninja on
|
||||
`localhost:8080` (see `QEMU_NET_OPTS` in the `justfile`) with root login `toor`.
|
||||
- `just clean` — removes `result`/`nixos.qcow2` and kills any running `qemu` process.
|
||||
@@ -28,10 +29,12 @@ This project uses `just` (see `justfile`) and Nix directly.
|
||||
### `tests/`
|
||||
|
||||
- `common.nix` — the shared `services.invoiceninja` config used by both the interactive VM and the automated test:
|
||||
imports the module, enables nginx, and points at the checked-in test fixtures (`invoice_ninja_test_password`,
|
||||
`test.env`).
|
||||
- `default.nix` — the interactive VM config (`nixosConfigurations.test` in `flake.nix`), used for manual,
|
||||
click-around verification via `just build-vm` / `just boot-vm`. Adds the qemu-guest profile, a root login, and
|
||||
imports the module and points at the checked-in test fixtures (`invoice_ninja_test_password`, `test.env`). It's a
|
||||
function taking `{ proxyServer ? "nginx" }` so callers can pick which proxy backend to test.
|
||||
- `default.nix` — the interactive VM config (`nixosConfigurations.test-nginx`/`test-caddy` in `flake.nix`), used
|
||||
for manual, click-around verification via `just build-vm [proxy]` / `just boot-vm`. It's also a function taking
|
||||
`{ proxyServer ? "nginx" }`, forwarded straight through to `common.nix`, so `flake.nix` can instantiate one
|
||||
`nixosConfigurations` entry per proxy backend. Adds the qemu-guest profile, a root login, and
|
||||
`nixpkgs.config.allowUnfree = true` (required to build `pkgs.chromium`). It also sets a dummy `fileSystems."/"`
|
||||
and disables `boot.loader.grub` purely to satisfy NixOS's built-in assertions when `nix flake check` evaluates
|
||||
`config.system.build.toplevel` directly — the qemu-vm module overrides both with a tmpfs root and direct kernel
|
||||
@@ -39,12 +42,15 @@ This project uses `just` (see `justfile`) and Nix directly.
|
||||
unused.
|
||||
- `nixos-test.nix` — the automated test (`pkgs.testers.nixosTest`, exposed as `checks.<system>.invoiceninja` in
|
||||
`flake.nix`). Builds its own `pkgs` (with `allowUnfree` baked in — `nixosTest` forbids setting `nixpkgs.config`
|
||||
on a node once `pkgs` is externally supplied) and boots a VM with `common.nix`, then: waits for
|
||||
mysql/redis/phpfpm/queue-worker/nginx to be active, checks the `invoiceninja-data-setup` marker files
|
||||
(`.initial-migration`, `.db-seeded`, `.admin-created`) to confirm the one-time setup actually completed (not just
|
||||
that the oneshot unit exited), curls `/` for the app shell, exercises the `invoiceninja-manage` wrapper, and logs
|
||||
in via `/api/v1/login` using the test admin credentials as an end-to-end check that migrations/seeding/account
|
||||
creation all worked. This is the only automated test in the repo — there is no separate unit-test suite.
|
||||
on a node once `pkgs` is externally supplied) and boots two nodes from `common.nix` — one with
|
||||
`proxyServer = "nginx"`, one with `proxyServer = "caddy"` — so both proxy backends get exercised. The shared
|
||||
assertion suite (factored into a `check_invoiceninja(machine, proxy_unit)` function in the test script) runs
|
||||
against each node: waits for mysql/redis/phpfpm/queue-worker/proxy to be active, checks the
|
||||
`invoiceninja-data-setup` marker files (`.initial-migration`, `.db-seeded`, `.admin-created`) to confirm the
|
||||
one-time setup actually completed (not just that the oneshot unit exited), curls `/` for the app shell, exercises
|
||||
the `invoiceninja-manage` wrapper, and logs in via `/api/v1/login` using the test admin credentials as an
|
||||
end-to-end check that migrations/seeding/account creation all worked. This is the only automated test in the
|
||||
repo — there is no separate unit-test suite.
|
||||
|
||||
## Architecture
|
||||
|
||||
@@ -108,8 +114,9 @@ expect Nix to report the correct hash on a failed build (or use `nix-prefetch`/`
|
||||
### `flake.nix`
|
||||
|
||||
Standard flake shape: `overlays.default` registers the package, `packages.<system>.invoiceninja` exposes it,
|
||||
`nixosModules` re-exports `nixos-module/default.nix`, and `nixosConfigurations.test` builds the VM defined in
|
||||
`tests/`. Only `x86_64-linux` is currently supported.
|
||||
`nixosModules` re-exports `nixos-module/default.nix`, and `nixosConfigurations.test-nginx`/`test-caddy` each build
|
||||
the VM defined in `tests/default.nix` with the corresponding `proxyServer`. Only `x86_64-linux` is currently
|
||||
supported.
|
||||
|
||||
## Conventions
|
||||
|
||||
|
||||
@@ -20,9 +20,15 @@
|
||||
);
|
||||
in
|
||||
rec {
|
||||
nixosConfigurations.test = nixpkgs.lib.nixosSystem {
|
||||
nixosConfigurations = {
|
||||
test-nginx = nixpkgs.lib.nixosSystem {
|
||||
system = "x86_64-linux";
|
||||
modules = [ ./tests ];
|
||||
modules = [ (import ./tests/default.nix { proxyServer = "nginx"; }) ];
|
||||
};
|
||||
test-caddy = nixpkgs.lib.nixosSystem {
|
||||
system = "x86_64-linux";
|
||||
modules = [ (import ./tests/default.nix { proxyServer = "caddy"; }) ];
|
||||
};
|
||||
};
|
||||
|
||||
overlays.default = final: prev: { invoiceninja = final.callPackage ./package.nix { }; };
|
||||
|
||||
@@ -18,10 +18,10 @@ clean:
|
||||
pkill qemu
|
||||
exit 0
|
||||
|
||||
[doc('Build virtual machine for testing')]
|
||||
[doc('Build virtual machine for testing (proxy: nginx or caddy)')]
|
||||
[group('main')]
|
||||
build-vm: clean
|
||||
nom build ".#nixosConfigurations.test.config.system.build.vm"
|
||||
build-vm proxy="nginx": clean
|
||||
nom build ".#nixosConfigurations.test-{{proxy}}.config.system.build.vm"
|
||||
|
||||
[doc('Run virtual machine in current terminal')]
|
||||
[group('main')]
|
||||
|
||||
+2
-1
@@ -1,3 +1,4 @@
|
||||
{ proxyServer ? "nginx" }:
|
||||
{ ... }:
|
||||
|
||||
{
|
||||
@@ -5,7 +6,7 @@
|
||||
|
||||
services.invoiceninja = {
|
||||
enable = true;
|
||||
proxy.server = "nginx";
|
||||
proxy.server = proxyServer;
|
||||
adminAccount.passwordFile = ./invoice_ninja_test_password;
|
||||
secretFile = ./test.env;
|
||||
settings.APP_DEBUG = true;
|
||||
|
||||
+2
-1
@@ -1,9 +1,10 @@
|
||||
{ proxyServer ? "nginx" }:
|
||||
{ pkgs, modulesPath, ... }:
|
||||
|
||||
{
|
||||
imports = [
|
||||
(modulesPath + "/profiles/qemu-guest.nix")
|
||||
./common.nix
|
||||
(import ./common.nix { inherit proxyServer; })
|
||||
];
|
||||
|
||||
# Required to build pkgs.chromium, which the module pulls in for PDF generation.
|
||||
|
||||
+13
-6
@@ -15,18 +15,18 @@ in
|
||||
pkgs.testers.nixosTest {
|
||||
name = "invoiceninja";
|
||||
|
||||
nodes.machine = {
|
||||
imports = [ ./common.nix ];
|
||||
nodes = {
|
||||
nginx.imports = [ (import ./common.nix { proxyServer = "nginx"; }) ];
|
||||
caddy.imports = [ (import ./common.nix { proxyServer = "caddy"; }) ];
|
||||
};
|
||||
|
||||
testScript = ''
|
||||
machine.start()
|
||||
|
||||
def check_invoiceninja(machine, proxy_unit):
|
||||
machine.wait_for_unit("mysql.service")
|
||||
machine.wait_for_unit("redis-invoiceninja.service")
|
||||
machine.wait_for_unit("phpfpm-invoiceninja.service")
|
||||
machine.wait_for_unit("invoiceninja-queue-worker.service")
|
||||
machine.wait_for_unit("nginx.service")
|
||||
machine.wait_for_unit(proxy_unit)
|
||||
machine.wait_for_open_port(80)
|
||||
|
||||
# phpfpm-invoiceninja/invoiceninja-queue-worker both Require= invoiceninja-data-setup,
|
||||
@@ -43,7 +43,7 @@ pkgs.testers.nixosTest {
|
||||
|
||||
with subtest("web UI login page is served"):
|
||||
# The UI is a client-side-routed React SPA, so curl (no JS) only sees the same
|
||||
# index.html shell as "/" - this confirms nginx/Laravel resolve the /login route
|
||||
# index.html shell as "/" - this confirms the proxy/Laravel resolve the /login route
|
||||
# to that shell instead of 404ing, which is what a browser needs before it can
|
||||
# render the actual login form.
|
||||
login_page = machine.succeed("curl -sf http://localhost/login")
|
||||
@@ -64,5 +64,12 @@ pkgs.testers.nixosTest {
|
||||
+ "-d '{\"email\":\"${adminEmail}\",\"password\":\"${adminPassword}\"}'"
|
||||
)
|
||||
assert "${adminEmail}" in login_response, f"login did not succeed: {login_response}"
|
||||
|
||||
|
||||
nginx.start()
|
||||
caddy.start()
|
||||
|
||||
check_invoiceninja(nginx, "nginx.service")
|
||||
check_invoiceninja(caddy, "caddy.service")
|
||||
'';
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user