diff --git a/Framework/CMakeLists.txt b/Framework/CMakeLists.txt index 23e1da6f6b..518866c05b 100644 --- a/Framework/CMakeLists.txt +++ b/Framework/CMakeLists.txt @@ -159,7 +159,8 @@ set(EXE_SRCS src/runUploadRootObjects.cxx src/runFileMerger.cxx src/runMetadataUpdater.cxx - src/runBookkeepingBenchmark.cxx) + src/runBookkeepingBenchmark.cxx + src/runConfigMerger.cxx) set(EXE_NAMES o2-qc-run-producer @@ -177,7 +178,8 @@ set(EXE_NAMES o2-qc-upload-root-objects o2-qc-file-merger o2-qc-metadata-updater - o2-qc-bk-benchmark) + o2-qc-bk-benchmark + o2-qc-config-merger) # These were the original names before the convention changed. We will get rid # of them but for the time being we want to create symlinks to avoid confusion. @@ -198,7 +200,8 @@ set(EXE_OLD_NAMES o2-qc-upload-root-objects o2-qc-file-merger o2-qc-metadata-updater - o2-qc-bk-benchmark) + o2-qc-bk-benchmark + o2-qc-config-merger) # As per https://stackoverflow.com/questions/35765106/symbolic-links-cmake diff --git a/Framework/include/QualityControl/ptreeUtils.h b/Framework/include/QualityControl/ptreeUtils.h index 81dc2cbd82..3f6516794c 100644 --- a/Framework/include/QualityControl/ptreeUtils.h +++ b/Framework/include/QualityControl/ptreeUtils.h @@ -20,278 +20,39 @@ #include #include #include -#include -#include -#include using boost::property_tree::ptree; using namespace std; namespace o2::quality_control::core { -//namespace tree_ops -//{ - -// TODO when you get at an array this path is finished, just add the items and continue - -// TODO what if we don't merge the trees and work with multiple ?ss -// -///// @brief Walk a Boost.PropertyTree tree, invoking the binary function with -///// the full path and the current node. -//template -//void for_each( -// const Tree& tree, -// Function fn, -// const typename Tree::path_type& parent_path = typename Tree::path_type(), -// std::string fullpath="") -//{ -// using path_type = typename Tree::path_type; -// cout << "*** " << parent_path.dump() << endl; -// for (auto&& value_pair : tree) { -// cout << "*** '" << value_pair.first << "'" << endl; -// cout << "*** fullpath: '" << fullpath << "'" << endl; -// auto current_path = parent_path / path_type(value_pair.first); -// // fn(current_path, value_pair.second); -// std::string new_path = fullpath.empty() ? value_pair.first : fullpath+"."+value_pair.first; -// fn(parent_path, path_type(value_pair.first), value_pair.second, new_path); -// for_each(value_pair.second, fn, current_path, new_path); -// } -//} - -/*/// @brief Return tree with elements in @ref s but not in @ref t. -template -Tree tree_difference(const Tree& s, const Tree& t) -{ - using data_type = typename Tree::data_type; - Tree result; - // Iterate 's', adding to the result when either a node in - // 't' is not present in 's' or the node's values differ. - for_each(s, - [&](const typename Tree::path_type& path, const Tree& node) { - auto value = t.template get_optional(path); - if (!value || (value.get() != node.data())) - result.add(path, node.data()); - }); - return result; -}*/ -// -///// @brief Return tree with elements from both @ref s and @ref t. -//template -//Tree tree_union(const Tree& s, const Tree& t) -//{ -// // The result will always contain all values in @ref s. -// Tree result = s; -// // Iterate 't', add values to the result only if the node is -// // either not in 's' or the values are different. -// for_each(t, -// [&](const typename Tree::path_type& parent_path, const typename Tree::path_type& this_path, const Tree& node, std::string fullpath) { -// cout << "--------------------------" << endl; -// cout << "tree_union parent_path : '" << parent_path.dump() << "' / '" << this_path.dump() << "' : " << node.data() << endl; -// cout << "fullpath : " << fullpath << endl; -// auto current_path = parent_path / this_path; -// auto child = s.get_child_optional(current_path); -// -// // if(child) -// // cout << "tree_union : child.data : " << child->data() << endl; -// // else -// // cout << "tree_union : no child "<< endl; -// if (!child || (child->data() != node.data())) { -// if(this_path.empty()) { -// cout << "EMPTY" << endl; -// // special case when the key is empty. It is probably a comment ? -// auto& result_parent= result.get_child(parent_path); -// result_parent.push_back(ptree::value_type("", node.data())); -// } else { -// result.add(fullpath, node.data()); -// } -// } -// }); -// return result; -//} -// -//} - -/*/// @brief Return tree with elements from both @ref s and @ref t. -template -Tree tree_union(const Tree& s, const Tree& t) -{ - // The result will always contain all values in @ref s. - Tree result = s; - // Iterate 't', add values to the result only if the node is - // either not in 's' or the values are different. - for_each(t, - [&](const typename Tree::path_type& path, const Tree& node) { - cout << "tree_union : '" << path.dump() << "' : " << node.data() << endl; - auto child = s.get_child_optional(path); -// if(child) -// cout << "tree_union : child.data : " << child->data() << endl; -// else -// cout << "tree_union : no child "<< endl; - if (!child || (child->data() != node.data())) - result.add(path, node.data()); - }); - return result; -}*/ -/* -/// @brief Return tree with elements common to @ref s and @ref t. -template -Tree tree_intersection(const Tree& s, const Tree& t) -{ - using data_type = typename Tree::data_type; - Tree result; - // Iterate 's', adding common elements found in 't' that have the same - // value. - for_each(s, - [&](const typename Tree::path_type& path, const Tree& node) { - auto value = t.template get_optional(path); - if (value && (value.get() == node.data())) - result.add(path, node.data()); - }); - return result; -} - -/// @brief Return tree with elements in either @ref s or @ref t, but not -/// both. -template -Tree tree_symmetric_difference(const Tree& s, const Tree& t) -{ - return tree_difference(tree_union(s, t), tree_intersection(s, t)); -} - -} // namespace tree_ops - -// Expose mathematical tree operations with operators. - -/// @brief Return tree with elements in @ref lhs but not in @ref rhs. -boost::property_tree::ptree operator-( - const boost::property_tree::ptree& lhs, - const boost::property_tree::ptree& rhs) -{ - return tree_ops::tree_difference(lhs, rhs); -}*/ - -///// @brief Return tree with elements in both @ref lhs and @ref rhs. -//boost::property_tree::ptree operator|( -// const boost::property_tree::ptree& lhs, -// const boost::property_tree::ptree& rhs) -//{ -// return tree_ops::tree_union(lhs, rhs); -//} - -/*/// @brief Return tree with elements common to @ref lhs and @ref rhs. -boost::property_tree::ptree operator&( - const boost::property_tree::ptree& lhs, - const boost::property_tree::ptree& rhs) -{ - return tree_ops::tree_intersection(lhs, rhs); -} - -/// @brief Return tree with elements in either @ref lhs or @ref rhs, but not -/// both. -boost::property_tree::ptree operator^( - const boost::property_tree::ptree& lhs, - const boost::property_tree::ptree& rhs) -{ - return tree_ops::tree_symmetric_difference(lhs, rhs); -}*/ - - -// Create necessary escape sequences from illegal characters -//template -//std::basic_string create_escapes(const std::basic_string &s) -//{ -// std::basic_string result; -// typename std::basic_string::const_iterator b = s.begin(); -// typename std::basic_string::const_iterator e = s.end(); -// while (b != e) -// { -// if (*b == Ch('\0')) result += Ch('\\'), result += Ch('0'); -// else if (*b == Ch('\a')) result += Ch('\\'), result += Ch('a'); -// else if (*b == Ch('\b')) result += Ch('\\'), result += Ch('b'); -// else if (*b == Ch('\f')) result += Ch('\\'), result += Ch('f'); -// else if (*b == Ch('\n')) result += Ch('\\'), result += Ch('n'); -// else if (*b == Ch('\r')) result += Ch('\\'), result += Ch('r'); -// else if (*b == Ch('\v')) result += Ch('\\'), result += Ch('v'); -// else if (*b == Ch('"')) result += Ch('\\'), result += Ch('"'); -// else if (*b == Ch('\\')) result += Ch('\\'), result += Ch('\\'); -// else -// result += *b; -// ++b; -// } -// return result; -//} - // Freely inspired from write_json_helper in boost template -void mergeInto(const Ptree& pt, /*ptree& destination, */ptree& parent, const std::string& fullPath , int indent) +void mergeInto(const Ptree& pt, ptree& parent, const std::string& fullPath , int indent) { typedef typename Ptree::key_type::value_type Ch; typedef typename std::basic_string Str; // Value or object or array if (indent > 0 && pt.empty()) { // Handle value - Str data = /*create_escapes(*/pt.template get_value()/*)*/; + Str data = pt.template get_value(); parent.add(fullPath, data); } else if (indent > 0 && pt.count(Str()) == pt.size()) { // Handle array typename Ptree::const_iterator it = pt.begin(); - cout << "ARRAY " << endl; - - // does the array exist in the destination ? -// ptree children; -// if ( parent.count(fullPath) > 0) { -// cout << " already exist in parent" << endl; -// children = parent.get_child(fullPath); -// } else { -// cout << " does not exist in parent" << endl; -// } - for (; it != pt.end(); ++it) { ptree object; -// std::string newFullPath = fullPath.empty() ? it->first : fullPath + "." + it->first; - cout << " processing item :" << it->first << endl; - cout << " fullPath :" << fullPath << endl; -// cout << " newFullPath:" << newFullPath << endl; -// mergeInto(it->second, /*destination, */object, "", indent + 1); -// boost::property_tree::write_json(std::cout, object); -// cout << " object: " << endl; -// boost::property_tree::write_json(std::cout, it->second); - parent.add_child(fullPath+".", it->second); -// ptree test = object.get_child("").get_child(""); -// -// if(test.empty()) -// cout << "Node doesn't have children" << endl; -// -// if(test.data().empty()) -// cout << "Node doesn't have data" << endl; -// -// if (object.empty() && !object.data().empty()) { // terminal -// cout << " terminal " << endl; -// children.put("", object.data()); -// } else { -// cout << " not termianl " << endl; -// children.add_child("", object.get_child("")); -// } - -// parent.add_child(fullPath, object); -// parent.add_child("", object); + // this check is to avoid problems when there is a node with data and we try to add children to it (forbidden in json) + if(parent.get_child_optional(fullPath+".") && !parent.get_child(fullPath+".").data().empty()) { + cerr << "could not add item to array '" + fullPath + ".' because it already contains some data." << endl; + } else { + parent.add_child(fullPath+".", it->second); + } } - -// cout << " children:" << endl; -// boost::property_tree::write_json(std::cout, children); -// -// if ( parent.count(fullPath) == 0) { -// cout << " add to parent" << endl; -// parent.add_child(fullPath, children); -// } - -// cout << " add to parent" << endl; - // TODO: check if array exist in parent, if so push_basck the object otherwise create it -// parent.add_child(fullPath, children); } else { // Handle object typename Ptree::const_iterator it = pt.begin(); for (; it != pt.end(); ++it) { std::string newFullPath = fullPath.empty() ? it->first : fullPath + "." + it->first; - mergeInto(it->second, /*destination, */parent, newFullPath, indent + 1); + mergeInto(it->second, parent, newFullPath, indent + 1); } } } @@ -299,9 +60,9 @@ void mergeInto(const Ptree& pt, /*ptree& destination, */ptree& parent, const std template void mergeInto(const Ptree& pt, ptree& destination) { - mergeInto(pt, destination, destination, "", 1); + mergeInto(pt, destination, "", 1); } -} // namespace o2::quality_control::test +} // namespace o2::quality_control::core #endif // QC_PTREE_UTILS_H diff --git a/Framework/include/QualityControl/stringUtils.h b/Framework/include/QualityControl/stringUtils.h index c30eb5438f..3519a9bd66 100644 --- a/Framework/include/QualityControl/stringUtils.h +++ b/Framework/include/QualityControl/stringUtils.h @@ -40,6 +40,14 @@ bool decodeBool(const std::string& value); /// @throw std::runtime_error the value is not a bool bool parseBoolParam(const CustomParameters& customParameters, const std::string& name, const std::string& runType = "default", const std::string& beamType = "default"); +/** + * Split a string using delim as delimiter. + * @param str + * @param delim + * @return + */ +std::vector splitString(const std::string& str, char delim); + } // namespace o2::quality_control::core #endif // QC_STRING_UTILS_H diff --git a/Framework/src/runConfigMerger.cxx b/Framework/src/runConfigMerger.cxx index 4faf2658a5..4ad72eab52 100644 --- a/Framework/src/runConfigMerger.cxx +++ b/Framework/src/runConfigMerger.cxx @@ -9,28 +9,28 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include "QualityControl/Bookkeeping.h" #include #include -#include "BookkeepingApi/BkpProtoClientFactory.h" -#include "QualityControl/Activity.h" -#include #include "QualityControl/QcInfoLogger.h" +#include "QualityControl/stringUtils.h" +#include "QualityControl/ptreeUtils.h" +#include +#include using namespace std; namespace bpo = boost::program_options; -using namespace o2::bkp::api; -using namespace o2::bkp::api::proto; using namespace o2::quality_control::core; +using boost::property_tree::ptree; +using namespace o2::configuration; /** - * A small utility to stress test the bookkeeping api. + * A small utility merge several configs into one. */ int main(int argc, const char* argv[]) { bpo::options_description desc{ "Options" }; - desc.add_options()("help,h", "Help screen")("url,u", bpo::value()->required(), "URL to the Bookkeeping")("run,r", bpo::value())("max,m", bpo::value()->default_value(10000), "Max number of executions, default: 10000")("printCycles,p", bpo::value()->default_value(1000), "We print every X cycles, default: 1000")("printActivity", bpo::value()->default_value(false), "just to check that we get something in the activity.")("delay,d", bpo::value()->default_value(0), "Minimum delay between calls in ms, default 0"); + desc.add_options()("help,h", "Help screen")("configs", bpo::value()->required(), "comma separated list of configs")("out,o",bpo::value()->default_value(""), "file to store the merged config"); bpo::variables_map vm; store(parse_command_line(argc, argv, desc), vm); @@ -40,53 +40,27 @@ int main(int argc, const char* argv[]) return 0; } notify(vm); - - const auto url = vm["url"].as(); - cout << "url : " << url << endl; - const auto run = vm["run"].as(); - cout << "run : " << run << endl; - const auto max = vm["max"].as(); - cout << "max : " << max << endl; - const auto printCycles = vm["printCycles"].as(); - cout << "printCycles : " << printCycles << endl; - const auto printActivity = vm["printActivity"].as(); - cout << "printActivity : " << printActivity << endl; - const auto minDelay = vm["delay"].as(); - cout << "minDelay : " << minDelay << endl; + const auto configs = vm["configs"].as(); + const auto out = vm["out"].as(); + std::vector allConfigurationSources; + allConfigurationSources = o2::quality_control::core::splitString(configs, ','); ILOG_INST.filterDiscardDebug(true); ILOG_INST.filterDiscardLevel(11); - Bookkeeping::getInstance().init(url); - - AliceO2::Common::Timer timer; - AliceO2::Common::Timer triggerTimer; - triggerTimer.reset(); - Activity activity; - double totalDuration = 0; - double cycleDuration = 0; - int numberOfExecutionsInCycle = 0; - int totalNumberOfExecutions = 0; + ptree merged; + for(auto config : allConfigurationSources) { + auto newTree = ConfigurationFactory::getConfiguration(config)->getRecursive(); + boost::property_tree::write_json(std::cout, newTree); + mergeInto(newTree, merged); + } - while (totalNumberOfExecutions < max) { - if (triggerTimer.isTimeout()) { - numberOfExecutionsInCycle++; - totalNumberOfExecutions++; - triggerTimer.reset(minDelay * 1000); - timer.reset(); - Bookkeeping::getInstance().populateActivity(activity, run); - auto duration = timer.getTime(); - if (printActivity) { - cout << activity << endl; - } - totalDuration += duration; - cycleDuration += duration; - if (totalNumberOfExecutions % printCycles == 0) { - cout << "average duration last " << printCycles << " calls in [ms]: " << cycleDuration / numberOfExecutionsInCycle * 1000 << endl; - numberOfExecutionsInCycle = 0; - cycleDuration = 0; - } - } + if(out.empty()) { + boost::property_tree::write_json(std::cout, merged); + } else { + ofstream outFile; + outFile.open (out); + boost::property_tree::write_json(outFile, merged); + outFile.close(); } - cout << "average duration overall in ms : " << totalDuration / totalNumberOfExecutions * 1000 << endl; } \ No newline at end of file diff --git a/Framework/src/stringUtils.cxx b/Framework/src/stringUtils.cxx index 267f711f16..de9c0acb46 100644 --- a/Framework/src/stringUtils.cxx +++ b/Framework/src/stringUtils.cxx @@ -80,4 +80,15 @@ bool parseBoolParam(const CustomParameters& customParameters, const std::string& } } +std::vector splitString(const std::string& str, char delim) +{ + std::vector result; + std::stringstream ss(str); + std::string token; + while(std::getline(ss, token, delim)) { + result.push_back(token); + } + return result; +} + } // namespace o2::quality_control::core \ No newline at end of file diff --git a/Framework/test/testPtreeUtils.cxx b/Framework/test/testPtreeUtils.cxx index 0bfc8831f5..7ec0be726d 100644 --- a/Framework/test/testPtreeUtils.cxx +++ b/Framework/test/testPtreeUtils.cxx @@ -40,264 +40,6 @@ ptree getTree(const std::string& str) read_json(stream1, tree1); return tree1; } -// -//BOOST_AUTO_TEST_CASE(ptree_merge_basic_test) -//{ -// cout << "test_simple_json_merge" << endl; -// std::string file1 = -// "{\n" -// " \"AAA\": {\n" -// " \"name\" : \"barth\"\n" -// " }\n" -// "}"; -// string file2 = -// "{\n" -// " \"BBB\": {\n" -// " \"name\" : \"von Haller\"\n" -// " }\n" -// "}"; -// ptree tree1 = getTree(file1); -// ptree tree2 = getTree(file2); -// -// ptree merged; -// -// // Compute the union of the two ptrees -// merged = tree1 | tree2; -// -// // Print the result or perform other actions -// boost::property_tree::write_json(std::cout, merged); -// -// BOOST_CHECK_EQUAL(merged.get("AAA.name"), "barth"); -// BOOST_CHECK_EQUAL(merged.get("BBB.name"), "von Haller"); -//} -// -// -//BOOST_AUTO_TEST_CASE(test_json_merge_identical) -//{ -// cout << "test_json_merge_identical" << endl; -// std::string file1 = -// "{\n" -// " \"AAA\": {\n" -// " \"name\" : \"Barth\"\n" -// " }\n" -// "}"; -// string file2 = -// "{\n" -// " \"AAA\": {\n" -// " \"name\" : \"von Haller\"\n" -// " }\n" -// "}"; -// ptree tree1 = getTree(file1); -// ptree tree2 = getTree(file2); -// -// ptree merged = tree1 | tree2; -// -// boost::property_tree::write_json(std::cout, merged); -// -// ptree sub = merged.get_child("AAA"); -// BOOST_CHECK_EQUAL(sub.size(), 2); -// int i = 0; -// for (auto it = sub.begin(); it != sub.end(); ++it, i++) -// { -// cout << it->first << endl; -// BOOST_CHECK_EQUAL(it->first, "name"); -// if(i == 0) { -// BOOST_CHECK_EQUAL(it->second.get_value(), "Barth"); -// } else { -// BOOST_CHECK_EQUAL(it->second.get_value(), "von Haller"); -// } -// } -//} -// -//BOOST_AUTO_TEST_CASE(test_json_merge_with_comments) -//{ -// cout << "test_json_merge_with_comments" << endl; -// std::string file1 = -// "{\n" -// " \"AAA\": {\n" -// " \"name\" : \"barth\", \"\": \"COMMENT\"\n" -// " }\n" -// "}"; -// string file2 = -// "{\n" -// " \"BBB\": {\n" -// " \"name\" : \"von Haller\", \"\": \"COMMENT2\"\n" -// " }\n" -// "}"; -// ptree tree1 = getTree(file1); -// ptree tree2 = getTree(file2); -// -// ptree merged = tree1 | tree2; -// -// boost::property_tree::write_json(std::cout, merged); -// ptree sub = merged.get_child("AAA"); -// BOOST_CHECK_EQUAL(sub.size(), 2); -// sub = merged.get_child("BBB"); -// BOOST_CHECK_EQUAL(sub.size(), 2); -//} -// -//BOOST_AUTO_TEST_CASE(test_json_merge_2_tasks) -//{ -// cout << "test_json_merge_2_tasks" << endl; -// std::string file1 ="{\n" -// " \"qc\": {\n" -// " \"tasks\": {\n" -// " \"QcTask\": {\n" -// " \"active\": \"true\",\n" -// " \"className\": \"o2::quality_control_modules::skeleton::SkeletonTask\",\n" -// " \"moduleName\": \"QcSkeleton\",\n" -// " \"detectorName\": \"TST\",\n" -// " \"cycleDurationSeconds\": \"10\", \"\": \"10 seconds minimum\",\n" -// " \"maxNumberCycles\": \"-1\",\n" -// " \"\": \"The other type of dataSource is \\\"direct\\\", see basic-no-sampling.json.\",\n" -// " \"dataSource\": {\n" -// " \"type\": \"dataSamplingPolicy\",\n" -// " \"name\": \"tst-raw\"\n" -// " },\n" -// " \"taskParameters\": {\n" -// " \"myOwnKey\": \"myOwnValue\"\n" -// " },\n" -// " \"location\": \"remote\",\n" -// " \"saveObjectsToFile\": \"\", \"\": \"For debugging, path to the file where to save. If empty or missing it won't save.\"\n" -// " }\n" -// " }" -// "}" -// "}"; -// std::string file2 ="{\n" -// " \"qc\": {\n" -// " \"tasks\": {\n" -// " \"QcTask2\": {\n" -// " \"active\": \"true\",\n" -// " \"className\": \"o2::quality_control_modules::skeleton::SkeletonTask\",\n" -// " \"moduleName\": \"QcSkeleton\",\n" -// " \"detectorName\": \"TST\",\n" -// " \"cycleDurationSeconds\": \"10\", \"\": \"10 seconds minimum\",\n" -// " \"maxNumberCycles\": \"-1\",\n" -// " \"\": \"The other type of dataSource is \\\"direct\\\", see basic-no-sampling.json.\",\n" -// " \"dataSource\": {\n" -// " \"type\": \"dataSamplingPolicy\",\n" -// " \"name\": \"tst-raw\"\n" -// " },\n" -// " \"taskParameters\": {\n" -// " \"myOwnKey\": \"myOwnValue\"\n" -// " },\n" -// " \"location\": \"remote\",\n" -// " \"saveObjectsToFile\": \"\", \"\": \"For debugging, path to the file where to save. If empty or missing it won't save.\"\n" -// " }\n" -// " }" -// "}" -// "}"; -// ptree tree1 = getTree(file1); -// ptree tree2 = getTree(file2); -// -// ptree merged = tree1 | tree2; -// -// boost::property_tree::write_json(std::cout, merged); -// -// ptree tasks = merged.get_child("qc.tasks"); -// BOOST_CHECK_EQUAL(tasks.size(), 2); -//} -// -//BOOST_AUTO_TEST_CASE(test_json_merge_simple_arrays) -//{ -// cout << "test_json_merge_simple_arrays" << endl; -// -// std::string file1 = -// "{\"MOs\": [\"example\"]}"; -// string file2 = -// "{\"MOs\": [\"example2\"]}"; -// ptree tree1 = getTree(file1); -// ptree tree2 = getTree(file2); -// -// ptree merged = tree1 | tree2; -// -// boost::property_tree::write_json(std::cout, merged); -// -// ptree mos = merged.get_child("MOs"); -// BOOST_CHECK_EQUAL(mos.size(), 2); -// auto it = mos.begin(); -// BOOST_CHECK_EQUAL(it->second.get_value(), "example"); -// it++; -// BOOST_CHECK_EQUAL(it->second.get_value(), "example2"); -//} -// -//BOOST_AUTO_TEST_CASE(test_json_merge_arrays_objects) -//{ -// cout << "test_json_merge_arrays_objects" << endl; -// -// std::string file1 = -// "{\n" -// " \"dataSource\": [{\n" -// " \"type\": \"Task\",\n" -// " \"name\": \"Task\"\n" -// " }]\n" -// "}"; -// string file2 = -// "{\n" -// " \"dataSource\": [{\n" -// " \"type\": \"Task2\",\n" -// " \"name\": \"Task2\"\n" -// " }]\n" -// "}"; -// ptree tree1 = getTree(file1); -// ptree tree2 = getTree(file2); -// -// ptree merged = tree1 | tree2; -// -// boost::property_tree::write_json(std::cout, merged); -// -// ptree array = merged.get_child("dataSource"); -// BOOST_CHECK_EQUAL(array.size(), 2); -//} -// -//BOOST_AUTO_TEST_CASE(test_json_merge_arrays_of_arrays) -//{ -// cout << "test_json_merge_arrays_of_arrays" << endl; -// -// std::string file1 = -// "{\n" -// " \"dataSamplingPolicies\": [\n" -// " {\n" -// " \"id\": \"tst-raw\",\n" -// " \"samplingConditions\": [\n" -// " {\n" -// " \"condition\": \"random\",\n" -// " \"fraction\": \"0.1\"\n" -// " }\n" -// " ],\n" -// " \"blocking\": \"false\"\n" -// " }\n" -// " ]\n" -// "}"; -// string file2 = -// "{\n" -// " \"dataSamplingPolicies\": [\n" -// " {\n" -// " \"id\": \"tst-raw2\",\n" -// " \"samplingConditions\": [\n" -// " {\n" -// " \"condition\": \"random\",\n" -// " \"fraction\": \"0.1\"\n" -// " }\n" -// " ],\n" -// " \"blocking\": \"false\"\n" -// " }\n" -// " ]\n" -// "}"; -// ptree tree1 = getTree(file1); -// ptree tree2 = getTree(file2); -// -// ptree merged = tree1 | tree2; -// -// boost::property_tree::write_json(std::cout, merged); -// -// ptree array = merged.get_child("dataSamplingPolicies"); -// BOOST_CHECK_EQUAL(array.size(), 2); -//} -// -// - - BOOST_AUTO_TEST_CASE(test_simple_json_merge2) { @@ -552,4 +294,29 @@ BOOST_AUTO_TEST_CASE(test_json_merge_arrays_of_arrays2) BOOST_CHECK_EQUAL(array.size(), 2); } +BOOST_AUTO_TEST_CASE(test_json_merge_comments) +{ + cout << "test_json_merge_simple_arrays2" << endl; + + std::string file1 = + "{\"infologger\": {\n" + " \"\": \"Configuration of the Infologger (optional).\",\n" + " \"filterDiscardDebug\": \"false\",\n" + " \"\": [\n" + " \"messages won't go there.\"\n" + " ]\n" + " }}"; + ptree tree1 = getTree(file1); + + std::cout << "tree1: " << std::endl; + boost::property_tree::write_json(std::cout, tree1); + + ptree merged; + + mergeInto(tree1, /*merged, */ merged, "", 1); + + cout << "merged after tree1: " << endl; + boost::property_tree::write_json(std::cout, merged); +} + } // namespace o2::quality_control::core