/ src / test / system_tests.cpp
system_tests.cpp
 1  // Copyright (c) 2019-2022 The Bitcoin Core developers
 2  // Distributed under the MIT software license, see the accompanying
 3  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
 4  //
 5  
 6  #include <bitcoin-build-config.h> // IWYU pragma: keep
 7  #include <test/util/setup_common.h>
 8  #include <common/run_command.h>
 9  #include <univalue.h>
10  
11  #ifdef ENABLE_EXTERNAL_SIGNER
12  #include <util/subprocess.h>
13  #endif // ENABLE_EXTERNAL_SIGNER
14  
15  #include <boost/test/unit_test.hpp>
16  
17  BOOST_FIXTURE_TEST_SUITE(system_tests, BasicTestingSetup)
18  
19  #ifdef ENABLE_EXTERNAL_SIGNER
20  
21  BOOST_AUTO_TEST_CASE(run_command)
22  {
23      {
24          const UniValue result = RunCommandParseJSON("");
25          BOOST_CHECK(result.isNull());
26      }
27      {
28  #ifdef WIN32
29          const UniValue result = RunCommandParseJSON("cmd.exe /c echo {\"success\": true}");
30  #else
31          const UniValue result = RunCommandParseJSON("echo {\"success\": true}");
32  #endif
33          BOOST_CHECK(result.isObject());
34          const UniValue& success = result.find_value("success");
35          BOOST_CHECK(!success.isNull());
36          BOOST_CHECK_EQUAL(success.get_bool(), true);
37      }
38      {
39          // An invalid command is handled by cpp-subprocess
40  #ifdef WIN32
41          const std::string expected{"CreateProcess failed: "};
42  #else
43          const std::string expected{"execve failed: "};
44  #endif
45          BOOST_CHECK_EXCEPTION(RunCommandParseJSON("invalid_command"), subprocess::CalledProcessError, HasReason(expected));
46      }
47      {
48          // Return non-zero exit code, no output to stderr
49  #ifdef WIN32
50          const std::string command{"cmd.exe /c exit 1"};
51  #else
52          const std::string command{"false"};
53  #endif
54          BOOST_CHECK_EXCEPTION(RunCommandParseJSON(command), std::runtime_error, [&](const std::runtime_error& e) {
55              const std::string what{e.what()};
56              BOOST_CHECK(what.find(strprintf("RunCommandParseJSON error: process(%s) returned 1: \n", command)) != std::string::npos);
57              return true;
58          });
59      }
60      {
61          // Return non-zero exit code, with error message for stderr
62  #ifdef WIN32
63          const std::string command{"cmd.exe /c \"echo err 1>&2 && exit 1\""};
64  #else
65          const std::string command{"sh -c 'echo err 1>&2 && false'"};
66  #endif
67          const std::string expected{"err"};
68          BOOST_CHECK_EXCEPTION(RunCommandParseJSON(command), std::runtime_error, [&](const std::runtime_error& e) {
69              const std::string what(e.what());
70              BOOST_CHECK(what.find(strprintf("RunCommandParseJSON error: process(%s) returned", command)) != std::string::npos);
71              BOOST_CHECK(what.find(expected) != std::string::npos);
72              return true;
73          });
74      }
75      {
76          // Unable to parse JSON
77  #ifdef WIN32
78          const std::string command{"cmd.exe /c echo {"};
79  #else
80          const std::string command{"echo {"};
81  #endif
82          BOOST_CHECK_EXCEPTION(RunCommandParseJSON(command), std::runtime_error, HasReason("Unable to parse JSON: {"));
83      }
84  #ifndef WIN32
85      {
86          // Test stdin
87          const UniValue result = RunCommandParseJSON("cat", "{\"success\": true}");
88          BOOST_CHECK(result.isObject());
89          const UniValue& success = result.find_value("success");
90          BOOST_CHECK(!success.isNull());
91          BOOST_CHECK_EQUAL(success.get_bool(), true);
92      }
93  #endif
94  }
95  #endif // ENABLE_EXTERNAL_SIGNER
96  
97  BOOST_AUTO_TEST_SUITE_END()