rippled
DatabaseDownloader_test.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright 2019 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/net/DatabaseDownloader.h>
21 #include <boost/filesystem/operations.hpp>
22 #include <boost/predef.h>
23 #include <condition_variable>
24 #include <mutex>
25 #include <test/jtx.h>
26 #include <test/jtx/TrustedPublisherServer.h>
27 #include <test/unit_test/FileDirGuard.h>
28 
29 namespace ripple {
30 namespace test {
31 
32 class DatabaseDownloader_test : public beast::unit_test::suite
33 {
35  createServer(jtx::Env& env, bool ssl = true)
36  {
40  env.app().getIOService(),
41  list,
42  env.timeKeeper().now() + std::chrono::seconds{3600},
43  // No future VLs
44  {},
45  ssl);
46  }
47 
49  {
52  bool called = false;
53  boost::filesystem::path dest;
54 
55  void
56  operator()(boost::filesystem::path dst)
57  {
59  called = true;
60  dest = std::move(dst);
61  cv.notify_one();
62  };
63 
64  bool
66  {
68  using namespace std::chrono_literals;
69 #if BOOST_OS_WINDOWS
70  auto constexpr timeout = 4s;
71 #else
72  auto constexpr timeout = 2s;
73 #endif
74  auto stat = cv.wait_for(lk, timeout, [this] { return called; });
75  called = false;
76  return stat;
77  };
78  };
80 
81  struct Downloader
82  {
86 
88  : journal_{sink_}
90  env.app().getIOService(),
91  env.app().config(),
92  journal_)}
93  {
94  }
95 
97  {
98  ptr_->onStop();
99  }
100 
103  {
104  return ptr_.get();
105  }
106  };
107 
108  void
110  {
111  testcase << std::string("Basic download - SSL ") +
112  (verify ? "Verify" : "No Verify");
113 
114  using namespace jtx;
115 
117  *this, "_cert", "ca.pem", TrustedPublisherServer::ca_cert()};
118 
119  Env env{*this, envconfig([&cert, &verify](std::unique_ptr<Config> cfg) {
120  if ((cfg->SSL_VERIFY = verify)) // yes, this is assignment
121  cfg->SSL_VERIFY_FILE = cert.file().string();
122  return cfg;
123  })};
124 
125  Downloader downloader{env};
126 
127  // create a TrustedPublisherServer as a simple HTTP
128  // server to request from. Use the /textfile endpoint
129  // to get a simple text file sent as response.
130  auto server = createServer(env);
131 
133  *this, "downloads", "data", "", false, false};
134  // initiate the download and wait for the callback
135  // to be invoked
136  auto stat = downloader->download(
137  server->local_endpoint().address().to_string(),
138  std::to_string(server->local_endpoint().port()),
139  "/textfile",
140  11,
141  data.file(),
142  std::function<void(boost::filesystem::path)>{std::ref(cb)});
143  if (!BEAST_EXPECT(stat))
144  {
145  log << "Failed. LOGS:\n" + downloader.sink_.messages().str();
146  return;
147  }
148  if (!BEAST_EXPECT(cb.waitComplete()))
149  {
150  log << "Failed. LOGS:\n" + downloader.sink_.messages().str();
151  return;
152  }
153  BEAST_EXPECT(cb.dest == data.file());
154  if (!BEAST_EXPECT(boost::filesystem::exists(data.file())))
155  return;
156  BEAST_EXPECT(boost::filesystem::file_size(data.file()) > 0);
157  }
158 
159  void
161  {
162  testcase("Error conditions");
163 
164  using namespace jtx;
165 
166  Env env{*this};
167 
168  {
169  // bad hostname
170  boost::system::error_code ec;
171  boost::asio::ip::tcp::resolver resolver{env.app().getIOService()};
172  auto const results = resolver.resolve("badhostname", "443", ec);
173  // we require an error in resolving this name in order
174  // for this test to pass. Some networks might have DNS hijacking
175  // that prevent NXDOMAIN, in which case the failure is not
176  // possible, so we skip the test.
177  if (ec)
178  {
179  Downloader dl{env};
180  ripple::test::detail::FileDirGuard const datafile{
181  *this, "downloads", "data", "", false, false};
182  BEAST_EXPECT(dl->download(
183  "badhostname",
184  "443",
185  "",
186  11,
187  datafile.file(),
188  std::function<void(boost::filesystem::path)>{
189  std::ref(cb)}));
190  BEAST_EXPECT(cb.waitComplete());
191  BEAST_EXPECT(!boost::filesystem::exists(datafile.file()));
192  BEAST_EXPECTS(
193  dl.sink_.messages().str().find("async_resolve") !=
194  std::string::npos,
195  dl.sink_.messages().str());
196  }
197  }
198  {
199  // can't connect
200  Downloader dl{env};
201  ripple::test::detail::FileDirGuard const datafile{
202  *this, "downloads", "data", "", false, false};
203  auto server = createServer(env);
204  auto host = server->local_endpoint().address().to_string();
205  auto port = std::to_string(server->local_endpoint().port());
206  server->stop();
207  BEAST_EXPECT(dl->download(
208  host,
209  port,
210  "",
211  11,
212  datafile.file(),
213  std::function<void(boost::filesystem::path)>{std::ref(cb)}));
214  BEAST_EXPECT(cb.waitComplete());
215  BEAST_EXPECT(!boost::filesystem::exists(datafile.file()));
216  BEAST_EXPECTS(
217  dl.sink_.messages().str().find("async_connect") !=
218  std::string::npos,
219  dl.sink_.messages().str());
220  }
221  {
222  // not ssl (failed handlshake)
223  Downloader dl{env};
224  ripple::test::detail::FileDirGuard const datafile{
225  *this, "downloads", "data", "", false, false};
226  auto server = createServer(env, false);
227  BEAST_EXPECT(dl->download(
228  server->local_endpoint().address().to_string(),
229  std::to_string(server->local_endpoint().port()),
230  "",
231  11,
232  datafile.file(),
233  std::function<void(boost::filesystem::path)>{std::ref(cb)}));
234  BEAST_EXPECT(cb.waitComplete());
235  BEAST_EXPECT(!boost::filesystem::exists(datafile.file()));
236  BEAST_EXPECTS(
237  dl.sink_.messages().str().find("async_handshake") !=
238  std::string::npos,
239  dl.sink_.messages().str());
240  }
241  {
242  // huge file (content length)
243  Downloader dl{env};
244  ripple::test::detail::FileDirGuard const datafile{
245  *this, "downloads", "data", "", false, false};
246  auto server = createServer(env);
247  BEAST_EXPECT(dl->download(
248  server->local_endpoint().address().to_string(),
249  std::to_string(server->local_endpoint().port()),
250  "/textfile/huge",
251  11,
252  datafile.file(),
253  std::function<void(boost::filesystem::path)>{std::ref(cb)}));
254  BEAST_EXPECT(cb.waitComplete());
255  BEAST_EXPECT(!boost::filesystem::exists(datafile.file()));
256  BEAST_EXPECTS(
257  dl.sink_.messages().str().find("Insufficient disk space") !=
258  std::string::npos,
259  dl.sink_.messages().str());
260  }
261  }
262 
263 public:
264  void
265  run() override
266  {
267  testDownload(true);
268  testDownload(false);
269  testFailures();
270  }
271 };
272 
274 } // namespace test
275 } // namespace ripple
ripple::test::DatabaseDownloader_test::testDownload
void testDownload(bool verify)
Definition: DatabaseDownloader_test.cpp:109
ripple::test::BEAST_DEFINE_TESTSUITE
BEAST_DEFINE_TESTSUITE(AccountDelete, app, ripple)
std::string
STL class.
std::shared_ptr
STL class.
ripple::test::DatabaseDownloader_test::Downloader::Downloader
Downloader(jtx::Env &env)
Definition: DatabaseDownloader_test.cpp:87
ripple::test::DatabaseDownloader_test::Downloader::~Downloader
~Downloader()
Definition: DatabaseDownloader_test.cpp:96
std::vector
STL class.
std::chrono::seconds
std::shared_ptr::get
T get(T... args)
ripple::test::jtx::Env::timeKeeper
ManualTimeKeeper & timeKeeper()
Definition: Env.h:252
ripple::test::jtx::Env::app
Application & app()
Definition: Env.h:240
std::function
ripple::test::DatabaseDownloader_test::DownloadCompleter::cv
std::condition_variable cv
Definition: DatabaseDownloader_test.cpp:51
ripple::test::jtx::envconfig
std::unique_ptr< Config > envconfig()
creates and initializes a default configuration for jtx::Env
Definition: envconfig.h:49
ripple::test::TrustedPublisherServer::ca_cert
static std::string const & ca_cert()
Definition: TrustedPublisherServer.h:400
ripple::test::DatabaseDownloader_test::cb
DownloadCompleter cb
Definition: DatabaseDownloader_test.cpp:79
std::vector::push_back
T push_back(T... args)
ripple::test::DatabaseDownloader_test::Downloader::ptr_
std::shared_ptr< DatabaseDownloader > ptr_
Definition: DatabaseDownloader_test.cpp:85
ripple::verify
bool verify(PublicKey const &publicKey, Slice const &m, Slice const &sig, bool mustBeFullyCanonical)
Verify a signature on a message.
Definition: PublicKey.cpp:268
ripple::test::DatabaseDownloader_test::Downloader::sink_
test::StreamSink sink_
Definition: DatabaseDownloader_test.cpp:83
ripple::test::DatabaseDownloader_test::DownloadCompleter::operator()
void operator()(boost::filesystem::path dst)
Definition: DatabaseDownloader_test.cpp:56
ripple::test::DatabaseDownloader_test::DownloadCompleter::waitComplete
bool waitComplete()
Definition: DatabaseDownloader_test.cpp:65
std::unique_lock
STL class.
std::to_string
T to_string(T... args)
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:58
ripple::test::DatabaseDownloader_test::run
void run() override
Definition: DatabaseDownloader_test.cpp:265
ripple::test::TrustedPublisherServer::randomValidator
static Validator randomValidator()
Definition: TrustedPublisherServer.h:148
ripple::test::DatabaseDownloader_test::Downloader::journal_
beast::Journal journal_
Definition: DatabaseDownloader_test.cpp:84
std::condition_variable::wait_for
T wait_for(T... args)
ripple::Application::getIOService
virtual boost::asio::io_service & getIOService()=0
ripple::test::StreamSink
Definition: SuiteJournal.h:114
std::condition_variable::notify_one
T notify_one(T... args)
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::test::DatabaseDownloader_test::Downloader::operator->
DatabaseDownloader * operator->()
Definition: DatabaseDownloader_test.cpp:102
ripple::test::DatabaseDownloader_test::DownloadCompleter::m
std::mutex m
Definition: DatabaseDownloader_test.cpp:50
ripple::test::DatabaseDownloader_test::DownloadCompleter
Definition: DatabaseDownloader_test.cpp:48
ripple::test::DatabaseDownloader_test::Downloader
Definition: DatabaseDownloader_test.cpp:81
condition_variable
ripple::test::make_TrustedPublisherServer
std::shared_ptr< TrustedPublisherServer > make_TrustedPublisherServer(boost::asio::io_context &ioc, std::vector< TrustedPublisherServer::Validator > const &validators, NetClock::time_point validUntil, std::vector< std::pair< NetClock::time_point, NetClock::time_point >> const &futures, bool useSSL=false, int version=1, bool immediateStart=true, int sequence=1)
Definition: TrustedPublisherServer.h:712
ripple::test::DatabaseDownloader_test::testFailures
void testFailures()
Definition: DatabaseDownloader_test.cpp:160
mutex
ripple::test::DatabaseDownloader_test::DownloadCompleter::dest
boost::filesystem::path dest
Definition: DatabaseDownloader_test.cpp:53
ripple::test::DatabaseDownloader_test::createServer
std::shared_ptr< TrustedPublisherServer > createServer(jtx::Env &env, bool ssl=true)
Definition: DatabaseDownloader_test.cpp:35
ripple::test::detail::FileDirGuard
Write a file in a directory and remove when done.
Definition: FileDirGuard.h:110
ripple::DatabaseDownloader
Definition: DatabaseDownloader.h:28
ripple::test::ManualTimeKeeper::now
time_point now() const override
Returns the estimate of wall time, in network time.
Definition: ManualTimeKeeper.cpp:37
std::unique_ptr
STL class.
ripple::make_DatabaseDownloader
std::shared_ptr< DatabaseDownloader > make_DatabaseDownloader(boost::asio::io_service &io_service, Config const &config, beast::Journal j)
Definition: DatabaseDownloader.cpp:25
ripple::test::jtx::Env
A transaction testing environment.
Definition: Env.h:115
ripple::test::DatabaseDownloader_test
Definition: DatabaseDownloader_test.cpp:32
ripple::test::DatabaseDownloader_test::DownloadCompleter::called
bool called
Definition: DatabaseDownloader_test.cpp:52