test: threadpool, add coverage for all Submit() errors
What changed, and why it matters
This commit only adds new test code to Bitcoin Core. It expands an existing unit test to check that a background worker pool (ThreadPool) returns the correct error messages when tasks are submitted while the pool is not started, interrupted, or stopped. There is no change to production code and no security fix or vulnerability is introduced.
No action required. This is a routine test-coverage addition. Reviewers may optionally confirm the new assertions match intended ThreadPool semantics, but no security response is warranted.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The diff modifies src/test/threadpool_tests.cpp, renaming and extending BOOST_AUTO_TEST_CASE(submit_fails_with_correct_error). The test now verifies Submit() behavior for a ThreadPool in three states: never started (returns ‘No active workers’), interrupted (returns ‘Interrupted’), and stopped (returns ‘No active workers’). It also asserts that Start() is rejected after interruption. No library or runtime logic is changed.
Changed components
src/test/threadpool_tests.cppInspect captured patch +31 / −3
diff --git a/src/test/threadpool_tests.cpp b/src/test/threadpool_tests.cpp
index 647b0f7c..f5ae2223 100644
--- a/src/test/threadpool_tests.cpp
+++ b/src/test/threadpool_tests.cpp
@@ -72,11 +72,39 @@ std::vector<std::future<void>> BlockWorkers(ThreadPool& threadPool, std::countin
return blocking_tasks;
}
-// Test 0, submit task to a non-started pool
-BOOST_AUTO_TEST_CASE(submit_task_before_start_fails)
+// Test 0, submit task to a non-started, interrupted, or stopped pool
+BOOST_AUTO_TEST_CASE(submit_fails_with_correct_error)
{
ThreadPool threadPool(POOL_NAME);
- auto res = threadPool.Submit([]{ return false; });
+ const auto fn_empty = [&] {};
+
+ // Never started: Inactive
+ auto res = threadPool.Submit(fn_empty);
+ BOOST_CHECK(!res);
+ BOOST_CHECK_EQUAL(SubmitErrorString(res.error()), "No active workers");
+
+ // Interrupted (workers still alive): Interrupted, and Start() must be rejected too
+ std::counting_semaphore<> blocker(0);
+ threadPool.Start(NUM_WORKERS_DEFAULT);
+ const auto blocking_tasks = BlockWorkers(threadPool, blocker, NUM_WORKERS_DEFAULT);
+ threadPool.Interrupt();
+ res = threadPool.Submit(fn_empty);
+ BOOST_CHECK(!res);
+ BOOST_CHECK_EQUAL(SubmitErrorString(res.error()), "Interrupted");
+ BOOST_CHECK_EXCEPTION(threadPool.Start(NUM_WORKERS_DEFAULT), std::runtime_error, HasReason("Thread pool has been interrupted or is stopping"));
+ blocker.release(NUM_WORKERS_DEFAULT);
+ WAIT_FOR(blocking_tasks);
+
+ // Interrupted then stopped: Inactive
+ threadPool.Stop();
+ res = threadPool.Submit(fn_empty);
+ BOOST_CHECK(!res);
+ BOOST_CHECK_EQUAL(SubmitErrorString(res.error()), "No active workers");
+
+ // Started then stopped: Inactive
+ threadPool.Start(NUM_WORKERS_DEFAULT);
+ threadPool.Stop();
+ res = threadPool.Submit(fn_empty);
BOOST_CHECK(!res);
BOOST_CHECK_EQUAL(SubmitErrorString(res.error()), "No active workers");
}
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.