at 24.11-pre 5.5 kB view raw
1import ./make-test-python.nix ( 2{ pkgs, lib, ...}: 3{ 4 name = "gnome-extensions"; 5 meta.maintainers = [ ]; 6 7 nodes.machine = 8 { pkgs, ... }: 9 { 10 imports = [ ./common/user-account.nix ]; 11 12 # Install all extensions 13 environment.systemPackages = lib.filter (e: e ? extensionUuid) (lib.attrValues pkgs.gnomeExtensions); 14 15 # Some extensions are broken, but that's kind of the point of a testing VM 16 nixpkgs.config.allowBroken = true; 17 # There are some aliases which throw exceptions; ignore them. 18 # Also prevent duplicate extensions under different names. 19 nixpkgs.config.allowAliases = false; 20 21 # Configure GDM 22 services.xserver.enable = true; 23 services.xserver.displayManager = { 24 gdm = { 25 enable = true; 26 debug = true; 27 wayland = true; 28 }; 29 autoLogin = { 30 enable = true; 31 user = "alice"; 32 }; 33 }; 34 35 # Configure Gnome 36 services.xserver.desktopManager.gnome.enable = true; 37 services.xserver.desktopManager.gnome.debug = true; 38 39 systemd.user.services = { 40 "org.gnome.Shell@wayland" = { 41 serviceConfig = { 42 ExecStart = [ 43 # Clear the list before overriding it. 44 "" 45 # Eval API is now internal so Shell needs to run in unsafe mode. 46 # TODO: improve test driver so that it supports openqa-like manipulation 47 # that would allow us to drop this mess. 48 "${pkgs.gnome.gnome-shell}/bin/gnome-shell --unsafe-mode" 49 ]; 50 }; 51 }; 52 }; 53 54 }; 55 56 testScript = { nodes, ... }: let 57 # Keep line widths somewhat manageable 58 user = nodes.machine.users.users.alice; 59 uid = toString user.uid; 60 bus = "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/${uid}/bus"; 61 # Run a command in the appropriate user environment 62 run = command: "su - ${user.name} -c '${bus} ${command}'"; 63 64 # Call javascript in gnome shell, returns a tuple (success, output), where 65 # `success` is true if the dbus call was successful and output is what the 66 # javascript evaluates to. 67 eval = command: run "gdbus call --session -d org.gnome.Shell -o /org/gnome/Shell -m org.gnome.Shell.Eval ${command}"; 68 69 # False when startup is done 70 startingUp = eval "Main.layoutManager._startingUp"; 71 72 # Extensions to keep always enabled together 73 # Those are extensions that are usually always on for many users, and that we expect to work 74 # well together with most others without conflicts 75 alwaysOnExtensions = map (name: pkgs.gnomeExtensions.${name}.extensionUuid) [ 76 "applications-menu" 77 "user-themes" 78 ]; 79 80 # Extensions to enable and disable individually 81 # Extensions like dash-to-dock and dash-to-panel cannot be enabled at the same time. 82 testExtensions = map (name: pkgs.gnomeExtensions.${name}.extensionUuid) [ 83 "appindicator" 84 "dash-to-dock" 85 "dash-to-panel" 86 "ddterm" 87 "emoji-selector" 88 "gsconnect" 89 "system-monitor-next" 90 "desktop-icons-ng-ding" 91 "workspace-indicator" 92 "vitals" 93 ]; 94 in 95 '' 96 with subtest("Login to GNOME with GDM"): 97 # wait for gdm to start 98 machine.wait_for_unit("display-manager.service") 99 # wait for the wayland server 100 machine.wait_for_file("/run/user/${uid}/wayland-0") 101 # wait for alice to be logged in 102 machine.wait_for_unit("default.target", "${user.name}") 103 # check that logging in has given the user ownership of devices 104 assert "alice" in machine.succeed("getfacl -p /dev/snd/timer") 105 106 with subtest("Wait for GNOME Shell"): 107 # correct output should be (true, 'false') 108 machine.wait_until_succeeds( 109 "${startingUp} | grep -q 'true,..false'" 110 ) 111 112 # Close the Activities view so that Shell can correctly track the focused window. 113 machine.send_key("esc") 114 # # Disable extension version validation (only use for manual testing) 115 # machine.succeed( 116 # "${run "gsettings set org.gnome.shell disable-extension-version-validation true"}" 117 # ) 118 119 # Assert that some extension is in a specific state 120 def checkState(target, extension): 121 state = machine.succeed( 122 f"${run "gnome-extensions info {extension}"} | grep '^ State: .*$'" 123 ) 124 assert target in state, f"{state} instead of {target}" 125 126 def checkExtension(extension, disable): 127 with subtest(f"Enable extension '{extension}'"): 128 # Check that the extension is properly initialized; skip out of date ones 129 state = machine.succeed( 130 f"${run "gnome-extensions info {extension}"} | grep '^ State: .*$'" 131 ) 132 if "OUT OF DATE" in state: 133 machine.log(f"Extension {extension} will be skipped because out of date") 134 return 135 136 assert "INITIALIZED" in state, f"{state} instead of INITIALIZED" 137 138 # Enable and optionally disable 139 140 machine.succeed(f"${run "gnome-extensions enable {extension}"}") 141 checkState("ENABLED", extension) 142 143 if disable: 144 machine.succeed(f"${run "gnome-extensions disable {extension}"}") 145 checkState("DISABLED", extension) 146 '' 147 + lib.concatLines (map (e: ''checkExtension("${e}", False)'') alwaysOnExtensions) 148 + lib.concatLines (map (e: ''checkExtension("${e}", True)'') testExtensions) 149 ; 150} 151)