Add tests for subscribe/unsubscribe error cases:

Fixes: RIPD-1417

Fix incorrect error case messages. Fix crash in NetworkOps instance when
exiting with remaining RPC subscriptions. Add code to remove URL
subscription when requested.
This commit is contained in:
Mike Ellery
2017-06-19 14:31:22 -07:00
committed by seelabs
parent e0168b98d7
commit ac1ab720c4
5 changed files with 367 additions and 58 deletions

View File

@@ -21,6 +21,7 @@
#include <ripple/core/ConfigSections.h>
#include <ripple/protocol/JsonFields.h>
#include <test/jtx/WSClient.h>
#include <test/jtx/envconfig.h>
#include <test/jtx.h>
#include <ripple/beast/unit_test.h>
@@ -382,6 +383,259 @@ public:
BEAST_EXPECT(jv[jss::status] == "success");
}
void
testSubByUrl()
{
using namespace jtx;
testcase("Subscribe by url");
Env env {*this};
Json::Value jv;
jv[jss::url] = "http://localhost/events";
jv[jss::url_username] = "admin";
jv[jss::url_password] = "password";
jv[jss::streams] = Json::arrayValue;
jv[jss::streams][0u] = "validations";
auto jr = env.rpc("json", "subscribe", to_string(jv)) [jss::result];
BEAST_EXPECT(jr[jss::status] == "success");
jv[jss::streams][0u] = "ledger";
jr = env.rpc("json", "subscribe", to_string(jv)) [jss::result];
BEAST_EXPECT(jr[jss::status] == "success");
jr = env.rpc("json", "unsubscribe", to_string(jv)) [jss::result];
BEAST_EXPECT(jr[jss::status] == "success");
jv[jss::streams][0u] = "validations";
jr = env.rpc("json", "unsubscribe", to_string(jv)) [jss::result];
BEAST_EXPECT(jr[jss::status] == "success");
}
void
testSubErrors(bool subscribe)
{
using namespace jtx;
auto const method = subscribe ? "subscribe" : "unsubscribe";
testcase << "Error cases for " << method;
Env env {*this};
auto wsc = makeWSClient(env.app().config());
{
auto jr = env.rpc("json", method, "{}") [jss::result];
BEAST_EXPECT(jr[jss::error] == "invalidParams");
BEAST_EXPECT(jr[jss::error_message] == "Invalid parameters.");
}
{
Json::Value jv;
jv[jss::url] = "not-a-url";
jv[jss::username] = "admin";
jv[jss::password] = "password";
auto jr = env.rpc("json", method, to_string(jv)) [jss::result];
if (subscribe)
{
BEAST_EXPECT(jr[jss::error] == "invalidParams");
BEAST_EXPECT(jr[jss::error_message] == "Failed to parse url.");
}
// else TODO: why isn't this an error for unsubscribe ?
// (findRpcSub returns null)
}
{
Json::Value jv;
jv[jss::url] = "ftp://scheme.not.supported.tld";
auto jr = env.rpc("json", method, to_string(jv)) [jss::result];
if (subscribe)
{
BEAST_EXPECT(jr[jss::error] == "invalidParams");
BEAST_EXPECT(jr[jss::error_message] == "Only http and https is supported.");
}
}
{
Env env_nonadmin {*this, no_admin(envconfig(port_increment, 2))};
Json::Value jv;
jv[jss::url] = "no-url";
auto jr = env_nonadmin.rpc("json", method, to_string(jv)) [jss::result];
BEAST_EXPECT(jr[jss::error] == "noPermission");
BEAST_EXPECT(jr[jss::error_message] == "You don't have permission for this command.");
}
for (auto const& f : {jss::accounts_proposed, jss::accounts})
{
{
Json::Value jv;
jv[f] = "";
auto jr = wsc->invoke(method, jv) [jss::result];
BEAST_EXPECT(jr[jss::error] == "invalidParams");
BEAST_EXPECT(jr[jss::error_message] == "Invalid parameters.");
}
{
Json::Value jv;
jv[f] = Json::arrayValue;
auto jr = wsc->invoke(method, jv) [jss::result];
BEAST_EXPECT(jr[jss::error] == "actMalformed");
BEAST_EXPECT(jr[jss::error_message] == "Account malformed.");
}
}
{
Json::Value jv;
jv[jss::books] = "";
auto jr = wsc->invoke(method, jv) [jss::result];
BEAST_EXPECT(jr[jss::error] == "invalidParams");
BEAST_EXPECT(jr[jss::error_message] == "Invalid parameters.");
}
{
Json::Value jv;
jv[jss::books] = Json::arrayValue;
jv[jss::books][0u] = 1;
auto jr = wsc->invoke(method, jv) [jss::result];
BEAST_EXPECT(jr[jss::error] == "invalidParams");
BEAST_EXPECT(jr[jss::error_message] == "Invalid parameters.");
}
{
Json::Value jv;
jv[jss::books] = Json::arrayValue;
jv[jss::books][0u] = Json::objectValue;
jv[jss::books][0u][jss::taker_gets] = Json::objectValue;
jv[jss::books][0u][jss::taker_pays] = Json::objectValue;
auto jr = wsc->invoke(method, jv) [jss::result];
BEAST_EXPECT(jr[jss::error] == "srcCurMalformed");
BEAST_EXPECT(jr[jss::error_message] == "Source currency is malformed.");
}
{
Json::Value jv;
jv[jss::books] = Json::arrayValue;
jv[jss::books][0u] = Json::objectValue;
jv[jss::books][0u][jss::taker_gets] = Json::objectValue;
jv[jss::books][0u][jss::taker_pays] = Json::objectValue;
jv[jss::books][0u][jss::taker_pays][jss::currency] = "ZZZZ";
auto jr = wsc->invoke(method, jv) [jss::result];
BEAST_EXPECT(jr[jss::error] == "srcCurMalformed");
BEAST_EXPECT(jr[jss::error_message] == "Source currency is malformed.");
}
{
Json::Value jv;
jv[jss::books] = Json::arrayValue;
jv[jss::books][0u] = Json::objectValue;
jv[jss::books][0u][jss::taker_gets] = Json::objectValue;
jv[jss::books][0u][jss::taker_pays] = Json::objectValue;
jv[jss::books][0u][jss::taker_pays][jss::currency] = "USD";
jv[jss::books][0u][jss::taker_pays][jss::issuer] = 1;
auto jr = wsc->invoke(method, jv) [jss::result];
BEAST_EXPECT(jr[jss::error] == "srcIsrMalformed");
BEAST_EXPECT(jr[jss::error_message] == "Source issuer is malformed.");
}
{
Json::Value jv;
jv[jss::books] = Json::arrayValue;
jv[jss::books][0u] = Json::objectValue;
jv[jss::books][0u][jss::taker_gets] = Json::objectValue;
jv[jss::books][0u][jss::taker_pays] = Json::objectValue;
jv[jss::books][0u][jss::taker_pays][jss::currency] = "USD";
jv[jss::books][0u][jss::taker_pays][jss::issuer] = Account{"gateway"}.human() + "DEAD";
auto jr = wsc->invoke(method, jv) [jss::result];
BEAST_EXPECT(jr[jss::error] == "srcIsrMalformed");
BEAST_EXPECT(jr[jss::error_message] == "Source issuer is malformed.");
}
{
Json::Value jv;
jv[jss::books] = Json::arrayValue;
jv[jss::books][0u] = Json::objectValue;
jv[jss::books][0u][jss::taker_pays] = Account{"gateway"}["USD"](1).value().getJson(1);
jv[jss::books][0u][jss::taker_gets] = Json::objectValue;
auto jr = wsc->invoke(method, jv) [jss::result];
// NOTE: this error is slightly incongruous with the
// equivalent source currency error
BEAST_EXPECT(jr[jss::error] == "dstAmtMalformed");
BEAST_EXPECT(jr[jss::error_message] == "Destination amount/currency/issuer is malformed.");
}
{
Json::Value jv;
jv[jss::books] = Json::arrayValue;
jv[jss::books][0u] = Json::objectValue;
jv[jss::books][0u][jss::taker_pays] = Account{"gateway"}["USD"](1).value().getJson(1);
jv[jss::books][0u][jss::taker_gets][jss::currency] = "ZZZZ";
auto jr = wsc->invoke(method, jv) [jss::result];
// NOTE: this error is slightly incongruous with the
// equivalent source currency error
BEAST_EXPECT(jr[jss::error] == "dstAmtMalformed");
BEAST_EXPECT(jr[jss::error_message] == "Destination amount/currency/issuer is malformed.");
}
{
Json::Value jv;
jv[jss::books] = Json::arrayValue;
jv[jss::books][0u] = Json::objectValue;
jv[jss::books][0u][jss::taker_pays] = Account{"gateway"}["USD"](1).value().getJson(1);
jv[jss::books][0u][jss::taker_gets][jss::currency] = "USD";
jv[jss::books][0u][jss::taker_gets][jss::issuer] = 1;
auto jr = wsc->invoke(method, jv) [jss::result];
BEAST_EXPECT(jr[jss::error] == "dstIsrMalformed");
BEAST_EXPECT(jr[jss::error_message] == "Destination issuer is malformed.");
}
{
Json::Value jv;
jv[jss::books] = Json::arrayValue;
jv[jss::books][0u] = Json::objectValue;
jv[jss::books][0u][jss::taker_pays] = Account{"gateway"}["USD"](1).value().getJson(1);
jv[jss::books][0u][jss::taker_gets][jss::currency] = "USD";
jv[jss::books][0u][jss::taker_gets][jss::issuer] = Account{"gateway"}.human() + "DEAD";
auto jr = wsc->invoke(method, jv) [jss::result];
BEAST_EXPECT(jr[jss::error] == "dstIsrMalformed");
BEAST_EXPECT(jr[jss::error_message] == "Destination issuer is malformed.");
}
{
Json::Value jv;
jv[jss::books] = Json::arrayValue;
jv[jss::books][0u] = Json::objectValue;
jv[jss::books][0u][jss::taker_pays] = Account{"gateway"}["USD"](1).value().getJson(1);
jv[jss::books][0u][jss::taker_gets] = Account{"gateway"}["USD"](1).value().getJson(1);
auto jr = wsc->invoke(method, jv) [jss::result];
BEAST_EXPECT(jr[jss::error] == "badMarket");
BEAST_EXPECT(jr[jss::error_message] == "No such market.");
}
{
Json::Value jv;
jv[jss::streams] = "";
auto jr = wsc->invoke(method, jv) [jss::result];
BEAST_EXPECT(jr[jss::error] == "invalidParams");
BEAST_EXPECT(jr[jss::error_message] == "Invalid parameters.");
}
{
Json::Value jv;
jv[jss::streams] = Json::arrayValue;
jv[jss::streams][0u] = 1;
auto jr = wsc->invoke(method, jv) [jss::result];
BEAST_EXPECT(jr[jss::error] == "malformedStream");
BEAST_EXPECT(jr[jss::error_message] == "Stream malformed.");
}
{
Json::Value jv;
jv[jss::streams] = Json::arrayValue;
jv[jss::streams][0u] = "not_a_stream";
auto jr = wsc->invoke(method, jv) [jss::result];
BEAST_EXPECT(jr[jss::error] == "malformedStream");
BEAST_EXPECT(jr[jss::error_message] == "Stream malformed.");
}
}
void run() override
{
testServer();
@@ -389,6 +643,9 @@ public:
testTransactions();
testManifests();
testValidations();
testSubErrors(true);
testSubErrors(false);
testSubByUrl();
}
};