summaryrefslogtreecommitdiff
path: root/hyprtester/src/tests/main/exec.cpp
diff options
context:
space:
mode:
authorNikolai Nechaev <nikolay_nechaev@mail.ru>2025-09-24 02:32:48 +0900
committerGitHub <noreply@github.com>2025-09-23 19:32:48 +0200
commit29b103c3762d01c9711aba33985f27869238143d (patch)
treeda6a4fba108d13a5624558b9824f9ae58124e931 /hyprtester/src/tests/main/exec.cpp
parent70a7047ee175d2e7fca1575d50a3738ac40fd2c6 (diff)
exec: Spawn processes as direct children (#11735)
* exec: Spawn processes as direct children Spawn processes as children rather than grandchildren. This way, spawned processes may track Hyprland's state by watching their parent, either directly or indirectly (e.g., Linux's `PR_SET_PDEATH_SIG`). Fixes #11728 * tests/exec: Add the test on process spawning Add a test that ensures that: - A spawned process remains a direct child of Hyprland; - Upon termination, the process does not become a zombie.
Diffstat (limited to 'hyprtester/src/tests/main/exec.cpp')
-rw-r--r--hyprtester/src/tests/main/exec.cpp64
1 files changed, 64 insertions, 0 deletions
diff --git a/hyprtester/src/tests/main/exec.cpp b/hyprtester/src/tests/main/exec.cpp
new file mode 100644
index 00000000..a475ac0d
--- /dev/null
+++ b/hyprtester/src/tests/main/exec.cpp
@@ -0,0 +1,64 @@
+#include "tests.hpp"
+#include "../../shared.hpp"
+#include "../../hyprctlCompat.hpp"
+#include <chrono>
+#include <thread>
+#include <hyprutils/os/Process.hpp>
+#include <hyprutils/memory/WeakPtr.hpp>
+#include "../shared.hpp"
+
+static int ret = 0;
+
+using namespace Hyprutils::OS;
+using namespace Hyprutils::Memory;
+
+#define UP CUniquePointer
+#define SP CSharedPointer
+
+static std::string execAndGet(const std::string& cmd) {
+ CProcess proc("/bin/sh", {"-c", cmd});
+
+ if (!proc.runSync()) {
+ return "error";
+ }
+
+ return proc.stdOut();
+}
+
+static bool test() {
+ NLog::log("{}Testing process spawning", Colors::GREEN);
+
+ // Note: POSIX sleep does not support fractional seconds, so
+ // can't sleep for less than 1 second.
+ OK(getFromSocket("/dispatch exec sleep 1"));
+
+ // Ensure that sleep is our child
+ const std::string sleepPidS = execAndGet("pgrep sleep");
+ pid_t sleepPid;
+ try {
+ sleepPid = std::stoull(sleepPidS);
+ } catch (...) {
+ NLog::log("{}Sleep was not spawned or several sleeps are running: pgrep returned '{}'", Colors::RED, sleepPidS);
+ return false;
+ }
+
+ const std::string sleepParentComm = execAndGet("cat \"/proc/$(ps -o ppid:1= -p " + sleepPidS + ")/comm\"");
+ NLog::log("{}Expecting that sleep's parent is Hyprland", Colors::YELLOW);
+ EXPECT_CONTAINS(sleepParentComm, "Hyprland");
+
+ std::this_thread::sleep_for(std::chrono::seconds(1));
+
+ // Ensure that sleep did not become a zombie
+ EXPECT(Tests::processAlive(sleepPid), false);
+
+ // kill all
+ NLog::log("{}Killing all windows", Colors::YELLOW);
+ Tests::killAllWindows();
+
+ NLog::log("{}Expecting 0 windows", Colors::YELLOW);
+ EXPECT(Tests::windowCount(), 0);
+
+ return !ret;
+}
+
+REGISTER_TEST_FN(test)