···11+import ./make-test-python.nix ({ pkgs, ... }: {
22+ name = "maestral";
33+ meta = with pkgs.lib.maintainers; {
44+ maintainers = [ peterhoeg ];
55+ };
66+77+ nodes =
88+ let
99+ common = attrs:
1010+ pkgs.lib.recursiveUpdate
1111+ {
1212+ imports = [ ./common/user-account.nix ];
1313+ systemd.user.services.maestral = {
1414+ description = "Maestral Dropbox Client";
1515+ serviceConfig.Type = "exec";
1616+ };
1717+ }
1818+ attrs;
1919+2020+ in
2121+ {
2222+ cli = { ... }: common {
2323+ systemd.user.services.maestral = {
2424+ wantedBy = [ "default.target" ];
2525+ serviceConfig.ExecStart = "${pkgs.maestral}/bin/maestral start --foreground";
2626+ };
2727+ };
2828+2929+ gui = { ... }: common {
3030+ services.xserver = {
3131+ enable = true;
3232+ displayManager.sddm.enable = true;
3333+ displayManager.defaultSession = "plasma";
3434+ desktopManager.plasma5.enable = true;
3535+ desktopManager.plasma5.runUsingSystemd = true;
3636+ displayManager.autoLogin = {
3737+ enable = true;
3838+ user = "alice";
3939+ };
4040+ };
4141+4242+ systemd.user.services = {
4343+ maestral = {
4444+ wantedBy = [ "graphical-session.target" ];
4545+ serviceConfig.ExecStart = "${pkgs.maestral-gui}/bin/maestral_qt";
4646+ };
4747+ # PowerDevil doesn't like our VM
4848+ plasma-powerdevil.enable = false;
4949+ };
5050+ };
5151+ };
5252+5353+ testScript = { nodes, ... }:
5454+ let
5555+ user = nodes.cli.config.users.users.alice;
5656+ in
5757+ ''
5858+ start_all()
5959+6060+ with subtest("CLI"):
6161+ # we need SOME way to give the user an active login session
6262+ cli.execute("loginctl enable-linger ${user.name}")
6363+ cli.systemctl("start user@${toString user.uid}")
6464+ cli.wait_for_unit("maestral.service", "${user.name}")
6565+6666+ with subtest("GUI"):
6767+ gui.wait_for_x()
6868+ gui.succeed("xauth merge ${user.home}/.Xauthority")
6969+ gui.wait_for_window("^Desktop ")
7070+ gui.wait_for_unit("maestral.service", "${user.name}")
7171+ '';
7272+})
+109
nixos/tests/mtp.nix
···11+import ./make-test-python.nix ({ pkgs, ... }: {
22+ name = "mtp";
33+ meta = with pkgs.lib.maintainers; {
44+ maintainers = [ matthewcroughan nixinator ];
55+ };
66+77+ nodes =
88+ {
99+ client = { config, pkgs, ... }: {
1010+ # DBUS runs only once a user session is created, which means a user has to
1111+ # login. Here, we log in as root. Once logged in, the gvfs-daemon service runs
1212+ # as UID 0 in User-0.service
1313+ services.getty.autologinUser = "root";
1414+1515+ # XDG_RUNTIME_DIR is needed for running systemd-user services such as
1616+ # gvfs-daemon as root.
1717+ environment.variables.XDG_RUNTIME_DIR = "/run/user/0";
1818+1919+ environment.systemPackages = with pkgs; [ usbutils glib jmtpfs tree ];
2020+ services.gvfs.enable = true;
2121+2222+ # Creates a usb-mtp device inside the VM, which is mapped to the host's
2323+ # /tmp folder, it is able to write files to this location, but only has
2424+ # permissions to read its own creations.
2525+ virtualisation.qemu.options = [
2626+ "-usb"
2727+ "-device usb-mtp,rootdir=/tmp,readonly=false"
2828+ ];
2929+ };
3030+ };
3131+3232+3333+ testScript = { nodes, ... }:
3434+ let
3535+ # Creates a list of QEMU MTP devices matching USB ID (46f4:0004). This
3636+ # value can be sourced in a shell script. This is so we can loop over the
3737+ # devices we find, as this test may want to use more than one MTP device
3838+ # in future.
3939+ mtpDevices = pkgs.writeScript "mtpDevices.sh" ''
4040+ export mtpDevices=$(lsusb -d 46f4:0004 | awk {'print $2","$4'} | sed 's/[:-]/ /g')
4141+ '';
4242+ # Qemu is only capable of creating an MTP device with Picture Transfer
4343+ # Protocol. This means that gvfs must use gphoto2:// rather than mtp://
4444+ # when mounting.
4545+ # https://github.com/qemu/qemu/blob/970bc16f60937bcfd334f14c614bd4407c247961/hw/usb/dev-mtp.c#L278
4646+ gvfs = rec {
4747+ mountAllMtpDevices = pkgs.writeScript "mountAllMtpDevices.sh" ''
4848+ set -e
4949+ source ${mtpDevices}
5050+ for i in $mtpDevices
5151+ do
5252+ gio mount "gphoto2://[usb:$i]/"
5353+ done
5454+ '';
5555+ unmountAllMtpDevices = pkgs.writeScript "unmountAllMtpDevices.sh" ''
5656+ set -e
5757+ source ${mtpDevices}
5858+ for i in $mtpDevices
5959+ do
6060+ gio mount -u "gphoto2://[usb:$i]/"
6161+ done
6262+ '';
6363+ # gvfsTest:
6464+ # 1. Creates a 10M test file
6565+ # 2. Copies it to the device using GIO tools
6666+ # 3. Checks for corruption with `diff`
6767+ # 4. Removes the file, then unmounts the disks.
6868+ gvfsTest = pkgs.writeScript "gvfsTest.sh" ''
6969+ set -e
7070+ source ${mtpDevices}
7171+ ${mountAllMtpDevices}
7272+ dd if=/dev/urandom of=testFile10M bs=1M count=10
7373+ for i in $mtpDevices
7474+ do
7575+ gio copy ./testFile10M gphoto2://[usb:$i]/
7676+ ls -lah /run/user/0/gvfs/*/testFile10M
7777+ gio remove gphoto2://[usb:$i]/testFile10M
7878+ done
7979+ ${unmountAllMtpDevices}
8080+ '';
8181+ };
8282+ jmtpfs = {
8383+ # jmtpfsTest:
8484+ # 1. Mounts the device on a dir named `phone` using jmtpfs
8585+ # 2. Puts the current Nixpkgs libmtp version into a file
8686+ # 3. Checks for corruption with `diff`
8787+ # 4. Prints the directory tree
8888+ jmtpfsTest = pkgs.writeScript "jmtpfsTest.sh" ''
8989+ set -e
9090+ mkdir phone
9191+ jmtpfs phone
9292+ echo "${pkgs.libmtp.version}" > phone/tmp/testFile
9393+ echo "${pkgs.libmtp.version}" > testFile
9494+ diff phone/tmp/testFile testFile
9595+ tree phone
9696+ '';
9797+ };
9898+ in
9999+ # Using >&2 allows the results of the scripts to be printed to the terminal
100100+ # when building this test with Nix. Scripts would otherwise complete
101101+ # silently.
102102+ ''
103103+ start_all()
104104+ client.wait_for_unit("multi-user.target")
105105+ client.wait_for_unit("dbus.service")
106106+ client.succeed("${gvfs.gvfsTest} >&2")
107107+ client.succeed("${jmtpfs.jmtpfsTest} >&2")
108108+ '';
109109+})
···102102 ./0090-pipewire-config-template-paths.patch
103103 # Place SPA data files in lib output to avoid dependency cycles
104104 ./0095-spa-data-dir.patch
105105+ # Fixes missing function declarations in pipewire headers
106106+ # Should be removed after the next release
107107+ (fetchpatch {
108108+ url = "https://gitlab.freedesktop.org/pipewire/pipewire/-/commit/a2e98e28c1e6fb58b273ef582398d8bee4d2b769.patch";
109109+ sha256 = "sha256-tqiiAW2fTEp23HT59XR2D/G08pVENJtpxUI7UVufj/A=";
110110+ })
105111 ];
106112107113 nativeBuildInputs = [