Skip to content

Commit 46b77c3

Browse files
committed
test(daemon-app): wait for the stable terminal state, not the draining window
The fresh-request guard test waited for 'job terminal AND >= N/2 subscribers still attached'. Publish flips terminal and releases the blocked prior requests in the same locked step, so that conjunction is a transient window whose width is thread-wakeup scheduling: the busy-spin caught it by luck, a 1ms-yield poll (#1307) sampled past it on fast x64 runners, and no budget can pin it (release runs 30305464193 and 30309182389 failed it from both directions). The production guard never consults subscriber counts — application_find_active_job_locked skips any terminal job — and the test's downstream assertions (starts==2, destroys==2, stale/fresh response separation) catch a terminal-job reuse in every interleaving. So wait only for the stable end-state (active jobs == 0) and drop the racy helper. 47/47 locally. Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
1 parent 0abd5c6 commit 46b77c3

1 file changed

Lines changed: 12 additions & 24 deletions

File tree

tests/test_daemon_application.c

Lines changed: 12 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1462,23 +1462,6 @@ static bool app_wait_for_active_jobs(cbm_daemon_application_t *application, size
14621462
return false;
14631463
}
14641464

1465-
static bool app_wait_for_terminal_job_with_subscribers(cbm_daemon_application_t *application,
1466-
const char *project,
1467-
size_t minimum_subscribers) {
1468-
uint64_t deadline = cbm_now_ms() + APP_TEST_TIMEOUT_MS;
1469-
while (cbm_now_ms() < deadline) {
1470-
if (cbm_daemon_application_active_jobs(application) == 0 &&
1471-
cbm_daemon_application_job_subscribers(application, project) >= minimum_subscribers) {
1472-
return true;
1473-
}
1474-
/* Yield like every sibling wait helper: a sleepless spin pins a core
1475-
* and can starve the daemon threads it polls on scarce-CPU runners
1476-
* (windows-11-arm release leg, run 30305464193). */
1477-
cbm_usleep(1000);
1478-
}
1479-
return false;
1480-
}
1481-
14821465
typedef struct {
14831466
cbm_daemon_application_t *application;
14841467
const char *project;
@@ -2646,16 +2629,21 @@ TEST(daemon_application_fresh_request_does_not_reuse_terminal_subscribed_job) {
26462629
bool first_worker_ready_to_publish =
26472630
all_subscribed && app_wait_for_atomic_int(&fake.destroys, 1);
26482631
atomic_store(&fake.release_destroy, true);
2649-
bool terminal_with_prior_subscribers =
2650-
first_worker_ready_to_publish &&
2651-
app_wait_for_terminal_job_with_subscribers(application, project, PRIOR_SUBSCRIBERS / 2U);
2632+
/* Wait only for the stable end-state. Publish flips terminal and lets the
2633+
* blocked prior requests drain in the same breath, so "terminal AND still
2634+
* subscribed" is a transient window no poll cadence can pin (release runs
2635+
* 30305464193 and 30309182389 missed it from both directions). The
2636+
* production guard ignores subscriber counts — find_active_job skips any
2637+
* terminal job — and the stale/fresh assertions below catch a reuse in
2638+
* every interleaving. */
2639+
bool job_terminal = first_worker_ready_to_publish && app_wait_for_active_jobs(application, 0);
26522640

26532641
uint8_t *fresh = NULL;
26542642
uint32_t fresh_length = 0;
26552643
cbm_daemon_runtime_application_status_t fresh_status =
2656-
terminal_with_prior_subscribers ? app_test_request(&callbacks, sessions[PRIOR_SUBSCRIBERS],
2657-
tool, tool_length, &fresh, &fresh_length)
2658-
: CBM_DAEMON_RUNTIME_APPLICATION_REJECTED;
2644+
job_terminal ? app_test_request(&callbacks, sessions[PRIOR_SUBSCRIBERS], tool, tool_length,
2645+
&fresh, &fresh_length)
2646+
: CBM_DAEMON_RUNTIME_APPLICATION_REJECTED;
26592647
for (size_t i = 0; i < PRIOR_SUBSCRIBERS; i++) {
26602648
if (started[i]) {
26612649
(void)cbm_thread_join(&threads[i]);
@@ -2672,7 +2660,7 @@ TEST(daemon_application_fresh_request_does_not_reuse_terminal_subscribed_job) {
26722660
ASSERT_TRUE(setup);
26732661
ASSERT_TRUE(all_subscribed);
26742662
ASSERT_TRUE(first_worker_ready_to_publish);
2675-
ASSERT_TRUE(terminal_with_prior_subscribers);
2663+
ASSERT_TRUE(job_terminal);
26762664
ASSERT_EQ(fresh_status, CBM_DAEMON_RUNTIME_APPLICATION_OK);
26772665
ASSERT_EQ(atomic_load(&fake.starts), 2);
26782666
ASSERT_EQ(atomic_load(&fake.destroys), 2);

0 commit comments

Comments
 (0)