18 #include <ripple/app/main/LoadManager.h>
19 #include <ripple/app/misc/LoadFeeTrack.h>
20 #include <ripple/app/misc/NetworkOPs.h>
21 #include <ripple/beast/unit_test.h>
22 #include <ripple/core/ConfigSections.h>
23 #include <ripple/protocol/jss.h>
25 #include <test/jtx/WSClient.h>
26 #include <test/jtx/envconfig.h>
37 using namespace std::chrono_literals;
46 stream[jss::streams].append(
"server");
47 auto jv = wsc->invoke(
"subscribe", stream);
48 if (wsc->version() == 2)
51 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
53 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
54 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
56 BEAST_EXPECT(jv[jss::status] ==
"success");
68 for (
int i = 0; i < 5; ++i)
73 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
74 return jv[jss::type] ==
"serverStatus";
80 auto jv = wsc->invoke(
"unsubscribe", stream);
81 if (wsc->version() == 2)
84 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
86 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
87 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
89 BEAST_EXPECT(jv[jss::status] ==
"success");
95 for (
int i = 0; i < 5; ++i)
100 auto jvo = wsc->getMsg(10ms);
101 BEAST_EXPECTS(!jvo,
"getMsg: " +
to_string(jvo.value()));
108 using namespace std::chrono_literals;
117 stream[jss::streams].append(
"ledger");
118 auto jv = wsc->invoke(
"subscribe", stream);
119 if (wsc->version() == 2)
122 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
124 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
125 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
127 BEAST_EXPECT(jv[jss::result][jss::ledger_index] == 2);
135 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
136 return jv[jss::ledger_index] == 3;
145 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
146 return jv[jss::ledger_index] == 4;
151 auto jv = wsc->invoke(
"unsubscribe", stream);
152 if (wsc->version() == 2)
155 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
157 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
158 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
160 BEAST_EXPECT(jv[jss::status] ==
"success");
166 using namespace std::chrono_literals;
175 stream[jss::streams].append(
"transactions");
176 auto jv = wsc->invoke(
"subscribe", stream);
177 if (wsc->version() == 2)
180 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
182 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
183 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
185 BEAST_EXPECT(jv[jss::status] ==
"success");
193 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
194 return jv[jss::meta][
"AffectedNodes"][1u][
"CreatedNode"]
195 [
"NewFields"][jss::Account] ==
196 Account(
"alice").human();
200 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
201 return jv[jss::meta][
"AffectedNodes"][0u][
"ModifiedNode"]
202 [
"FinalFields"][jss::Account] ==
203 Account(
"alice").human();
210 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
211 return jv[jss::meta][
"AffectedNodes"][1u][
"CreatedNode"]
212 [
"NewFields"][jss::Account] == Account(
"bob").human();
216 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
217 return jv[jss::meta][
"AffectedNodes"][0u][
"ModifiedNode"]
218 [
"FinalFields"][jss::Account] ==
219 Account(
"bob").human();
225 auto jv = wsc->invoke(
"unsubscribe", stream);
226 if (wsc->version() == 2)
229 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
231 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
232 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
234 BEAST_EXPECT(jv[jss::status] ==
"success");
241 stream[jss::accounts].append(
Account(
"alice").human());
242 auto jv = wsc->invoke(
"subscribe", stream);
243 if (wsc->version() == 2)
246 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
248 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
249 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
251 BEAST_EXPECT(jv[jss::status] ==
"success");
258 BEAST_EXPECT(!wsc->getMsg(10ms));
265 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
266 return jv[jss::meta][
"AffectedNodes"][1u][
"ModifiedNode"]
267 [
"FinalFields"][jss::Account] ==
268 Account(
"alice").human();
271 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
272 return jv[jss::meta][
"AffectedNodes"][1u][
"CreatedNode"]
273 [
"NewFields"][
"LowLimit"][jss::issuer] ==
274 Account(
"alice").human();
279 auto jv = wsc->invoke(
"unsubscribe", stream);
280 if (wsc->version() == 2)
283 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
285 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
286 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
288 BEAST_EXPECT(jv[jss::status] ==
"success");
302 stream[jss::streams].append(
"manifests");
303 auto jv = wsc->invoke(
"subscribe", stream);
304 if (wsc->version() == 2)
307 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
309 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
310 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
312 BEAST_EXPECT(jv[jss::status] ==
"success");
316 auto jv = wsc->invoke(
"unsubscribe", stream);
317 if (wsc->version() == 2)
320 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
322 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
323 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
325 BEAST_EXPECT(jv[jss::status] ==
"success");
334 auto& cfg = env.app().config();
335 if (!BEAST_EXPECT(cfg.section(SECTION_VALIDATION_SEED).empty()))
337 auto const parsedseed =
338 parseBase58<Seed>(cfg.section(SECTION_VALIDATION_SEED).values()[0]);
339 if (!BEAST_EXPECT(parsedseed))
354 stream[jss::streams].append(
"validations");
355 auto jv = wsc->invoke(
"subscribe", stream);
356 if (wsc->version() == 2)
359 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
361 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
362 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
364 BEAST_EXPECT(jv[jss::status] ==
"success");
369 auto validValidationFields = [&env, &valPublicKey](
371 if (jv[jss::type] !=
"validationReceived")
374 if (jv[jss::validation_public_key].asString() != valPublicKey)
377 if (jv[jss::ledger_hash] !=
381 if (jv[jss::ledger_index] !=
388 if (jv[jss::full] !=
true)
391 if (jv.isMember(jss::load_fee))
394 if (!jv.isMember(jss::signature))
397 if (!jv.isMember(jss::signing_time))
400 if (!jv.isMember(jss::cookie))
403 if (!jv.isMember(jss::validated_hash))
408 (env.closed()->info().seq + 1) % 256 == 0;
424 while (env.closed()->info().seq < 300)
427 using namespace std::chrono_literals;
428 BEAST_EXPECT(wsc->findMsg(5s, validValidationFields));
433 auto jv = wsc->invoke(
"unsubscribe", stream);
434 if (wsc->version() == 2)
437 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
439 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
440 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
442 BEAST_EXPECT(jv[jss::status] ==
"success");
449 testcase(
"Subscribe by url");
453 jv[jss::url] =
"http://localhost/events";
454 jv[jss::url_username] =
"admin";
455 jv[jss::url_password] =
"password";
457 jv[jss::streams][0u] =
"validations";
458 auto jr = env.rpc(
"json",
"subscribe",
to_string(jv))[jss::result];
459 BEAST_EXPECT(jr[jss::status] ==
"success");
461 jv[jss::streams][0u] =
"ledger";
462 jr = env.rpc(
"json",
"subscribe",
to_string(jv))[jss::result];
463 BEAST_EXPECT(jr[jss::status] ==
"success");
465 jr = env.rpc(
"json",
"unsubscribe",
to_string(jv))[jss::result];
466 BEAST_EXPECT(jr[jss::status] ==
"success");
468 jv[jss::streams][0u] =
"validations";
469 jr = env.rpc(
"json",
"unsubscribe",
to_string(jv))[jss::result];
470 BEAST_EXPECT(jr[jss::status] ==
"success");
477 auto const method = subscribe ?
"subscribe" :
"unsubscribe";
478 testcase <<
"Error cases for " << method;
484 auto jr = env.rpc(
"json", method,
"{}")[jss::result];
485 BEAST_EXPECT(jr[jss::error] ==
"invalidParams");
486 BEAST_EXPECT(jr[jss::error_message] ==
"Invalid parameters.");
491 jv[jss::url] =
"not-a-url";
492 jv[jss::username] =
"admin";
493 jv[jss::password] =
"password";
494 auto jr = env.rpc(
"json", method,
to_string(jv))[jss::result];
497 BEAST_EXPECT(jr[jss::error] ==
"invalidParams");
498 BEAST_EXPECT(jr[jss::error_message] ==
"Failed to parse url.");
506 jv[jss::url] =
"ftp://scheme.not.supported.tld";
507 auto jr = env.rpc(
"json", method,
to_string(jv))[jss::result];
510 BEAST_EXPECT(jr[jss::error] ==
"invalidParams");
512 jr[jss::error_message] ==
513 "Only http and https is supported.");
520 jv[jss::url] =
"no-url";
522 env_nonadmin.rpc(
"json", method,
to_string(jv))[jss::result];
523 BEAST_EXPECT(jr[jss::error] ==
"noPermission");
525 jr[jss::error_message] ==
526 "You don't have permission for this command.");
538 for (
auto const& f : {jss::accounts_proposed, jss::accounts})
540 for (
auto const& nonArray : nonArrays)
544 auto jr = wsc->invoke(method, jv)[jss::result];
545 BEAST_EXPECT(jr[jss::error] ==
"invalidParams");
546 BEAST_EXPECT(jr[jss::error_message] ==
"Invalid parameters.");
552 auto jr = wsc->invoke(method, jv)[jss::result];
553 BEAST_EXPECT(jr[jss::error] ==
"actMalformed");
554 BEAST_EXPECT(jr[jss::error_message] ==
"Account malformed.");
558 for (
auto const& nonArray : nonArrays)
561 jv[jss::books] = nonArray;
562 auto jr = wsc->invoke(method, jv)[jss::result];
563 BEAST_EXPECT(jr[jss::error] ==
"invalidParams");
564 BEAST_EXPECT(jr[jss::error_message] ==
"Invalid parameters.");
570 jv[jss::books][0u] = 1;
571 auto jr = wsc->invoke(method, jv)[jss::result];
572 BEAST_EXPECT(jr[jss::error] ==
"invalidParams");
573 BEAST_EXPECT(jr[jss::error_message] ==
"Invalid parameters.");
582 auto jr = wsc->invoke(method, jv)[jss::result];
583 BEAST_EXPECT(jr[jss::error] ==
"srcCurMalformed");
585 jr[jss::error_message] ==
"Source currency is malformed.");
594 jv[jss::books][0u][jss::taker_pays][jss::currency] =
"ZZZZ";
595 auto jr = wsc->invoke(method, jv)[jss::result];
596 BEAST_EXPECT(jr[jss::error] ==
"srcCurMalformed");
598 jr[jss::error_message] ==
"Source currency is malformed.");
607 jv[jss::books][0u][jss::taker_pays][jss::currency] =
"USD";
608 jv[jss::books][0u][jss::taker_pays][jss::issuer] = 1;
609 auto jr = wsc->invoke(method, jv)[jss::result];
610 BEAST_EXPECT(jr[jss::error] ==
"srcIsrMalformed");
612 jr[jss::error_message] ==
"Source issuer is malformed.");
621 jv[jss::books][0u][jss::taker_pays][jss::currency] =
"USD";
622 jv[jss::books][0u][jss::taker_pays][jss::issuer] =
624 auto jr = wsc->invoke(method, jv)[jss::result];
625 BEAST_EXPECT(jr[jss::error] ==
"srcIsrMalformed");
627 jr[jss::error_message] ==
"Source issuer is malformed.");
634 jv[jss::books][0u][jss::taker_pays] =
635 Account{
"gateway"}[
"USD"](1).value().getJson(
638 auto jr = wsc->invoke(method, jv)[jss::result];
641 BEAST_EXPECT(jr[jss::error] ==
"dstAmtMalformed");
643 jr[jss::error_message] ==
644 "Destination amount/currency/issuer is malformed.");
651 jv[jss::books][0u][jss::taker_pays] =
652 Account{
"gateway"}[
"USD"](1).value().getJson(
654 jv[jss::books][0u][jss::taker_gets][jss::currency] =
"ZZZZ";
655 auto jr = wsc->invoke(method, jv)[jss::result];
658 BEAST_EXPECT(jr[jss::error] ==
"dstAmtMalformed");
660 jr[jss::error_message] ==
661 "Destination amount/currency/issuer is malformed.");
668 jv[jss::books][0u][jss::taker_pays] =
669 Account{
"gateway"}[
"USD"](1).value().getJson(
671 jv[jss::books][0u][jss::taker_gets][jss::currency] =
"USD";
672 jv[jss::books][0u][jss::taker_gets][jss::issuer] = 1;
673 auto jr = wsc->invoke(method, jv)[jss::result];
674 BEAST_EXPECT(jr[jss::error] ==
"dstIsrMalformed");
676 jr[jss::error_message] ==
"Destination issuer is malformed.");
683 jv[jss::books][0u][jss::taker_pays] =
684 Account{
"gateway"}[
"USD"](1).value().getJson(
686 jv[jss::books][0u][jss::taker_gets][jss::currency] =
"USD";
687 jv[jss::books][0u][jss::taker_gets][jss::issuer] =
689 auto jr = wsc->invoke(method, jv)[jss::result];
690 BEAST_EXPECT(jr[jss::error] ==
"dstIsrMalformed");
692 jr[jss::error_message] ==
"Destination issuer is malformed.");
699 jv[jss::books][0u][jss::taker_pays] =
700 Account{
"gateway"}[
"USD"](1).value().getJson(
702 jv[jss::books][0u][jss::taker_gets] =
703 Account{
"gateway"}[
"USD"](1).value().getJson(
705 auto jr = wsc->invoke(method, jv)[jss::result];
706 BEAST_EXPECT(jr[jss::error] ==
"badMarket");
707 BEAST_EXPECT(jr[jss::error_message] ==
"No such market.");
710 for (
auto const& nonArray : nonArrays)
713 jv[jss::streams] = nonArray;
714 auto jr = wsc->invoke(method, jv)[jss::result];
715 BEAST_EXPECT(jr[jss::error] ==
"invalidParams");
716 BEAST_EXPECT(jr[jss::error_message] ==
"Invalid parameters.");
722 jv[jss::streams][0u] = 1;
723 auto jr = wsc->invoke(method, jv)[jss::result];
724 BEAST_EXPECT(jr[jss::error] ==
"malformedStream");
725 BEAST_EXPECT(jr[jss::error_message] ==
"Stream malformed.");
731 jv[jss::streams][0u] =
"not_a_stream";
732 auto jr = wsc->invoke(method, jv)[jss::result];
733 BEAST_EXPECT(jr[jss::error] ==
"malformedStream");
734 BEAST_EXPECT(jr[jss::error_message] ==
"Stream malformed.");