LCOV - code coverage report
Current view: top level - tests - catch_journal.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1565 1606 97.4 %
Date: 2024-02-03 18:59:18 Functions: 13 13 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14

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