test: Do not pass tests on unhandled exceptions #33001

pull maflcko wants to merge 2 commits into bitcoin:master from maflcko:2507-test-actually-fail-on-failure changing 1 files +3 −15
  1. maflcko commented at 10:43 AM on July 17, 2025: member

    Currently the functional tests are problematic, because they pass, even if they encounter an unhanded exception.

    Fix this by handling all exceptions: Catch BaseException as fallback and mark it as failure.

    Can be tested via:

    diff --git a/test/functional/wallet_disable.py b/test/functional/wallet_disable.py
    index da6e5d408f..ecc41fb041 100755
    --- a/test/functional/wallet_disable.py
    +++ b/test/functional/wallet_disable.py
    @@ -19,6 +19,7 @@ class DisableWalletTest (BitcoinTestFramework):
             self.wallet_names = []
     
         def run_test (self):
    +        import sys;sys.exit("fatal error")
             # Make sure wallet is really disabled
             assert_raises_rpc_error(-32601, 'Method not found', self.nodes[0].getwalletinfo)
             x = self.nodes[0].validateaddress('3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy')
    

    Previously, the test would pass. With this patch, it would fail.

  2. in test/functional/test_framework/test_framework.py:208 in fad0cd510c outdated
     214 | @@ -215,6 +215,9 @@ def main(self):
     215 |          except KeyboardInterrupt:
     216 |              self.log.warning("Exiting after keyboard interrupt")
     217 |              self.success = TestStatus.FAILED
     218 | +        except BaseException as e:
     219 | +            self.log.warning(f"Unhandled base exception {repr(e)}")
     220 | +            self.success = TestStatus.FAILED
    


    stickies-v commented at 1:36 PM on July 17, 2025:

    All these exception handlers (except SkipTest) have the same behaviour, except for making the logs less useful by hiding the actual error. Can't we just remove all (except SkipTest and BaseException) and let the exception speak for itself? + updates log to exception instead of warning.

    <details> <summary>git diff on fad0cd510c</summary>

    diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py
    index 21007d9156..17e5a6b397 100755
    --- a/test/functional/test_framework/test_framework.py
    +++ b/test/functional/test_framework/test_framework.py
    @@ -194,29 +194,11 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
                 else:
                     self.run_test()
     
    -        except JSONRPCException:
    -            self.log.exception("JSONRPC error")
    -            self.success = TestStatus.FAILED
             except SkipTest as e:
                 self.log.warning("Test Skipped: %s" % e.message)
                 self.success = TestStatus.SKIPPED
    -        except AssertionError:
    -            self.log.exception("Assertion failed")
    -            self.success = TestStatus.FAILED
    -        except KeyError:
    -            self.log.exception("Key error")
    -            self.success = TestStatus.FAILED
    -        except subprocess.CalledProcessError as e:
    -            self.log.exception("Called Process failed with '{}'".format(e.output))
    -            self.success = TestStatus.FAILED
    -        except Exception:
    -            self.log.exception("Unexpected exception caught during testing")
    -            self.success = TestStatus.FAILED
    -        except KeyboardInterrupt:
    -            self.log.warning("Exiting after keyboard interrupt")
    -            self.success = TestStatus.FAILED
             except BaseException as e:
    -            self.log.warning(f"Unhandled base exception {repr(e)}")
    +            self.log.exception(repr(e))
                 self.success = TestStatus.FAILED
             finally:
                 exit_code = self.shutdown()
    
    

    </details>


    maflcko commented at 2:57 PM on July 17, 2025:

    Agree; thx, done


    stickies-v commented at 3:15 PM on July 17, 2025:

    Logging the exception e seems more useful than "Unexpected exception", and imo completely obviates the need for having the CalledProcessError and KeyboardInterrupt special case handling?


    stickies-v commented at 3:21 PM on July 17, 2025:

    Logs with special case handling:

    2025-07-17T15:07:39.774663Z TestFramework (ERROR): Called Process failed with 'None'
    2025-07-17T15:18:22.039274Z TestFramework (WARNING): Exiting after keyboard interrupt
    

    Logs without special case handling:

    2025-07-17T15:19:09.169925Z TestFramework (ERROR): CalledProcessError(1, ['ls', '--invalid-flag'])
    2025-07-17T15:19:26.639162Z TestFramework (ERROR): KeyboardInterrupt()
    

    Imo, they're equally informative for KeyboardInterrupt, and more informative without special case handling for CalledProcessError, with less code.

    <details> <summary>git diff on fa86ba62de</summary>

    diff --git a/test/functional/feature_abortnode.py b/test/functional/feature_abortnode.py
    index a5c8aa163a..748875b25d 100755
    --- a/test/functional/feature_abortnode.py
    +++ b/test/functional/feature_abortnode.py
    @@ -22,6 +22,8 @@ class AbortNodeTest(BitcoinTestFramework):
             # We'll connect the nodes later
     
         def run_test(self):
    +        import subprocess
    +        subprocess.run(["ls", "--invalid-flag"], check=True)
             self.generate(self.nodes[0], 3, sync_fun=self.no_op)
     
             # Deleting the undo file will result in reorg failure
    diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py
    index 823d946cfe..17e5a6b397 100755
    --- a/test/functional/test_framework/test_framework.py
    +++ b/test/functional/test_framework/test_framework.py
    @@ -197,14 +197,8 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
             except SkipTest as e:
                 self.log.warning("Test Skipped: %s" % e.message)
                 self.success = TestStatus.SKIPPED
    -        except subprocess.CalledProcessError as e:
    -            self.log.exception("Called Process failed with '{}'".format(e.output))
    -            self.success = TestStatus.FAILED
    -        except KeyboardInterrupt:
    -            self.log.warning("Exiting after keyboard interrupt")
    -            self.success = TestStatus.FAILED
             except BaseException as e:
    -            self.log.exception(f"Unexpected exception")
    +            self.log.exception(repr(e))
                 self.success = TestStatus.FAILED
             finally:
                 exit_code = self.shutdown()
    
    

    </details>


    maflcko commented at 3:59 PM on July 17, 2025:

    more informative without special case handling for CalledProcessError, with less code.

    I don't think this is true. It is missing the output. You can try this for any command that captures the output:

    subprocess.run(['bash', '-c', 'echo aaaaa && false'], check=True, capture_output=True)

    There could be an argument about stderr, but this seems better as a separate commit or pull.

    KeyboardInterrupt

    It currently uses self.log.warning, which is different in verbosity. I don't think it makes sense to show the traceback when the user pressed CTRL+C?


    stickies-v commented at 5:47 PM on July 17, 2025:

    You can try this for any command that captures the output:

    Ah cool, thanks for the example. Agreed that improving is out of scope for this PR then.

    I don't think it makes sense to show the traceback when the user pressed CTRL+C?

    No strong preference either way, I kinda like seeing where it got interrupted (and I'm already used to it because the KeyboardInterrupt exception handling doesn't work for test_runner.py which is my usual interface), but makes sense to not change this behaviour here and leave as-is.

    Can be marked as resolved.


    maflcko commented at 5:35 AM on July 18, 2025:

    I kinda like seeing where it got interrupted

    Yeah, I realize it is useful to debug timeouts. Pushed a fresh commit for KeyboardInterrupt.

  3. maflcko added the label Tests on Jul 17, 2025
  4. maflcko force-pushed on Jul 17, 2025
  5. DrahtBot commented at 2:56 PM on July 17, 2025: contributor

    <!--e57a25ab6845829454e8d69fc972939a-->

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    <!--006a51241073e994b41acfe9ec718e94-->

    Code Coverage & Benchmarks

    For details see: https://corecheck.dev/bitcoin/bitcoin/pulls/33001.

    <!--021abf342d371248e50ceaed478a90ca-->

    Reviews

    See the guideline for information on the review process.

    Type Reviewers
    ACK stickies-v, pablomartin4btc, enirox001

    If your review is incorrectly listed, please react with πŸ‘Ž to this comment and the bot will ignore it on the next update.

    <!--5faf32d7da4f0f540f40219e4f7537a3-->

  6. test: Do not pass tests on unhandled exceptions
    This adds a missing catch for BaseException (e.g. SystemExit), which
    would otherwise be silently ignored.
    
    Also, remove the redundant other catches, which are just calling
    log.exception with a redundant log message.
    fa30b34026
  7. maflcko force-pushed on Jul 17, 2025
  8. DrahtBot added the label CI failed on Jul 17, 2025
  9. DrahtBot commented at 3:05 PM on July 17, 2025: contributor

    <!--85328a0da195eb286784d51f73fa0af9-->

    🚧 At least one of the CI tasks failed. <sub>Task lint: https://github.com/bitcoin/bitcoin/runs/46188973278</sub> <sub>LLM reason (✨ experimental): The test_framework code contains two lint errors related to unused variables and f-string formatting, which are detected by the linter and cause the CI failure.</sub>

    <details><summary>Hints</summary>

    Try to run the tests locally, according to the documentation. However, a CI failure may still happen due to a number of reasons, for example:

    • Possibly due to a silent merge conflict (the changes in this pull request being incompatible with the current code in the target branch). If so, make sure to rebase on the latest commit of the target branch.

    • A sanitizer issue, which can only be found by compiling with the sanitizer and running the affected test.

    • An intermittent issue.

    Leave a comment here, if you need help tracking down a confusing failure.

    </details>

  10. DrahtBot removed the label CI failed on Jul 17, 2025
  11. stickies-v approved
  12. stickies-v commented at 5:48 PM on July 17, 2025: contributor

    ACK fa30b34026f76a5b8af997152fced2d281782e0d

  13. test: Log KeyboardInterrupt as exception
    log.exception is more verbose and useful to debug timeouts.
    
    Also, log stderr for CalledProcessError to make debugging easier.
    faa3e68411
  14. stickies-v approved
  15. stickies-v commented at 10:10 AM on July 18, 2025: contributor

    re-ACK faa3e684118bffa7a98cf76eeeb59243219df900

  16. maflcko commented at 6:56 AM on July 21, 2025: member

    @OrangeDoro Every LLM generated point in your comment is wrong and completely misses the point. This is trivial to see, if you took a look at the previous comments and commit messages. (Please stop sharing LLM generated content that you didn't review or even understand yourself)

  17. pablomartin4btc approved
  18. pablomartin4btc commented at 9:24 PM on July 22, 2025: member

    tACK faa3e684118bffa7a98cf76eeeb59243219df900

    Managed to reproduce the issue with the patch provided in the PR description, this branch fixes it. Nice detail handling KeyboardInterrupt for debugging purpose. Code-wise refactoring: better reading removing redundant catches.

  19. enirox001 commented at 3:35 PM on July 23, 2025: contributor

    Looks good to meβ€”ACK faa3e68

    I verified both versions: before the patch the test passed erroneously, but with your changes it now fails as intended. This will be invaluable for debugging by ensuring unhandled exceptions surface as test failures.

  20. fanquake merged this on Jul 23, 2025
  21. fanquake closed this on Jul 23, 2025

  22. fanquake referenced this in commit 79e1a3c9c6 on Jul 23, 2025
  23. fanquake referenced this in commit 5e327e6703 on Jul 23, 2025
  24. fanquake commented at 4:03 PM on July 23, 2025: member

    Backported to 29.x in #33046.

  25. fanquake referenced this in commit 8063d55446 on Jul 24, 2025
  26. maflcko deleted the branch on Jul 24, 2025
  27. fanquake referenced this in commit a828e64b7d on Jul 28, 2025
  28. fanquake referenced this in commit 41fa1e0ee5 on Jul 28, 2025
  29. fanquake commented at 9:39 AM on July 28, 2025: member

    Backported to 28.x in #33076

  30. sedited referenced this in commit 02ded863ba on Jul 28, 2025
  31. sedited referenced this in commit 52d7f32bd6 on Jul 28, 2025
  32. fanquake referenced this in commit 5492e1be3b on Jul 30, 2025
  33. alexanderwiederin referenced this in commit 28fe919bf7 on Aug 6, 2025
  34. sedited referenced this in commit b98d982d79 on Aug 7, 2025
  35. alexanderwiederin referenced this in commit 4152176d02 on Aug 8, 2025
  36. alexanderwiederin referenced this in commit 9ef94c31db on Aug 8, 2025
  37. stringintech referenced this in commit 71275a1b5e on Aug 17, 2025
  38. yuvicc referenced this in commit 22f55cf11d on Aug 26, 2025
  39. ajtowns referenced this in commit b386d0c813 on Sep 4, 2025
  40. ajtowns referenced this in commit 7215b740c3 on Sep 4, 2025
  41. bug-castercv502 referenced this in commit 4aa5572aea on Sep 28, 2025
  42. stickies-v referenced this in commit a19c56cd7c on Nov 4, 2025
  43. tomt1664 referenced this in commit 68d6ca288b on Nov 25, 2025
  44. tomt1664 referenced this in commit b7ee5fb8a5 on Nov 25, 2025
  45. delta1 referenced this in commit 6664587c2f on Nov 27, 2025
  46. Fabcien referenced this in commit 8d19b4b2d4 on Jan 20, 2026
  47. morozow referenced this in commit a2ab979d20 on May 8, 2026
  48. morozow referenced this in commit 5dd92caf4e on May 8, 2026
  49. morozow referenced this in commit 076dd5e035 on May 8, 2026
  50. morozow referenced this in commit 1ad62d964f on May 8, 2026
  51. morozow referenced this in commit 251f26f599 on May 8, 2026
  52. morozow referenced this in commit a985b50ab9 on May 8, 2026
  53. roqqit referenced this in commit 3f6ea9bf93 on Jun 8, 2026
  54. Kino1994 referenced this in commit c3ed4ab28a on Jun 28, 2026
  55. BigcoinBGC referenced this in commit 7c02802b3a on Jun 30, 2026
  56. bitcoin locked this on Jul 30, 2026

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-08-10 22:51 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me