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