about summary refs log tree commit diff
path: root/nixos/tests/mtp.nix
blob: 8f0835d75d3fea5e55c94ccf8c70883921d6bcf8 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
import ./make-test-python.nix ({ pkgs, ... }: {
  name = "mtp";
  meta = with pkgs.lib.maintainers; {
    maintainers = [ matthewcroughan nixinator ];
  };

  nodes =
  {
    client = { config, pkgs, ... }: {
      # DBUS runs only once a user session is created, which means a user has to
      # login. Here, we log in as root. Once logged in, the gvfs-daemon service runs
      # as UID 0 in User-0.service
      services.getty.autologinUser = "root";

      # XDG_RUNTIME_DIR is needed for running systemd-user services such as
      # gvfs-daemon as root.
      environment.variables.XDG_RUNTIME_DIR = "/run/user/0";

      environment.systemPackages = with pkgs; [ usbutils glib jmtpfs tree ];
      services.gvfs.enable = true;

      # Creates a usb-mtp device inside the VM, which is mapped to the host's
      # /tmp folder, it is able to write files to this location, but only has
      # permissions to read its own creations.
      virtualisation.qemu.options = [
        "-usb"
        "-device usb-mtp,rootdir=/tmp,readonly=false"
      ];
    };
  };


  testScript = { nodes, ... }:
    let
      # Creates a list of QEMU MTP devices matching USB ID (46f4:0004). This
      # value can be sourced in a shell script. This is so we can loop over the
      # devices we find, as this test may want to use more than one MTP device
      # in future.
      mtpDevices = pkgs.writeScript "mtpDevices.sh" ''
        export mtpDevices=$(lsusb -d 46f4:0004 | awk {'print $2","$4'} | sed 's/[:-]/ /g')
      '';
      # Qemu is only capable of creating an MTP device with Picture Transfer
      # Protocol. This means that gvfs must use gphoto2:// rather than mtp://
      # when mounting.
      # https://github.com/qemu/qemu/blob/970bc16f60937bcfd334f14c614bd4407c247961/hw/usb/dev-mtp.c#L278
      gvfs = rec {
        mountAllMtpDevices = pkgs.writeScript "mountAllMtpDevices.sh" ''
          set -e
          source ${mtpDevices}
          for i in $mtpDevices
          do
            gio mount "gphoto2://[usb:$i]/"
          done
        '';
        unmountAllMtpDevices = pkgs.writeScript "unmountAllMtpDevices.sh" ''
          set -e
          source ${mtpDevices}
          for i in $mtpDevices
          do
            gio mount -u "gphoto2://[usb:$i]/"
          done
        '';
        # gvfsTest:
        # 1. Creates a 10M test file
        # 2. Copies it to the device using GIO tools
        # 3. Checks for corruption with `diff`
        # 4. Removes the file, then unmounts the disks.
        gvfsTest = pkgs.writeScript "gvfsTest.sh" ''
          set -e
          source ${mtpDevices}
          ${mountAllMtpDevices}
          dd if=/dev/urandom of=testFile10M bs=1M count=10
          for i in $mtpDevices
          do
            gio copy ./testFile10M gphoto2://[usb:$i]/
            ls -lah /run/user/0/gvfs/*/testFile10M
            gio remove gphoto2://[usb:$i]/testFile10M
          done
          ${unmountAllMtpDevices}
        '';
      };
      jmtpfs = {
        # jmtpfsTest:
        # 1. Mounts the device on a dir named `phone` using jmtpfs
        # 2. Puts the current Nixpkgs libmtp version into a file
        # 3. Checks for corruption with `diff`
        # 4. Prints the directory tree
        jmtpfsTest = pkgs.writeScript "jmtpfsTest.sh" ''
          set -e
          mkdir phone
          jmtpfs phone
          echo "${pkgs.libmtp.version}" > phone/tmp/testFile
          echo "${pkgs.libmtp.version}" > testFile
          diff phone/tmp/testFile testFile
          tree phone
        '';
      };
    in
    # Using >&2 allows the results of the scripts to be printed to the terminal
    # when building this test with Nix. Scripts would otherwise complete
    # silently.
    ''
    start_all()
    client.wait_for_unit("multi-user.target")
    client.wait_for_unit("dbus.service")
    client.succeed("${gvfs.gvfsTest} >&2")
    client.succeed("${jmtpfs.jmtpfsTest} >&2")
  '';
})