31#include <jau/test/catch2_ext.hpp>
48 const size_t IDX_11kiB = 0;
49 const size_t IDX_65MiB = 1;
50 static std::vector<std::string> fname_payload_lst;
51 static std::vector<std::string> fname_payload_copy_lst;
52 static std::vector<uint64_t> fname_payload_size_lst;
53 const std::string url_input_root =
"http://localhost:8080/";
57 static bool add_test_file(
const std::string&
name,
const size_t size_limit) {
64 static const std::string one_line =
"Hello World, this is a test and I like it. Exactly 100 characters long. 0123456780 abcdefghjklmnop..";
67 REQUIRE( ofs.
good() ==
true );
68 REQUIRE( ofs.
is_open() ==
true );
70 for(size=0; size < size_limit; size+=one_line.size()) {
71 if( one_line.size() != ofs.
write(one_line.data(), one_line.size()) ) {
72 ERR_PRINT(
"Write %zu bytes to test file failed: %s", one_line.size(), ofs.
to_string().c_str());
76 if( 1 != ofs.
write(
"X", 1) ) {
82 fname_payload_lst.push_back(
name);
83 fname_payload_copy_lst.push_back(
name+
".copy");
84 fname_payload_size_lst.push_back( size );
88 REQUIRE(
true == add_test_file(
"testfile_blob_01_11kiB.bin", (
size_t)(1024*11)) );
89 REQUIRE(
true == add_test_file(
"testfile_blob_02_65MiB.bin", (
size_t)(1024*1024*65)) );
92 static const data& get() {
101 const data& d = data::get();
107 int res = std::system(
"killall mini_httpd");
114 int res = std::system(
"killall mini_httpd");
117 const std::string cmd = std::string(
mini_httpd_exe)+
" -p 8080 -l "+cwd+
"/mini_httpd.log";
119 res = std::system(cmd.c_str());
129 if( output_stats.
exists() ) {
132 ERR_PRINT2(
"ByteStream copy failed: Failed deletion of existing output file %s", output_fname.c_str());
136 ERR_PRINT2(
"ByteStream copy failed: Not overwriting existing output file %s", output_fname.c_str());
143 ERR_PRINT2(
"ByteStream copy failed: Couldn't open output file %s", output_fname.c_str());
147 uint64_t out_bytes_payload = 0;
150 const size_t written = outfile.
write(data.data(), data.size());
151 out_bytes_payload += written;
152 return data.size() == written;
154 const size_t written = outfile.
write(data.data(), data.size());
155 out_bytes_payload += written;
160 io_buffer.reserve(buffer_size);
164 if ( 0==in_bytes_total || input.
fail() ) {
168 if ( outfile.
fail() ) {
169 IRQ_PRINT(
"ByteStream copy failed: Output file write failed in %s, out %s", input.
to_string().c_str(), outfile.
to_string().c_str());
188 if( http_support_expected ) {
189 REQUIRE( 0 < protos.size() );
191 REQUIRE( 0 == protos.size() );
194 const size_t file_idx = IDX_11kiB;
196 const std::string url =
"not_exiting_file.txt";
201 if(
nullptr != in ) {
202 jau::PLAIN_PRINT(
true,
"test00_protocols: not_exiting_file: %s", in->to_string().c_str());
204 REQUIRE(
nullptr == in );
207 const std::string url =
"file://not_exiting_file_uri.txt";
212 if(
nullptr != in ) {
213 jau::PLAIN_PRINT(
true,
"test00_protocols: not_exiting_file_uri: %s", in->to_string().c_str());
215 REQUIRE(
nullptr == in );
218 const std::string url =
"lala://localhost:8080/" + fname_payload_lst[file_idx];
223 if(
nullptr != in ) {
224 jau::PLAIN_PRINT(
true,
"test00_protocols: not_exiting_protocol_uri: %s", in->to_string().c_str());
226 REQUIRE(
nullptr == in );
229 const std::string url = url_input_root +
"not_exiting_http_uri.txt";
234 if( http_support_expected ) {
235 REQUIRE(
nullptr != in );
237 jau::PLAIN_PRINT(
true,
"test00_protocols: not_exiting_http_uri: %s", in->to_string().c_str());
238 REQUIRE(
false == in->good() );
239 REQUIRE(
true == in->fail() );
240 REQUIRE( 0 == in->content_size() );
242 REQUIRE(
nullptr == in );
252 const size_t file_idx = IDX_11kiB;
254 const std::string url = fname_payload_lst[file_idx];
259 if(
nullptr != in ) {
260 jau::PLAIN_PRINT(
true,
"test00_protocols: local-file-0: %s", in->to_string().c_str());
262 REQUIRE(
nullptr != in );
263 REQUIRE(
false == in->fail() );
265 bool res =
transfer(*in, fname_payload_copy_lst[file_idx]);
266 REQUIRE(
true == res );
269 REQUIRE(
true == out_stats.
exists() );
270 REQUIRE(
true == out_stats.
is_file() );
271 REQUIRE( in->content_size() == out_stats.
size() );
272 REQUIRE( fname_payload_size_lst[file_idx] == out_stats.
size() );
276 const std::string url =
"file://" + fname_payload_lst[file_idx];
281 if(
nullptr != in ) {
282 jau::PLAIN_PRINT(
true,
"test00_protocols: local-file-1: %s", in->to_string().c_str());
284 jau::PLAIN_PRINT(
true,
"test00_protocols: local-file-1: NULL from url '%s'", url.c_str());
286 REQUIRE(
nullptr != in );
287 REQUIRE(
false == in->fail() );
289 bool res =
transfer(*in, fname_payload_copy_lst[file_idx]);
290 REQUIRE(
true == res );
293 REQUIRE(
true == out_stats.
exists() );
294 REQUIRE(
true == out_stats.
is_file() );
295 REQUIRE( in->content_size() == out_stats.
size() );
296 REQUIRE( fname_payload_size_lst[file_idx] == out_stats.
size() );
300 const std::string url = url_input_root + fname_payload_lst[file_idx];
305 if(
nullptr != in ) {
306 jau::PLAIN_PRINT(
true,
"test00_protocols: http: %s", in->to_string().c_str());
308 if( http_support_expected ) {
309 REQUIRE(
nullptr != in );
310 REQUIRE(
false == in->fail() );
312 bool res =
transfer(*in, fname_payload_copy_lst[file_idx]);
313 REQUIRE(
true == res );
316 REQUIRE(
true == out_stats.
exists() );
317 REQUIRE(
true == out_stats.
is_file() );
318 REQUIRE( in->content_size() == out_stats.
size() );
319 REQUIRE( fname_payload_size_lst[file_idx] == out_stats.
size() );
322 REQUIRE(
nullptr == in );
329 const size_t file_idx = IDX_11kiB;
332 bool res =
transfer(data_stream, fname_payload_copy_lst[file_idx], 4096);
333 REQUIRE(
true == res );
336 REQUIRE(
true == out_stats.
exists() );
337 REQUIRE(
true == out_stats.
is_file() );
339 REQUIRE( fname_payload_size_lst[file_idx] == out_stats.
size() );
345 const size_t file_idx = IDX_65MiB;
348 bool res =
transfer(data_stream, fname_payload_copy_lst[file_idx], 4096);
349 REQUIRE(
true == res );
352 REQUIRE(
true == out_stats.
exists() );
353 REQUIRE(
true == out_stats.
is_file() );
355 REQUIRE( fname_payload_size_lst[file_idx] == out_stats.
size() );
361 const size_t file_idx = IDX_65MiB;
364 bool res =
transfer(data_stream, fname_payload_copy_lst[file_idx], 32768);
365 REQUIRE(
true == res );
368 REQUIRE(
true == out_stats.
exists() );
369 REQUIRE(
true == out_stats.
is_file() );
371 REQUIRE( fname_payload_size_lst[file_idx] == out_stats.
size() );
383 const size_t file_idx = IDX_11kiB;
385 const std::string uri_original = url_input_root + fname_payload_lst[file_idx];
389 bool res =
transfer(data_stream, fname_payload_copy_lst[file_idx], 32768);
390 REQUIRE(
true == res );
393 REQUIRE(
true == out_stats.
exists() );
394 REQUIRE(
true == out_stats.
is_file() );
396 REQUIRE( fname_payload_size_lst[file_idx] == out_stats.
size() );
400 const size_t file_idx = IDX_65MiB;
402 const std::string uri_original = url_input_root + fname_payload_lst[file_idx];
406 bool res =
transfer(data_stream, fname_payload_copy_lst[file_idx], 32768);
407 REQUIRE(
true == res );
410 REQUIRE(
true == out_stats.
exists() );
411 REQUIRE(
true == out_stats.
is_file() );
413 REQUIRE( fname_payload_size_lst[file_idx] == out_stats.
size() );
426 const size_t file_idx = IDX_11kiB;
428 const std::string uri_original = url_input_root +
"doesnt_exists.txt";
432 bool res =
transfer(data_stream, fname_payload_copy_lst[file_idx]);
433 REQUIRE(
false == res );
436 REQUIRE(
true == out_stats.
exists() );
437 REQUIRE(
true == out_stats.
is_file() );
438 REQUIRE( data_stream.
fail() ==
true );
441 REQUIRE( 0 == out_stats.
size() );
447 uint64_t xfer_total = 0;
449 std::vector<uint8_t> buffer;
450 buffer.resize(feed_size);
451 while( data_stream.
good() ) {
452 size_t count = data_stream.
read(buffer.data(), buffer.size());
455 if( data_feed->
write(buffer.data(), count) ) {
469 uint64_t xfer_total = 0;
473 std::vector<uint8_t> buffer;
474 buffer.resize(feed_size);
475 while( data_stream.
good() && xfer_total < file_size ) {
476 size_t count = data_stream.
read(buffer.data(), buffer.size());
479 if( data_feed->
write(buffer.data(), count) ) {
492 uint64_t xfer_total = 0;
496 std::vector<uint8_t> buffer;
497 buffer.resize(feed_size);
498 while( data_stream.
good() && xfer_total < file_size ) {
499 size_t count = data_stream.
read(buffer.data(), buffer.size());
502 if( !data_feed->
write(buffer.data(), count) ) {
512 uint64_t xfer_total = 0;
514 std::vector<uint8_t> buffer;
515 buffer.resize(feed_size);
516 while( data_stream.
good() ) {
517 size_t count = data_stream.
read(buffer.data(), buffer.size());
520 if( data_feed->
write(buffer.data(), count) ) {
521 if( xfer_total >= 1024 ) {
536 uint64_t xfer_total = 0;
540 std::vector<uint8_t> buffer;
541 buffer.resize(feed_size);
542 while( data_stream.
good() ) {
543 size_t count = data_stream.
read(buffer.data(), buffer.size());
546 if( data_feed->
write(buffer.data(), count) ) {
547 if( xfer_total >= file_size/4 ) {
562 const size_t buffer_size = 4096;
563 const size_t feed_size = 1024;
565 const size_t file_idx = IDX_11kiB;
569 std::thread feeder_thread= std::thread(&
feed_source_10, &data_feed, feed_size);
571 bool res =
transfer(data_feed, fname_payload_copy_lst[file_idx], buffer_size);
572 if( feeder_thread.joinable() ) {
573 feeder_thread.join();
575 REQUIRE(
true == res );
578 REQUIRE(
true == out_stats.
exists() );
579 REQUIRE(
true == out_stats.
is_file() );
581 REQUIRE( fname_payload_size_lst[file_idx] == out_stats.
size() );
587 std::thread feeder_thread= std::thread(&
feed_source_01, &data_feed, feed_size);
589 bool res =
transfer(data_feed, fname_payload_copy_lst[file_idx], buffer_size);
590 if( feeder_thread.joinable() ) {
591 feeder_thread.join();
593 REQUIRE(
true == res );
596 REQUIRE(
true == out_stats.
exists() );
597 REQUIRE(
true == out_stats.
is_file() );
599 REQUIRE( fname_payload_size_lst[file_idx] == out_stats.
size() );
605 std::thread feeder_thread= std::thread(&
feed_source_00, &data_feed, feed_size);
607 bool res =
transfer(data_feed, fname_payload_copy_lst[file_idx], buffer_size);
608 if( feeder_thread.joinable() ) {
609 feeder_thread.join();
611 REQUIRE(
true == res );
614 REQUIRE(
true == out_stats.
exists() );
615 REQUIRE(
true == out_stats.
is_file() );
617 REQUIRE( fname_payload_size_lst[file_idx] == out_stats.
size() );
622 const size_t file_idx = IDX_65MiB;
626 std::thread feeder_thread= std::thread(&
feed_source_10, &data_feed, feed_size);
628 bool res =
transfer(data_feed, fname_payload_copy_lst[file_idx], buffer_size);
629 if( feeder_thread.joinable() ) {
630 feeder_thread.join();
632 REQUIRE(
true == res );
635 REQUIRE(
true == out_stats.
exists() );
636 REQUIRE(
true == out_stats.
is_file() );
638 REQUIRE( fname_payload_size_lst[file_idx] == out_stats.
size() );
646 const size_t buffer_size = 32768;
647 const size_t feed_size = 32768;
649 const size_t file_idx = IDX_11kiB;
653 std::thread feeder_thread= std::thread(&
feed_source_10, &data_feed, feed_size);
655 bool res =
transfer(data_feed, fname_payload_copy_lst[file_idx], buffer_size);
656 if( feeder_thread.joinable() ) {
657 feeder_thread.join();
659 REQUIRE(
true == res );
662 REQUIRE(
true == out_stats.
exists() );
663 REQUIRE(
true == out_stats.
is_file() );
665 REQUIRE( fname_payload_size_lst[file_idx] == out_stats.
size() );
671 std::thread feeder_thread= std::thread(&
feed_source_01, &data_feed, feed_size);
673 bool res =
transfer(data_feed, fname_payload_copy_lst[file_idx], buffer_size);
674 if( feeder_thread.joinable() ) {
675 feeder_thread.join();
677 REQUIRE(
true == res );
680 REQUIRE(
true == out_stats.
exists() );
681 REQUIRE(
true == out_stats.
is_file() );
683 REQUIRE( fname_payload_size_lst[file_idx] == out_stats.
size() );
689 std::thread feeder_thread= std::thread(&
feed_source_00, &data_feed, feed_size);
691 bool res =
transfer(data_feed, fname_payload_copy_lst[file_idx], buffer_size);
692 if( feeder_thread.joinable() ) {
693 feeder_thread.join();
695 REQUIRE(
true == res );
698 REQUIRE(
true == out_stats.
exists() );
699 REQUIRE(
true == out_stats.
is_file() );
701 REQUIRE( fname_payload_size_lst[file_idx] == out_stats.
size() );
709 const size_t buffer_size = 32768;
710 const size_t feed_size = 32768;
712 const size_t file_idx = IDX_65MiB;
716 std::thread feeder_thread= std::thread(&
feed_source_10, &data_feed, feed_size);
718 bool res =
transfer(data_feed, fname_payload_copy_lst[file_idx], buffer_size);
719 if( feeder_thread.joinable() ) {
720 feeder_thread.join();
722 REQUIRE(
true == res );
725 REQUIRE(
true == out_stats.
exists() );
726 REQUIRE(
true == out_stats.
is_file() );
728 REQUIRE( fname_payload_size_lst[file_idx] == out_stats.
size() );
736 const size_t buffer_size = 4096;
737 const size_t feed_size = 1024;
739 const size_t file_idx = IDX_65MiB;
743 std::thread feeder_thread= std::thread(&
feed_source_20, &data_feed, feed_size);
745 bool res =
transfer(data_feed, fname_payload_copy_lst[file_idx], buffer_size);
746 if( feeder_thread.joinable() ) {
747 feeder_thread.join();
749 REQUIRE(
false == res );
752 REQUIRE(
true == out_stats.
exists() );
753 REQUIRE(
true == out_stats.
is_file() );
756 REQUIRE( fname_payload_size_lst[file_idx] > out_stats.
size() );
762 std::thread feeder_thread= std::thread(&
feed_source_21, &data_feed, feed_size);
764 bool res =
transfer(data_feed, fname_payload_copy_lst[file_idx], buffer_size);
765 if( feeder_thread.joinable() ) {
766 feeder_thread.join();
768 REQUIRE(
false == res );
771 REQUIRE(
true == out_stats.
exists() );
772 REQUIRE(
true == out_stats.
is_file() );
774 REQUIRE( fname_payload_size_lst[file_idx] == data_feed.
content_size() );
783std::vector<std::string> TestByteStream01::fname_payload_lst;
784std::vector<std::string> TestByteStream01::fname_payload_copy_lst;
785std::vector<uint64_t> TestByteStream01::fname_payload_size_lst;
static void feed_source_00(jau::io::ByteInStream_Feed *data_feed, const size_t feed_size=1024)
static void feed_source_20(jau::io::ByteInStream_Feed *data_feed, const size_t feed_size=1024)
static bool transfer(jau::io::ByteInStream &input, const std::string &output_fname, const size_t buffer_size=4096)
void test04_copy_file_ok_65MiB_buff32k()
static void httpd_start()
void test11_copy_http_ok_buff32k()
static void feed_source_01(jau::io::ByteInStream_Feed *data_feed, const size_t feed_size=1024)
void test22_copy_fed_ok_buff32k()
void test20_copy_fed_ok_buff4k_feed1k()
void test01_copy_file_ok_11kiB_buff4k()
void test23_copy_fed_irq()
void test00a_protocols_error()
void test02_copy_file_ok_65MiB_buff4k()
void test21_copy_fed_ok_buff32k()
void test12_copy_http_404()
static void feed_source_10(jau::io::ByteInStream_Feed *data_feed, const size_t feed_size=1024)
static void feed_source_21(jau::io::ByteInStream_Feed *data_feed, const size_t feed_size=1024)
void test00b_protocols_ok()
Platform agnostic representation of POSIX ::lstat() and ::stat() for a given pathname.
constexpr bool exists() const noexcept
Returns true if entity does not exist, exclusive bit.
constexpr bool is_file() const noexcept
Returns true if entity is a file, might be in combination with is_link().
uint64_t size() const noexcept
Returns the size in bytes of this element if is_file(), otherwise zero.
std::string path() const noexcept
Returns the unix path representation.
Ringbuffer-Based byte input stream with an externally provisioned data feed.
void set_content_size(const uint64_t size) noexcept
Set known content size, informal only.
bool has_content_size() const noexcept override
Returns true if implementation is aware of content_size(), otherwise false.
void set_eof(const async_io_result_t result) noexcept
Set end-of-data (EOS), i.e.
bool write(uint8_t in[], size_t length, const jau::fraction_i64 &timeout) noexcept
Write given bytes to the async ringbuffer using explicit given timeout.
uint64_t content_size() const noexcept override
Returns the content_size if known.
std::string id() const noexcept override
return the id of this data source
File based byte input stream, including named file descriptor.
uint64_t content_size() const noexcept override
Returns the content_size if known.
size_t read(void *, size_t) noexcept override
Read from the source.
std::string id() const noexcept override
return the id of this data source
Ringbuffer-Based byte input stream with a URL connection provisioned data feed.
uint64_t content_size() const noexcept override
Returns the content_size if known.
bool has_content_size() const noexcept override
Returns true if implementation is aware of content_size(), otherwise false.
Abstract byte input stream object.
virtual void close() noexcept=0
Close the stream if supported by the underlying mechanism.
virtual bool has_content_size() const noexcept=0
Returns true if implementation is aware of content_size(), otherwise false.
virtual uint64_t content_size() const noexcept=0
Returns the content_size if known.
virtual std::string to_string() const noexcept=0
File based byte output stream, including named file descriptor.
size_t write(const void *, size_t) noexcept override
Write to the data sink.
std::string to_string() const noexcept override
bool is_open() const noexcept override
Checks if the stream has an associated file.
bool fail() const noexcept
Checks if an error has occurred.
bool good() const noexcept
Checks if no error nor eof() has occurred i.e.
#define ERR_PRINT(...)
Use for unconditional error messages, prefix '[elapsed_time] Error @ FILE:LINE FUNC: '.
#define ERR_PRINT2(...)
Use for unconditional error messages, prefix '[elapsed_time] Error @ FILE:LINE FUNC: '.
#define IRQ_PRINT(...)
Use for unconditional interruption messages, prefix '[elapsed_time] Interrupted @ FILE:LINE FUNC: '.
std::string to_string(const endian_t v) noexcept
Return std::string representation of the given endian.
constexpr std::string_view name(const Bool v) noexcept
std::string get_cwd() noexcept
Return the current working directory or empty on failure.
bool compare(const file_stats &source1, const file_stats &source2, const bool verbose=false) noexcept
Compare the bytes of both files, denoted by source1 and source2.
bool remove(const std::string &path, const traverse_options topts=traverse_options::none) noexcept
Remove the given path.
bool to_fraction_i64(fraction_i64 &result, const std::string &value, const fraction_i64 &min_allowed, const fraction_i64 &max_allowed) noexcept
Stores the fraction_i64 value of the given string value in format <num>/<denom>, which may contain wh...
fraction_timespec getMonotonicTime() noexcept
Returns current monotonic time since Unix Epoch 00:00:00 UTC on 1970-01-01.
fraction< int64_t > fraction_i64
fraction using int64_t as integral type
std::unique_ptr< ByteInStream > to_ByteInStream(const std::string &path_or_uri, jau::fraction_i64 timeout=20_s) noexcept
Parses the given path_or_uri, if it matches a supported protocol, see jau::io::uri::protocol_supporte...
bool is_local_file_protocol(const std::string_view &uri) noexcept
Returns true if the uri-scheme of given uri matches the local file protocol, i.e.
uint64_t read_stream(ByteInStream &in, secure_vector< uint8_t > &buffer, const StreamConsumerFunc &consumer_fn) noexcept
Synchronous byte input stream reader using the given StreamConsumerFunc consumer_fn.
jau::function< bool(secure_vector< uint8_t > &, bool)> StreamConsumerFunc
Stream consumer function.
std::vector< std::string_view > supported_protocols() noexcept
Returns a list of supported protocol supported by libcurl network protocols, queried at runtime.
std::vector< T, jau::callocator_sec< T > > secure_vector
void print_stats(const std::string &prefix, const uint64_t &out_bytes_total, const jau::fraction_i64 &td) noexcept
bool protocol_supported(const std::string_view &uri) noexcept
Returns true if the uri-scheme of given uri matches a supported by libcurl network protocols otherwis...
@ FAILED
Operation failed.
@ SUCCESS
Operation succeeded.
void PLAIN_PRINT(const bool printPrefix, const char *format,...) noexcept
Use for unconditional plain messages, prefix '[elapsed_time] ' if printPrefix == true.
int fprintf_td(const uint64_t elapsed_ms, FILE *stream, const char *format,...) noexcept
Convenient fprintf() invocation, prepending the given elapsed_ms timestamp.
bool sleep_for(const fraction_timespec &relative_time, const bool monotonic=true, const bool ignore_irq=true) noexcept
sleep_for causes the current thread to block until a specific amount of time has passed.
Timespec structure using int64_t for its components in analogy to struct timespec_t on 64-bit platfor...
METHOD_AS_TEST_CASE(TestByteStream01::test00a_protocols_error, "test00a_protocols_error")
constexpr std::string_view mini_httpd_exe