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()
|