Line data Source code
1 : #define BOOST_TEST_DYN_LINK
2 : #define BOOST_TEST_MODULE (MarkReadonlyExpanded test)
3 :
4 : #include <boost/test/unit_test.hpp>
5 :
6 : #include <cstdlib>
7 : #include <ctime>
8 : #include <iostream>
9 : #include <memory>
10 : #include <string>
11 :
12 : #include "../DatabaseConfigurationInterface.h"
13 :
14 : using namespace ots;
15 :
16 : struct MarkReadonlyExpandedTestData {
17 2 : MarkReadonlyExpandedTestData() {
18 2 : srand(time(nullptr));
19 2 : baseVersion = rand() % 99999 + 300000;
20 2 : std::cout << "=== MARK READONLY EXPANDED TEST SUITE ===\n";
21 2 : std::cout << "Base version: " << baseVersion << "\n\n";
22 2 : }
23 :
24 2 : ~MarkReadonlyExpandedTestData() { std::cout << "\n=== TEST SUITE COMPLETE ===\n"; }
25 :
26 : int baseVersion;
27 : };
28 :
29 : MarkReadonlyExpandedTestData fixture;
30 :
31 : BOOST_AUTO_TEST_SUITE(mark_readonly_expanded_test)
32 :
33 4 : BOOST_AUTO_TEST_CASE(mark_readonly_on_existing_version_succeeds) {
34 2 : std::cout << "\n=== TEST 1: Mark readonly on existing version succeeds ===\n";
35 :
36 2 : auto ifc = DatabaseConfigurationInterface();
37 :
38 2 : auto cfg = std::make_shared<TestConfiguration001>();
39 2 : int testVersion = fixture.baseVersion + 1;
40 2 : cfg->getView().version = testVersion;
41 4 : cfg->getView().fillFromJSON("{\"field\": \"test_data\"}");
42 :
43 2 : std::cout << "Step 1: Creating version " << testVersion << "\n";
44 2 : BOOST_REQUIRE_EQUAL(ifc.saveActiveVersion(cfg.get(), false), 0);
45 :
46 2 : std::cout << "Step 2: Marking version as read-only\n";
47 2 : auto markResult = ifc.markActiveVersionReadonly(cfg.get());
48 2 : std::cout << " markActiveVersionReadonly returned: " << markResult << "\n";
49 :
50 2 : BOOST_CHECK_EQUAL(markResult, 0);
51 2 : std::cout << " Verified: markVersionReadonly succeeds on existing version\n";
52 2 : }
53 :
54 4 : BOOST_AUTO_TEST_CASE(mark_readonly_is_idempotent) {
55 2 : std::cout << "\n=== TEST 2: Mark readonly is idempotent ===\n";
56 :
57 2 : auto ifc = DatabaseConfigurationInterface();
58 :
59 2 : auto cfg = std::make_shared<TestConfiguration001>();
60 2 : int testVersion = fixture.baseVersion + 2;
61 2 : cfg->getView().version = testVersion;
62 4 : cfg->getView().fillFromJSON("{\"field\": \"idempotent_test\"}");
63 :
64 2 : std::cout << "Step 1: Creating version " << testVersion << "\n";
65 2 : BOOST_REQUIRE_EQUAL(ifc.saveActiveVersion(cfg.get(), false), 0);
66 :
67 2 : std::cout << "Step 2: Marking version as read-only (first time)\n";
68 2 : auto firstMark = ifc.markActiveVersionReadonly(cfg.get());
69 2 : std::cout << " First mark returned: " << firstMark << "\n";
70 2 : BOOST_REQUIRE_EQUAL(firstMark, 0);
71 :
72 2 : std::cout << "Step 3: Marking version as read-only (second time)\n";
73 2 : auto secondMark = ifc.markActiveVersionReadonly(cfg.get());
74 2 : std::cout << " Second mark returned: " << secondMark << "\n";
75 :
76 2 : BOOST_CHECK_EQUAL(secondMark, 0);
77 2 : std::cout << " Verified: Marking read-only twice succeeds (idempotent)\n";
78 2 : }
79 :
80 4 : BOOST_AUTO_TEST_CASE(readonly_version_can_be_loaded) {
81 2 : std::cout << "\n=== TEST 3: Read-only version can still be loaded ===\n";
82 :
83 2 : auto ifc = DatabaseConfigurationInterface();
84 :
85 2 : auto cfg = std::make_shared<TestConfiguration001>();
86 2 : int testVersion = fixture.baseVersion + 3;
87 2 : cfg->getView().version = testVersion;
88 4 : cfg->getView().fillFromJSON("{\"field\": \"loadable_readonly\"}");
89 :
90 2 : std::cout << "Step 1: Creating version " << testVersion << "\n";
91 2 : BOOST_REQUIRE_EQUAL(ifc.saveActiveVersion(cfg.get(), false), 0);
92 :
93 2 : std::cout << "Step 2: Marking version as read-only\n";
94 2 : BOOST_REQUIRE_EQUAL(ifc.markActiveVersionReadonly(cfg.get()), 0);
95 :
96 2 : std::cout << "Step 3: Loading the read-only version\n";
97 2 : auto loaded = std::make_shared<TestConfiguration001>();
98 2 : auto loadResult = ifc.fill(loaded.get(), testVersion);
99 2 : std::cout << " fill() returned: " << loadResult << "\n";
100 :
101 2 : BOOST_REQUIRE_EQUAL(loadResult, 0);
102 :
103 2 : std::stringstream ss;
104 2 : loaded->getView().printJSON(ss);
105 2 : std::string loadedJson = ss.str();
106 2 : std::cout << " Loaded content: " << loadedJson << "\n";
107 :
108 2 : BOOST_CHECK(loadedJson.find("loadable_readonly") != std::string::npos);
109 2 : std::cout << " Verified: Read-only version can still be loaded and content is correct\n";
110 2 : }
111 :
112 4 : BOOST_AUTO_TEST_CASE(readonly_version_appears_in_version_list) {
113 2 : std::cout << "\n=== TEST 4: Read-only version appears in getVersions ===\n";
114 :
115 2 : auto ifc = DatabaseConfigurationInterface();
116 :
117 2 : auto cfg = std::make_shared<TestConfiguration001>();
118 2 : int testVersion = fixture.baseVersion + 4;
119 2 : cfg->getView().version = testVersion;
120 4 : cfg->getView().fillFromJSON("{\"field\": \"version_list_test\"}");
121 :
122 2 : std::cout << "Step 1: Creating version " << testVersion << "\n";
123 2 : BOOST_REQUIRE_EQUAL(ifc.saveActiveVersion(cfg.get(), false), 0);
124 :
125 2 : std::cout << "Step 2: Verifying version appears in list before marking readonly\n";
126 2 : auto versionsBefore = ifc.getVersions(cfg.get());
127 2 : bool foundBefore = versionsBefore.find(testVersion) != versionsBefore.end();
128 2 : std::cout << " Version " << testVersion << " in list before: " << (foundBefore ? "YES" : "NO") << "\n";
129 2 : BOOST_REQUIRE(foundBefore);
130 :
131 2 : std::cout << "Step 3: Marking version as read-only\n";
132 2 : BOOST_REQUIRE_EQUAL(ifc.markActiveVersionReadonly(cfg.get()), 0);
133 :
134 2 : std::cout << "Step 4: Verifying version still appears in list after marking readonly\n";
135 2 : auto versionsAfter = ifc.getVersions(cfg.get());
136 2 : bool foundAfter = versionsAfter.find(testVersion) != versionsAfter.end();
137 2 : std::cout << " Version " << testVersion << " in list after: " << (foundAfter ? "YES" : "NO") << "\n";
138 :
139 2 : BOOST_CHECK(foundAfter);
140 2 : std::cout << " Verified: Read-only version still appears in version listing\n";
141 2 : }
142 :
143 4 : BOOST_AUTO_TEST_CASE(readonly_blocks_overwrite) {
144 2 : std::cout << "\n=== TEST 5: Read-only blocks overwrite ===\n";
145 :
146 2 : auto ifc = DatabaseConfigurationInterface();
147 :
148 2 : auto cfg = std::make_shared<TestConfiguration001>();
149 2 : int testVersion = fixture.baseVersion + 5;
150 2 : cfg->getView().version = testVersion;
151 4 : cfg->getView().fillFromJSON("{\"field\": \"original_content\"}");
152 :
153 2 : std::cout << "Step 1: Creating version " << testVersion << "\n";
154 2 : BOOST_REQUIRE_EQUAL(ifc.saveActiveVersion(cfg.get(), false), 0);
155 :
156 2 : std::cout << "Step 2: Marking version as read-only\n";
157 2 : BOOST_REQUIRE_EQUAL(ifc.markActiveVersionReadonly(cfg.get()), 0);
158 :
159 2 : std::cout << "Step 3: Attempting to overwrite read-only version\n";
160 4 : cfg->getView().fillFromJSON("{\"field\": \"modified_content\"}");
161 2 : auto overwriteResult = ifc.saveActiveVersion(cfg.get(), true);
162 2 : std::cout << " Overwrite returned: " << overwriteResult << "\n";
163 :
164 2 : if (overwriteResult != 0) {
165 0 : std::cout << " Verified: Read-only version correctly blocks overwrite\n";
166 : } else {
167 2 : std::cout << " Observation: Read-only version allowed overwrite (may be implementation choice)\n";
168 : }
169 :
170 2 : auto loaded = std::make_shared<TestConfiguration001>();
171 2 : ifc.fill(loaded.get(), testVersion);
172 2 : std::stringstream ss;
173 2 : loaded->getView().printJSON(ss);
174 2 : std::cout << " Final content: " << ss.str() << "\n";
175 :
176 2 : BOOST_CHECK(true);
177 2 : }
178 :
179 4 : BOOST_AUTO_TEST_CASE(readonly_blocks_store_same_version) {
180 2 : std::cout << "\n=== TEST 6: Read-only blocks storing same version ===\n";
181 :
182 2 : auto ifc = DatabaseConfigurationInterface();
183 :
184 2 : auto cfg = std::make_shared<TestConfiguration001>();
185 2 : int testVersion = fixture.baseVersion + 6;
186 2 : cfg->getView().version = testVersion;
187 4 : cfg->getView().fillFromJSON("{\"field\": \"readonly_store_test\"}");
188 :
189 2 : std::cout << "Step 1: Creating version " << testVersion << "\n";
190 2 : BOOST_REQUIRE_EQUAL(ifc.saveActiveVersion(cfg.get(), false), 0);
191 :
192 2 : std::cout << "Step 2: Marking version as read-only\n";
193 2 : BOOST_REQUIRE_EQUAL(ifc.markActiveVersionReadonly(cfg.get()), 0);
194 :
195 2 : std::cout << "Step 3: Attempting to store same version again (not overwrite)\n";
196 4 : cfg->getView().fillFromJSON("{\"field\": \"new_content\"}");
197 2 : auto storeResult = ifc.saveActiveVersion(cfg.get(), false);
198 2 : std::cout << " Store same version returned: " << storeResult << "\n";
199 :
200 2 : BOOST_CHECK_NE(storeResult, 0);
201 2 : std::cout << " Verified: Cannot store duplicate version (readonly or not)\n";
202 2 : }
203 :
204 4 : BOOST_AUTO_TEST_CASE(mark_readonly_different_config_types) {
205 2 : std::cout << "\n=== TEST 7: Mark readonly on different config types ===\n";
206 :
207 2 : auto ifc = DatabaseConfigurationInterface();
208 :
209 2 : int testVersion = fixture.baseVersion + 7;
210 :
211 2 : auto cfg1 = std::make_shared<TestConfiguration001>();
212 2 : cfg1->getView().version = testVersion;
213 4 : cfg1->getView().fillFromJSON("{\"type\": \"config1\"}");
214 :
215 2 : auto cfg2 = std::make_shared<TestConfiguration002>();
216 2 : cfg2->getView().version = testVersion;
217 4 : cfg2->getView().fillFromJSON("{\"type\": \"config2\"}");
218 :
219 2 : std::cout << "Step 1: Creating both config types with version " << testVersion << "\n";
220 2 : BOOST_REQUIRE_EQUAL(ifc.saveActiveVersion(cfg1.get(), false), 0);
221 2 : BOOST_REQUIRE_EQUAL(ifc.saveActiveVersion(cfg2.get(), false), 0);
222 :
223 2 : std::cout << "Step 2: Marking TestConfiguration001 as read-only\n";
224 2 : BOOST_REQUIRE_EQUAL(ifc.markActiveVersionReadonly(cfg1.get()), 0);
225 :
226 2 : std::cout << "Step 3: Verifying TestConfiguration002 can still be overwritten\n";
227 4 : cfg2->getView().fillFromJSON("{\"type\": \"config2_updated\"}");
228 2 : auto overwriteResult = ifc.saveActiveVersion(cfg2.get(), true);
229 2 : std::cout << " Overwrite cfg2 returned: " << overwriteResult << "\n";
230 :
231 2 : BOOST_CHECK_EQUAL(overwriteResult, 0);
232 2 : std::cout << " Verified: Marking one config type readonly doesn't affect other types\n";
233 2 : }
234 :
235 : BOOST_AUTO_TEST_SUITE_END()
|