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  {
84 
86  : journal_{sink_}
88  env.app().getIOService(),
89  env.app().config(),
90  journal_)}
91  {
92  }
93 
95  {
96  ptr_->onStop();
97  }
98 
101  {
102  return ptr_.get();
103  }
104  };
105 
106  void
108  {
109  testcase << std::string("Basic download - SSL ") +
110  (verify ? "Verify" : "No Verify");
111 
112  using namespace jtx;
113 
115  *this, "_cert", "ca.pem", TrustedPublisherServer::ca_cert()};
116 
117  Env env{*this, envconfig([&cert, &verify](std::unique_ptr<Config> cfg) {
118  if ((cfg->SSL_VERIFY = verify)) // yes, this is assignment
119  cfg->SSL_VERIFY_FILE = cert.file().string();
120  return cfg;
121  })};
122 
123  Downloader downloader{env};
124 
125  // create a TrustedPublisherServer as a simple HTTP
126  // server to request from. Use the /textfile endpoint
127  // to get a simple text file sent as response.
128  auto server = createServer(env);
129 
131  *this, "downloads", "data", "", false, false};
132  // initiate the download and wait for the callback
133  // to be invoked
134  auto stat = downloader->download(
135  server->local_endpoint().address().to_string(),
136  std::to_string(server->local_endpoint().port()),
137  "/textfile",
138  11,
139  data.file(),
140  std::function<void(boost::filesystem::path)>{std::ref(cb)});
141  if (!BEAST_EXPECT(stat))
142  {
143  log << "Failed. LOGS:\n" + downloader.sink_.messages().str();
144  return;
145  }
146  if (!BEAST_EXPECT(cb.waitComplete()))
147  {
148  log << "Failed. LOGS:\n" + downloader.sink_.messages().str();
149  return;
150  }
151  BEAST_EXPECT(cb.dest == data.file());
152  if (!BEAST_EXPECT(boost::filesystem::exists(data.file())))
153  return;
154  BEAST_EXPECT(boost::filesystem::file_size(data.file()) > 0);
155  }
156 
157  void
159  {
160  testcase("Error conditions");
161 
162  using namespace jtx;
163 
164  Env env{*this};
165 
166  {
167  // bad hostname
168  boost::system::error_code ec;
169  boost::asio::ip::tcp::resolver resolver{env.app().getIOService()};
170  auto const results = resolver.resolve("badhostname", "443", ec);
171  // we require an error in resolving this name in order
172  // for this test to pass. Some networks might have DNS hijacking
173  // that prevent NXDOMAIN, in which case the failure is not
174  // possible, so we skip the test.
175  if (ec)
176  {
177  Downloader dl{env};
178  ripple::test::detail::FileDirGuard const datafile{
179  *this, "downloads", "data", "", false, false};
180  BEAST_EXPECT(dl->download(
181  "badhostname",
182  "443",
183  "",
184  11,
185  datafile.file(),
186  std::function<void(boost::filesystem::path)>{
187  std::ref(cb)}));
188  BEAST_EXPECT(cb.waitComplete());
189  BEAST_EXPECT(!boost::filesystem::exists(datafile.file()));
190  BEAST_EXPECTS(
191  dl.sink_.messages().str().find("async_resolve") !=
192  std::string::npos,
193  dl.sink_.messages().str());
194  }
195  }
196  {
197  // can't connect
198  Downloader dl{env};
199  ripple::test::detail::FileDirGuard const datafile{
200  *this, "downloads", "data", "", false, false};
201  auto server = createServer(env);
202  auto host = server->local_endpoint().address().to_string();
203  auto port = std::to_string(server->local_endpoint().port());
204  server->stop();
205  BEAST_EXPECT(dl->download(
206  host,
207  port,
208  "",
209  11,
210  datafile.file(),
211  std::function<void(boost::filesystem::path)>{std::ref(cb)}));
212  BEAST_EXPECT(cb.waitComplete());
213  BEAST_EXPECT(!boost::filesystem::exists(datafile.file()));
214  BEAST_EXPECTS(
215  dl.sink_.messages().str().find("async_connect") !=
216  std::string::npos,
217  dl.sink_.messages().str());
218  }
219  {
220  // not ssl (failed handlshake)
221  Downloader dl{env};
222  ripple::test::detail::FileDirGuard const datafile{
223  *this, "downloads", "data", "", false, false};
224  auto server = createServer(env, false);
225  BEAST_EXPECT(dl->download(
226  server->local_endpoint().address().to_string(),
227  std::to_string(server->local_endpoint().port()),
228  "",
229  11,
230  datafile.file(),
231  std::function<void(boost::filesystem::path)>{std::ref(cb)}));
232  BEAST_EXPECT(cb.waitComplete());
233  BEAST_EXPECT(!boost::filesystem::exists(datafile.file()));
234  BEAST_EXPECTS(
235  dl.sink_.messages().str().find("async_handshake") !=
236  std::string::npos,
237  dl.sink_.messages().str());
238  }
239  {
240  // huge file (content length)
241  Downloader dl{env};
242  ripple::test::detail::FileDirGuard const datafile{
243  *this, "downloads", "data", "", false, false};
244  auto server = createServer(env);
245  BEAST_EXPECT(dl->download(
246  server->local_endpoint().address().to_string(),
247  std::to_string(server->local_endpoint().port()),
248  "/textfile/huge",
249  11,
250  datafile.file(),
251  std::function<void(boost::filesystem::path)>{std::ref(cb)}));
252  BEAST_EXPECT(cb.waitComplete());
253  BEAST_EXPECT(!boost::filesystem::exists(datafile.file()));
254  BEAST_EXPECTS(
255  dl.sink_.messages().str().find("Insufficient disk space") !=
256  std::string::npos,
257  dl.sink_.messages().str());
258  }
259  }
260 
261 public:
262  void
263  run() override
264  {
265  testDownload(true);
266  testDownload(false);
267  testFailures();
268  }
269 };
270 
272 } // namespace test
273 } // namespace ripple
ripple::test::DatabaseDownloader_test::testDownload
void testDownload(bool verify)
Definition: DatabaseDownloader_test.cpp:107
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:85
ripple::test::DatabaseDownloader_test::Downloader::~Downloader
~Downloader()
Definition: DatabaseDownloader_test.cpp:94
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:327
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:83
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::make_TrustedPublisherServer
std::shared_ptr< TrustedPublisherServer > make_TrustedPublisherServer(boost::asio::io_context &ioc, std::vector< TrustedPublisherServer::Validator > const &validators, NetClock::time_point expiration, bool useSSL=false, int version=1, bool immediateStart=true, int sequence=1)
Definition: TrustedPublisherServer.h:618
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)
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:58
ripple::test::DatabaseDownloader_test::run
void run() override
Definition: DatabaseDownloader_test.cpp:263
ripple::test::TrustedPublisherServer::randomValidator
static Validator randomValidator()
Definition: TrustedPublisherServer.h:131
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:100
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:158
mutex
ripple::test::DatabaseDownloader_test::DownloadCompleter::dest
boost::filesystem::path dest
Definition: DatabaseDownloader_test.cpp:51
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:50