LCOV - code coverage report
Current view: top level - /opt/artdaq/srcs/artdaq-database/test/StorageProviders/MongoJson - MongoJson_t.cc (source / functions) Coverage Total Hit
Test: artdaq.info.cleaned Lines: 76.1 % 230 175
Test Date: 2026-10-29 00:35:58 Functions: 100.0 % 7 7

            Line data    Source code
       1              : #include "artdaq-database/BasicTypes/basictypes.h"
       2              : #include "test/common.h"
       3              : 
       4              : #include "artdaq-database/JsonDocument/JSONDocument.h"
       5              : #include "artdaq-database/JsonDocument/JSONDocumentBuilder.h"
       6              : #include "artdaq-database/StorageProviders/MongoDB/provider_mongodb.h"
       7              : #include "artdaq-database/StorageProviders/storage_providers.h"
       8              : 
       9              : #include <bsoncxx/json.hpp>
      10              : 
      11              : namespace bpo = boost::program_options;
      12              : using namespace artdaq::database;
      13              : 
      14              : using artdaq::database::docrecord::JSONDocument;
      15              : using artdaq::database::docrecord::JSONDocumentBuilder;
      16              : namespace ovl = artdaq::database::overlay;
      17              : 
      18              : using test_case = bool (*)(const std::string&, const std::string&, const std::string&);
      19              : 
      20              : bool test_insert(std::string const& /*source*/, std::string const& /*compare*/, std::string const& /*filter*/);
      21              : bool test_search1(std::string const& /*source*/, std::string const& /*compare*/, std::string const& /*filter*/);
      22              : bool test_search2(std::string const& /*source*/, std::string const& /*compare*/, std::string const& /*options*/);
      23              : bool test_update(std::string const& /*source*/, std::string const& /*compare*/, std::string const& /*update*/);
      24              : bool test_search_collection(std::string const& /*source*/, std::string const& /*compare*/, std::string const& /*options*/);
      25              : 
      26            5 : int main(int argc, char* argv[]) try {
      27            5 :   artdaq::database::mongo::debug::enable();
      28              :   //  artdaq::database::docrecord::debug::JSONDocument();
      29              : 
      30            5 :   debug::registerUngracefullExitHandlers();
      31            5 :   artdaq::database::useFakeTime(true);
      32              : 
      33            5 :   std::ostringstream descstr;
      34              :   descstr << argv[0]
      35              :           << " <-s <source-file>> <-c <compare-with-file>> <-t <test-name>> [<-o <options file>>] "
      36            5 :              "(available test names: insert,search1,search1,update)";
      37              : 
      38            5 :   bpo::options_description desc = descstr.str();
      39              : 
      40            5 :   desc.add_options()("source,s", bpo::value<std::string>(), "Input source file.")("compare,c", bpo::value<std::string>(), "Expected result.")(
      41            5 :       "testname,t", bpo::value<std::string>(), "Test name.")("options,o", bpo::value<std::string>(), "Test options file.")
      42              : 
      43            5 :       ("help,h", "produce help message");
      44              : 
      45            5 :   bpo::variables_map vm;
      46              : 
      47              :   try {
      48            5 :     bpo::store(bpo::command_line_parser(argc, argv).options(desc).run(), vm);
      49            5 :     bpo::notify(vm);
      50            0 :   } catch (bpo::error const& e) {
      51            0 :     std::cerr << "Exception from command line processing in " << argv[0] << ": " << e.what() << "\n";
      52            0 :     return process_exit_code::INVALID_ARGUMENT;
      53            0 :   }
      54              : 
      55           10 :   if (vm.count("help") != 0u) {
      56            0 :     std::cout << desc << std::endl;
      57            0 :     return process_exit_code::HELP;
      58              :   }
      59              : 
      60           10 :   if (vm.count("source") == 0u) {
      61              :     std::cerr << "Exception from command line processing in " << argv[0] << ": no source file given.\n"
      62              :               << "For usage and an options list, please do '" << argv[0] << " --help"
      63            0 :               << "'.\n";
      64            0 :     return process_exit_code::INVALID_ARGUMENT | 1;
      65              :   }
      66              : 
      67           10 :   if (vm.count("compare") == 0u) {
      68              :     std::cerr << "Exception from command line processing in " << argv[0] << ": no compare file given.\n"
      69              :               << "For usage and an options list, please do '" << argv[0] << " --help"
      70            0 :               << "'.\n";
      71            0 :     return process_exit_code::INVALID_ARGUMENT | 2;
      72              :   }
      73              : 
      74           10 :   if (vm.count("testname") == 0u) {
      75              :     std::cerr << "Exception from command line processing in " << argv[0] << ": no test name given.\n"
      76              :               << "For usage and an options list, please do '" << argv[0] << " --help"
      77            0 :               << "'.\n";
      78            0 :     return process_exit_code::INVALID_ARGUMENT | 3;
      79              :   }
      80              : 
      81           10 :   auto input_name = vm["source"].as<std::string>();
      82           10 :   auto compare_name = vm["compare"].as<std::string>();
      83            5 :   auto test_name = vm["testname"].as<std::string>();
      84              : 
      85            5 :   auto input = std::string{};
      86            5 :   db::read_buffer_from_file(input, input_name);
      87              : 
      88            5 :   auto compare = std::string{};
      89            5 :   db::read_buffer_from_file(compare, compare_name);
      90              : 
      91            5 :   auto options = std::string();
      92              : 
      93           10 :   if (vm.count("options") != 0u) {
      94            3 :     auto opts_name = vm["options"].as<std::string>();
      95              : 
      96            3 :     db::read_buffer_from_file(options, opts_name);
      97            3 :   }
      98              : 
      99            5 :   auto runTest = [](std::string const& name) {
     100              :     auto tests = std::map<std::string, test_case>{
     101              :         {"insert", test_insert},
     102              :         {"update", test_update},
     103              :         {"search1", test_search1},
     104              :         {"search2", test_search2},
     105              :         {"search_collection", test_search_collection},
     106           35 :     };
     107              : 
     108            5 :     std::cout << "Running test:<" << name << ">\n";
     109              : 
     110           10 :     return tests.at(name);
     111           10 :   };
     112              : 
     113            5 :   auto testResult = runTest(test_name)(input, compare, options);
     114              : 
     115            5 :   if (testResult) {
     116            5 :     return process_exit_code::SUCCESS;
     117              :   }
     118              : 
     119            0 :   return process_exit_code::FAILURE;
     120            5 : } catch (...) {
     121            0 :   std::cerr << "Process exited with error: " << ::debug::current_exception_diagnostic_information();
     122            0 :   return process_exit_code::UNCAUGHT_EXCEPTION;
     123            0 : }
     124              : 
     125            1 : bool test_insert(std::string const& source, std::string const& compare, std::string const& filter) {
     126            1 :   confirm(!source.empty());
     127            1 :   confirm(!compare.empty());
     128              : 
     129              :   // validate source
     130            1 :   auto insert = JSONDocument(source);
     131              : 
     132              :   // validate compare
     133            1 :   auto cmpdoc = JSONDocument(compare);
     134              : 
     135              :   using artdaq::database::basictypes::JsonData;
     136              : 
     137              :   namespace DBI = artdaq::database::mongo;
     138              : 
     139            1 :   auto config = DBI::DBConfig{};
     140            1 :   auto database = DBI::DB::create(config);
     141            1 :   auto provider = DBI::DBProvider<JSONDocument>::create(database);
     142              : 
     143            1 :   auto collection = std::string("testJSON_V001");
     144              : 
     145            1 :   auto json = JSONDocument{"{\"document\":" + insert.to_string() + ", \"collection\":\"" + collection + "\"}"};
     146              : 
     147            1 :   auto object_id = provider->writeDocument(json);
     148              : 
     149            1 :   auto search = JSONDocument{"{\"filter\":" + (filter.empty() ? object_id : filter) + ", \"collection\":\"" + collection + "\"}"};
     150              : 
     151            1 :   std::cout << "Search criteria " << search << "\n";
     152              : 
     153            1 :   auto results = provider->readDocument(search);
     154              : 
     155            1 :   if (results.size() != 1) {
     156            0 :     std::cout << "Search returned " << results.size() << " results.\n";
     157              : 
     158            0 :     for (auto&& element : results) {
     159            0 :       std::cout << element << "\n";
     160              :     }
     161            0 :     return false;
     162              :   }
     163              : 
     164            1 :   auto retdoc = JSONDocument{*results.begin()};
     165            1 :   JSONDocumentBuilder returned{retdoc};
     166            1 :   JSONDocumentBuilder expected{cmpdoc};
     167              : 
     168              :   using namespace artdaq::database::overlay;
     169            1 :   ovl::useCompareMask(DOCUMENT_COMPARE_MUTE_TIMESTAMPS | DOCUMENT_COMPARE_MUTE_OUIDS | DOCUMENT_COMPARE_MUTE_UPDATES |
     170              :                       DOCUMENT_COMPARE_MUTE_COLLECTION);
     171              : 
     172            1 :   auto result = returned == expected;
     173              : 
     174            1 :   if (result.first) {
     175            1 :     return true;
     176              :   }
     177              : 
     178            0 :   std::cout << "Error returned!=expected.\n";
     179            0 :   std::cerr << "returned:\n" << returned << "\n";
     180            0 :   std::cerr << "expected:\n" << expected << "\n";
     181            0 :   std::cerr << "error:\n" << result.second << "\n";
     182            0 :   return false;
     183            1 : }
     184              : 
     185            1 : bool test_search1(std::string const& source, std::string const& compare, std::string const& filter) {
     186            1 :   confirm(!source.empty());
     187            1 :   confirm(!compare.empty());
     188              : 
     189              :   // validate source
     190            1 :   auto insert = JSONDocument(source);
     191              : 
     192              :   // validate compare
     193            1 :   auto cmpdoc = JSONDocument(compare);
     194              : 
     195              :   using artdaq::database::docrecord::JSONDocument;
     196              : 
     197              :   namespace DBI = artdaq::database::mongo;
     198              : 
     199            1 :   auto config = DBI::DBConfig{};
     200            1 :   auto database = DBI::DB::create(config);
     201            1 :   auto provider = DBI::DBProvider<JSONDocument>::create(database);
     202              : 
     203            1 :   auto collection = std::string("testJSON_V001");
     204              : 
     205            1 :   auto json = JSONDocument{"{\"document\":" + insert.to_string() + ", \"collection\":\"" + collection + "\"}"};
     206              : 
     207            1 :   auto object_id = provider->writeDocument(json);
     208              : 
     209            1 :   auto search = JSONDocument{"{\"filter\":" + (filter.empty() ? object_id : filter) + ", \"collection\":\"" + collection + "\"}"};
     210              : 
     211            1 :   std::cout << "Search criteria " << search << "\n";
     212              : 
     213            1 :   auto results = provider->readDocument(search);
     214              : 
     215            1 :   if (results.size() != 1) {
     216            0 :     std::cout << "Search returned " << results.size() << " results.\n";
     217              : 
     218            0 :     for (auto&& element : results) {
     219            0 :       std::cout << element << "\n";
     220              :     }
     221            0 :     return false;
     222              :   }
     223              : 
     224            1 :   auto retdoc = JSONDocument{*results.begin()};
     225            1 :   JSONDocumentBuilder returned{retdoc};
     226            1 :   JSONDocumentBuilder expected{cmpdoc};
     227              : 
     228              :   using namespace artdaq::database::overlay;
     229            1 :   ovl::useCompareMask(DOCUMENT_COMPARE_MUTE_TIMESTAMPS | DOCUMENT_COMPARE_MUTE_OUIDS | DOCUMENT_COMPARE_MUTE_UPDATES |
     230              :                       DOCUMENT_COMPARE_MUTE_COLLECTION);
     231              : 
     232            1 :   auto result = returned == expected;
     233              : 
     234            1 :   if (result.first) {
     235            1 :     return true;
     236              :   }
     237              : 
     238            0 :   std::cout << "Error returned!=expected.\n";
     239            0 :   std::cerr << "returned:\n" << returned << "\n";
     240            0 :   std::cerr << "expected:\n" << expected << "\n";
     241            0 :   std::cerr << "error:\n" << result.second << "\n";
     242            0 :   return false;
     243            1 : }
     244              : 
     245            1 : bool test_search2(std::string const& source, std::string const& compare, std::string const& options [[gnu::unused]]) {
     246            1 :   confirm(!source.empty());
     247            1 :   confirm(!compare.empty());
     248              : 
     249              :   using artdaq::database::docrecord::JSONDocument;
     250              : 
     251              :   namespace DBI = artdaq::database::mongo;
     252              : 
     253            1 :   auto config = DBI::DBConfig{};
     254            1 :   auto database = DBI::DB::create(config);
     255            1 :   auto provider = DBI::DBProvider<JSONDocument>::create(database);
     256              : 
     257            1 :   auto collection = std::string("testJSON_V001");
     258              : 
     259            1 :   auto json = JSONDocument{"{\"document\":" + source + ", \"collection\":\"" + collection + "\"}"};
     260              : 
     261            1 :   auto repeatCount = std::size_t{10};
     262              : 
     263            1 :   auto object_ids = std::vector<std::string>();
     264              : 
     265            1 :   std::ostringstream oss;
     266            1 :   oss << R"({"_id" : { "$in" : [)";
     267              : 
     268            1 :   auto nodata_pos = oss.tellp();
     269              : 
     270           11 :   for (int i = repeatCount; i != 0; i--) {
     271           10 :     auto object_id = provider->writeDocument(json);
     272           10 :     object_ids.push_back(object_id);
     273           30 :     oss << JSONDocument(object_id).findChildDocument("_id").to_string() << ",";
     274           10 :   }
     275              : 
     276            1 :   if (oss.tellp() != nodata_pos) {
     277            1 :     oss.seekp(-1, oss.cur);
     278              :   }
     279              : 
     280            1 :   oss << "]} }";
     281              : 
     282            1 :   auto filter = oss.str();
     283              : 
     284            1 :   auto search = JSONDocument{"{\"filter\":" + (filter.empty() ? options : filter) + ", \"collection\":\"" + collection + "\"}"};
     285              : 
     286            1 :   std::cout << "Search criteria " << search << "\n";
     287              : 
     288            1 :   auto results = provider->readDocument(search);
     289              : 
     290            1 :   if (results.size() != repeatCount) {
     291            0 :     std::cout << "Search returned " << results.size() << " results.\n";
     292              : 
     293            0 :     for (auto&& element : results) {
     294            0 :       std::cout << element << "\n";
     295              :     }
     296            0 :     return false;
     297              :   }
     298              : 
     299            1 :   return true;
     300            1 : }
     301              : 
     302            1 : bool test_search_collection(std::string const& source, std::string const& compare, std::string const& options [[gnu::unused]]) {
     303            1 :   confirm(!source.empty());
     304            1 :   confirm(!compare.empty());
     305              : 
     306              :   using artdaq::database::docrecord::JSONDocument;
     307              : 
     308              :   namespace DBI = artdaq::database::mongo;
     309              : 
     310            1 :   auto config = DBI::DBConfig{};
     311            1 :   auto database = DBI::DB::create(config);
     312            1 :   auto provider = DBI::DBProvider<JSONDocument>::create(database);
     313              : 
     314            1 :   auto collection = std::string("testJSON_V002");
     315              : 
     316            1 :   auto repeatCount = std::size_t{5};
     317              : 
     318            1 :   auto object_ids = std::vector<std::string>();
     319              : 
     320            1 :   std::ostringstream oss;
     321            1 :   oss << R"({"_id" : { "$in" : [)";
     322              : 
     323            1 :   auto nodata_pos = oss.tellp();
     324              : 
     325            6 :   for (int i = repeatCount; i != 0; i--) {
     326            5 :     auto version_str = "version_search_" + std::to_string(i);
     327            5 :     auto json = JSONDocument{"{\"document\":" + source + ", \"version\":\"" + version_str + "\", \"collection\":\"" + collection + "\"}"};
     328            5 :     auto object_id = provider->writeDocument(json);
     329            5 :     object_ids.push_back(object_id);
     330           15 :     oss << JSONDocument(object_id).findChildDocument("_id").to_string() << ",";
     331            5 :   }
     332              : 
     333            1 :   if (oss.tellp() != nodata_pos) {
     334            1 :     oss.seekp(-1, oss.cur);
     335              :   }
     336              : 
     337            1 :   oss << "]} }";
     338              : 
     339            1 :   auto filter = oss.str();
     340              : 
     341            1 :   auto search = JSONDocument{"{\"filter\":" + (options.empty() ? filter : options) + ", \"collection\":\"" + collection + "\"}"};
     342              : 
     343            1 :   std::cout << "Search criteria " << search << "\n";
     344              : 
     345            1 :   auto results = provider->searchCollection(search);
     346              : 
     347            1 :   if (results.size() != repeatCount) {
     348            0 :     std::cout << "Search returned " << results.size() << " results.\n";
     349              : 
     350            0 :     for (auto&& element : results) {
     351            0 :       std::cout << element << "\n";
     352              :     }
     353            0 :     return false;
     354              :   }
     355              : 
     356            1 :   return true;
     357            1 : }
     358              : 
     359            1 : bool test_update(std::string const& source, std::string const& compare, std::string const& update) {
     360            1 :   confirm(!source.empty());
     361            1 :   confirm(!compare.empty());
     362              : 
     363              :   // validate source
     364            1 :   auto insert = JSONDocument(source);
     365              : 
     366              :   // validate compare
     367            1 :   auto cmpdoc = JSONDocument(compare);
     368              : 
     369            1 :   auto updates = JSONDocument(update);
     370              : 
     371              :   using artdaq::database::docrecord::JSONDocument;
     372              : 
     373              :   namespace DBI = artdaq::database::mongo;
     374              : 
     375            1 :   auto config = DBI::DBConfig{};
     376            1 :   auto database = DBI::DB::create(config);
     377            1 :   auto provider = DBI::DBProvider<JSONDocument>::create(database);
     378              : 
     379            1 :   auto collection = std::string("testJSON_V001");
     380              : 
     381            1 :   auto json = JSONDocument{"{\"document\":" + insert.to_string() + ", \"collection\":\"" + collection + "\"}"};
     382              : 
     383            1 :   auto object_id = provider->writeDocument(json);
     384              : 
     385            1 :   auto search = JSONDocument{"{\"filter\":" + object_id + ", \"collection\":\"" + collection + "\"}"};
     386              : 
     387            1 :   std::cout << "Search criteria " << search << "\n";
     388              : 
     389            1 :   auto results = provider->readDocument(search);
     390              : 
     391            1 :   if (results.size() != 1) {
     392            0 :     std::cout << "Search returned " << results.size() << " results.\n";
     393              : 
     394            0 :     for (auto&& element : results) {
     395            0 :       std::cout << element << "\n";
     396              :     }
     397            0 :     return false;
     398              :   }
     399              : 
     400            1 :   auto found = JSONDocument{*results.begin()};
     401              : 
     402            1 :   std::cout << "Update candidate=<" << found.to_string() << ">\n";
     403            1 :   auto displaced = found.replaceChild(updates, "document");
     404            1 :   std::cout << "Update result=<" << found.to_string() << ">\n";
     405            1 :   std::cout << "Displaced value=<" << displaced.to_string() << ">\n";
     406              : 
     407            1 :   json = JSONDocument{"{\"document\":" + found.to_string() + ", \"filter\":" + object_id + ",\"collection\":\"" + collection + "\"}"};
     408              : 
     409            1 :   object_id = provider->writeDocument(json);
     410            1 :   search = JSONDocument{"{\"filter\":" + object_id + ", \"collection\":\"" + collection + "\"}"};
     411              : 
     412            1 :   results = provider->readDocument(search);
     413              : 
     414            1 :   if (results.size() != 1) {
     415            0 :     std::cout << "Search returned " << results.size() << " results.\n";
     416              : 
     417            0 :     for (auto&& element : results) {
     418            0 :       std::cout << element << "\n";
     419              :     }
     420            0 :     return false;
     421              :   }
     422              : 
     423            1 :   auto retdoc = JSONDocument{*results.begin()};
     424              : 
     425            1 :   JSONDocumentBuilder returned{retdoc};
     426            1 :   JSONDocumentBuilder expected{cmpdoc};
     427              : 
     428              :   using namespace artdaq::database::overlay;
     429            1 :   ovl::useCompareMask(DOCUMENT_COMPARE_MUTE_TIMESTAMPS | DOCUMENT_COMPARE_MUTE_OUIDS | DOCUMENT_COMPARE_MUTE_UPDATES |
     430              :                       DOCUMENT_COMPARE_MUTE_COLLECTION);
     431              : 
     432            1 :   auto result = returned == expected;
     433              : 
     434            1 :   if (result.first) {
     435            1 :     return true;
     436              :   }
     437              : 
     438            0 :   std::cout << "Error returned!=expected.\n";
     439            0 :   std::cerr << "returned:\n" << returned << "\n";
     440            0 :   std::cerr << "expected:\n" << expected << "\n";
     441            0 :   std::cerr << "error:\n" << result.second << "\n";
     442            0 :   return false;
     443            1 : }
        

Generated by: LCOV version 2.0-1