mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-04-23 13:29:43 +02:00
Merge #15382: util: add RunCommandParseJSON
31cf68a3ad[util] add RunCommandParseJSON (Sjors Provoost)c17f54ee53[ci] use boost::process (Sjors Provoost)32128ba682[doc] include Doxygen comments for HAVE_BOOST_PROCESS (Sjors Provoost)3c84d85f7d[build] msvc: add boost::process (Sjors Provoost)c47e4bbf0b[build] make boost-process opt-in (Sjors Provoost)929cda5470configure: add ax_boost_process (Sjors Provoost)8314c23d7b[depends] boost: patch unused variable in boost_process (Sjors Provoost) Pull request description: Prerequisite for external signer support in #16546. Big picture overview in [this gist](https://gist.github.com/Sjors/29d06728c685e6182828c1ce9b74483d). This adds a new dependency [boost process](https://github.com/boostorg/process/tree/boost-1.64.0). This is part of Boost since 1.64 which is part of `depends`. Because the minimum Boost version is 1.47, this functionality is skipped for older versions of Boost. Use `./configure --with-boost-process` to opt in, which checks for the presence of Boost::Process. We add `UniValue runCommandParseJSON(const std::string& strCommand)` to `system.{h,cpp}` which calls an arbitrary command and processes the JSON returned by it. This is currently only called by the test suite. ~For testing purposes this adds a new regtest-only RPC method `runcommand`, as well as `test/mocks/command.py` used by functional tests.~ (this is no longer the case) TODO: - [ ] review boost process in #15440 ACKs for top commit: achow101: ACK31cf68a3adhebasto: re-ACK31cf68a3ad, only rebased (verified with `git range-diff`) and removed an unintentional tab character since the [previous](https://github.com/bitcoin/bitcoin/pull/15382#pullrequestreview-458371035) review. meshcollider: Very light utACK31cf68a3ad, although I am not very confident with build stuff. promag: Code review ACK31cf68a3ad, don't mind the nit. ryanofsky: Code review ACK31cf68a3ad. I left some comments below that could be ignored or followed up later. The current change is clean and comprehensive. Tree-SHA512: c506e747014b263606e1f538ed4624a8ad7bcf4e025cb700c12cc5739964e254dc04a2bbb848996b170e2ccec3fbfa4fe9e2b3976b191222cfb82fc3e6ab182d
This commit is contained in:
95
src/test/system_tests.cpp
Normal file
95
src/test/system_tests.cpp
Normal file
@@ -0,0 +1,95 @@
|
||||
// Copyright (c) 2019 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
//
|
||||
#include <test/util/setup_common.h>
|
||||
#include <util/system.h>
|
||||
#include <univalue.h>
|
||||
|
||||
#ifdef HAVE_BOOST_PROCESS
|
||||
#include <boost/process.hpp>
|
||||
#endif // HAVE_BOOST_PROCESS
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
BOOST_FIXTURE_TEST_SUITE(system_tests, BasicTestingSetup)
|
||||
|
||||
// At least one test is required (in case HAVE_BOOST_PROCESS is not defined).
|
||||
// Workaround for https://github.com/bitcoin/bitcoin/issues/19128
|
||||
BOOST_AUTO_TEST_CASE(dummy)
|
||||
{
|
||||
BOOST_CHECK(true);
|
||||
}
|
||||
|
||||
#ifdef HAVE_BOOST_PROCESS
|
||||
|
||||
bool checkMessage(const std::runtime_error& ex)
|
||||
{
|
||||
// On Linux & Mac: "No such file or directory"
|
||||
// On Windows: "The system cannot find the file specified."
|
||||
const std::string what(ex.what());
|
||||
BOOST_CHECK(what.find("file") != std::string::npos);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool checkMessageFalse(const std::runtime_error& ex)
|
||||
{
|
||||
BOOST_CHECK_EQUAL(ex.what(), std::string("RunCommandParseJSON error: process(false) returned 1: \n"));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool checkMessageStdErr(const std::runtime_error& ex)
|
||||
{
|
||||
const std::string what(ex.what());
|
||||
BOOST_CHECK(what.find("RunCommandParseJSON error:") != std::string::npos);
|
||||
return checkMessage(ex);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(run_command)
|
||||
{
|
||||
{
|
||||
const UniValue result = RunCommandParseJSON("");
|
||||
BOOST_CHECK(result.isNull());
|
||||
}
|
||||
{
|
||||
#ifdef WIN32
|
||||
// Windows requires single quotes to prevent escaping double quotes from the JSON...
|
||||
const UniValue result = RunCommandParseJSON("echo '{\"success\": true}'");
|
||||
#else
|
||||
// ... but Linux and macOS echo a single quote if it's used
|
||||
const UniValue result = RunCommandParseJSON("echo \"{\"success\": true}\"");
|
||||
#endif
|
||||
BOOST_CHECK(result.isObject());
|
||||
const UniValue& success = find_value(result, "success");
|
||||
BOOST_CHECK(!success.isNull());
|
||||
BOOST_CHECK_EQUAL(success.getBool(), true);
|
||||
}
|
||||
{
|
||||
// An invalid command is handled by Boost
|
||||
BOOST_CHECK_EXCEPTION(RunCommandParseJSON("invalid_command"), boost::process::process_error, checkMessage); // Command failed
|
||||
}
|
||||
{
|
||||
// Return non-zero exit code, no output to stderr
|
||||
BOOST_CHECK_EXCEPTION(RunCommandParseJSON("false"), std::runtime_error, checkMessageFalse);
|
||||
}
|
||||
{
|
||||
// Return non-zero exit code, with error message for stderr
|
||||
BOOST_CHECK_EXCEPTION(RunCommandParseJSON("ls nosuchfile"), std::runtime_error, checkMessageStdErr);
|
||||
}
|
||||
{
|
||||
BOOST_REQUIRE_THROW(RunCommandParseJSON("echo \"{\""), std::runtime_error); // Unable to parse JSON
|
||||
}
|
||||
// Test std::in, except for Windows
|
||||
#ifndef WIN32
|
||||
{
|
||||
const UniValue result = RunCommandParseJSON("cat", "{\"success\": true}");
|
||||
BOOST_CHECK(result.isObject());
|
||||
const UniValue& success = find_value(result, "success");
|
||||
BOOST_CHECK(!success.isNull());
|
||||
BOOST_CHECK_EQUAL(success.getBool(), true);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif // HAVE_BOOST_PROCESS
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
Reference in New Issue
Block a user