rippled
Loading...
Searching...
No Matches
Config_test.cpp
1#include <test/jtx/TestSuite.h>
2#include <test/unit_test/FileDirGuard.h>
3
4#include <xrpld/core/Config.h>
5#include <xrpld/core/ConfigSections.h>
6
7#include <xrpl/beast/unit_test/suite.h>
8#include <xrpl/server/Port.h>
9
10#include <boost/filesystem.hpp>
11#include <boost/format.hpp>
12
13#include <fstream>
14#include <regex>
15
16namespace ripple {
17namespace detail {
19configContents(std::string const& dbPath, std::string const& validatorsFile)
20{
21 static boost::format configContentsTemplate(R"rippleConfig(
22[server]
23port_rpc
24port_peer
25port_wss_admin
26
27[port_rpc]
28port = 5005
29ip = 127.0.0.1
30admin = 127.0.0.1, ::1
31protocol = https
32
33[port_peer]
34port = 51235
35ip = 0.0.0.0
36protocol = peer
37
38[port_wss_admin]
39port = 6006
40ip = 127.0.0.1
41admin = 127.0.0.1
42protocol = wss
43
44#[port_ws_public]
45#port = 5005
46#ip = 127.0.0.1
47#protocol = wss
48
49#-------------------------------------------------------------------------------
50
51[node_size]
52medium
53
54# This is primary persistent datastore for rippled. This includes transaction
55# metadata, account states, and ledger headers. Helpful information can be
56# found on https://xrpl.org/capacity-planning.html#node-db-type
57# delete old ledgers while maintaining at least 2000. Do not require an
58# external administrative command to initiate deletion.
59[node_db]
60type=memory
61path=/Users/dummy/ripple/config/db/rocksdb
62open_files=2000
63filter_bits=12
64cache_mb=256
65file_size_mb=8
66file_size_mult=2
67
68%1%
69
70%2%
71
72# This needs to be an absolute directory reference, not a relative one.
73# Modify this value as required.
74[debug_logfile]
75/Users/dummy/ripple/config/log/debug.log
76
77[sntp_servers]
78time.windows.com
79time.apple.com
80time.nist.gov
81pool.ntp.org
82
83# Where to find some other servers speaking the Ripple protocol.
84#
85[ips]
86r.ripple.com 51235
87
88# Turn down default logging to save disk space in the long run.
89# Valid values here are trace, debug, info, warning, error, and fatal
90[rpc_startup]
91{ "command": "log_level", "severity": "warning" }
92
93# Defaults to 1 ("yes") so that certificates will be validated. To allow the use
94# of self-signed certificates for development or internal use, set to 0 ("no").
95[ssl_verify]
960
97
98[sqdb]
99backend=sqlite
100)rippleConfig");
101
102 std::string dbPathSection =
103 dbPath.empty() ? "" : "[database_path]\n" + dbPath;
104 std::string valFileSection =
105 validatorsFile.empty() ? "" : "[validators_file]\n" + validatorsFile;
106 return boost::str(configContentsTemplate % dbPathSection % valFileSection);
107}
108
113{
114private:
116
117 bool rmDataDir_{false};
118
120
121public:
124 path subDir,
125 path const& dbPath,
126 path const& validatorsFile,
127 bool useCounter = true,
128 std::string confContents = "")
129 : FileDirGuard(
130 test,
131 std::move(subDir),
132 path(Config::configFileName),
133 confContents.empty()
134 ? configContents(dbPath.string(), validatorsFile.string())
135 : confContents,
136 useCounter)
137 , dataDir_(dbPath)
138 {
139 if (dbPath.empty())
141
142 rmDataDir_ = !exists(dataDir_);
144 file_.string(),
145 /* bQuiet */ true,
146 /* bSilent */ false,
147 /* bStandalone */ false);
148 }
149
150 Config const&
151 config() const
152 {
153 return config_;
154 }
155
158 {
159 return file().string();
160 }
161
162 bool
164 {
165 return boost::filesystem::is_directory(dataDir_);
166 }
167
168 bool
170 {
171 return fileExists();
172 }
173
175 {
176 try
177 {
178 using namespace boost::filesystem;
179 if (rmDataDir_)
181 }
182 catch (std::exception& e)
183 {
184 // if we throw here, just let it die.
185 test_.log << "Error in ~RippledCfgGuard: " << e.what() << std::endl;
186 };
187 }
188};
189
192{
193 std::string configContents(R"rippleConfig(
194[validators]
195n949f75evCHwgyP4fPVgaHqNHxUVN15PsJEZ3B3HnXPcPjcZAoy7
196n9MD5h24qrQqiyBC8aeqqCWvpiBiYQ3jxSr91uiDvmrkyHRdYLUj
197n9L81uNCaPgtUJfaHh89gmdvXKAmSt5Gdsw2g1iPWaPkAHW5Nm4C
198n9KiYM9CgngLvtRCQHZwgC2gjpdaZcCcbt3VboxiNFcKuwFVujzS
199n9LdgEtkmGB9E2h3K4Vp7iGUaKuq23Zr32ehxiU8FWY7xoxbWTSA
200
201[validator_keys]
202nHUhG1PgAG8H8myUENypM35JgfqXAKNQvRVVAFDRzJrny5eZN8d5
203nHBu9PTL9dn2GuZtdW4U2WzBwffyX9qsQCd9CNU4Z5YG3PQfViM8
204nHUPDdcdb2Y5DZAJne4c2iabFuAP3F34xZUgYQT2NH7qfkdapgnz
205
206[validator_list_sites]
207recommendedripplevalidators.com
208moreripplevalidators.net
209
210[validator_list_keys]
21103E74EE14CB525AFBB9F1B7D86CD58ECC4B91452294B42AB4E78F260BD905C091D
212030775A669685BD6ABCEBD80385921C7851783D991A8055FD21D2F3966C96F1B56
213
214[validator_list_threshold]
2152
216)rippleConfig");
217 return configContents;
218}
219
224{
225public:
228 path subDir,
229 path const& validatorsFileName,
230 bool useCounter = true)
231 : FileDirGuard(
232 test,
233 std::move(subDir),
234 path(
235 validatorsFileName.empty() ? Config::validatorsFileName
236 : validatorsFileName),
238 useCounter)
239 {
240 }
241
242 bool
244 {
245 return fileExists();
246 }
247
250 {
251 return absolute(file()).string();
252 }
253
255 {
256 }
257};
258} // namespace detail
259
260class Config_test final : public TestSuite
261{
262private:
263 using path = boost::filesystem::path;
264
265public:
266 void
268 {
269 testcase("legacy");
270
271 Config c;
272
273 std::string toLoad(R"rippleConfig(
274[server]
275port_rpc
276port_peer
277port_wss_admin
278
279[ssl_verify]
2800
281)rippleConfig");
282
283 c.loadFromString(toLoad);
284
285 BEAST_EXPECT(c.legacy("ssl_verify") == "0");
286 expectException([&c] { c.legacy("server"); }); // not a single line
287
288 // set a legacy value
289 BEAST_EXPECT(c.legacy("not_in_file") == "");
290 c.legacy("not_in_file", "new_value");
291 BEAST_EXPECT(c.legacy("not_in_file") == "new_value");
292 }
293 void
295 {
296 testcase("database_path");
297
298 using namespace boost::filesystem;
299 {
300 boost::format cc("[database_path]\n%1%\n");
301
302 auto const cwd = current_path();
303 path const dataDirRel("test_data_dir");
304 path const dataDirAbs(cwd / dataDirRel);
305 {
306 // Dummy test - do we get back what we put in
307 Config c;
308 c.loadFromString(boost::str(cc % dataDirAbs.string()));
309 BEAST_EXPECT(c.legacy("database_path") == dataDirAbs.string());
310 }
311 {
312 // Rel paths should convert to abs paths
313 Config c;
314 c.loadFromString(boost::str(cc % dataDirRel.string()));
315 BEAST_EXPECT(c.legacy("database_path") == dataDirAbs.string());
316 }
317 {
318 // No db section.
319 // N.B. Config::setup will give database_path a default,
320 // load will not.
321 Config c;
322 c.loadFromString("");
323 BEAST_EXPECT(c.legacy("database_path") == "");
324 }
325 }
326 {
327 // read from file absolute path
328 auto const cwd = current_path();
329 ripple::detail::DirGuard const g0(*this, "test_db");
330 path const dataDirRel("test_data_dir");
331 path const dataDirAbs(cwd / g0.subdir() / dataDirRel);
333 *this, g0.subdir(), dataDirAbs, "", false);
334 auto const& c(g.config());
335 BEAST_EXPECT(g.dataDirExists());
336 BEAST_EXPECT(g.configFileExists());
337 BEAST_EXPECT(c.legacy("database_path") == dataDirAbs.string());
338 }
339 {
340 // read from file relative path
341 std::string const dbPath("my_db");
342 detail::RippledCfgGuard const g(*this, "test_db", dbPath, "");
343 auto const& c(g.config());
344 std::string const nativeDbPath = absolute(path(dbPath)).string();
345 BEAST_EXPECT(g.dataDirExists());
346 BEAST_EXPECT(g.configFileExists());
347 BEAST_EXPECT(c.legacy("database_path") == nativeDbPath);
348 }
349 {
350 // read from file no path
351 detail::RippledCfgGuard const g(*this, "test_db", "", "");
352 auto const& c(g.config());
353 std::string const nativeDbPath =
354 absolute(g.subdir() / path(Config::databaseDirName)).string();
355 BEAST_EXPECT(g.dataDirExists());
356 BEAST_EXPECT(g.configFileExists());
357 BEAST_EXPECT(c.legacy("database_path") == nativeDbPath);
358 }
359 }
360
361 void
363 {
364 testcase("validator keys");
365
366 std::string const validationSeed = "spA4sh1qTvwq92X715tYyGQKmAKfa";
367
368 auto const token =
369 "eyJ2YWxpZGF0aW9uX3ByaXZhdGVfa2V5IjoiOWVkNDVmODY2MjQxY2MxOGEyNzQ3Yj"
370 "U0Mzg3YzA2MjU5MDc5NzJmNGU3MTkwMjMxZmFhOTM3NDU3ZmE5ZGFmNiIsIm1hbmlm"
371 "ZXN0IjoiSkFBQUFBRnhJZTFGdHdtaW12R3RIMmlDY01KcUM5Z1ZGS2lsR2Z3MS92Q3"
372 "hIWFhMcGxjMkduTWhBa0UxYWdxWHhCd0R3RGJJRDZPTVNZdU0wRkRBbHBBZ05rOFNL"
373 "Rm43TU8yZmRrY3dSUUloQU9uZ3U5c0FLcVhZb3VKK2wyVjBXK3NBT2tWQitaUlM2UF"
374 "NobEpBZlVzWGZBaUJzVkpHZXNhYWRPSmMvYUFab2tTMXZ5bUdtVnJsSFBLV1gzWXl3"
375 "dTZpbjhIQVNRS1B1Z0JENjdrTWFSRkd2bXBBVEhsR0tKZHZERmxXUFl5NUFxRGVkRn"
376 "Y1VEphMncwaTIxZXEzTVl5d0xWSlpuRk9yN0Mwa3cyQWlUelNDakl6ZGl0UTg9In0"
377 "=";
378
379 {
380 Config c;
381 static boost::format configTemplate(R"rippleConfig(
382[validation_seed]
383%1%
384
385[validator_token]
386%2%
387)rippleConfig");
388 std::string error;
389 auto const expectedError =
390 "Cannot have both [validation_seed] "
391 "and [validator_token] config sections";
392 try
393 {
395 boost::str(configTemplate % validationSeed % token));
396 }
397 catch (std::runtime_error& e)
398 {
399 error = e.what();
400 }
401 BEAST_EXPECT(error == expectedError);
402 }
403 }
404
405 void
407 {
408 testcase("network id");
409 std::string error;
410 Config c;
411 try
412 {
413 c.loadFromString(R"rippleConfig(
414[network_id]
415main
416)rippleConfig");
417 }
418 catch (std::runtime_error& e)
419 {
420 error = e.what();
421 }
422
423 BEAST_EXPECT(error == "");
424 BEAST_EXPECT(c.NETWORK_ID == 0);
425
426 try
427 {
428 c.loadFromString(R"rippleConfig(
429)rippleConfig");
430 }
431 catch (std::runtime_error& e)
432 {
433 error = e.what();
434 }
435
436 BEAST_EXPECT(error == "");
437 BEAST_EXPECT(c.NETWORK_ID == 0);
438
439 try
440 {
441 c.loadFromString(R"rippleConfig(
442[network_id]
443255
444)rippleConfig");
445 }
446 catch (std::runtime_error& e)
447 {
448 error = e.what();
449 }
450
451 BEAST_EXPECT(error == "");
452 BEAST_EXPECT(c.NETWORK_ID == 255);
453
454 try
455 {
456 c.loadFromString(R"rippleConfig(
457[network_id]
45810000
459)rippleConfig");
460 }
461 catch (std::runtime_error& e)
462 {
463 error = e.what();
464 }
465
466 BEAST_EXPECT(error == "");
467 BEAST_EXPECT(c.NETWORK_ID == 10000);
468 }
469
470 void
472 {
473 testcase("validators_file");
474
475 using namespace boost::filesystem;
476 {
477 // load should throw for missing specified validators file
478 boost::format cc("[validators_file]\n%1%\n");
479 std::string error;
480 std::string const missingPath = "/no/way/this/path/exists";
481 auto const expectedError =
482 "The file specified in [validators_file] does not exist: " +
483 missingPath;
484 try
485 {
486 Config c;
487 c.loadFromString(boost::str(cc % missingPath));
488 }
489 catch (std::runtime_error& e)
490 {
491 error = e.what();
492 }
493 BEAST_EXPECT(error == expectedError);
494 }
495 {
496 // load should throw for invalid [validators_file]
498 *this, "test_cfg", "validators.cfg");
499 path const invalidFile = current_path() / vtg.subdir();
500 boost::format cc("[validators_file]\n%1%\n");
501 std::string error;
502 auto const expectedError =
503 "Invalid file specified in [validators_file]: " +
504 invalidFile.string();
505 try
506 {
507 Config c;
508 c.loadFromString(boost::str(cc % invalidFile.string()));
509 }
510 catch (std::runtime_error& e)
511 {
512 error = e.what();
513 }
514 BEAST_EXPECT(error == expectedError);
515 }
516 {
517 // load validators from config into single section
518 Config c;
519 std::string toLoad(R"rippleConfig(
520[validators]
521n949f75evCHwgyP4fPVgaHqNHxUVN15PsJEZ3B3HnXPcPjcZAoy7
522n9MD5h24qrQqiyBC8aeqqCWvpiBiYQ3jxSr91uiDvmrkyHRdYLUj
523n9L81uNCaPgtUJfaHh89gmdvXKAmSt5Gdsw2g1iPWaPkAHW5Nm4C
524
525[validator_keys]
526nHUhG1PgAG8H8myUENypM35JgfqXAKNQvRVVAFDRzJrny5eZN8d5
527nHBu9PTL9dn2GuZtdW4U2WzBwffyX9qsQCd9CNU4Z5YG3PQfViM8
528)rippleConfig");
529 c.loadFromString(toLoad);
530 BEAST_EXPECT(c.legacy("validators_file").empty());
531 BEAST_EXPECT(c.section(SECTION_VALIDATORS).values().size() == 5);
532 BEAST_EXPECT(c.VALIDATOR_LIST_THRESHOLD == std::nullopt);
533 }
534 {
535 // load validator list sites and keys from config
536 Config c;
537 std::string toLoad(R"rippleConfig(
538[validator_list_sites]
539ripplevalidators.com
540trustthesevalidators.gov
541
542[validator_list_keys]
543021A99A537FDEBC34E4FCA03B39BEADD04299BB19E85097EC92B15A3518801E566
544
545[validator_list_threshold]
5461
547)rippleConfig");
548 c.loadFromString(toLoad);
549 BEAST_EXPECT(
550 c.section(SECTION_VALIDATOR_LIST_SITES).values().size() == 2);
551 BEAST_EXPECT(
552 c.section(SECTION_VALIDATOR_LIST_SITES).values()[0] ==
553 "ripplevalidators.com");
554 BEAST_EXPECT(
555 c.section(SECTION_VALIDATOR_LIST_SITES).values()[1] ==
556 "trustthesevalidators.gov");
557 BEAST_EXPECT(
558 c.section(SECTION_VALIDATOR_LIST_KEYS).values().size() == 1);
559 BEAST_EXPECT(
560 c.section(SECTION_VALIDATOR_LIST_KEYS).values()[0] ==
561 "021A99A537FDEBC34E4FCA03B39BEADD04299BB19E85097EC92B15A3518801"
562 "E566");
563 BEAST_EXPECT(
564 c.section(SECTION_VALIDATOR_LIST_THRESHOLD).values().size() ==
565 1);
566 BEAST_EXPECT(
567 c.section(SECTION_VALIDATOR_LIST_THRESHOLD).values()[0] == "1");
568 BEAST_EXPECT(c.VALIDATOR_LIST_THRESHOLD == std::size_t(1));
569 }
570 {
571 // load validator list sites and keys from config
572 Config c;
573 std::string toLoad(R"rippleConfig(
574[validator_list_sites]
575ripplevalidators.com
576trustthesevalidators.gov
577
578[validator_list_keys]
579021A99A537FDEBC34E4FCA03B39BEADD04299BB19E85097EC92B15A3518801E566
580
581[validator_list_threshold]
5820
583)rippleConfig");
584 c.loadFromString(toLoad);
585 BEAST_EXPECT(
586 c.section(SECTION_VALIDATOR_LIST_SITES).values().size() == 2);
587 BEAST_EXPECT(
588 c.section(SECTION_VALIDATOR_LIST_SITES).values()[0] ==
589 "ripplevalidators.com");
590 BEAST_EXPECT(
591 c.section(SECTION_VALIDATOR_LIST_SITES).values()[1] ==
592 "trustthesevalidators.gov");
593 BEAST_EXPECT(
594 c.section(SECTION_VALIDATOR_LIST_KEYS).values().size() == 1);
595 BEAST_EXPECT(
596 c.section(SECTION_VALIDATOR_LIST_KEYS).values()[0] ==
597 "021A99A537FDEBC34E4FCA03B39BEADD04299BB19E85097EC92B15A3518801"
598 "E566");
599 BEAST_EXPECT(
600 c.section(SECTION_VALIDATOR_LIST_THRESHOLD).values().size() ==
601 1);
602 BEAST_EXPECT(
603 c.section(SECTION_VALIDATOR_LIST_THRESHOLD).values()[0] == "0");
604 BEAST_EXPECT(c.VALIDATOR_LIST_THRESHOLD == std::nullopt);
605 }
606 {
607 // load should throw if [validator_list_threshold] is greater than
608 // the number of [validator_list_keys]
609 Config c;
610 std::string toLoad(R"rippleConfig(
611[validator_list_sites]
612ripplevalidators.com
613trustthesevalidators.gov
614
615[validator_list_keys]
616021A99A537FDEBC34E4FCA03B39BEADD04299BB19E85097EC92B15A3518801E566
617
618[validator_list_threshold]
6192
620)rippleConfig");
621 std::string error;
622 auto const expectedError =
623 "Value in config section [validator_list_threshold] exceeds "
624 "the number of configured list keys";
625 try
626 {
627 c.loadFromString(toLoad);
628 fail();
629 }
630 catch (std::runtime_error& e)
631 {
632 error = e.what();
633 }
634 BEAST_EXPECT(error == expectedError);
635 }
636 {
637 // load should throw if [validator_list_threshold] is malformed
638 Config c;
639 std::string toLoad(R"rippleConfig(
640[validator_list_sites]
641ripplevalidators.com
642trustthesevalidators.gov
643
644[validator_list_keys]
645021A99A537FDEBC34E4FCA03B39BEADD04299BB19E85097EC92B15A3518801E566
646
647[validator_list_threshold]
648value = 2
649)rippleConfig");
650 std::string error;
651 auto const expectedError =
652 "Config section [validator_list_threshold] should contain "
653 "single value only";
654 try
655 {
656 c.loadFromString(toLoad);
657 fail();
658 }
659 catch (std::runtime_error& e)
660 {
661 error = e.what();
662 }
663 BEAST_EXPECT(error == expectedError);
664 }
665 {
666 // load should throw if [validator_list_threshold] is negative
667 Config c;
668 std::string toLoad(R"rippleConfig(
669[validator_list_sites]
670ripplevalidators.com
671trustthesevalidators.gov
672
673[validator_list_keys]
674021A99A537FDEBC34E4FCA03B39BEADD04299BB19E85097EC92B15A3518801E566
675
676[validator_list_threshold]
677-1
678)rippleConfig");
679 bool error = false;
680 try
681 {
682 c.loadFromString(toLoad);
683 fail();
684 }
685 catch (std::bad_cast& e)
686 {
687 error = true;
688 }
689 BEAST_EXPECT(error);
690 }
691 {
692 // load should throw if [validator_list_sites] is configured but
693 // [validator_list_keys] is not
694 Config c;
695 std::string toLoad(R"rippleConfig(
696[validator_list_sites]
697ripplevalidators.com
698trustthesevalidators.gov
699)rippleConfig");
700 std::string error;
701 auto const expectedError =
702 "[validator_list_keys] config section is missing";
703 try
704 {
705 c.loadFromString(toLoad);
706 fail();
707 }
708 catch (std::runtime_error& e)
709 {
710 error = e.what();
711 }
712 BEAST_EXPECT(error == expectedError);
713 }
714 {
715 // load from specified [validators_file] absolute path
717 *this, "test_cfg", "validators.cfg");
718 BEAST_EXPECT(vtg.validatorsFileExists());
719 Config c;
720 boost::format cc("[validators_file]\n%1%\n");
721 c.loadFromString(boost::str(cc % vtg.validatorsFile()));
722 BEAST_EXPECT(c.legacy("validators_file") == vtg.validatorsFile());
723 BEAST_EXPECT(c.section(SECTION_VALIDATORS).values().size() == 8);
724 BEAST_EXPECT(
725 c.section(SECTION_VALIDATOR_LIST_SITES).values().size() == 2);
726 BEAST_EXPECT(
727 c.section(SECTION_VALIDATOR_LIST_KEYS).values().size() == 2);
728 BEAST_EXPECT(
729 c.section(SECTION_VALIDATOR_LIST_THRESHOLD).values().size() ==
730 1);
731 BEAST_EXPECT(c.VALIDATOR_LIST_THRESHOLD == 2);
732 }
733 {
734 // load from specified [validators_file] file name
735 // in config directory
736 std::string const valFileName = "validators.txt";
738 *this, "test_cfg", valFileName);
739 detail::RippledCfgGuard const rcg(
740 *this, vtg.subdir(), "", valFileName, false);
741 BEAST_EXPECT(vtg.validatorsFileExists());
742 BEAST_EXPECT(rcg.configFileExists());
743 auto const& c(rcg.config());
744 BEAST_EXPECT(c.legacy("validators_file") == valFileName);
745 BEAST_EXPECT(c.section(SECTION_VALIDATORS).values().size() == 8);
746 BEAST_EXPECT(
747 c.section(SECTION_VALIDATOR_LIST_SITES).values().size() == 2);
748 BEAST_EXPECT(
749 c.section(SECTION_VALIDATOR_LIST_KEYS).values().size() == 2);
750 BEAST_EXPECT(
751 c.section(SECTION_VALIDATOR_LIST_THRESHOLD).values().size() ==
752 1);
753 BEAST_EXPECT(c.VALIDATOR_LIST_THRESHOLD == 2);
754 }
755 {
756 // load from specified [validators_file] relative path
757 // to config directory
759 *this, "test_cfg", "validators.txt");
760 auto const valFilePath = ".." / vtg.subdir() / "validators.txt";
761 detail::RippledCfgGuard const rcg(
762 *this, vtg.subdir(), "", valFilePath, false);
763 BEAST_EXPECT(vtg.validatorsFileExists());
764 BEAST_EXPECT(rcg.configFileExists());
765 auto const& c(rcg.config());
766 BEAST_EXPECT(c.legacy("validators_file") == valFilePath);
767 BEAST_EXPECT(c.section(SECTION_VALIDATORS).values().size() == 8);
768 BEAST_EXPECT(
769 c.section(SECTION_VALIDATOR_LIST_SITES).values().size() == 2);
770 BEAST_EXPECT(
771 c.section(SECTION_VALIDATOR_LIST_KEYS).values().size() == 2);
772 BEAST_EXPECT(
773 c.section(SECTION_VALIDATOR_LIST_THRESHOLD).values().size() ==
774 1);
775 BEAST_EXPECT(c.VALIDATOR_LIST_THRESHOLD == 2);
776 }
777 {
778 // load from validators file in default location
780 *this, "test_cfg", "validators.txt");
781 detail::RippledCfgGuard const rcg(
782 *this, vtg.subdir(), "", "", false);
783 BEAST_EXPECT(vtg.validatorsFileExists());
784 BEAST_EXPECT(rcg.configFileExists());
785 auto const& c(rcg.config());
786 BEAST_EXPECT(c.legacy("validators_file").empty());
787 BEAST_EXPECT(c.section(SECTION_VALIDATORS).values().size() == 8);
788 BEAST_EXPECT(
789 c.section(SECTION_VALIDATOR_LIST_SITES).values().size() == 2);
790 BEAST_EXPECT(
791 c.section(SECTION_VALIDATOR_LIST_KEYS).values().size() == 2);
792 BEAST_EXPECT(
793 c.section(SECTION_VALIDATOR_LIST_THRESHOLD).values().size() ==
794 1);
795 BEAST_EXPECT(c.VALIDATOR_LIST_THRESHOLD == 2);
796 }
797 {
798 // load from specified [validators_file] instead
799 // of default location
801 *this, "test_cfg", "validators.cfg");
802 BEAST_EXPECT(vtg.validatorsFileExists());
803 detail::ValidatorsTxtGuard const vtgDefault(
804 *this, vtg.subdir(), "validators.txt", false);
805 BEAST_EXPECT(vtgDefault.validatorsFileExists());
806 detail::RippledCfgGuard const rcg(
807 *this, vtg.subdir(), "", vtg.validatorsFile(), false);
808 BEAST_EXPECT(rcg.configFileExists());
809 auto const& c(rcg.config());
810 BEAST_EXPECT(c.legacy("validators_file") == vtg.validatorsFile());
811 BEAST_EXPECT(c.section(SECTION_VALIDATORS).values().size() == 8);
812 BEAST_EXPECT(
813 c.section(SECTION_VALIDATOR_LIST_SITES).values().size() == 2);
814 BEAST_EXPECT(
815 c.section(SECTION_VALIDATOR_LIST_KEYS).values().size() == 2);
816 BEAST_EXPECT(
817 c.section(SECTION_VALIDATOR_LIST_THRESHOLD).values().size() ==
818 1);
819 BEAST_EXPECT(c.VALIDATOR_LIST_THRESHOLD == 2);
820 }
821
822 {
823 // load validators from both config and validators file
824 boost::format cc(R"rippleConfig(
825[validators_file]
826%1%
827
828[validators]
829n949f75evCHwgyP4fPVgaHqNHxUVN15PsJEZ3B3HnXPcPjcZAoy7
830n9MD5h24qrQqiyBC8aeqqCWvpiBiYQ3jxSr91uiDvmrkyHRdYLUj
831n9L81uNCaPgtUJfaHh89gmdvXKAmSt5Gdsw2g1iPWaPkAHW5Nm4C
832n9KiYM9CgngLvtRCQHZwgC2gjpdaZcCcbt3VboxiNFcKuwFVujzS
833n9LdgEtkmGB9E2h3K4Vp7iGUaKuq23Zr32ehxiU8FWY7xoxbWTSA
834
835[validator_keys]
836nHB1X37qrniVugfQcuBTAjswphC1drx7QjFFojJPZwKHHnt8kU7v
837nHUkAWDR4cB8AgPg7VXMX6et8xRTQb2KJfgv1aBEXozwrawRKgMB
838
839[validator_list_sites]
840ripplevalidators.com
841trustthesevalidators.gov
842
843[validator_list_keys]
844021A99A537FDEBC34E4FCA03B39BEADD04299BB19E85097EC92B15A3518801E566
845)rippleConfig");
847 *this, "test_cfg", "validators.cfg");
848 BEAST_EXPECT(vtg.validatorsFileExists());
849 Config c;
850 c.loadFromString(boost::str(cc % vtg.validatorsFile()));
851 BEAST_EXPECT(c.legacy("validators_file") == vtg.validatorsFile());
852 BEAST_EXPECT(c.section(SECTION_VALIDATORS).values().size() == 15);
853 BEAST_EXPECT(
854 c.section(SECTION_VALIDATOR_LIST_SITES).values().size() == 4);
855 BEAST_EXPECT(
856 c.section(SECTION_VALIDATOR_LIST_KEYS).values().size() == 3);
857 BEAST_EXPECT(
858 c.section(SECTION_VALIDATOR_LIST_THRESHOLD).values().size() ==
859 1);
860 BEAST_EXPECT(c.VALIDATOR_LIST_THRESHOLD == 2);
861 }
862 {
863 // load should throw if [validator_list_threshold] is present both
864 // in rippled cfg and validators file
865 boost::format cc(R"rippleConfig(
866[validators_file]
867%1%
868
869[validator_list_threshold]
8701
871)rippleConfig");
872 std::string error;
874 *this, "test_cfg", "validators.cfg");
875 BEAST_EXPECT(vtg.validatorsFileExists());
876 auto const expectedError =
877 "Config section [validator_list_threshold] should contain "
878 "single value only";
879 try
880 {
881 Config c;
882 c.loadFromString(boost::str(cc % vtg.validatorsFile()));
883 fail();
884 }
885 catch (std::runtime_error& e)
886 {
887 error = e.what();
888 }
889 BEAST_EXPECT(error == expectedError);
890 }
891 {
892 // load should throw if [validators], [validator_keys] and
893 // [validator_list_keys] are missing from rippled cfg and
894 // validators file
895 Config c;
896 boost::format cc("[validators_file]\n%1%\n");
897 std::string error;
899 *this, "test_cfg", "validators.cfg");
900 BEAST_EXPECT(vtg.validatorsFileExists());
901 auto const expectedError =
902 "The file specified in [validators_file] does not contain a "
903 "[validators], [validator_keys] or [validator_list_keys] "
904 "section: " +
905 vtg.validatorsFile();
907 try
908 {
909 Config c2;
910 c2.loadFromString(boost::str(cc % vtg.validatorsFile()));
911 }
912 catch (std::runtime_error& e)
913 {
914 error = e.what();
915 }
916 BEAST_EXPECT(error == expectedError);
917 }
918 }
919
920 void
921 testSetup(bool explicitPath)
922 {
923 detail::RippledCfgGuard const cfg(
924 *this, "testSetup", explicitPath ? "test_db" : "", "");
925 /* RippledCfgGuard has a Config object that gets loaded on
926 construction, but Config::setup is not reentrant, so we
927 need a fresh config for every test case, so ignore it.
928 */
929 {
930 Config config;
931 config.setup(
932 cfg.configFile(),
933 /*bQuiet*/ false,
934 /* bSilent */ false,
935 /* bStandalone */ false);
936 BEAST_EXPECT(!config.quiet());
937 BEAST_EXPECT(!config.silent());
938 BEAST_EXPECT(!config.standalone());
939 BEAST_EXPECT(config.LEDGER_HISTORY == 256);
940 BEAST_EXPECT(!config.legacy("database_path").empty());
941 }
942 {
943 Config config;
944 config.setup(
945 cfg.configFile(),
946 /*bQuiet*/ true,
947 /* bSilent */ false,
948 /* bStandalone */ false);
949 BEAST_EXPECT(config.quiet());
950 BEAST_EXPECT(!config.silent());
951 BEAST_EXPECT(!config.standalone());
952 BEAST_EXPECT(config.LEDGER_HISTORY == 256);
953 BEAST_EXPECT(!config.legacy("database_path").empty());
954 }
955 {
956 Config config;
957 config.setup(
958 cfg.configFile(),
959 /*bQuiet*/ false,
960 /* bSilent */ true,
961 /* bStandalone */ false);
962 BEAST_EXPECT(config.quiet());
963 BEAST_EXPECT(config.silent());
964 BEAST_EXPECT(!config.standalone());
965 BEAST_EXPECT(config.LEDGER_HISTORY == 256);
966 BEAST_EXPECT(!config.legacy("database_path").empty());
967 }
968 {
969 Config config;
970 config.setup(
971 cfg.configFile(),
972 /*bQuiet*/ true,
973 /* bSilent */ true,
974 /* bStandalone */ false);
975 BEAST_EXPECT(config.quiet());
976 BEAST_EXPECT(config.silent());
977 BEAST_EXPECT(!config.standalone());
978 BEAST_EXPECT(config.LEDGER_HISTORY == 256);
979 BEAST_EXPECT(!config.legacy("database_path").empty());
980 }
981 {
982 Config config;
983 config.setup(
984 cfg.configFile(),
985 /*bQuiet*/ false,
986 /* bSilent */ false,
987 /* bStandalone */ true);
988 BEAST_EXPECT(!config.quiet());
989 BEAST_EXPECT(!config.silent());
990 BEAST_EXPECT(config.standalone());
991 BEAST_EXPECT(config.LEDGER_HISTORY == 0);
992 BEAST_EXPECT(
993 config.legacy("database_path").empty() == !explicitPath);
994 }
995 {
996 Config config;
997 config.setup(
998 cfg.configFile(),
999 /*bQuiet*/ true,
1000 /* bSilent */ false,
1001 /* bStandalone */ true);
1002 BEAST_EXPECT(config.quiet());
1003 BEAST_EXPECT(!config.silent());
1004 BEAST_EXPECT(config.standalone());
1005 BEAST_EXPECT(config.LEDGER_HISTORY == 0);
1006 BEAST_EXPECT(
1007 config.legacy("database_path").empty() == !explicitPath);
1008 }
1009 {
1010 Config config;
1011 config.setup(
1012 cfg.configFile(),
1013 /*bQuiet*/ false,
1014 /* bSilent */ true,
1015 /* bStandalone */ true);
1016 BEAST_EXPECT(config.quiet());
1017 BEAST_EXPECT(config.silent());
1018 BEAST_EXPECT(config.standalone());
1019 BEAST_EXPECT(config.LEDGER_HISTORY == 0);
1020 BEAST_EXPECT(
1021 config.legacy("database_path").empty() == !explicitPath);
1022 }
1023 {
1024 Config config;
1025 config.setup(
1026 cfg.configFile(),
1027 /*bQuiet*/ true,
1028 /* bSilent */ true,
1029 /* bStandalone */ true);
1030 BEAST_EXPECT(config.quiet());
1031 BEAST_EXPECT(config.silent());
1032 BEAST_EXPECT(config.standalone());
1033 BEAST_EXPECT(config.LEDGER_HISTORY == 0);
1034 BEAST_EXPECT(
1035 config.legacy("database_path").empty() == !explicitPath);
1036 }
1037 }
1038
1039 void
1041 {
1042 detail::RippledCfgGuard const cfg(*this, "testPort", "", "");
1043 auto const& conf = cfg.config();
1044 if (!BEAST_EXPECT(conf.exists("port_rpc")))
1045 return;
1046 if (!BEAST_EXPECT(conf.exists("port_wss_admin")))
1047 return;
1048 ParsedPort rpc;
1049 if (!unexcept([&]() { parse_Port(rpc, conf["port_rpc"], log); }))
1050 return;
1051 BEAST_EXPECT(rpc.admin_nets_v4.size() + rpc.admin_nets_v6.size() == 2);
1052 ParsedPort wss;
1053 if (!unexcept([&]() { parse_Port(wss, conf["port_wss_admin"], log); }))
1054 return;
1055 BEAST_EXPECT(wss.admin_nets_v4.size() + wss.admin_nets_v6.size() == 1);
1056 }
1057
1058 void
1060 {
1061 auto const contents = std::regex_replace(
1062 detail::configContents("", ""),
1063 std::regex("port\\s*=\\s*\\d+"),
1064 "port = 0");
1065
1066 try
1067 {
1068 detail::RippledCfgGuard const cfg(
1069 *this, "testPort", "", "", true, contents);
1070 BEAST_EXPECT(false);
1071 }
1072 catch (std::exception const& ex)
1073 {
1074 BEAST_EXPECT(std::string_view(ex.what()).starts_with(
1075 "Invalid value '0' for key 'port'"));
1076 }
1077 }
1078
1079 void
1081 {
1082 Config cfg;
1083 /* NOTE: this string includes some explicit
1084 * space chars in order to verify proper trimming */
1085 std::string toLoad(R"(
1086[port_rpc])"
1087 "\x20"
1088 R"(
1089# comment
1090 # indented comment
1091)"
1092 "\x20\x20"
1093 R"(
1094[ips])"
1095 "\x20"
1096 R"(
1097r.ripple.com 51235
1098
1099 [ips_fixed])"
1100 "\x20\x20"
1101 R"(
1102 # COMMENT
1103 s1.ripple.com 51235
1104 s2.ripple.com 51235
1105
1106)");
1107 cfg.loadFromString(toLoad);
1108 BEAST_EXPECT(
1109 cfg.exists("port_rpc") && cfg.section("port_rpc").lines().empty() &&
1110 cfg.section("port_rpc").values().empty());
1111 BEAST_EXPECT(
1112 cfg.exists(SECTION_IPS) &&
1113 cfg.section(SECTION_IPS).lines().size() == 1 &&
1114 cfg.section(SECTION_IPS).values().size() == 1);
1115 BEAST_EXPECT(
1116 cfg.exists(SECTION_IPS_FIXED) &&
1117 cfg.section(SECTION_IPS_FIXED).lines().size() == 2 &&
1118 cfg.section(SECTION_IPS_FIXED).values().size() == 2);
1119 }
1120
1121 void
1122 testColons()
1123 {
1124 Config cfg;
1125 /* NOTE: this string includes some explicit
1126 * space chars in order to verify proper trimming */
1127 std::string toLoad(R"(
1128[port_rpc])"
1129 "\x20"
1130 R"(
1131# comment
1132 # indented comment
1133)"
1134 "\x20\x20"
1135 R"(
1136[ips])"
1137 "\x20"
1138 R"(
1139r.ripple.com:51235
1140
1141 [ips_fixed])"
1142 "\x20\x20"
1143 R"(
1144 # COMMENT
1145 s1.ripple.com:51235
1146 s2.ripple.com 51235
1147 anotherserversansport
1148 anotherserverwithport:12
1149 1.1.1.1:1
1150 1.1.1.1 1
1151 12.34.12.123:12345
1152 12.34.12.123 12345
1153 ::
1154 2001:db8::
1155 ::1
1156 ::1:12345
1157 [::1]:12345
1158 2001:db8:3333:4444:5555:6666:7777:8888:12345
1159 [2001:db8:3333:4444:5555:6666:7777:8888]:1
1160
1161
1162)");
1163 cfg.loadFromString(toLoad);
1164 BEAST_EXPECT(
1165 cfg.exists("port_rpc") && cfg.section("port_rpc").lines().empty() &&
1166 cfg.section("port_rpc").values().empty());
1167 BEAST_EXPECT(
1168 cfg.exists(SECTION_IPS) &&
1169 cfg.section(SECTION_IPS).lines().size() == 1 &&
1170 cfg.section(SECTION_IPS).values().size() == 1);
1171 BEAST_EXPECT(
1172 cfg.exists(SECTION_IPS_FIXED) &&
1173 cfg.section(SECTION_IPS_FIXED).lines().size() == 15 &&
1174 cfg.section(SECTION_IPS_FIXED).values().size() == 15);
1175 BEAST_EXPECT(cfg.IPS[0] == "r.ripple.com 51235");
1176
1177 BEAST_EXPECT(cfg.IPS_FIXED[0] == "s1.ripple.com 51235");
1178 BEAST_EXPECT(cfg.IPS_FIXED[1] == "s2.ripple.com 51235");
1179 BEAST_EXPECT(cfg.IPS_FIXED[2] == "anotherserversansport");
1180 BEAST_EXPECT(cfg.IPS_FIXED[3] == "anotherserverwithport 12");
1181 BEAST_EXPECT(cfg.IPS_FIXED[4] == "1.1.1.1 1");
1182 BEAST_EXPECT(cfg.IPS_FIXED[5] == "1.1.1.1 1");
1183 BEAST_EXPECT(cfg.IPS_FIXED[6] == "12.34.12.123 12345");
1184 BEAST_EXPECT(cfg.IPS_FIXED[7] == "12.34.12.123 12345");
1185
1186 // all ipv6 should be ignored by colon replacer, howsoever formated
1187 BEAST_EXPECT(cfg.IPS_FIXED[8] == "::");
1188 BEAST_EXPECT(cfg.IPS_FIXED[9] == "2001:db8::");
1189 BEAST_EXPECT(cfg.IPS_FIXED[10] == "::1");
1190 BEAST_EXPECT(cfg.IPS_FIXED[11] == "::1:12345");
1191 BEAST_EXPECT(cfg.IPS_FIXED[12] == "[::1]:12345");
1192 BEAST_EXPECT(
1193 cfg.IPS_FIXED[13] ==
1194 "2001:db8:3333:4444:5555:6666:7777:8888:12345");
1195 BEAST_EXPECT(
1196 cfg.IPS_FIXED[14] == "[2001:db8:3333:4444:5555:6666:7777:8888]:1");
1197 }
1198
1199 void
1200 testComments()
1201 {
1202 struct TestCommentData
1203 {
1204 std::string_view line;
1205 std::string_view field;
1206 std::string_view expect;
1207 bool had_comment;
1208 };
1209
1211 {{"password = aaaa\\#bbbb", "password", "aaaa#bbbb", false},
1212 {"password = aaaa#bbbb", "password", "aaaa", true},
1213 {"password = aaaa #bbbb", "password", "aaaa", true},
1214 // since the value is all comment, this doesn't parse as k=v :
1215 {"password = #aaaa #bbbb", "", "password =", true},
1216 {"password = aaaa\\# #bbbb", "password", "aaaa#", true},
1217 {"password = aaaa\\##bbbb", "password", "aaaa#", true},
1218 {"aaaa#bbbb", "", "aaaa", true},
1219 {"aaaa\\#bbbb", "", "aaaa#bbbb", false},
1220 {"aaaa\\##bbbb", "", "aaaa#", true},
1221 {"aaaa #bbbb", "", "aaaa", true},
1222 {"1 #comment", "", "1", true},
1223 {"#whole thing is comment", "", "", false},
1224 {" #whole comment with space", "", "", false}}};
1225
1226 for (auto const& t : tests)
1227 {
1228 Section s;
1229 s.append(t.line.data());
1230 BEAST_EXPECT(s.had_trailing_comments() == t.had_comment);
1231 if (t.field.empty())
1232 {
1233 BEAST_EXPECTS(s.legacy() == t.expect, s.legacy());
1234 }
1235 else
1236 {
1238 BEAST_EXPECTS(set(field, t.field.data(), s), t.line);
1239 BEAST_EXPECTS(field == t.expect, t.line);
1240 }
1241 }
1242
1243 {
1244 Section s;
1245 s.append("online_delete = 3000");
1246 std::uint32_t od = 0;
1247 BEAST_EXPECT(set(od, "online_delete", s));
1248 BEAST_EXPECTS(od == 3000, *(s.get<std::string>("online_delete")));
1249 }
1250
1251 {
1252 Section s;
1253 s.append("online_delete = 2000 #my comment on this");
1254 std::uint32_t od = 0;
1255 BEAST_EXPECT(set(od, "online_delete", s));
1256 BEAST_EXPECTS(od == 2000, *(s.get<std::string>("online_delete")));
1257 }
1258 }
1259
1260 void
1261 testGetters()
1262 {
1263 using namespace std::string_literals;
1264 Section s{"MySection"};
1265 s.append("a_string = mystring");
1266 s.append("positive_int = 2");
1267 s.append("negative_int = -3");
1268 s.append("bool_ish = 1");
1269
1270 {
1271 auto val_1 = "value 1"s;
1272 BEAST_EXPECT(set(val_1, "a_string", s));
1273 BEAST_EXPECT(val_1 == "mystring");
1274
1275 auto val_2 = "value 2"s;
1276 BEAST_EXPECT(!set(val_2, "not_a_key", s));
1277 BEAST_EXPECT(val_2 == "value 2");
1278 BEAST_EXPECT(!set(val_2, "default"s, "not_a_key", s));
1279 BEAST_EXPECT(val_2 == "default");
1280
1281 auto val_3 = get<std::string>(s, "a_string");
1282 BEAST_EXPECT(val_3 == "mystring");
1283 auto val_4 = get<std::string>(s, "not_a_key");
1284 BEAST_EXPECT(val_4 == "");
1285 auto val_5 = get<std::string>(s, "not_a_key", "default");
1286 BEAST_EXPECT(val_5 == "default");
1287
1288 auto val_6 = "value 6"s;
1289 BEAST_EXPECT(get_if_exists(s, "a_string", val_6));
1290 BEAST_EXPECT(val_6 == "mystring");
1291
1292 auto val_7 = "value 7"s;
1293 BEAST_EXPECT(!get_if_exists(s, "not_a_key", val_7));
1294 BEAST_EXPECT(val_7 == "value 7");
1295 }
1296
1297 {
1298 int val_1 = 1;
1299 BEAST_EXPECT(set(val_1, "positive_int", s));
1300 BEAST_EXPECT(val_1 == 2);
1301
1302 int val_2 = 2;
1303 BEAST_EXPECT(set(val_2, "negative_int", s));
1304 BEAST_EXPECT(val_2 == -3);
1305
1306 int val_3 = 3;
1307 BEAST_EXPECT(!set(val_3, "a_string", s));
1308 BEAST_EXPECT(val_3 == 3);
1309
1310 auto val_4 = get<int>(s, "positive_int");
1311 BEAST_EXPECT(val_4 == 2);
1312 auto val_5 = get<int>(s, "not_a_key");
1313 BEAST_EXPECT(val_5 == 0);
1314 auto val_6 = get<int>(s, "not_a_key", 5);
1315 BEAST_EXPECT(val_6 == 5);
1316 auto val_7 = get<int>(s, "a_string", 6);
1317 BEAST_EXPECT(val_7 == 6);
1318
1319 int val_8 = 8;
1320 BEAST_EXPECT(get_if_exists(s, "positive_int", val_8));
1321 BEAST_EXPECT(val_8 == 2);
1322
1323 auto val_9 = 9;
1324 BEAST_EXPECT(!get_if_exists(s, "not_a_key", val_9));
1325 BEAST_EXPECT(val_9 == 9);
1326
1327 auto val_10 = 10;
1328 BEAST_EXPECT(!get_if_exists(s, "a_string", val_10));
1329 BEAST_EXPECT(val_10 == 10);
1330
1331 BEAST_EXPECT(s.get<int>("not_a_key") == std::nullopt);
1332 try
1333 {
1334 s.get<int>("a_string");
1335 fail();
1336 }
1337 catch (boost::bad_lexical_cast&)
1338 {
1339 pass();
1340 }
1341 }
1342
1343 {
1344 bool flag_1 = false;
1345 BEAST_EXPECT(get_if_exists(s, "bool_ish", flag_1));
1346 BEAST_EXPECT(flag_1 == true);
1347
1348 bool flag_2 = false;
1349 BEAST_EXPECT(!get_if_exists(s, "not_a_key", flag_2));
1350 BEAST_EXPECT(flag_2 == false);
1351 }
1352 }
1353
1354 void
1356 {
1357 testcase("amendment");
1358 struct ConfigUnit
1359 {
1360 std::string unit;
1361 std::uint32_t numSeconds;
1362 std::uint32_t configVal;
1363 bool shouldPass;
1364 };
1365
1366 std::vector<ConfigUnit> units = {
1367 {"seconds", 1, 15 * 60, false},
1368 {"minutes", 60, 14, false},
1369 {"minutes", 60, 15, true},
1370 {"hours", 3600, 10, true},
1371 {"days", 86400, 10, true},
1372 {"weeks", 604800, 2, true},
1373 {"months", 2592000, 1, false},
1374 {"years", 31536000, 1, false}};
1375
1376 std::string space = "";
1377 for (auto& [unit, sec, val, shouldPass] : units)
1378 {
1379 Config c;
1380 std::string toLoad(R"rippleConfig(
1381[amendment_majority_time]
1382)rippleConfig");
1383 toLoad += std::to_string(val) + space + unit;
1384 space = space == "" ? " " : "";
1385
1386 try
1387 {
1388 c.loadFromString(toLoad);
1389 if (shouldPass)
1390 BEAST_EXPECT(
1391 c.AMENDMENT_MAJORITY_TIME.count() == val * sec);
1392 else
1393 fail();
1394 }
1395 catch (std::runtime_error&)
1396 {
1397 if (!shouldPass)
1398 pass();
1399 else
1400 fail();
1401 }
1402 }
1403 }
1404
1405 void
1406 testOverlay()
1407 {
1408 testcase("overlay: unknown time");
1409
1410 auto testUnknown =
1412 try
1413 {
1414 Config c;
1415 c.loadFromString("[overlay]\nmax_unknown_time=" + value);
1416 return c.MAX_UNKNOWN_TIME;
1417 }
1418 catch (std::runtime_error&)
1419 {
1420 return {};
1421 }
1422 };
1423
1424 // Failures
1425 BEAST_EXPECT(!testUnknown("none"));
1426 BEAST_EXPECT(!testUnknown("0.5"));
1427 BEAST_EXPECT(!testUnknown("180 seconds"));
1428 BEAST_EXPECT(!testUnknown("9 minutes"));
1429
1430 // Below lower bound
1431 BEAST_EXPECT(!testUnknown("299"));
1432
1433 // In bounds
1434 BEAST_EXPECT(testUnknown("300") == std::chrono::seconds{300});
1435 BEAST_EXPECT(testUnknown("301") == std::chrono::seconds{301});
1436 BEAST_EXPECT(testUnknown("1799") == std::chrono::seconds{1799});
1437 BEAST_EXPECT(testUnknown("1800") == std::chrono::seconds{1800});
1438
1439 // Above upper bound
1440 BEAST_EXPECT(!testUnknown("1801"));
1441
1442 testcase("overlay: diverged time");
1443
1444 // In bounds:
1445 auto testDiverged =
1447 try
1448 {
1449 Config c;
1450 c.loadFromString("[overlay]\nmax_diverged_time=" + value);
1451 return c.MAX_DIVERGED_TIME;
1452 }
1453 catch (std::runtime_error&)
1454 {
1455 return {};
1456 }
1457 };
1458
1459 // Failures
1460 BEAST_EXPECT(!testDiverged("none"));
1461 BEAST_EXPECT(!testDiverged("0.5"));
1462 BEAST_EXPECT(!testDiverged("180 seconds"));
1463 BEAST_EXPECT(!testDiverged("9 minutes"));
1464
1465 // Below lower bound
1466 BEAST_EXPECT(!testDiverged("0"));
1467 BEAST_EXPECT(!testDiverged("59"));
1468
1469 // In bounds
1470 BEAST_EXPECT(testDiverged("60") == std::chrono::seconds{60});
1471 BEAST_EXPECT(testDiverged("61") == std::chrono::seconds{61});
1472 BEAST_EXPECT(testDiverged("899") == std::chrono::seconds{899});
1473 BEAST_EXPECT(testDiverged("900") == std::chrono::seconds{900});
1474
1475 // Above upper bound
1476 BEAST_EXPECT(!testDiverged("901"));
1477 }
1478
1479 void
1480 run() override
1481 {
1482 testLegacy();
1483 testDbPath();
1486 testSetup(false);
1487 testSetup(true);
1488 testPort();
1489 testZeroPort();
1491 testColons();
1492 testComments();
1493 testGetters();
1494 testAmendment();
1495 testOverlay();
1497 }
1498};
1499
1500BEAST_DEFINE_TESTSUITE(Config, core, ripple);
1501
1502} // namespace ripple
A testsuite class.
Definition suite.h:52
log_os< char > log
Logging output stream.
Definition suite.h:149
void pass()
Record a successful test condition.
Definition suite.h:508
testcase_t testcase
Memberspace for declaring test cases.
Definition suite.h:152
bool unexcept(F &&f, String const &reason)
Definition suite.h:479
void fail(String const &reason, char const *file, int line)
Record a failure.
Definition suite.h:530
bool exists(std::string const &name) const
Returns true if a section with the given name exists.
Section & section(std::string const &name)
Returns the section with the given name.
void legacy(std::string const &section, std::string value)
Set a value that is not a key/value pair.
void testSetup(bool explicitPath)
void run() override
Runs the suite.
boost::filesystem::path path
bool silent() const
Definition Config.h:312
uint32_t NETWORK_ID
Definition Config.h:137
static char const *const databaseDirName
Definition Config.h:71
std::uint32_t LEDGER_HISTORY
Definition Config.h:188
std::vector< std::string > IPS_FIXED
Definition Config.h:125
void setup(std::string const &strConf, bool bQuiet, bool bSilent, bool bStandalone)
Definition Config.cpp:292
std::vector< std::string > IPS
Definition Config.h:122
bool standalone() const
Definition Config.h:317
std::optional< std::size_t > VALIDATOR_LIST_THRESHOLD
Definition Config.h:281
bool quiet() const
Definition Config.h:307
std::chrono::seconds MAX_DIVERGED_TIME
Definition Config.h:265
void loadFromString(std::string const &fileContents)
Load the config from the contents of the string.
Definition Config.cpp:460
std::vector< std::string > const & lines() const
Returns all the lines in the section.
Definition BasicConfig.h:51
std::vector< std::string > const & values() const
Returns all the values in the section.
Definition BasicConfig.h:60
bool expectException(Functor f, std::string const &message="")
Definition TestSuite.h:81
Create a directory and remove it when it's done.
auto rmDir(path const &toRm)
boost::filesystem::path path
path const & subdir() const
beast::unit_test::suite & test_
Write a file in a directory and remove when done.
path const & file() const
Write a rippled config file and remove when done.
RippledCfgGuard(beast::unit_test::suite &test, path subDir, path const &dbPath, path const &validatorsFile, bool useCounter=true, std::string confContents="")
Config const & config() const
Write a validators.txt file and remove when done.
ValidatorsTxtGuard(beast::unit_test::suite &test, path subDir, path const &validatorsFileName, bool useCounter=true)
T empty(T... args)
T endl(T... args)
T is_same_v
field_t< CharT, Traits, Allocator > field(std::basic_string< CharT, Traits, Allocator > const &text, int width=8, int pad=0, bool right=false)
Definition iosformat.h:143
std::string configContents(std::string const &dbPath, std::string const &validatorsFile)
std::string valFileContents()
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:6
static std::optional< Seed > validationSeed(Json::Value const &params)
bool set(T &target, std::string const &name, Section const &section)
Set a value from a configuration Section If the named value is not found or doesn't parse as a T,...
bool get_if_exists(Section const &section, std::string const &name, T &v)
void parse_Port(ParsedPort &port, Section const &section, std::ostream &log)
Definition Port.cpp:195
STL namespace.
T regex_replace(T... args)
T size(T... args)
T starts_with(T... args)
std::vector< boost::asio::ip::network_v4 > admin_nets_v4
Definition Port.h:98
std::vector< boost::asio::ip::network_v6 > admin_nets_v6
Definition Port.h:99
T to_string(T... args)
T what(T... args)