2#include <test/jtx/JSONRPCClient.h> 
    3#include <test/jtx/WSClient.h> 
    4#include <test/jtx/envconfig.h> 
    6#include <xrpld/app/ledger/LedgerMaster.h> 
    7#include <xrpld/app/misc/LoadFeeTrack.h> 
    8#include <xrpld/app/misc/NetworkOPs.h> 
    9#include <xrpld/rpc/ServerHandler.h> 
   11#include <xrpl/basics/base64.h> 
   12#include <xrpl/beast/test/yield_to.h> 
   13#include <xrpl/json/json_reader.h> 
   15#include <boost/algorithm/string/predicate.hpp> 
   16#include <boost/asio.hpp> 
   17#include <boost/asio/io_context.hpp> 
   18#include <boost/asio/ssl.hpp> 
   19#include <boost/beast/core/multi_buffer.hpp> 
   20#include <boost/beast/http.hpp> 
   33    class myFields : 
public boost::beast::http::fields
 
 
   41        bool credentials = 
false)
 
   43        auto const section_name =
 
   44            boost::starts_with(proto, 
"h") ? 
"port_rpc" : 
"port_ws";
 
   47        p->overwrite(section_name, 
"protocol", proto);
 
   49            p->overwrite(section_name, 
"admin", 
"");
 
   53            (*p)[section_name].set(
"admin_password", 
"p");
 
   54            (*p)[section_name].set(
"admin_user", 
"u");
 
   58            boost::starts_with(proto, 
"h") ? 
"port_ws" : 
"port_rpc",
 
   60            boost::starts_with(proto, 
"h") ? 
"ws" : 
"http");
 
   67            (*p)[
"server"].append(
"port_alt");
 
   69            (*p)[
"port_alt"].set(
"port", 
"7099");
 
   70            (*p)[
"port_alt"].set(
"protocol", 
"http");
 
 
   81        using namespace boost::beast::http;
 
   82        request<string_body> req;
 
   87        req.insert(
"User-Agent", 
"test");
 
   88        req.method(boost::beast::http::verb::get);
 
   89        req.insert(
"Upgrade", 
"websocket");
 
  101        req.insert(
"Sec-WebSocket-Version", 
"13");
 
  102        req.insert(boost::beast::http::field::connection, 
"upgrade");
 
 
  114        using namespace boost::beast::http;
 
  115        request<string_body> req;
 
  119        for (
auto const& f : fields)
 
  120            req.insert(f.name(), f.value());
 
  122        req.insert(
"User-Agent", 
"test");
 
  125            req.method(boost::beast::http::verb::get);
 
  129            req.method(boost::beast::http::verb::post);
 
  130            req.insert(
"Content-Type", 
"application/json; charset=UTF-8");
 
  133        req.prepare_payload();
 
 
  140        boost::asio::yield_context& yield,
 
  141        boost::beast::http::request<boost::beast::http::string_body>&& req,
 
  145        boost::beast::http::response<boost::beast::http::string_body>& resp,
 
  146        boost::system::error_code& ec)
 
  149        using namespace boost::beast::http;
 
  151        ip::tcp::resolver r{ios};
 
  152        boost::beast::multi_buffer sb;
 
  161            ssl::context ctx{ssl::context::sslv23};
 
  162            ctx.set_verify_mode(ssl::verify_none);
 
  163            ssl::stream<ip::tcp::socket> ss{ios, ctx};
 
  164            async_connect(ss.next_layer(), it, yield[ec]);
 
  167            ss.async_handshake(ssl::stream_base::client, yield[ec]);
 
  170            boost::beast::http::async_write(ss, req, yield[ec]);
 
  173            async_read(ss, sb, resp, yield[ec]);
 
  179            ip::tcp::socket sock{ios};
 
  180            async_connect(sock, it, yield[ec]);
 
  183            boost::beast::http::async_write(sock, req, yield[ec]);
 
  186            async_read(sock, sb, resp, yield[ec]);
 
 
  197        boost::asio::yield_context& yield,
 
  199        boost::beast::http::response<boost::beast::http::string_body>& resp,
 
  200        boost::system::error_code& ec)
 
  206            yield, 
makeWSUpgrade(*ip, *port), *ip, *port, secure, resp, ec);
 
 
  213        boost::asio::yield_context& yield,
 
  215        boost::beast::http::response<boost::beast::http::string_body>& resp,
 
  216        boost::system::error_code& ec,
 
 
  240        bool subobject = 
false)
 
  247            jp[
"admin_user"] = user;
 
  252                jpi[
"admin_password"] = password;
 
  253                jp[
"admin_password"] = jpi;
 
  257                jp[
"admin_password"] = password;
 
  261        if (boost::starts_with(proto, 
"h"))
 
  264            jrr = jrc->invoke(
"ledger_accept", jp);
 
  269            jrr = wsc->invoke(
"ledger_accept", jp);
 
 
  282        testcase << 
"Admin request over " << proto << 
", config " 
  283                 << (admin ? 
"enabled" : 
"disabled") << 
", credentials " 
  284                 << (credentials ? 
"" : 
"not ") << 
"set";
 
  289        auto const proto_ws = boost::starts_with(proto, 
"w");
 
  294        if (admin && credentials)
 
  296            auto const user = env.
app()
 
  297                                  .
config()[proto_ws ? 
"port_ws" : 
"port_rpc"]
 
  300            auto const password =
 
  302                    .
config()[proto_ws ? 
"port_ws" : 
"port_rpc"]
 
  307                env, proto, *user, *password + 
"_")[jss::result];
 
  309                jrr[
"error"] == proto_ws ? 
"forbidden" : 
"noPermission");
 
  311                jrr[
"error_message"] == proto_ws
 
  313                    : 
"You don't have permission for this command.");
 
  317                env, proto, *user, *password, 
true)[jss::result];
 
  319                jrr[
"error"] == proto_ws ? 
"forbidden" : 
"noPermission");
 
  321                jrr[
"error_message"] == proto_ws
 
  323                    : 
"You don't have permission for this command.");
 
  327                env, proto, *user + 
"_", *password)[jss::result];
 
  329                jrr[
"error"] == proto_ws ? 
"forbidden" : 
"noPermission");
 
  331                jrr[
"error_message"] == proto_ws
 
  333                    : 
"You don't have permission for this command.");
 
  338                jrr[
"error"] == proto_ws ? 
"forbidden" : 
"noPermission");
 
  340                jrr[
"error_message"] == proto_ws
 
  342                    : 
"You don't have permission for this command.");
 
  346            BEAST_EXPECT(jrr[
"status"] == 
"success");
 
  352            BEAST_EXPECT(jrr[
"status"] == 
"success");
 
  356            BEAST_EXPECT(jrr[
"status"] == 
"success");
 
  363                jrr[
"error"] == proto_ws ? 
"forbidden" : 
"noPermission");
 
  365                jrr[
"error_message"] == proto_ws
 
  367                    : 
"You don't have permission for this command.");
 
 
  374        testcase(
"WS client to http server fails");
 
  377                    cfg->section(
"port_ws").
set(
"protocol", 
"http,https");
 
  383            boost::system::error_code ec;
 
  384            boost::beast::http::response<boost::beast::http::string_body> resp;
 
  386            if (!BEAST_EXPECTS(!ec, ec.message()))
 
  389                resp.result() == boost::beast::http::status::unauthorized);
 
  394            boost::system::error_code ec;
 
  395            boost::beast::http::response<boost::beast::http::string_body> resp;
 
  397            if (!BEAST_EXPECTS(!ec, ec.message()))
 
  400                resp.result() == boost::beast::http::status::unauthorized);
 
 
  410                    cfg->section(
"port_rpc").
set(
"protocol", 
"ws2,wss2");
 
  411                    cfg->section(
"port_ws").
set(
"protocol", 
"http");
 
  417            boost::system::error_code ec;
 
  418            boost::beast::http::response<boost::beast::http::string_body> resp;
 
  420            if (!BEAST_EXPECTS(!ec, ec.message()))
 
  422            BEAST_EXPECT(resp.result() == boost::beast::http::status::ok);
 
  427            boost::system::error_code ec;
 
  428            boost::beast::http::response<boost::beast::http::string_body> resp;
 
  430            if (!BEAST_EXPECTS(!ec, ec.message()))
 
  432            BEAST_EXPECT(resp.result() == boost::beast::http::status::ok);
 
 
  439        testcase(
"Partial WS upgrade request");
 
  442        using namespace boost::beast::http;
 
  444                    cfg->section(
"port_ws").
set(
"protocol", 
"ws2");
 
  452        boost::system::error_code ec;
 
  453        response<string_body> resp;
 
  457        auto req_string = boost::lexical_cast<std::string>(req);
 
  458        req_string.erase(req_string.find_last_of(
"13"), std::string::npos);
 
  461        ip::tcp::resolver r{ios};
 
  462        boost::beast::multi_buffer sb;
 
  465        if (!BEAST_EXPECTS(!ec, ec.message()))
 
  468        ip::tcp::socket sock{ios};
 
  469        async_connect(sock, it, yield[ec]);
 
  470        if (!BEAST_EXPECTS(!ec, ec.message()))
 
  472        async_write(sock, boost::asio::buffer(req_string), yield[ec]);
 
  473        if (!BEAST_EXPECTS(!ec, ec.message()))
 
  477        async_read(sock, sb, resp, yield[ec]);
 
 
  485        boost::asio::yield_context& yield)
 
  490        testcase << 
"Connect fails: " << client_protocol << 
" client to " 
  491                 << server_protocol << 
" server";
 
  495        boost::beast::http::response<boost::beast::http::string_body> resp;
 
  496        boost::system::error_code ec;
 
  497        if (boost::starts_with(client_protocol, 
"h"))
 
  499            doHTTPRequest(env, yield, client_protocol == 
"https", resp, ec);
 
  507                client_protocol == 
"wss" || client_protocol == 
"wss2",
 
 
  515    testAuth(
bool secure, boost::asio::yield_context& yield)
 
  517        testcase << 
"Server with authorization, " 
  518                 << (secure ? 
"secure" : 
"non-secure");
 
  520        using namespace test::jtx;
 
  522                    (*cfg)[
"port_rpc"].set(
"user", 
"me");
 
  523                    (*cfg)[
"port_rpc"].set(
"password", 
"secret");
 
  524                    (*cfg)[
"port_rpc"].set(
 
  525                        "protocol", secure ? 
"https" : 
"http");
 
  527                        (*cfg)[
"port_ws"].set(
"protocol", 
"http,ws");
 
  532        jr[jss::method] = 
"server_info";
 
  533        boost::beast::http::response<boost::beast::http::string_body> resp;
 
  534        boost::system::error_code ec;
 
  536        BEAST_EXPECT(resp.result() == boost::beast::http::status::forbidden);
 
  539        auth.insert(
"Authorization", 
"");
 
  541        BEAST_EXPECT(resp.result() == boost::beast::http::status::forbidden);
 
  543        auth.set(
"Authorization", 
"Basic NOT-VALID");
 
  545        BEAST_EXPECT(resp.result() == boost::beast::http::status::forbidden);
 
  549        BEAST_EXPECT(resp.result() == boost::beast::http::status::forbidden);
 
  551        auto const user = env.
app()
 
  563        auth.set(
"Authorization", 
"Basic " + user + 
":" + 
pass);
 
  565        BEAST_EXPECT(resp.result() == boost::beast::http::status::forbidden);
 
  570        BEAST_EXPECT(resp.result() == boost::beast::http::status::ok);
 
  571        BEAST_EXPECT(!resp.body().empty());
 
 
  577        testcase << 
"Server with connection limit of " << limit;
 
  579        using namespace test::jtx;
 
  581        using namespace boost::beast::http;
 
  592        boost::system::error_code ec;
 
  594        ip::tcp::resolver r{ios};
 
  597        jr[jss::method] = 
"server_info";
 
  604        int connectionCount{1};  
 
  612        int testTo = (limit == 0) ? 50 : limit + 1;
 
  613        while (connectionCount < testTo)
 
  616                ip::tcp::socket{ios}, boost::beast::multi_buffer{}));
 
  617            async_connect(clients.
back().first, it, yield[ec]);
 
  620            async_write(clients.
back().first, req, yield[ec]);
 
  626        for (
auto& [soc, buf] : clients)
 
  628            boost::beast::http::response<boost::beast::http::string_body> resp;
 
  629            async_read(soc, buf, resp, yield[ec]);
 
  634                (limit == 0 || readCount < limit - 1) ? (!ec) : bool(ec));
 
 
  641        testcase(
"Connection with WS handoff");
 
  643        using namespace test::jtx;
 
  645                    (*cfg)[
"port_ws"].set(
"protocol", 
"wss");
 
  653        boost::beast::http::response<boost::beast::http::string_body> resp;
 
  654        boost::system::error_code ec;
 
  657            resp.result() == boost::beast::http::status::switching_protocols);
 
  659            resp.find(
"Upgrade") != resp.end() &&
 
  660            resp[
"Upgrade"] == 
"websocket");
 
  662            resp.find(
"Connection") != resp.end() &&
 
  663            boost::iequals(resp[
"Connection"], 
"upgrade"));
 
 
  669        testcase(
"Connection to port with no RPC enabled");
 
  671        using namespace test::jtx;
 
  678        boost::beast::http::response<boost::beast::http::string_body> resp;
 
  679        boost::system::error_code ec;
 
  690        BEAST_EXPECT(resp.result() == boost::beast::http::status::forbidden);
 
  691        BEAST_EXPECT(resp.body() == 
"Forbidden\r\n");
 
 
  697        testcase(
"WS client sends assorted input");
 
  699        using namespace test::jtx;
 
  701        using namespace boost::beast::http;
 
  708        boost::system::error_code ec;
 
  711        ip::tcp::resolver r{ios};
 
  714        if (!BEAST_EXPECT(!ec))
 
  717        ip::tcp::socket sock{ios};
 
  718        async_connect(sock, it, yield[ec]);
 
  719        if (!BEAST_EXPECT(!ec))
 
  722        boost::beast::websocket::stream<boost::asio::ip::tcp::socket&> ws{sock};
 
  727            ws.async_write_some(
true, buffer(req), yield[ec]);
 
  728            if (!BEAST_EXPECT(!ec))
 
  731            boost::beast::multi_buffer sb;
 
  732            ws.async_read(sb, yield[ec]);
 
  733            if (!BEAST_EXPECT(!ec))
 
  738            if (!BEAST_EXPECT(jr.
parse(
 
  739                    boost::lexical_cast<std::string>(
 
  740                        boost::beast::make_printable(sb.data())),
 
  743            sb.consume(sb.size());
 
  748            auto resp = sendAndParse(
"NOT JSON");
 
  750                resp.isMember(jss::error) && resp[jss::error] == 
"jsonInvalid");
 
  751            BEAST_EXPECT(!resp.isMember(jss::status));
 
  756            jv[jss::command] = 
"foo";
 
  757            jv[jss::method] = 
"bar";
 
  760                resp.isMember(jss::error) &&
 
  761                resp[jss::error] == 
"missingCommand");
 
  763                resp.isMember(jss::status) && resp[jss::status] == 
"error");
 
  768            jv[jss::command] = 
"ping";
 
  771                resp.isMember(jss::status) && resp[jss::status] == 
"success");
 
  773                resp.isMember(jss::result) &&
 
  774                resp[jss::result].isMember(jss::role) &&
 
  775                resp[jss::result][jss::role] == 
"admin");
 
 
  783            "Status request over WS and RPC with/without Amendment Warning");
 
  786        using namespace boost::beast::http;
 
  791                    cfg->section(
"port_rpc").
set(
"protocol", 
"http");
 
  805        auto si = env.
rpc(
"server_info")[jss::result];
 
  806        BEAST_EXPECT(si.isMember(jss::info));
 
  807        BEAST_EXPECT(!si[jss::info].isMember(jss::amendment_blocked));
 
  810        BEAST_EXPECT(!si.isMember(jss::warnings));
 
  814        si = env.
rpc(
"server_state")[jss::result];
 
  815        BEAST_EXPECT(si.isMember(jss::state));
 
  816        BEAST_EXPECT(!si[jss::state].isMember(jss::amendment_blocked));
 
  819        BEAST_EXPECT(!si[jss::state].isMember(jss::warnings));
 
  825        boost::system::error_code ec;
 
  826        response<string_body> resp;
 
  837        if (!BEAST_EXPECTS(!ec, ec.message()))
 
  839        BEAST_EXPECT(resp.result() == boost::beast::http::status::ok);
 
  841            resp.body().find(
"connectivity is working.") != std::string::npos);
 
  853        si = env.
rpc(
"server_info")[jss::result];
 
  854        BEAST_EXPECT(si.isMember(jss::info));
 
  855        BEAST_EXPECT(!si[jss::info].isMember(jss::amendment_blocked));
 
  857            si[jss::info].isMember(jss::warnings) &&
 
  858            si[jss::info][jss::warnings].isArray() &&
 
  859            si[jss::info][jss::warnings].size() == 1 &&
 
  860            si[jss::info][jss::warnings][0u][jss::id].asInt() ==
 
  865        si = env.
rpc(
"server_state")[jss::result];
 
  866        BEAST_EXPECT(si.isMember(jss::state));
 
  867        BEAST_EXPECT(!si[jss::state].isMember(jss::amendment_blocked));
 
  869            si[jss::state].isMember(jss::warnings) &&
 
  870            si[jss::state][jss::warnings].isArray() &&
 
  871            si[jss::state][jss::warnings].size() == 1 &&
 
  872            si[jss::state][jss::warnings][0u][jss::id].asInt() ==
 
  885        if (!BEAST_EXPECTS(!ec, ec.message()))
 
  887        BEAST_EXPECT(resp.result() == boost::beast::http::status::ok);
 
  889            resp.body().find(
"connectivity is working.") != std::string::npos);
 
  903        if (!BEAST_EXPECTS(!ec, ec.message()))
 
  905        BEAST_EXPECT(resp.result() == boost::beast::http::status::ok);
 
  907            resp.body().find(
"connectivity is working.") != std::string::npos);
 
 
  913        testcase(
"Status request over WS and RPC with/without Amendment Block");
 
  916        using namespace boost::beast::http;
 
  921                    cfg->section(
"port_rpc").
set(
"protocol", 
"http");
 
  935        auto si = env.
rpc(
"server_info")[jss::result];
 
  936        BEAST_EXPECT(si.isMember(jss::info));
 
  937        BEAST_EXPECT(!si[jss::info].isMember(jss::amendment_blocked));
 
  940        BEAST_EXPECT(!si.isMember(jss::warnings));
 
  944        si = env.
rpc(
"server_state")[jss::result];
 
  945        BEAST_EXPECT(si.isMember(jss::state));
 
  946        BEAST_EXPECT(!si[jss::state].isMember(jss::amendment_blocked));
 
  949        BEAST_EXPECT(!si[jss::state].isMember(jss::warnings));
 
  955        boost::system::error_code ec;
 
  956        response<string_body> resp;
 
  967        if (!BEAST_EXPECTS(!ec, ec.message()))
 
  969        BEAST_EXPECT(resp.result() == boost::beast::http::status::ok);
 
  971            resp.body().find(
"connectivity is working.") != std::string::npos);
 
  983        si = env.
rpc(
"server_info")[jss::result];
 
  984        BEAST_EXPECT(si.isMember(jss::info));
 
  986            si[jss::info].isMember(jss::amendment_blocked) &&
 
  987            si[jss::info][jss::amendment_blocked] == 
true);
 
  989            si[jss::info].isMember(jss::warnings) &&
 
  990            si[jss::info][jss::warnings].isArray() &&
 
  991            si[jss::info][jss::warnings].size() == 1 &&
 
  992            si[jss::info][jss::warnings][0u][jss::id].asInt() ==
 
  996        si = env.
rpc(
"server_state")[jss::result];
 
  998            si[jss::state].isMember(jss::amendment_blocked) &&
 
  999            si[jss::state][jss::amendment_blocked] == 
true);
 
 1001            si[jss::state].isMember(jss::warnings) &&
 
 1002            si[jss::state][jss::warnings].isArray() &&
 
 1003            si[jss::state][jss::warnings].size() == 1 &&
 
 1004            si[jss::state][jss::warnings][0u][jss::id].asInt() ==
 
 1018        if (!BEAST_EXPECTS(!ec, ec.message()))
 
 1020        BEAST_EXPECT(resp.result() == boost::beast::http::status::ok);
 
 1022            resp.body().find(
"connectivity is working.") != std::string::npos);
 
 1035        if (!BEAST_EXPECTS(!ec, ec.message()))
 
 1038            resp.result() == boost::beast::http::status::internal_server_error);
 
 1040            resp.body().find(
"cannot accept clients:") != std::string::npos);
 
 1042            resp.body().find(
"Server version too old") != std::string::npos);
 
 
 1048        testcase(
"RPC client sends assorted input");
 
 1050        using namespace test::jtx;
 
 1053        boost::system::error_code ec;
 
 1055            boost::beast::http::response<boost::beast::http::string_body> resp;
 
 1058                resp.result() == boost::beast::http::status::bad_request);
 
 1059            BEAST_EXPECT(resp.body() == 
"Unable to parse request: \r\n");
 
 1063            boost::beast::http::response<boost::beast::http::string_body> resp;
 
 1068                resp.result() == boost::beast::http::status::bad_request);
 
 1069            BEAST_EXPECT(resp.body() == 
"Null method\r\n");
 
 1073            boost::beast::http::response<boost::beast::http::string_body> resp;
 
 1078                resp.result() == boost::beast::http::status::bad_request);
 
 1079            BEAST_EXPECT(resp.body() == 
"Unable to parse request: \r\n");
 
 1083            boost::beast::http::response<boost::beast::http::string_body> resp;
 
 1090                resp.result() == boost::beast::http::status::bad_request);
 
 1091            BEAST_EXPECT(resp.body() == 
"Unable to parse request: \r\n");
 
 1095            boost::beast::http::response<boost::beast::http::string_body> resp;
 
 1097            jv[jss::method] = 
"batch";
 
 1098            jv[jss::params] = 2;
 
 1101                resp.result() == boost::beast::http::status::bad_request);
 
 1102            BEAST_EXPECT(resp.body() == 
"Malformed batch request\r\n");
 
 1106            boost::beast::http::response<boost::beast::http::string_body> resp;
 
 1108            jv[jss::method] = 
"batch";
 
 1110            jv[jss::params][
"invalid"] = 3;
 
 1113                resp.result() == boost::beast::http::status::bad_request);
 
 1114            BEAST_EXPECT(resp.body() == 
"Malformed batch request\r\n");
 
 1119            boost::beast::http::response<boost::beast::http::string_body> resp;
 
 1123                resp.result() == boost::beast::http::status::bad_request);
 
 1124            BEAST_EXPECT(resp.body() == 
"Null method\r\n");
 
 1128            boost::beast::http::response<boost::beast::http::string_body> resp;
 
 1129            jv[jss::method] = 1;
 
 1132                resp.result() == boost::beast::http::status::bad_request);
 
 1133            BEAST_EXPECT(resp.body() == 
"method is not string\r\n");
 
 1137            boost::beast::http::response<boost::beast::http::string_body> resp;
 
 1138            jv[jss::method] = 
"";
 
 1141                resp.result() == boost::beast::http::status::bad_request);
 
 1142            BEAST_EXPECT(resp.body() == 
"method is empty\r\n");
 
 1146            boost::beast::http::response<boost::beast::http::string_body> resp;
 
 1147            jv[jss::method] = 
"some_method";
 
 1148            jv[jss::params] = 
"params";
 
 1151                resp.result() == boost::beast::http::status::bad_request);
 
 1152            BEAST_EXPECT(resp.body() == 
"params unparseable\r\n");
 
 1156            boost::beast::http::response<boost::beast::http::string_body> resp;
 
 1158            jv[jss::params][0u] = 
"not an object";
 
 1161                resp.result() == boost::beast::http::status::bad_request);
 
 1162            BEAST_EXPECT(resp.body() == 
"params unparseable\r\n");
 
 
 1169        testcase(
"Server status not okay");
 
 1171        using namespace test::jtx;
 
 1173                    cfg->ELB_SUPPORT = 
true;
 
 1180        boost::beast::http::response<boost::beast::http::string_body> resp;
 
 1181        boost::system::error_code ec;
 
 1184            resp.result() == boost::beast::http::status::internal_server_error);
 
 1185        std::regex body{
"Server cannot accept clients"};
 
 
 1193        for (
auto it : {
"http", 
"ws", 
"ws2"})
 
 1200        yield_to([&](boost::asio::yield_context& yield) {
 
 
 
 1229BEAST_DEFINE_TESTSUITE(ServerStatus, server, 
ripple);
 
Unserialize a JSON document into a Value.
 
bool parse(std::string const &document, Value &root)
Read a Value from a JSON document.
 
Value & append(Value const &value)
Append value to array at the end.
 
Mix-in to support tests using asio coroutines.
 
boost::asio::io_context & get_io_context()
Return the io_context associated with the object.
 
void yield_to(F0 &&f0, FN &&... fn)
Run one or more functions, each in a coroutine.
 
void pass()
Record a successful test condition.
 
testcase_t testcase
Memberspace for declaring test cases.
 
virtual Config & config()=0
 
virtual LoadFeeTrack & getFeeTrack()=0
 
virtual NetworkOPs & getOPs()=0
 
virtual LedgerMaster & getLedgerMaster()=0
 
Section & section(std::string const &name)
Returns the section with the given name.
 
virtual void setAmendmentWarned()=0
 
virtual Json::Value getConsensusInfo()=0
 
virtual void setAmendmentBlocked()=0
 
virtual bool beginConsensus(uint256 const &netLCL, std::unique_ptr< std::stringstream > const &clog)=0
 
std::optional< T > get(std::string const &name) const
 
void testAmendmentBlock(boost::asio::yield_context &yield)
 
void testCantConnect(std::string const &client_protocol, std::string const &server_protocol, boost::asio::yield_context &yield)
 
void testAuth(bool secure, boost::asio::yield_context &yield)
 
auto makeHTTPRequest(std::string const &host, uint16_t port, std::string const &body, myFields const &fields)
 
void testRPCRequests(boost::asio::yield_context &yield)
 
void testStatusRequest(boost::asio::yield_context &yield)
 
void testAmendmentWarning(boost::asio::yield_context &yield)
 
void testTruncatedWSUpgrade(boost::asio::yield_context &yield)
 
auto makeConfig(std::string const &proto, bool admin=true, bool credentials=false)
 
void doRequest(boost::asio::yield_context &yield, boost::beast::http::request< boost::beast::http::string_body > &&req, std::string const &host, uint16_t port, bool secure, boost::beast::http::response< boost::beast::http::string_body > &resp, boost::system::error_code &ec)
 
void doWSRequest(test::jtx::Env &env, boost::asio::yield_context &yield, bool secure, boost::beast::http::response< boost::beast::http::string_body > &resp, boost::system::error_code &ec)
 
void testWSRequests(boost::asio::yield_context &yield)
 
void testLimit(boost::asio::yield_context &yield, int limit)
 
void testWSHandoff(boost::asio::yield_context &yield)
 
void testNoRPC(boost::asio::yield_context &yield)
 
void testStatusNotOkay(boost::asio::yield_context &yield)
 
void testWSClientToHttpServer(boost::asio::yield_context &yield)
 
void run() override
Runs the suite.
 
auto makeAdminRequest(jtx::Env &env, std::string const &proto, std::string const &user, std::string const &password, bool subobject=false)
 
auto makeWSUpgrade(std::string const &host, uint16_t port)
 
void doHTTPRequest(test::jtx::Env &env, boost::asio::yield_context &yield, bool secure, boost::beast::http::response< boost::beast::http::string_body > &resp, boost::system::error_code &ec, std::string const &body="", myFields const &fields={})
 
void testAdminRequest(std::string const &proto, bool admin, bool credentials)
 
A transaction testing environment.
 
std::shared_ptr< ReadView const > closed()
Returns the last closed ledger.
 
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
 
Json::Value rpc(unsigned apiVersion, std::unordered_map< std::string, std::string > const &headers, std::string const &cmd, Args &&... args)
Execute an RPC command.
 
T emplace_back(T... args)
 
@ arrayValue
array value (ordered list)
 
@ objectValue
object value (collection of name/value pairs).
 
std::unique_ptr< Config > validator(std::unique_ptr< Config >, std::string const &)
adjust configuration with params needed to be a validator
 
std::unique_ptr< Config > envconfig()
creates and initializes a default configuration for jtx::Env
 
std::unique_ptr< WSClient > makeWSClient(Config const &cfg, bool v2, unsigned rpc_version, std::unordered_map< std::string, std::string > const &headers)
Returns a client operating through WebSockets/S.
 
char const * getEnvLocalhostAddr()
 
std::unique_ptr< AbstractClient > makeJSONRPCClient(Config const &cfg, unsigned rpc_version)
Returns a client using JSON-RPC over HTTP/S.
 
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
 
@ warnRPC_UNSUPPORTED_MAJORITY
 
@ warnRPC_AMENDMENT_BLOCKED
 
bool set(T &target, std::string const &name, Section const §ion)
Set a value from a configuration Section If the named value is not found or doesn't parse as a T,...
 
std::string base64_encode(std::uint8_t const *data, std::size_t len)
 
std::string to_string(base_uint< Bits, Tag > const &a)
 
T regex_search(T... args)