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  ssl};
44  }
45 
47  {
50  bool called = false;
51  boost::filesystem::path dest;
52 
53  void
54  operator()(boost::filesystem::path dst)
55  {
57  called = true;
58  dest = std::move(dst);
59  cv.notify_one();
60  };
61 
62  bool
64  {
66  using namespace std::chrono_literals;
67 #if BOOST_OS_WINDOWS
68  auto constexpr timeout = 4s;
69 #else
70  auto constexpr timeout = 2s;
71 #endif
72  auto stat = cv.wait_for(lk, timeout, [this] { return called; });
73  called = false;
74  return stat;
75  };
76  };
78 
79  struct Downloader
80  {
83  // The DatabaseDownloader must be created as shared_ptr
84  // because it uses shared_from_this
86 
88  : journal_{sink_}
89  , ptr_{std::make_shared<DatabaseDownloader>(
90  env.app().getIOService(),
91  journal_,
92  env.app().config())}
93  {
94  }
95 
98  {
99  return ptr_.get();
100  }
101  };
102 
103  void
105  {
106  testcase << std::string("Basic download - SSL ") +
107  (verify ? "Verify" : "No Verify");
108 
109  using namespace jtx;
110 
112  *this, "_cert", "ca.pem", TrustedPublisherServer::ca_cert()};
113 
114  Env env{*this, envconfig([&cert, &verify](std::unique_ptr<Config> cfg) {
115  if ((cfg->SSL_VERIFY = verify)) // yes, this is assignment
116  cfg->SSL_VERIFY_FILE = cert.file().string();
117  return cfg;
118  })};
119 
120  Downloader downloader{env};
121 
122  // create a TrustedPublisherServer as a simple HTTP
123  // server to request from. Use the /textfile endpoint
124  // to get a simple text file sent as response.
125  auto server = createServer(env);
126 
128  *this, "downloads", "data", "", false, false};
129  // initiate the download and wait for the callback
130  // to be invoked
131  auto stat = downloader->download(
132  server.local_endpoint().address().to_string(),
133  std::to_string(server.local_endpoint().port()),
134  "/textfile",
135  11,
136  data.file(),
137  std::function<void(boost::filesystem::path)>{std::ref(cb)});
138  if (!BEAST_EXPECT(stat))
139  {
140  log << "Failed. LOGS:\n" + downloader.sink_.messages().str();
141  return;
142  }
143  if (!BEAST_EXPECT(cb.waitComplete()))
144  {
145  log << "Failed. LOGS:\n" + downloader.sink_.messages().str();
146  return;
147  }
148  BEAST_EXPECT(cb.dest == data.file());
149  if (!BEAST_EXPECT(boost::filesystem::exists(data.file())))
150  return;
151  BEAST_EXPECT(boost::filesystem::file_size(data.file()) > 0);
152  }
153 
154  void
156  {
157  testcase("Error conditions");
158 
159  using namespace jtx;
160 
161  Env env{*this};
162 
163  {
164  // bad hostname
165  boost::system::error_code ec;
166  boost::asio::ip::tcp::resolver resolver{env.app().getIOService()};
167  auto const results = resolver.resolve("badhostname", "443", ec);
168  // we require an error in resolving this name in order
169  // for this test to pass. Some networks might have DNS hijacking
170  // that prevent NXDOMAIN, in which case the failure is not
171  // possible, so we skip the test.
172  if (ec)
173  {
174  Downloader dl{env};
175  ripple::test::detail::FileDirGuard const datafile{
176  *this, "downloads", "data", "", false, false};
177  BEAST_EXPECT(dl->download(
178  "badhostname",
179  "443",
180  "",
181  11,
182  datafile.file(),
183  std::function<void(boost::filesystem::path)>{
184  std::ref(cb)}));
185  BEAST_EXPECT(cb.waitComplete());
186  BEAST_EXPECT(!boost::filesystem::exists(datafile.file()));
187  BEAST_EXPECTS(
188  dl.sink_.messages().str().find("async_resolve") !=
189  std::string::npos,
190  dl.sink_.messages().str());
191  }
192  }
193  {
194  // can't connect
195  Downloader dl{env};
196  ripple::test::detail::FileDirGuard const datafile{
197  *this, "downloads", "data", "", false, false};
198  auto server = createServer(env);
199  auto host = server.local_endpoint().address().to_string();
200  auto port = std::to_string(server.local_endpoint().port());
201  server.stop();
202  BEAST_EXPECT(dl->download(
203  host,
204  port,
205  "",
206  11,
207  datafile.file(),
208  std::function<void(boost::filesystem::path)>{std::ref(cb)}));
209  BEAST_EXPECT(cb.waitComplete());
210  BEAST_EXPECT(!boost::filesystem::exists(datafile.file()));
211  BEAST_EXPECTS(
212  dl.sink_.messages().str().find("async_connect") !=
213  std::string::npos,
214  dl.sink_.messages().str());
215  }
216  {
217  // not ssl (failed handlshake)
218  Downloader dl{env};
219  ripple::test::detail::FileDirGuard const datafile{
220  *this, "downloads", "data", "", false, false};
221  auto server = createServer(env, false);
222  BEAST_EXPECT(dl->download(
223  server.local_endpoint().address().to_string(),
224  std::to_string(server.local_endpoint().port()),
225  "",
226  11,
227  datafile.file(),
228  std::function<void(boost::filesystem::path)>{std::ref(cb)}));
229  BEAST_EXPECT(cb.waitComplete());
230  BEAST_EXPECT(!boost::filesystem::exists(datafile.file()));
231  BEAST_EXPECTS(
232  dl.sink_.messages().str().find("async_handshake") !=
233  std::string::npos,
234  dl.sink_.messages().str());
235  }
236  {
237  // huge file (content length)
238  Downloader dl{env};
239  ripple::test::detail::FileDirGuard const datafile{
240  *this, "downloads", "data", "", false, false};
241  auto server = createServer(env);
242  BEAST_EXPECT(dl->download(
243  server.local_endpoint().address().to_string(),
244  std::to_string(server.local_endpoint().port()),
245  "/textfile/huge",
246  11,
247  datafile.file(),
248  std::function<void(boost::filesystem::path)>{std::ref(cb)}));
249  BEAST_EXPECT(cb.waitComplete());
250  BEAST_EXPECT(!boost::filesystem::exists(datafile.file()));
251  BEAST_EXPECTS(
252  dl.sink_.messages().str().find("Insufficient disk space") !=
253  std::string::npos,
254  dl.sink_.messages().str());
255  }
256  }
257 
258 public:
259  void
260  run() override
261  {
262  testDownload(true);
263  testDownload(false);
264  testFailures();
265  }
266 };
267 
269 } // namespace test
270 } // namespace ripple
ripple::test::DatabaseDownloader_test::testDownload
void testDownload(bool verify)
Definition: DatabaseDownloader_test.cpp:104
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
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:49
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:320
ripple::test::DatabaseDownloader_test::cb
DownloadCompleter cb
Definition: DatabaseDownloader_test.cpp:77
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:81
ripple::test::DatabaseDownloader_test::DownloadCompleter::operator()
void operator()(boost::filesystem::path dst)
Definition: DatabaseDownloader_test.cpp:54
ripple::test::DatabaseDownloader_test::DownloadCompleter::waitComplete
bool waitComplete()
Definition: DatabaseDownloader_test.cpp:63
std::unique_lock
STL class.
std::to_string
T to_string(T... args)
ripple::test::TrustedPublisherServer
Definition: TrustedPublisherServer.h:42
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:58
ripple::test::DatabaseDownloader_test::run
void run() override
Definition: DatabaseDownloader_test.cpp:260
ripple::test::TrustedPublisherServer::randomValidator
static Validator randomValidator()
Definition: TrustedPublisherServer.h:128
ripple::test::DatabaseDownloader_test::Downloader::journal_
beast::Journal journal_
Definition: DatabaseDownloader_test.cpp:82
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:97
ripple::test::DatabaseDownloader_test::DownloadCompleter::m
std::mutex m
Definition: DatabaseDownloader_test.cpp:48
ripple::test::DatabaseDownloader_test::DownloadCompleter
Definition: DatabaseDownloader_test.cpp:46
ripple::test::DatabaseDownloader_test::Downloader
Definition: DatabaseDownloader_test.cpp:79
condition_variable
ripple::test::DatabaseDownloader_test::testFailures
void testFailures()
Definition: DatabaseDownloader_test.cpp:155
mutex
ripple::test::DatabaseDownloader_test::DownloadCompleter::dest
boost::filesystem::path dest
Definition: DatabaseDownloader_test.cpp:51
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::test::DatabaseDownloader_test::createServer
TrustedPublisherServer createServer(jtx::Env &env, bool ssl=true)
Definition: DatabaseDownloader_test.cpp:35
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:50