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