Suggested (by me) as a followup for #36088: #36088 (review)
Reverting that PR will cause the test to fail.
The first refactor commit changes assert_capnp_failed to assert_capnp_raises to reduce repetition.
Suggested (by me) as a followup for #36088: #36088 (review)
Reverting that PR will cause the test to fail.
The first refactor commit changes assert_capnp_failed to assert_capnp_raises to reduce repetition.
<!--e57a25ab6845829454e8d69fc972939a-->
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.
<!--006a51241073e994b41acfe9ec718e94-->
For details see: https://corecheck.dev/bitcoin/bitcoin/pulls/36093.
<!--021abf342d371248e50ceaed478a90ca-->
See the guideline and AI policy for information on the review process.
| Type | Reviewers |
|---|---|
| ACK | hodlinator, jeanpablojp, sedited |
If your review is incorrectly listed, please copy-paste <code><!--meta-tag:bot-skip--></code> into the comment that the bot should ignore.
<!--5faf32d7da4f0f540f40219e4f7537a3-->
Possible places where named args for integral literals may be used (e.g. func(x, /*named_arg=*/0) in C++, and func(x, named_arg=0) in Python):
template.submitSolution(ctx, 0, 0, 0, b"\x00") in test/functional/interface_ipc_mining.py<sup>2026-08-28 07:33:06</sup>
62 | + self.log.debug("Invalid JSON in an executeRpc request must be rejected") 63 | + try: 64 | + await rpc.executeRpc(ctx, "invalid json", "/", "") 65 | + raise AssertionError("executeRpc unexpectedly succeeded") 66 | + except capnp.KjException as e: 67 | + assert_capnp_failed(e, "remote exception: std::exception: invalid JSON received over IPC")
This pattern would become repeated in 5 places. Maybe assert_capnp_failed() could be turned into assert_capnp_raises()?
<details><summary>diff</summary>
diff --git a/test/functional/interface_ipc.py b/test/functional/interface_ipc.py
index 119591a675..3e2f64fcac 100755
--- a/test/functional/interface_ipc.py
+++ b/test/functional/interface_ipc.py
@@ -10,7 +10,7 @@ from contextlib import ExitStack
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal
from test_framework.ipc_util import (
- assert_capnp_failed,
+ assert_capnp_raises,
load_capnp_modules,
make_capnp_init_ctx,
make_mining_ctx,
@@ -60,11 +60,8 @@ class IPCInterfaceTest(BitcoinTestFramework):
self.log.debug("Create Rpc proxy object")
rpc = init.makeRpc(ctx).result
self.log.debug("Invalid JSON in an executeRpc request must be rejected")
- try:
- await rpc.executeRpc(ctx, "invalid json", "/", "")
- raise AssertionError("executeRpc unexpectedly succeeded")
- except capnp.KjException as e:
- assert_capnp_failed(e, "remote exception: std::exception: invalid JSON received over IPC")
+ await assert_capnp_raises(lambda: rpc.executeRpc(ctx, "invalid json", "/", ""),
+ "remote exception: std::exception: invalid JSON received over IPC")
self.log.debug("The connection still works after the failed call")
request = json.dumps({"method": "getblockcount", "params": [], "id": 1})
response = json.loads((await rpc.executeRpc(ctx, request, "/", "")).result)
diff --git a/test/functional/interface_ipc_mining.py b/test/functional/interface_ipc_mining.py
index c36d73ab0a..05dc75a532 100755
--- a/test/functional/interface_ipc_mining.py
+++ b/test/functional/interface_ipc_mining.py
@@ -37,7 +37,7 @@ from test_framework.util import (
from test_framework.wallet import MiniWallet
from test_framework.p2p import P2PInterface
from test_framework.ipc_util import (
- assert_capnp_failed,
+ assert_capnp_raises,
assert_create_new_block_fails,
destroying,
load_capnp_modules,
@@ -523,11 +523,8 @@ class IPCMiningTest(BitcoinTestFramework):
assert_equal(submitted, False)
self.log.debug("Submit solution that can't be deserialized")
- try:
- await template.submitSolution(ctx, 0, 0, 0, b"\x00")
- raise AssertionError("submitSolution unexpectedly succeeded")
- except capnp.lib.capnp.KjException as e:
- assert_capnp_failed(e, "remote exception: std::exception: SpanReader::read(): end of data:")
+ await assert_capnp_raises(lambda: template.submitSolution(ctx, 0, 0, 0, b"\x00"),
+ "remote exception: std::exception: SpanReader::read(): end of data:")
self.log.debug("Submit a block with a bad version")
block.nVersion = 0
@@ -712,18 +709,12 @@ class IPCMiningTest(BitcoinTestFramework):
)
self.log.debug("Submit a malformed complete block")
- try:
- await mining2.submitBlock(ctx2, block.serialize()[:-15])
- raise AssertionError("submitBlock unexpectedly succeeded")
- except capnp.lib.capnp.KjException as e:
- assert_capnp_failed(e, "remote exception: std::exception: SpanReader::read(): end of data:")
+ await assert_capnp_raises(lambda: mining2.submitBlock(ctx2, block.serialize()[:-15]),
+ "remote exception: std::exception: SpanReader::read(): end of data:")
self.log.debug("Submit empty block data")
- try:
- await mining2.submitBlock(ctx2, b"")
- raise AssertionError("submitBlock unexpectedly succeeded")
- except capnp.lib.capnp.KjException as e:
- assert_capnp_failed(e, "remote exception: std::exception: SpanReader::read(): end of data:")
+ await assert_capnp_raises(lambda: mining2.submitBlock(ctx2, b""),
+ "remote exception: std::exception: SpanReader::read(): end of data:")
assert_equal(self.nodes[2].is_node_stopped(), False)
asyncio.run(capnp.run(async_routine()))
diff --git a/test/functional/test_framework/ipc_util.py b/test/functional/test_framework/ipc_util.py
index a4ebd091e8..4a221ed7d7 100644
--- a/test/functional/test_framework/ipc_util.py
+++ b/test/functional/test_framework/ipc_util.py
@@ -159,15 +159,17 @@ async def make_mining_ctx(self, node_index=0):
mining = init.makeMining(ctx).result
return ctx, mining
-def assert_capnp_failed(e, description_prefix):
- assert e.description.startswith(description_prefix), f"Expected description starting with '{description_prefix}', got '{e.description}'"
- assert_equal(e.type, "FAILED")
+
+async def assert_capnp_raises(fun, description_prefix):
+ try:
+ await fun()
+ raise AssertionError(f"Function unexpectedly succeeded without raising {description_prefix!r}")
+ except capnp.lib.capnp.KjException as e:
+ assert e.description.startswith(description_prefix), f"Expected description starting with '{description_prefix}', got '{e.description}'"
+ assert_equal(e.type, "FAILED")
async def assert_create_new_block_fails(ctx, mining, opts, expected_msg):
"""Assert that mining.createNewBlock fails with the expected remote exception."""
- try:
- await mining.createNewBlock(ctx, opts)
- raise AssertionError("createNewBlock unexpectedly succeeded")
- except capnp.lib.capnp.KjException as e:
- assert_capnp_failed(e, f"remote exception: std::exception: {expected_msg}")
+ await assert_capnp_raises(lambda: mining.createNewBlock(ctx, opts),
+ f"remote exception: std::exception: {expected_msg}")
</details>
Taken.
ACK abd24ace1bbc146789593959af15258b854932a9
Hmm, corecheck doesn't detect new coverage. Maybe it should compile with the dev-mode preset? cc @m3dwards
I've added the pycapnp package to corecheck to enable the interface_ipc.py functional test and can see it being run and now appearing in the coverage checking. Do we think this is enough?
2026-08-27T14:44:59.692Z 256/299 - interface_ipc.py passed, Duration: 1 s
Co-authored-by: Hodlinator <172445034+hodlinator@users.noreply.github.com>
Suggested as a followup for #36088:
https://github.com/bitcoin/bitcoin/pull/36088#discussion_r3864044274
Added @hodlinator's suggested refactor as a prep commit, see #36093 (review).
Nice. corecheck now shows a green line in "Gained baseline coverage"
re-ACK f14569f97d081c6d34353bdf22e901a9baf92ef3
Thanks for taking the test refactor suggestion. Re-ran functional tests.
tACK f14569f97d081c6d34353bdf22e901a9baf92ef3
I reverted #36088 and the test fails. It also fails with only the throw removed, where all unit tests still pass. And changing the SpanReader message makes the rewritten assertions fail too.
ACK f14569f97d081c6d34353bdf22e901a9baf92ef3