From ebc924d4925093a551fa5fd888bb24205f7c6177 Mon Sep 17 00:00:00 2001 From: Florian Klink Date: Tue, 18 Mar 2025 00:45:26 +0000 Subject: [PATCH] tests(tvix/nix-daemon): add a test suite for tvix nix-daemon This uses runInLinuxVM to seed tvix-store with a path/closure, then sets up a local-overlay store mount config using the following setup: /tmp/tvix exposes everything seeded into tvix /tmp/scratch represents an empty "local" nix store This is overlayed to /tmp/merged/nix/store (using /tmp/work as an overlayfs work dir). Nix is configured with the local-overlay feature: - setting /tmp/merged as root - configuring a unix:///tmp/tvix-daemon.sock as lower store, with lower-store.real set to /tmp/tvix - configuring /tmp/scratch as an upper layer For some reasons, check-mount needs to be set to false, as Nix doesn't seem happy with the way we set up the mountpoints. Change-Id: I03e1cf1d3aaa021a63dcb30ae482a6c3977851ba Reviewed-on: https://cl.snix.dev/c/snix/+/30087 Reviewed-by: Vova Kryachko Reviewed-by: Ilan Joselevich Tested-by: besadii --- snix/nix-daemon/tests/default.nix | 118 ++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 snix/nix-daemon/tests/default.nix diff --git a/snix/nix-daemon/tests/default.nix b/snix/nix-daemon/tests/default.nix new file mode 100644 index 000000000..186cdab79 --- /dev/null +++ b/snix/nix-daemon/tests/default.nix @@ -0,0 +1,118 @@ +{ depot +, pkgs +, lib +, ... +}: + +let + mkTest = + { closure + , blobServiceAddr ? "objectstore+file:///tmp/blobs" + , directoryServiceAddr ? "redb:///tmp/directories.redb" + , pathInfoServiceAddr ? "redb:///tmp/pathinfo.redb" + , testScript + , # FUTUREWORK: make overlay setup configurable for non-local-overlay tests? + }: + + pkgs.vmTools.runInLinuxVM ( + (pkgs.runCommand "test-script" + { + nativeBuildInputs = [ + pkgs.util-linux # mount, mountpoint + depot.third_party.nixpkgs.nixVersions.stable + depot.snix.store + ]; + __structuredAttrs = true; + exportReferencesGraph.closure = [ closure ]; + } + ( + '' + touch $out + # Ensure we can construct http clients. + export SSL_CERT_FILE=/dev/null + + # Start the snix daemon, listening on a unix socket. + BLOB_SERVICE_ADDR=${lib.escapeShellArg blobServiceAddr} \ + DIRECTORY_SERVICE_ADDR=${lib.escapeShellArg directoryServiceAddr} \ + PATH_INFO_SERVICE_ADDR=${lib.escapeShellArg pathInfoServiceAddr} \ + snix-store \ + --otlp=false \ + daemon -l $PWD/snix-store.sock & + + # Wait for the service to report healthy. + timeout 22 sh -c "until ${pkgs.ip2unix}/bin/ip2unix -r out,path=$PWD/snix-store.sock ${pkgs.grpc-health-check}/bin/grpc-health-check --address 127.0.0.1 --port 8080; do sleep 1; done" + + # Export env vars so that subsequent snix-store commands will talk to + # our snix-store daemon over the unix socket. + export BLOB_SERVICE_ADDR=grpc+unix://$PWD/snix-store.sock + export DIRECTORY_SERVICE_ADDR=grpc+unix://$PWD/snix-store.sock + export PATH_INFO_SERVICE_ADDR=grpc+unix://$PWD/snix-store.sock + + echo "Copying closure ${closure}…" + # This picks up the `closure` key in `$NIX_ATTRS_JSON_FILE` automatically. + snix-store --otlp=false copy 2> /dev/null # noisy progress bars + + # Create mountpoints + # For this test, we overlay a (treated read-only) snix-provided mountpoint + # with a read-writeable scratch space. + # It is exposed at /tmp/merged/nix/store. + mkdir -p /tmp/snix /tmp/scratch /tmp/work /tmp/merged/nix/store + + snix-store --otlp=false mount -l /tmp/snix --allow-other & + # FUTUREWORK: add snix-store mount "forking to background" option + timeout 22 sh -c 'until mountpoint -q /tmp/snix; do sleep 0.5; done' + + mount -t overlay overlay -o lowerdir=/tmp/snix -o workdir=/tmp/work -o upperdir=/tmp/scratch /tmp/merged/nix/store + + # Run the Snix nix-daemon + RUST_LOG=nix_daemon=debug ${depot.snix.nix-daemon}/bin/nix-daemon --otlp=false --unix-listen-unlink --unix-listen-chmod everybody & + timeout 22 sh -c 'until [ -e /tmp/snix-daemon.sock ]; do sleep 1; done' + + # Run the test script + ${testScript} + '' + ) + ).overrideAttrs + (_: { + memSize = 4096; + }) + ); + closure = pkgs.hello; + localOverlayStoreConfig = "local-overlay://?root=/tmp/merged&lower-store=unix%3A%2F%2F%2Ftmp%2Fsnix-daemon.sock&lower-store.real%3D%2Ftmp%2Fsnix&upper-layer=/tmp/scratch&check-mount=false"; +in +{ + nixstoreQr = ( + mkTest { + inherit closure; + testScript = '' + nix-store -qR ${closure} \ + --store "${localOverlayStoreConfig}" --extra-experimental-features 'local-overlay-store' + ''; + } + ); + pathInfo = ( + mkTest { + inherit closure; + testScript = '' + nix path-info --json --closure-size --recursive ${closure} \ + --store "${localOverlayStoreConfig}" --extra-experimental-features 'local-overlay-store nix-command' + ''; + } + ); + /* + This currently cannot work as our store is not mounted at /nix/store but at another location, and since nix-shell + needs bash it fails with `unable to exec /nix/store/xxx-bash/bin/bash`, to run shell we need to chroot to have the + overlay store at /nix/store. + */ + shell = ( + mkTest { + inherit closure; + testScript = '' + nix shell ${pkgs.hello} \ + --store "${localOverlayStoreConfig}" --extra-experimental-features 'local-overlay-store nix-command' + ''; + } + ); + + meta.ci.targets = [ "nixstoreQr" "pathInfo" ]; +}