test: Env unit test RPC errors return a unique result: (#4877)

* telENV_RPC_FAILED is a new code, reserved exclusively
  for unit tests when RPC fails. This will
  make those types of errors distinct and easier to test
  for when expected and/or diagnose when not.
* Output RPC command result when result is not expected.
This commit is contained in:
Ed Hennis
2024-03-19 12:13:52 -04:00
committed by GitHub
parent af9cabe100
commit 0c32fc5f2a
10 changed files with 69 additions and 32 deletions

View File

@@ -247,7 +247,10 @@ public:
// Duplicate signers should fail.
aliceSeq = env.seq(alice);
env(noop(alice), msig(demon, demon), fee(3 * baseFee), ter(temINVALID));
env(noop(alice),
msig(demon, demon),
fee(3 * baseFee),
ter(telENV_RPC_FAILED));
env.close();
BEAST_EXPECT(env.seq(alice) == aliceSeq);
@@ -358,7 +361,7 @@ public:
msig phantoms{bogie, demon};
std::reverse(phantoms.signers.begin(), phantoms.signers.end());
std::uint32_t const aliceSeq = env.seq(alice);
env(noop(alice), phantoms, ter(temINVALID));
env(noop(alice), phantoms, ter(telENV_RPC_FAILED));
env.close();
BEAST_EXPECT(env.seq(alice) == aliceSeq);
}
@@ -1634,7 +1637,10 @@ public:
// Duplicate signers should fail.
aliceSeq = env.seq(alice);
env(noop(alice), msig(demon, demon), fee(3 * baseFee), ter(temINVALID));
env(noop(alice),
msig(demon, demon),
fee(3 * baseFee),
ter(telENV_RPC_FAILED));
env.close();
BEAST_EXPECT(env.seq(alice) == aliceSeq);

View File

@@ -149,7 +149,7 @@ struct Regression_test : public beast::unit_test::suite
secp256r1Sig->setFieldVL(sfSigningPubKey, *pubKeyBlob);
jt.stx.reset(secp256r1Sig.release());
env(jt, ter(temINVALID));
env(jt, ter(telENV_RPC_FAILED));
};
Account const alice{"alice", KeyType::secp256k1};

View File

@@ -237,7 +237,10 @@ private:
std::vector<std::string> uris;
for (auto const& u : servers)
{
log << "Testing " << u.uri << std::endl;
uris.push_back(u.uri);
}
sites->load(uris);
sites->start();
sites->join();

View File

@@ -512,7 +512,11 @@ public:
of JTx submission.
*/
void
postconditions(JTx const& jt, TER ter, bool didApply);
postconditions(
JTx const& jt,
TER ter,
bool didApply,
Json::Value const& jr = Json::Value());
/** Apply funclets and submit. */
/** @{ */

View File

@@ -747,8 +747,9 @@ public:
// Force the factor low enough to fail
params[jss::fee_mult_max] = 1;
params[jss::fee_div_max] = 2;
// RPC errors result in temINVALID
envs(noop(alice), fee(none), seq(none), ter(temINVALID))(params);
// RPC errors result in telENV_RPC_FAILED
envs(noop(alice), fee(none), seq(none), ter(telENV_RPC_FAILED))(
params);
auto tx = env.tx();
BEAST_EXPECT(!tx);

View File

@@ -280,7 +280,9 @@ Env::parseResult(Json::Value const& jr)
jr[jss::result].isMember(jss::engine_result_code))
ter = TER::fromInt(jr[jss::result][jss::engine_result_code].asInt());
else
ter = temINVALID;
// Use an error code that is not used anywhere in the transaction engine
// to distinguish this case.
ter = telENV_RPC_FAILED;
return std::make_pair(ter, isTesSuccess(ter) || isTecClaim(ter));
}
@@ -288,23 +290,29 @@ void
Env::submit(JTx const& jt)
{
bool didApply;
if (jt.stx)
{
txid_ = jt.stx->getTransactionID();
Serializer s;
jt.stx->add(s);
auto const jr = rpc("submit", strHex(s.slice()));
auto const jr = [&]() {
if (jt.stx)
{
txid_ = jt.stx->getTransactionID();
Serializer s;
jt.stx->add(s);
auto const jr = rpc("submit", strHex(s.slice()));
std::tie(ter_, didApply) = parseResult(jr);
}
else
{
// Parsing failed or the JTx is
// otherwise missing the stx field.
ter_ = temMALFORMED;
didApply = false;
}
return postconditions(jt, ter_, didApply);
std::tie(ter_, didApply) = parseResult(jr);
return jr;
}
else
{
// Parsing failed or the JTx is
// otherwise missing the stx field.
ter_ = temMALFORMED;
didApply = false;
return Json::Value();
}
}();
return postconditions(jt, ter_, didApply, jr);
}
void
@@ -342,11 +350,15 @@ Env::sign_and_submit(JTx const& jt, Json::Value params)
std::tie(ter_, didApply) = parseResult(jr);
return postconditions(jt, ter_, didApply);
return postconditions(jt, ter_, didApply, jr);
}
void
Env::postconditions(JTx const& jt, TER ter, bool didApply)
Env::postconditions(
JTx const& jt,
TER ter,
bool didApply,
Json::Value const& jr)
{
if (jt.ter &&
!test.expect(
@@ -356,6 +368,8 @@ Env::postconditions(JTx const& jt, TER ter, bool didApply)
transHuman(*jt.ter) + ")"))
{
test.log << pretty(jt.jv) << std::endl;
if (jr)
test.log << pretty(jr) << std::endl;
// Don't check postconditions if
// we didn't get the expected result.
return;

View File

@@ -147,6 +147,7 @@ class DatabaseDownloader_test : public beast::unit_test::suite
// server to request from. Use the /textfile endpoint
// to get a simple text file sent as response.
auto server = createServer(env);
log << "Downloading DB from " << server->local_endpoint() << std::endl;
ripple::test::detail::FileDirGuard const data{
*this, "downloads", "data", "", false, false};
@@ -225,6 +226,8 @@ class DatabaseDownloader_test : public beast::unit_test::suite
auto server = createServer(env);
auto host = server->local_endpoint().address().to_string();
auto port = std::to_string(server->local_endpoint().port());
log << "Downloading DB from " << server->local_endpoint()
<< std::endl;
server->stop();
BEAST_EXPECT(dl->download(
host,
@@ -249,6 +252,8 @@ class DatabaseDownloader_test : public beast::unit_test::suite
ripple::test::detail::FileDirGuard const datafile{
*this, "downloads", "data", "", false, false};
auto server = createServer(env, false);
log << "Downloading DB from " << server->local_endpoint()
<< std::endl;
BEAST_EXPECT(dl->download(
server->local_endpoint().address().to_string(),
std::to_string(server->local_endpoint().port()),
@@ -272,6 +277,8 @@ class DatabaseDownloader_test : public beast::unit_test::suite
ripple::test::detail::FileDirGuard const datafile{
*this, "downloads", "data", "", false, false};
auto server = createServer(env);
log << "Downloading DB from " << server->local_endpoint()
<< std::endl;
BEAST_EXPECT(dl->download(
server->local_endpoint().address().to_string(),
std::to_string(server->local_endpoint().port()),

View File

@@ -56,7 +56,7 @@ public:
JTx memoSize = makeJtxWithMemo();
memoSize.jv[sfMemos.jsonName][0u][sfMemo.jsonName]
[sfMemoData.jsonName] = std::string(2020, '0');
env(memoSize, ter(temINVALID));
env(memoSize, ter(telENV_RPC_FAILED));
// This memo is just barely small enough.
memoSize.jv[sfMemos.jsonName][0u][sfMemo.jsonName]
@@ -72,7 +72,7 @@ public:
auto& m = mi[sfCreatedNode.jsonName]; // CreatedNode in Memos
m[sfMemoData.jsonName] = "3030303030";
env(memoNonMemo, ter(temINVALID));
env(memoNonMemo, ter(telENV_RPC_FAILED));
}
{
// Put an invalid field in a Memo object.
@@ -80,7 +80,7 @@ public:
memoExtra
.jv[sfMemos.jsonName][0u][sfMemo.jsonName][sfFlags.jsonName] =
13;
env(memoExtra, ter(temINVALID));
env(memoExtra, ter(telENV_RPC_FAILED));
}
{
// Put a character that is not allowed in a URL in a MemoType field.
@@ -88,7 +88,7 @@ public:
memoBadChar.jv[sfMemos.jsonName][0u][sfMemo.jsonName]
[sfMemoType.jsonName] =
strHex(std::string_view("ONE<INFINITY"));
env(memoBadChar, ter(temINVALID));
env(memoBadChar, ter(telENV_RPC_FAILED));
}
{
// Put a character that is not allowed in a URL in a MemoData field.
@@ -105,7 +105,7 @@ public:
memoBadChar.jv[sfMemos.jsonName][0u][sfMemo.jsonName]
[sfMemoFormat.jsonName] =
strHex(std::string_view("NoBraces{}InURL"));
env(memoBadChar, ter(temINVALID));
env(memoBadChar, ter(telENV_RPC_FAILED));
}
}