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