LCOV - code coverage report
Current view: top level - /opt/artdaq/srcs/artdaq-database/test/CaseStudy/OtsDaqCPPInterface/test011 - LargeData_t.cc (source / functions) Coverage Total Hit
Test: artdaq.info.cleaned Lines: 98.1 % 214 210
Test Date: 2026-10-29 00:35:58 Functions: 100.0 % 16 16

            Line data    Source code
       1              : #define BOOST_TEST_DYN_LINK
       2              : #define BOOST_TEST_MODULE (LargeData test)
       3              : 
       4              : #include <boost/test/unit_test.hpp>
       5              : 
       6              : #include <atomic>
       7              : #include <chrono>
       8              : #include <cstdlib>
       9              : #include <ctime>
      10              : #include <iostream>
      11              : #include <memory>
      12              : #include <sstream>
      13              : #include <string>
      14              : #include <thread>
      15              : #include <vector>
      16              : 
      17              : #include "../DatabaseConfigurationInterface.h"
      18              : 
      19              : using namespace ots;
      20              : 
      21              : struct LargeDataTestData {
      22            2 :   LargeDataTestData() {
      23            2 :     srand(time(nullptr));
      24            2 :     baseVersion = rand() % 99999 + 100000;
      25            2 :     std::cout << "=== LARGE DATA TEST SUITE ===\n";
      26            2 :     std::cout << "Base version: " << baseVersion << "\n\n";
      27            2 :   }
      28              : 
      29            2 :   ~LargeDataTestData() { std::cout << "\n=== TEST SUITE COMPLETE ===\n"; }
      30              : 
      31            6 :   std::string generateLargeJson(size_t targetSize) {
      32            6 :     std::stringstream ss;
      33            6 :     ss << "{\n";
      34            6 :     ss << "  \"largeData\": [\n";
      35              : 
      36            6 :     size_t currentSize = ss.str().size() + 10;
      37            6 :     int itemCount = 0;
      38              : 
      39         3330 :     while (currentSize < targetSize) {
      40         3324 :       if (itemCount > 0) ss << ",\n";
      41         6648 :       ss << "    {\"item\": " << itemCount << ", \"data\": \"value_" << itemCount << "_padding_" << std::string(50, 'x') << "\"}";
      42         3324 :       currentSize = ss.str().size() + 10;
      43         3324 :       itemCount++;
      44              :     }
      45              : 
      46            6 :     ss << "\n  ]\n}";
      47           12 :     return ss.str();
      48            6 :   }
      49              : 
      50              :   int baseVersion;
      51              : };
      52              : 
      53              : LargeDataTestData fixture;
      54              : 
      55              : BOOST_AUTO_TEST_SUITE(large_data_test)
      56              : 
      57            4 : BOOST_AUTO_TEST_CASE(large_configuration_payload_10kb) {
      58            2 :   std::cout << "\n=== TEST 1: Large configuration payload (10KB) ===\n";
      59              : 
      60            2 :   auto ifc = DatabaseConfigurationInterface();
      61            2 :   int testVersion = fixture.baseVersion;
      62              : 
      63            2 :   size_t targetSize = 10 * 1024;
      64            2 :   auto largeJson = fixture.generateLargeJson(targetSize);
      65            2 :   std::cout << "Step 1: Generated JSON payload of " << largeJson.size() << " bytes\n";
      66              : 
      67            2 :   std::shared_ptr<ConfigurationBase> cfg = std::make_shared<TestConfiguration001>();
      68            2 :   cfg->getView().version = testVersion;
      69            2 :   cfg->getView().fillFromJSON(largeJson);
      70              : 
      71            2 :   auto startStore = std::chrono::high_resolution_clock::now();
      72            2 :   auto saveResult = ifc.saveActiveVersion(cfg.get());
      73            2 :   auto endStore = std::chrono::high_resolution_clock::now();
      74            2 :   auto storeDuration = std::chrono::duration_cast<std::chrono::milliseconds>(endStore - startStore).count();
      75              : 
      76            2 :   BOOST_REQUIRE_EQUAL(saveResult, 0);
      77            2 :   std::cout << "Step 2: Stored in " << storeDuration << "ms\n";
      78              : 
      79            2 :   std::shared_ptr<ConfigurationBase> cfgRead = std::make_shared<TestConfiguration001>();
      80              : 
      81            2 :   auto startLoad = std::chrono::high_resolution_clock::now();
      82            2 :   auto fillResult = ifc.fill(cfgRead.get(), testVersion);
      83            2 :   auto endLoad = std::chrono::high_resolution_clock::now();
      84            2 :   auto loadDuration = std::chrono::duration_cast<std::chrono::milliseconds>(endLoad - startLoad).count();
      85              : 
      86            2 :   BOOST_REQUIRE_EQUAL(fillResult, 0);
      87            2 :   std::cout << "Step 3: Loaded in " << loadDuration << "ms\n";
      88              : 
      89            2 :   bool hasLargeData = (cfgRead->getView()._json.find("largeData") != std::string::npos);
      90            2 :   BOOST_CHECK_MESSAGE(hasLargeData, "Loaded data should contain largeData field");
      91              : 
      92            2 :   size_t loadedSize = cfgRead->getView()._json.size();
      93            2 :   std::cout << "Step 4: Original size: " << largeJson.size() << ", Loaded size: " << loadedSize << "\n";
      94              : 
      95            2 :   BOOST_CHECK_GT(loadedSize, targetSize / 2);
      96              : 
      97            2 :   std::cout << "  Verified: 10KB payload stored/loaded correctly\n";
      98            2 : }
      99              : 
     100            4 : BOOST_AUTO_TEST_CASE(large_configuration_payload_100kb) {
     101            2 :   std::cout << "\n=== TEST 2: Large configuration payload (100KB) ===\n";
     102              : 
     103            2 :   auto ifc = DatabaseConfigurationInterface();
     104            2 :   int testVersion = fixture.baseVersion + 1;
     105              : 
     106            2 :   size_t targetSize = 100 * 1024;
     107            2 :   auto largeJson = fixture.generateLargeJson(targetSize);
     108            2 :   std::cout << "Step 1: Generated JSON payload of " << largeJson.size() << " bytes\n";
     109              : 
     110            2 :   std::shared_ptr<ConfigurationBase> cfg = std::make_shared<TestConfiguration001>();
     111            2 :   cfg->getView().version = testVersion;
     112            2 :   cfg->getView().fillFromJSON(largeJson);
     113              : 
     114            2 :   auto startStore = std::chrono::high_resolution_clock::now();
     115            2 :   auto saveResult = ifc.saveActiveVersion(cfg.get());
     116            2 :   auto endStore = std::chrono::high_resolution_clock::now();
     117            2 :   auto storeDuration = std::chrono::duration_cast<std::chrono::milliseconds>(endStore - startStore).count();
     118              : 
     119            2 :   BOOST_REQUIRE_EQUAL(saveResult, 0);
     120            2 :   std::cout << "Step 2: Stored in " << storeDuration << "ms\n";
     121              : 
     122            2 :   std::shared_ptr<ConfigurationBase> cfgRead = std::make_shared<TestConfiguration001>();
     123              : 
     124            2 :   auto startLoad = std::chrono::high_resolution_clock::now();
     125            2 :   auto fillResult = ifc.fill(cfgRead.get(), testVersion);
     126            2 :   auto endLoad = std::chrono::high_resolution_clock::now();
     127            2 :   auto loadDuration = std::chrono::duration_cast<std::chrono::milliseconds>(endLoad - startLoad).count();
     128              : 
     129            2 :   BOOST_REQUIRE_EQUAL(fillResult, 0);
     130            2 :   std::cout << "Step 3: Loaded in " << loadDuration << "ms\n";
     131              : 
     132            2 :   bool hasLargeData = (cfgRead->getView()._json.find("largeData") != std::string::npos);
     133            2 :   BOOST_CHECK_MESSAGE(hasLargeData, "Loaded data should contain largeData field");
     134              : 
     135            2 :   std::cout << "  Verified: 100KB payload stored/loaded correctly\n";
     136            2 : }
     137              : 
     138            4 : BOOST_AUTO_TEST_CASE(many_versions_single_type) {
     139            2 :   std::cout << "\n=== TEST 3: Many versions single type ===\n";
     140              : 
     141            2 :   auto ifc = DatabaseConfigurationInterface();
     142            2 :   int baseV = fixture.baseVersion + 100;
     143            2 :   const int NUM_VERSIONS = 50;
     144              : 
     145            2 :   auto startCreate = std::chrono::high_resolution_clock::now();
     146              : 
     147          102 :   for (int i = 0; i < NUM_VERSIONS; ++i) {
     148          100 :     std::shared_ptr<ConfigurationBase> cfg = std::make_shared<TestConfiguration001>();
     149          100 :     cfg->getView().version = baseV + i;
     150          100 :     cfg->getView().fillFromJSON("{\"version_index\": " + std::to_string(i) + "}");
     151          100 :     auto result = ifc.saveActiveVersion(cfg.get());
     152          100 :     BOOST_REQUIRE_EQUAL(result, 0);
     153          100 :   }
     154              : 
     155            2 :   auto endCreate = std::chrono::high_resolution_clock::now();
     156            2 :   auto createDuration = std::chrono::duration_cast<std::chrono::milliseconds>(endCreate - startCreate).count();
     157            2 :   std::cout << "Step 1: Created " << NUM_VERSIONS << " versions in " << createDuration << "ms\n";
     158              : 
     159            2 :   std::shared_ptr<ConfigurationBase> cfg = std::make_shared<TestConfiguration001>();
     160              : 
     161            2 :   auto startQuery = std::chrono::high_resolution_clock::now();
     162            2 :   auto versions = ifc.getVersions(cfg.get());
     163            2 :   auto endQuery = std::chrono::high_resolution_clock::now();
     164            2 :   auto queryDuration = std::chrono::duration_cast<std::chrono::milliseconds>(endQuery - startQuery).count();
     165              : 
     166            2 :   std::cout << "Step 2: getVersions returned " << versions.size() << " versions in " << queryDuration << "ms\n";
     167              : 
     168            2 :   int foundCount = 0;
     169          102 :   for (int i = 0; i < NUM_VERSIONS; ++i) {
     170          100 :     if (versions.find(baseV + i) != versions.end()) {
     171          100 :       foundCount++;
     172              :     }
     173              :   }
     174              : 
     175            2 :   BOOST_CHECK_EQUAL(foundCount, NUM_VERSIONS);
     176            2 :   std::cout << "Step 3: Found " << foundCount << "/" << NUM_VERSIONS << " created versions\n";
     177              : 
     178            2 :   if (queryDuration > 5000) {
     179            0 :     BOOST_WARN_MESSAGE(false, "getVersions took longer than 5 seconds - may need optimization");
     180              :   }
     181              : 
     182            2 :   std::cout << "  Verified: All " << NUM_VERSIONS << " versions found\n";
     183            2 : }
     184              : 
     185            4 : BOOST_AUTO_TEST_CASE(large_composition) {
     186            2 :   std::cout << "\n=== TEST 4: Large composition (many members) ===\n";
     187              : 
     188            2 :   auto ifc = DatabaseConfigurationInterface();
     189            2 :   int baseV = fixture.baseVersion + 200;
     190              : 
     191            2 :   const int VERSIONS_PER_TYPE = 10;
     192              : 
     193           22 :   for (int i = 0; i < VERSIONS_PER_TYPE; ++i) {
     194           20 :     std::shared_ptr<ConfigurationBase> cfg1 = std::make_shared<TestConfiguration001>();
     195           20 :     cfg1->getView().version = baseV + i;
     196           20 :     auto result1 = ifc.saveActiveVersion(cfg1.get());
     197           20 :     BOOST_REQUIRE_EQUAL(result1, 0);
     198              : 
     199           20 :     std::shared_ptr<ConfigurationBase> cfg2 = std::make_shared<TestConfiguration002>();
     200           20 :     cfg2->getView().version = baseV + i;
     201           20 :     auto result2 = ifc.saveActiveVersion(cfg2.get());
     202           20 :     BOOST_REQUIRE_EQUAL(result2, 0);
     203           20 :   }
     204            2 :   std::cout << "Step 1: Created " << VERSIONS_PER_TYPE << " versions of each config type\n";
     205              : 
     206            2 :   auto map = DatabaseConfigurationInterface::config_version_map_t{};
     207              : 
     208            2 :   std::shared_ptr<ConfigurationBase> cfg1 = std::make_shared<TestConfiguration001>();
     209            2 :   std::shared_ptr<ConfigurationBase> cfg2 = std::make_shared<TestConfiguration002>();
     210              : 
     211            2 :   map[cfg1->getConfigurationName()] = baseV;
     212            2 :   map[cfg2->getConfigurationName()] = baseV;
     213              : 
     214            2 :   std::string compName = "LargeComp_" + std::to_string(fixture.baseVersion);
     215              : 
     216            2 :   auto startStore = std::chrono::high_resolution_clock::now();
     217            2 :   BOOST_CHECK_NO_THROW(ifc.storeGlobalConfiguration(map, compName));
     218            2 :   auto endStore = std::chrono::high_resolution_clock::now();
     219            2 :   auto storeDuration = std::chrono::duration_cast<std::chrono::milliseconds>(endStore - startStore).count();
     220              : 
     221            2 :   std::cout << "Step 2: Created composition in " << storeDuration << "ms\n";
     222              : 
     223            2 :   auto startLoad = std::chrono::high_resolution_clock::now();
     224            2 :   auto loaded = ifc.loadGlobalConfiguration(compName);
     225            2 :   auto endLoad = std::chrono::high_resolution_clock::now();
     226            2 :   auto loadDuration = std::chrono::duration_cast<std::chrono::milliseconds>(endLoad - startLoad).count();
     227              : 
     228            2 :   std::cout << "Step 3: Loaded composition with " << loaded.size() << " members in " << loadDuration << "ms\n";
     229              : 
     230            2 :   BOOST_CHECK_EQUAL(loaded.size(), 2);
     231            2 :   BOOST_CHECK_EQUAL(loaded.at(cfg1->getConfigurationName()), baseV);
     232            2 :   BOOST_CHECK_EQUAL(loaded.at(cfg2->getConfigurationName()), baseV);
     233              : 
     234            2 :   std::cout << "  Verified: Composition with 2 members handled correctly\n";
     235            2 : }
     236              : 
     237            4 : BOOST_AUTO_TEST_CASE(many_compositions_lookup) {
     238            2 :   std::cout << "\n=== TEST 5: Many compositions lookup ===\n";
     239              : 
     240            2 :   auto ifc = DatabaseConfigurationInterface();
     241            2 :   int baseV = fixture.baseVersion + 300;
     242            2 :   const int NUM_COMPOSITIONS = 20;
     243              : 
     244            2 :   std::shared_ptr<ConfigurationBase> cfg = std::make_shared<TestConfiguration001>();
     245            2 :   cfg->getView().version = baseV;
     246            2 :   auto saveResult = ifc.saveActiveVersion(cfg.get());
     247            2 :   BOOST_REQUIRE_EQUAL(saveResult, 0);
     248              : 
     249            2 :   auto startCreate = std::chrono::high_resolution_clock::now();
     250              : 
     251           42 :   for (int i = 0; i < NUM_COMPOSITIONS; ++i) {
     252           40 :     auto map = DatabaseConfigurationInterface::config_version_map_t{};
     253           40 :     map[cfg->getConfigurationName()] = baseV;
     254              : 
     255           40 :     std::string compName = "ManyComp_" + std::to_string(fixture.baseVersion) + "_" + std::to_string(i);
     256           40 :     ifc.storeGlobalConfiguration(map, compName);
     257           40 :   }
     258              : 
     259            2 :   auto endCreate = std::chrono::high_resolution_clock::now();
     260            2 :   auto createDuration = std::chrono::duration_cast<std::chrono::milliseconds>(endCreate - startCreate).count();
     261            2 :   std::cout << "Step 1: Created " << NUM_COMPOSITIONS << " compositions in " << createDuration << "ms\n";
     262              : 
     263            2 :   std::string searchPattern = "ManyComp_" + std::to_string(fixture.baseVersion) + "*";
     264              : 
     265            2 :   auto startSearch = std::chrono::high_resolution_clock::now();
     266            2 :   auto compositions = ifc.findAllGlobalConfigurations(searchPattern);
     267            2 :   auto endSearch = std::chrono::high_resolution_clock::now();
     268            2 :   auto searchDuration = std::chrono::duration_cast<std::chrono::milliseconds>(endSearch - startSearch).count();
     269              : 
     270            2 :   std::cout << "Step 2: Search found " << compositions.size() << " compositions in " << searchDuration << "ms\n";
     271              : 
     272            2 :   BOOST_CHECK_EQUAL(compositions.size(), NUM_COMPOSITIONS);
     273              : 
     274            2 :   std::cout << "  Verified: All " << NUM_COMPOSITIONS << " compositions found via search\n";
     275            2 : }
     276              : 
     277            4 : BOOST_AUTO_TEST_CASE(concurrent_reads_large_payload) {
     278            2 :   std::cout << "\n=== TEST 6: Concurrent reads large payload ===\n";
     279              : 
     280            2 :   auto ifc = DatabaseConfigurationInterface();
     281            2 :   int testVersion = fixture.baseVersion + 400;
     282              : 
     283            2 :   size_t targetSize = 50 * 1024;
     284            2 :   auto largeJson = fixture.generateLargeJson(targetSize);
     285              : 
     286            2 :   std::shared_ptr<ConfigurationBase> cfg = std::make_shared<TestConfiguration001>();
     287            2 :   cfg->getView().version = testVersion;
     288            2 :   cfg->getView().fillFromJSON(largeJson);
     289            2 :   auto saveResult = ifc.saveActiveVersion(cfg.get());
     290            2 :   BOOST_REQUIRE_EQUAL(saveResult, 0);
     291            2 :   std::cout << "Step 1: Stored " << largeJson.size() << " byte payload\n";
     292              : 
     293            2 :   const int NUM_THREADS = 5;
     294            2 :   std::vector<std::thread> threads;
     295            2 :   std::atomic<int> successCount{0};
     296            2 :   std::atomic<int> failCount{0};
     297              : 
     298            2 :   auto startRead = std::chrono::high_resolution_clock::now();
     299              : 
     300           12 :   for (int i = 0; i < NUM_THREADS; ++i) {
     301           20 :     threads.emplace_back([&ifc, testVersion, &successCount, &failCount]() {
     302              :       try {
     303           10 :         auto localIfc = DatabaseConfigurationInterface();
     304           10 :         std::shared_ptr<ConfigurationBase> readCfg = std::make_shared<TestConfiguration001>();
     305           10 :         auto result = localIfc.fill(readCfg.get(), testVersion);
     306           10 :         if (result == 0 && readCfg->getView()._json.find("largeData") != std::string::npos) {
     307           10 :           successCount++;
     308              :         } else {
     309            0 :           failCount++;
     310              :         }
     311           10 :       } catch (...) {
     312            0 :         failCount++;
     313            0 :       }
     314           10 :     });
     315              :   }
     316              : 
     317           12 :   for (auto& t : threads) {
     318           10 :     t.join();
     319              :   }
     320              : 
     321            2 :   auto endRead = std::chrono::high_resolution_clock::now();
     322            2 :   auto readDuration = std::chrono::duration_cast<std::chrono::milliseconds>(endRead - startRead).count();
     323              : 
     324            2 :   std::cout << "Step 2: " << NUM_THREADS << " concurrent reads completed in " << readDuration << "ms\n";
     325            2 :   std::cout << "        Success: " << successCount << ", Failures: " << failCount << "\n";
     326              : 
     327            4 :   BOOST_CHECK_EQUAL(successCount.load(), NUM_THREADS);
     328            4 :   BOOST_CHECK_EQUAL(failCount.load(), 0);
     329              : 
     330            2 :   std::cout << "  Verified: " << successCount << "/" << NUM_THREADS << " concurrent reads of large payload succeeded\n";
     331            2 : }
     332              : 
     333              : BOOST_AUTO_TEST_SUITE_END()
        

Generated by: LCOV version 2.0-1