LCOV - code coverage report
Current view: top level - /opt/artdaq/srcs/artdaq-database/test/ConfigurationDB - ConfigurationDB_t.cc (source / functions) Coverage Total Hit
Test: artdaq.info.cleaned Lines: 45.5 % 121 55
Test Date: 2026-10-29 00:35:58 Functions: 66.7 % 3 2

            Line data    Source code
       1              : #include "test/common.h"
       2              : 
       3              : #include "artdaq-database/ConfigurationDB/common.h"
       4              : #include "artdaq-database/ConfigurationDB/conftoolifc.h"
       5              : 
       6              : #include "artdaq-database/BasicTypes/basictypes.h"
       7              : #include "artdaq-database/DataFormats/Json/json_reader.h"
       8              : #include "artdaq-database/DataFormats/Json/presort_json.h"
       9              : #include "artdaq-database/JsonDocument/JSONDocument.h"
      10              : #include "artdaq-database/JsonDocument/JSONDocumentBuilder.h"
      11              : 
      12              : #include <fstream>
      13              : 
      14              : namespace db = artdaq::database;
      15              : namespace bpo = boost::program_options;
      16              : namespace impl = db::configuration::json;
      17              : 
      18              : using artdaq::database::docrecord::JSONDocument;
      19              : using artdaq::database::docrecord::JSONDocumentBuilder;
      20              : namespace ovl = artdaq::database::overlay;
      21              : 
      22              : namespace apiliteral = db::configapi::literal;
      23              : 
      24              : // Helper function to write content to a file
      25            0 : bool write_to_file(const std::string& filename, const std::string& content) {
      26            0 :   std::ofstream outfile(filename);
      27              : 
      28            0 :   if (!outfile.is_open()) {
      29            0 :     std::cerr << "ERROR: Failed to open file for writing: " << filename << "\n";
      30            0 :     return false;
      31              :   }
      32              : 
      33            0 :   outfile << content;
      34            0 :   outfile.close();
      35              : 
      36            0 :   std::cout << "Debug file written: " << filename << "\n";
      37            0 :   return true;
      38            0 : }
      39              : 
      40          112 : int main(int argc, char* argv[]) try {
      41              : #if 1
      42              : 
      43          112 :   impl::enable_trace();
      44              : 
      45          112 :   debug::registerUngracefullExitHandlers();
      46              :   // artdaq::database::useFakeTime(true);
      47              : #endif
      48              : 
      49          112 :   std::unique_ptr<db::configuration::OperationBase> options = std::make_unique<db::configuration::OperationBase>("ConfigurationDB_t");
      50              :   // artdaq::database::filesystem::index::shouldAutoRebuildSearchIndex(true);
      51              : 
      52          336 :   auto make_opt_name = [](auto& long_name, auto& short_name) { return std::string{long_name}.append(",").append(short_name); };
      53              : 
      54          112 :   bpo::variables_map vm;
      55              : 
      56          112 :   bpo::options_description opts;
      57          112 :   opts.add_options()("help,h", "Produce help message");
      58          112 :   opts.add_options()(make_opt_name(apiliteral::option::operation, "o").c_str(), bpo::value<std::string>(), "Operation");
      59              : 
      60              :   try {
      61          112 :     bpo::store(bpo::command_line_parser(argc, argv).options(opts).allow_unregistered().run(), vm);
      62          112 :     bpo::notify(vm);
      63            0 :   } catch (bpo::error const& e) {
      64            0 :     std::cerr << "Exception from command line processing in " << options->processName() << ": " << e.what() << "\n";
      65            0 :     return process_exit_code::INVALID_ARGUMENT;
      66            0 :   }
      67              : 
      68          224 :   if (vm.count("help") != 0u) {
      69            0 :     std::cerr << opts << std::endl;
      70            0 :     return process_exit_code::HELP;
      71              :   }
      72              : 
      73          224 :   if (vm.count(apiliteral::option::operation) == 0u) {
      74            0 :     std::cerr << "Operation option is missing\n";
      75            0 :     std::cerr << opts << std::endl;
      76              : 
      77            0 :     return process_exit_code::INVALID_ARGUMENT;
      78              :   }
      79              : 
      80          112 :   auto opname = vm[apiliteral::option::operation].as<std::string>();
      81              : 
      82          112 :   if (opname == apiliteral::operation::addversionalias || opname == apiliteral::operation::rmversionalias) {
      83            4 :     options = std::make_unique<db::configuration::ManageAliasesOperation>(argv[0]);
      84          108 :   } else if (opname == apiliteral::operation::findconfigs) {
      85            4 :     options = std::make_unique<db::configuration::ManageConfigsOperation>(argv[0]);
      86              :   } else {
      87          104 :     options = std::make_unique<db::configuration::ManageDocumentOperation>(argv[0]);
      88              :   }
      89              : 
      90          112 :   auto result = db::conftool_impl(options, argc, argv);
      91              : 
      92          112 :   if (!result.first) {
      93            0 :     std::cout << "Failed; error message: " << result.second << "\n";
      94            0 :     std::cout << ::debug::current_exception_diagnostic_information();
      95            0 :     return process_exit_code::FAILURE;
      96              :   }
      97              : 
      98          112 :   auto returned = std::string{result.second};
      99          112 :   if (!result.first) {
     100            0 :     std::cout << "Test failed; error message: " << result.second << "\n";
     101            0 :     std::cout << ::debug::current_exception_diagnostic_information();
     102            0 :     return process_exit_code::FAILURE;
     103              :   }
     104              : 
     105          112 :   if (result.second.empty()) {
     106              :     std::cout << "Test failed; error message: result is empty."
     107            0 :               << "\n";
     108            0 :     return process_exit_code::FAILURE;
     109              :   }
     110              : 
     111          112 :   auto retdoc = std::string{result.second};
     112              : 
     113          112 :   auto cmpdoc = std::string{};
     114          112 :   db::read_buffer_from_file(cmpdoc, options->resultFileName());
     115              : 
     116              :   using cfo::data_format_t;
     117              : 
     118          112 :   if (options->format() == data_format_t::db) {
     119           12 :     auto rdoc = JSONDocument{retdoc};
     120           12 :     auto cdoc = JSONDocument{cmpdoc};
     121           12 :     JSONDocumentBuilder returned{rdoc};
     122           12 :     JSONDocumentBuilder expected{cdoc};
     123              : 
     124              :     using namespace artdaq::database::overlay;
     125           12 :     ovl::useCompareMask(DOCUMENT_COMPARE_MUTE_TIMESTAMPS | DOCUMENT_COMPARE_MUTE_OUIDS | DOCUMENT_COMPARE_MUTE_UPDATES);
     126              : 
     127           12 :     auto result = returned == expected;
     128              : 
     129           12 :     if (result.first) {
     130           12 :       return process_exit_code::SUCCESS;
     131              :     }
     132              : 
     133            0 :     std::cout << "Error returned!=expected.\n";
     134            0 :     std::cerr << "returned:\n" << returned << "\n";
     135            0 :     std::cerr << "expected:\n" << expected << "\n";
     136            0 :     std::cerr << "error:\n" << result.second << "\n";
     137              : 
     138              :     // Write debug files
     139            0 :     std::ostringstream returned_stream, expected_stream;
     140            0 :     returned_stream << returned;
     141            0 :     expected_stream << expected;
     142            0 :     write_to_file(options->operation() + ".output.json", returned_stream.str());
     143            0 :     write_to_file(options->operation() + ".expected.json", expected_stream.str());
     144              : 
     145            0 :     return process_exit_code::FAILURE;
     146          112 :   } else if (options->format() == data_format_t::gui) {
     147              :     // Presort GUI JSON documents by "name" field before comparison
     148           34 :     auto sorted_retdoc = artdaq::database::json::presort_gui_json_by_name(retdoc);
     149           34 :     auto sorted_cmpdoc = artdaq::database::json::presort_gui_json_by_name(cmpdoc);
     150              : 
     151           34 :     auto compare_result = artdaq::database::json::compare_json_objects(sorted_retdoc, sorted_cmpdoc);
     152           34 :     if (compare_result.first) {
     153           34 :       std::cout << "returned:\n" << retdoc << "\n";
     154              : 
     155           34 :       return process_exit_code::SUCCESS;
     156              :     }
     157            0 :     std::cout << "Test failed (expected!=returned); error message: " << compare_result.second << "\n";
     158              : 
     159              :     // Write debug files
     160            0 :     write_to_file(options->operation() + ".output.json", sorted_retdoc);
     161            0 :     write_to_file(options->operation() + ".expected.json", sorted_cmpdoc);
     162          168 :   } else if (options->format() == data_format_t::json) {
     163           40 :     auto compare_result = artdaq::database::json::compare_json_objects(retdoc, cmpdoc);
     164           40 :     if (compare_result.first) {
     165           40 :       std::cout << "returned:\n" << retdoc << "\n";
     166              : 
     167           40 :       return process_exit_code::SUCCESS;
     168              :     }
     169            0 :     std::cout << "Test failed (expected!=returned); error message: " << compare_result.second << "\n";
     170              : 
     171              :     // Write debug files
     172            0 :     write_to_file(options->operation() + ".output.json", retdoc);
     173            0 :     write_to_file(options->operation() + ".expected.json", cmpdoc);
     174           66 :   } else if (cmpdoc == retdoc) {
     175           24 :     std::cout << "returned:\n" << retdoc << "\n";
     176              : 
     177           24 :     return process_exit_code::SUCCESS;
     178            2 :   } else if (cmpdoc.pop_back(), cmpdoc == retdoc) {
     179            2 :     std::cout << "returned:\n" << retdoc << "\n";
     180              : 
     181            2 :     return process_exit_code::SUCCESS;
     182              :   }
     183              : 
     184            0 :   std::cout << "Test failed (expected!=returned)\n";
     185              : 
     186            0 :   std::cout << "returned:\n" << retdoc << "\n";
     187            0 :   std::cout << "expected:\n" << cmpdoc << "\n";
     188              : 
     189            0 :   auto mismatch = std::mismatch(cmpdoc.begin(), cmpdoc.end(), retdoc.begin());
     190            0 :   std::cout << "File sizes (exp,ret)=(" << std::distance(cmpdoc.begin(), cmpdoc.end()) << "," << std::distance(retdoc.begin(), retdoc.end()) << ")\n";
     191              : 
     192            0 :   std::cout << "First mismatch at position " << std::distance(cmpdoc.begin(), mismatch.first) << ", (exp,ret)=(0x" << std::hex
     193            0 :             << static_cast<unsigned int>(*mismatch.first) << ",0x" << static_cast<unsigned int>(*mismatch.second) << ")\n";
     194              : 
     195              :   // Write simple debug files in current directory
     196            0 :   write_to_file(options->operation() + ".output.txt", retdoc);
     197            0 :   write_to_file(options->operation() + ".expected.txt", cmpdoc);
     198              : 
     199              :   // Also write to temp directory for compatibility with existing workflows
     200            0 :   auto file_out_name = std::string(db::make_temp_dir())
     201            0 :                            .append("/")
     202            0 :                            .append(argv[0])
     203            0 :                            .append("-")
     204            0 :                            .append(options->operation())
     205            0 :                            .append("-")
     206            0 :                            .append(basename(const_cast<char*>(options->resultFileName().c_str())))
     207            0 :                            .append(".txt");
     208              : 
     209            0 :   db::write_buffer_to_file(retdoc, file_out_name);
     210              : 
     211            0 :   std::cout << "Wrote file:" << file_out_name << "\n";
     212              : 
     213            0 :   return process_exit_code::FAILURE;
     214          112 : } catch (...) {
     215            0 :   std::cout << "Process exited with error: " << ::debug::current_exception_diagnostic_information();
     216            0 :   return process_exit_code::UNCAUGHT_EXCEPTION;
     217            0 : }
        

Generated by: LCOV version 2.0-1