LCOV - code coverage report
Current view: top level - tests - catch_journal.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 97.5 % 1606 1566
Test Date: 2025-06-19 11:28:46 Functions: 100.0 % 13 13
Legend: Lines: hit not hit

            Line data    Source code
       1              : // Copyright (c) 2023-2025  Made to Order Software Corp.  All Rights Reserved
       2              : //
       3              : // https://snapwebsites.org/project/prinbee
       4              : // contact@m2osw.com
       5              : //
       6              : // This program is free software: you can redistribute it and/or modify
       7              : // it under the terms of the GNU General Public License as published by
       8              : // the Free Software Foundation, either version 3 of the License, or
       9              : // (at your option) any later version.
      10              : //
      11              : // This program is distributed in the hope that it will be useful,
      12              : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      13              : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14              : // GNU General Public License for more details.
      15              : //
      16              : // You should have received a copy of the GNU General Public License
      17              : // along with this program.  If not, see <https://www.gnu.org/licenses/>.
      18              : 
      19              : // self
      20              : //
      21              : #include    "catch_main.h"
      22              : 
      23              : 
      24              : // prinbee
      25              : //
      26              : #include    <prinbee/exception.h>
      27              : #include    <prinbee/journal/journal.h>
      28              : 
      29              : 
      30              : // snapdev
      31              : //
      32              : #include    <snapdev/file_contents.h>
      33              : #include    <snapdev/mkdir_p.h>
      34              : #include    <snapdev/pathinfo.h>
      35              : 
      36              : 
      37              : // C++
      38              : //
      39              : #include    <random>
      40              : 
      41              : 
      42              : // advgetopt
      43              : //
      44              : #include    <advgetopt/conf_file.h>
      45              : 
      46              : 
      47              : // last include
      48              : //
      49              : #include    <snapdev/poison.h>
      50              : 
      51              : 
      52              : 
      53              : namespace
      54              : {
      55              : 
      56              : 
      57              : 
      58       222935 : std::string conf_filename(std::string const & path)
      59              : {
      60       222935 :     return path + "/journal.conf";
      61              : }
      62              : 
      63              : 
      64       111621 : std::string event_filename(std::string const & path, int index)
      65              : {
      66       223242 :     return path + "/journal-" + std::to_string(index) + ".events";
      67              : }
      68              : 
      69              : 
      70       111523 : void unlink_conf(std::string const & path)
      71              : {
      72       111523 :     std::string const filename(conf_filename(path));
      73       111523 :     if(unlink(filename.c_str()) != 0)
      74              :     {
      75          116 :         if(errno != ENOENT)
      76              :         {
      77            0 :             perror("unlink() returned unexpected error.");
      78            0 :             CATCH_REQUIRE(!"unlink() returned an unexpected error");
      79              :         }
      80              :     }
      81       223046 : }
      82              : 
      83              : 
      84       111523 : void unlink_events(std::string const & path)
      85              : {
      86       111523 :     for(int idx(0);; ++idx)
      87              :     {
      88       111566 :         std::string const filename(event_filename(path, idx));
      89       111566 :         if(unlink(filename.c_str()) != 0)
      90              :         {
      91       111523 :             if(errno != ENOENT)
      92              :             {
      93            0 :                 perror("unlink() returned unexpected error.");
      94            0 :                 CATCH_REQUIRE(!"unlink() returned an unexpected error");
      95              :             }
      96       111523 :             break;
      97              :         }
      98       111609 :     }
      99       111523 : }
     100              : 
     101              : 
     102       111523 : std::string conf_path(std::string const & sub_path, bool create_directory = false)
     103              : {
     104       111523 :     std::string const path(SNAP_CATCH2_NAMESPACE::g_tmp_dir() + '/' + sub_path);
     105       111523 :     if(create_directory)
     106              :     {
     107            1 :         CATCH_REQUIRE(snapdev::mkdir_p(path) == 0);
     108              :     }
     109       111523 :     unlink_conf(path);
     110       111523 :     unlink_events(path);
     111       111523 :     return path;
     112            0 : }
     113              : 
     114              : 
     115              : typedef std::map<std::string, std::string> conf_values_t;
     116              : 
     117       111403 : conf_values_t load_conf(std::string const & path)
     118              : {
     119       111403 :     conf_values_t conf_values;
     120       111403 :     snapdev::file_contents file(conf_filename(path));
     121       111403 :     bool const valid(file.read_all());
     122       111403 :     if(!valid)
     123              :     {
     124              :         std::cerr << "--- error loading configuration file: "
     125            0 :             << file.last_error()
     126            0 :             << "\n";
     127              :     }
     128       111403 :     CATCH_REQUIRE(valid);
     129       111403 :     std::string const contents(file.contents());
     130       111403 :     std::list<std::string> lines;
     131       334209 :     snapdev::tokenize_string(lines, contents, "\r\n", true);
     132      1336836 :     for(auto const & l : lines)
     133              :     {
     134      1225433 :         if(l.empty()
     135      1225433 :         || l[0] == '#')
     136              :         {
     137       334209 :             continue;
     138              :         }
     139       891224 :         std::string::size_type const pos(l.find('='));
     140       891224 :         CATCH_REQUIRE(std::string::npos != pos);
     141       891224 :         std::string const name(l.substr(0, pos));
     142       891224 :         std::string const value(l.substr(pos + 1));
     143       891224 :         conf_values.emplace(name, value);
     144       891224 :     }
     145       111403 :     return conf_values;
     146       111403 : }
     147              : 
     148              : 
     149              : }
     150              : 
     151              : 
     152            1 : CATCH_TEST_CASE("journal_helper_functions", "[journal]")
     153              : {
     154            3 :     CATCH_START_SECTION("journal_helper_functions: id_to_string()")
     155              :     {
     156            1 :         std::uint32_t const id((0x31 << 24) | (0x32 << 16) | (0x33 << 8) | 0x34);
     157            1 :         CATCH_REQUIRE(prinbee::id_to_string(id) == "1234");
     158              :     }
     159            2 :     CATCH_END_SECTION()
     160            1 : }
     161              : 
     162              : 
     163           16 : CATCH_TEST_CASE("journal_options", "[journal]")
     164              : {
     165           18 :     CATCH_START_SECTION("journal_options: set_maximum_number_of_files(): default does nothing")
     166              :     {
     167            3 :         std::string const path(conf_path("journal_options"));
     168            1 :         advgetopt::conf_file::reset_conf_files();
     169            1 :         prinbee::journal j(path);
     170            1 :         CATCH_REQUIRE(j.is_valid());
     171            1 :         CATCH_REQUIRE(j.set_maximum_number_of_files(prinbee::JOURNAL_DEFAULT_NUMBER_OF_FILES));
     172            1 :         std::string const filename(conf_filename(path));
     173            1 :         struct stat s;
     174            1 :         if(stat(filename.c_str(), &s) != 0)
     175              :         {
     176            1 :             CATCH_REQUIRE(errno == ENOENT);
     177              :         }
     178              :         else
     179              :         {
     180            0 :             CATCH_REQUIRE(!"set_maximum_number_of_files() default created a configuration file.");
     181              :         }
     182            1 :     }
     183           17 :     CATCH_END_SECTION()
     184              : 
     185           18 :     CATCH_START_SECTION("journal_options: set_maximum_file_size(): default does nothing")
     186              :     {
     187            3 :         std::string const path(conf_path("journal_options"));
     188            1 :         advgetopt::conf_file::reset_conf_files();
     189            1 :         prinbee::journal j(path);
     190            1 :         CATCH_REQUIRE(j.is_valid());
     191            1 :         CATCH_REQUIRE(j.set_maximum_file_size(prinbee::JOURNAL_DEFAULT_FILE_SIZE));
     192            1 :         std::string const filename(conf_filename(path));
     193            1 :         struct stat s;
     194            1 :         if(stat(filename.c_str(), &s) != 0)
     195              :         {
     196            1 :             CATCH_REQUIRE(errno == ENOENT);
     197              :         }
     198              :         else
     199              :         {
     200            0 :             CATCH_REQUIRE(!"set_maximum_file_size() default created a configuration file.");
     201              :         }
     202            1 :     }
     203           17 :     CATCH_END_SECTION()
     204              : 
     205           18 :     CATCH_START_SECTION("journal_options: set_maximum_events(): default does nothing")
     206              :     {
     207            3 :         std::string const path(conf_path("journal_options"));
     208            1 :         advgetopt::conf_file::reset_conf_files();
     209            1 :         prinbee::journal j(path);
     210            1 :         CATCH_REQUIRE(j.is_valid());
     211            1 :         CATCH_REQUIRE(j.set_maximum_events(prinbee::JOURNAL_DEFAULT_EVENTS));
     212            1 :         std::string const filename(conf_filename(path));
     213            1 :         struct stat s;
     214            1 :         if(stat(filename.c_str(), &s) != 0)
     215              :         {
     216            1 :             CATCH_REQUIRE(errno == ENOENT);
     217              :         }
     218              :         else
     219              :         {
     220            0 :             CATCH_REQUIRE(!"set_maximum_events() default created a configuration file.");
     221              :         }
     222            1 :     }
     223           17 :     CATCH_END_SECTION()
     224              : 
     225           18 :     CATCH_START_SECTION("journal_options: set_inline_attachment_size_threshold(): default does nothing")
     226              :     {
     227            3 :         std::string const path(conf_path("journal_options"));
     228            1 :         advgetopt::conf_file::reset_conf_files();
     229            1 :         prinbee::journal j(path);
     230            1 :         CATCH_REQUIRE(j.is_valid());
     231            1 :         CATCH_REQUIRE(j.set_inline_attachment_size_threshold(prinbee::JOURNAL_INLINE_ATTACHMENT_SIZE_DEFAULT_THRESHOLD));
     232            1 :         std::string const filename(conf_filename(path));
     233            1 :         struct stat s;
     234            1 :         if(stat(filename.c_str(), &s) != 0)
     235              :         {
     236            1 :             CATCH_REQUIRE(errno == ENOENT);
     237              :         }
     238              :         else
     239              :         {
     240            0 :             CATCH_REQUIRE(!"set_inline_attachment_size_threshold() default created a configuration file.");
     241              :         }
     242            1 :     }
     243           17 :     CATCH_END_SECTION()
     244              : 
     245           18 :     CATCH_START_SECTION("journal_options: set_sync(): default does nothing")
     246              :     {
     247            3 :         std::string const path(conf_path("journal_options"));
     248            1 :         advgetopt::conf_file::reset_conf_files();
     249            1 :         prinbee::journal j(path);
     250            1 :         CATCH_REQUIRE(j.is_valid());
     251            1 :         CATCH_REQUIRE(j.set_sync(prinbee::sync_t::SYNC_NONE));
     252            1 :         std::string const filename(conf_filename(path));
     253            1 :         struct stat s;
     254            1 :         if(stat(filename.c_str(), &s) != 0)
     255              :         {
     256            1 :             CATCH_REQUIRE(errno == ENOENT);
     257              :         }
     258              :         else
     259              :         {
     260            0 :             CATCH_REQUIRE(!"set_sync() default created a configuration file.");
     261              :         }
     262            1 :     }
     263           17 :     CATCH_END_SECTION()
     264              : 
     265           18 :     CATCH_START_SECTION("journal_options: set_file_management(): default does nothing")
     266              :     {
     267            3 :         std::string const path(conf_path("journal_options"));
     268            1 :         advgetopt::conf_file::reset_conf_files();
     269            1 :         prinbee::journal j(path);
     270            1 :         CATCH_REQUIRE(j.is_valid());
     271            1 :         CATCH_REQUIRE(j.set_file_management(prinbee::file_management_t::FILE_MANAGEMENT_KEEP));
     272            1 :         std::string const filename(conf_filename(path));
     273            1 :         struct stat s;
     274            1 :         if(stat(filename.c_str(), &s) != 0)
     275              :         {
     276            1 :             CATCH_REQUIRE(errno == ENOENT);
     277              :         }
     278              :         else
     279              :         {
     280            0 :             CATCH_REQUIRE(!"set_file_management() default created a configuration file.");
     281              :         }
     282            1 :     }
     283           17 :     CATCH_END_SECTION()
     284              : 
     285           18 :     CATCH_START_SECTION("journal_options: set_compress_when_full(): default does nothing")
     286              :     {
     287            3 :         std::string const path(conf_path("journal_options"));
     288            1 :         advgetopt::conf_file::reset_conf_files();
     289            1 :         prinbee::journal j(path);
     290            1 :         CATCH_REQUIRE(j.is_valid());
     291            1 :         CATCH_REQUIRE(j.set_compress_when_full(false));
     292            1 :         std::string const filename(conf_filename(path));
     293            1 :         struct stat s;
     294            1 :         if(stat(filename.c_str(), &s) != 0)
     295              :         {
     296            1 :             CATCH_REQUIRE(errno == ENOENT);
     297              :         }
     298              :         else
     299              :         {
     300            0 :             CATCH_REQUIRE(!"set_compress_when_full() default created a configuration file.");
     301              :         }
     302            1 :     }
     303           17 :     CATCH_END_SECTION()
     304              : 
     305           18 :     CATCH_START_SECTION("journal_options: set_attachment_copy_handling(): default does nothing")
     306              :     {
     307              :         {
     308            3 :             std::string const path(conf_path("journal_options"));
     309            1 :             advgetopt::conf_file::reset_conf_files();
     310            1 :             prinbee::journal j(path);
     311            1 :             CATCH_REQUIRE(j.is_valid());
     312            1 :             CATCH_REQUIRE(j.set_attachment_copy_handling(prinbee::attachment_copy_handling_t::ATTACHMENT_COPY_HANDLING_SOFTLINK));
     313            1 :             std::string const filename(conf_filename(path));
     314            1 :             struct stat s;
     315            1 :             if(stat(filename.c_str(), &s) != 0)
     316              :             {
     317            1 :                 CATCH_REQUIRE(errno == ENOENT);
     318              :             }
     319              :             else
     320              :             {
     321            0 :                 CATCH_REQUIRE(!"set_attachment_copy_handling() default created a configuration file.");
     322              :             }
     323            1 :             CATCH_REQUIRE(j.get_attachment_copy_handling() == prinbee::attachment_copy_handling_t::ATTACHMENT_COPY_HANDLING_SOFTLINK);
     324            1 :         }
     325              : 
     326              :         // "default" is viewed as "softlink" so it's also the default
     327              :         {
     328            3 :             std::string const path(conf_path("journal_options"));
     329            1 :             advgetopt::conf_file::reset_conf_files();
     330            1 :             prinbee::journal j(path);
     331            1 :             CATCH_REQUIRE(j.is_valid());
     332            1 :             CATCH_REQUIRE(j.set_attachment_copy_handling(prinbee::attachment_copy_handling_t::ATTACHMENT_COPY_HANDLING_DEFAULT));
     333            1 :             std::string const filename(conf_filename(path));
     334            1 :             struct stat s;
     335            1 :             if(stat(filename.c_str(), &s) != 0)
     336              :             {
     337            1 :                 CATCH_REQUIRE(errno == ENOENT);
     338              :             }
     339              :             else
     340              :             {
     341            0 :                 CATCH_REQUIRE(!"set_attachment_copy_handling() default created a configuration file.");
     342              :             }
     343            1 :             CATCH_REQUIRE(j.get_attachment_copy_handling() == prinbee::attachment_copy_handling_t::ATTACHMENT_COPY_HANDLING_SOFTLINK);
     344            1 :         }
     345              :     }
     346           17 :     CATCH_END_SECTION()
     347              : 
     348           18 :     CATCH_START_SECTION("journal_options: verify set options")
     349              :     {
     350              :         enum
     351              :         {
     352              :             COMPRESS_WHEN_FULL,
     353              :             FILE_MANAGEMENT,
     354              :             MAXIMUM_EVENTS,
     355              :             MAXIMUM_FILE_SIZE,
     356              :             MAXIMUM_NUMBER_OF_FILES,
     357              :             FLUSH,
     358              :             SYNC,
     359              :             INLINE_ATTACHMENT_SIZE_THRESHOLD,
     360              :             ATTACHMENT_COPY_HANDLING_SOFTLINK,
     361              :             ATTACHMENT_COPY_HANDLING_HARDLINK,
     362              :             ATTACHMENT_COPY_HANDLING_REFLINK,
     363              :             ATTACHMENT_COPY_HANDLING_FULL,
     364              : 
     365              :             max_options
     366              :         };
     367           13 :         for(int index(0); index < max_options; ++index)
     368              :         {
     369           12 :             std::string expected_result;
     370           36 :             std::string const path(conf_path("journal_options"));
     371           12 :             advgetopt::conf_file::reset_conf_files();
     372           12 :             prinbee::journal j(path);
     373           12 :             CATCH_REQUIRE(j.is_valid());
     374           12 :             switch(index)
     375              :             {
     376            1 :             case COMPRESS_WHEN_FULL:
     377            1 :                 CATCH_REQUIRE(j.set_compress_when_full(true));
     378              :                 //CATCH_REQUIRE(j.get_compress_when_full());
     379            1 :                 break;
     380              : 
     381            1 :             case FILE_MANAGEMENT:
     382              :                 {
     383            1 :                     prinbee::file_management_t const value(static_cast<prinbee::file_management_t>(rand() % 3));
     384              : 
     385              :                     // just setting the default does not re-save the configuration file
     386              :                     // which we need to happen for this test
     387              :                     //
     388            1 :                     if(value == prinbee::file_management_t::FILE_MANAGEMENT_KEEP)
     389              :                     {
     390            1 :                         CATCH_REQUIRE(j.set_file_management(rand() % 2 == 0
     391              :                                     ? prinbee::file_management_t::FILE_MANAGEMENT_TRUNCATE
     392              :                                     : prinbee::file_management_t::FILE_MANAGEMENT_DELETE));
     393              :                     }
     394              : 
     395            1 :                     CATCH_REQUIRE(j.set_file_management(value));
     396            1 :                     CATCH_REQUIRE(j.get_file_management() == value);
     397            1 :                     switch(value)
     398              :                     {
     399            1 :                     case prinbee::file_management_t::FILE_MANAGEMENT_KEEP:
     400            1 :                         expected_result = "keep";
     401            1 :                         break;
     402              : 
     403            0 :                     case prinbee::file_management_t::FILE_MANAGEMENT_TRUNCATE:
     404            0 :                         expected_result = "truncate";
     405            0 :                         break;
     406              : 
     407            0 :                     case prinbee::file_management_t::FILE_MANAGEMENT_DELETE:
     408            0 :                         expected_result = "delete";
     409            0 :                         break;
     410              : 
     411              :                     }
     412              :                 }
     413              :                 break;
     414              : 
     415            1 :             case MAXIMUM_EVENTS:
     416              :                 {
     417            1 :                     std::uint32_t value(0);
     418              :                     do
     419              :                     {
     420            1 :                         value = rand();
     421              :                     }
     422            1 :                     while(value == prinbee::JOURNAL_DEFAULT_EVENTS);
     423            1 :                     CATCH_REQUIRE(j.set_maximum_events(value));
     424            1 :                     if(value < prinbee::JOURNAL_MINIMUM_EVENTS)
     425              :                     {
     426            0 :                         expected_result = std::to_string(prinbee::JOURNAL_MINIMUM_EVENTS);
     427              :                     }
     428            1 :                     else if(value > prinbee::JOURNAL_MAXIMUM_EVENTS)
     429              :                     {
     430            1 :                         expected_result = std::to_string(prinbee::JOURNAL_MAXIMUM_EVENTS);
     431              :                     }
     432              :                     else
     433              :                     {
     434            0 :                         expected_result = std::to_string(value);
     435              :                     }
     436              :                 }
     437            1 :                 break;
     438              : 
     439            1 :             case MAXIMUM_FILE_SIZE:
     440              :                 {
     441              :                     std::uint32_t value;
     442              :                     do
     443              :                     {
     444            1 :                         value = rand() + 1;
     445              :                     }
     446            1 :                     while(value == prinbee::JOURNAL_DEFAULT_FILE_SIZE);
     447            1 :                     CATCH_REQUIRE(j.set_maximum_file_size(value));
     448            1 :                     if(value < prinbee::JOURNAL_MINIMUM_FILE_SIZE)
     449              :                     {
     450            0 :                         expected_result = std::to_string(prinbee::JOURNAL_MINIMUM_FILE_SIZE);
     451              :                     }
     452            1 :                     else if(value > prinbee::JOURNAL_MAXIMUM_FILE_SIZE)
     453              :                     {
     454            1 :                         expected_result = std::to_string(prinbee::JOURNAL_MAXIMUM_FILE_SIZE);
     455              :                     }
     456              :                     else
     457              :                     {
     458            0 :                         expected_result = std::to_string(value);
     459              :                     }
     460              :                 }
     461            1 :                 break;
     462              : 
     463            1 :             case MAXIMUM_NUMBER_OF_FILES:
     464              :                 {
     465              :                     // avoid the default (i.e. 2) so the configuration file
     466              :                     // gets saved
     467              :                     //
     468            1 :                     int const value(rand() % (256 - 3) + 3);
     469            1 :                     CATCH_REQUIRE(j.set_maximum_number_of_files(value));
     470            1 :                     expected_result = std::to_string(value);
     471              :                 }
     472            1 :                 break;
     473              : 
     474            1 :             case FLUSH:
     475            1 :                 CATCH_REQUIRE(j.set_sync(prinbee::sync_t::SYNC_FLUSH));
     476              :                 //CATCH_REQUIRE(j.get_sync() == prinbee::sync_t::SYNC_FLUSH);
     477            1 :                 break;
     478              : 
     479            1 :             case SYNC:
     480            1 :                 CATCH_REQUIRE(j.set_sync(prinbee::sync_t::SYNC_FULL));
     481              :                 //CATCH_REQUIRE(j.get_sync() == prinbee::sync_t::SYNC_FULL);
     482            1 :                 break;
     483              : 
     484            1 :             case INLINE_ATTACHMENT_SIZE_THRESHOLD:
     485              :                 {
     486            1 :                     int value(0);
     487              :                     do
     488              :                     {
     489            1 :                         value = (rand() % (prinbee::JOURNAL_INLINE_ATTACHMENT_SIZE_MAXIMUM_THRESHOLD - prinbee::JOURNAL_INLINE_ATTACHMENT_SIZE_MINIMUM_THRESHOLD)
     490            1 :                                         + prinbee::JOURNAL_INLINE_ATTACHMENT_SIZE_MINIMUM_THRESHOLD);
     491              :                     }
     492            1 :                     while(value == prinbee::JOURNAL_INLINE_ATTACHMENT_SIZE_DEFAULT_THRESHOLD);
     493            1 :                     CATCH_REQUIRE(j.set_inline_attachment_size_threshold(value));
     494            1 :                     expected_result = std::to_string(value);
     495              :                 }
     496            1 :                 break;
     497              : 
     498            1 :             case ATTACHMENT_COPY_HANDLING_SOFTLINK:
     499              :                 // SOFTLINK is the default, to make sure we get a conf file,
     500              :                 // first set HARDLINK and then switch back
     501              :                 //
     502            1 :                 CATCH_REQUIRE(j.set_attachment_copy_handling(prinbee::attachment_copy_handling_t::ATTACHMENT_COPY_HANDLING_HARDLINK));
     503            1 :                 CATCH_REQUIRE(j.set_attachment_copy_handling(prinbee::attachment_copy_handling_t::ATTACHMENT_COPY_HANDLING_SOFTLINK));
     504            1 :                 CATCH_REQUIRE(j.get_attachment_copy_handling() == prinbee::attachment_copy_handling_t::ATTACHMENT_COPY_HANDLING_SOFTLINK);
     505            1 :                 break;
     506              : 
     507            1 :             case ATTACHMENT_COPY_HANDLING_HARDLINK:
     508            1 :                 CATCH_REQUIRE(j.set_attachment_copy_handling(prinbee::attachment_copy_handling_t::ATTACHMENT_COPY_HANDLING_HARDLINK));
     509            1 :                 CATCH_REQUIRE(j.get_attachment_copy_handling() == prinbee::attachment_copy_handling_t::ATTACHMENT_COPY_HANDLING_HARDLINK);
     510            1 :                 break;
     511              : 
     512            1 :             case ATTACHMENT_COPY_HANDLING_REFLINK:
     513            1 :                 CATCH_REQUIRE(j.set_attachment_copy_handling(prinbee::attachment_copy_handling_t::ATTACHMENT_COPY_HANDLING_REFLINK));
     514            1 :                 CATCH_REQUIRE(j.get_attachment_copy_handling() == prinbee::attachment_copy_handling_t::ATTACHMENT_COPY_HANDLING_REFLINK);
     515            1 :                 break;
     516              : 
     517            1 :             case ATTACHMENT_COPY_HANDLING_FULL:
     518            1 :                 CATCH_REQUIRE(j.set_attachment_copy_handling(prinbee::attachment_copy_handling_t::ATTACHMENT_COPY_HANDLING_FULL));
     519            1 :                 CATCH_REQUIRE(j.get_attachment_copy_handling() == prinbee::attachment_copy_handling_t::ATTACHMENT_COPY_HANDLING_FULL);
     520            1 :                 break;
     521              : 
     522            0 :             default:
     523            0 :                 CATCH_REQUIRE(!"the test is invalid, add another case as required");
     524            0 :                 break;
     525              : 
     526              :             }
     527              : 
     528              :             // load configuration we just updated
     529              :             //
     530           24 :             conf_values_t conf_values(load_conf(path));
     531              : 
     532           36 :             auto it(conf_values.find("compress_when_full"));
     533           12 :             CATCH_REQUIRE(it != conf_values.end());
     534           12 :             CATCH_REQUIRE((index == COMPRESS_WHEN_FULL ? "true" : "false") == it->second);
     535           12 :             conf_values.erase(it);
     536              : 
     537           36 :             it = conf_values.find("file_management");
     538           12 :             CATCH_REQUIRE(it != conf_values.end());
     539           34 :             CATCH_REQUIRE((index == FILE_MANAGEMENT ? expected_result : "keep") == it->second);
     540           12 :             conf_values.erase(it);
     541              : 
     542           36 :             it = conf_values.find("maximum_events");
     543           12 :             CATCH_REQUIRE(it != conf_values.end());
     544           34 :             CATCH_REQUIRE((index == MAXIMUM_EVENTS ? expected_result : "4096") == it->second);
     545           12 :             conf_values.erase(it);
     546              : 
     547           36 :             it = conf_values.find("maximum_file_size");
     548           12 :             CATCH_REQUIRE(it != conf_values.end());
     549           34 :             CATCH_REQUIRE((index == MAXIMUM_FILE_SIZE ? expected_result : "1048576") == it->second);
     550           12 :             conf_values.erase(it);
     551              : 
     552           36 :             it = conf_values.find("maximum_number_of_files");
     553           12 :             CATCH_REQUIRE(it != conf_values.end());
     554           34 :             CATCH_REQUIRE((index == MAXIMUM_NUMBER_OF_FILES ? expected_result : "2") == it->second);
     555           12 :             conf_values.erase(it);
     556              : 
     557           36 :             it = conf_values.find("sync");
     558           12 :             CATCH_REQUIRE(it != conf_values.end());
     559           12 :             switch(index)
     560              :             {
     561            1 :             case FLUSH:
     562            1 :                 CATCH_REQUIRE("flush" == it->second);
     563            1 :                 break;
     564              : 
     565            1 :             case SYNC:
     566            1 :                 CATCH_REQUIRE("full" == it->second);
     567            1 :                 break;
     568              : 
     569           10 :             default:
     570           10 :                 CATCH_REQUIRE("none" == it->second);
     571           10 :                 break;
     572              : 
     573              :             }
     574           12 :             conf_values.erase(it);
     575              : 
     576           36 :             it = conf_values.find("inline_attachment_size_threshold");
     577           12 :             CATCH_REQUIRE(it != conf_values.end());
     578           12 :             CATCH_REQUIRE((index == INLINE_ATTACHMENT_SIZE_THRESHOLD
     579              :                                         ? expected_result
     580              :                                         : std::to_string(prinbee::JOURNAL_INLINE_ATTACHMENT_SIZE_DEFAULT_THRESHOLD)) == it->second);
     581           12 :             conf_values.erase(it);
     582              : 
     583           36 :             it = conf_values.find("attachment_copy_handling");
     584           12 :             CATCH_REQUIRE(it != conf_values.end());
     585           12 :             switch(index)
     586              :             {
     587            1 :             case ATTACHMENT_COPY_HANDLING_HARDLINK:
     588            1 :                 CATCH_REQUIRE("hardlink" == it->second);
     589            1 :                 break;
     590              : 
     591            1 :             case ATTACHMENT_COPY_HANDLING_REFLINK:
     592            1 :                 CATCH_REQUIRE("reflink" == it->second);
     593            1 :                 break;
     594              : 
     595            1 :             case ATTACHMENT_COPY_HANDLING_FULL:
     596            1 :                 CATCH_REQUIRE("full" == it->second);
     597            1 :                 break;
     598              : 
     599              :             // the default is "softlink"
     600            9 :             case ATTACHMENT_COPY_HANDLING_SOFTLINK:
     601              :             default:
     602            9 :                 CATCH_REQUIRE("softlink" == it->second);
     603            9 :                 break;
     604              : 
     605              :             }
     606           12 :             conf_values.erase(it);
     607              : 
     608           12 :             CATCH_REQUIRE(conf_values.empty());
     609           12 :         }
     610              :     }
     611           17 :     CATCH_END_SECTION()
     612              : 
     613           18 :     CATCH_START_SECTION("journal_options: reducing the number of files generates a TODO")
     614              :     {
     615            3 :         std::string const path(conf_path("journal_options"));
     616            1 :         advgetopt::conf_file::reset_conf_files();
     617            1 :         prinbee::journal j(path);
     618            1 :         CATCH_REQUIRE(j.is_valid());
     619            1 :         CATCH_REQUIRE(j.set_maximum_file_size(10));
     620            1 :         CATCH_REQUIRE(j.set_maximum_file_size(5));  // <- here (TODO: add logger output capture to verify what happens)
     621            1 :     }
     622           17 :     CATCH_END_SECTION()
     623              : 
     624           18 :     CATCH_START_SECTION("journal_options: invalid file management numbers")
     625              :     {
     626            3 :         std::string const path(conf_path("journal_options"));
     627            1 :         advgetopt::conf_file::reset_conf_files();
     628            1 :         prinbee::journal j(path);
     629            1 :         CATCH_REQUIRE(j.is_valid());
     630              : 
     631          257 :         for(int i(0); i < 256; ++i)
     632              :         {
     633          256 :             switch(static_cast<prinbee::file_management_t>(i))
     634              :             {
     635            3 :             case prinbee::file_management_t::FILE_MANAGEMENT_KEEP:
     636              :             case prinbee::file_management_t::FILE_MANAGEMENT_TRUNCATE:
     637              :             case prinbee::file_management_t::FILE_MANAGEMENT_DELETE:
     638              :                 // these are valid, ignore
     639            3 :                 break;
     640              : 
     641          253 :             default:
     642          759 :                 CATCH_REQUIRE_THROWS_MATCHES(
     643              :                           j.set_file_management(static_cast<prinbee::file_management_t>(i))
     644              :                         , prinbee::invalid_parameter
     645              :                         , Catch::Matchers::ExceptionMessage(
     646              :                                   "prinbee_exception: unsupported file management number"));
     647              :                 break;
     648              : 
     649              :             }
     650              :         }
     651            1 :     }
     652           17 :     CATCH_END_SECTION()
     653              : 
     654           18 :     CATCH_START_SECTION("journal_options: invalid attachment copy handling numbers")
     655              :     {
     656            3 :         std::string const path(conf_path("journal_options"));
     657            1 :         advgetopt::conf_file::reset_conf_files();
     658            1 :         prinbee::journal j(path);
     659            1 :         CATCH_REQUIRE(j.is_valid());
     660              : 
     661          257 :         for(int i(0); i < 256; ++i)
     662              :         {
     663          256 :             switch(static_cast<prinbee::attachment_copy_handling_t>(i))
     664              :             {
     665            5 :             case prinbee::attachment_copy_handling_t::ATTACHMENT_COPY_HANDLING_DEFAULT:
     666              :             case prinbee::attachment_copy_handling_t::ATTACHMENT_COPY_HANDLING_SOFTLINK:
     667              :             case prinbee::attachment_copy_handling_t::ATTACHMENT_COPY_HANDLING_HARDLINK:
     668              :             case prinbee::attachment_copy_handling_t::ATTACHMENT_COPY_HANDLING_REFLINK:
     669              :             case prinbee::attachment_copy_handling_t::ATTACHMENT_COPY_HANDLING_FULL:
     670              :                 // these are valid, ignore
     671            5 :                 break;
     672              : 
     673          251 :             default:
     674              :                 {
     675          251 :                     std::stringstream ss;
     676          251 :                     ss << "prinbee_exception: unknown attachment_copy_handling_t enumeration type ("
     677              :                        << i
     678          251 :                        << ").";
     679          251 :                     CATCH_REQUIRE_THROWS_MATCHES(
     680              :                               j.set_attachment_copy_handling(static_cast<prinbee::attachment_copy_handling_t>(i))
     681              :                             , prinbee::invalid_parameter
     682              :                             , Catch::Matchers::ExceptionMessage(ss.str()));
     683          251 :                 }
     684              :                 break;
     685              : 
     686              :             }
     687              :         }
     688            1 :     }
     689           17 :     CATCH_END_SECTION()
     690              : 
     691           18 :     CATCH_START_SECTION("journal_options: minimum number of events")
     692              :     {
     693          102 :         for(std::uint32_t count(0); count <= prinbee::JOURNAL_MINIMUM_EVENTS; ++count)
     694              :         {
     695          303 :             std::string const path(conf_path("journal_options"));
     696          101 :             advgetopt::conf_file::reset_conf_files();
     697          101 :             prinbee::journal j(path);
     698          101 :             CATCH_REQUIRE(j.is_valid());
     699          101 :             CATCH_REQUIRE(j.set_maximum_events(count));
     700          101 :             conf_values_t conf_values(load_conf(path));
     701              : 
     702          303 :             auto const it(conf_values.find("maximum_events"));
     703          101 :             CATCH_REQUIRE(it != conf_values.end());
     704          101 :             CATCH_REQUIRE(std::to_string(prinbee::JOURNAL_MINIMUM_EVENTS) == it->second);
     705          101 :         }
     706              :     }
     707           17 :     CATCH_END_SECTION()
     708              : 
     709           18 :     CATCH_START_SECTION("journal_options: maximum number of events")
     710              :     {
     711          732 :         for(std::uint32_t count(prinbee::JOURNAL_MAXIMUM_EVENTS); count <= 1'000'000; count += rand() % 2'500 + 1)
     712              :         {
     713         2193 :             std::string const path(conf_path("journal_options"));
     714          731 :             advgetopt::conf_file::reset_conf_files();
     715          731 :             prinbee::journal j(path);
     716          731 :             CATCH_REQUIRE(j.is_valid());
     717          731 :             CATCH_REQUIRE(j.set_maximum_events(count));
     718          731 :             conf_values_t conf_values(load_conf(path));
     719              : 
     720         2193 :             auto const it(conf_values.find("maximum_events"));
     721          731 :             CATCH_REQUIRE(it != conf_values.end());
     722          731 :             CATCH_REQUIRE(std::to_string(prinbee::JOURNAL_MAXIMUM_EVENTS) == it->second);
     723          731 :         }
     724              :     }
     725           17 :     CATCH_END_SECTION()
     726              : 
     727           18 :     CATCH_START_SECTION("journal_options: minimum file size")
     728              :     {
     729        65538 :         for(std::uint32_t size(0); size <= prinbee::JOURNAL_MINIMUM_FILE_SIZE; ++size)
     730              :         {
     731       196611 :             std::string const path(conf_path("journal_options"));
     732        65537 :             advgetopt::conf_file::reset_conf_files();
     733        65537 :             prinbee::journal j(path);
     734        65537 :             CATCH_REQUIRE(j.is_valid());
     735        65537 :             CATCH_REQUIRE(j.set_maximum_file_size(size));
     736        65537 :             conf_values_t conf_values(load_conf(path));
     737              : 
     738       196611 :             auto const it(conf_values.find("maximum_file_size"));
     739        65537 :             CATCH_REQUIRE(it != conf_values.end());
     740        65537 :             CATCH_REQUIRE(std::to_string(prinbee::JOURNAL_MINIMUM_FILE_SIZE) == it->second);
     741        65537 :         }
     742              :     }
     743           17 :     CATCH_END_SECTION()
     744              : 
     745           18 :     CATCH_START_SECTION("journal_options: maximum file size")
     746              :     {
     747        45023 :         for(std::uint32_t size(prinbee::JOURNAL_MAXIMUM_FILE_SIZE); size <= 0x6000'0000; size += rand() % 65536 + 1)
     748              :         {
     749       135066 :             std::string const path(conf_path("journal_options"));
     750        45022 :             advgetopt::conf_file::reset_conf_files();
     751        45022 :             prinbee::journal j(path);
     752        45022 :             CATCH_REQUIRE(j.is_valid());
     753        45022 :             CATCH_REQUIRE(j.set_maximum_file_size(size));
     754        45022 :             conf_values_t conf_values(load_conf(path));
     755              : 
     756       135066 :             auto const it(conf_values.find("maximum_file_size"));
     757        45022 :             CATCH_REQUIRE(it != conf_values.end());
     758        45022 :             CATCH_REQUIRE(std::to_string(prinbee::JOURNAL_MAXIMUM_FILE_SIZE) == it->second);
     759        45022 :         }
     760              :     }
     761           17 :     CATCH_END_SECTION()
     762           16 : }
     763              : 
     764              : 
     765            4 : CATCH_TEST_CASE("journal_event_status_sequence", "[journal]")
     766              : {
     767            6 :     CATCH_START_SECTION("journal_event_status_sequence: all valid/invalid sequences")
     768              :     {
     769            1 :         std::vector<prinbee::status_t> next_status[]
     770              :         {
     771              :             // ready -> ... -> completed
     772              :             {
     773              :                 prinbee::status_t::STATUS_FORWARDED,
     774              :                 prinbee::status_t::STATUS_ACKNOWLEDGED,
     775              :                 prinbee::status_t::STATUS_COMPLETED,
     776              :             },
     777              :             {
     778              :                 prinbee::status_t::STATUS_ACKNOWLEDGED,
     779              :                 prinbee::status_t::STATUS_COMPLETED,
     780              :             },
     781              :             {
     782              :                 prinbee::status_t::STATUS_FORWARDED,
     783              :                 prinbee::status_t::STATUS_COMPLETED,
     784              :             },
     785              :             {
     786              :                 prinbee::status_t::STATUS_COMPLETED,
     787              :             },
     788              : 
     789              :             // ready -> ... -> fails
     790              :             {
     791              :                 prinbee::status_t::STATUS_FORWARDED,
     792              :                 prinbee::status_t::STATUS_ACKNOWLEDGED,
     793              :                 prinbee::status_t::STATUS_FAILED,
     794              :             },
     795              :             {
     796              :                 prinbee::status_t::STATUS_ACKNOWLEDGED,
     797              :                 prinbee::status_t::STATUS_FAILED,
     798              :             },
     799              :             {
     800              :                 prinbee::status_t::STATUS_FORWARDED,
     801              :                 prinbee::status_t::STATUS_FAILED,
     802              :             },
     803              :             {
     804              :                 prinbee::status_t::STATUS_FAILED,
     805              :             },
     806              : 
     807              :             // impossible
     808              :             {
     809              :                 prinbee::status_t::STATUS_FORWARDED,
     810              :                 prinbee::status_t::STATUS_UNKNOWN,
     811              :                 prinbee::status_t::STATUS_FORWARDED,
     812              :             },
     813              :             {
     814              :                 prinbee::status_t::STATUS_FORWARDED,
     815              :                 prinbee::status_t::STATUS_ACKNOWLEDGED,
     816              :                 prinbee::status_t::STATUS_UNKNOWN,
     817              :                 prinbee::status_t::STATUS_FORWARDED,
     818              :             },
     819              :             {
     820              :                 prinbee::status_t::STATUS_FORWARDED,
     821              :                 prinbee::status_t::STATUS_ACKNOWLEDGED,
     822              :                 prinbee::status_t::STATUS_UNKNOWN,
     823              :                 prinbee::status_t::STATUS_ACKNOWLEDGED,
     824              :             },
     825              :             {
     826              :                 prinbee::status_t::STATUS_ACKNOWLEDGED,
     827              :                 prinbee::status_t::STATUS_UNKNOWN,
     828              :                 prinbee::status_t::STATUS_FORWARDED,
     829              :             },
     830              :             {
     831              :                 prinbee::status_t::STATUS_ACKNOWLEDGED,
     832              :                 prinbee::status_t::STATUS_UNKNOWN,
     833              :                 prinbee::status_t::STATUS_ACKNOWLEDGED,
     834              :             },
     835              :             {
     836              :                 prinbee::status_t::STATUS_FORWARDED,
     837              :                 prinbee::status_t::STATUS_ACKNOWLEDGED,
     838              :                 prinbee::status_t::STATUS_COMPLETED,
     839              :                 prinbee::status_t::STATUS_UNKNOWN,
     840              :                 prinbee::status_t::STATUS_FORWARDED,
     841              :             },
     842              :             {
     843              :                 prinbee::status_t::STATUS_FORWARDED,
     844              :                 prinbee::status_t::STATUS_ACKNOWLEDGED,
     845              :                 prinbee::status_t::STATUS_COMPLETED,
     846              :                 prinbee::status_t::STATUS_UNKNOWN,
     847              :                 prinbee::status_t::STATUS_ACKNOWLEDGED,
     848              :             },
     849              :             {
     850              :                 prinbee::status_t::STATUS_FORWARDED,
     851              :                 prinbee::status_t::STATUS_ACKNOWLEDGED,
     852              :                 prinbee::status_t::STATUS_COMPLETED,
     853              :                 prinbee::status_t::STATUS_UNKNOWN,
     854              :                 prinbee::status_t::STATUS_COMPLETED,
     855              :             },
     856              :             {
     857              :                 prinbee::status_t::STATUS_ACKNOWLEDGED,
     858              :                 prinbee::status_t::STATUS_COMPLETED,
     859              :                 prinbee::status_t::STATUS_UNKNOWN,
     860              :                 prinbee::status_t::STATUS_FORWARDED,
     861              :             },
     862              :             {
     863              :                 prinbee::status_t::STATUS_ACKNOWLEDGED,
     864              :                 prinbee::status_t::STATUS_COMPLETED,
     865              :                 prinbee::status_t::STATUS_UNKNOWN,
     866              :                 prinbee::status_t::STATUS_ACKNOWLEDGED,
     867              :             },
     868              :             {
     869              :                 prinbee::status_t::STATUS_ACKNOWLEDGED,
     870              :                 prinbee::status_t::STATUS_COMPLETED,
     871              :                 prinbee::status_t::STATUS_UNKNOWN,
     872              :                 prinbee::status_t::STATUS_COMPLETED,
     873              :             },
     874              :             {
     875              :                 prinbee::status_t::STATUS_COMPLETED,
     876              :                 prinbee::status_t::STATUS_UNKNOWN,
     877              :                 prinbee::status_t::STATUS_FORWARDED,
     878              :             },
     879              :             {
     880              :                 prinbee::status_t::STATUS_COMPLETED,
     881              :                 prinbee::status_t::STATUS_UNKNOWN,
     882              :                 prinbee::status_t::STATUS_ACKNOWLEDGED,
     883              :             },
     884              :             {
     885              :                 prinbee::status_t::STATUS_COMPLETED,
     886              :                 prinbee::status_t::STATUS_UNKNOWN,
     887              :                 prinbee::status_t::STATUS_COMPLETED,
     888              :             },
     889              :             {
     890              :                 prinbee::status_t::STATUS_FORWARDED,
     891              :                 prinbee::status_t::STATUS_ACKNOWLEDGED,
     892              :                 prinbee::status_t::STATUS_FAILED,
     893              :                 prinbee::status_t::STATUS_UNKNOWN,
     894              :                 prinbee::status_t::STATUS_FORWARDED,
     895              :             },
     896              :             {
     897              :                 prinbee::status_t::STATUS_FORWARDED,
     898              :                 prinbee::status_t::STATUS_ACKNOWLEDGED,
     899              :                 prinbee::status_t::STATUS_FAILED,
     900              :                 prinbee::status_t::STATUS_UNKNOWN,
     901              :                 prinbee::status_t::STATUS_ACKNOWLEDGED,
     902              :             },
     903              :             {
     904              :                 prinbee::status_t::STATUS_FORWARDED,
     905              :                 prinbee::status_t::STATUS_ACKNOWLEDGED,
     906              :                 prinbee::status_t::STATUS_FAILED,
     907              :                 prinbee::status_t::STATUS_UNKNOWN,
     908              :                 prinbee::status_t::STATUS_FAILED,
     909              :             },
     910              :             {
     911              :                 prinbee::status_t::STATUS_ACKNOWLEDGED,
     912              :                 prinbee::status_t::STATUS_FAILED,
     913              :                 prinbee::status_t::STATUS_UNKNOWN,
     914              :                 prinbee::status_t::STATUS_FORWARDED,
     915              :             },
     916              :             {
     917              :                 prinbee::status_t::STATUS_ACKNOWLEDGED,
     918              :                 prinbee::status_t::STATUS_FAILED,
     919              :                 prinbee::status_t::STATUS_UNKNOWN,
     920              :                 prinbee::status_t::STATUS_ACKNOWLEDGED,
     921              :             },
     922              :             {
     923              :                 prinbee::status_t::STATUS_ACKNOWLEDGED,
     924              :                 prinbee::status_t::STATUS_FAILED,
     925              :                 prinbee::status_t::STATUS_UNKNOWN,
     926              :                 prinbee::status_t::STATUS_FAILED,
     927              :             },
     928              :             {
     929              :                 prinbee::status_t::STATUS_FAILED,
     930              :                 prinbee::status_t::STATUS_UNKNOWN,
     931              :                 prinbee::status_t::STATUS_FORWARDED,
     932              :             },
     933              :             {
     934              :                 prinbee::status_t::STATUS_FAILED,
     935              :                 prinbee::status_t::STATUS_UNKNOWN,
     936              :                 prinbee::status_t::STATUS_ACKNOWLEDGED,
     937              :             },
     938              :             {
     939              :                 prinbee::status_t::STATUS_FAILED,
     940              :                 prinbee::status_t::STATUS_UNKNOWN,
     941              :                 prinbee::status_t::STATUS_FAILED,
     942              :             },
     943              :             {
     944              :                 prinbee::status_t::STATUS_FORWARDED,
     945              :                 prinbee::status_t::STATUS_ACKNOWLEDGED,
     946              :                 prinbee::status_t::STATUS_FAILED,
     947              :                 prinbee::status_t::STATUS_UNKNOWN,
     948              :                 prinbee::status_t::STATUS_COMPLETED,
     949              :             },
     950              :             {
     951              :                 prinbee::status_t::STATUS_ACKNOWLEDGED,
     952              :                 prinbee::status_t::STATUS_FAILED,
     953              :                 prinbee::status_t::STATUS_UNKNOWN,
     954              :                 prinbee::status_t::STATUS_COMPLETED,
     955              :             },
     956              :             {
     957              :                 prinbee::status_t::STATUS_FAILED,
     958              :                 prinbee::status_t::STATUS_UNKNOWN,
     959              :                 prinbee::status_t::STATUS_COMPLETED,
     960              :             },
     961              :             {
     962              :                 prinbee::status_t::STATUS_FORWARDED,
     963              :                 prinbee::status_t::STATUS_ACKNOWLEDGED,
     964              :                 prinbee::status_t::STATUS_COMPLETED,
     965              :                 prinbee::status_t::STATUS_UNKNOWN,
     966              :                 prinbee::status_t::STATUS_FAILED,
     967              :             },
     968              :             {
     969              :                 prinbee::status_t::STATUS_ACKNOWLEDGED,
     970              :                 prinbee::status_t::STATUS_COMPLETED,
     971              :                 prinbee::status_t::STATUS_UNKNOWN,
     972              :                 prinbee::status_t::STATUS_FAILED,
     973              :             },
     974              :             {
     975              :                 prinbee::status_t::STATUS_COMPLETED,
     976              :                 prinbee::status_t::STATUS_UNKNOWN,
     977              :                 prinbee::status_t::STATUS_FAILED,
     978              :             },
     979           41 :         };
     980            1 :         int count(0);
     981           38 :         for(auto const & sequence : next_status)
     982              :         {
     983          111 :             std::string const path(conf_path("journal_events"));
     984           37 :             advgetopt::conf_file::reset_conf_files();
     985           37 :             prinbee::journal j(path);
     986           37 :             CATCH_REQUIRE(j.is_valid());
     987              : 
     988           37 :             ++count;
     989           37 :             std::cerr << "--- running sequence #" << count << "\n";
     990           37 :             std::size_t const size(rand() % 10 * 1024 + 1);
     991          111 :             std::vector<std::uint8_t> data(size);
     992       211018 :             for(std::size_t idx(0); idx < size; ++idx)
     993              :             {
     994       210981 :                 data[idx] = static_cast<std::uint8_t>(rand());
     995              :             }
     996           37 :             std::string const request_id(SNAP_CATCH2_NAMESPACE::random_string(1, 255));
     997           37 :             prinbee::in_event event;
     998           37 :             event.set_request_id(request_id);
     999              :             {
    1000           37 :                 prinbee::attachment a;
    1001           37 :                 a.set_data(data.data(), data.size());
    1002           37 :                 event.add_attachment(a);
    1003           37 :             }
    1004           37 :             snapdev::timespec_ex const event_time(snapdev::now());
    1005           37 :             snapdev::timespec_ex pass_time(event_time);
    1006           37 :             CATCH_REQUIRE(j.add_event(event, pass_time));
    1007           37 :             CATCH_REQUIRE(event_time == pass_time);
    1008              : 
    1009              :             // the only way to verify that the event was sent to the journal
    1010              :             // properly is to read it back using the next_event() function, but
    1011              :             // since we just added a first even, the next_event() won't find
    1012              :             // it (i.e. that iterator is already pointing to end()), so we'll
    1013              :             // need a rewind() call first
    1014              :             //
    1015           37 :             prinbee::out_event out_event;
    1016           37 :             CATCH_REQUIRE_FALSE(j.next_event(out_event));
    1017              : 
    1018           37 :             j.rewind();
    1019           37 :             CATCH_REQUIRE(j.next_event(out_event, true, true));
    1020              : 
    1021           37 :             std::string const filename(path + "/journal-0.events");
    1022           37 :             CATCH_REQUIRE(filename == out_event.get_debug_filename());
    1023           37 :             CATCH_REQUIRE(8U == out_event.get_debug_offset());
    1024              : 
    1025           37 :             CATCH_REQUIRE(request_id == out_event.get_request_id());
    1026           37 :             CATCH_REQUIRE(prinbee::status_t::STATUS_READY == out_event.get_status());
    1027           37 :             CATCH_REQUIRE(event_time == out_event.get_event_time());
    1028              : 
    1029              :             {
    1030           37 :                 CATCH_REQUIRE(out_event.get_attachment_size() == 1);
    1031           37 :                 prinbee::attachment a(out_event.get_attachment(0));
    1032           37 :                 CATCH_REQUIRE(size == static_cast<std::size_t>(a.size()));
    1033          185 :                 CATCH_REQUIRE_LONG_STRING(std::string(reinterpret_cast<char const *>(data.data()), data.size())
    1034              :                                         , std::string(reinterpret_cast<char const *>(a.data()), a.size()));
    1035           37 :             }
    1036              : 
    1037           37 :             CATCH_REQUIRE_FALSE(j.next_event(out_event));
    1038              : 
    1039          111 :             CATCH_REQUIRE_FALSE(j.event_forwarded("inexistant"));
    1040          111 :             CATCH_REQUIRE_FALSE(j.event_acknowledged("inexistant"));
    1041          111 :             CATCH_REQUIRE_FALSE(j.event_completed("inexistant"));
    1042          111 :             CATCH_REQUIRE_FALSE(j.event_failed("inexistant"));
    1043              : 
    1044              :             // Process sequence
    1045              :             //
    1046           37 :             bool expect_success(true);
    1047           37 :             bool gone(false);
    1048           37 :             prinbee::status_t last_success(prinbee::status_t::STATUS_UNKNOWN);
    1049          166 :             for(auto const & status : sequence)
    1050              :             {
    1051          129 :                 switch(status)
    1052              :                 {
    1053           29 :                 case prinbee::status_t::STATUS_UNKNOWN:
    1054           29 :                     expect_success = false;
    1055           29 :                     continue;
    1056              : 
    1057            0 :                 case prinbee::status_t::STATUS_READY:
    1058            0 :                     CATCH_REQUIRE(status != prinbee::status_t::STATUS_READY);
    1059            0 :                     break;
    1060              : 
    1061           24 :                 case prinbee::status_t::STATUS_FORWARDED:
    1062           24 :                     CATCH_REQUIRE(j.event_forwarded(request_id) == expect_success);
    1063           24 :                     break;
    1064              : 
    1065           32 :                 case prinbee::status_t::STATUS_ACKNOWLEDGED:
    1066           32 :                     CATCH_REQUIRE(j.event_acknowledged(request_id) == expect_success);
    1067           32 :                     break;
    1068              : 
    1069           22 :                 case prinbee::status_t::STATUS_COMPLETED:
    1070           22 :                     CATCH_REQUIRE(j.event_completed(request_id) == expect_success);
    1071           22 :                     gone = true;
    1072           22 :                     break;
    1073              : 
    1074           22 :                 case prinbee::status_t::STATUS_FAILED:
    1075           22 :                     CATCH_REQUIRE(j.event_failed(request_id) == expect_success);
    1076           22 :                     gone = true;
    1077           22 :                     break;
    1078              : 
    1079           29 :                 }
    1080          100 :                 CATCH_REQUIRE_FALSE(j.next_event(out_event));
    1081          100 :                 j.rewind();
    1082          100 :                 if(gone)
    1083              :                 {
    1084              :                     // if gone, a second attempt still fails
    1085              :                     //
    1086           56 :                     CATCH_REQUIRE_FALSE(j.next_event(out_event));
    1087              :                 }
    1088              :                 else
    1089              :                 {
    1090              :                     // not gone yet, all the data is still accessible
    1091              :                     //
    1092           44 :                     prinbee::out_event out_event2;
    1093           44 :                     CATCH_REQUIRE(j.next_event(out_event2));
    1094              : 
    1095              :                     // at the moment the debug does not get cleared, so we
    1096              :                     // used a separate structure to verify that by default
    1097              :                     // the debug data remains untouched
    1098              :                     //
    1099           44 :                     CATCH_REQUIRE("" == out_event2.get_debug_filename());
    1100           44 :                     CATCH_REQUIRE(0 == out_event2.get_debug_offset());
    1101              : 
    1102           44 :                     CATCH_REQUIRE(request_id == out_event2.get_request_id());
    1103              : 
    1104              :                     {
    1105           44 :                         CATCH_REQUIRE(out_event2.get_attachment_size() == 1);
    1106           44 :                         prinbee::attachment a(out_event2.get_attachment(0));
    1107           44 :                         CATCH_REQUIRE(size == static_cast<std::size_t>(a.size()));
    1108          220 :                         CATCH_REQUIRE_LONG_STRING(std::string(reinterpret_cast<char const *>(data.data()), data.size())
    1109              :                                                 , std::string(reinterpret_cast<char const *>(a.data()), a.size()));
    1110           44 :                     }
    1111              : 
    1112           44 :                     if(expect_success)
    1113              :                     {
    1114           39 :                         CATCH_REQUIRE(status == out_event2.get_status());
    1115           39 :                         last_success = out_event2.get_status();
    1116              :                     }
    1117              :                     else
    1118              :                     {
    1119              :                         // on error, it does not change
    1120              :                         //
    1121            5 :                         CATCH_REQUIRE(last_success == out_event2.get_status());
    1122              :                     }
    1123           44 :                     CATCH_REQUIRE(event_time == out_event2.get_event_time());
    1124           44 :                 }
    1125              : 
    1126          100 :                 CATCH_REQUIRE_FALSE(j.next_event(out_event));
    1127              :             }
    1128           37 :         }
    1129           38 :     }
    1130            5 :     CATCH_END_SECTION()
    1131              : 
    1132            6 :     CATCH_START_SECTION("journal_event_status_sequence: verify the delete functionality when empty")
    1133              :     {
    1134            1 :         std::random_device rd;
    1135            1 :         std::mt19937 g(rd());
    1136              : 
    1137            3 :         std::string const path(conf_path("journal_delete"));
    1138              : 
    1139            4 :         for(int sync(0); sync < 3; ++sync)
    1140              :         {
    1141              :             {
    1142            3 :                 advgetopt::conf_file::reset_conf_files();
    1143            3 :                 prinbee::journal j(path);
    1144            3 :                 CATCH_REQUIRE(j.set_file_management(prinbee::file_management_t::FILE_MANAGEMENT_DELETE));
    1145            3 :                 CATCH_REQUIRE(j.set_maximum_events(5));
    1146            3 :                 CATCH_REQUIRE(j.set_sync(static_cast<prinbee::sync_t>(sync)));
    1147            3 :                 CATCH_REQUIRE(j.is_valid());
    1148              : 
    1149            3 :                 std::vector<int> ids;
    1150           33 :                 for(int id(1); id <= 10; ++id)
    1151              :                 {
    1152           30 :                     std::size_t const size(rand() % 1024 + 1);
    1153           90 :                     std::vector<std::uint8_t> data(size);
    1154        14655 :                     for(std::size_t idx(0); idx < size; ++idx)
    1155              :                     {
    1156        14625 :                         data[idx] = rand();
    1157              :                     }
    1158           30 :                     prinbee::in_event event;
    1159           30 :                     event.set_request_id(prinbee::id_to_string(id));
    1160              :                     {
    1161           30 :                         prinbee::attachment a;
    1162           30 :                         a.set_data(data.data(), size);
    1163           30 :                         event.add_attachment(a);
    1164           30 :                     }
    1165              : 
    1166           30 :                     snapdev::timespec_ex const event_time(snapdev::now());
    1167           30 :                     snapdev::timespec_ex pass_time(event_time);
    1168           30 :                     CATCH_REQUIRE(j.add_event(event, pass_time));
    1169           30 :                     CATCH_REQUIRE(event_time == pass_time);
    1170              : 
    1171           30 :                     ids.push_back(id);
    1172           30 :                 }
    1173              : 
    1174           12 :                 for(int status(0); status < 3; ++status)
    1175              :                 {
    1176            9 :                     std::shuffle(ids.begin(), ids.end(), g);
    1177              : 
    1178           99 :                     for(auto const & id : ids)
    1179              :                     {
    1180           90 :                         switch(status)
    1181              :                         {
    1182           30 :                         case 0:
    1183           30 :                             CATCH_REQUIRE(j.event_forwarded(prinbee::id_to_string(id)));
    1184           30 :                             break;
    1185              : 
    1186           30 :                         case 1:
    1187           30 :                             CATCH_REQUIRE(j.event_acknowledged(prinbee::id_to_string(id)));
    1188           30 :                             break;
    1189              : 
    1190           30 :                         case 2:
    1191           30 :                             CATCH_REQUIRE(j.event_completed(prinbee::id_to_string(id)));
    1192           30 :                             break;
    1193              : 
    1194            0 :                         default:
    1195            0 :                             CATCH_REQUIRE(!"unknown status");
    1196              : 
    1197              :                         }
    1198              :                     }
    1199              :                 }
    1200            3 :             }
    1201              : 
    1202              :             // make sure the DELETE happened
    1203              :             //
    1204           12 :             for(int idx(0); idx < 3; ++idx)
    1205              :             {
    1206            9 :                 std::string const filename(event_filename(path, idx));
    1207            9 :                 CATCH_REQUIRE(access(filename.c_str(), R_OK) != 0);
    1208            9 :             }
    1209              : 
    1210              :             // just re-opening does not re-create files
    1211              :             {
    1212            3 :                 prinbee::journal j(path);
    1213            3 :                 CATCH_REQUIRE(j.empty());
    1214            3 :             }
    1215              : 
    1216              :             // make sure the files were not re-created
    1217              :             //
    1218           12 :             for(int idx(0); idx < 3; ++idx)
    1219              :             {
    1220            9 :                 std::string const filename(event_filename(path, idx));
    1221            9 :                 CATCH_REQUIRE(access(filename.c_str(), R_OK) != 0);
    1222            9 :             }
    1223              :         }
    1224            1 :     }
    1225            5 :     CATCH_END_SECTION()
    1226              : 
    1227            6 :     CATCH_START_SECTION("journal_event_status_sequence: verify the delete functionality when not empty")
    1228              :     {
    1229            1 :         std::random_device rd;
    1230            1 :         std::mt19937 g(rd());
    1231              : 
    1232            4 :         for(int sync(0); sync < 3; ++sync)
    1233              :         {
    1234            3 :             std::string const name("journal_truncate_delete-" + std::to_string(sync));
    1235            3 :             std::string const path(conf_path(name));
    1236              : 
    1237              :             {
    1238            3 :                 advgetopt::conf_file::reset_conf_files();
    1239            3 :                 prinbee::journal j(path);
    1240            3 :                 CATCH_REQUIRE(j.set_file_management(prinbee::file_management_t::FILE_MANAGEMENT_DELETE));
    1241            3 :                 CATCH_REQUIRE(j.set_maximum_events(5));
    1242            3 :                 CATCH_REQUIRE(j.set_sync(static_cast<prinbee::sync_t>(sync)));
    1243            3 :                 CATCH_REQUIRE(j.is_valid());
    1244              : 
    1245            3 :                 std::vector<int> ids;
    1246           33 :                 for(int id(1); id <= 10; ++id)
    1247              :                 {
    1248           30 :                     std::size_t const size(rand() % 1024 + 1);
    1249           90 :                     std::vector<std::uint8_t> data(size);
    1250        13957 :                     for(std::size_t idx(0); idx < size; ++idx)
    1251              :                     {
    1252        13927 :                         data[idx] = rand();
    1253              :                     }
    1254           30 :                     prinbee::in_event event;
    1255           30 :                     event.set_request_id(prinbee::id_to_string(id));
    1256              :                     {
    1257           30 :                         prinbee::attachment a;
    1258           30 :                         a.set_data(data.data(), size);
    1259           30 :                         event.add_attachment(a);
    1260           30 :                     }
    1261           30 :                     snapdev::timespec_ex const event_time(snapdev::now());
    1262           30 :                     snapdev::timespec_ex pass_time(event_time);
    1263           30 :                     CATCH_REQUIRE(j.add_event(event, pass_time));
    1264           30 :                     CATCH_REQUIRE(event_time == pass_time);
    1265              : 
    1266           30 :                     if(rand() % 2 != 0)
    1267              :                     {
    1268           13 :                         ids.push_back(id);
    1269              :                     }
    1270           30 :                 }
    1271            3 :                 if(ids.size() == 10)
    1272              :                 {
    1273              :                     // make sure at least one entry is out
    1274              :                     //
    1275            0 :                     ids.erase(ids.begin() + rand() % 10);
    1276              :                 }
    1277              : 
    1278           12 :                 for(int status(0); status < 3; ++status)
    1279              :                 {
    1280            9 :                     std::shuffle(ids.begin(), ids.end(), g);
    1281              : 
    1282           48 :                     for(auto const & id : ids)
    1283              :                     {
    1284           39 :                         switch(status)
    1285              :                         {
    1286           13 :                         case 0:
    1287           13 :                             CATCH_REQUIRE(j.event_forwarded(prinbee::id_to_string(id)));
    1288           13 :                             break;
    1289              : 
    1290           13 :                         case 1:
    1291           13 :                             CATCH_REQUIRE(j.event_acknowledged(prinbee::id_to_string(id)));
    1292           13 :                             break;
    1293              : 
    1294           13 :                         case 2:
    1295           13 :                             CATCH_REQUIRE(j.event_completed(prinbee::id_to_string(id)));
    1296           13 :                             break;
    1297              : 
    1298            0 :                         default:
    1299            0 :                             CATCH_REQUIRE(!"unknown status");
    1300              : 
    1301              :                         }
    1302              :                     }
    1303              :                 }
    1304            3 :             }
    1305              : 
    1306              :             {
    1307              :                 // make sure the DELETE does not happen when not empty
    1308              :                 //
    1309            6 :                 for(int idx(0); idx < 3; ++idx)
    1310              :                 {
    1311            6 :                     std::string const filename(event_filename(path, idx));
    1312              :                     //CATCH_REQUIRE(access(filename.c_str(), R_OK) != 0);
    1313              : 
    1314            6 :                     struct stat s = {};
    1315            6 :                     if(stat(filename.c_str(), &s) == 0)
    1316              :                     {
    1317              :                           // main header is 8 bytes (See event_journal_header_t)
    1318              :                           //
    1319            3 :                           CATCH_REQUIRE(s.st_size > 8);
    1320              :                     }
    1321              :                     else
    1322              :                     {
    1323              :                         // we (probably) reached the last file
    1324              :                         //
    1325            3 :                         int const e(errno);
    1326            3 :                         CATCH_REQUIRE(e == ENOENT);
    1327              : 
    1328              :                         // we at least needed 1 file to save the few entries
    1329              :                         // created above, so idx should never be zero if it
    1330              :                         // worked as expected
    1331              :                         //
    1332            3 :                         CATCH_REQUIRE(idx > 0);
    1333            3 :                         break;
    1334              :                     }
    1335            6 :                 }
    1336              :             }
    1337            3 :         }
    1338            1 :     }
    1339            5 :     CATCH_END_SECTION()
    1340              : 
    1341            6 :     CATCH_START_SECTION("journal_event_status_sequence: verify the truncate functionality")
    1342              :     {
    1343            1 :         std::random_device rd;
    1344            1 :         std::mt19937 g(rd());
    1345              : 
    1346            3 :         std::string const path(conf_path("journal_truncate"));
    1347              : 
    1348            4 :         for(int sync(0); sync < 3; ++sync)
    1349              :         {
    1350              :             {
    1351            3 :                 advgetopt::conf_file::reset_conf_files();
    1352            3 :                 prinbee::journal j(path);
    1353            3 :                 CATCH_REQUIRE(j.set_file_management(prinbee::file_management_t::FILE_MANAGEMENT_TRUNCATE));
    1354            3 :                 CATCH_REQUIRE(j.set_maximum_events(5));
    1355            3 :                 CATCH_REQUIRE(j.set_sync(static_cast<prinbee::sync_t>(sync)));
    1356            3 :                 CATCH_REQUIRE(j.is_valid());
    1357              : 
    1358            3 :                 std::vector<int> ids;
    1359           33 :                 for(int id(1); id <= 10; ++id)
    1360              :                 {
    1361           30 :                     std::size_t const size(rand() % 1024 + 1);
    1362           90 :                     std::vector<std::uint8_t> data(size);
    1363        16234 :                     for(std::size_t idx(0); idx < size; ++idx)
    1364              :                     {
    1365        16204 :                         data[idx] = rand();
    1366              :                     }
    1367           30 :                     prinbee::in_event event;
    1368           30 :                     event.set_request_id(prinbee::id_to_string(id));
    1369              :                     {
    1370           30 :                         prinbee::attachment a;
    1371           30 :                         a.set_data(data.data(), size);
    1372           30 :                         event.add_attachment(a);
    1373           30 :                     }
    1374           30 :                     snapdev::timespec_ex const event_time(snapdev::now());
    1375           30 :                     snapdev::timespec_ex pass_time(event_time);
    1376           30 :                     CATCH_REQUIRE(j.add_event(event, pass_time));
    1377           30 :                     CATCH_REQUIRE(event_time == pass_time);
    1378              : 
    1379           30 :                     ids.push_back(id);
    1380           30 :                 }
    1381              : 
    1382           12 :                 for(int status(0); status < 3; ++status)
    1383              :                 {
    1384            9 :                     std::shuffle(ids.begin(), ids.end(), g);
    1385              : 
    1386           99 :                     for(auto const & id : ids)
    1387              :                     {
    1388           90 :                         switch(status)
    1389              :                         {
    1390           30 :                         case 0:
    1391           30 :                             CATCH_REQUIRE(j.event_forwarded(prinbee::id_to_string(id)));
    1392           30 :                             break;
    1393              : 
    1394           30 :                         case 1:
    1395           30 :                             CATCH_REQUIRE(j.event_acknowledged(prinbee::id_to_string(id)));
    1396           30 :                             break;
    1397              : 
    1398           30 :                         case 2:
    1399           30 :                             CATCH_REQUIRE(j.event_completed(prinbee::id_to_string(id)));
    1400           30 :                             break;
    1401              : 
    1402            0 :                         default:
    1403            0 :                             CATCH_REQUIRE(!"unknown status");
    1404              : 
    1405              :                         }
    1406              :                     }
    1407              :                 }
    1408            3 :             }
    1409              : 
    1410              :             {
    1411              :                 // make sure the TRUNCATE happened
    1412              :                 //
    1413            6 :                 for(int idx(0); idx < 3; ++idx)
    1414              :                 {
    1415            6 :                     std::string const filename(event_filename(path, idx));
    1416            6 :                     struct stat s = {};
    1417            6 :                     if(stat(filename.c_str(), &s) == 0)
    1418              :                     {
    1419            3 :                         CATCH_REQUIRE(s.st_size == 8);  // main header is 8 bytes (See event_journal_header_t)
    1420              :                     }
    1421              :                     else
    1422              :                     {
    1423              :                         // we (probably) reached the last file
    1424              :                         //
    1425            3 :                         int const e(errno);
    1426            3 :                         CATCH_REQUIRE(e == ENOENT);
    1427              : 
    1428              :                         // we at least needed 1 file to save the few entries
    1429              :                         // created above, so idx should never be zero if it
    1430              :                         // worked as expected
    1431              :                         //
    1432            3 :                         CATCH_REQUIRE(idx > 0);
    1433            3 :                         break;
    1434              :                     }
    1435            6 :                 }
    1436              :             }
    1437              :         }
    1438            1 :     }
    1439            5 :     CATCH_END_SECTION()
    1440            4 : }
    1441              : 
    1442              : 
    1443            2 : CATCH_TEST_CASE("journal_event_list", "[journal]")
    1444              : {
    1445            4 :     CATCH_START_SECTION("journal_event_list: verify the unicity of the timestamp")
    1446              :     {
    1447            1 :         std::random_device rd;
    1448            1 :         std::mt19937 g(rd());
    1449              : 
    1450            3 :         std::string const name("journal_repeated_event_time");
    1451            1 :         std::string const path(conf_path(name));
    1452              : 
    1453            1 :         snapdev::timespec_ex const start_time(snapdev::now());
    1454            1 :         snapdev::timespec_ex event_time(start_time);
    1455            1 :         snapdev::timespec_ex pass_time(event_time);
    1456              : 
    1457              :         // we want the ids to be in a different order than the time
    1458              :         //
    1459            1 :         std::vector<int> ids;
    1460           11 :         for(int id(1); id <= 10; ++id)
    1461              :         {
    1462           10 :             ids.push_back(id);
    1463              :         }
    1464            1 :         std::shuffle(ids.begin(), ids.end(), g);
    1465              : 
    1466            3 :         std::vector<snapdev::timespec_ex> times(ids.size());
    1467              :         {
    1468            1 :             advgetopt::conf_file::reset_conf_files();
    1469            1 :             prinbee::journal j(path);
    1470            1 :             CATCH_REQUIRE(j.set_file_management(prinbee::file_management_t::FILE_MANAGEMENT_DELETE));
    1471            1 :             CATCH_REQUIRE(j.set_maximum_events(5));
    1472            1 :             CATCH_REQUIRE(j.is_valid());
    1473            1 :             CATCH_REQUIRE(j.empty());
    1474              : 
    1475           11 :             for(int r(0); r < 10; ++r)
    1476              :             {
    1477           10 :                 std::size_t const size(rand() % 124 + 1);
    1478           30 :                 std::vector<std::uint8_t> data(size);
    1479          574 :                 for(std::size_t idx(0); idx < size; ++idx)
    1480              :                 {
    1481          564 :                     data[idx] = rand();
    1482              :                 }
    1483           10 :                 prinbee::in_event event;
    1484           10 :                 event.set_request_id(prinbee::id_to_string(ids[r]));
    1485              :                 {
    1486           10 :                     prinbee::attachment a;
    1487           10 :                     a.set_data(data.data(), size);
    1488           10 :                     event.add_attachment(a);
    1489           10 :                 }
    1490           10 :                 CATCH_REQUIRE(j.add_event(event, pass_time));
    1491           10 :                 CATCH_REQUIRE(event_time == pass_time);
    1492           10 :                 CATCH_REQUIRE(j.size() == r + 1ULL);
    1493           10 :                 CATCH_REQUIRE_FALSE(j.empty());
    1494           10 :                 times[ids[r] - 1] = pass_time;
    1495              : 
    1496           10 :                 ++event_time; // next time it will be incremented by one
    1497           10 :             }
    1498            1 :         }
    1499              : 
    1500              :         {
    1501            1 :             prinbee::journal j(path);
    1502            1 :             event_time = start_time;
    1503           11 :             for(int r(0); r < 10; ++r)
    1504              :             {
    1505           10 :                 prinbee::out_event event;
    1506           10 :                 CATCH_REQUIRE(j.next_event(event));
    1507           10 :                 CATCH_REQUIRE(event_time == event.get_event_time());
    1508           10 :                 CATCH_REQUIRE(prinbee::id_to_string(ids[r]) == event.get_request_id());
    1509           10 :                 ++event_time;
    1510           10 :             }
    1511              : 
    1512              :             // make sure we reached the end
    1513              :             //
    1514              :             {
    1515            1 :                 prinbee::out_event event;
    1516            1 :                 CATCH_REQUIRE_FALSE(j.next_event(event));
    1517            1 :             }
    1518            1 :         }
    1519              : 
    1520              :         {
    1521            1 :             prinbee::journal j(path);
    1522           11 :             for(int r(0); r < 10; ++r)
    1523              :             {
    1524           10 :                 prinbee::out_event event;
    1525           10 :                 CATCH_REQUIRE(j.next_event(event, false));
    1526           10 :                 CATCH_REQUIRE(times[r] == event.get_event_time());
    1527           10 :                 CATCH_REQUIRE(prinbee::id_to_string(r + 1) == event.get_request_id());
    1528           10 :             }
    1529              : 
    1530              :             // make sure we reached the end
    1531              :             //
    1532              :             {
    1533            1 :                 prinbee::out_event event;
    1534            1 :                 CATCH_REQUIRE_FALSE(j.next_event(event, false));
    1535            1 :             }
    1536            1 :         }
    1537            1 :     }
    1538            3 :     CATCH_END_SECTION()
    1539              : 
    1540            4 :     CATCH_START_SECTION("journal_event_list: fill an event with files & direct data")
    1541              :     {
    1542            1 :         std::string const temp(SNAP_CATCH2_NAMESPACE::g_tmp_dir() + "/files_of_mixed_test");
    1543            1 :         CATCH_REQUIRE(snapdev::mkdir_p(temp) == 0);
    1544              : 
    1545              :         // we want a realpath (a.k.a. absolute path) and a relative path
    1546              :         //
    1547            1 :         std::string error_msg;
    1548            1 :         std::string const temp_absolute(snapdev::pathinfo::realpath(temp, error_msg));
    1549            1 :         std::string const cwd(snapdev::pathinfo::getcwd(error_msg));
    1550            1 :         std::string const temp_relative(snapdev::pathinfo::relative_path(cwd, temp_absolute));
    1551              : 
    1552            1 :         prinbee::attachment_copy_handling_t const mode[] =
    1553              :         {
    1554              :             prinbee::attachment_copy_handling_t::ATTACHMENT_COPY_HANDLING_SOFTLINK,
    1555              :             prinbee::attachment_copy_handling_t::ATTACHMENT_COPY_HANDLING_HARDLINK,
    1556              :             prinbee::attachment_copy_handling_t::ATTACHMENT_COPY_HANDLING_REFLINK,
    1557              :             prinbee::attachment_copy_handling_t::ATTACHMENT_COPY_HANDLING_FULL,
    1558              :         };
    1559              : 
    1560            5 :         for(auto const & handling : mode)
    1561              :         {
    1562           24 :             for(int count(0); count < 5; ++count)
    1563              :             {
    1564           60 :                 std::string name("journal_event_with_mixed_data-");
    1565           20 :                 name += std::to_string(count + 1);
    1566           20 :                 name += '-';
    1567           20 :                 name += std::to_string(static_cast<int>(handling));
    1568           20 :                 std::string const path(conf_path(name));
    1569              : 
    1570           20 :                 std::size_t const max(rand() % 100 + 150);
    1571           60 :                 std::vector<prinbee::data_t> data(max);
    1572              : 
    1573              :                 // create one event in a journal with many attachments
    1574              :                 // some of which are direct others will be files
    1575              :                 {
    1576           20 :                     advgetopt::conf_file::reset_conf_files();
    1577           20 :                     prinbee::journal j(path);
    1578           20 :                     CATCH_REQUIRE(j.set_file_management(prinbee::file_management_t::FILE_MANAGEMENT_DELETE));
    1579           20 :                     CATCH_REQUIRE(j.set_attachment_copy_handling(handling));
    1580           20 :                     CATCH_REQUIRE(j.is_valid());
    1581           20 :                     CATCH_REQUIRE(j.empty());
    1582              : 
    1583              :                     // create the event with many attachments
    1584              :                     //
    1585           20 :                     prinbee::in_event event;
    1586           20 :                     event.set_request_id(prinbee::id_to_string(count));
    1587              : 
    1588           20 :                     std::uint16_t select(0);
    1589         3918 :                     for(std::size_t r(0); r < max; ++r, select >>= 1)
    1590              :                     {
    1591         3898 :                         if((r % 16) == 0)
    1592              :                         {
    1593          256 :                             select = rand();
    1594              :                         }
    1595              : 
    1596         3898 :                         std::size_t const size(rand() % (20 * 1024) + 1);
    1597         3898 :                         data[r].resize(size);
    1598     40137297 :                         for(std::size_t idx(0); idx < size; ++idx)
    1599              :                         {
    1600     40133399 :                             data[r][idx] = rand();
    1601              :                         }
    1602              : 
    1603         3898 :                         prinbee::attachment a;
    1604         3898 :                         if((select & 1) == 0)
    1605              :                         {
    1606              :                             // add as direct data
    1607              :                             //
    1608         1924 :                             a.set_data(data[r].data(), size);
    1609              :                         }
    1610              :                         else
    1611              :                         {
    1612              :                             // add as a file
    1613              :                             //
    1614         1974 :                             std::string filename((rand() & 1) == 0 ? temp_absolute : temp_relative);
    1615         1974 :                             filename += "/in-";
    1616         1974 :                             filename += std::to_string(count + 1);
    1617         1974 :                             filename += '-';
    1618         1974 :                             filename += std::to_string(r + 1);
    1619         1974 :                             filename += ".data";
    1620              :                             {
    1621         1974 :                                 std::ofstream out(filename);
    1622         1974 :                                 CATCH_REQUIRE(out.is_open());
    1623         1974 :                                 out.write(reinterpret_cast<char const *>(data[r].data()), size);
    1624         1974 :                             }
    1625         1974 :                             a.set_file(filename);
    1626         1974 :                         }
    1627         3898 :                         event.add_attachment(a);
    1628         3898 :                     }
    1629              : 
    1630           20 :                     snapdev::timespec_ex event_time(snapdev::now());
    1631           20 :                     CATCH_REQUIRE(j.add_event(event, event_time));
    1632           20 :                     CATCH_REQUIRE(j.size() == 1ULL);
    1633           20 :                     CATCH_REQUIRE_FALSE(j.empty());
    1634           20 :                 }
    1635              : 
    1636              :                 // now reload that journal and see that we can retrieve all
    1637              :                 // the attachments as we added above
    1638              :                 {
    1639           20 :                     prinbee::journal j(path);
    1640              : 
    1641           20 :                     prinbee::out_event event;
    1642           20 :                     CATCH_REQUIRE(j.next_event(event));
    1643           20 :                     CATCH_REQUIRE(prinbee::id_to_string(count) == event.get_request_id());
    1644           20 :                     CATCH_REQUIRE(max == event.get_attachment_size());
    1645              : 
    1646         3918 :                     for(std::size_t r(0); r < max; ++r)
    1647              :                     {
    1648         3898 :                         prinbee::attachment const a(event.get_attachment(r));
    1649         3898 :                         void * d(a.data());
    1650         3898 :                         std::size_t sz(a.size());
    1651         3898 :                         CATCH_REQUIRE(data[r].size() == sz);
    1652         3898 :                         CATCH_REQUIRE(memcmp(d, data[r].data(), sz) == 0);
    1653         3898 :                     }
    1654              : 
    1655              :                     // make sure we reached the end
    1656           20 :                     CATCH_REQUIRE_FALSE(j.next_event(event));
    1657           20 :                 }
    1658           20 :             }
    1659              :         }
    1660            1 :     }
    1661            3 :     CATCH_END_SECTION()
    1662            2 : }
    1663              : 
    1664              : 
    1665            1 : CATCH_TEST_CASE("journal_event_files", "[journal]")
    1666              : {
    1667            3 :     CATCH_START_SECTION("journal_event_files: reduce number of files with missing files")
    1668              :     {
    1669            3 :         std::string const path(conf_path("journal_event_files"));
    1670            1 :         advgetopt::conf_file::reset_conf_files();
    1671              : 
    1672              :         {
    1673            1 :             prinbee::journal j(path);
    1674            1 :             CATCH_REQUIRE(j.is_valid());
    1675            1 :             CATCH_REQUIRE(j.set_maximum_number_of_files(5));
    1676              : 
    1677              :             // 9 to 10 Kb of data per message so we should be able to add
    1678              :             // between 6 and 7 messages per file; i.e. 14 maximum then we
    1679              :             // are expecting an error on the add_event()
    1680              :             //
    1681            1 :             std::size_t const size(rand() % 1024 + 1);
    1682            3 :             std::vector<std::uint8_t> data(size);
    1683          493 :             for(std::size_t idx(0); idx < size; ++idx)
    1684              :             {
    1685          492 :                 data[idx] = rand();
    1686              :             }
    1687            1 :             prinbee::in_event event;
    1688            3 :             event.set_request_id("id-1");
    1689              :             {
    1690            1 :                 prinbee::attachment a;
    1691            1 :                 a.set_data(data.data(), size);
    1692            1 :                 event.add_attachment(a);
    1693            1 :             }
    1694            1 :             snapdev::timespec_ex event_time(snapdev::now());
    1695            1 :             CATCH_REQUIRE(j.add_event(event, event_time));
    1696              : 
    1697              :             // trying to reduce the number of files works fine when events are
    1698              :             // only in the very first file
    1699              :             //
    1700            1 :             CATCH_REQUIRE(j.set_maximum_number_of_files(prinbee::JOURNAL_MINIMUM_NUMBER_OF_FILES));
    1701            1 :         }
    1702              : 
    1703              :         {
    1704            1 :             prinbee::journal j(path);
    1705            1 :             CATCH_REQUIRE(j.is_valid());
    1706            1 :             CATCH_REQUIRE(j.get_file_management() == prinbee::file_management_t::FILE_MANAGEMENT_KEEP);
    1707            1 :         }
    1708            1 :     }
    1709            2 :     CATCH_END_SECTION()
    1710            1 : }
    1711              : 
    1712              : 
    1713            2 : CATCH_TEST_CASE("journal_attachement", "[journal][attachment]")
    1714              : {
    1715            4 :     CATCH_START_SECTION("journal_attachment: attachment save_data() makes a copy")
    1716              :     {
    1717          101 :         for(int i(0); i < 100; ++i)
    1718              :         {
    1719          100 :             prinbee::attachment a;
    1720              : 
    1721          100 :             std::size_t sz(rand() & 1000 + 1);
    1722          300 :             std::vector<std::uint8_t> data(sz);
    1723        50661 :             for(std::size_t idx(0); idx < sz; ++idx)
    1724              :             {
    1725        50561 :                 data[idx] = rand();
    1726              :             }
    1727          100 :             a.save_data(data.data(), sz);
    1728              : 
    1729              :             // keep a copy
    1730              :             //
    1731          100 :             std::vector<std::uint8_t> copy(data);
    1732              : 
    1733              :             // "mess up original"
    1734              :             //
    1735        50661 :             for(std::size_t idx(0); idx < sz; ++idx)
    1736              :             {
    1737              :                 do
    1738              :                 {
    1739        50744 :                     data[idx] = rand();
    1740              :                 }
    1741        50744 :                 while(data[idx] == copy[idx]);
    1742              :             }
    1743              : 
    1744          100 :             CATCH_REQUIRE(static_cast<off_t>(sz) == a.size());
    1745              : 
    1746          100 :             void const * p(a.data());
    1747          100 :             std::uint8_t const * ptr(reinterpret_cast<std::uint8_t const *>(p));
    1748              : 
    1749        50661 :             for(std::size_t idx(0); idx < sz; ++idx)
    1750              :             {
    1751        50561 :                 CATCH_REQUIRE(ptr[idx] == copy[idx]);
    1752              :             }
    1753          100 :         }
    1754              :     }
    1755            3 :     CATCH_END_SECTION()
    1756              : 
    1757            4 :     CATCH_START_SECTION("journal_attachment: attachment set_file() saves a filename and reads its data")
    1758              :     {
    1759            3 :         std::string const content("This is the file.\n");
    1760            1 :         std::string const path(SNAP_CATCH2_NAMESPACE::g_tmp_dir() + "/set_file-test-file.txt");
    1761              :         {
    1762            1 :             std::ofstream out(path);
    1763            1 :             CATCH_REQUIRE(out.is_open());
    1764            1 :             out << content;
    1765            1 :         }
    1766            1 :         prinbee::attachment a;
    1767            1 :         a.set_file(path);
    1768            1 :         CATCH_REQUIRE_FALSE(a.empty());
    1769            1 :         CATCH_REQUIRE(a.size() == static_cast<off_t>(content.length()));
    1770            1 :         CATCH_REQUIRE(a.is_file());
    1771            1 :         CATCH_REQUIRE(a.filename() == path);
    1772              : 
    1773              :         // the a.data() will read the file in memory inside the attachment
    1774              :         // object then we can compare and make sure it is equal to our input
    1775              :         //
    1776            1 :         void const * p(a.data());
    1777            1 :         char const * ptr(reinterpret_cast<char const *>(p));
    1778           19 :         for(std::size_t idx(0); idx < content.length(); ++idx)
    1779              :         {
    1780           18 :             CATCH_REQUIRE(ptr[idx] == content[idx]);
    1781              :         }
    1782            1 :     }
    1783            3 :     CATCH_END_SECTION()
    1784            2 : }
    1785              : 
    1786              : 
    1787           29 : CATCH_TEST_CASE("journal_errors", "[journal][error]")
    1788              : {
    1789           31 :     CATCH_START_SECTION("journal_errors: trying to re-add the same event multiple times fails")
    1790              :     {
    1791            3 :         std::string const path(conf_path("journal_duplicate_event"));
    1792            1 :         advgetopt::conf_file::reset_conf_files();
    1793            1 :         prinbee::journal j(path);
    1794            1 :         CATCH_REQUIRE(j.is_valid());
    1795              : 
    1796            1 :         std::size_t const size(rand() % 10 * 1024 + 1);
    1797            3 :         std::vector<std::uint8_t> data(size);
    1798         3074 :         for(std::size_t idx(0); idx < size; ++idx)
    1799              :         {
    1800         3073 :             data[idx] = rand();
    1801              :         }
    1802            1 :         prinbee::in_event event;
    1803            3 :         event.set_request_id("id-123");
    1804              :         {
    1805            1 :             prinbee::attachment a;
    1806            1 :             a.set_data(data.data(), size);
    1807            1 :             event.add_attachment(a);
    1808            1 :         }
    1809            1 :         snapdev::timespec_ex event_time(snapdev::now());
    1810            1 :         CATCH_REQUIRE(j.add_event(event, event_time));
    1811              : 
    1812              :         // if we try again, it fails
    1813              :         //
    1814            1 :         event_time = snapdev::now();
    1815            1 :         CATCH_REQUIRE_FALSE(j.add_event(event, event_time));
    1816            1 :     }
    1817           30 :     CATCH_END_SECTION()
    1818              : 
    1819           31 :     CATCH_START_SECTION("journal_errors: attachment negative size (set_data)")
    1820              :     {
    1821            1 :         prinbee::attachment a;
    1822            1 :         std::uint8_t buf[256];
    1823              : 
    1824          101 :         for(int i(0); i < 100; ++i)
    1825              :         {
    1826          100 :             off_t size(0);
    1827          200 :             while(size >= 0)
    1828              :             {
    1829          100 :                 size = -rand();
    1830              :             }
    1831          300 :             CATCH_REQUIRE_THROWS_MATCHES(
    1832              :                       a.set_data(buf, size)
    1833              :                     , prinbee::invalid_parameter
    1834              :                     , Catch::Matchers::ExceptionMessage("prinbee_exception: attachment cannot have a negative size."));
    1835              :         }
    1836            1 :     }
    1837           30 :     CATCH_END_SECTION()
    1838              : 
    1839           31 :     CATCH_START_SECTION("journal_errors: attachment invalid size / pointer combo (set_data)")
    1840              :     {
    1841            1 :         prinbee::attachment a;
    1842              : 
    1843          101 :         for(int i(0); i < 100; ++i)
    1844              :         {
    1845          100 :             off_t size(0);
    1846          200 :             while(size <= 0)
    1847              :             {
    1848          100 :                 size = rand();
    1849              :             }
    1850          300 :             CATCH_REQUIRE_THROWS_MATCHES(
    1851              :                       a.set_data(nullptr, size)
    1852              :                     , prinbee::invalid_parameter
    1853              :                     , Catch::Matchers::ExceptionMessage("prinbee_exception: attachment with a size > 0 must have a non null data pointer."));
    1854              :         }
    1855            1 :     }
    1856           30 :     CATCH_END_SECTION()
    1857              : 
    1858           31 :     CATCH_START_SECTION("journal_errors: attachment negative size (save_data)")
    1859              :     {
    1860            1 :         prinbee::attachment a;
    1861            1 :         std::uint8_t buf[256];
    1862              : 
    1863          101 :         for(int i(0); i < 100; ++i)
    1864              :         {
    1865          100 :             off_t size(0);
    1866          200 :             while(size >= 0)
    1867              :             {
    1868          100 :                 size = -rand();
    1869              :             }
    1870          300 :             CATCH_REQUIRE_THROWS_MATCHES(
    1871              :                       a.save_data(buf, size)
    1872              :                     , prinbee::invalid_parameter
    1873              :                     , Catch::Matchers::ExceptionMessage("prinbee_exception: attachment cannot have a negative size."));
    1874              :         }
    1875            1 :     }
    1876           30 :     CATCH_END_SECTION()
    1877              : 
    1878           31 :     CATCH_START_SECTION("journal_errors: attachment invalid size / pointer combo (save_data)")
    1879              :     {
    1880            1 :         prinbee::attachment a;
    1881              : 
    1882          101 :         for(int i(0); i < 100; ++i)
    1883              :         {
    1884          100 :             off_t size(0);
    1885          200 :             while(size <= 0)
    1886              :             {
    1887          100 :                 size = rand();
    1888              :             }
    1889          300 :             CATCH_REQUIRE_THROWS_MATCHES(
    1890              :                       a.save_data(nullptr, size)
    1891              :                     , prinbee::invalid_parameter
    1892              :                     , Catch::Matchers::ExceptionMessage("prinbee_exception: attachment with a size > 0 must have a non null data pointer (2)."));
    1893              :         }
    1894            1 :     }
    1895           30 :     CATCH_END_SECTION()
    1896              : 
    1897           31 :     CATCH_START_SECTION("journal_errors: request_id too long")
    1898              :     {
    1899            3 :         std::string const path(conf_path("journal_large_event"));
    1900            1 :         advgetopt::conf_file::reset_conf_files();
    1901            1 :         prinbee::journal j(path);
    1902            1 :         CATCH_REQUIRE(j.is_valid());
    1903              : 
    1904            1 :         std::size_t const size(rand() % 10 * 1024 + 1);
    1905            3 :         std::vector<std::uint8_t> data(size);
    1906         6146 :         for(std::size_t idx(0); idx < size; ++idx)
    1907              :         {
    1908         6145 :             data[idx] = rand();
    1909              :         }
    1910            1 :         prinbee::in_event event;
    1911            3 :         event.set_request_id("for a request identifier too be way to long here it needs to be some two hundred and fifty six or way more characters which means this is a really long sentence to make it happen and well, since I have a lot of imagination that is really no issue at all, right?");
    1912              :         {
    1913            1 :             prinbee::attachment a;
    1914            1 :             a.set_data(data.data(), size);
    1915            1 :             event.add_attachment(a);
    1916            1 :         }
    1917            1 :         snapdev::timespec_ex event_time(snapdev::now());
    1918            1 :         CATCH_REQUIRE_FALSE(j.add_event(event, event_time));
    1919            1 :     }
    1920           30 :     CATCH_END_SECTION()
    1921              : 
    1922           31 :     CATCH_START_SECTION("journal_errors: invalid number of files")
    1923              :     {
    1924            3 :         std::string const path(conf_path("journal_out_of_range"));
    1925            1 :         advgetopt::conf_file::reset_conf_files();
    1926            1 :         prinbee::journal j(path);
    1927              : 
    1928            3 :         for(std::uint32_t count(0); count < prinbee::JOURNAL_MINIMUM_NUMBER_OF_FILES; ++count)
    1929              :         {
    1930            2 :             std::stringstream ss;
    1931              :             ss << "out_of_range: maximum number of files ("
    1932            4 :                << std::to_string(count)
    1933              :                << ") is out of range: ["
    1934            4 :                << std::to_string(prinbee::JOURNAL_MINIMUM_NUMBER_OF_FILES)
    1935              :                << ".."
    1936            4 :                << std::to_string(prinbee::JOURNAL_MAXIMUM_NUMBER_OF_FILES)
    1937            8 :                << "]";
    1938            2 :             CATCH_REQUIRE_THROWS_MATCHES(
    1939              :                       j.set_maximum_number_of_files(count)
    1940              :                     , prinbee::out_of_range
    1941              :                     , Catch::Matchers::ExceptionMessage(ss.str()));
    1942            2 :         }
    1943          100 :         for(std::uint32_t count(prinbee::JOURNAL_MAXIMUM_NUMBER_OF_FILES + 1); count < prinbee::JOURNAL_MAXIMUM_NUMBER_OF_FILES + 100; ++count)
    1944              :         {
    1945           99 :             std::stringstream ss;
    1946              :             ss << "out_of_range: maximum number of files ("
    1947          198 :                << std::to_string(count)
    1948              :                << ") is out of range: ["
    1949          198 :                << std::to_string(prinbee::JOURNAL_MINIMUM_NUMBER_OF_FILES)
    1950              :                << ".."
    1951          198 :                << std::to_string(prinbee::JOURNAL_MAXIMUM_NUMBER_OF_FILES)
    1952          396 :                << "]";
    1953           99 :             CATCH_REQUIRE_THROWS_MATCHES(
    1954              :                       j.set_maximum_number_of_files(count)
    1955              :                     , prinbee::out_of_range
    1956              :                     , Catch::Matchers::ExceptionMessage(ss.str()));
    1957           99 :         }
    1958            1 :     }
    1959           30 :     CATCH_END_SECTION()
    1960              : 
    1961           31 :     CATCH_START_SECTION("journal_errors: missing folder")
    1962              :     {
    1963            3 :         std::string const path(conf_path("journal_missing", true));
    1964            1 :         chmod(path.c_str(), 0); // remove permissions so the add_event() fails with EPERM
    1965            1 :         advgetopt::conf_file::reset_conf_files();
    1966            1 :         prinbee::journal j(path);
    1967            1 :         CATCH_REQUIRE(j.is_valid());
    1968              : 
    1969            1 :         std::size_t const size(rand() % 10 * 1024 + 1);
    1970            3 :         std::vector<std::uint8_t> data(size);
    1971         3074 :         for(std::size_t idx(0); idx < size; ++idx)
    1972              :         {
    1973         3073 :             data[idx] = rand();
    1974              :         }
    1975            1 :         prinbee::in_event event;
    1976            3 :         event.set_request_id("id-123");
    1977              :         {
    1978            1 :             prinbee::attachment a;
    1979            1 :             a.set_data(data.data(), size);
    1980            1 :             event.add_attachment(a);
    1981            1 :         }
    1982            1 :         snapdev::timespec_ex event_time(snapdev::now());
    1983            1 :         CATCH_REQUIRE_FALSE(j.add_event(event, event_time));
    1984            1 :     }
    1985           30 :     CATCH_END_SECTION()
    1986              : 
    1987           31 :     CATCH_START_SECTION("journal_errors: filled up journal (small size)")
    1988              :     {
    1989            3 :         std::string const path(conf_path("journal_filled"));
    1990            1 :         advgetopt::conf_file::reset_conf_files();
    1991            1 :         prinbee::journal j(path);
    1992            1 :         CATCH_REQUIRE(j.is_valid());
    1993              : 
    1994            1 :         j.set_maximum_file_size(prinbee::JOURNAL_MINIMUM_FILE_SIZE);
    1995            1 :         j.set_inline_attachment_size_threshold(prinbee::JOURNAL_INLINE_ATTACHMENT_SIZE_MAXIMUM_THRESHOLD);
    1996              : 
    1997              :         // 9 to 10 Kb of data per message so we should be able to add
    1998              :         // between 6 and 7 messages per file; i.e. 14 maximum then we
    1999              :         // are expecting an error on the add_event()
    2000              :         //
    2001            1 :         std::vector<std::uint8_t> data;
    2002            1 :         bool success(false);
    2003            1 :         int count(0);
    2004           13 :         for(; count < 15; ++count)
    2005              :         {
    2006           13 :             std::size_t const size(rand() % 1024 + 1024 * 9);
    2007           13 :             data.resize(size);
    2008       128098 :             for(std::size_t idx(0); idx < size; ++idx)
    2009              :             {
    2010       128085 :                 data[idx] = rand();
    2011              :             }
    2012           13 :             prinbee::in_event event;
    2013           13 :             event.set_request_id("id-" + std::to_string(count));
    2014              :             {
    2015           13 :                 prinbee::attachment a;
    2016           13 :                 a.set_data(data.data(), size);
    2017           13 :                 event.add_attachment(a);
    2018           13 :             };
    2019           13 :             snapdev::timespec_ex event_time(snapdev::now());
    2020           13 :             bool const r(j.add_event(event, event_time));
    2021           13 :             if(!r)
    2022              :             {
    2023            1 :                 success = true;
    2024            1 :                 break;
    2025              :             }
    2026           13 :         }
    2027            1 :         CATCH_REQUIRE(success);
    2028              : 
    2029              :         // mark a few as complete and attempt another insert, it should
    2030              :         // still fail
    2031              :         //
    2032            3 :         std::vector<int> ids(count);
    2033           13 :         for(int mark_complete(0); mark_complete < count; ++mark_complete)
    2034              :         {
    2035           12 :             ids[mark_complete] = mark_complete;
    2036              :         }
    2037            1 :         std::random_device rd;
    2038            1 :         std::mt19937 g(rd());
    2039            1 :         std::shuffle(ids.begin(), ids.end(), g);
    2040            1 :         int const complete_count(rand() % 3 + 1);
    2041            3 :         for(int idx(0); idx < complete_count; ++idx)
    2042              :         {
    2043            2 :             std::string const request_id("id-" + std::to_string(ids[idx]));
    2044            2 :             if((rand() & 1) == 0)
    2045              :             {
    2046            1 :                 CATCH_REQUIRE(j.event_completed(request_id));
    2047              :             }
    2048              :             else
    2049              :             {
    2050            1 :                 CATCH_REQUIRE(j.event_failed(request_id));
    2051              :             }
    2052            2 :         }
    2053              : 
    2054              :         {
    2055              :             // as is, it still overflows (because we are not compressing)
    2056              :             //
    2057              :             //std::size_t const size(rand() % 1024 + 1024 * 8);
    2058              :             //std::vector<std::uint8_t> data(size);
    2059              :             //for(std::size_t idx(0); idx < size; ++idx)
    2060              :             //{
    2061              :             //    data[idx] = rand();
    2062              :             //}
    2063            1 :             prinbee::in_event event;
    2064            3 :             event.set_request_id("id-extra");
    2065              :             {
    2066            1 :                 prinbee::attachment a;
    2067            1 :                 a.set_data(data.data(), data.size());
    2068            1 :                 event.add_attachment(a);
    2069            1 :             };
    2070            1 :             snapdev::timespec_ex event_time(snapdev::now());
    2071            1 :             CATCH_REQUIRE_FALSE(j.add_event(event, event_time));
    2072              : 
    2073              :             // however, if we turn on the "allow compression" flag, it works
    2074              :             //
    2075            1 :             CATCH_REQUIRE(j.set_compress_when_full(true));
    2076            1 :             CATCH_REQUIRE(j.add_event(event, event_time));
    2077            1 :         }
    2078            1 :     }
    2079           30 :     CATCH_END_SECTION()
    2080              : 
    2081           31 :     CATCH_START_SECTION("journal_errors: fail with invalid size as ID is not complete and data is missing")
    2082              :     {
    2083            3 :         std::string const name("journal_incomplete_id");
    2084            1 :         std::string const path(conf_path(name));
    2085              : 
    2086              :         // create a journal file with one valid event
    2087              :         {
    2088            1 :             advgetopt::conf_file::reset_conf_files();
    2089            1 :             prinbee::journal j(path);
    2090            1 :             CATCH_REQUIRE(j.is_valid());
    2091            1 :             CATCH_REQUIRE(j.empty());
    2092              : 
    2093            1 :             std::uint8_t data[20] = {};
    2094            1 :             prinbee::in_event event;
    2095            3 :             event.set_request_id("this-id");
    2096              :             {
    2097            1 :                 prinbee::attachment a;
    2098            1 :                 a.set_data(data, sizeof(data));
    2099            1 :                 event.add_attachment(a);
    2100            1 :             }
    2101            1 :             snapdev::timespec_ex now(snapdev::now());
    2102            1 :             CATCH_REQUIRE(j.add_event(event, now));
    2103            1 :             CATCH_REQUIRE(j.size() == 1ULL);
    2104            1 :             CATCH_REQUIRE_FALSE(j.empty());
    2105            1 :         }
    2106              : 
    2107              :         // open that journal and add a broken header (invalid identifier) 
    2108              :         {
    2109            1 :             std::string const filename(event_filename(path, 0));
    2110            1 :             std::ofstream out(filename, std::ios::app | std::ios::binary);
    2111              :             char data[1];
    2112            1 :             std::size_t const size(32 /* == sizeof(header) */
    2113              :                              + 1 * sizeof(prinbee::attachment_offsets_t)
    2114              :                              + sizeof("next-id") - 1
    2115              :                              + sizeof(data));
    2116            1 :             CATCH_REQUIRE(size < 256ULL);
    2117            1 :             std::uint8_t const header[] = {
    2118              :                 'e', 'v',                               // f_magic
    2119              :                 static_cast<std::uint8_t>(prinbee::status_t::STATUS_READY), // f_status
    2120              :                 sizeof("next-id") - 1,                  // f_request_id_size
    2121              :                 size, 0, 0, 0,                          // f_size
    2122              :                 0, 0, 0, 0, 0, 0, 0, 0,                 // f_time
    2123              :                 0, 0, 0, 0, 0, 0, 0, 0,
    2124              :                 1,                                      // f_attachment_offsets
    2125              :                 0, 0, 0, 0, 0, 0, 0,                    // f_pad[7]
    2126              :             };
    2127            1 :             out.write(reinterpret_cast<char const *>(header), sizeof(header));
    2128            1 :             prinbee::attachment_offsets_t const offset(
    2129              :                       sizeof(header)
    2130              :                     + 1 * sizeof(prinbee::attachment_offsets_t)     // itself
    2131              :                     + sizeof("next-id") - 1);
    2132            1 :             out.write(reinterpret_cast<char const *>(&offset), sizeof(offset));
    2133            1 :             out.write("next", 4);                           // <-- only 4 bytes
    2134            1 :         }
    2135              : 
    2136              :         {
    2137            1 :             prinbee::journal j(path);
    2138            1 :             prinbee::out_event event;
    2139              : 
    2140              :             // we find the first valid event
    2141              :             //
    2142            1 :             CATCH_REQUIRE(j.next_event(event));
    2143            1 :             CATCH_REQUIRE("this-id" == event.get_request_id());
    2144              : 
    2145              :             // make sure we reached the end; the second event was invalid
    2146              :             //
    2147            1 :             CATCH_REQUIRE_FALSE(j.next_event(event));
    2148            1 :         }
    2149            1 :     }
    2150           30 :     CATCH_END_SECTION()
    2151              : 
    2152           31 :     CATCH_START_SECTION("journal_errors: invalid event date & time")
    2153              :     {
    2154            3 :         std::string const name("journal_wrong_time");
    2155            1 :         std::string const path(conf_path(name));
    2156              : 
    2157              :         // create a journal file with one valid event
    2158              :         {
    2159            1 :             advgetopt::conf_file::reset_conf_files();
    2160            1 :             prinbee::journal j(path);
    2161            1 :             CATCH_REQUIRE(j.is_valid());
    2162            1 :             CATCH_REQUIRE(j.empty());
    2163              : 
    2164            1 :             std::uint8_t data[20] = {};
    2165            1 :             prinbee::in_event event;
    2166            3 :             event.set_request_id("this-id");
    2167              :             {
    2168            1 :                 prinbee::attachment a;
    2169            1 :                 a.set_data(data, sizeof(data));
    2170            1 :                 event.add_attachment(a);
    2171            1 :             }
    2172            1 :             snapdev::timespec_ex now(snapdev::now());
    2173            1 :             CATCH_REQUIRE(j.add_event(event, now));
    2174            1 :             CATCH_REQUIRE(j.size() == 1ULL);
    2175            1 :             CATCH_REQUIRE_FALSE(j.empty());
    2176              : 
    2177              :             // trying to add an event in the future fails
    2178              :             //
    2179            1 :             snapdev::timespec_ex soon(snapdev::now());
    2180            1 :             soon += snapdev::timespec_ex(100, 0);            // 100 seconds in the future
    2181            3 :             event.set_request_id("future");
    2182            1 :             CATCH_REQUIRE_FALSE(j.add_event(event, soon));
    2183            1 :         }
    2184              : 
    2185              :         // open that journal and add a broken header (invalid date & time) 
    2186              :         {
    2187            1 :             std::string const filename(event_filename(path, 0));
    2188            1 :             std::ofstream out(filename, std::ios::app | std::ios::binary);
    2189            1 :             snapdev::timespec_ex soon(snapdev::now());
    2190            1 :             soon += snapdev::timespec_ex(100, 0);            // 100 seconds in the future
    2191            1 :             char data[32]; // content not used by the test, no need to initialized
    2192            1 :             std::size_t const size(32 /* == sizeof(header)*/
    2193              :                                  + 1 * sizeof(prinbee::attachment_offsets_t)
    2194              :                                  + sizeof("next-id") - 1
    2195              :                                  + sizeof(data));
    2196            1 :             CATCH_REQUIRE(size < 256ULL);
    2197            1 :             std::uint8_t const header[] = {
    2198              :                 'e', 'v',                               // f_magic
    2199              :                 static_cast<std::uint8_t>(prinbee::status_t::STATUS_READY), // f_status
    2200              :                 sizeof("next-id") - 1,                  // f_request_id_size
    2201              :                 size, 0, 0, 0,                          // f_size
    2202            1 :                 static_cast<std::uint8_t>(soon.tv_sec >>  0), // f_time
    2203            1 :                 static_cast<std::uint8_t>(soon.tv_sec >>  8),
    2204            1 :                 static_cast<std::uint8_t>(soon.tv_sec >> 16),
    2205            1 :                 static_cast<std::uint8_t>(soon.tv_sec >> 24),
    2206            1 :                 static_cast<std::uint8_t>(soon.tv_sec >> 32),
    2207            1 :                 static_cast<std::uint8_t>(soon.tv_sec >> 40),
    2208            1 :                 static_cast<std::uint8_t>(soon.tv_sec >> 48),
    2209            1 :                 static_cast<std::uint8_t>(soon.tv_sec >> 56),
    2210            1 :                 static_cast<std::uint8_t>(soon.tv_nsec >>  0),
    2211            1 :                 static_cast<std::uint8_t>(soon.tv_nsec >>  8),
    2212            1 :                 static_cast<std::uint8_t>(soon.tv_nsec >> 16),
    2213            1 :                 static_cast<std::uint8_t>(soon.tv_nsec >> 24),
    2214            1 :                 static_cast<std::uint8_t>(soon.tv_nsec >> 32),
    2215            1 :                 static_cast<std::uint8_t>(soon.tv_nsec >> 40),
    2216            1 :                 static_cast<std::uint8_t>(soon.tv_nsec >> 48),
    2217            1 :                 static_cast<std::uint8_t>(soon.tv_nsec >> 56),
    2218              :                 1,                                      // f_attachment_count
    2219              :                 0, 0, 0, 0, 0, 0, 0,                    // f_pad[7]
    2220            1 :             };
    2221            1 :             out.write(reinterpret_cast<char const *>(header), sizeof(header));
    2222            1 :             prinbee::attachment_offsets_t const offset(
    2223              :                       sizeof(header)
    2224              :                     + 1 * sizeof(prinbee::attachment_offsets_t)     // itself
    2225              :                     + sizeof("next-id") - 1);
    2226            1 :             out.write(reinterpret_cast<char const *>(&offset), sizeof(offset));
    2227            1 :             out.write("next-id", sizeof("next-id") - 1);
    2228            1 :             out.write(data, sizeof(data));
    2229            1 :         }
    2230              : 
    2231              :         {
    2232            1 :             prinbee::journal j(path);
    2233            1 :             prinbee::out_event event;
    2234              : 
    2235              :             // we find the first valid event
    2236              :             //
    2237            1 :             CATCH_REQUIRE(j.next_event(event));
    2238            1 :             CATCH_REQUIRE("this-id" == event.get_request_id());
    2239              : 
    2240              :             // make sure we reached the end; the second event was invalid
    2241              :             //
    2242            1 :             CATCH_REQUIRE_FALSE(j.next_event(event));
    2243            1 :         }
    2244            1 :     }
    2245           30 :     CATCH_END_SECTION()
    2246              : 
    2247           31 :     CATCH_START_SECTION("journal_errors: invalid end marker")
    2248              :     {
    2249              :         // to test the conversions, we need multiple cases so use a loop
    2250              :         //
    2251              :         struct marker
    2252              :         {
    2253              :             char a;
    2254              :             char b;
    2255              :         };
    2256            1 :         std::vector<marker> invalid_markers{
    2257              :             { 'n', 'g' },
    2258              :             { '\0', '@' },       // starts well, bad ending
    2259              :             { 0x03, 0x07 },
    2260              :             { 0x7F, static_cast<char>(0x97) },
    2261            3 :         };
    2262            1 :         int count(0);
    2263            5 :         for(auto const & bad_marker : invalid_markers)
    2264              :         {
    2265            4 :             ++count;
    2266           12 :             std::string name("journal_invalid_end_marker-");
    2267            4 :             name += std::to_string(count);
    2268            4 :             std::string const path(conf_path(name));
    2269              : 
    2270              :             // create a journal file with one valid event
    2271              :             {
    2272            4 :                 advgetopt::conf_file::reset_conf_files();
    2273            4 :                 prinbee::journal j(path);
    2274            4 :                 CATCH_REQUIRE(j.is_valid());
    2275            4 :                 CATCH_REQUIRE(j.empty());
    2276              : 
    2277            4 :                 std::uint8_t data[20] = {};
    2278            4 :                 prinbee::in_event event;
    2279           12 :                 event.set_request_id("this-id");
    2280              :                 {
    2281            4 :                     prinbee::attachment a;
    2282            4 :                     a.set_data(data, sizeof(data));
    2283            4 :                     event.add_attachment(a);
    2284            4 :                 }
    2285            4 :                 snapdev::timespec_ex now(snapdev::now());
    2286            4 :                 CATCH_REQUIRE(j.add_event(event, now));
    2287            4 :                 CATCH_REQUIRE(j.size() == 1ULL);
    2288            4 :                 CATCH_REQUIRE_FALSE(j.empty());
    2289            4 :             }
    2290              : 
    2291              :             // open that journal and add a broken end marker
    2292              :             // the header and data are otherwise valid
    2293              :             {
    2294            4 :                 std::string const filename(event_filename(path, 0));
    2295            4 :                 std::ofstream out(filename, std::ios::app | std::ios::binary);
    2296            4 :                 char data[1];
    2297            4 :                 std::size_t const size(32 /* == sizeof(header) */
    2298              :                                  + 1 * sizeof(prinbee::attachment_offsets_t)
    2299              :                                  + sizeof("next-id") - 1
    2300              :                                  + sizeof(data));
    2301            4 :                 CATCH_REQUIRE(size < 256ULL);
    2302            4 :                 std::uint8_t const header[] = {
    2303            4 :                     static_cast<std::uint8_t>(bad_marker.a), // f_magic
    2304            4 :                     static_cast<std::uint8_t>(bad_marker.b),
    2305              :                     static_cast<std::uint8_t>(prinbee::status_t::STATUS_READY), // f_status
    2306              :                     sizeof("next-id") - 1,                  // f_request_id_size
    2307              :                     size, 0, 0, 0,                          // f_size
    2308              :                     0, 0, 0, 0, 0, 0, 0, 0,                 // f_time
    2309              :                     0, 0, 0, 0, 0, 0, 0, 0,
    2310              :                     1,                                      // f_attachment_offsets
    2311              :                     0, 0, 0, 0, 0, 0, 0,                    // f_pad[7]
    2312            4 :                 };
    2313            4 :                 out.write(reinterpret_cast<char const *>(header), sizeof(header));
    2314            4 :                 prinbee::attachment_offsets_t const offset(
    2315              :                           sizeof(header)
    2316              :                         + 1 * sizeof(prinbee::attachment_offsets_t)     // itself
    2317              :                         + sizeof("next-id") - 1);
    2318            4 :                 out.write(reinterpret_cast<char const *>(&offset), sizeof(offset));
    2319            4 :                 out.write("next-id", sizeof("next-id") - 1);
    2320            4 :                 out.write(data, sizeof(data));
    2321            4 :             }
    2322              : 
    2323              :             {
    2324            4 :                 prinbee::journal j(path);
    2325            4 :                 prinbee::out_event event;
    2326              : 
    2327              :                 // we find the first valid event
    2328              :                 //
    2329            4 :                 CATCH_REQUIRE(j.next_event(event));
    2330            4 :                 CATCH_REQUIRE("this-id" == event.get_request_id());
    2331              : 
    2332              :                 // make sure we reached the end; the second event was invalid
    2333              :                 //
    2334            4 :                 CATCH_REQUIRE_FALSE(j.next_event(event));
    2335            4 :             }
    2336            4 :         }
    2337            1 :     }
    2338           30 :     CATCH_END_SECTION()
    2339              : 
    2340           31 :     CATCH_START_SECTION("journal_errors: incomplete header")
    2341              :     {
    2342            6 :         for(int idx(0); idx < 5; ++idx)
    2343              :         {
    2344           15 :             std::string name("journal_incomplete_header-");
    2345            5 :             name += std::to_string(idx + 1);
    2346            5 :             std::string const path(conf_path(name));
    2347              : 
    2348              :             // create a journal file with one valid event
    2349              :             {
    2350            5 :                 advgetopt::conf_file::reset_conf_files();
    2351            5 :                 prinbee::journal j(path);
    2352            5 :                 CATCH_REQUIRE(j.is_valid());
    2353            5 :                 CATCH_REQUIRE(j.empty());
    2354              : 
    2355            5 :                 std::uint8_t data[20] = {};
    2356            5 :                 prinbee::in_event event;
    2357           15 :                 event.set_request_id("this-id");
    2358              :                 {
    2359            5 :                     prinbee::attachment a;
    2360            5 :                     a.set_data(data, sizeof(data));
    2361            5 :                     event.add_attachment(a);
    2362            5 :                 };
    2363            5 :                 snapdev::timespec_ex now(snapdev::now());
    2364            5 :                 CATCH_REQUIRE(j.add_event(event, now));
    2365            5 :                 CATCH_REQUIRE(j.size() == 1ULL);
    2366            5 :                 CATCH_REQUIRE_FALSE(j.empty());
    2367            5 :             }
    2368              : 
    2369              :             // create a broken header (too small by 1 or more bytes)
    2370              :             {
    2371            5 :                 std::string const filename(event_filename(path, 0));
    2372            5 :                 std::ofstream out(filename, std::ios::app | std::ios::binary);
    2373              :                 char data[1];
    2374            5 :                 std::size_t const size(32 /* == sizeof(header) */
    2375              :                                  + 1 * sizeof(prinbee::attachment_offsets_t)
    2376              :                                  + sizeof("next-id") - 1
    2377              :                                  + sizeof(data));
    2378            5 :                 CATCH_REQUIRE(size < 256ULL);
    2379            5 :                 std::uint8_t const header[] = {
    2380              :                     'e', 'v',                               // f_magic
    2381              :                     static_cast<std::uint8_t>(prinbee::status_t::STATUS_READY), // f_status
    2382              :                     sizeof("next-id") - 1,                  // f_request_id_size
    2383              :                     size, 0, 0, 0,                          // f_size
    2384              :                     0, 0, 0, 0, 0, 0, 0, 0,                 // f_time
    2385              :                     0, 0, 0, 0, 0, 0, 0, 0,
    2386              :                     1,                                      // f_attachment_offsets
    2387              :                     0, 0, 0, 0, 0, 0, 0,                    // f_pad[7]
    2388              :                 };
    2389            5 :                 std::size_t const bad_size(rand() % (sizeof(header) - 1) + 1);
    2390            5 :                 out.write(reinterpret_cast<char const *>(header), bad_size);
    2391            5 :             }
    2392              : 
    2393              :             {
    2394            5 :                 prinbee::journal j(path);
    2395            5 :                 prinbee::out_event event;
    2396              : 
    2397              :                 // we find the first valid event
    2398              :                 //
    2399            5 :                 CATCH_REQUIRE(j.next_event(event));
    2400            5 :                 CATCH_REQUIRE("this-id" == event.get_request_id());
    2401              : 
    2402              :                 // make sure we reached the end; the second event was invalid
    2403              :                 // note: in this case we do not get an error message
    2404              :                 //
    2405            5 :                 CATCH_REQUIRE_FALSE(j.next_event(event));
    2406            5 :             }
    2407            5 :         }
    2408              :     }
    2409           30 :     CATCH_END_SECTION()
    2410              : 
    2411           31 :     CATCH_START_SECTION("journal_errors: invalid magic (start of file header magic tampered)")
    2412              :     {
    2413            7 :         for(int pos(0); pos < 6; ++pos)
    2414              :         {
    2415           18 :             std::string name("journal_invalid_magic-");
    2416            6 :             name += std::to_string(pos);
    2417            6 :             std::string const path(conf_path(name));
    2418              : 
    2419              :             // create a journal file with one valid event
    2420              :             // (without the event, it does not create the file)
    2421              :             {
    2422            6 :                 advgetopt::conf_file::reset_conf_files();
    2423            6 :                 prinbee::journal j(path);
    2424            6 :                 CATCH_REQUIRE(j.is_valid());
    2425            6 :                 CATCH_REQUIRE(j.empty());
    2426              : 
    2427            6 :                 std::uint8_t data[20] = {};
    2428            6 :                 prinbee::in_event event;
    2429           18 :                 event.set_request_id("this-id");
    2430              :                 {
    2431            6 :                     prinbee::attachment a;
    2432            6 :                     a.set_data(data, sizeof(data));
    2433            6 :                     event.add_attachment(a);
    2434            6 :                 }
    2435            6 :                 snapdev::timespec_ex now(snapdev::now());
    2436            6 :                 CATCH_REQUIRE(j.add_event(event, now));
    2437            6 :                 CATCH_REQUIRE(j.size() == 1ULL);
    2438            6 :                 CATCH_REQUIRE_FALSE(j.empty());
    2439            6 :             }
    2440              : 
    2441              :             // smash one of the header characters
    2442              :             {
    2443            6 :                 std::string const filename(event_filename(path, 0));
    2444            6 :                 std::fstream out(filename);
    2445            6 :                 out.seekp(pos);
    2446            6 :                 std::string header;
    2447            6 :                 header += 'E';
    2448            6 :                 header += 'V';
    2449            6 :                 header += 'T';
    2450            6 :                 header += 'J';
    2451            6 :                 header += '\1';
    2452            6 :                 header += '\0';
    2453              :                 for(;;)
    2454              :                 {
    2455            6 :                     char c(static_cast<char>(rand()));
    2456            6 :                     if(c != header[pos])
    2457              :                     {
    2458            6 :                         out.write(&c, 1);
    2459            6 :                         break;
    2460              :                     }
    2461            0 :                 }
    2462            6 :             }
    2463              : 
    2464              :             {
    2465            6 :                 prinbee::journal j(path);
    2466            6 :                 prinbee::out_event event;
    2467              : 
    2468              :                 // we find no events
    2469              :                 //
    2470            6 :                 CATCH_REQUIRE_FALSE(j.next_event(event));
    2471            6 :             }
    2472            6 :         }
    2473              :     }
    2474           30 :     CATCH_END_SECTION()
    2475              : 
    2476           31 :     CATCH_START_SECTION("journal_errors: short magic (start of file header)")
    2477              :     {
    2478            9 :         for(int size(0); size < 8; ++size)
    2479              :         {
    2480           24 :             std::string name("journal_short_magic-");
    2481            8 :             name += std::to_string(size);
    2482            8 :             std::string const path(conf_path(name));
    2483              : 
    2484              :             // create a journal file with one valid event
    2485              :             // (without the event, it does not create the file)
    2486              :             {
    2487            8 :                 advgetopt::conf_file::reset_conf_files();
    2488            8 :                 prinbee::journal j(path);
    2489            8 :                 CATCH_REQUIRE(j.is_valid());
    2490            8 :                 CATCH_REQUIRE(j.empty());
    2491              : 
    2492            8 :                 std::uint8_t data[20] = {};
    2493            8 :                 prinbee::in_event event;
    2494           24 :                 event.set_request_id("this-id");
    2495              :                 {
    2496            8 :                     prinbee::attachment a;
    2497            8 :                     a.set_data(data, sizeof(data));
    2498            8 :                     event.add_attachment(a);
    2499            8 :                 };
    2500            8 :                 snapdev::timespec_ex now(snapdev::now());
    2501            8 :                 CATCH_REQUIRE(j.add_event(event, now));
    2502            8 :                 CATCH_REQUIRE(j.size() == 1ULL);
    2503            8 :                 CATCH_REQUIRE_FALSE(j.empty());
    2504            8 :             }
    2505              : 
    2506              :             // truncate the header to `size` bytes
    2507              :             {
    2508            8 :                 std::string const filename(event_filename(path, 0));
    2509            8 :                 CATCH_REQUIRE(truncate(filename.c_str(), size) == 0);
    2510            8 :             }
    2511              : 
    2512              :             {
    2513            8 :                 prinbee::journal j(path);
    2514            8 :                 prinbee::out_event event;
    2515              : 
    2516              :                 // we find no events
    2517              :                 //
    2518            8 :                 CATCH_REQUIRE_FALSE(j.next_event(event));
    2519            8 :             }
    2520            8 :         }
    2521              :     }
    2522           30 :     CATCH_END_SECTION()
    2523              : 
    2524           31 :     CATCH_START_SECTION("journal_errors: invalid out event statuses")
    2525              :     {
    2526          257 :         for(int idx(0); idx < 256; ++idx)
    2527              :         {
    2528          256 :             switch(static_cast<prinbee::status_t>(idx))
    2529              :             {
    2530            6 :             case prinbee::status_t::STATUS_UNKNOWN:
    2531              :             case prinbee::status_t::STATUS_READY:
    2532              :             case prinbee::status_t::STATUS_FORWARDED:
    2533              :             case prinbee::status_t::STATUS_ACKNOWLEDGED:
    2534              :             case prinbee::status_t::STATUS_COMPLETED:
    2535              :             case prinbee::status_t::STATUS_FAILED:
    2536            6 :                 continue;
    2537              : 
    2538          250 :             default:
    2539          250 :                 break;
    2540              : 
    2541              :             }
    2542              : 
    2543          500 :             prinbee::out_event event;
    2544          750 :             CATCH_REQUIRE_THROWS_MATCHES(
    2545              :                       event.set_status(static_cast<prinbee::status_t>(idx))
    2546              :                     , prinbee::invalid_parameter
    2547              :                     , Catch::Matchers::ExceptionMessage(
    2548              :                               "prinbee_exception: unsupported status number."));
    2549              :         }
    2550              :     }
    2551           30 :     CATCH_END_SECTION()
    2552              : 
    2553           31 :     CATCH_START_SECTION("journal_errors: can't reduce number of files in a filled up journal")
    2554              :     {
    2555            3 :         std::string const path(conf_path("journal_reduce_max_files"));
    2556            1 :         advgetopt::conf_file::reset_conf_files();
    2557            1 :         prinbee::journal j(path);
    2558            1 :         CATCH_REQUIRE(j.is_valid());
    2559            1 :         CATCH_REQUIRE(j.set_maximum_number_of_files(5));
    2560              : 
    2561            1 :         j.set_maximum_file_size(prinbee::JOURNAL_MINIMUM_FILE_SIZE);
    2562              : 
    2563              :         // 9 to 10 Kb of data per message so we should be able to add
    2564              :         // between 6 and 7 messages per file; i.e. 14 maximum then we
    2565              :         // are expecting an error on the add_event()
    2566              :         //
    2567            1 :         std::vector<std::uint8_t> data;
    2568            1 :         bool success(false);
    2569            1 :         int count(0);
    2570         7641 :         for(;; ++count)
    2571              :         {
    2572         7642 :             std::size_t const size(rand() % 1024 + 1024 * 9);
    2573         7642 :             data.resize(size);
    2574     74357662 :             for(std::size_t idx(0); idx < size; ++idx)
    2575              :             {
    2576     74350020 :                 data[idx] = rand();
    2577              :             }
    2578         7642 :             prinbee::in_event event;
    2579         7642 :             event.set_request_id("id-" + std::to_string(count));
    2580              :             {
    2581         7642 :                 prinbee::attachment a;
    2582         7642 :                 a.set_data(data.data(), size);
    2583         7642 :                 event.add_attachment(a);
    2584         7642 :             };
    2585         7642 :             snapdev::timespec_ex event_time(snapdev::now());
    2586         7642 :             bool const r(j.add_event(event, event_time));
    2587         7642 :             if(!r)
    2588              :             {
    2589            1 :                 success = true;
    2590            1 :                 break;
    2591              :             }
    2592        15283 :         }
    2593            1 :         CATCH_REQUIRE(success);
    2594              : 
    2595              :         // trying to reduce the number of files when full fails with
    2596              :         // an exception
    2597              :         //
    2598            3 :         CATCH_REQUIRE_THROWS_MATCHES(
    2599              :                   j.set_maximum_number_of_files(prinbee::JOURNAL_MINIMUM_NUMBER_OF_FILES)
    2600              :                 , prinbee::file_still_in_use
    2601              :                 , Catch::Matchers::ExceptionMessage(
    2602              :                           "prinbee_exception: it is not currently possible to reduce the maximum number of files when some of those over the new limit are still in use."));
    2603              : 
    2604              :         // mark all as complete and re-attempt the reduction
    2605              :         //
    2606         7642 :         for(int idx(0); idx < count; ++idx)
    2607              :         {
    2608         7641 :             std::string const request_id("id-" + std::to_string(idx));
    2609         7641 :             if((rand() & 1) == 0)
    2610              :             {
    2611         3762 :                 CATCH_REQUIRE(j.event_completed(request_id));
    2612              :             }
    2613              :             else
    2614              :             {
    2615         3879 :                 CATCH_REQUIRE(j.event_failed(request_id));
    2616              :             }
    2617         7641 :         }
    2618              : 
    2619            1 :         CATCH_REQUIRE(j.set_maximum_number_of_files(prinbee::JOURNAL_MINIMUM_NUMBER_OF_FILES));
    2620            1 :     }
    2621           30 :     CATCH_END_SECTION()
    2622              : 
    2623           31 :     CATCH_START_SECTION("journal_errors: source file missing")
    2624              :     {
    2625            1 :         prinbee::attachment a;
    2626            1 :         std::string const path(SNAP_CATCH2_NAMESPACE::g_tmp_dir() + "/this-does-not-exist.txt");
    2627            3 :         CATCH_REQUIRE_THROWS_MATCHES(
    2628              :                   a.set_file(path)
    2629              :                 , prinbee::file_not_found
    2630              :                 , Catch::Matchers::ExceptionMessage(
    2631              :                             std::string("prinbee_exception: file \"")
    2632              :                           + path
    2633              :                           + "\" not accessible: No such file or directory."));
    2634            1 :     }
    2635           30 :     CATCH_END_SECTION()
    2636              : 
    2637           31 :     CATCH_START_SECTION("journal_errors: file size mismatch")
    2638              :     {
    2639            1 :         prinbee::attachment a;
    2640            1 :         std::size_t real_size(0);
    2641            1 :         std::string const path(SNAP_CATCH2_NAMESPACE::g_tmp_dir() + "/some-file.txt");
    2642              :         {
    2643            1 :             std::ofstream out(path);
    2644            1 :             CATCH_REQUIRE(out.is_open());
    2645            1 :             out << "This small file.\n";
    2646            1 :             real_size = out.tellp();
    2647            1 :         }
    2648            1 :         CATCH_REQUIRE_THROWS_MATCHES(
    2649              :                   a.set_file(path, 100)
    2650              :                 , prinbee::invalid_parameter
    2651              :                 , Catch::Matchers::ExceptionMessage(
    2652              :                             "prinbee_exception: trying to save more data (100) than available in file attachment \""
    2653              :                           + path
    2654              :                           + "\" ("
    2655              :                           + std::to_string(real_size)
    2656              :                           + ")."));
    2657            1 :     }
    2658           30 :     CATCH_END_SECTION()
    2659              : 
    2660           31 :     CATCH_START_SECTION("journal_errors: delete attachment file then try to read the data")
    2661              :     {
    2662            3 :         std::string content("File about to be deleted.\n");
    2663            1 :         std::string const path(SNAP_CATCH2_NAMESPACE::g_tmp_dir() + "/set_file-unlink-file.txt");
    2664              :         {
    2665            1 :             std::ofstream out(path);
    2666            1 :             CATCH_REQUIRE(out.is_open());
    2667            1 :             out << content;
    2668            1 :         }
    2669            1 :         prinbee::attachment a;
    2670            1 :         a.set_file(path);
    2671            1 :         CATCH_REQUIRE_FALSE(a.empty());
    2672            1 :         CATCH_REQUIRE(a.size() == static_cast<off_t>(content.length()));
    2673            1 :         CATCH_REQUIRE(a.is_file());
    2674            1 :         CATCH_REQUIRE(a.filename() == path);
    2675              : 
    2676              :         // deleting the file before call a.data() means we get an error
    2677              :         //
    2678            1 :         CATCH_REQUIRE(unlink(path.c_str()) == 0);
    2679            1 :         CATCH_REQUIRE_THROWS_MATCHES(
    2680              :                   a.data()
    2681              :                 , prinbee::file_not_found
    2682              :                 , Catch::Matchers::ExceptionMessage(
    2683              :                             "prinbee_exception: file \""
    2684              :                           + path
    2685              :                           + "\" not found or permission denied."));
    2686            1 :     }
    2687           30 :     CATCH_END_SECTION()
    2688              : 
    2689           31 :     CATCH_START_SECTION("journal_errors: delete small attachment file before adding event to journal")
    2690              :     {
    2691            3 :         std::string const path(conf_path("journal_small_attachment"));
    2692            1 :         advgetopt::conf_file::reset_conf_files();
    2693            1 :         prinbee::journal j(path);
    2694              : 
    2695            3 :         std::string content("Another file about to be deleted.\n");
    2696            1 :         std::string const to_unlink(SNAP_CATCH2_NAMESPACE::g_tmp_dir() + "/set_file-add_event-unlink-file.txt");
    2697              :         {
    2698            1 :             std::ofstream out(to_unlink);
    2699            1 :             CATCH_REQUIRE(out.is_open());
    2700            1 :             out << content;
    2701            1 :         }
    2702            1 :         prinbee::attachment a;
    2703            1 :         a.set_file(to_unlink);
    2704            1 :         CATCH_REQUIRE_FALSE(a.empty());
    2705            1 :         CATCH_REQUIRE(a.size() == static_cast<off_t>(content.length()));
    2706            1 :         CATCH_REQUIRE(a.is_file());
    2707            1 :         CATCH_REQUIRE(a.filename() == to_unlink);
    2708              : 
    2709            1 :         prinbee::in_event event;
    2710            3 :         event.set_request_id("unlinked");
    2711            1 :         event.add_attachment(a);
    2712              : 
    2713              :         // deleting the file before calling j.add_event()
    2714              :         //
    2715            1 :         CATCH_REQUIRE(unlink(to_unlink.c_str()) == 0);
    2716              : 
    2717              :         // the add fails as a result
    2718              :         //
    2719            1 :         snapdev::timespec_ex event_time(snapdev::now());
    2720            1 :         CATCH_REQUIRE_FALSE(j.add_event(event, event_time));
    2721            1 :     }
    2722           30 :     CATCH_END_SECTION()
    2723              : 
    2724           31 :     CATCH_START_SECTION("journal_errors: delete large attachment file before adding event to journal")
    2725              :     {
    2726            1 :         prinbee::attachment_copy_handling_t const mode[] =
    2727              :         {
    2728              :             prinbee::attachment_copy_handling_t::ATTACHMENT_COPY_HANDLING_SOFTLINK,
    2729              :             prinbee::attachment_copy_handling_t::ATTACHMENT_COPY_HANDLING_HARDLINK,
    2730              :             prinbee::attachment_copy_handling_t::ATTACHMENT_COPY_HANDLING_REFLINK,
    2731              :             prinbee::attachment_copy_handling_t::ATTACHMENT_COPY_HANDLING_FULL,
    2732              :         };
    2733              : 
    2734            5 :         for(auto const & handling : mode)
    2735              :         {
    2736           12 :             std::string const path(conf_path("journal_large_attachment"));
    2737            4 :             advgetopt::conf_file::reset_conf_files();
    2738            4 :             prinbee::journal j(path);
    2739            4 :             j.set_attachment_copy_handling(handling);
    2740              : 
    2741              :             // create a large string so we go through the large file case
    2742              :             //
    2743            4 :             std::string const content(SNAP_CATCH2_NAMESPACE::random_string(
    2744              :                     prinbee::JOURNAL_INLINE_ATTACHMENT_SIZE_DEFAULT_THRESHOLD,
    2745              :                     prinbee::JOURNAL_INLINE_ATTACHMENT_SIZE_DEFAULT_THRESHOLD * 2,
    2746            4 :                     SNAP_CATCH2_NAMESPACE::character_t::CHARACTER_ZUNICODE));
    2747            4 :             std::string const to_unlink(SNAP_CATCH2_NAMESPACE::g_tmp_dir() + "/set_file-add_event-unlink-file.txt");
    2748              :             {
    2749            4 :                 std::ofstream out(to_unlink);
    2750            4 :                 CATCH_REQUIRE(out.is_open());
    2751            4 :                 out << content;
    2752            4 :             }
    2753            4 :             prinbee::attachment a;
    2754            4 :             a.set_file(to_unlink);
    2755            4 :             CATCH_REQUIRE_FALSE(a.empty());
    2756            4 :             CATCH_REQUIRE(a.size() == static_cast<off_t>(content.length()));
    2757            4 :             CATCH_REQUIRE(a.is_file());
    2758            4 :             CATCH_REQUIRE(a.filename() == to_unlink);
    2759              : 
    2760            4 :             prinbee::in_event event;
    2761           12 :             event.set_request_id("unlinked");
    2762            4 :             event.add_attachment(a);
    2763              : 
    2764              :             // deleting the file before calling j.add_event()
    2765              :             //
    2766            4 :             CATCH_REQUIRE(unlink(to_unlink.c_str()) == 0);
    2767              : 
    2768              :             // the add fails as a result
    2769              :             //
    2770            4 :             snapdev::timespec_ex event_time(snapdev::now());
    2771            4 :             if(handling == prinbee::attachment_copy_handling_t::ATTACHMENT_COPY_HANDLING_SOFTLINK)
    2772              :             {
    2773              :                 // softlink does not require access to the original file so
    2774              :                 // the test passes in this case (oops?)
    2775              :                 //
    2776            1 :                 CATCH_REQUIRE(j.add_event(event, event_time));
    2777              :             }
    2778              :             else
    2779              :             {
    2780            3 :                 CATCH_REQUIRE_FALSE(j.add_event(event, event_time));
    2781              :             }
    2782            4 :         }
    2783              :     }
    2784           30 :     CATCH_END_SECTION()
    2785              : 
    2786           31 :     CATCH_START_SECTION("journal_errors: large attachment file destination is a directory")
    2787              :     {
    2788            1 :         prinbee::attachment_copy_handling_t const mode[] =
    2789              :         {
    2790              :             prinbee::attachment_copy_handling_t::ATTACHMENT_COPY_HANDLING_SOFTLINK,
    2791              :             prinbee::attachment_copy_handling_t::ATTACHMENT_COPY_HANDLING_HARDLINK,
    2792              :             prinbee::attachment_copy_handling_t::ATTACHMENT_COPY_HANDLING_REFLINK,
    2793              :             prinbee::attachment_copy_handling_t::ATTACHMENT_COPY_HANDLING_FULL,
    2794              :         };
    2795              : 
    2796            1 :         prinbee::attachment_offsets_t id(0);
    2797            5 :         for(auto const & handling : mode)
    2798              :         {
    2799           12 :             std::string const path(conf_path("journal_attachment_to_directory"));
    2800            4 :             advgetopt::conf_file::reset_conf_files();
    2801            4 :             prinbee::journal j(path);
    2802            4 :             j.set_attachment_copy_handling(handling);
    2803              : 
    2804              :             // create a large string so we go through the large file case
    2805              :             //
    2806            4 :             std::string const content(SNAP_CATCH2_NAMESPACE::random_string(
    2807              :                     prinbee::JOURNAL_INLINE_ATTACHMENT_SIZE_DEFAULT_THRESHOLD,
    2808              :                     prinbee::JOURNAL_INLINE_ATTACHMENT_SIZE_DEFAULT_THRESHOLD * 2,
    2809            4 :                     SNAP_CATCH2_NAMESPACE::character_t::CHARACTER_ZUNICODE));
    2810            4 :             std::string const to_unlink(SNAP_CATCH2_NAMESPACE::g_tmp_dir() + "/set_file-add_event-unlink-file.txt");
    2811              :             {
    2812            4 :                 std::ofstream out(to_unlink);
    2813            4 :                 CATCH_REQUIRE(out.is_open());
    2814            4 :                 out << content;
    2815            4 :             }
    2816            4 :             prinbee::attachment a;
    2817            4 :             a.set_file(to_unlink);
    2818            4 :             CATCH_REQUIRE_FALSE(a.empty());
    2819            4 :             CATCH_REQUIRE(a.size() == static_cast<off_t>(content.length()));
    2820            4 :             CATCH_REQUIRE(a.is_file());
    2821            4 :             CATCH_REQUIRE(a.filename() == to_unlink);
    2822              : 
    2823            4 :             prinbee::in_event event;
    2824           12 :             event.set_request_id("directory_as_destination");
    2825            4 :             event.add_attachment(a);
    2826              : 
    2827              :             // create a directory preventing creation of destination file
    2828              :             //
    2829              :             // note: we use the same directory so the sequence counter will
    2830              :             // continue to increase instead of using 1.bin each time
    2831              :             //
    2832            4 :             ++id;
    2833            4 :             std::string const dirname(path + "/" + std::to_string(id) + ".bin");
    2834           12 :             CATCH_REQUIRE(snapdev::mkdir_p(dirname.c_str()) == 0);
    2835              : 
    2836              :             // the add fails as a result
    2837              :             //
    2838            4 :             snapdev::timespec_ex event_time(snapdev::now());
    2839            4 :             CATCH_REQUIRE_FALSE(j.add_event(event, event_time));
    2840            4 :         }
    2841              :     }
    2842           30 :     CATCH_END_SECTION()
    2843              : 
    2844           31 :     CATCH_START_SECTION("journal_errors: large attachment buffer destination is a directory")
    2845              :     {
    2846            3 :         std::string const path(conf_path("journal_large_buffer_attachment_to_directory"));
    2847            1 :         advgetopt::conf_file::reset_conf_files();
    2848            1 :         prinbee::journal j(path);
    2849              : 
    2850              :         // create a large string so we go through the large file case
    2851              :         //
    2852            1 :         std::string const content(SNAP_CATCH2_NAMESPACE::random_string(
    2853              :                 prinbee::JOURNAL_INLINE_ATTACHMENT_SIZE_DEFAULT_THRESHOLD,
    2854              :                 prinbee::JOURNAL_INLINE_ATTACHMENT_SIZE_DEFAULT_THRESHOLD * 2,
    2855            1 :                 SNAP_CATCH2_NAMESPACE::character_t::CHARACTER_ZUNICODE));
    2856            1 :         prinbee::attachment a;
    2857            1 :         a.set_data(const_cast<char *>(content.data()), content.size());
    2858            1 :         CATCH_REQUIRE_FALSE(a.empty());
    2859            1 :         CATCH_REQUIRE(a.size() == static_cast<off_t>(content.length()));
    2860            1 :         CATCH_REQUIRE_FALSE(a.is_file());
    2861            1 :         CATCH_REQUIRE(a.filename() == "");
    2862              : 
    2863            1 :         prinbee::in_event event;
    2864            3 :         event.set_request_id("directory_as_destination");
    2865            1 :         event.add_attachment(a);
    2866              : 
    2867              :         // create a directory preventing creation of destination file
    2868              :         //
    2869            1 :         std::string const dirname(path + "/1.bin");
    2870            3 :         CATCH_REQUIRE(snapdev::mkdir_p(dirname.c_str()) == 0);
    2871              : 
    2872              :         // the add fails as a result
    2873              :         //
    2874            1 :         snapdev::timespec_ex event_time(snapdev::now());
    2875            1 :         CATCH_REQUIRE_FALSE(j.add_event(event, event_time));
    2876            1 :     }
    2877           30 :     CATCH_END_SECTION()
    2878              : 
    2879           31 :     CATCH_START_SECTION("journal_errors: large attachment file shorten before added to journal in FULL copy mode")
    2880              :     {
    2881            3 :         std::string const path(conf_path("journal_shorten_large_attachment"));
    2882            1 :         advgetopt::conf_file::reset_conf_files();
    2883            1 :         prinbee::journal j(path);
    2884            1 :         j.set_attachment_copy_handling(prinbee::attachment_copy_handling_t::ATTACHMENT_COPY_HANDLING_FULL);
    2885              : 
    2886              :         // create a large string so we go through the large file case
    2887              :         //
    2888            1 :         std::string const content(SNAP_CATCH2_NAMESPACE::random_string(
    2889              :                 prinbee::JOURNAL_INLINE_ATTACHMENT_SIZE_DEFAULT_THRESHOLD,
    2890              :                 prinbee::JOURNAL_INLINE_ATTACHMENT_SIZE_DEFAULT_THRESHOLD * 2,
    2891            1 :                 SNAP_CATCH2_NAMESPACE::character_t::CHARACTER_ZUNICODE));
    2892            1 :         std::string const to_unlink(SNAP_CATCH2_NAMESPACE::g_tmp_dir() + "/set_file-add_event-unlink-file.txt");
    2893              :         {
    2894            1 :             std::ofstream out(to_unlink);
    2895            1 :             CATCH_REQUIRE(out.is_open());
    2896            1 :             out << content;
    2897            1 :         }
    2898            1 :         prinbee::attachment a;
    2899            1 :         a.set_file(to_unlink);
    2900            1 :         CATCH_REQUIRE_FALSE(a.empty());
    2901            1 :         CATCH_REQUIRE(a.size() == static_cast<off_t>(content.length()));
    2902            1 :         CATCH_REQUIRE(a.is_file());
    2903            1 :         CATCH_REQUIRE(a.filename() == to_unlink);
    2904              : 
    2905            1 :         prinbee::in_event event;
    2906            3 :         event.set_request_id("shorten");
    2907            1 :         event.add_attachment(a);
    2908              : 
    2909              :         // shortening the file before calling j.add_event()
    2910              :         //
    2911            1 :         CATCH_REQUIRE(truncate(to_unlink.c_str(), content.length() / 2) == 0);
    2912              : 
    2913              :         // the add fails as a result
    2914              :         //
    2915            1 :         snapdev::timespec_ex event_time(snapdev::now());
    2916            1 :         CATCH_REQUIRE_FALSE(j.add_event(event, event_time));
    2917            1 :     }
    2918           30 :     CATCH_END_SECTION()
    2919              : 
    2920           31 :     CATCH_START_SECTION("journal_errors: special file cannot be used")
    2921              :     {
    2922            1 :         prinbee::attachment a;
    2923            7 :         CATCH_REQUIRE_THROWS_MATCHES(
    2924              :               a.set_file("/dev/null")
    2925              :             , prinbee::invalid_parameter
    2926              :             , Catch::Matchers::ExceptionMessage(
    2927              :                         "prinbee_exception: file \"/dev/null\" does not represent a regular file."));
    2928            1 :     }
    2929           30 :     CATCH_END_SECTION()
    2930              : 
    2931           31 :     CATCH_START_SECTION("journal_errors: directories cannot be used")
    2932              :     {
    2933            1 :         prinbee::attachment a;
    2934            7 :         CATCH_REQUIRE_THROWS_MATCHES(
    2935              :               a.set_file("/usr/bin")
    2936              :             , prinbee::invalid_parameter
    2937              :             , Catch::Matchers::ExceptionMessage(
    2938              :                         "prinbee_exception: file \"/usr/bin\" does not represent a regular file."));
    2939            1 :     }
    2940           30 :     CATCH_END_SECTION()
    2941              : 
    2942           31 :     CATCH_START_SECTION("journal_errors: add too many attachments (in)")
    2943              :     {
    2944              :         // create a journal
    2945              :         //
    2946            3 :         std::string const path(conf_path("journal_events"));
    2947            1 :         advgetopt::conf_file::reset_conf_files();
    2948            1 :         prinbee::journal j(path);
    2949            1 :         CATCH_REQUIRE(j.is_valid());
    2950            1 :         prinbee::in_event event;
    2951              : 
    2952              :         // add the maximum number of attachments
    2953              :         //
    2954          256 :         for(std::size_t count(0); count < prinbee::MAXIMUM_ATTACHMENT_COUNT; ++count)
    2955              :         {
    2956        32895 :             for(std::size_t id(count); id < prinbee::MAXIMUM_ATTACHMENT_COUNT; ++id)
    2957              :             {
    2958        97920 :                 CATCH_REQUIRE_THROWS_MATCHES(
    2959              :                           event.get_attachment(id)
    2960              :                         , prinbee::out_of_range
    2961              :                         , Catch::Matchers::ExceptionMessage(
    2962              :                                     "out_of_range: identifier out of range retrieving attachment from in_event."));
    2963              :             }
    2964              : 
    2965          255 :             prinbee::attachment a;
    2966          255 :             std::size_t const size(rand() % 25 + 1);
    2967          765 :             std::vector<std::uint8_t> data(size);
    2968         3573 :             for(std::size_t idx(0); idx < size; ++idx)
    2969              :             {
    2970         3318 :                 data[idx] = static_cast<std::uint8_t>(rand());
    2971              :             }
    2972          255 :             a.set_data(data.data(), size);
    2973          255 :             event.add_attachment(a);
    2974          255 :         }
    2975              : 
    2976              :         // try to add one more attachment, that must fail
    2977              :         //
    2978              :         {
    2979            1 :             prinbee::attachment a;
    2980            1 :             std::size_t const size(rand() % 25 + 1);
    2981            3 :             std::vector<std::uint8_t> data(size);
    2982           25 :             for(std::size_t idx(0); idx < size; ++idx)
    2983              :             {
    2984           24 :                 data[idx] = static_cast<std::uint8_t>(rand());
    2985              :             }
    2986            1 :             a.set_data(data.data(), size);
    2987              : 
    2988            3 :             CATCH_REQUIRE_THROWS_MATCHES(
    2989              :                       event.add_attachment(a)
    2990              :                     , prinbee::full
    2991              :                     , Catch::Matchers::ExceptionMessage(
    2992              :                                 "prinbee_exception: attachment table is full, this attachment cannot be added (in_event)."));
    2993            1 :         }
    2994            1 :     }
    2995           30 :     CATCH_END_SECTION()
    2996              : 
    2997           31 :     CATCH_START_SECTION("journal_errors: add too many attachments (out)")
    2998              :     {
    2999              :         // create a journal
    3000              :         //
    3001            3 :         std::string const path(conf_path("journal_events"));
    3002            1 :         advgetopt::conf_file::reset_conf_files();
    3003            1 :         prinbee::journal j(path);
    3004            1 :         CATCH_REQUIRE(j.is_valid());
    3005            1 :         prinbee::out_event event;
    3006              : 
    3007              :         // add the maximum number of attachments
    3008              :         //
    3009          256 :         for(std::size_t count(0); count < prinbee::MAXIMUM_ATTACHMENT_COUNT; ++count)
    3010              :         {
    3011        32895 :             for(std::size_t id(count); id < prinbee::MAXIMUM_ATTACHMENT_COUNT; ++id)
    3012              :             {
    3013        97920 :                 CATCH_REQUIRE_THROWS_MATCHES(
    3014              :                           event.get_attachment(id)
    3015              :                         , prinbee::out_of_range
    3016              :                         , Catch::Matchers::ExceptionMessage(
    3017              :                                     "out_of_range: identifier out of range retrieving attachment from out_event."));
    3018              :             }
    3019              : 
    3020          255 :             prinbee::attachment a;
    3021          255 :             std::size_t const size(rand() % 25 + 1);
    3022          765 :             std::vector<std::uint8_t> data(size);
    3023         3700 :             for(std::size_t idx(0); idx < size; ++idx)
    3024              :             {
    3025         3445 :                 data[idx] = static_cast<std::uint8_t>(rand());
    3026              :             }
    3027          255 :             a.set_data(data.data(), size);
    3028          255 :             event.add_attachment(a);
    3029          255 :         }
    3030              : 
    3031              :         // try to add one more attachment, that must fail
    3032              :         //
    3033              :         {
    3034            1 :             prinbee::attachment a;
    3035            1 :             std::size_t const size(rand() % 25 + 1);
    3036            3 :             std::vector<std::uint8_t> data(size);
    3037           22 :             for(std::size_t idx(0); idx < size; ++idx)
    3038              :             {
    3039           21 :                 data[idx] = static_cast<std::uint8_t>(rand());
    3040              :             }
    3041            1 :             a.set_data(data.data(), size);
    3042              : 
    3043            3 :             CATCH_REQUIRE_THROWS_MATCHES(
    3044              :                       event.add_attachment(a)
    3045              :                     , prinbee::full
    3046              :                     , Catch::Matchers::ExceptionMessage(
    3047              :                                 "prinbee_exception: attachment table is full, this attachment cannot be added (out_event)."));
    3048            1 :         }
    3049            1 :     }
    3050           30 :     CATCH_END_SECTION()
    3051           29 : }
    3052              : 
    3053              : 
    3054              : // vim: ts=4 sw=4 et
        

Generated by: LCOV version 2.0-1

Snap C++ | List of projects | List of versions