8#include "../../../tests/testXWC.hpp"
15namespace streamWriterFaultInject
19enum class xrifFaultMode
29 xrifFaultMode mode{ xrifFaultMode::none };
31 xrif_error_t error{ XRIF_ERROR_BADARG };
38 bool enabled{
false };
40 size_t resultNmemb{ 0 };
49 xrifFault allocateRaw;
50 xrifFault allocateReordered;
53 xrifFault writeHeader;
64bool shouldFault( xrifFault &fault );
67bool shouldFault( fwriteFault &fault );
88streamWriter_test_xrif_configure( xrif_t handle,
int difference_method,
int reorder_method,
int compress_method );
89xrif_error_t streamWriter_test_xrif_set_size(
90 xrif_t handle, xrif_dimension_t w, xrif_dimension_t h, xrif_dimension_t d, xrif_dimension_t f, xrif_typecode_t c );
91xrif_error_t streamWriter_test_xrif_allocate_raw( xrif_t handle );
92xrif_error_t streamWriter_test_xrif_allocate_reordered( xrif_t handle );
93xrif_error_t streamWriter_test_xrif_set_lz4_acceleration( xrif_t handle, int32_t lz4_accel );
94xrif_error_t streamWriter_test_xrif_encode( xrif_t handle );
95xrif_error_t streamWriter_test_xrif_write_header(
char *header, xrif_t handle );
96size_t streamWriter_test_fwrite(
const void *ptr,
size_t size,
size_t nmemb, FILE *stream );
99#define xrif_configure streamWriter_test_xrif_configure
100#define xrif_set_size streamWriter_test_xrif_set_size
101#define xrif_allocate_raw streamWriter_test_xrif_allocate_raw
102#define xrif_allocate_reordered streamWriter_test_xrif_allocate_reordered
103#define xrif_set_lz4_acceleration streamWriter_test_xrif_set_lz4_acceleration
104#define xrif_encode streamWriter_test_xrif_encode
105#define xrif_write_header streamWriter_test_xrif_write_header
106#define fwrite streamWriter_test_fwrite
107#define protected public
108#include "../streamWriter.hpp"
111#undef xrif_write_header
113#undef xrif_set_lz4_acceleration
114#undef xrif_allocate_reordered
115#undef xrif_allocate_raw
119#include "../../../tests/testMacrosINDI.hpp"
126namespace streamWriterFaultInject
131 static state s_faults;
140bool shouldFault( xrifFault &fault )
143 return fault.mode != xrifFaultMode::none && ( fault.triggerCall == -1 || fault.callCount == fault.triggerCall );
146bool shouldFault( fwriteFault &fault )
149 return fault.enabled && ( fault.triggerCall == -1 || fault.callCount == fault.triggerCall );
155streamWriter_test_xrif_configure( xrif_t handle,
int difference_method,
int reorder_method,
int compress_method )
157 auto &fault = streamWriterFaultInject::faults().configure;
159 if( streamWriterFaultInject::shouldFault( fault ) )
161 if( fault.mode == streamWriterFaultInject::xrifFaultMode::passThroughError )
163 xrif_error_t rv =
::xrif_configure( handle, difference_method, reorder_method, compress_method );
164 if( rv != XRIF_NOERROR )
173 return ::xrif_configure( handle, difference_method, reorder_method, compress_method );
176xrif_error_t streamWriter_test_xrif_set_size(
177 xrif_t handle, xrif_dimension_t w, xrif_dimension_t h, xrif_dimension_t d, xrif_dimension_t f, xrif_typecode_t c )
179 auto &fault = streamWriterFaultInject::faults().setSize;
181 if( streamWriterFaultInject::shouldFault( fault ) )
183 if( fault.mode == streamWriterFaultInject::xrifFaultMode::passThroughError )
186 if( rv != XRIF_NOERROR )
195 return ::xrif_set_size( handle, w, h, d, f, c );
198xrif_error_t streamWriter_test_xrif_allocate_raw( xrif_t handle )
200 auto &fault = streamWriterFaultInject::faults().allocateRaw;
202 if( streamWriterFaultInject::shouldFault( fault ) )
204 if( fault.mode == streamWriterFaultInject::xrifFaultMode::passThroughError )
207 if( rv != XRIF_NOERROR )
216 return ::xrif_allocate_raw( handle );
219xrif_error_t streamWriter_test_xrif_allocate_reordered( xrif_t handle )
221 auto &fault = streamWriterFaultInject::faults().allocateReordered;
223 if( streamWriterFaultInject::shouldFault( fault ) )
225 if( fault.mode == streamWriterFaultInject::xrifFaultMode::passThroughError )
228 if( rv != XRIF_NOERROR )
237 return ::xrif_allocate_reordered( handle );
240xrif_error_t streamWriter_test_xrif_set_lz4_acceleration( xrif_t handle, int32_t lz4_accel )
242 auto &fault = streamWriterFaultInject::faults().setLz4;
244 if( streamWriterFaultInject::shouldFault( fault ) )
246 if( fault.mode == streamWriterFaultInject::xrifFaultMode::passThroughError )
249 if( rv != XRIF_NOERROR )
258 return ::xrif_set_lz4_acceleration( handle, lz4_accel );
261xrif_error_t streamWriter_test_xrif_encode( xrif_t handle )
263 auto &fault = streamWriterFaultInject::faults().encode;
265 if( streamWriterFaultInject::shouldFault( fault ) )
267 if( fault.mode == streamWriterFaultInject::xrifFaultMode::passThroughError )
270 if( rv != XRIF_NOERROR )
279 return ::xrif_encode( handle );
282xrif_error_t streamWriter_test_xrif_write_header(
char *header, xrif_t handle )
284 auto &fault = streamWriterFaultInject::faults().writeHeader;
286 if( streamWriterFaultInject::shouldFault( fault ) )
288 if( fault.mode == streamWriterFaultInject::xrifFaultMode::passThroughError )
291 if( rv != XRIF_NOERROR )
300 return ::xrif_write_header( header, handle );
303size_t streamWriter_test_fwrite(
const void *ptr,
size_t size,
size_t nmemb, FILE *stream )
305 auto &fault = streamWriterFaultInject::faults().write;
307 if( streamWriterFaultInject::shouldFault( fault ) )
309 return ::fwrite( ptr, size, std::min( nmemb, fault.resultNmemb ), stream );
312 return ::fwrite( ptr, size, nmemb, stream );
330namespace streamWriterTest
339 streamWriter_test(
const std::string &device )
341 m_configName = device;
350struct streamWriter_data_test
352 streamWriter_test *m_sw;
355 streamWriter_data_test( streamWriter_test *sw )
361 std::string rawimageDir()
363 return m_sw->m_rawimageDir;
367 pcf::IndiProperty writingToggle( pcf::IndiElement::SwitchStateType state )
369 pcf::IndiProperty ip;
370 m_sw->createStandardIndiToggleSw( ip,
"writing" );
371 ip[
"toggle"].setSwitchState( state );
377 int setup_circbufs(
int width,
int height,
int dataType,
int circBuffLength,
int writeChunkLength )
379 m_sw->m_typeSize = ImageStreamIO_typesize( dataType );
381 m_sw->m_maxCircBuffLength = circBuffLength;
382 m_sw->m_maxCircBuffSize = (
width * height * m_sw->m_typeSize * circBuffLength + 1 ) / 1048576.0;
383 m_sw->m_maxWriteChunkLength = writeChunkLength;
385 m_sw->m_width =
width;
386 m_sw->m_height = height;
387 m_sw->m_dataType = dataType;
389 return m_sw->allocate_circbufs();
395 m_sw->initialize_xrif();
396 return m_sw->allocate_xrif();
400 int fill_circbuf_uint16()
403 for(
size_t pp = 0; pp < m_sw->m_circBuffLength; ++pp )
406 for(
size_t rr = 0; rr < m_sw->m_width; ++rr )
408 for(
size_t cc = 0; cc < m_sw->m_height; ++cc )
411 m_sw->m_rawImageCircBuff )[pp * m_sw->m_width * m_sw->m_height + rr * m_sw->m_height + cc] =
421 uint64_t *curr_timing = m_sw->m_timingCircBuff + 5 * pp;
423 curr_timing[1] = pp + 1000;
424 curr_timing[2] = pp + 2000;
425 curr_timing[3] = pp + m_sw->m_circBuffLength + 1000;
426 curr_timing[4] = pp + m_sw->m_circBuffLength + 2000;
432 int write_frames(
int start,
int stop )
434 m_sw->m_rawimageDir =
"/tmp";
436 m_sw->m_currSaveStart = start;
437 m_sw->m_currSaveStop = stop;
438 m_sw->m_currSaveStopFrameNo = stop;
441 return m_sw->doEncode();
445 int comp_frames_uint16(
size_t start,
size_t stop )
447 std::cout <<
"Reading: " << m_sw->m_outFilePath <<
"\n";
449 xrif_t xrif =
nullptr;
450 if( xrif_new( &xrif ) != XRIF_NOERROR )
452 std::cerr <<
"Error allocating XRIF image decoder.\n";
456 xrif_t xrif_timing =
nullptr;
457 if( xrif_new( &xrif_timing ) != XRIF_NOERROR )
459 std::cerr <<
"Error allocating XRIF timing decoder.\n";
464 char header[XRIF_HEADER_SIZE];
466 FILE *fp_xrif = fopen( m_sw->m_outFilePath.c_str(),
"rb" );
467 if( fp_xrif ==
nullptr )
469 std::cerr <<
"Error opening " << m_sw->m_outFilePath <<
" for readback.\n";
471 xrif_delete( xrif_timing );
475 size_t nr = fread( header, 1, XRIF_HEADER_SIZE, fp_xrif );
477 if( nr != XRIF_HEADER_SIZE )
479 std::cerr <<
"Error reading header of " << m_sw->m_outFilePath <<
"\n";
482 xrif_delete( xrif_timing );
486 uint32_t header_size;
487 xrif_read_header( xrif, &header_size, header );
490 if( xrif_width( xrif ) != m_sw->m_width )
492 std::cerr <<
"width mismatch\n";
496 if( xrif_height( xrif ) != m_sw->m_height )
498 std::cerr <<
"height mismatch\n";
502 if( xrif_depth( xrif ) != 1 )
504 std::cerr <<
"depth mismatch\n";
508 if( xrif_frames( xrif ) != stop - start )
510 std::cerr <<
"frames mismatch\n";
514 xrif_allocate( xrif );
516 nr = fread( xrif->raw_buffer, 1, xrif->compressed_size, fp_xrif );
518 if( nr != xrif->compressed_size )
520 std::cerr <<
"error reading compressed image buffer.\n";
523 xrif_delete( xrif_timing );
527 if( xrif_decode( xrif ) != XRIF_NOERROR )
529 std::cerr <<
"error decoding compressed image buffer.\n";
532 xrif_delete( xrif_timing );
538 for(
size_t n = 0; n < m_sw->m_width * m_sw->m_height * m_sw->m_typeSize * ( stop - start ); ++n )
540 if( m_sw->m_rawImageCircBuff[start * m_sw->m_width * m_sw->m_height * m_sw->m_typeSize + n] !=
541 xrif->raw_buffer[n] )
547 std::cerr <<
"Buffers don't match: " << badpix <<
" bad pixels.\n";
551 char timing_header[XRIF_HEADER_SIZE];
552 nr = fread( timing_header, 1, XRIF_HEADER_SIZE, fp_xrif );
553 if( nr != XRIF_HEADER_SIZE )
555 std::cerr <<
"Error reading timing header of " << m_sw->m_outFilePath <<
"\n";
558 xrif_delete( xrif_timing );
562 uint32_t timing_header_size;
563 xrif_read_header( xrif_timing, &timing_header_size, timing_header );
565 if( xrif_width( xrif_timing ) != 5 )
567 std::cerr <<
"timing width mismatch\n";
571 if( xrif_height( xrif_timing ) != 1 )
573 std::cerr <<
"timing height mismatch\n";
577 if( xrif_depth( xrif_timing ) != 1 )
579 std::cerr <<
"timing depth mismatch\n";
583 if( xrif_frames( xrif_timing ) != stop - start )
585 std::cerr <<
"timing frame count mismatch\n";
589 xrif_allocate( xrif_timing );
591 nr = fread( xrif_timing->raw_buffer, 1, xrif_timing->compressed_size, fp_xrif );
592 if( nr != xrif_timing->compressed_size )
594 std::cerr <<
"error reading compressed timing buffer.\n";
597 xrif_delete( xrif_timing );
601 if( xrif_decode( xrif_timing ) != XRIF_NOERROR )
603 std::cerr <<
"error decoding compressed timing buffer.\n";
606 xrif_delete( xrif_timing );
610 size_t badtiming = 0;
611 for(
size_t n = 0; n < 5 * ( stop - start ); ++n )
613 if( m_sw->m_timingCircBuff[start * 5 + n] !=
reinterpret_cast<uint64_t *
>( xrif_timing->raw_buffer )[n] )
621 std::cerr <<
"Timing buffers don't match: " << badtiming <<
" bad entries.\n";
627 xrif_delete( xrif_timing );
638SCENARIO(
"streamWriter INDI Callbacks",
"[streamWriter]" )
641 #ifdef STREAMWRITER_TEST_DOXYGEN_REF
642 streamWriter::newCallBack_m_indiP_writing( pcf::IndiProperty() );
654TEST_CASE(
"streamWriter writing toggle transitions and stopped writes",
"[streamWriter]" )
657 #ifdef STREAMWRITER_TEST_DOXYGEN_REF
663 SECTION(
"toggle requests only change state for valid start and stop transitions" )
665 streamWriter_test sw(
"testdev" );
666 streamWriter_data_test sw_test( &sw );
668 pcf::IndiProperty ipOn = sw_test.writingToggle( pcf::IndiElement::On );
669 pcf::IndiProperty ipOff = sw_test.writingToggle( pcf::IndiElement::Off );
672 REQUIRE( sw.newCallBack_m_indiP_writing( ipOn ) == 0 );
675 REQUIRE( sw.newCallBack_m_indiP_writing( ipOn ) == 0 );
678 REQUIRE( sw.newCallBack_m_indiP_writing( ipOff ) == 0 );
681 REQUIRE( sw.newCallBack_m_indiP_writing( ipOn ) == 0 );
686 REQUIRE( sw.newCallBack_m_indiP_writing( ipOff ) == 0 );
690 SECTION(
"stopping without queued frames settles back to NOT_WRITING" )
692 streamWriter_test sw(
"testdev" );
693 streamWriter_data_test sw_test( &sw );
695 pcf::IndiProperty ipOn = sw_test.writingToggle( pcf::IndiElement::On );
696 pcf::IndiProperty ipOff = sw_test.writingToggle( pcf::IndiElement::Off );
698 REQUIRE( sw_test.setup_circbufs( 16, 16, XRIF_TYPECODE_UINT16, 8, 4 ) == 0 );
699 REQUIRE( sw_test.setup_xrif() == 0 );
701 REQUIRE( sw.newCallBack_m_indiP_writing( ipOn ) == 0 );
704 REQUIRE( sw.newCallBack_m_indiP_writing( ipOff ) == 0 );
707 sw.m_currSaveStart = 0;
708 sw.m_currSaveStop = 0;
709 sw.m_currSaveStopFrameNo = 17;
711 REQUIRE( sw.doEncode() == 0 );
715 SECTION(
"stopping with pending frames encodes through the final queued frame" )
717 streamWriter_test sw(
"testdev" );
718 streamWriter_data_test sw_test( &sw );
720 pcf::IndiProperty ipOff = sw_test.writingToggle( pcf::IndiElement::Off );
722 REQUIRE( sw_test.setup_circbufs( 120, 120, XRIF_TYPECODE_UINT16, 10, 5 ) == 0 );
723 REQUIRE( sw_test.setup_xrif() == 0 );
724 REQUIRE( sw_test.fill_circbuf_uint16() == 0 );
727 REQUIRE( sw.newCallBack_m_indiP_writing( ipOff ) == 0 );
730 sw.m_rawimageDir =
"/tmp";
731 sw.m_currSaveStart = 5;
732 sw.m_currSaveStop = 8;
733 sw.m_currSaveStopFrameNo = 8;
735 REQUIRE( sw.doEncode() == 0 );
737 REQUIRE( sw_test.comp_frames_uint16( 5, 8 ) == 0 );
745TEST_CASE(
"streamWriter allocation and encode edge cases",
"[streamWriter]" )
748 #ifdef STREAMWRITER_TEST_DOXYGEN_REF
755 SECTION(
"allocate_circbufs rejects frames that cannot fit in the requested maximum buffer size" )
757 streamWriter_test sw(
"testdev" );
759 sw.m_typeSize = ImageStreamIO_typesize( XRIF_TYPECODE_UINT16 );
760 sw.m_maxCircBuffLength = 1024;
761 sw.m_maxCircBuffSize = 1024.0;
762 sw.m_maxWriteChunkLength = 512;
765 sw.m_dataType = XRIF_TYPECODE_UINT16;
767 REQUIRE( sw.allocate_circbufs() < 0 );
770 SECTION(
"uncompressed XRIF encoding still preserves the saved frames" )
772 streamWriter_test sw(
"testdev" );
773 streamWriter_data_test sw_test( &sw );
775 sw.m_compress =
false;
777 REQUIRE( sw_test.setup_circbufs( 120, 120, XRIF_TYPECODE_UINT16, 10, 5 ) == 0 );
778 REQUIRE( sw_test.setup_xrif() == 0 );
779 REQUIRE( sw_test.fill_circbuf_uint16() == 0 );
780 REQUIRE( sw_test.write_frames( 0, 5 ) == 0 );
781 REQUIRE( sw_test.comp_frames_uint16( 0, 5 ) == 0 );
784 SECTION(
"doEncode returns immediately when not writing" )
786 streamWriter_test sw(
"testdev" );
790 REQUIRE( sw.doEncode() == 0 );
793 SECTION(
"doEncode rejects an all-zero timestamp for the first saved frame" )
795 streamWriter_test sw(
"testdev" );
796 streamWriter_data_test sw_test( &sw );
798 REQUIRE( sw_test.setup_circbufs( 16, 16, XRIF_TYPECODE_UINT16, 8, 4 ) == 0 );
799 REQUIRE( sw_test.setup_xrif() == 0 );
800 REQUIRE( sw_test.fill_circbuf_uint16() == 0 );
802 std::fill_n( sw.m_timingCircBuff, 5 * sw.m_circBuffLength, 0ULL );
804 sw.m_rawimageDir =
"/tmp";
805 sw.m_currSaveStart = 0;
806 sw.m_currSaveStop = 1;
807 sw.m_currSaveStopFrameNo = 1;
810 REQUIRE( sw.doEncode() < 0 );
813 SECTION(
"doEncode reports directory creation failures below a non-directory save root" )
815 streamWriter_test sw(
"testdev" );
816 streamWriter_data_test sw_test( &sw );
818 const std::filesystem::path blocker = std::filesystem::path(
"/tmp" ) /
"streamWriter_encode_blocker";
820 std::filesystem::remove( blocker );
822 std::ofstream blockerOut( blocker.string() );
823 blockerOut <<
"block";
826 REQUIRE( sw_test.setup_circbufs( 16, 16, XRIF_TYPECODE_UINT16, 8, 4 ) == 0 );
827 REQUIRE( sw_test.setup_xrif() == 0 );
828 REQUIRE( sw_test.fill_circbuf_uint16() == 0 );
830 sw.m_rawimageDir = blocker.string();
831 sw.m_currSaveStart = 0;
832 sw.m_currSaveStop = 1;
833 sw.m_currSaveStopFrameNo = 1;
836 REQUIRE( sw.doEncode() < 0 );
838 std::filesystem::remove( blocker );
841 SECTION(
"doEncode reports file open failures when the output name contains a path separator" )
843 streamWriter_test sw(
"testdev" );
844 streamWriter_data_test sw_test( &sw );
846 REQUIRE( sw_test.setup_circbufs( 16, 16, XRIF_TYPECODE_UINT16, 8, 4 ) == 0 );
847 REQUIRE( sw_test.setup_xrif() == 0 );
848 REQUIRE( sw_test.fill_circbuf_uint16() == 0 );
850 sw.m_rawimageDir =
"/tmp";
851 sw.m_outName =
"bad/name";
852 sw.m_currSaveStart = 0;
853 sw.m_currSaveStop = 1;
854 sw.m_currSaveStopFrameNo = 1;
857 REQUIRE( sw.doEncode() < 0 );
865TEST_CASE(
"streamWriter fault injection covers XRIF setup and write warnings",
"[streamWriter]" )
868 #ifdef STREAMWRITER_TEST_DOXYGEN_REF
875 SECTION(
"allocate_xrif fails when image XRIF configuration faults" )
877 streamWriterFaultInject::resetScope faultScope;
878 streamWriter_test sw(
"testdev" );
879 streamWriter_data_test sw_test( &sw );
881 REQUIRE( sw_test.setup_circbufs( 16, 16, XRIF_TYPECODE_UINT16, 8, 4 ) == 0 );
882 REQUIRE( sw.initialize_xrif() == 0 );
884 streamWriterFaultInject::reset();
885 streamWriterFaultInject::faults().configure.mode = streamWriterFaultInject::xrifFaultMode::fail;
886 streamWriterFaultInject::faults().configure.triggerCall = 1;
888 REQUIRE( sw.allocate_xrif() < 0 );
891 SECTION(
"allocate_xrif fails when timing XRIF reordered allocation faults" )
893 streamWriterFaultInject::resetScope faultScope;
894 streamWriter_test sw(
"testdev" );
895 streamWriter_data_test sw_test( &sw );
897 REQUIRE( sw_test.setup_circbufs( 16, 16, XRIF_TYPECODE_UINT16, 8, 4 ) == 0 );
898 REQUIRE( sw.initialize_xrif() == 0 );
900 streamWriterFaultInject::reset();
901 streamWriterFaultInject::faults().allocateReordered.mode = streamWriterFaultInject::xrifFaultMode::fail;
902 streamWriterFaultInject::faults().allocateReordered.triggerCall = 2;
903 streamWriterFaultInject::faults().allocateReordered.error = XRIF_ERROR_MALLOC;
905 REQUIRE( sw.allocate_xrif() < 0 );
908 SECTION(
"doEncode still recovers frames when image XRIF size reports a warning after setup" )
910 streamWriterFaultInject::resetScope faultScope;
911 streamWriter_test sw(
"testdev" );
912 streamWriter_data_test sw_test( &sw );
914 REQUIRE( sw_test.setup_circbufs( 120, 120, XRIF_TYPECODE_UINT16, 10, 5 ) == 0 );
915 REQUIRE( sw_test.setup_xrif() == 0 );
916 REQUIRE( sw_test.fill_circbuf_uint16() == 0 );
918 streamWriterFaultInject::faults().setSize.mode = streamWriterFaultInject::xrifFaultMode::passThroughError;
919 streamWriterFaultInject::faults().setSize.triggerCall = 1;
920 streamWriterFaultInject::faults().setSize.error = XRIF_ERROR_INVALID_SIZE;
922 REQUIRE( sw_test.write_frames( 0, 5 ) == 0 );
923 REQUIRE( sw_test.comp_frames_uint16( 0, 5 ) == 0 );
926 SECTION(
"doEncode still recovers frames when timing LZ4 setup reports a warning" )
928 streamWriterFaultInject::resetScope faultScope;
929 streamWriter_test sw(
"testdev" );
930 streamWriter_data_test sw_test( &sw );
932 REQUIRE( sw_test.setup_circbufs( 120, 120, XRIF_TYPECODE_UINT16, 10, 5 ) == 0 );
933 REQUIRE( sw_test.setup_xrif() == 0 );
934 REQUIRE( sw_test.fill_circbuf_uint16() == 0 );
936 streamWriterFaultInject::faults().setLz4.mode = streamWriterFaultInject::xrifFaultMode::fail;
937 streamWriterFaultInject::faults().setLz4.triggerCall = 2;
938 streamWriterFaultInject::faults().setLz4.error = XRIF_ERROR_BADARG;
940 REQUIRE( sw_test.write_frames( 5, 10 ) == 0 );
941 REQUIRE( sw_test.comp_frames_uint16( 5, 10 ) == 0 );
944 SECTION(
"doEncode still recovers frames when timing encode reports an alert after encoding" )
946 streamWriterFaultInject::resetScope faultScope;
947 streamWriter_test sw(
"testdev" );
948 streamWriter_data_test sw_test( &sw );
950 REQUIRE( sw_test.setup_circbufs( 120, 120, XRIF_TYPECODE_UINT16, 10, 5 ) == 0 );
951 REQUIRE( sw_test.setup_xrif() == 0 );
952 REQUIRE( sw_test.fill_circbuf_uint16() == 0 );
954 streamWriterFaultInject::faults().encode.mode = streamWriterFaultInject::xrifFaultMode::passThroughError;
955 streamWriterFaultInject::faults().encode.triggerCall = 2;
956 streamWriterFaultInject::faults().encode.error = XRIF_ERROR_NOTIMPL;
958 REQUIRE( sw_test.write_frames( 2, 5 ) == 0 );
959 REQUIRE( sw_test.comp_frames_uint16( 2, 5 ) == 0 );
962 SECTION(
"doEncode still recovers frames when timing header generation reports an alert" )
964 streamWriterFaultInject::resetScope faultScope;
965 streamWriter_test sw(
"testdev" );
966 streamWriter_data_test sw_test( &sw );
968 REQUIRE( sw_test.setup_circbufs( 120, 120, XRIF_TYPECODE_UINT16, 10, 5 ) == 0 );
969 REQUIRE( sw_test.setup_xrif() == 0 );
970 REQUIRE( sw_test.fill_circbuf_uint16() == 0 );
972 streamWriterFaultInject::faults().writeHeader.mode = streamWriterFaultInject::xrifFaultMode::passThroughError;
973 streamWriterFaultInject::faults().writeHeader.triggerCall = 2;
974 streamWriterFaultInject::faults().writeHeader.error = XRIF_ERROR_NULLPTR;
976 REQUIRE( sw_test.write_frames( 5, 8 ) == 0 );
977 REQUIRE( sw_test.comp_frames_uint16( 5, 8 ) == 0 );
980 SECTION(
"doEncode returns success but leaves a truncated archive after a short image-data write" )
982 streamWriterFaultInject::resetScope faultScope;
983 streamWriter_test sw(
"testdev" );
984 streamWriter_data_test sw_test( &sw );
986 REQUIRE( sw_test.setup_circbufs( 120, 120, XRIF_TYPECODE_UINT16, 10, 5 ) == 0 );
987 REQUIRE( sw_test.setup_xrif() == 0 );
988 REQUIRE( sw_test.fill_circbuf_uint16() == 0 );
990 streamWriterFaultInject::faults().write.enabled =
true;
991 streamWriterFaultInject::faults().write.triggerCall = 2;
992 streamWriterFaultInject::faults().write.resultNmemb = sw.m_xrif->compressed_size / 2;
994 REQUIRE( sw_test.write_frames( 0, 5 ) == 0 );
995 REQUIRE( sw_test.comp_frames_uint16( 0, 5 ) < 0 );
998 SECTION(
"doEncode returns success but leaves a truncated archive after a short timing-data write" )
1000 streamWriterFaultInject::resetScope faultScope;
1001 streamWriter_test sw(
"testdev" );
1002 streamWriter_data_test sw_test( &sw );
1004 REQUIRE( sw_test.setup_circbufs( 120, 120, XRIF_TYPECODE_UINT16, 10, 5 ) == 0 );
1005 REQUIRE( sw_test.setup_xrif() == 0 );
1006 REQUIRE( sw_test.fill_circbuf_uint16() == 0 );
1008 streamWriterFaultInject::faults().write.enabled =
true;
1009 streamWriterFaultInject::faults().write.triggerCall = 4;
1010 streamWriterFaultInject::faults().write.resultNmemb =
1011 std::max<size_t>( 1, sw.m_xrif_timing->compressed_size / 2 );
1013 REQUIRE( sw_test.write_frames( 7, 8 ) == 0 );
1014 REQUIRE( sw_test.comp_frames_uint16( 7, 8 ) < 0 );
1022SCENARIO(
"streamWriter Configuration",
"[streamWriter]" )
1024 GIVEN(
"A default constructed streamWriter" )
1026 streamWriter_test sw(
"testdev" );
1027 streamWriter_data_test sw_test( &sw );
1029 WHEN(
"default configurations" )
1031 REQUIRE( sw_test.rawimageDir() ==
"" );
1040SCENARIO(
"streamWriter encoding data",
"[streamWriter]" )
1042 GIVEN(
"A default constructed streamWriter and a 120x120 uint16 stream" )
1044 streamWriter_test sw(
"testdev" );
1045 streamWriter_data_test sw_test( &sw );
1047 WHEN(
"writing full 1st chunk" )
1049 int circBuffLength = 10;
1050 int writeChunkLength = 5;
1051 REQUIRE( sw_test.setup_circbufs( 120, 120, XRIF_TYPECODE_UINT16, circBuffLength, writeChunkLength ) == 0 );
1052 REQUIRE( sw_test.setup_xrif() == 0 );
1054 REQUIRE( sw_test.fill_circbuf_uint16() == 0 );
1056 REQUIRE( sw_test.write_frames( 0, 5 ) == 0 );
1058 REQUIRE( sw_test.comp_frames_uint16( 0, 5 ) == 0 );
1061 WHEN(
"writing full 2nd chunk" )
1063 int circBuffLength = 10;
1064 int writeChunkLength = 5;
1065 REQUIRE( sw_test.setup_circbufs( 120, 120, XRIF_TYPECODE_UINT16, circBuffLength, writeChunkLength ) == 0 );
1066 REQUIRE( sw_test.setup_xrif() == 0 );
1069 REQUIRE( sw_test.fill_circbuf_uint16() == 0 );
1071 REQUIRE( sw_test.write_frames( 5, 10 ) == 0 );
1073 REQUIRE( sw_test.comp_frames_uint16( 5, 10 ) == 0 );
1076 WHEN(
"writing partial 1st chunk" )
1078 int circBuffLength = 10;
1079 int writeChunkLength = 5;
1080 REQUIRE( sw_test.setup_circbufs( 120, 120, XRIF_TYPECODE_UINT16, circBuffLength, writeChunkLength ) == 0 );
1081 REQUIRE( sw_test.setup_xrif() == 0 );
1084 REQUIRE( sw_test.fill_circbuf_uint16() == 0 );
1086 REQUIRE( sw_test.write_frames( 2, 5 ) == 0 );
1088 REQUIRE( sw_test.comp_frames_uint16( 2, 5 ) == 0 );
1091 WHEN(
"writing partial 2nd chunk" )
1093 int circBuffLength = 10;
1094 int writeChunkLength = 5;
1095 REQUIRE( sw_test.setup_circbufs( 120, 120, XRIF_TYPECODE_UINT16, circBuffLength, writeChunkLength ) == 0 );
1096 REQUIRE( sw_test.setup_xrif() == 0 );
1099 REQUIRE( sw_test.fill_circbuf_uint16() == 0 );
1101 REQUIRE( sw_test.write_frames( 5, 8 ) == 0 );
1103 REQUIRE( sw_test.comp_frames_uint16( 5, 8 ) == 0 );
1106 WHEN(
"writing a single middle frame" )
1108 int circBuffLength = 10;
1109 int writeChunkLength = 5;
1110 REQUIRE( sw_test.setup_circbufs( 120, 120, XRIF_TYPECODE_UINT16, circBuffLength, writeChunkLength ) == 0 );
1111 REQUIRE( sw_test.setup_xrif() == 0 );
1113 REQUIRE( sw_test.fill_circbuf_uint16() == 0 );
1115 REQUIRE( sw_test.write_frames( 4, 5 ) == 0 );
1117 REQUIRE( sw_test.comp_frames_uint16( 4, 5 ) == 0 );
1120 WHEN(
"writing a shorter follow-up save after a longer save" )
1122 int circBuffLength = 10;
1123 int writeChunkLength = 5;
1124 REQUIRE( sw_test.setup_circbufs( 120, 120, XRIF_TYPECODE_UINT16, circBuffLength, writeChunkLength ) == 0 );
1125 REQUIRE( sw_test.setup_xrif() == 0 );
1127 REQUIRE( sw_test.fill_circbuf_uint16() == 0 );
1129 REQUIRE( sw_test.write_frames( 0, 5 ) == 0 );
1130 REQUIRE( sw_test.comp_frames_uint16( 0, 5 ) == 0 );
1132 REQUIRE( sw_test.write_frames( 7, 8 ) == 0 );
1133 REQUIRE( sw_test.comp_frames_uint16( 7, 8 ) == 0 );
int initialize_xrif()
Initialize the xrif system.
int allocate_circbufs()
Worker function to allocate the circular buffers.
int allocate_xrif()
Worker function to configure and allocate the xrif handles.
int doEncode()
Function called when semaphore is raised to do the encode and write.
SCENARIO("streamWriter INDI Callbacks", "[streamWriter]")
Verify the streamWriter INDI callback validator accepts only the expected property.
TEST_CASE("streamWriter configuration loads defaults and overrides", "[streamWriter]")
Verify setupConfig() and loadConfig() preserve defaults, overrides, and clamp invalid accelerations.
#define XWCTEST_INDI_NEW_CALLBACK(testclass, propname)
Catch-2 tests for whether a NEW callback properly validates the input property properly.
#define XWCTEST_DOXYGEN_REF(fxn)
This inserts an unused call to a function signature to make doxygen make the link.
Namespace for all libXWC tests.
#define xrif_allocate_reordered
#define xrif_write_header
#define xrif_set_lz4_acceleration
#define xrif_allocate_raw
#define XWCTEST_SETUP_INDI_NEW_PROP(propname)