From 3e50eea6055862f1d9180a27611091dd19472291 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BChlbacher?= Date: Fri, 14 Jun 2024 17:11:25 +0200 Subject: [PATCH 1/9] test(nix): add basic functionality testing infra MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use nixos-test scaffolding to spawn VMs and run any scripts in `checks/*.sh` as tests inside of the VM. This should lessen the risk of any obvious breakage in the CI but needs more and better tests to cover more commands. Signed-off-by: Thomas Mühlbacher --- README.md | 14 +++++++ checks/README.md | 72 ++++++++++++++++++++++++++++++++++++ checks/default.nix | 47 +++++++++++++++++++++++ checks/encrypted-multidev.sh | 34 +++++++++++++++++ checks/encrypted-unlock.sh | 39 +++++++++++++++++++ checks/outputs.sh | 20 ++++++++++ checks/subvolume.sh | 36 ++++++++++++++++++ flake.nix | 56 +++++++++++++++------------- 8 files changed, 293 insertions(+), 25 deletions(-) create mode 100644 checks/README.md create mode 100644 checks/default.nix create mode 100755 checks/encrypted-multidev.sh create mode 100755 checks/encrypted-unlock.sh create mode 100755 checks/outputs.sh create mode 100755 checks/subvolume.sh diff --git a/README.md b/README.md index f95defa55..7dcb8a03c 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,20 @@ Build and install Refer to [INSTALL.md](./INSTALL.md) +Testing +------- + +Besides manual testing, which is also encouraged, there are also a number of +checks defined that are used for CI (e.g. github actions). + +These checks can be listed using `nix flake show`. You can, for example, test +the current state of the repo or test every patch before publishing them. + +```console +$ nix flake check +$ git rev-list origin/master.. | xargs -I{} nix flake check "git+file://$(pwd)?rev={}" +``` + Bug reports and contributions ----------------------------- diff --git a/checks/README.md b/checks/README.md new file mode 100644 index 000000000..1deecea60 --- /dev/null +++ b/checks/README.md @@ -0,0 +1,72 @@ +# NixOS tests + +Any `*.sh` file in this directory will be run in a NixOS VM for basic +functionality testing as part of CI. To list all outputs, including the checks, +you can use this command: + +```console +$ nix flake show +``` + +You can also run these tests locally by running `nix flake check`. To run one +specific test you can use `nix build` like this: + +```console +$ nix build ".#checks.x86_64-linux.subvolume" +``` + +With the flag `-L`/`--print-build-logs` outputs are shown fully as checks are +executing. Additionally, if the specific check has already been run locally, you +can view the log for the check or force another run with the following: + +```console +$ nix log .#checks.x86_64-linux.subvolume +$ nix build --rebuild .#checks.x86_64-linux.subvolume +``` + +If you need any more packages inside of the VM for a test, you can add them to +`environment.systemPackages` in `default.nix`. If you're unsure about the +package you need, [NixOS package search] may be able to help. + +For more information about the NixOS testing library see the +[testing wiki article]. + +## Kernel version inside VM + +By default `linuxPackages_latest` from nixpkgs is used in the testing VM. This +is the latest stable kernel version available in the nixpkgs revision. Updating +the nixpkgs flake input may update the used kernel. A custom-built kernel can be +used as well but with added build times in CI. + +## Adding new tests + +The easiest way to add new tests is of course to copy an existing test and adapt +it accordingly. Importantly, for nix to see a file as part of the sources, the +file needs to be in the git index. It doesn't have to be committed to the repo +just yet but you need to `git add` it. If `git ls-files` lists the file, nix +will also see it. + +## Interactive debugging of tests + +When writing a new test or experiencing a difficult to understand test failure, +an interactive login can be very handy. This can be achieved by building the +`driverInteractive` attribute of the check, for example like this: + +```console +$ nix build .#checks.x86_64-linux.subvolume.driverInteractive +``` + +The `nix build` will create a symlink in your working directory called `result` +which leads to a script that launches the VM interactively: + +```console +$ ./result/bin/nixos-test-driver +``` + +There is more information about this in the NixOS manual under +[running tests interactively]. + +[Linux wiki article]: https://wiki.nixos.org/wiki/Linux_kernel +[NixOS package search]: https://search.nixos.org +[running tests interactively]: https://nixos.org/manual/nixos/stable/#sec-running-nixos-tests-interactively +[testing wiki article]: https://wiki.nixos.org/wiki/NixOS_Testing_library diff --git a/checks/default.nix b/checks/default.nix new file mode 100644 index 000000000..5a85d1e69 --- /dev/null +++ b/checks/default.nix @@ -0,0 +1,47 @@ +{ pkgs }: +let + inherit (builtins) baseNameOf readDir; + inherit (pkgs.lib) + filterAttrs + genAttrs + hasSuffix + mapAttrsToList + removeSuffix + ; + + scriptName = shFile: removeSuffix ".sh" (baseNameOf shFile); + + scriptNames = mapAttrsToList (n: v: scriptName n) ( + filterAttrs (n: v: v == "regular" && hasSuffix ".sh" n) (readDir ./.) + ); + + mkTest = + name: + pkgs.testers.runNixOSTest { + inherit name; + + nodes.machine = + { pkgs, ... }: + { + virtualisation.emptyDiskImages = [ 4096 ]; + boot.supportedFilesystems = [ "bcachefs" ]; + boot.kernelPackages = pkgs.linuxPackages_latest; + + # Add any packages you need inside test scripts here + environment.systemPackages = with pkgs; [ + genpass + keyutils + ]; + + environment.variables = { + RUST_BACKTRACE = "full"; + }; + }; + + testScript = '' + machine.succeed("modprobe bcachefs") + machine.succeed("${./${name}.sh} 1>&2") + ''; + }; +in +genAttrs scriptNames mkTest diff --git a/checks/encrypted-multidev.sh b/checks/encrypted-multidev.sh new file mode 100755 index 000000000..bcd092e25 --- /dev/null +++ b/checks/encrypted-multidev.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash +set -euxo pipefail + +blkdev="/dev/vdb" +mnt="/tmp/mnt" +pw=$(genpass) +uuid=$(uuidgen) + +# link user and session keyrings so that the key can be found by the kernel +keyctl link @u @s + +sfdisk "$blkdev" < Date: Mon, 10 Jun 2024 23:22:00 +0200 Subject: [PATCH 2/9] build(nix): filter src to reduce useless rebuilds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This in particular speeds up the dev/run/debug cycle for writing more tests. Without this, the actual bcachefs-tools package will be rebuilt by Nix all the time because of changes to files that are tracked by git. Even when it's changes in parts that aren't relevant to that package build such as `checks/*`. Signed-off-by: Thomas Mühlbacher --- flake.nix | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index 963dee119..c95912c3e 100644 --- a/flake.nix +++ b/flake.nix @@ -58,6 +58,7 @@ }: let inherit (builtins) readFile split; + inherit (lib) fileset; inherit (lib.lists) findFirst; inherit (lib.strings) hasPrefix removePrefix substring; @@ -74,7 +75,17 @@ commonArgs = { inherit version; - src = self; + src = fileset.toSource { + root = ./.; + + fileset = fileset.difference (fileset.gitTracked ./.) ( + fileset.unions [ + ./checks + ./doc + ./tests + ] + ); + }; env = { PKG_CONFIG_SYSTEMD_SYSTEMDSYSTEMUNITDIR = "${placeholder "out"}/lib/systemd/system"; From 6377d93b1c8aba89878957b6e573c35f70c91f1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BChlbacher?= Date: Fri, 14 Jun 2024 00:41:39 +0200 Subject: [PATCH 3/9] Revert "ci: run nix build in workflow" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 88aa61eb9550c1c92ef63812f09861e4005af581. No longer required because the added nixos-tests check already causes the package to be built now. Signed-off-by: Thomas Mühlbacher --- .github/workflows/nix-flake.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/nix-flake.yml b/.github/workflows/nix-flake.yml index 4dfb6453a..af9582acd 100644 --- a/.github/workflows/nix-flake.yml +++ b/.github/workflows/nix-flake.yml @@ -19,4 +19,3 @@ jobs: authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' - run: nix flake show - run: nix flake check --print-build-logs - - run: nix build --print-build-logs From 99b02a82fe1d30b80641a94adfea5fe5012aa937 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BChlbacher?= Date: Sat, 22 Jun 2024 16:50:39 +0200 Subject: [PATCH 4/9] fixup! test(nix): add basic functionality testing infra --- checks/encrypted-multidev.sh | 3 +-- checks/encrypted-unlock.sh | 4 +--- checks/outputs.sh | 3 +-- checks/subvolume.sh | 3 +-- 4 files changed, 4 insertions(+), 9 deletions(-) diff --git a/checks/encrypted-multidev.sh b/checks/encrypted-multidev.sh index bcd092e25..6899d0f27 100755 --- a/checks/encrypted-multidev.sh +++ b/checks/encrypted-multidev.sh @@ -2,7 +2,7 @@ set -euxo pipefail blkdev="/dev/vdb" -mnt="/tmp/mnt" +mnt=$(mktemp -d) pw=$(genpass) uuid=$(uuidgen) @@ -28,7 +28,6 @@ echo "$pw" | bcachefs format \ udevadm settle -mkdir -p "$mnt" echo "$pw" | bcachefs mount -v "UUID=$uuid" "$mnt" keyctl search @u user "bcachefs:$uuid" diff --git a/checks/encrypted-unlock.sh b/checks/encrypted-unlock.sh index 4f319adc7..960744f3f 100755 --- a/checks/encrypted-unlock.sh +++ b/checks/encrypted-unlock.sh @@ -2,7 +2,7 @@ set -euxo pipefail blkdev="/dev/vdb" -mnt="/tmp/mnt" +mnt=$(mktemp -d) pw=$(genpass) uuid=$(uuidgen) @@ -18,8 +18,6 @@ echo "$pw" | bcachefs format \ udevadm settle -mkdir -p "$mnt" - bcachefs unlock -c "$blkdev" echo "$pw" | bcachefs unlock "$blkdev" diff --git a/checks/outputs.sh b/checks/outputs.sh index 91d51f282..c4e551270 100755 --- a/checks/outputs.sh +++ b/checks/outputs.sh @@ -2,7 +2,7 @@ set -euxo pipefail blkdev="/dev/vdb" -mnt="/tmp/mnt" +mnt=$(mktemp -d) uuid=$(uuidgen) bcachefs format \ @@ -13,7 +13,6 @@ bcachefs format \ udevadm settle -mkdir -p "$mnt" mount "$blkdev" "$mnt" bcachefs show-super "$blkdev" | grep -i "external.*$uuid" diff --git a/checks/subvolume.sh b/checks/subvolume.sh index 620bbe811..179554ef6 100755 --- a/checks/subvolume.sh +++ b/checks/subvolume.sh @@ -2,7 +2,7 @@ set -euxo pipefail blkdev="/dev/vdb" -mnt="/tmp/mnt" +mnt=$(mktemp -d) uuid=$(uuidgen) bcachefs format \ @@ -13,7 +13,6 @@ bcachefs format \ udevadm settle -mkdir -p "$mnt" mount "$blkdev" "$mnt" touch "$mnt/file1" From 9d000957eb46de020dbd78d8ddbc77a032e9d0d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BChlbacher?= Date: Mon, 24 Jun 2024 20:12:11 +0200 Subject: [PATCH 5/9] fixup! test(nix): add basic functionality testing infra --- checks/default.nix | 1 + checks/nested.sh | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100755 checks/nested.sh diff --git a/checks/default.nix b/checks/default.nix index 5a85d1e69..b014687ba 100644 --- a/checks/default.nix +++ b/checks/default.nix @@ -29,6 +29,7 @@ let # Add any packages you need inside test scripts here environment.systemPackages = with pkgs; [ + f3 genpass keyutils ]; diff --git a/checks/nested.sh b/checks/nested.sh new file mode 100755 index 000000000..20cb58a3f --- /dev/null +++ b/checks/nested.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +set -euxo pipefail + +blkdev="/dev/vdb" +mnt1=$(mktemp -d) +mnt2=$(mktemp -d) +pw=$(genpass) +uuid=$(uuidgen) + +# link user and session keyrings so that the key can be found by the kernel +keyctl link @u @s + +echo "$pw" | bcachefs format \ + --verbose \ + --encrypted \ + --uuid "$uuid" \ + --fs_label test-fs \ + "$blkdev" + +udevadm settle + +echo "$pw" | bcachefs mount -v "UUID=$uuid" "$mnt1" + +fallocate --length 2G "$mnt1/fs.img" + +bcachefs format \ + --verbose \ + "$mnt1/fs.img" + +loopdev=$(losetup --find --show "$mnt1/fs.img") + +udevadm settle + +mount "$loopdev" "$mnt2" + +f3write "$mnt1" +f3write "$mnt2" + +f3read "$mnt1" +f3read "$mnt2" From 31d031ba1e376095e1903e0d988aded276620b01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BChlbacher?= Date: Mon, 24 Jun 2024 20:12:26 +0200 Subject: [PATCH 6/9] fixup! test(nix): add basic functionality testing infra --- checks/encrypted-multidev.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/checks/encrypted-multidev.sh b/checks/encrypted-multidev.sh index 6899d0f27..c6f4426db 100755 --- a/checks/encrypted-multidev.sh +++ b/checks/encrypted-multidev.sh @@ -31,3 +31,7 @@ udevadm settle echo "$pw" | bcachefs mount -v "UUID=$uuid" "$mnt" keyctl search @u user "bcachefs:$uuid" + +umount "$mnt" + +bcachefs mount -v "${blkdev}1" "$mnt" From 77e90e74bca1cc7f9eb09fe7552e9589d43faf86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BChlbacher?= Date: Wed, 26 Jun 2024 19:27:02 +0200 Subject: [PATCH 7/9] fixup! test(nix): add basic functionality testing infra --- checks/encrypted-unlock.sh | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/checks/encrypted-unlock.sh b/checks/encrypted-unlock.sh index 960744f3f..9a85e2e88 100755 --- a/checks/encrypted-unlock.sh +++ b/checks/encrypted-unlock.sh @@ -35,3 +35,21 @@ mount -t bcachefs "$blkdev" "$mnt" umount "$mnt" keyctl unlink "$key_id" + +bcachefs mount -v -f <(echo "$pw") "$blkdev" "$mnt" +key_id=$(keyctl search @u user "bcachefs:$uuid") +umount "$mnt" +keyctl unlink "$key_id" + +echo "$pw" | bcachefs mount -v -k stdin "$blkdev" "$mnt" +key_id=$(keyctl search @u user "bcachefs:$uuid") +umount "$mnt" +keyctl unlink "$key_id" + +echo "$pw" | bcachefs mount -v "$blkdev" "$mnt" +key_id=$(keyctl search @u user "bcachefs:$uuid") +umount "$mnt" +bcachefs mount -v -k fail "$blkdev" +bcachefs mount -v -k wait "$blkdev" "$mnt" +umount "$mnt" +keyctl unlink "$key_id" From 65f1c3f52a1ef6516f2ddb70a8f4bae58c87c3de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BChlbacher?= Date: Thu, 27 Jun 2024 16:30:15 +0200 Subject: [PATCH 8/9] fixup! test(nix): add basic functionality testing infra --- checks/default.nix | 1 + checks/encrypted-multidev.sh | 4 ++-- checks/encrypted-unlock.sh | 12 ++++++------ checks/nested.sh | 2 +- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/checks/default.nix b/checks/default.nix index b014687ba..7f535f80a 100644 --- a/checks/default.nix +++ b/checks/default.nix @@ -35,6 +35,7 @@ let ]; environment.variables = { + BCACHEFS_LOG = "trace"; RUST_BACKTRACE = "full"; }; }; diff --git a/checks/encrypted-multidev.sh b/checks/encrypted-multidev.sh index c6f4426db..d4e5c9ff3 100755 --- a/checks/encrypted-multidev.sh +++ b/checks/encrypted-multidev.sh @@ -28,10 +28,10 @@ echo "$pw" | bcachefs format \ udevadm settle -echo "$pw" | bcachefs mount -v "UUID=$uuid" "$mnt" +echo "$pw" | bcachefs mount "UUID=$uuid" "$mnt" keyctl search @u user "bcachefs:$uuid" umount "$mnt" -bcachefs mount -v "${blkdev}1" "$mnt" +bcachefs mount "${blkdev}1" "$mnt" diff --git a/checks/encrypted-unlock.sh b/checks/encrypted-unlock.sh index 9a85e2e88..23a345bb4 100755 --- a/checks/encrypted-unlock.sh +++ b/checks/encrypted-unlock.sh @@ -23,7 +23,7 @@ bcachefs unlock -c "$blkdev" echo "$pw" | bcachefs unlock "$blkdev" key_id=$(keyctl search @u user "bcachefs:$uuid") -bcachefs mount -v "$blkdev" "$mnt" +bcachefs mount "$blkdev" "$mnt" umount "$mnt" keyctl unlink "$key_id" @@ -36,20 +36,20 @@ umount "$mnt" keyctl unlink "$key_id" -bcachefs mount -v -f <(echo "$pw") "$blkdev" "$mnt" +bcachefs mount -f <(echo "$pw") "$blkdev" "$mnt" key_id=$(keyctl search @u user "bcachefs:$uuid") umount "$mnt" keyctl unlink "$key_id" -echo "$pw" | bcachefs mount -v -k stdin "$blkdev" "$mnt" +echo "$pw" | bcachefs mount -k stdin "$blkdev" "$mnt" key_id=$(keyctl search @u user "bcachefs:$uuid") umount "$mnt" keyctl unlink "$key_id" -echo "$pw" | bcachefs mount -v "$blkdev" "$mnt" +echo "$pw" | bcachefs mount "$blkdev" "$mnt" key_id=$(keyctl search @u user "bcachefs:$uuid") umount "$mnt" -bcachefs mount -v -k fail "$blkdev" -bcachefs mount -v -k wait "$blkdev" "$mnt" +bcachefs mount -k fail "$blkdev" +bcachefs mount -k wait "$blkdev" "$mnt" umount "$mnt" keyctl unlink "$key_id" diff --git a/checks/nested.sh b/checks/nested.sh index 20cb58a3f..edb955c11 100755 --- a/checks/nested.sh +++ b/checks/nested.sh @@ -19,7 +19,7 @@ echo "$pw" | bcachefs format \ udevadm settle -echo "$pw" | bcachefs mount -v "UUID=$uuid" "$mnt1" +echo "$pw" | bcachefs mount "UUID=$uuid" "$mnt1" fallocate --length 2G "$mnt1/fs.img" From 0e0be9baa62bc680533fc2af392a11ab8dbee9ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BChlbacher?= Date: Sun, 30 Jun 2024 12:54:26 +0200 Subject: [PATCH 9/9] test: add failing sub-test w/ dev added post mkfs The second mount works if the device is already part of the `bcachefs format` but fails if it's added afterwards. In particular the `blkid` output is interesting. --- checks/default.nix | 5 ++++- checks/encrypted-multidev.sh | 12 ++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/checks/default.nix b/checks/default.nix index 7f535f80a..425814333 100644 --- a/checks/default.nix +++ b/checks/default.nix @@ -23,7 +23,10 @@ let nodes.machine = { pkgs, ... }: { - virtualisation.emptyDiskImages = [ 4096 ]; + virtualisation.emptyDiskImages = [ + 4096 + 1024 + ]; boot.supportedFilesystems = [ "bcachefs" ]; boot.kernelPackages = pkgs.linuxPackages_latest; diff --git a/checks/encrypted-multidev.sh b/checks/encrypted-multidev.sh index d4e5c9ff3..3048d61ee 100755 --- a/checks/encrypted-multidev.sh +++ b/checks/encrypted-multidev.sh @@ -2,6 +2,7 @@ set -euxo pipefail blkdev="/dev/vdb" +blkdev2="/dev/vdc" mnt=$(mktemp -d) pw=$(genpass) uuid=$(uuidgen) @@ -24,14 +25,21 @@ echo "$pw" | bcachefs format \ --replicas=2 \ --uuid "$uuid" \ --fs_label test-fs \ - "$blkdev"? + "${blkdev}"{1,2} udevadm settle echo "$pw" | bcachefs mount "UUID=$uuid" "$mnt" +bcachefs device add "$mnt" "${blkdev}3" +bcachefs device add "$mnt" "$blkdev2" + +udevadm settle + +blkid + keyctl search @u user "bcachefs:$uuid" umount "$mnt" -bcachefs mount "${blkdev}1" "$mnt" +bcachefs mount "UUID=$uuid" "$mnt"