rippled
LedgerLoad_test.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2012-2017 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/beast/unit_test.h>
21 #include <ripple/beast/utility/temp_dir.h>
22 #include <ripple/protocol/SField.h>
23 #include <ripple/protocol/jss.h>
24 #include <test/jtx.h>
25 #include <test/jtx/Env.h>
26 
27 #include <boost/algorithm/string.hpp>
28 #include <boost/filesystem.hpp>
29 #include <fstream>
30 
31 namespace ripple {
32 
33 class LedgerLoad_test : public beast::unit_test::suite
34 {
35  auto static ledgerConfig(
37  std::string const& dbPath,
38  std::string const& ledger,
40  {
41  cfg->START_LEDGER = ledger;
42  cfg->START_UP = type;
43  assert(!dbPath.empty());
44  cfg->legacy("database_path", dbPath);
45  return cfg;
46  }
47 
48  // setup for test cases
49  struct SetupData
50  {
55  };
56 
57  SetupData
59  {
60  using namespace test::jtx;
61  SetupData retval = {td.path()};
62 
63  retval.ledgerFile = td.file("ledgerdata.json");
64 
65  Env env{*this};
66  Account prev;
67 
68  for (auto i = 0; i < 20; ++i)
69  {
70  Account acct{"A" + std::to_string(i)};
71  env.fund(XRP(10000), acct);
72  env.close();
73  if (i > 0)
74  {
75  env.trust(acct["USD"](1000), prev);
76  env(pay(acct, prev, acct["USD"](5)));
77  }
78  env(offer(acct, XRP(100), acct["USD"](1)));
79  env.close();
80  prev = std::move(acct);
81  }
82 
83  retval.ledger = env.rpc("ledger", "current", "full")[jss::result];
84  BEAST_EXPECT(
85  retval.ledger[jss::ledger][jss::accountState].size() == 102);
86 
87  retval.hashes = [&] {
88  for (auto const& it : retval.ledger[jss::ledger][jss::accountState])
89  {
90  if (it[sfLedgerEntryType.fieldName] == jss::LedgerHashes)
91  return it[sfHashes.fieldName];
92  }
93  return Json::Value{};
94  }();
95 
96  BEAST_EXPECT(retval.hashes.size() == 41);
97 
98  // write this ledger data to a file.
99  std::ofstream o(retval.ledgerFile, std::ios::out | std::ios::trunc);
100  o << to_string(retval.ledger);
101  o.close();
102  return retval;
103  }
104 
105  void
106  testLoad(SetupData const& sd)
107  {
108  testcase("Load a saved ledger");
109  using namespace test::jtx;
110 
111  // create a new env with the ledger file specified for startup
112  Env env(
113  *this,
114  envconfig(
116  nullptr,
118  auto jrb = env.rpc("ledger", "current", "full")[jss::result];
119  BEAST_EXPECT(
120  sd.ledger[jss::ledger][jss::accountState].size() ==
121  jrb[jss::ledger][jss::accountState].size());
122  }
123 
124  void
126  {
127  testcase("Load ledger: Bad Files");
128  using namespace test::jtx;
129  using namespace boost::filesystem;
130 
131  // empty path
132  except([&] {
133  Env env(
134  *this,
135  envconfig(ledgerConfig, sd.dbPath, "", Config::LOAD_FILE),
136  nullptr,
138  });
139 
140  // file does not exist
141  except([&] {
142  Env env(
143  *this,
144  envconfig(
145  ledgerConfig, sd.dbPath, "badfile.json", Config::LOAD_FILE),
146  nullptr,
148  });
149 
150  // make a corrupted version of the ledger file (last 10 bytes removed).
151  boost::system::error_code ec;
152  auto ledgerFileCorrupt =
153  boost::filesystem::path{sd.dbPath} / "ledgerdata_bad.json";
154  copy_file(
155  sd.ledgerFile,
156  ledgerFileCorrupt,
157  copy_option::overwrite_if_exists,
158  ec);
159  if (!BEAST_EXPECTS(!ec, ec.message()))
160  return;
161  auto filesize = file_size(ledgerFileCorrupt, ec);
162  if (!BEAST_EXPECTS(!ec, ec.message()))
163  return;
164  resize_file(ledgerFileCorrupt, filesize - 10, ec);
165  if (!BEAST_EXPECTS(!ec, ec.message()))
166  return;
167 
168  except([&] {
169  Env env(
170  *this,
171  envconfig(
172  ledgerConfig,
173  sd.dbPath,
174  ledgerFileCorrupt.string(),
176  nullptr,
178  });
179  }
180 
181  void
183  {
184  testcase("Load by hash");
185  using namespace test::jtx;
186 
187  // create a new env with the ledger hash specified for startup
188  auto ledgerHash = to_string(sd.hashes[sd.hashes.size() - 1]);
189  boost::erase_all(ledgerHash, "\"");
190  Env env(
191  *this,
192  envconfig(ledgerConfig, sd.dbPath, ledgerHash, Config::LOAD),
193  nullptr,
195  auto jrb = env.rpc("ledger", "current", "full")[jss::result];
196  BEAST_EXPECT(jrb[jss::ledger][jss::accountState].size() == 98);
197  BEAST_EXPECT(
198  jrb[jss::ledger][jss::accountState].size() <=
199  sd.ledger[jss::ledger][jss::accountState].size());
200  }
201 
202  void
204  {
205  testcase("Load by keyword");
206  using namespace test::jtx;
207 
208  // create a new env with the ledger "latest" specified for startup
209  Env env(
210  *this,
211  envconfig(ledgerConfig, sd.dbPath, "latest", Config::LOAD),
212  nullptr,
214  auto jrb = env.rpc("ledger", "current", "full")[jss::result];
215  BEAST_EXPECT(
216  sd.ledger[jss::ledger][jss::accountState].size() ==
217  jrb[jss::ledger][jss::accountState].size());
218  }
219 
220  void
222  {
223  testcase("Load by index");
224  using namespace test::jtx;
225 
226  // create a new env with specific ledger index at startup
227  Env env(
228  *this,
229  envconfig(ledgerConfig, sd.dbPath, "43", Config::LOAD),
230  nullptr,
232  auto jrb = env.rpc("ledger", "current", "full")[jss::result];
233  BEAST_EXPECT(
234  sd.ledger[jss::ledger][jss::accountState].size() ==
235  jrb[jss::ledger][jss::accountState].size());
236  }
237 
238 public:
239  void
240  run() override
241  {
242  beast::temp_dir td;
243  auto sd = setupLedger(td);
244 
245  // test cases
246  testLoad(sd);
247  testBadFiles(sd);
248  testLoadByHash(sd);
249  testLoadLatest(sd);
250  testLoadIndex(sd);
251  }
252 };
253 
254 BEAST_DEFINE_TESTSUITE(LedgerLoad, app, ripple);
255 
256 } // namespace ripple
fstream
std::string
STL class.
ripple::BEAST_DEFINE_TESTSUITE
BEAST_DEFINE_TESTSUITE(AccountTxPaging, app, ripple)
beast::severities::kDisabled
@ kDisabled
Definition: Journal.h:41
ripple::LedgerLoad_test::SetupData::hashes
Json::Value hashes
Definition: LedgerLoad_test.cpp:54
ripple::SField::fieldName
const std::string fieldName
Definition: SField.h:132
ripple::Config::LOAD
@ LOAD
Definition: Config.h:153
ripple::Config::StartUpType
StartUpType
Definition: Config.h:153
ripple::LedgerLoad_test::run
void run() override
Definition: LedgerLoad_test.cpp:240
ripple::LedgerLoad_test::SetupData::ledger
Json::Value ledger
Definition: LedgerLoad_test.cpp:53
ripple::LedgerLoad_test::testLoadLatest
void testLoadLatest(SetupData const &sd)
Definition: LedgerLoad_test.cpp:203
ripple::LedgerLoad_test::SetupData
Definition: LedgerLoad_test.cpp:49
std::ofstream
STL class.
std::to_string
T to_string(T... args)
ripple::LedgerLoad_test::setupLedger
SetupData setupLedger(beast::temp_dir const &td)
Definition: LedgerLoad_test.cpp:58
std::ofstream::close
T close(T... args)
Json::Value::size
UInt size() const
Number of values in array or object.
Definition: json_value.cpp:706
ripple::LedgerLoad_test::testLoadByHash
void testLoadByHash(SetupData const &sd)
Definition: LedgerLoad_test.cpp:182
ripple::LedgerLoad_test::ledgerConfig
static auto ledgerConfig(std::unique_ptr< Config > cfg, std::string const &dbPath, std::string const &ledger, Config::StartUpType type)
Definition: LedgerLoad_test.cpp:35
beast::temp_dir::path
std::string path() const
Get the native path for the temporary directory.
Definition: temp_dir.h:66
ripple::LedgerLoad_test::testBadFiles
void testBadFiles(SetupData const &sd)
Definition: LedgerLoad_test.cpp:125
ripple::sfHashes
const SF_VECTOR256 sfHashes
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::LedgerLoad_test::SetupData::dbPath
const std::string dbPath
Definition: LedgerLoad_test.cpp:51
ripple::sfLedgerEntryType
const SF_UINT16 sfLedgerEntryType
ripple::LedgerLoad_test::SetupData::ledgerFile
std::string ledgerFile
Definition: LedgerLoad_test.cpp:52
std::string::empty
T empty(T... args)
ripple::LedgerLoad_test::testLoad
void testLoad(SetupData const &sd)
Definition: LedgerLoad_test.cpp:106
ripple::to_string
std::string to_string(Manifest const &m)
Format the specified manifest to a string for debugging purposes.
Definition: app/misc/impl/Manifest.cpp:41
std::unique_ptr
STL class.
ripple::LedgerLoad_test::testLoadIndex
void testLoadIndex(SetupData const &sd)
Definition: LedgerLoad_test.cpp:221
beast::temp_dir::file
std::string file(std::string const &name) const
Get the native path for the a file.
Definition: temp_dir.h:76
ripple::Config::LOAD_FILE
@ LOAD_FILE
Definition: Config.h:153
beast::temp_dir
RAII temporary directory.
Definition: temp_dir.h:33
ripple::LedgerLoad_test
Definition: LedgerLoad_test.cpp:33
Json::Value
Represents a JSON value.
Definition: json_value.h:145