mirror of
https://github.com/NixOS/nixpkgs.git
synced 2026-07-06 17:13:24 -05:00
[Backport release-26.05] nixosTests/cosmic: move core logic into a dedicated script (#535620)
This commit is contained in:
commit
bc26245eca
5 changed files with 528 additions and 151 deletions
|
|
@ -407,25 +407,25 @@ in
|
|||
corerad = runTest ./corerad.nix;
|
||||
corteza = runTest ./corteza.nix;
|
||||
cosmic = runTest {
|
||||
imports = [ ./cosmic.nix ];
|
||||
imports = [ ./cosmic ];
|
||||
_module.args.testName = "cosmic";
|
||||
_module.args.enableAutologin = false;
|
||||
_module.args.enableXWayland = true;
|
||||
};
|
||||
cosmic-autologin = runTest {
|
||||
imports = [ ./cosmic.nix ];
|
||||
imports = [ ./cosmic ];
|
||||
_module.args.testName = "cosmic-autologin";
|
||||
_module.args.enableAutologin = true;
|
||||
_module.args.enableXWayland = true;
|
||||
};
|
||||
cosmic-autologin-noxwayland = runTest {
|
||||
imports = [ ./cosmic.nix ];
|
||||
imports = [ ./cosmic ];
|
||||
_module.args.testName = "cosmic-autologin-noxwayland";
|
||||
_module.args.enableAutologin = true;
|
||||
_module.args.enableXWayland = false;
|
||||
};
|
||||
cosmic-noxwayland = runTest {
|
||||
imports = [ ./cosmic.nix ];
|
||||
imports = [ ./cosmic ];
|
||||
_module.args.testName = "cosmic-noxwayland";
|
||||
_module.args.enableAutologin = false;
|
||||
_module.args.enableXWayland = false;
|
||||
|
|
|
|||
|
|
@ -1,147 +0,0 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
testName,
|
||||
enableAutologin,
|
||||
enableXWayland,
|
||||
...
|
||||
}:
|
||||
|
||||
{
|
||||
name = testName;
|
||||
|
||||
meta.maintainers = lib.teams.cosmic.members;
|
||||
|
||||
nodes.machine = {
|
||||
imports = [ ./common/user-account.nix ];
|
||||
|
||||
services = {
|
||||
# For `cosmic-store` to be added to `environment.systemPackages`
|
||||
# and for it to work correctly because Flatpak is a runtime
|
||||
# dependency of `cosmic-store`.
|
||||
flatpak.enable = true;
|
||||
|
||||
displayManager.cosmic-greeter.enable = true;
|
||||
desktopManager.cosmic = {
|
||||
enable = true;
|
||||
xwayland.enable = enableXWayland;
|
||||
};
|
||||
};
|
||||
|
||||
services.displayManager.autoLogin = lib.mkIf enableAutologin {
|
||||
enable = true;
|
||||
user = "alice";
|
||||
};
|
||||
|
||||
environment.systemPackages = with config.node.pkgs; [
|
||||
# These two packages are used to check if a window was opened
|
||||
# under the COSMIC session or not. Kinda important.
|
||||
# TODO: Move the check from the test module to
|
||||
# `nixos/lib/test-driver/src/test_driver/machine.py` so more
|
||||
# Wayland-only testing can be done using the existing testing
|
||||
# infrastructure.
|
||||
jq
|
||||
lswt
|
||||
];
|
||||
|
||||
# So far, all COSMIC tests launch a few GUI applications. In doing
|
||||
# so, the default allocated memory to the guest of 1024M quickly
|
||||
# poses a very high risk of an OOM-shutdown which is worse than an
|
||||
# OOM-kill. Because now, the test failed, but not for a genuine
|
||||
# reason, but an OOM-shutdown. That's an inconclusive failure
|
||||
# which might possibly mask an actual failure. Not enabling
|
||||
# systemd-oomd because we need said applications running for a
|
||||
# few seconds. So instead, bump the allocated memory to the guest
|
||||
# from 1024M to 4x; 4096M.
|
||||
virtualisation.memorySize = 4096;
|
||||
};
|
||||
|
||||
testScript =
|
||||
{ nodes, ... }:
|
||||
let
|
||||
cfg = nodes.machine;
|
||||
user = cfg.users.users.alice;
|
||||
DISPLAY = lib.strings.optionalString enableXWayland (
|
||||
if enableAutologin then "DISPLAY=:0" else "DISPLAY=:1"
|
||||
);
|
||||
emptyPDF = config.node.pkgs.stdenvNoCC.mkDerivation {
|
||||
name = "empty-pdf";
|
||||
dontUnpack = true;
|
||||
nativeBuildInputs = [ config.node.pkgs.imagemagick ];
|
||||
buildPhase = ''
|
||||
magick xc:none -page Letter empty.pdf
|
||||
'';
|
||||
installPhase = ''
|
||||
mkdir $out
|
||||
mv empty.pdf $out/empty.pdf
|
||||
'';
|
||||
};
|
||||
in
|
||||
''
|
||||
#testName: ${testName}
|
||||
''
|
||||
+ (
|
||||
if enableAutologin then
|
||||
''
|
||||
with subtest("cosmic-greeter initialisation"):
|
||||
machine.wait_for_unit("graphical.target", timeout=120)
|
||||
''
|
||||
else
|
||||
''
|
||||
from time import sleep
|
||||
|
||||
machine.wait_for_unit("graphical.target", timeout=120)
|
||||
machine.wait_until_succeeds("pgrep --uid ${toString cfg.users.users.cosmic-greeter.name} --full cosmic-greeter", timeout=30)
|
||||
# Sleep for 10 seconds for ensuring that `greetd` loads the
|
||||
# password prompt for the login screen properly.
|
||||
sleep(10)
|
||||
|
||||
with subtest("cosmic-session login"):
|
||||
machine.send_chars("${user.password}\n", delay=0.2)
|
||||
''
|
||||
)
|
||||
+ ''
|
||||
# _One_ of the final processes to start as part of the
|
||||
# `cosmic-session` target is the Workspaces applet. So, wait
|
||||
# for it to start. The process existing means that COSMIC
|
||||
# now handles any opened windows from now on.
|
||||
machine.wait_until_succeeds("pgrep --uid ${toString user.uid} --full 'cosmic-panel-button com.system76.CosmicWorkspaces'", timeout=30)
|
||||
|
||||
# The best way to test for Wayland and XWayland is to launch
|
||||
# the GUI applications and see the results yourself.
|
||||
with subtest("Launch applications"):
|
||||
# key: binary_name
|
||||
# value: "app-id" as reported by `lswt`
|
||||
gui_apps_to_launch = {}
|
||||
|
||||
# We want to ensure that the first-party applications
|
||||
# start/launch properly.
|
||||
gui_apps_to_launch['cosmic-edit'] = 'com.system76.CosmicEdit'
|
||||
gui_apps_to_launch['cosmic-files'] = 'com.system76.CosmicFiles'
|
||||
gui_apps_to_launch['cosmic-player'] = 'com.system76.CosmicPlayer'
|
||||
gui_apps_to_launch['cosmic-reader'] = 'com.system76.CosmicReader'
|
||||
gui_apps_to_launch['cosmic-settings'] = 'com.system76.CosmicSettings'
|
||||
gui_apps_to_launch['cosmic-store'] = 'com.system76.CosmicStore'
|
||||
gui_apps_to_launch['cosmic-term'] = 'com.system76.CosmicTerm'
|
||||
|
||||
for gui_app, app_id in gui_apps_to_launch.items():
|
||||
# Don't fail the test if binary is absent
|
||||
if machine.execute(f"su - ${user.name} -c 'command -v {gui_app}'", timeout=5)[0] == 0:
|
||||
match gui_app:
|
||||
case 'cosmic-reader':
|
||||
opt_arg = '${emptyPDF}/empty.pdf'
|
||||
case _:
|
||||
opt_arg = ""
|
||||
|
||||
machine.succeed(f"su - ${user.name} -c 'WAYLAND_DISPLAY=wayland-1 XDG_RUNTIME_DIR=/run/user/${toString user.uid} ${DISPLAY} {gui_app} {opt_arg} >&2 &'", timeout=5)
|
||||
# Nix builds the following non-commented expression to the following:
|
||||
# `su - alice -c 'WAYLAND_DISPLAY=wayland-1 XDG_RUNTIME_DIR=/run/user/1000 lswt --json | jq ".toplevels" | grep "^ \\"app-id\\": \\"{app_id}\\"$"' `
|
||||
machine.wait_until_succeeds(f''''su - ${user.name} -c 'WAYLAND_DISPLAY=wayland-1 XDG_RUNTIME_DIR=/run/user/${toString user.uid} lswt --json | jq ".toplevels" | grep "^ \\"app-id\\": \\"{app_id}\\"$"' '''', timeout=60)
|
||||
machine.succeed(f"pkill {gui_app}", timeout=5)
|
||||
|
||||
machine.succeed("echo 'test completed succeessfully' > /${testName}", timeout=5)
|
||||
machine.copy_from_machine('/${testName}')
|
||||
|
||||
machine.shutdown()
|
||||
'';
|
||||
}
|
||||
168
nixos/tests/cosmic/default.nix
Normal file
168
nixos/tests/cosmic/default.nix
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
testName,
|
||||
enableAutologin,
|
||||
enableXWayland,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
user = config.nodes.machine.users.users.alice;
|
||||
logFilePath = "/home/${user.name}/${testName}";
|
||||
# Use `writeShellScriptBin` instead of `writeShellScript` so that the
|
||||
# process name in the journald log appears as 'cosmicTest[$pid]'
|
||||
cosmicTest = config.node.pkgs.writeShellScriptBin "cosmicTest" ''
|
||||
exec ${lib.getExe config.node.pkgs.python3Minimal} ${./test-script.py} \
|
||||
--log-file-path ${logFilePath} \
|
||||
--cosmic-reader-pdf ${config.node.pkgs.empty-pdf} \
|
||||
--polkit-agent-helper-path ${config.node.pkgs.polkit.out}/lib/polkit-1/polkit-agent-helper-1 \
|
||||
--root-user-password ${user.password}
|
||||
'';
|
||||
cosmicTestDesktop = config.node.pkgs.makeDesktopItem {
|
||||
name = "cosmicTest";
|
||||
desktopName = "COSMIC NixOS VM test (${testName})";
|
||||
exec = "cosmicTest";
|
||||
};
|
||||
cosmicTestAutostartItem = config.node.pkgs.makeAutostartItem {
|
||||
name = "cosmicTest";
|
||||
package = cosmicTestDesktop;
|
||||
};
|
||||
in
|
||||
|
||||
{
|
||||
name = testName;
|
||||
|
||||
meta.maintainers = lib.teams.cosmic.members;
|
||||
|
||||
nodes.machine = {
|
||||
imports = [ ../common/user-account.nix ];
|
||||
|
||||
services = {
|
||||
# For `cosmic-store` to be added to `environment.systemPackages`
|
||||
# and for it to work correctly because Flatpak is a runtime
|
||||
# dependency of `cosmic-store`.
|
||||
flatpak.enable = true;
|
||||
|
||||
displayManager.cosmic-greeter.enable = true;
|
||||
desktopManager.cosmic = {
|
||||
enable = true;
|
||||
xwayland.enable = enableXWayland;
|
||||
};
|
||||
};
|
||||
|
||||
services.displayManager.autoLogin = lib.mkIf enableAutologin {
|
||||
enable = true;
|
||||
user = user.name;
|
||||
};
|
||||
|
||||
users.users = {
|
||||
alice.extraGroups = [
|
||||
"uinput" # for ydotoold
|
||||
];
|
||||
|
||||
root.password = user.password;
|
||||
root.hashedPasswordFile = lib.mkForce null;
|
||||
};
|
||||
|
||||
hardware.uinput.enable = true;
|
||||
|
||||
environment.systemPackages = with config.node.pkgs; [
|
||||
ydotool
|
||||
cosmicTest
|
||||
cosmicTestAutostartItem
|
||||
|
||||
# These two packages are used to check if a window was opened
|
||||
# under the COSMIC session or not. Kinda important.
|
||||
# TODO: Move the check from the test module to
|
||||
# `nixos/lib/test-driver/src/test_driver/machine.py` so more
|
||||
# Wayland-only testing can be done using the existing testing
|
||||
# infrastructure.
|
||||
jq
|
||||
lswt
|
||||
];
|
||||
|
||||
# So far, all COSMIC tests launch a few GUI applications. In doing
|
||||
# so, the default allocated memory to the guest of 1024M quickly
|
||||
# poses a very high risk of an OOM-shutdown which is worse than an
|
||||
# OOM-kill. Because now, the test failed, but not for a genuine
|
||||
# reason, but an OOM-shutdown. That's an inconclusive failure
|
||||
# which might possibly mask an actual failure. Not enabling
|
||||
# systemd-oomd because we need said applications running for a
|
||||
# few seconds. So instead, bump the allocated memory to the guest
|
||||
# from 1024M to 4x; 4096M.
|
||||
virtualisation.memorySize = 4096;
|
||||
};
|
||||
|
||||
testScript =
|
||||
{ nodes, ... }:
|
||||
''
|
||||
#testName: ${testName}
|
||||
import sys
|
||||
''
|
||||
+ (
|
||||
if enableAutologin then
|
||||
''
|
||||
with subtest("cosmic-greeter initialisation"):
|
||||
machine.wait_for_unit("graphical.target", timeout=120)
|
||||
''
|
||||
else
|
||||
''
|
||||
from time import sleep
|
||||
|
||||
machine.wait_for_unit("graphical.target", timeout=120)
|
||||
machine.wait_until_succeeds("pgrep --uid ${config.nodes.machine.users.users.cosmic-greeter.name} --full cosmic-greeter", timeout=30)
|
||||
# Sleep for 10 seconds for ensuring that `greetd` loads the
|
||||
# password prompt for the login screen properly.
|
||||
sleep(10)
|
||||
|
||||
with subtest("cosmic-session login"):
|
||||
machine.send_chars("${user.password}\n", delay=0.2)
|
||||
''
|
||||
)
|
||||
+ ''
|
||||
with subtest("xdg autostart support in cosmic"):
|
||||
# When checking the status of our `cosmicTest` package with:
|
||||
# `machine.wait_for_unit("app-cosmicTest@autostart.service", user="${user.name}")`
|
||||
# We are immediately greeted with the error:
|
||||
# ```
|
||||
# subtest: xdg autostart support in cosmic
|
||||
# machine: waiting for unit app-cosmicTest@autostart.service with user alice
|
||||
# machine # [ 26.497516] cosmic-comp[1352]: [EGL] 0x3008 (BAD_DISPLAY) eglCreateSync: _eglCreateSync
|
||||
# machine # [ 26.511706] su[1416]: Successful su for alice by root
|
||||
# machine # [ 26.528190] su[1416]: pam_unix(su:session): session opened for user alice(uid=1000) by (uid=0)
|
||||
# machine # Failed to connect to user scope bus via local transport: No such file or directory
|
||||
# machine # [ 26.599563] su[1416]: pam_unix(su:session): session closed for user alice
|
||||
# !!! Test "xdg autostart support in cosmic" failed with error: "retrieving systemctl property "ActiveState" for unit "app-cosmicTest@autostart.service" under user "alice" failed with exit code 1"
|
||||
# ```
|
||||
# Meaning, our session is extremely new and the D-Bus user
|
||||
# session socket does not yet exist. Instead, lets poll for
|
||||
# the log file that the test is guaranteed to write to, as
|
||||
# soon as it starts.
|
||||
machine.wait_for_file("${logFilePath}.log", timeout=120)
|
||||
|
||||
exit_code = 0
|
||||
try:
|
||||
machine.wait_for_file("${logFilePath}.done", timeout=700)
|
||||
except Exception:
|
||||
exit_code = 1
|
||||
|
||||
# The log file is created in the very beginning of the test
|
||||
# script's execution. If we are here, it means that the
|
||||
# `wait_for_unit`'s "guard" on the test script's autostart unit
|
||||
# plus the 630 second combined timeout of other two
|
||||
# `wait_for_file`s, make it extremely likely for the log file to
|
||||
# be present.
|
||||
machine.copy_from_machine("${logFilePath}.log")
|
||||
|
||||
machine.shutdown()
|
||||
|
||||
with open(f"{machine.out_dir}/${testName}.log") as test_log_file:
|
||||
contents = test_log_file.read()
|
||||
print(contents)
|
||||
if any("Z [ERROR] [L:" in line for line in contents.splitlines()):
|
||||
exit_code = 1
|
||||
|
||||
sys.exit(exit_code)
|
||||
'';
|
||||
}
|
||||
315
nixos/tests/cosmic/test-script.py
Normal file
315
nixos/tests/cosmic/test-script.py
Normal file
|
|
@ -0,0 +1,315 @@
|
|||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import logging
|
||||
import os
|
||||
import pathlib
|
||||
import subprocess
|
||||
import time
|
||||
|
||||
|
||||
def parse_cli_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
"--log-file-path",
|
||||
required=True,
|
||||
type=str,
|
||||
help="The path to the log file (without the '.log' suffix/extension)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--cosmic-reader-pdf",
|
||||
required=True,
|
||||
type=str,
|
||||
help="The PDF that the `cosmic-reader` should open for testing",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--polkit-agent-helper-path",
|
||||
required=True,
|
||||
type=str,
|
||||
help="The path to the polkit agent helper (`${pkgs.polkit.out}/lib/polkit-1/polkit-agent-helper-1`)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--root-user-password", required=True, type=str, help="The root user's password"
|
||||
)
|
||||
args = parser.parse_args()
|
||||
return args
|
||||
|
||||
|
||||
def start_ydotool_daemon() -> tuple[str, subprocess.Popen]:
|
||||
"""
|
||||
The ydotool requires a daemon to be running.
|
||||
"""
|
||||
xdg_runtime_dir = os.getenv("XDG_RUNTIME_DIR") or f"/run/user/{os.getuid()}"
|
||||
ydotool_daemon_socket_path = f"{xdg_runtime_dir}/.ydotool_socket"
|
||||
ydotool_daemon_process = subprocess.Popen(
|
||||
[
|
||||
"ydotoold",
|
||||
"--socket-path",
|
||||
ydotool_daemon_socket_path,
|
||||
"--mouse-off",
|
||||
],
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
)
|
||||
return ydotool_daemon_socket_path, ydotool_daemon_process
|
||||
|
||||
|
||||
def wait_for_cosmic_de_readiness() -> None:
|
||||
"""
|
||||
Wait for the COSMIC DE to be ready, before running the tests. This
|
||||
is done by waiting on the supposedly last component of the COSMIC
|
||||
DE to be "ready." That component is the notification watcher, of
|
||||
the `cosmic-applet` derivation.
|
||||
"""
|
||||
logging.info("=" * 80)
|
||||
logging.info("Waiting for COSMIC DE to complete initialization")
|
||||
|
||||
notification_watcher_wait_deadline = time.monotonic() + 360
|
||||
notification_watcher_exists = False
|
||||
while time.monotonic() < notification_watcher_wait_deadline:
|
||||
busctl_process = subprocess.run(
|
||||
["busctl", "--user", "status", "com.system76.CosmicStatusNotifierWatcher"],
|
||||
check=False,
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
)
|
||||
if busctl_process.returncode == 0:
|
||||
notification_watcher_exists = True
|
||||
break
|
||||
else:
|
||||
time.sleep(1)
|
||||
logging_msg = "The COSMIC DE is "
|
||||
if notification_watcher_exists:
|
||||
logging.info(f"{logging_msg} ready")
|
||||
else:
|
||||
logging.error(f"{logging_msg} not ready")
|
||||
return
|
||||
|
||||
|
||||
def perform_polkit_authentication_test(
|
||||
cli_args: argparse.Namespace,
|
||||
ydotool_daemon_socket_path: str,
|
||||
ydotool_daemon_process: subprocess.Popen,
|
||||
) -> None:
|
||||
"""
|
||||
1. Run `pkexec` as a background process that produces a specific
|
||||
output to stdout upon successful completion.
|
||||
2. Wait unil it has been confimred that `cosmic-osd` has created
|
||||
a pop-up requesting the root user's password.
|
||||
3. Use ydotool to type the root user's password in the pop-up
|
||||
prompt.
|
||||
4. Ensure that the the `pkexec` background process' stdout matches
|
||||
the output that we expect.
|
||||
|
||||
Any breakage in this flow is considered a failure of the polkit
|
||||
authenticaion test.
|
||||
"""
|
||||
logging.info("=" * 80)
|
||||
logging.info("Performing polkit authentication test")
|
||||
|
||||
polkit_test_passed = False
|
||||
polkit_test_command = [
|
||||
"pkexec",
|
||||
"--disable-internal-agent",
|
||||
"bash",
|
||||
"-c",
|
||||
"echo -n 'polkit test was successful'",
|
||||
]
|
||||
logging.info(f"Running: {polkit_test_command}")
|
||||
polkit_test_process = subprocess.Popen(
|
||||
polkit_test_command,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
text=True,
|
||||
)
|
||||
|
||||
polkit_popup_deadline = time.monotonic() + 60
|
||||
pop_up_msg = "the pop-up for polkit password authentication"
|
||||
encountered_polkit_authentication_popup = False
|
||||
while time.monotonic() < polkit_popup_deadline:
|
||||
polkit_popup_check_process = subprocess.run(
|
||||
[
|
||||
"pgrep",
|
||||
"-afx",
|
||||
f"{cli_args.polkit_agent_helper_path} --socket-activated",
|
||||
],
|
||||
check=False,
|
||||
)
|
||||
if polkit_popup_check_process.returncode == 0:
|
||||
encountered_polkit_authentication_popup = True
|
||||
logging.info(f"Noticed {pop_up_msg}")
|
||||
if ydotool_daemon_process.poll() is None:
|
||||
# The polkit-agent-helper process exists, but that
|
||||
# doesn't necessarily mean that the pop-up is
|
||||
# **rendered** and ready to accept the password. So we
|
||||
# sleep for a few seconds.
|
||||
time.sleep(20)
|
||||
ydotool_process = subprocess.run(
|
||||
[
|
||||
"ydotool",
|
||||
"type",
|
||||
"--key-delay=500",
|
||||
f"{cli_args.root_user_password}\n",
|
||||
],
|
||||
env={
|
||||
**os.environ.copy(),
|
||||
"YDOTOOL_SOCKET": ydotool_daemon_socket_path,
|
||||
},
|
||||
check=False,
|
||||
)
|
||||
ydotool_msg = (
|
||||
"the root user's password in the pop-up for polkit authentication"
|
||||
)
|
||||
if ydotool_process.returncode == 0:
|
||||
logging.info(f"ydotool typed {ydotool_msg}")
|
||||
else:
|
||||
logging.error(f"ydotool did not type {ydotool_msg}")
|
||||
else:
|
||||
logging.error(
|
||||
"The ydotool daemon exited for some reason before it could be used"
|
||||
)
|
||||
break
|
||||
time.sleep(1)
|
||||
if not encountered_polkit_authentication_popup:
|
||||
logging.error(f"Did not notice {pop_up_msg}")
|
||||
|
||||
polkit_test_process_stdout = ""
|
||||
polkit_test_process_stderr = ""
|
||||
try:
|
||||
polkit_test_process_stdout, polkit_test_process_stderr = (
|
||||
polkit_test_process.communicate(timeout=45)
|
||||
)
|
||||
except subprocess.TimeoutExpired:
|
||||
polkit_test_process.kill()
|
||||
polkit_test_process_stdout, polkit_test_process_stderr = (
|
||||
polkit_test_process.communicate()
|
||||
)
|
||||
|
||||
logging.info(f"polkit stdout: '{polkit_test_process_stdout}'")
|
||||
logging.info(f"polkit stderr: '{polkit_test_process_stderr}'")
|
||||
|
||||
if polkit_test_process_stdout:
|
||||
logging.info(f"pkexec command stdout: {polkit_test_process_stdout}")
|
||||
polkit_test_passed = "polkit test was successful" in polkit_test_process_stdout
|
||||
else:
|
||||
logging.warning("Could not capture stdout from the polkit test command")
|
||||
|
||||
if polkit_test_passed:
|
||||
logging.info("The polkit authentication test passed")
|
||||
else:
|
||||
logging.error("The polkit authentication test failed")
|
||||
return
|
||||
|
||||
|
||||
def perform_gui_application_test(cli_args: argparse.Namespace) -> None:
|
||||
"""
|
||||
1. Start one GUI application as a background process.
|
||||
2. Wait unil it has been confimred that the GUI application is
|
||||
running.
|
||||
3. Kill the background process of the GUI application.
|
||||
|
||||
Any breakage in this flow is considered a failure of the test for
|
||||
the GUI application.
|
||||
"""
|
||||
logging.info("=" * 80)
|
||||
logging.info("Performing test to launch GUI applications")
|
||||
|
||||
gui_apps_to_test = {
|
||||
"com.system76.CosmicEdit": [
|
||||
"cosmic-edit",
|
||||
],
|
||||
"com.system76.CosmicFiles": [
|
||||
"cosmic-files",
|
||||
],
|
||||
"com.system76.CosmicPlayer": [
|
||||
"cosmic-player",
|
||||
],
|
||||
"com.system76.CosmicReader": [
|
||||
"cosmic-reader",
|
||||
cli_args.cosmic_reader_pdf,
|
||||
],
|
||||
"com.system76.CosmicSettings": [
|
||||
"cosmic-settings",
|
||||
],
|
||||
"com.system76.CosmicStore": [
|
||||
"cosmic-store",
|
||||
],
|
||||
"com.system76.CosmicTerm": [
|
||||
"cosmic-term",
|
||||
],
|
||||
}
|
||||
|
||||
for gui_app_id, gui_app_command in gui_apps_to_test.items():
|
||||
logging.info(f"Running: {gui_app_command}")
|
||||
gui_app_bg_process = subprocess.Popen(
|
||||
gui_app_command,
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
)
|
||||
gui_app_bg_process_deadline = time.monotonic() + 30
|
||||
gui_app_is_running = False
|
||||
|
||||
while time.monotonic() < gui_app_bg_process_deadline and not gui_app_is_running:
|
||||
lswt_process = subprocess.run(
|
||||
[
|
||||
"lswt",
|
||||
"--custom",
|
||||
"a",
|
||||
],
|
||||
check=False,
|
||||
text=True,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.DEVNULL,
|
||||
)
|
||||
lswt_process_stdout = lswt_process.stdout.strip()
|
||||
if lswt_process_stdout:
|
||||
if gui_app_id in lswt_process_stdout.splitlines():
|
||||
gui_app_is_running = True
|
||||
time.sleep(1)
|
||||
pkill_process = subprocess.run(
|
||||
["pkill", gui_app_command[0]],
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
check=False,
|
||||
)
|
||||
|
||||
log_message = (
|
||||
f"The GUI application test for '{gui_app_command[0]}' ({gui_app_id})"
|
||||
)
|
||||
if gui_app_is_running:
|
||||
logging.info(f"{log_message} passed")
|
||||
else:
|
||||
logging.error(f"{log_message} failed")
|
||||
return
|
||||
|
||||
|
||||
def main() -> None:
|
||||
cli_args = parse_cli_args()
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format=f"%(asctime)sZ [%(levelname)s] [L:%(lineno)d] %(message)s",
|
||||
datefmt="%H:%M:%S",
|
||||
handlers=[
|
||||
logging.StreamHandler(),
|
||||
logging.FileHandler(f"{cli_args.log_file_path}.log", mode="w"),
|
||||
],
|
||||
)
|
||||
logging.Formatter.converter = time.gmtime
|
||||
logging.info(f"Logging to '{cli_args.log_file_path}.log'")
|
||||
|
||||
ydotool_daemon_socket_path, ydotool_daemon_process = start_ydotool_daemon()
|
||||
|
||||
# Wait for the DE to be ready
|
||||
wait_for_cosmic_de_readiness()
|
||||
|
||||
# tests go here
|
||||
perform_polkit_authentication_test(
|
||||
cli_args, ydotool_daemon_socket_path, ydotool_daemon_process
|
||||
)
|
||||
perform_gui_application_test(cli_args)
|
||||
|
||||
pathlib.Path(f"{cli_args.log_file_path}.done").touch()
|
||||
return
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
41
pkgs/by-name/em/empty-pdf/package.nix
Normal file
41
pkgs/by-name/em/empty-pdf/package.nix
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
{
|
||||
stdenvNoCC,
|
||||
imagemagick,
|
||||
lib,
|
||||
}:
|
||||
|
||||
stdenvNoCC.mkDerivation {
|
||||
name = "empty-pdf";
|
||||
|
||||
__structuredAttrs = true;
|
||||
strictDeps = true;
|
||||
|
||||
dontUnpack = true;
|
||||
|
||||
nativeBuildInputs = [ imagemagick ];
|
||||
|
||||
buildPhase = ''
|
||||
runHook preBuild
|
||||
|
||||
magick xc:none -page Letter empty.pdf
|
||||
|
||||
runHook postBuild
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
|
||||
mv empty.pdf $out
|
||||
|
||||
runHook postInstall
|
||||
'';
|
||||
|
||||
meta = {
|
||||
description = "Empty PDF file intended for testing";
|
||||
maintainers = with lib.maintainers; [
|
||||
pandapip1
|
||||
thefossguy
|
||||
];
|
||||
platforms = imagemagick.meta.platforms;
|
||||
};
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue