rippled
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 <ripple/basics/contract.h>
21 #include <ripple/core/Config.h>
22 #include <ripple/core/ConfigSections.h>
23 #include <ripple/server/Port.h>
24 #include <test/jtx/TestSuite.h>
25 #include <test/unit_test/FileDirGuard.h>
26 #include <boost/filesystem.hpp>
27 #include <boost/format.hpp>
28 #include <fstream>
29 #include <iostream>
30 
31 namespace ripple {
32 namespace detail {
34  std::string const& validatorsFile)
35 {
36  static boost::format configContentsTemplate (R"rippleConfig(
37 [server]
38 port_rpc
39 port_peer
40 port_wss_admin
41 
42 [port_rpc]
43 port = 5005
44 ip = 127.0.0.1
45 admin = 127.0.0.1, ::1
46 protocol = https
47 
48 [port_peer]
49 port = 51235
50 ip = 0.0.0.0
51 protocol = peer
52 
53 [port_wss_admin]
54 port = 6006
55 ip = 127.0.0.1
56 admin = 127.0.0.1
57 protocol = wss
58 
59 #[port_ws_public]
60 #port = 5005
61 #ip = 127.0.0.1
62 #protocol = wss
63 
64 #-------------------------------------------------------------------------------
65 
66 [node_size]
67 medium
68 
69 # This is primary persistent datastore for rippled. This includes transaction
70 # metadata, account states, and ledger headers. Helpful information can be
71 # found here: https://ripple.com/wiki/NodeBackEnd
72 # delete old ledgers while maintaining at least 2000. Do not require an
73 # external administrative command to initiate deletion.
74 [node_db]
75 type=memory
76 path=/Users/dummy/ripple/config/db/rocksdb
77 open_files=2000
78 filter_bits=12
79 cache_mb=256
80 file_size_mb=8
81 file_size_mult=2
82 
83 %1%
84 
85 %2%
86 
87 # This needs to be an absolute directory reference, not a relative one.
88 # Modify this value as required.
89 [debug_logfile]
90 /Users/dummy/ripple/config/log/debug.log
91 
92 [sntp_servers]
93 time.windows.com
94 time.apple.com
95 time.nist.gov
96 pool.ntp.org
97 
98 # Where to find some other servers speaking the Ripple protocol.
99 #
100 [ips]
101 r.ripple.com 51235
102 
103 # Turn down default logging to save disk space in the long run.
104 # Valid values here are trace, debug, info, warning, error, and fatal
105 [rpc_startup]
106 { "command": "log_level", "severity": "warning" }
107 
108 # Defaults to 1 ("yes") so that certificates will be validated. To allow the use
109 # of self-signed certificates for development or internal use, set to 0 ("no").
110 [ssl_verify]
111 0
112 
113 [sqdb]
114 backend=sqlite
115 )rippleConfig");
116 
117  std::string dbPathSection =
118  dbPath.empty () ? "" : "[database_path]\n" + dbPath;
119  std::string valFileSection =
120  validatorsFile.empty () ? "" : "[validators_file]\n" + validatorsFile;
121  return boost::str (
122  configContentsTemplate % dbPathSection % valFileSection);
123 }
124 
129 {
130 private:
132 
133  bool rmDataDir_{false};
134 
136 
137 public:
138  RippledCfgGuard (beast::unit_test::suite& test,
139  path subDir, path const& dbPath,
140  path const& validatorsFile,
141  bool useCounter = true)
142  : FileDirGuard(test, std::move (subDir),
143  path (Config::configFileName),
144  configContents (dbPath.string (), validatorsFile.string ()),
145  useCounter)
146  , dataDir_ (dbPath)
147  {
148  if (dbPath.empty ())
150 
151  rmDataDir_ = !exists (dataDir_);
152  config_.setup (file_.string (), /*bQuiet*/ true,
153  /* bSilent */ false, /* bStandalone */ false);
154  }
155 
156  Config const& config () const
157  {
158  return config_;
159  }
160 
162  {
163  return file().string();
164  }
165 
166  bool dataDirExists () const
167  {
168  return boost::filesystem::is_directory (dataDir_);
169  }
170 
171  bool configFileExists () const
172  {
173  return fileExists();
174  }
175 
177  {
178  try
179  {
180  using namespace boost::filesystem;
181  if (rmDataDir_)
182  rmDir (dataDir_);
183  else
184  test_.log << "Skipping rm dir: "
185  << dataDir_.string () << std::endl;
186  }
187  catch (std::exception& e)
188  {
189  // if we throw here, just let it die.
190  test_.log << "Error in ~RippledCfgGuard: "
191  << e.what () << std::endl;
192  };
193  }
194 };
195 
197 {
198  std::string configContents (R"rippleConfig(
199 [validators]
200 n949f75evCHwgyP4fPVgaHqNHxUVN15PsJEZ3B3HnXPcPjcZAoy7
201 n9MD5h24qrQqiyBC8aeqqCWvpiBiYQ3jxSr91uiDvmrkyHRdYLUj
202 n9L81uNCaPgtUJfaHh89gmdvXKAmSt5Gdsw2g1iPWaPkAHW5Nm4C
203 n9KiYM9CgngLvtRCQHZwgC2gjpdaZcCcbt3VboxiNFcKuwFVujzS
204 n9LdgEtkmGB9E2h3K4Vp7iGUaKuq23Zr32ehxiU8FWY7xoxbWTSA
205 
206 [validator_keys]
207 nHUhG1PgAG8H8myUENypM35JgfqXAKNQvRVVAFDRzJrny5eZN8d5
208 nHBu9PTL9dn2GuZtdW4U2WzBwffyX9qsQCd9CNU4Z5YG3PQfViM8
209 nHUPDdcdb2Y5DZAJne4c2iabFuAP3F34xZUgYQT2NH7qfkdapgnz
210 
211 [validator_list_sites]
212 recommendedripplevalidators.com
213 moreripplevalidators.net
214 
215 [validator_list_keys]
216 03E74EE14CB525AFBB9F1B7D86CD58ECC4B91452294B42AB4E78F260BD905C091D
217 030775A669685BD6ABCEBD80385921C7851783D991A8055FD21D2F3966C96F1B56
218 )rippleConfig");
219  return configContents;
220 }
221 
226 {
227 public:
228  ValidatorsTxtGuard (beast::unit_test::suite& test,
229  path subDir, path const& validatorsFileName,
230  bool useCounter = true)
231  : FileDirGuard (test, std::move (subDir),
232  path (
233  validatorsFileName.empty () ? Config::validatorsFileName :
234  validatorsFileName),
235  valFileContents (),
236  useCounter)
237  {
238  }
239 
240  bool validatorsFileExists () const
241  {
242  return fileExists();
243  }
244 
246  {
247  return absolute(file()).string();
248  }
249 
251  {
252  }
253 };
254 } // detail
255 
256 class Config_test final : public TestSuite
257 {
258 private:
259  using path = boost::filesystem::path;
260 
261 public:
262  void testLegacy ()
263  {
264  testcase ("legacy");
265 
266  Config c;
267 
268  std::string toLoad(R"rippleConfig(
269 [server]
270 port_rpc
271 port_peer
272 port_wss_admin
273 
274 [ssl_verify]
275 0
276 )rippleConfig");
277 
278  c.loadFromString (toLoad);
279 
280  BEAST_EXPECT(c.legacy ("ssl_verify") == "0");
281  expectException ([&c] {c.legacy ("server");}); // not a single line
282 
283  // set a legacy value
284  BEAST_EXPECT(c.legacy ("not_in_file") == "");
285  c.legacy ("not_in_file", "new_value");
286  BEAST_EXPECT(c.legacy ("not_in_file") == "new_value");
287  }
288  void testDbPath ()
289  {
290  testcase ("database_path");
291 
292  using namespace boost::filesystem;
293  {
294  boost::format cc ("[database_path]\n%1%\n");
295 
296  auto const cwd = current_path ();
297  path const dataDirRel ("test_data_dir");
298  path const dataDirAbs (cwd / dataDirRel);
299  {
300  // Dummy test - do we get back what we put in
301  Config c;
302  c.loadFromString (boost::str (cc % dataDirAbs.string ()));
303  BEAST_EXPECT(c.legacy ("database_path") == dataDirAbs.string ());
304  }
305  {
306  // Rel paths should convert to abs paths
307  Config c;
308  c.loadFromString (boost::str (cc % dataDirRel.string ()));
309  BEAST_EXPECT(c.legacy ("database_path") == dataDirAbs.string ());
310  }
311  {
312  // No db section.
313  // N.B. Config::setup will give database_path a default,
314  // load will not.
315  Config c;
316  c.loadFromString ("");
317  BEAST_EXPECT(c.legacy ("database_path") == "");
318  }
319  }
320  {
321  // read from file absolute path
322  auto const cwd = current_path ();
323  ripple::test::detail::DirGuard const g0(*this, "test_db");
324  path const dataDirRel ("test_data_dir");
325  path const dataDirAbs(cwd / g0.subdir () / dataDirRel);
326  detail::RippledCfgGuard const g (*this, g0.subdir(),
327  dataDirAbs, "", false);
328  auto const& c (g.config ());
329  BEAST_EXPECT(g.dataDirExists ());
330  BEAST_EXPECT(g.configFileExists ());
331  BEAST_EXPECT(c.legacy ("database_path") == dataDirAbs.string ());
332  }
333  {
334  // read from file relative path
335  std::string const dbPath ("my_db");
336  detail::RippledCfgGuard const g (*this, "test_db", dbPath, "");
337  auto const& c (g.config ());
338  std::string const nativeDbPath = absolute (path (dbPath)).string ();
339  BEAST_EXPECT(g.dataDirExists ());
340  BEAST_EXPECT(g.configFileExists ());
341  BEAST_EXPECT(c.legacy ("database_path") == nativeDbPath);
342  }
343  {
344  // read from file no path
345  detail::RippledCfgGuard const g (*this, "test_db", "", "");
346  auto const& c (g.config ());
347  std::string const nativeDbPath =
348  absolute (g.subdir () /
350  .string ();
351  BEAST_EXPECT(g.dataDirExists ());
352  BEAST_EXPECT(g.configFileExists ());
353  BEAST_EXPECT(c.legacy ("database_path") == nativeDbPath);
354  }
355  }
356 
358  {
359  testcase ("validator keys");
360 
361  std::string const validationSeed = "spA4sh1qTvwq92X715tYyGQKmAKfa";
362 
363  auto const token =
364  "eyJ2YWxpZGF0aW9uX3ByaXZhdGVfa2V5IjoiOWVkNDVmODY2MjQxY2MxOGEyNzQ3Yj"
365  "U0Mzg3YzA2MjU5MDc5NzJmNGU3MTkwMjMxZmFhOTM3NDU3ZmE5ZGFmNiIsIm1hbmlm"
366  "ZXN0IjoiSkFBQUFBRnhJZTFGdHdtaW12R3RIMmlDY01KcUM5Z1ZGS2lsR2Z3MS92Q3"
367  "hIWFhMcGxjMkduTWhBa0UxYWdxWHhCd0R3RGJJRDZPTVNZdU0wRkRBbHBBZ05rOFNL"
368  "Rm43TU8yZmRrY3dSUUloQU9uZ3U5c0FLcVhZb3VKK2wyVjBXK3NBT2tWQitaUlM2UF"
369  "NobEpBZlVzWGZBaUJzVkpHZXNhYWRPSmMvYUFab2tTMXZ5bUdtVnJsSFBLV1gzWXl3"
370  "dTZpbjhIQVNRS1B1Z0JENjdrTWFSRkd2bXBBVEhsR0tKZHZERmxXUFl5NUFxRGVkRn"
371  "Y1VEphMncwaTIxZXEzTVl5d0xWSlpuRk9yN0Mwa3cyQWlUelNDakl6ZGl0UTg9In0=";
372 
373  {
374  Config c;
375  static boost::format configTemplate (R"rippleConfig(
376 [validation_seed]
377 %1%
378 
379 [validator_token]
380 %2%
381 )rippleConfig");
382  std::string error;
383  auto const expectedError =
384  "Cannot have both [validation_seed] "
385  "and [validator_token] config sections";
386  try {
387  c.loadFromString (boost::str (
388  configTemplate % validationSeed % token));
389  } catch (std::runtime_error& e) {
390  error = e.what();
391  }
392  BEAST_EXPECT(error == expectedError);
393  }
394  }
395 
397  {
398  testcase ("validators_file");
399 
400  using namespace boost::filesystem;
401  {
402  // load should throw for missing specified validators file
403  boost::format cc ("[validators_file]\n%1%\n");
404  std::string error;
405  std::string const missingPath = "/no/way/this/path/exists";
406  auto const expectedError =
407  "The file specified in [validators_file] does not exist: " +
408  missingPath;
409  try {
410  Config c;
411  c.loadFromString (boost::str (cc % missingPath));
412  } catch (std::runtime_error& e) {
413  error = e.what();
414  }
415  BEAST_EXPECT(error == expectedError);
416  }
417  {
418  // load should throw for invalid [validators_file]
419  detail::ValidatorsTxtGuard const vtg (
420  *this, "test_cfg", "validators.cfg");
421  path const invalidFile = current_path () / vtg.subdir ();
422  boost::format cc ("[validators_file]\n%1%\n");
423  std::string error;
424  auto const expectedError =
425  "Invalid file specified in [validators_file]: " +
426  invalidFile.string ();
427  try {
428  Config c;
429  c.loadFromString (boost::str (cc % invalidFile.string ()));
430  } catch (std::runtime_error& e) {
431  error = e.what();
432  }
433  BEAST_EXPECT(error == expectedError);
434  }
435  {
436  // load validators from config into single section
437  Config c;
438  std::string toLoad(R"rippleConfig(
439 [validators]
440 n949f75evCHwgyP4fPVgaHqNHxUVN15PsJEZ3B3HnXPcPjcZAoy7
441 n9MD5h24qrQqiyBC8aeqqCWvpiBiYQ3jxSr91uiDvmrkyHRdYLUj
442 n9L81uNCaPgtUJfaHh89gmdvXKAmSt5Gdsw2g1iPWaPkAHW5Nm4C
443 
444 [validator_keys]
445 nHUhG1PgAG8H8myUENypM35JgfqXAKNQvRVVAFDRzJrny5eZN8d5
446 nHBu9PTL9dn2GuZtdW4U2WzBwffyX9qsQCd9CNU4Z5YG3PQfViM8
447 )rippleConfig");
448  c.loadFromString (toLoad);
449  BEAST_EXPECT(c.legacy ("validators_file").empty ());
450  BEAST_EXPECT(c.section (SECTION_VALIDATORS).values ().size () == 5);
451  }
452  {
453  // load validator list sites and keys from config
454  Config c;
455  std::string toLoad(R"rippleConfig(
456 [validator_list_sites]
457 ripplevalidators.com
458 trustthesevalidators.gov
459 
460 [validator_list_keys]
461 021A99A537FDEBC34E4FCA03B39BEADD04299BB19E85097EC92B15A3518801E566
462 )rippleConfig");
463  c.loadFromString (toLoad);
464  BEAST_EXPECT(
465  c.section (SECTION_VALIDATOR_LIST_SITES).values ().size () == 2);
466  BEAST_EXPECT(
467  c.section (SECTION_VALIDATOR_LIST_SITES).values ()[0] ==
468  "ripplevalidators.com");
469  BEAST_EXPECT(
470  c.section (SECTION_VALIDATOR_LIST_SITES).values ()[1] ==
471  "trustthesevalidators.gov");
472  BEAST_EXPECT(
473  c.section (SECTION_VALIDATOR_LIST_KEYS).values ().size () == 1);
474  BEAST_EXPECT(
475  c.section (SECTION_VALIDATOR_LIST_KEYS).values ()[0] ==
476  "021A99A537FDEBC34E4FCA03B39BEADD04299BB19E85097EC92B15A3518801E566");
477  }
478  {
479  // load should throw if [validator_list_sites] is configured but
480  // [validator_list_keys] is not
481  Config c;
482  std::string toLoad(R"rippleConfig(
483 [validator_list_sites]
484 ripplevalidators.com
485 trustthesevalidators.gov
486 )rippleConfig");
487  std::string error;
488  auto const expectedError =
489  "[validator_list_keys] config section is missing";
490  try {
491  c.loadFromString (toLoad);
492  } catch (std::runtime_error& e) {
493  error = e.what();
494  }
495  BEAST_EXPECT(error == expectedError);
496  }
497  {
498  // load from specified [validators_file] absolute path
499  detail::ValidatorsTxtGuard const vtg (
500  *this, "test_cfg", "validators.cfg");
501  BEAST_EXPECT(vtg.validatorsFileExists ());
502  Config c;
503  boost::format cc ("[validators_file]\n%1%\n");
504  c.loadFromString (boost::str (cc % vtg.validatorsFile ()));
505  BEAST_EXPECT(c.legacy ("validators_file") == vtg.validatorsFile ());
506  BEAST_EXPECT(c.section (SECTION_VALIDATORS).values ().size () == 8);
507  BEAST_EXPECT(
508  c.section (SECTION_VALIDATOR_LIST_SITES).values ().size () == 2);
509  BEAST_EXPECT(
510  c.section (SECTION_VALIDATOR_LIST_KEYS).values ().size () == 2);
511  }
512  {
513  // load from specified [validators_file] file name
514  // in config directory
515  std::string const valFileName = "validators.txt";
516  detail::ValidatorsTxtGuard const vtg (
517  *this, "test_cfg", valFileName);
518  detail::RippledCfgGuard const rcg (
519  *this, vtg.subdir (), "", valFileName, false);
520  BEAST_EXPECT(vtg.validatorsFileExists ());
521  BEAST_EXPECT(rcg.configFileExists ());
522  auto const& c (rcg.config ());
523  BEAST_EXPECT(c.legacy ("validators_file") == valFileName);
524  BEAST_EXPECT(c.section (SECTION_VALIDATORS).values ().size () == 8);
525  BEAST_EXPECT(
526  c.section (SECTION_VALIDATOR_LIST_SITES).values ().size () == 2);
527  BEAST_EXPECT(
528  c.section (SECTION_VALIDATOR_LIST_KEYS).values ().size () == 2);
529  }
530  {
531  // load from specified [validators_file] relative path
532  // to config directory
533  detail::ValidatorsTxtGuard const vtg (
534  *this, "test_cfg", "validators.txt");
535  auto const valFilePath = ".." / vtg.subdir() / "validators.txt";
536  detail::RippledCfgGuard const rcg (
537  *this, vtg.subdir (), "", valFilePath, false);
538  BEAST_EXPECT(vtg.validatorsFileExists ());
539  BEAST_EXPECT(rcg.configFileExists ());
540  auto const& c (rcg.config ());
541  BEAST_EXPECT(c.legacy ("validators_file") == valFilePath);
542  BEAST_EXPECT(c.section (SECTION_VALIDATORS).values ().size () == 8);
543  BEAST_EXPECT(
544  c.section (SECTION_VALIDATOR_LIST_SITES).values ().size () == 2);
545  BEAST_EXPECT(
546  c.section (SECTION_VALIDATOR_LIST_KEYS).values ().size () == 2);
547  }
548  {
549  // load from validators file in default location
550  detail::ValidatorsTxtGuard const vtg (
551  *this, "test_cfg", "validators.txt");
552  detail::RippledCfgGuard const rcg (*this, vtg.subdir (),
553  "", "", false);
554  BEAST_EXPECT(vtg.validatorsFileExists ());
555  BEAST_EXPECT(rcg.configFileExists ());
556  auto const& c (rcg.config ());
557  BEAST_EXPECT(c.legacy ("validators_file").empty ());
558  BEAST_EXPECT(c.section (SECTION_VALIDATORS).values ().size () == 8);
559  BEAST_EXPECT(
560  c.section (SECTION_VALIDATOR_LIST_SITES).values ().size () == 2);
561  BEAST_EXPECT(
562  c.section (SECTION_VALIDATOR_LIST_KEYS).values ().size () == 2);
563  }
564  {
565  // load from specified [validators_file] instead
566  // of default location
567  detail::ValidatorsTxtGuard const vtg (
568  *this, "test_cfg", "validators.cfg");
569  BEAST_EXPECT(vtg.validatorsFileExists ());
570  detail::ValidatorsTxtGuard const vtgDefault (
571  *this, vtg.subdir (), "validators.txt", false);
572  BEAST_EXPECT(vtgDefault.validatorsFileExists ());
573  detail::RippledCfgGuard const rcg (
574  *this, vtg.subdir (), "", vtg.validatorsFile (), false);
575  BEAST_EXPECT(rcg.configFileExists ());
576  auto const& c (rcg.config ());
577  BEAST_EXPECT(c.legacy ("validators_file") == vtg.validatorsFile ());
578  BEAST_EXPECT(c.section (SECTION_VALIDATORS).values ().size () == 8);
579  BEAST_EXPECT(
580  c.section (SECTION_VALIDATOR_LIST_SITES).values ().size () == 2);
581  BEAST_EXPECT(
582  c.section (SECTION_VALIDATOR_LIST_KEYS).values ().size () == 2);
583  }
584 
585  {
586  // load validators from both config and validators file
587  boost::format cc (R"rippleConfig(
588 [validators_file]
589 %1%
590 
591 [validators]
592 n949f75evCHwgyP4fPVgaHqNHxUVN15PsJEZ3B3HnXPcPjcZAoy7
593 n9MD5h24qrQqiyBC8aeqqCWvpiBiYQ3jxSr91uiDvmrkyHRdYLUj
594 n9L81uNCaPgtUJfaHh89gmdvXKAmSt5Gdsw2g1iPWaPkAHW5Nm4C
595 n9KiYM9CgngLvtRCQHZwgC2gjpdaZcCcbt3VboxiNFcKuwFVujzS
596 n9LdgEtkmGB9E2h3K4Vp7iGUaKuq23Zr32ehxiU8FWY7xoxbWTSA
597 
598 [validator_keys]
599 nHB1X37qrniVugfQcuBTAjswphC1drx7QjFFojJPZwKHHnt8kU7v
600 nHUkAWDR4cB8AgPg7VXMX6et8xRTQb2KJfgv1aBEXozwrawRKgMB
601 
602 [validator_list_sites]
603 ripplevalidators.com
604 trustthesevalidators.gov
605 
606 [validator_list_keys]
607 021A99A537FDEBC34E4FCA03B39BEADD04299BB19E85097EC92B15A3518801E566
608 )rippleConfig");
609  detail::ValidatorsTxtGuard const vtg (
610  *this, "test_cfg", "validators.cfg");
611  BEAST_EXPECT(vtg.validatorsFileExists ());
612  Config c;
613  c.loadFromString (boost::str (cc % vtg.validatorsFile ()));
614  BEAST_EXPECT(c.legacy ("validators_file") == vtg.validatorsFile ());
615  BEAST_EXPECT(c.section (SECTION_VALIDATORS).values ().size () == 15);
616  BEAST_EXPECT(
617  c.section (SECTION_VALIDATOR_LIST_SITES).values ().size () == 4);
618  BEAST_EXPECT(
619  c.section (SECTION_VALIDATOR_LIST_KEYS).values ().size () == 3);
620  }
621  {
622  // load should throw if [validators], [validator_keys] and
623  // [validator_list_keys] are missing from rippled cfg and
624  // validators file
625  Config c;
626  boost::format cc ("[validators_file]\n%1%\n");
627  std::string error;
628  detail::ValidatorsTxtGuard const vtg (
629  *this, "test_cfg", "validators.cfg");
630  BEAST_EXPECT(vtg.validatorsFileExists ());
631  auto const expectedError =
632  "The file specified in [validators_file] does not contain a "
633  "[validators], [validator_keys] or [validator_list_keys] section: " +
634  vtg.validatorsFile ();
635  std::ofstream o (vtg.validatorsFile ());
636  try {
637  Config c2;
638  c2.loadFromString (boost::str (cc % vtg.validatorsFile ()));
639  } catch (std::runtime_error& e) {
640  error = e.what();
641  }
642  BEAST_EXPECT(error == expectedError);
643  }
644  }
645 
646  void testSetup(bool explicitPath)
647  {
648  detail::RippledCfgGuard const cfg(*this, "testSetup",
649  explicitPath ? "test_db" : "", "");
650  /* RippledCfgGuard has a Config object that gets loaded on
651  construction, but Config::setup is not reentrant, so we
652  need a fresh config for every test case, so ignore it.
653  */
654  {
655  Config config;
656  config.setup(cfg.configFile(), /*bQuiet*/ false,
657  /* bSilent */ false, /* bStandalone */ false);
658  BEAST_EXPECT(!config.quiet());
659  BEAST_EXPECT(!config.silent());
660  BEAST_EXPECT(!config.standalone());
661  BEAST_EXPECT(config.LEDGER_HISTORY == 256);
662  BEAST_EXPECT(!config.legacy("database_path").empty());
663  }
664  {
665  Config config;
666  config.setup(cfg.configFile(), /*bQuiet*/ true,
667  /* bSilent */ false, /* bStandalone */ false);
668  BEAST_EXPECT(config.quiet());
669  BEAST_EXPECT(!config.silent());
670  BEAST_EXPECT(!config.standalone());
671  BEAST_EXPECT(config.LEDGER_HISTORY == 256);
672  BEAST_EXPECT(!config.legacy("database_path").empty());
673  }
674  {
675  Config config;
676  config.setup(cfg.configFile(), /*bQuiet*/ false,
677  /* bSilent */ true, /* bStandalone */ false);
678  BEAST_EXPECT(config.quiet());
679  BEAST_EXPECT(config.silent());
680  BEAST_EXPECT(!config.standalone());
681  BEAST_EXPECT(config.LEDGER_HISTORY == 256);
682  BEAST_EXPECT(!config.legacy("database_path").empty());
683  }
684  {
685  Config config;
686  config.setup(cfg.configFile(), /*bQuiet*/ true,
687  /* bSilent */ true, /* bStandalone */ false);
688  BEAST_EXPECT(config.quiet());
689  BEAST_EXPECT(config.silent());
690  BEAST_EXPECT(!config.standalone());
691  BEAST_EXPECT(config.LEDGER_HISTORY == 256);
692  BEAST_EXPECT(!config.legacy("database_path").empty());
693  }
694  {
695  Config config;
696  config.setup(cfg.configFile(), /*bQuiet*/ false,
697  /* bSilent */ false, /* bStandalone */ true);
698  BEAST_EXPECT(!config.quiet());
699  BEAST_EXPECT(!config.silent());
700  BEAST_EXPECT(config.standalone());
701  BEAST_EXPECT(config.LEDGER_HISTORY == 0);
702  BEAST_EXPECT(config.legacy("database_path").empty() == !explicitPath);
703  }
704  {
705  Config config;
706  config.setup(cfg.configFile(), /*bQuiet*/ true,
707  /* bSilent */ false, /* bStandalone */ true);
708  BEAST_EXPECT(config.quiet());
709  BEAST_EXPECT(!config.silent());
710  BEAST_EXPECT(config.standalone());
711  BEAST_EXPECT(config.LEDGER_HISTORY == 0);
712  BEAST_EXPECT(config.legacy("database_path").empty() == !explicitPath);
713  }
714  {
715  Config config;
716  config.setup(cfg.configFile(), /*bQuiet*/ false,
717  /* bSilent */ true, /* bStandalone */ true);
718  BEAST_EXPECT(config.quiet());
719  BEAST_EXPECT(config.silent());
720  BEAST_EXPECT(config.standalone());
721  BEAST_EXPECT(config.LEDGER_HISTORY == 0);
722  BEAST_EXPECT(config.legacy("database_path").empty() == !explicitPath);
723  }
724  {
725  Config config;
726  config.setup(cfg.configFile(), /*bQuiet*/ true,
727  /* bSilent */ true, /* bStandalone */ true);
728  BEAST_EXPECT(config.quiet());
729  BEAST_EXPECT(config.silent());
730  BEAST_EXPECT(config.standalone());
731  BEAST_EXPECT(config.LEDGER_HISTORY == 0);
732  BEAST_EXPECT(config.legacy("database_path").empty() == !explicitPath);
733  }
734  }
735 
736  void testPort ()
737  {
738  detail::RippledCfgGuard const cfg(*this, "testPort", "", "");
739  auto const& conf = cfg.config();
740  if (!BEAST_EXPECT(conf.exists("port_rpc")))
741  return;
742  if (!BEAST_EXPECT(conf.exists("port_wss_admin")))
743  return;
744  ParsedPort rpc;
745  if (!unexcept([&]() { parse_Port (rpc, conf["port_rpc"], log); }))
746  return;
747  BEAST_EXPECT(rpc.admin_ip && (rpc.admin_ip .get().size() == 2));
748  ParsedPort wss;
749  if (!unexcept([&]() { parse_Port (wss, conf["port_wss_admin"], log); }))
750  return;
751  BEAST_EXPECT(wss.admin_ip && (wss.admin_ip .get().size() == 1));
752  }
753 
755  {
756  Config cfg;
757  /* NOTE: this string includes some explicit
758  * space chars in order to verify proper trimming */
759  std::string toLoad(R"(
760 [port_rpc])" "\x20" R"(
761 # comment
762  # indented comment
763 )" "\x20\x20" R"(
764 [ips])" "\x20" R"(
765 r.ripple.com 51235
766 
767  [ips_fixed])" "\x20\x20" R"(
768  # COMMENT
769  s1.ripple.com 51235
770  s2.ripple.com 51235
771 
772 )");
773  cfg.loadFromString (toLoad);
774  BEAST_EXPECT (
775  cfg.exists ("port_rpc") &&
776  cfg.section ("port_rpc").lines ().empty () &&
777  cfg.section ("port_rpc").values ().empty ());
778  BEAST_EXPECT (
779  cfg.exists (SECTION_IPS) &&
780  cfg.section (SECTION_IPS).lines ().size () == 1 &&
781  cfg.section (SECTION_IPS).values ().size () == 1);
782  BEAST_EXPECT (
783  cfg.exists (SECTION_IPS_FIXED) &&
784  cfg.section (SECTION_IPS_FIXED).lines ().size () == 2 &&
785  cfg.section (SECTION_IPS_FIXED).values ().size () == 2);
786 
787  }
788 
789  void testComments()
790  {
791  struct TestCommentData
792  {
793  std::string_view line;
794  std::string_view field;
795  std::string_view expect;
796  bool had_comment;
797  };
798 
800  { "password = aaaa\\#bbbb", "password", "aaaa#bbbb", false},
801  { "password = aaaa#bbbb", "password", "aaaa", true},
802  { "password = aaaa #bbbb", "password", "aaaa", true},
803  // since the value is all comment, this doesn't parse as k=v :
804  { "password = #aaaa #bbbb", "", "password =", true},
805  { "password = aaaa\\# #bbbb", "password", "aaaa#", true},
806  { "password = aaaa\\##bbbb", "password", "aaaa#", true},
807  { "aaaa#bbbb", "", "aaaa", true},
808  { "aaaa\\#bbbb", "", "aaaa#bbbb", false},
809  { "aaaa\\##bbbb", "", "aaaa#", true},
810  { "aaaa #bbbb", "", "aaaa", true},
811  { "1 #comment", "", "1", true},
812  { "#whole thing is comment", "", "", false},
813  { " #whole comment with space", "", "", false}
814  }};
815 
816  for (auto const& t : tests)
817  {
818  Section s;
819  s.append(t.line.data());
820  BEAST_EXPECT(s.had_trailing_comments() == t.had_comment);
821  if (t.field.empty())
822  {
823  BEAST_EXPECTS(s.legacy() == t.expect, s.legacy());
824  }
825  else
826  {
828  BEAST_EXPECTS(set(field, t.field.data(), s), t.line);
829  BEAST_EXPECTS(field == t.expect, t.line);
830  }
831  }
832 
833  {
834  Section s;
835  s.append("online_delete = 3000");
836  std::uint32_t od = 0;
837  BEAST_EXPECT(set(od, "online_delete", s));
838  BEAST_EXPECTS(od == 3000, *(s.get<std::string>("online_delete")));
839  }
840 
841  {
842  Section s;
843  s.append("online_delete = 2000 #my comment on this");
844  std::uint32_t od = 0;
845  BEAST_EXPECT(set(od, "online_delete", s));
846  BEAST_EXPECTS(od == 2000, *(s.get<std::string>("online_delete")));
847  }
848  }
849 
850  void testGetters()
851  {
852  using namespace std::string_literals;
853  Section s {"MySection"};
854  s.append("a_string = mystring");
855  s.append("positive_int = 2");
856  s.append("negative_int = -3");
857  s.append("bool_ish = 1");
858 
859  {
860  auto val_1 = "value 1"s;
861  BEAST_EXPECT(set(val_1, "a_string", s));
862  BEAST_EXPECT(val_1 == "mystring");
863 
864  auto val_2 = "value 2"s;
865  BEAST_EXPECT(!set(val_2, "not_a_key", s));
866  BEAST_EXPECT(val_2 == "value 2");
867  BEAST_EXPECT(!set(val_2, "default"s, "not_a_key", s));
868  BEAST_EXPECT(val_2 == "default");
869 
870  auto val_3 = get<std::string>(s, "a_string");
871  BEAST_EXPECT(val_3 == "mystring");
872  auto val_4 = get<std::string>(s, "not_a_key");
873  BEAST_EXPECT(val_4 == "");
874  auto val_5 = get<std::string>(s, "not_a_key", "default");
875  BEAST_EXPECT(val_5 == "default");
876 
877  auto val_6 = "value 6"s;
878  BEAST_EXPECT(get_if_exists(s, "a_string", val_6));
879  BEAST_EXPECT(val_6 == "mystring");
880 
881  auto val_7 = "value 7"s;
882  BEAST_EXPECT(!get_if_exists(s, "not_a_key", val_7));
883  BEAST_EXPECT(val_7 == "value 7");
884  }
885 
886  {
887  int val_1 = 1;
888  BEAST_EXPECT(set(val_1, "positive_int", s));
889  BEAST_EXPECT(val_1 == 2);
890 
891  int val_2 = 2;
892  BEAST_EXPECT(set(val_2, "negative_int", s));
893  BEAST_EXPECT(val_2 == -3);
894 
895  int val_3 = 3;
896  BEAST_EXPECT(!set(val_3, "a_string", s));
897  BEAST_EXPECT(val_3 == 3);
898 
899  auto val_4 = get<int>(s, "positive_int");
900  BEAST_EXPECT(val_4 == 2);
901  auto val_5 = get<int>(s, "not_a_key");
902  BEAST_EXPECT(val_5 == 0);
903  auto val_6 = get<int>(s, "not_a_key", 5);
904  BEAST_EXPECT(val_6 == 5);
905  auto val_7 = get<int>(s, "a_string", 6);
906  BEAST_EXPECT(val_7 == 6);
907 
908  int val_8 = 8;
909  BEAST_EXPECT(get_if_exists(s, "positive_int", val_8));
910  BEAST_EXPECT(val_8 == 2);
911 
912  auto val_9 = 9;
913  BEAST_EXPECT(!get_if_exists(s, "not_a_key", val_9));
914  BEAST_EXPECT(val_9 == 9);
915 
916  auto val_10 = 10;
917  BEAST_EXPECT(!get_if_exists(s, "a_string", val_10));
918  BEAST_EXPECT(val_10 == 10);
919 
920  BEAST_EXPECT(s.get<int>("not_a_key") == boost::none);
921  try
922  {
923  s.get<int>("a_string");
924  fail();
925  }
926  catch(boost::bad_lexical_cast&)
927  {
928  pass();
929  }
930  }
931 
932  {
933  bool flag_1 = false;
934  BEAST_EXPECT(get_if_exists(s, "bool_ish", flag_1));
935  BEAST_EXPECT(flag_1 == true);
936 
937  bool flag_2 = false;
938  BEAST_EXPECT(!get_if_exists(s, "not_a_key", flag_2));
939  BEAST_EXPECT(flag_2 == false);
940  }
941  }
942 
943  void run () override
944  {
945  testLegacy ();
946  testDbPath ();
947  testValidatorKeys ();
948  testValidatorsFile ();
949  testSetup (false);
950  testSetup (true);
951  testPort ();
952  testWhitespace ();
953  testComments ();
954  testGetters ();
955  }
956 };
957 
958 BEAST_DEFINE_TESTSUITE (Config, core, ripple);
959 
960 } // ripple
ripple::Config_test::testWhitespace
void testWhitespace()
Definition: Config_test.cpp:754
ripple::Section
Holds a collection of configuration values.
Definition: BasicConfig.h:43
ripple::Config_test
Definition: Config_test.cpp:256
ripple::detail::RippledCfgGuard::RippledCfgGuard
RippledCfgGuard(beast::unit_test::suite &test, path subDir, path const &dbPath, path const &validatorsFile, bool useCounter=true)
Definition: Config_test.cpp:138
fstream
std::string
STL class.
ripple::BEAST_DEFINE_TESTSUITE
BEAST_DEFINE_TESTSUITE(AccountTxPaging, app, ripple)
ripple::detail::ValidatorsTxtGuard::ValidatorsTxtGuard
ValidatorsTxtGuard(beast::unit_test::suite &test, path subDir, path const &validatorsFileName, bool useCounter=true)
Definition: Config_test.cpp:228
std::exception
STL class.
std::string_view
STL class.
ripple::test::detail::DirGuard
Create a directory and remove it when it's done.
Definition: FileDirGuard.h:34
ripple::Config_test::testSetup
void testSetup(bool explicitPath)
Definition: Config_test.cpp:646
std::vector::size
T size(T... args)
ripple::detail::RippledCfgGuard::config_
Config config_
Definition: Config_test.cpp:135
ripple::Config::silent
bool silent() const
Definition: Config.h:203
ripple::detail::ValidatorsTxtGuard::validatorsFile
std::string validatorsFile() const
Definition: Config_test.cpp:245
ripple::Config_test::testDbPath
void testDbPath()
Definition: Config_test.cpp:288
ripple::parse_Port
void parse_Port(ParsedPort &port, Section const &section, std::ostream &log)
Definition: Port.cpp:139
ripple::Config_test::path
boost::filesystem::path path
Definition: Config_test.cpp:259
ripple::ParsedPort
Definition: Port.h:81
iostream
ripple::Config::quiet
bool quiet() const
Definition: Config.h:202
ripple::test::detail::DirGuard::subdir
path const & subdir() const
Definition: FileDirGuard.h:101
ripple::Section::values
std::vector< std::string > const & values() const
Returns all the values in the section.
Definition: BasicConfig.h:78
ripple::validationSeed
static boost::optional< Seed > validationSeed(Json::Value const &params)
Definition: ValidationCreate.cpp:31
ripple::detail::RippledCfgGuard::~RippledCfgGuard
~RippledCfgGuard()
Definition: Config_test.cpp:176
ripple::get_if_exists
bool get_if_exists(Section const &section, std::string const &name, T &v)
Definition: BasicConfig.h:342
ripple::Section::append
void append(std::vector< std::string > const &lines)
Append a set of lines to this section.
Definition: BasicConfig.cpp:41
ripple::Config_test::testLegacy
void testLegacy()
Definition: Config_test.cpp:262
ripple::test::detail::FileDirGuard::file
path const & file() const
Definition: FileDirGuard.h:164
ripple::detail::ValidatorsTxtGuard::validatorsFileExists
bool validatorsFileExists() const
Definition: Config_test.cpp:240
ripple::Config::loadFromString
void loadFromString(std::string const &fileContents)
Load the config from the contents of the string.
Definition: Config.cpp:337
ripple::detail::RippledCfgGuard::configFile
std::string configFile() const
Definition: Config_test.cpp:161
ripple::Config
Definition: Config.h:67
std::ofstream
STL class.
ripple::Config_test::testPort
void testPort()
Definition: Config_test.cpp:736
ripple::Config::standalone
bool standalone() const
Definition: Config.h:204
ripple::set
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:271
std::array
STL class.
ripple::BasicConfig::legacy
void legacy(std::string const &section, std::string value)
Set a value that is not a key/value pair.
Definition: BasicConfig.cpp:173
ripple::Section::lines
std::vector< std::string > const & lines() const
Returns all the lines in the section.
Definition: BasicConfig.h:69
ripple::detail::valFileContents
std::string valFileContents()
Definition: Config_test.cpp:196
std::runtime_error
STL class.
ripple::test::detail::DirGuard::test_
beast::unit_test::suite & test_
Definition: FileDirGuard.h:44
std::uint32_t
ripple::Config::databaseDirName
static char const *const databaseDirName
Definition: Config.h:72
ripple::detail::RippledCfgGuard::configFileExists
bool configFileExists() const
Definition: Config_test.cpp:171
ripple::detail::RippledCfgGuard
Write a rippled config file and remove when done.
Definition: Config_test.cpp:128
ripple::Config::LEDGER_HISTORY
std::uint32_t LEDGER_HISTORY
Definition: Config.h:165
ripple::TestSuite
Definition: TestSuite.h:28
beast::field
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:158
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::Section::get
boost::optional< T > get(std::string const &name) const
Definition: BasicConfig.h:145
ripple::test::detail::FileDirGuard::FileDirGuard
FileDirGuard(beast::unit_test::suite &test, path subDir, path file, std::string const &contents, bool useCounter=true, bool create=true)
Definition: FileDirGuard.h:117
ripple::detail::RippledCfgGuard::rmDataDir_
bool rmDataDir_
Definition: Config_test.cpp:133
ripple::Config::setup
void setup(std::string const &strConf, bool bQuiet, bool bSilent, bool bStandalone)
Definition: Config.cpp:213
std::endl
T endl(T... args)
ripple::Config_test::testValidatorsFile
void testValidatorsFile()
Definition: Config_test.cpp:396
std
STL namespace.
std::string::empty
T empty(T... args)
ripple::test::detail::FileDirGuard::fileExists
bool fileExists() const
Definition: FileDirGuard.h:169
ripple::test::detail::FileDirGuard
Write a file in a directory and remove when done.
Definition: FileDirGuard.h:110
ripple::ParsedPort::admin_ip
boost::optional< std::vector< beast::IP::Address > > admin_ip
Definition: Port.h:101
ripple::test::detail::DirGuard::rmDir
auto rmDir(path const &toRm)
Definition: FileDirGuard.h:46
ripple::Config_test::testValidatorKeys
void testValidatorKeys()
Definition: Config_test.cpp:357
ripple::test::detail::FileDirGuard::file_
const path file_
Definition: FileDirGuard.h:113
ripple::detail::RippledCfgGuard::dataDirExists
bool dataDirExists() const
Definition: Config_test.cpp:166
ripple::detail::ValidatorsTxtGuard
Write a validators.txt file and remove when done.
Definition: Config_test.cpp:225
ripple::detail::configContents
std::string configContents(std::string const &dbPath, std::string const &validatorsFile)
Definition: Config_test.cpp:33
ripple::detail::RippledCfgGuard::dataDir_
path dataDir_
Definition: Config_test.cpp:131
ripple::test::detail::DirGuard::path
boost::filesystem::path path
Definition: FileDirGuard.h:37
ripple::detail::ValidatorsTxtGuard::~ValidatorsTxtGuard
~ValidatorsTxtGuard()
Definition: Config_test.cpp:250
std::exception::what
T what(T... args)
ripple::BasicConfig::exists
bool exists(std::string const &name) const
Returns true if a section with the given name exists.
Definition: BasicConfig.cpp:134
ripple::BasicConfig::section
Section & section(std::string const &name)
Returns the section with the given name.
Definition: BasicConfig.cpp:140
ripple::detail::RippledCfgGuard::config
Config const & config() const
Definition: Config_test.cpp:156