test: add interface_gui.py to test bitcoin-qt startup #35551

pull ryanofsky wants to merge 1 commits into bitcoin:master from ryanofsky:pr/guistart changing 8 files +79 −8
  1. ryanofsky commented at 6:55 PM on June 17, 2026: contributor

    Adds a functional test that starts bitcoin-qt using QT_QPA_PLATFORM=minimal for headless operation, then verifies it responds to a stop RPC call. This detects startup crashes in the GUI that have no CI coverage today like https://github.com/bitcoin-core/gui/issues/940

    The new test is currently skipped on macos and windows due to different problems on those platforms that may be resolved with future PRs. Fixing the windows issue should also allow the tool_bitcoin.py test to be enabled on windows, and fixing the macos issue should allow Qt addressbook and wallet tests to be enabled on macos.

  2. DrahtBot added the label Tests on Jun 17, 2026
  3. DrahtBot commented at 6:55 PM on June 17, 2026: 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/35551.

    <!--021abf342d371248e50ceaed478a90ca-->

    Reviews

    See the guideline for information on the review process.

    Type Reviewers
    ACK sedited, pablomartin4btc
    Concept ACK hebasto

    If your review is incorrectly listed, please copy-paste <code>&lt;!--meta-tag:bot-skip--&gt;</code> into the comment that the bot should ignore.

    <!--174a7506f384e20aa4161008e828411d-->

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #30437 (ipc: add bitcoin-mine test program by ryanofsky)

    If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

    <!--5faf32d7da4f0f540f40219e4f7537a3-->

  4. sedited commented at 7:01 PM on June 17, 2026: contributor

    Concept ACK

  5. pablomartin4btc commented at 7:45 PM on June 17, 2026: member

    Concept ACK

    It seems that the offscreen platform plugin isn't available in all CI environments, perhaps adding -feature-offscreen to depends/packages/qt.mk fixes it.

  6. DrahtBot added the label CI failed on Jun 17, 2026
  7. in test/functional/interface_gui.py:19 in 0d0f797419 outdated
      14 | +
      15 | +    def skip_test_if_missing_module(self):
      16 | +        self.skip_if_no_gui()
      17 | +
      18 | +    def setup_nodes(self):
      19 | +        self.extra_init = [{"use_gui": True}]
    


    maflcko commented at 6:05 AM on June 18, 2026:

    I wonder if this should be a test-level option, similar to --usecli, so that all tests can be run under the gui (modulo those that ask a question or show a message box with an error or warning)?


    ryanofsky commented at 12:50 AM on June 26, 2026:

    re: #35551 (review)

    I wonder if this should be a test-level option, similar to --usecli, so that all tests can be run under the gui (modulo those that ask a question or show a message box with an error or warning)?

    This seems like a nice idea for a followup. I think strictly speaking it isn't necessary because you can use environment variables to run other tests under the GUI like:

    QT_QPA_PLATFORM=minimal BITCOIND=bitcoin-qt build/test/functional/example_test.py
    

    but a new option could be more convenient or help customize test behavior.

  8. in test/functional/test_framework/test_node.py:285 in 0d0f797419
     280 | @@ -279,6 +281,8 @@ def start(self, extra_args=None, *, cwd=None, stdout=None, stderr=None, env=None
     281 |  
     282 |          # add environment variable LIBC_FATAL_STDERR_=1 so that libc errors are written to stderr and not the terminal
     283 |          subp_env = dict(os.environ, LIBC_FATAL_STDERR_="1")
     284 | +        if self.use_gui:
     285 | +            subp_env.setdefault("QT_QPA_PLATFORM", "offscreen")
    


    maflcko commented at 6:08 AM on June 18, 2026:

    Could also set something like LC_ALL=nl_NL.UTF-8 to check the RPC response is not translated by accident?


    ryanofsky commented at 12:55 AM on June 26, 2026:

    re: #35551 (review)

    Could also set something like LC_ALL=nl_NL.UTF-8 to check the RPC response is not translated by accident?

    Good idea, added environment variable to try to trigger translation bugs if they are present. I didn't add any new RPC calls or checks, because I wasn't sure what good candidates might be, but just setting variable could help make problems more obvious in the future.

  9. hebasto commented at 8:23 AM on June 18, 2026: member

    Concept ACK.

    It seems that the offscreen platform plugin isn't available ...

    --- a/src/qt/CMakeLists.txt
    +++ b/src/qt/CMakeLists.txt
    @@ -16,6 +16,7 @@ get_target_property(qt_lib_type Qt6::Core TYPE)
     function(import_plugins target)
       if(qt_lib_type STREQUAL "STATIC_LIBRARY")
         set(plugins Qt6::QMinimalIntegrationPlugin)
    +    list(APPEND plugins Qt6::QOffscreenIntegrationPlugin)
         if(CMAKE_SYSTEM_NAME MATCHES "^(Linux|FreeBSD)$")
           list(APPEND plugins Qt6::QXcbIntegrationPlugin)
         elseif(WIN32)
    ```
    
  10. test: add interface_gui.py to test bitcoin-gui startup via RPC
    Adds a functional test that starts bitcoin-gui (via the bitcoin wrapper
    with "gui" subcommand) using QT_QPA_PLATFORM=minimal for headless
    operation, then verifies it responds to a stop RPC call. This catches
    startup regressions in the GUI that have no CI coverage today.
    
    Extends the test framework to support use_gui=True in TestNode, which
    invokes "bitcoin gui" instead of "bitcoin node" and automatically sets
    QT_QPA_PLATFORM=minimal. Adds BUILD_GUI to test/config.ini.in and
    is_gui_compiled()/skip_if_no_gui() helpers to BitcoinTestFramework.
    
    Co-Authored-By: MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz>
    Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
    aa01721c89
  11. ryanofsky force-pushed on Jun 26, 2026
  12. ryanofsky commented at 1:04 AM on June 26, 2026: contributor

    Thanks for the suggestions! I wound up switching from offscreen to minimal backend, since it seems like minimal can work with a small tweak to LoadFont.

    <!-- begin push-2 -->

    Rebased 0d0f7974193f94715a96f7f4c82f7b8d39bcf585 -> c5db4557256e208ac9268a071d28a1fa05ec6061 (pr/guistart.1 -> pr/guistart.2, compare)<!-- end --> switching QT_QPA_PLATFORM from offscreen to minimal to fix various CI jobs (https://github.com/bitcoin/bitcoin/actions/runs/27712423591/job/81976587629), fixing guiutil LoadFont assert under minimal, fixing BUILD_GUI cmake var so TSan/MSan skip the test (https://github.com/bitcoin/bitcoin/actions/runs/27712423591/job/81976587665), and rebasing after #35549 to fix macos CI failure (https://github.com/bitcoin/bitcoin/actions/runs/27712423591/job/81976587391)

    <!-- begin push-3 -->

    Updated c5db4557256e208ac9268a071d28a1fa05ec6061 -> cb3f9c2ea83b01259623496abe12f26f6a97552b (pr/guistart.2 -> pr/guistart.3, compare)<!-- end --> to fix Windows (bitcoin-gui.exe wrapper exits before bitcoin-qt starts) and Linux CI (XDG_RUNTIME_DIR not set causes unexpected stderr) https://github.com/bitcoin/bitcoin/actions/runs/28210333880/job/83570053295

    <!-- begin push-4 -->

    Updated cb3f9c2ea83b01259623496abe12f26f6a97552b -> fc0d350025505dd3819e3dfc5a0d88693ac96338 (pr/guistart.3 -> pr/guistart.4, compare)<!-- end --> to fix remaining CI failures: fix XDG_RUNTIME_DIR permissions (create 0700 subdir — Qt also warns when dir has 0755) https://github.com/bitcoin/bitcoin/actions/runs/28212198960/job/83575751969, and skip test on macOS (two CI crash modes: ConnectionResetError from apparent external signal and SIGSEGV in Qt window init) https://github.com/bitcoin/bitcoin/actions/runs/28212198960/job/83575751965

  13. ryanofsky marked this as ready for review on Jun 26, 2026
  14. ryanofsky force-pushed on Jun 26, 2026
  15. ryanofsky force-pushed on Jun 26, 2026
  16. DrahtBot removed the label CI failed on Jun 26, 2026
  17. in test/functional/test_framework/util.py:312 in fc0d350025
     310 |          """Return argv array that should be used to invoke the command.
     311 |  
     312 | -        It either uses the bitcoin wrapper executable (if BITCOIN_CMD is set or
     313 | -        need_ipc is True), or the direct binary path (bitcoind, etc). When
     314 | +        It either uses the bitcoin wrapper executable (if BITCOIN_CMD, need_ipc,
     315 | +        or need_gui are set), or the direct binary path (bitcoind, etc). When
    


    pablomartin4btc commented at 3:05 PM on June 26, 2026:

    nit:

            or use_gui are set), or the direct binary path (bitcoind, etc). When
    

    ryanofsky commented at 2:18 PM on July 6, 2026:

    re: #35551 (review)

    Thanks! Fixed comment

  18. in test/functional/test_framework/test_node.py:285 in fc0d350025 outdated
     279 | @@ -278,6 +280,20 @@ def start(self, extra_args=None, *, cwd=None, stdout=None, stderr=None, env=None
     280 |  
     281 |          # add environment variable LIBC_FATAL_STDERR_=1 so that libc errors are written to stderr and not the terminal
     282 |          subp_env = dict(os.environ, LIBC_FATAL_STDERR_="1")
     283 | +        if self.use_gui:
     284 | +            subp_env.setdefault("QT_QPA_PLATFORM", "minimal")
     285 | +            subp_env.setdefault("LC_ALL", "nl_NL.UTF-8") # Set language to try to trigger translation bugs
    


    pablomartin4btc commented at 3:06 PM on June 26, 2026:

    out of curiosity, why nl_NL specifically? any non-English locale would work?


    ryanofsky commented at 2:20 PM on July 6, 2026:

    re: #35551 (review)

    out of curiosity, why nl_NL specifically? any non-English locale would work?

    This was suggested #35551 (review) but I'm guessing the idea is to choose a locale that has more translated strings, because if you choose one where most strings aren't translated, problems might not be detected.

  19. pablomartin4btc commented at 3:20 PM on June 26, 2026: member

    ACK fc0d350025505dd3819e3dfc5a0d88693ac96338

    nit: the commit message and PR description still reference offscreen but the implementation now uses minimal. Also worth noting that both Windows and macOS are currently skipped, perhaps would be good to track follow-up issues for those platforms in the PR description?

  20. DrahtBot requested review from hebasto on Jun 26, 2026
  21. DrahtBot requested review from sedited on Jun 26, 2026
  22. in src/qt/guiutil.cpp:291 in fc0d350025 outdated
     289 | @@ -290,6 +290,8 @@ bool hasEntryData(const QAbstractItemView *view, int column, int role)
     290 |  
     291 |  void LoadFont(const QString& file_name)
    


    sedited commented at 7:28 PM on June 29, 2026:

    In commit fc0d350025505dd3819e3dfc5a0d88693ac96338:

    Is the commit message stale? This mentions "offscreen" being set, but we set "minimal" here.


    ryanofsky commented at 2:23 PM on July 6, 2026:

    re: #35551 (review)

    Is the commit message stale? This mentions "offscreen" being set, but we set "minimal" here.

    Yes this was originally using offscreen, which worked well on my system, but didn't seem to work on CI. (Using offscreen made the PR a little simpler because it didn't require the LoadFont change, so that was the reason for choosing it.)

  23. DrahtBot requested review from sedited on Jun 29, 2026
  24. in test/functional/interface_gui.py:39 in fc0d350025
      34 | +        #    from macOS process management (launchd, jetsam, or CI runner) killing the
      35 | +        #    process.
      36 | +        # 2. FailedToStartError: [node 0] bitcoind exited with status -11 (SIGSEGV) — the
      37 | +        #    process crashes ~193ms after window->show() is called (after
      38 | +        #    "This plugin does not support propagateSizeHints()" is logged), suggesting a
      39 | +        #    crash in Qt's macOS Cocoa/minimal-plugin initialization.
    



    hebasto commented at 5:25 PM on July 1, 2026:

    Here is a proposed fix for this case, including some related cleanups (feel free to grab any part of it):

    diff --git a/src/qt/macdockiconhandler.mm b/src/qt/macdockiconhandler.mm
    index b7b1b98eef..1b62032c1e 100644
    --- a/src/qt/macdockiconhandler.mm
    +++ b/src/qt/macdockiconhandler.mm
    @@ -20,7 +20,8 @@ bool dockClickHandler(id self, SEL _cmd, ...) {
     }
     
     void setupDockClickHandler() {
    -    Class delClass = (Class)[[[NSApplication sharedApplication] delegate] class];
    +    if (NSApp == nil) return;
    +    Class delClass = (Class)[[NSApp delegate] class];
         SEL shouldHandle = sel_registerName("applicationShouldHandleReopen:hasVisibleWindows:");
         class_replaceMethod(delClass, shouldHandle, (IMP)dockClickHandler, "B@:");
     }
    @@ -49,5 +50,6 @@ void setupDockClickHandler() {
      */
     void ForceActivation()
     {
    -    [[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
    +    if (NSApp == nil) return;
    +    [NSApp activateIgnoringOtherApps:YES];
     }
    diff --git a/src/qt/test/addressbooktests.cpp b/src/qt/test/addressbooktests.cpp
    index 58b8a6d2ea..fae94ef0f7 100644
    --- a/src/qt/test/addressbooktests.cpp
    +++ b/src/qt/test/addressbooktests.cpp
    @@ -212,16 +212,5 @@ void TestAddAddressesToSendBook(interfaces::Node& node)
     
     void AddressBookTests::addressBookTests()
     {
    -#ifdef Q_OS_MACOS
    -    if (QApplication::platformName() == "minimal") {
    -        // Disable for mac on "minimal" platform to avoid crashes inside the Qt
    -        // framework when it tries to look up unimplemented cocoa functions,
    -        // and fails to handle returned nulls
    -        // (https://bugreports.qt.io/browse/QTBUG-49686).
    -        qWarning() << "Skipping AddressBookTests on mac build with 'minimal' platform set due to Qt bugs. To run AppTests, invoke "
    -                      "with 'QT_QPA_PLATFORM=cocoa test_bitcoin-qt' on mac, or else use a linux or windows build.";
    -        return;
    -    }
    -#endif
         TestAddAddressesToSendBook(m_node);
     }
    diff --git a/src/qt/test/apptests.cpp b/src/qt/test/apptests.cpp
    index 752c877381..7802696d5f 100644
    --- a/src/qt/test/apptests.cpp
    +++ b/src/qt/test/apptests.cpp
    @@ -54,18 +54,6 @@ void TestRpcCommand(RPCConsole* console)
     //! Entry point for BitcoinApplication tests.
     void AppTests::appTests()
     {
    -#ifdef Q_OS_MACOS
    -    if (QApplication::platformName() == "minimal") {
    -        // Disable for mac on "minimal" platform to avoid crashes inside the Qt
    -        // framework when it tries to look up unimplemented cocoa functions,
    -        // and fails to handle returned nulls
    -        // (https://bugreports.qt.io/browse/QTBUG-49686).
    -        qWarning() << "Skipping AppTests on mac build with 'minimal' platform set due to Qt bugs. To run AppTests, invoke "
    -                      "with 'QT_QPA_PLATFORM=cocoa test_bitcoin-qt' on mac, or else use a linux or windows build.";
    -        return;
    -    }
    -#endif
    -
         qRegisterMetaType<interfaces::BlockAndHeaderTipInfo>("interfaces::BlockAndHeaderTipInfo");
         m_app.parameterSetup();
         QVERIFY(m_app.createOptionsModel(/*resetSettings=*/true));
    diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp
    index a2983c2397..af620b6738 100644
    --- a/src/qt/test/wallettests.cpp
    +++ b/src/qt/test/wallettests.cpp
    @@ -455,16 +455,5 @@ void TestGUI(interfaces::Node& node)
     
     void WalletTests::walletTests()
     {
    -#ifdef Q_OS_MACOS
    -    if (QApplication::platformName() == "minimal") {
    -        // Disable for mac on "minimal" platform to avoid crashes inside the Qt
    -        // framework when it tries to look up unimplemented cocoa functions,
    -        // and fails to handle returned nulls
    -        // (https://bugreports.qt.io/browse/QTBUG-49686).
    -        qWarning() << "Skipping WalletTests on mac build with 'minimal' platform set due to Qt bugs. To run AppTests, invoke "
    -                      "with 'QT_QPA_PLATFORM=cocoa test_bitcoin-qt' on mac, or else use a linux or windows build.";
    -        return;
    -    }
    -#endif
         TestGUI(m_node);
     }
    

    ryanofsky commented at 2:29 PM on July 6, 2026:

    re: #35551 (review)

    Here is a proposed fix for this case, including some related cleanups (feel free to grab any part of it):

    Looks promising! Since the main goal of the PR is just to catch GUI-specific bitcoin startup errors in CI and running the test on linux is sufficient to do this, I want to avoid making this PR more complicated or asking reviewers to review platform-specific fixes they might not have familiarity with.

    Also should point out there were two different failures that seemed to happen on macos. The first one was a ConnectionResetError error where it seemed like the GUI process might just be shutting down early instead of crashing (https://github.com/bitcoin/bitcoin/actions/runs/28210333880/job/83570053149#step:9:3855), and the second was was a "bitcoind exited with status -11" crash (https://github.com/bitcoin/bitcoin/actions/runs/28212198960/job/83575751965#step:9:4017).

    But it looks your change could potentially address both and be a good followup to enable this test and others on macos. And it looks like another change might be possible on windows to enable this test and the tool_bitcoin.py test there:

    --- a/src/util/exec.cpp
    +++ b/src/util/exec.cpp
    @@ -38,7 +38,9 @@ int ExecVp(const char* file, char* const argv[])
         new_argv.reserve(escaped_args.size() + 1);
         for (const auto& s : escaped_args) new_argv.push_back(s.c_str());
         new_argv.push_back(nullptr);
    -    return _wexecvp(converter.from_bytes(file).c_str(), new_argv.data());
    +    int result{_wspawnvp(_P_WAIT, converter.from_bytes(file).c_str(), new_argv.data())};
    +    if (result == -1) return -1;
    +    std::exit(result);
     #endif
     }
     
    
  25. DrahtBot requested review from hebasto on Jul 1, 2026
  26. DrahtBot requested review from hebasto on Jul 1, 2026
  27. ryanofsky force-pushed on Jul 6, 2026
  28. ryanofsky commented at 2:43 PM on July 6, 2026: contributor

    re: #35551#pullrequestreview-4580478980

    PR description still reference offscreen but the implementation now uses minimal. Also worth noting that both Windows and macOS are currently skipped, perhaps would be good to track follow-up issues for those platforms in the PR description?

    Thanks! Removed all old references to offscreen and also mentioned the disabled platforms in the PR description.


    <!-- begin push-5 -->

    Updated fc0d350025505dd3819e3dfc5a0d88693ac96338 -> aa01721c8994fe188f5998a0e397b9a2004f3215 (pr/guistart.4 -> pr/guistart.5, compare)<!-- end --> just fixing up comments and error messages

  29. sedited approved
  30. sedited commented at 3:32 PM on July 6, 2026: contributor

    ACK aa01721c8994fe188f5998a0e397b9a2004f3215

    I'm still not sure about giving a chatbot attribution. If I apply a clang-tidy fixup I also don't give the clang developers attribution, but maybe that is a bad comparison?

  31. DrahtBot requested review from pablomartin4btc on Jul 6, 2026
  32. in test/functional/test_framework/test_framework.py:1170 in aa01721c89
    1164 | @@ -1160,6 +1165,10 @@ def is_ipc_compiled(self):
    1165 |          """Checks whether ipc was compiled."""
    1166 |          return self.config["components"].getboolean("ENABLE_IPC")
    1167 |  
    1168 | +    def is_gui_compiled(self):
    1169 | +        """Checks whether the GUI was compiled."""
    1170 | +        return self.config["components"].getboolean("BUILD_GUI", fallback=False)
    


    maflcko commented at 7:22 AM on July 7, 2026:

    not sure about the fallback value here. You are trying to imply it is possible to run the tests without compiling Bitcoin Core. However, this is already not supported and broken: Many tests are regression tests and will fail without compiling Bitcoin Core.

    Going further, the test added in this pull request will require re-compiling Bitcoin Core, because it is otherwise lacking the src/qt/guiutil.cpp fix.

    Finally, this is inconsistent with all other build options, and adding more ways the tests can silently skip doesn't seem great when the whole point of the tests are to run.

  33. maflcko commented at 7:50 AM on July 7, 2026: member

    I'm still not sure about giving a chatbot attribution.

    I agree here, and I think there are several issues:

    • Giving co-authorship for every minimal fixup seems too extreme. E.g. I ended up as co-author because I suggested a minimal nl_NL fixup. This is fine, but I think (co-)authors should be limited to people that substantially understand the authored diff. This way, when a bug is later noticed, it is clear who to ask for review on the bugfix pull request. That is: Mostly the original author(s), as well as all reviewers can be considered to for a ping for review in the future.
    • Giving attribution to an LLM bot to me reads like an excuse: "I don't care about the code changes here, and I didn't want to understand them fully myself, so I added this disclaimer, so that issues can be plausibly dismissed as ai slop by a random third party tool"

    I think it would be better to only add co-authors if they are real co-authors that fully understand the changes in the commit.

    Going even further, I am not sure if LLM bots are the right tool to write tests. Instead of meaningfully expanding existing tests, they often tend to write new test cases in an append-only fashion: (e.g. https://www.github.com/bitcoin/bitcoin/pull/35281#pullrequestreview-4635181464). Also, they tend to prefer tests that silently do nothing or silently skip over what the tests are supposed to test (E.g #34494 (comment), or somewhat this pull request, see my review comment)

    I think it would be better to just write the changes here by hand, given that they are simple enough, instead of relying on the LLM auto-completion style odd patterns and having to fix them up afterward.


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-07-09 06:47 UTC