test(utils): stress SleeperThread wake and stop control flow
SleeperThread concurrency paths needed stress coverage around wake/stop races. I added a subprocess stress test that repeatedly interleaves wake_up() and stop() and verifies the worker exits cleanly. Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
This commit is contained in:
@@ -19,24 +19,61 @@ SafeSignal<bool>& prepare_for_sleep() {
|
|||||||
} // namespace waybar::util
|
} // namespace waybar::util
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
int run_in_subprocess(int (*task)()) {
|
||||||
|
const auto pid = fork();
|
||||||
|
if (pid < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (pid == 0) {
|
||||||
|
alarm(5);
|
||||||
|
_exit(task());
|
||||||
|
}
|
||||||
|
|
||||||
|
int status = -1;
|
||||||
|
if (waitpid(pid, &status, 0) != pid) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (!WIFEXITED(status)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return WEXITSTATUS(status);
|
||||||
|
}
|
||||||
|
|
||||||
int run_reassignment_regression() {
|
int run_reassignment_regression() {
|
||||||
waybar::util::SleeperThread thread;
|
waybar::util::SleeperThread thread;
|
||||||
thread = [] { std::this_thread::sleep_for(std::chrono::milliseconds(10)); };
|
thread = [] { std::this_thread::sleep_for(std::chrono::milliseconds(10)); };
|
||||||
thread = [] { std::this_thread::sleep_for(std::chrono::milliseconds(1)); };
|
thread = [] { std::this_thread::sleep_for(std::chrono::milliseconds(1)); };
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int run_control_flag_stress() {
|
||||||
|
for (int i = 0; i < 200; ++i) {
|
||||||
|
waybar::util::SleeperThread thread;
|
||||||
|
thread = [&thread] { thread.sleep_for(std::chrono::milliseconds(1)); };
|
||||||
|
|
||||||
|
std::thread waker([&thread] {
|
||||||
|
for (int j = 0; j < 100; ++j) {
|
||||||
|
thread.wake_up();
|
||||||
|
std::this_thread::yield();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(2));
|
||||||
|
thread.stop();
|
||||||
|
waker.join();
|
||||||
|
if (thread.isRunning()) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
TEST_CASE("SleeperThread reassignment does not terminate process", "[util][sleeper_thread]") {
|
TEST_CASE("SleeperThread reassignment does not terminate process", "[util][sleeper_thread]") {
|
||||||
const auto pid = fork();
|
REQUIRE(run_in_subprocess(run_reassignment_regression) == 0);
|
||||||
REQUIRE(pid >= 0);
|
}
|
||||||
|
|
||||||
if (pid == 0) {
|
TEST_CASE("SleeperThread control flags are stable under concurrent wake and stop",
|
||||||
_exit(run_reassignment_regression());
|
"[util][sleeper_thread]") {
|
||||||
}
|
REQUIRE(run_in_subprocess(run_control_flag_stress) == 0);
|
||||||
|
|
||||||
int status = -1;
|
|
||||||
REQUIRE(waitpid(pid, &status, 0) == pid);
|
|
||||||
REQUIRE(WIFEXITED(status));
|
|
||||||
REQUIRE(WEXITSTATUS(status) == 0);
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user