diff --git a/overlays.nix b/overlays.nix index faf7429..4139094 100644 --- a/overlays.nix +++ b/overlays.nix @@ -43,4 +43,40 @@ final: prev: { } ); }; + + list-usb-drives = prev.writeShellApplication { + name = "list-usb-drives"; + runtimeInputs = with prev; [ + findutils + gawk + coreutils + gnugrep + util-linux + ]; + + excludeShellChecks = [ + "SC2086" + "SC2157" + "SC2155" + ]; + + text = '' + # Allow overriding the disk-by-id directory for testing + DISK_BY_ID_DIR="''${LIST_USB_DRIVES_DISK_DIR:-/dev/disk/by-id}" + + # Mock lsblk for testing + if [ -n "''${LIST_USB_DRIVES_TEST_MODE:-}" ]; then + lsblk() { + echo "''$LIST_USB_DRIVES_MOCK_DATA" | tr '|' '\n' | while IFS=: read -r pattern response; do + case "$(basename "$3")" in *"$pattern"*) echo "$response"; return ;; esac + done || echo "UNKNOWN_MODEL UNKNOWN_SERIAL" + } + fi + + # Scan for USB devices in the specified directory + if [ -d "$DISK_BY_ID_DIR" ]; then + find "$DISK_BY_ID_DIR" -name "usb*" | grep -v "part[0-9]\$" | while read -r drive; do lsblk -no model,serial "$drive" | head -n1 | tr -d '\n' | tr " " "_" && echo -e " $(echo \"$drive\" | cut -d':' -f2-)"; done | column -t --table-columns=DRIVE,BAY | sort -n -k 2 + fi + ''; + }; } diff --git a/tests/list-usb-drives.nix b/tests/list-usb-drives.nix new file mode 100644 index 0000000..7b9f4f1 --- /dev/null +++ b/tests/list-usb-drives.nix @@ -0,0 +1,46 @@ +{ + config, + lib, + pkgs, + inputs, + ... +}: +let + # Create pkgs with list-usb-drives overlay + testPkgs = import inputs.nixpkgs { + system = pkgs.system; + overlays = [ (import ../overlays.nix) ]; + }; +in +testPkgs.testers.runNixOSTest { + name = "list-usb-drives test"; + + nodes.machine = + { pkgs, ... }: + { + environment.systemPackages = [ + testPkgs.list-usb-drives + ]; + }; + + testScript = '' + start_all() + machine.wait_for_unit("multi-user.target") + + # Create mock USB device symlinks + machine.succeed("mkdir -p /tmp/mock-by-id") + machine.succeed("touch /tmp/mock-by-id/usb-drive1-0:0") + machine.succeed("touch /tmp/mock-by-id/usb-drive2-0:1") + machine.succeed("touch /tmp/mock-by-id/usb-drive1-0:0-part1") # Should be filtered out + + # Test with mock data + mock_data = "drive1:Model1 Serial1|drive2:Model2 Serial2" + output = machine.succeed(f"LIST_USB_DRIVES_DISK_DIR=/tmp/mock-by-id LIST_USB_DRIVES_TEST_MODE=1 LIST_USB_DRIVES_MOCK_DATA='{mock_data}' list-usb-drives") + + # Expected exact output + expected = 'DRIVE BAY\nModel1_Serial1 0"\nModel2_Serial2 1"\n' + + assert output == expected + print("✓ Mock USB device test passed") + ''; +} diff --git a/tests/tests.nix b/tests/tests.nix index e2b6e5e..2b6f125 100644 --- a/tests/tests.nix +++ b/tests/tests.nix @@ -11,4 +11,5 @@ in zfsTest = handleTest ./zfs.nix; testTest = handleTest ./testTest.nix; minecraftTest = handleTest ./minecraft.nix; + listUsbDrivesTest = handleTest ./list-usb-drives.nix; }