Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions src/plugin-qt/power/session/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# SPDX-License-Identifier: LGPL-3.0-or-later

find_package(Qt6 REQUIRED COMPONENTS Test)
find_program(DBUS_RUN_SESSION dbus-run-session REQUIRED)
find_program(DBUS_DAEMON dbus-daemon REQUIRED)

add_executable(tst-screensaverproxy
tst-screensaverproxy.cpp
Expand All @@ -11,7 +11,12 @@ add_executable(tst-screensaverproxy
)
target_include_directories(tst-screensaverproxy PRIVATE ..)
target_link_libraries(tst-screensaverproxy PRIVATE Qt6::Test Qt6::DBus Dtk6::Core)

# run-with-private-bus.sh, not dbus-run-session: the usec LSM denies signals to
# dbus-daemon, which would make dbus-run-session hang and the test time out.
add_test(NAME power-screensaver-proxy
COMMAND ${DBUS_RUN_SESSION} --config-file=${CMAKE_CURRENT_SOURCE_DIR}/session.conf
-- $<TARGET_FILE:tst-screensaverproxy>)
set_tests_properties(power-screensaver-proxy PROPERTIES TIMEOUT 20)
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/run-with-private-bus.sh
${CMAKE_CURRENT_SOURCE_DIR}/session.conf
$<TARGET_FILE:tst-screensaverproxy>)
set_tests_properties(power-screensaver-proxy PROPERTIES TIMEOUT 20
ENVIRONMENT "DBUS_DAEMON_BIN=${DBUS_DAEMON}")
77 changes: 77 additions & 0 deletions src/plugin-qt/power/session/tests/run-with-private-bus.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#!/bin/sh
# SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd.
#
# SPDX-License-Identifier: LGPL-3.0-or-later
#
# Run a command against a freshly started private session bus.
#
# Do not use dbus-run-session here. It terminates the bus by signalling
# dbus-daemon, and UOS kernels with the usec LSM label /usr/bin/dbus-daemon as
# deepin_unkillable_t, so that signal is denied:
#
# uavc: denied { signal } for comm="dbus-run-sessio"
# scontext=...:deepin_usec_t tcontext=...:deepin_unkillable_t
#
# dbus-run-session then waits forever for its daemon. That daemon also inherits
# the stdout pipe of the test runner, so ctest never sees EOF and reports a
# timeout even though the test itself finished and passed. Starting the daemon
# with --fork avoids depending on a signal at all: cleanup below is best effort,
# and an unreapable daemon only costs a little idle memory.
#
# Under fakeroot (dpkg-buildpackage) libfakeroot is injected through LD_PRELOAD
# and fakes getuid() as root. The client then authenticates with "AUTH EXTERNAL
# 30" while the daemon checks the real uid 10759 via SO_PEERCRED and refuses the
# connection, so every registerObject/registerService call fails. The intercept
# library is of no use to this test, so drop it and restore the real uid.
LD_PRELOAD=
export LD_PRELOAD

set -u

if [ $# -lt 2 ]; then
echo "usage: $0 <bus-config> <command> [args...]" >&2
exit 2
fi

bus_config=$1
shift
dbus_daemon=${DBUS_DAEMON_BIN:-dbus-daemon}

command -v "$dbus_daemon" >/dev/null 2>&1 || {
echo "$0: dbus-daemon not found (looked for '$dbus_daemon')" >&2
exit 1
}

address_file=$(mktemp) || exit 1
pid_file=$(mktemp) || exit 1
trap 'rm -f "$address_file" "$pid_file"' EXIT HUP INT TERM

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium · Signals leave tests running

When the wrapper receives HUP, INT, or TERM while its command remains alive and does not receive the signal, the signal trap only removes temporary files, so the wrapper remains blocked waiting for the command and never reaches normal daemon cleanup; the command and private bus keep running until it returns.

Make the signal trap terminate the command and run daemon cleanup.

Prompt for AI agents
In `src/plugin-qt/power/session/tests/run-with-private-bus.sh` at line 47:

**Signals leave tests running**

When the wrapper receives `HUP`, `INT`, or `TERM` while its command remains alive and does not receive the signal, the signal trap only removes temporary files, so the wrapper remains blocked waiting for the command and never reaches normal daemon cleanup; the command and private bus keep running until it returns.

Make the signal trap terminate the command and run daemon cleanup.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚪ Low · Early exits leave bus daemons

When the command is interrupted or times out, or dbus-daemon starts without printing a bus address, the trap removes the PID file without signaling the daemon; interruption skips the end-of-script kill, and the missing-address path exits immediately, leaving the private bus running.

Make exit and signal cleanup read the PID and signal the daemon before removing the temporary files.

Also at src/plugin-qt/power/session/tests/run-with-private-bus.sh:63.

Prompt for AI agents
In `src/plugin-qt/power/session/tests/run-with-private-bus.sh` at line 47:

**Early exits leave bus daemons**

When the command is interrupted or times out, or `dbus-daemon` starts without printing a bus address, the trap removes the PID file without signaling the daemon; interruption skips the end-of-script `kill`, and the missing-address path exits immediately, leaving the private bus running.

Make exit and signal cleanup read the PID and signal the daemon before removing the temporary files.

Also at `src/plugin-qt/power/session/tests/run-with-private-bus.sh:63`.


# stdin and both output streams to /dev/null: a daemon that survives cleanup
# must never hold a pipe of the test runner open.
"$dbus_daemon" --config-file="$bus_config" --fork \
--print-address=3 --print-pid=4 \
3>"$address_file" 4>"$pid_file" </dev/null >/dev/null 2>&1 || {
echo "$0: cannot start $dbus_daemon with $bus_config" >&2
exit 1
}

bus_address=$(cat "$address_file")
daemon_pid=$(cat "$pid_file")
if [ -z "$bus_address" ]; then
echo "$0: dbus-daemon did not print a bus address" >&2
exit 1
fi
Comment on lines +61 to +63

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium · Private bus survives failed startup

When dbus-daemon forks but writes no address, the bus_address check exits before the normal kill block, and the EXIT trap only removes temporary files; the private bus remains running after startup fails.

Route this exit through daemon cleanup before returning.

Also at src/plugin-qt/power/session/tests/run-with-private-bus.sh:47.

Prompt for AI agents
In `src/plugin-qt/power/session/tests/run-with-private-bus.sh` at lines 61-63:

**Private bus survives failed startup**

When `dbus-daemon` forks but writes no address, the `bus_address` check exits before the normal `kill` block, and the `EXIT` trap only removes temporary files; the private bus remains running after startup fails.

Route this exit through daemon cleanup before returning.

Also at `src/plugin-qt/power/session/tests/run-with-private-bus.sh:47`.


DBUS_SESSION_BUS_ADDRESS=$bus_address
export DBUS_SESSION_BUS_ADDRESS

"$@"
status=$?

# Best effort only: where the LSM allows it the daemon is reaped, where it does
# not the failure to signal must not turn a passing test into a failing one.
if [ -n "$daemon_pid" ]; then
kill "$daemon_pid" 2>/dev/null || :
fi

exit $status
Loading