Repository: bitcoin/bitcoin (language: cpp)

Issue:
test: "system_tests/run_command" unit test fails with different locale
The issue from yesterday was closed (https://github.com/bitcoin/bitcoin/issues/30601#event-13795338265), so opening a new issue for this, because the workaround does not fix the issue.

The error is:

```
test/system_tests.cpp(88): error: in "system_tests/run_command": check what.find(expected) != std::string::npos has failed 
```

As a temporary workaround, one can try `--disable-external-signer`, if they don't need it. Alternatively, they can set a different locale, for just the tests.

A fix would be something like https://github.com/bitcoin/bitcoin/pull/28286, if someone wants to pick that up.


Discussion / hints:

Fix patch:
diff --git a/depends/packages/libevent.mk b/depends/packages/libevent.mk
index 24e940eaa0dcb..4c05e8a0a7425 100644
--- a/depends/packages/libevent.mk
+++ b/depends/packages/libevent.mk
@@ -14,6 +14,7 @@ define $(package)_set_vars
   $(package)_config_opts=-DEVENT__DISABLE_BENCHMARK=ON -DEVENT__DISABLE_OPENSSL=ON
   $(package)_config_opts+=-DEVENT__DISABLE_SAMPLES=ON -DEVENT__DISABLE_REGRESS=ON
   $(package)_config_opts+=-DEVENT__DISABLE_TESTS=ON -DEVENT__LIBRARY_TYPE=STATIC
+  $(package)_cppflags += -D_GNU_SOURCE
   $(package)_cppflags_mingw32=-D_WIN32_WINNT=0x0601
 
   ifeq ($(NO_HARDEN),)


Test patch:
diff --git a/src/test/system_tests.cpp b/src/test/system_tests.cpp
index baa759e42c26b..07d15f5552bb6 100644
--- a/src/test/system_tests.cpp
+++ b/src/test/system_tests.cpp
@@ -54,8 +54,8 @@ BOOST_AUTO_TEST_CASE(run_command)
     }
     {
         // Return non-zero exit code, with error message for stderr
-        const std::string command{"ls nosuchfile"};
-        const std::string expected{"No such file or directory"};
+        const std::string command{"python3 -c 'import sys; print(\"err\", file=sys.stderr); sys.exit(2)'"};
+        const std::string expected{"err"};
         BOOST_CHECK_EXCEPTION(RunCommandParseJSON(command), std::runtime_error, [&](const std::runtime_error& e) {
             const std::string what(e.what());
             BOOST_CHECK(what.find(strprintf("RunCommandParseJSON error: process(%s) returned", command)) != std::string::npos);
diff --git a/test/functional/p2p_headers_sync_with_minchainwork.py b/test/functional/p2p_headers_sync_with_minchainwork.py
index 9055232cf316a..6e7b4b399e518 100755
--- a/test/functional/p2p_headers_sync_with_minchainwork.py
+++ b/test/functional/p2p_headers_sync_with_minchainwork.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python3
-# Copyright (c) 2019-2022 The Bitcoin Core developers
+# Copyright (c) 2019-present The Bitcoin Core developers
 # Distributed under the MIT software license, see the accompanying
 # file COPYING or http://www.opensource.org/licenses/mit-license.php.
 """Test that we reject low difficulty headers to prevent our block tree from filling up with useless bloat"""
@@ -21,6 +21,8 @@
 
 from test_framework.util import assert_equal
 
+import time
+
 NODE1_BLOCKS_REQUIRED = 15
 NODE2_BLOCKS_REQUIRED = 2047
 
@@ -48,6 +50,10 @@ def reconnect_all(self):
         self.connect_nodes(0, 2)
         self.connect_nodes(0, 3)
 
+    def mocktime_all(self, time):
+        for n in self.nodes:
+            n.setmocktime(time)
+
     def test_chains_sync_when_long_enough(self):
         self.log.info("Generate blocks on the node with no required chainwork, and verify nodes 1 and 2 have no new headers in their headers tree")
         with self.nodes[1].assert_debug_log(expected_msgs=["[net] Ignoring low-work chain (height=14)"]), self.nodes[2].assert_debug_log(expected_msgs=["[net] Ignoring low-work chain (height=14)"]), self.nodes[3].assert_debug_log(expected_msgs=["Synchronizing blockheaders, height: 14"]):
@@ -149,7 +155,9 @@ def test_large_reorgs_can_succeed(self):
 
         self.reconnect_all()
 
+        self.mocktime_all(int(time.time()))  # Temporarily hold time to avoid internal timeouts
         self.sync_blocks(timeout=300) # Ensure tips eventually agree
+        self.mocktime_all(0)
 
 
     def run_test(self):
diff --git a/test/functional/test_framework/test_shell.py b/test/functional/test_framework/test_shell.py
index 09ccec28a1aa6..e232430507b76 100644
--- a/test/functional/test_framework/test_shell.py
+++ b/test/functional/test_framework/test_shell.py
@@ -2,9 +2,11 @@
 # Copyright (c) 2019-2022 The Bitcoin Core developers
 # Distributed under the MIT software license, see the accompanying
 # file COPYING or http://www.opensource.org/licenses/mit-license.php.
+import pathlib
 
 from test_framework.test_framework import BitcoinTestFramework
 
+
 class TestShell:
     """Wrapper Class for BitcoinTestFramework.
 
@@ -67,7 +69,13 @@ def __new__(cls):
         # This implementation enforces singleton pattern, and will return the
         # previously initialized instance if available
         if not TestShell.instance:
-            TestShell.instance = TestShell.__TestShell()
+            # BitcoinTestFramework instances are supposed to be constructed with the path
+            # of the calling test in order to find shared data like configuration and the
+            # cache. Since TestShell is meant for interactive use, there is no concrete
+            # test; passing a dummy name is fine though, as only the containing directory
+            # is relevant for successful initialization.
+            tests_directory = pathlib.Path(__file__).resolve().parent.parent
+            TestShell.instance = TestShell.__TestShell(tests_directory / "testshell_dummy.py")
             TestShell.instance.running = False
         return TestShell.instance