util: Work around (virtual) memory exhaustion on 32-bit w/ glibc
[bitcoinplatinum.git] / src / test / dbwrapper_tests.cpp
blob9d55beb8ea6100f5ea601ac13ea359587d4de631
1 // Copyright (c) 2012-2016 The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 #include "dbwrapper.h"
6 #include "uint256.h"
7 #include "random.h"
8 #include "test/test_bitcoin.h"
10 #include <boost/assign/std/vector.hpp> // for 'operator+=()'
11 #include <boost/assert.hpp>
12 #include <boost/test/unit_test.hpp>
14 // Test if a string consists entirely of null characters
15 bool is_null_key(const std::vector<unsigned char>& key) {
16 bool isnull = true;
18 for (unsigned int i = 0; i < key.size(); i++)
19 isnull &= (key[i] == '\x00');
21 return isnull;
24 BOOST_FIXTURE_TEST_SUITE(dbwrapper_tests, BasicTestingSetup)
26 BOOST_AUTO_TEST_CASE(dbwrapper)
28 // Perform tests both obfuscated and non-obfuscated.
29 for (int i = 0; i < 2; i++) {
30 bool obfuscate = (bool)i;
31 boost::filesystem::path ph = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
32 CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate);
33 char key = 'k';
34 uint256 in = GetRandHash();
35 uint256 res;
37 // Ensure that we're doing real obfuscation when obfuscate=true
38 BOOST_CHECK(obfuscate != is_null_key(dbwrapper_private::GetObfuscateKey(dbw)));
40 BOOST_CHECK(dbw.Write(key, in));
41 BOOST_CHECK(dbw.Read(key, res));
42 BOOST_CHECK_EQUAL(res.ToString(), in.ToString());
46 // Test batch operations
47 BOOST_AUTO_TEST_CASE(dbwrapper_batch)
49 // Perform tests both obfuscated and non-obfuscated.
50 for (int i = 0; i < 2; i++) {
51 bool obfuscate = (bool)i;
52 boost::filesystem::path ph = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
53 CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate);
55 char key = 'i';
56 uint256 in = GetRandHash();
57 char key2 = 'j';
58 uint256 in2 = GetRandHash();
59 char key3 = 'k';
60 uint256 in3 = GetRandHash();
62 uint256 res;
63 CDBBatch batch(dbw);
65 batch.Write(key, in);
66 batch.Write(key2, in2);
67 batch.Write(key3, in3);
69 // Remove key3 before it's even been written
70 batch.Erase(key3);
72 dbw.WriteBatch(batch);
74 BOOST_CHECK(dbw.Read(key, res));
75 BOOST_CHECK_EQUAL(res.ToString(), in.ToString());
76 BOOST_CHECK(dbw.Read(key2, res));
77 BOOST_CHECK_EQUAL(res.ToString(), in2.ToString());
79 // key3 should've never been written
80 BOOST_CHECK(dbw.Read(key3, res) == false);
84 BOOST_AUTO_TEST_CASE(dbwrapper_iterator)
86 // Perform tests both obfuscated and non-obfuscated.
87 for (int i = 0; i < 2; i++) {
88 bool obfuscate = (bool)i;
89 boost::filesystem::path ph = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
90 CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate);
92 // The two keys are intentionally chosen for ordering
93 char key = 'j';
94 uint256 in = GetRandHash();
95 BOOST_CHECK(dbw.Write(key, in));
96 char key2 = 'k';
97 uint256 in2 = GetRandHash();
98 BOOST_CHECK(dbw.Write(key2, in2));
100 std::unique_ptr<CDBIterator> it(const_cast<CDBWrapper*>(&dbw)->NewIterator());
102 // Be sure to seek past the obfuscation key (if it exists)
103 it->Seek(key);
105 char key_res;
106 uint256 val_res;
108 it->GetKey(key_res);
109 it->GetValue(val_res);
110 BOOST_CHECK_EQUAL(key_res, key);
111 BOOST_CHECK_EQUAL(val_res.ToString(), in.ToString());
113 it->Next();
115 it->GetKey(key_res);
116 it->GetValue(val_res);
117 BOOST_CHECK_EQUAL(key_res, key2);
118 BOOST_CHECK_EQUAL(val_res.ToString(), in2.ToString());
120 it->Next();
121 BOOST_CHECK_EQUAL(it->Valid(), false);
125 // Test that we do not obfuscation if there is existing data.
126 BOOST_AUTO_TEST_CASE(existing_data_no_obfuscate)
128 // We're going to share this boost::filesystem::path between two wrappers
129 boost::filesystem::path ph = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
130 create_directories(ph);
132 // Set up a non-obfuscated wrapper to write some initial data.
133 CDBWrapper* dbw = new CDBWrapper(ph, (1 << 10), false, false, false);
134 char key = 'k';
135 uint256 in = GetRandHash();
136 uint256 res;
138 BOOST_CHECK(dbw->Write(key, in));
139 BOOST_CHECK(dbw->Read(key, res));
140 BOOST_CHECK_EQUAL(res.ToString(), in.ToString());
142 // Call the destructor to free leveldb LOCK
143 delete dbw;
144 dbw = nullptr;
146 // Now, set up another wrapper that wants to obfuscate the same directory
147 CDBWrapper odbw(ph, (1 << 10), false, false, true);
149 // Check that the key/val we wrote with unobfuscated wrapper exists and
150 // is readable.
151 uint256 res2;
152 BOOST_CHECK(odbw.Read(key, res2));
153 BOOST_CHECK_EQUAL(res2.ToString(), in.ToString());
155 BOOST_CHECK(!odbw.IsEmpty()); // There should be existing data
156 BOOST_CHECK(is_null_key(dbwrapper_private::GetObfuscateKey(odbw))); // The key should be an empty string
158 uint256 in2 = GetRandHash();
159 uint256 res3;
161 // Check that we can write successfully
162 BOOST_CHECK(odbw.Write(key, in2));
163 BOOST_CHECK(odbw.Read(key, res3));
164 BOOST_CHECK_EQUAL(res3.ToString(), in2.ToString());
167 // Ensure that we start obfuscating during a reindex.
168 BOOST_AUTO_TEST_CASE(existing_data_reindex)
170 // We're going to share this boost::filesystem::path between two wrappers
171 boost::filesystem::path ph = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
172 create_directories(ph);
174 // Set up a non-obfuscated wrapper to write some initial data.
175 CDBWrapper* dbw = new CDBWrapper(ph, (1 << 10), false, false, false);
176 char key = 'k';
177 uint256 in = GetRandHash();
178 uint256 res;
180 BOOST_CHECK(dbw->Write(key, in));
181 BOOST_CHECK(dbw->Read(key, res));
182 BOOST_CHECK_EQUAL(res.ToString(), in.ToString());
184 // Call the destructor to free leveldb LOCK
185 delete dbw;
186 dbw = nullptr;
188 // Simulate a -reindex by wiping the existing data store
189 CDBWrapper odbw(ph, (1 << 10), false, true, true);
191 // Check that the key/val we wrote with unobfuscated wrapper doesn't exist
192 uint256 res2;
193 BOOST_CHECK(!odbw.Read(key, res2));
194 BOOST_CHECK(!is_null_key(dbwrapper_private::GetObfuscateKey(odbw)));
196 uint256 in2 = GetRandHash();
197 uint256 res3;
199 // Check that we can write successfully
200 BOOST_CHECK(odbw.Write(key, in2));
201 BOOST_CHECK(odbw.Read(key, res3));
202 BOOST_CHECK_EQUAL(res3.ToString(), in2.ToString());
205 BOOST_AUTO_TEST_CASE(iterator_ordering)
207 boost::filesystem::path ph = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
208 CDBWrapper dbw(ph, (1 << 20), true, false, false);
209 for (int x=0x00; x<256; ++x) {
210 uint8_t key = x;
211 uint32_t value = x*x;
212 BOOST_CHECK(dbw.Write(key, value));
215 std::unique_ptr<CDBIterator> it(const_cast<CDBWrapper*>(&dbw)->NewIterator());
216 for (int c=0; c<2; ++c) {
217 int seek_start;
218 if (c == 0)
219 seek_start = 0x00;
220 else
221 seek_start = 0x80;
222 it->Seek((uint8_t)seek_start);
223 for (int x=seek_start; x<256; ++x) {
224 uint8_t key;
225 uint32_t value;
226 BOOST_CHECK(it->Valid());
227 if (!it->Valid()) // Avoid spurious errors about invalid iterator's key and value in case of failure
228 break;
229 BOOST_CHECK(it->GetKey(key));
230 BOOST_CHECK(it->GetValue(value));
231 BOOST_CHECK_EQUAL(key, x);
232 BOOST_CHECK_EQUAL(value, x*x);
233 it->Next();
235 BOOST_CHECK(!it->Valid());
239 struct StringContentsSerializer {
240 // Used to make two serialized objects the same while letting them have a different lengths
241 // This is a terrible idea
242 std::string str;
243 StringContentsSerializer() {}
244 StringContentsSerializer(const std::string& inp) : str(inp) {}
246 StringContentsSerializer& operator+=(const std::string& s) {
247 str += s;
248 return *this;
250 StringContentsSerializer& operator+=(const StringContentsSerializer& s) { return *this += s.str; }
252 ADD_SERIALIZE_METHODS;
254 template <typename Stream, typename Operation>
255 inline void SerializationOp(Stream& s, Operation ser_action) {
256 if (ser_action.ForRead()) {
257 str.clear();
258 char c = 0;
259 while (true) {
260 try {
261 READWRITE(c);
262 str.push_back(c);
263 } catch (const std::ios_base::failure& e) {
264 break;
267 } else {
268 for (size_t i = 0; i < str.size(); i++)
269 READWRITE(str[i]);
274 BOOST_AUTO_TEST_CASE(iterator_string_ordering)
276 char buf[10];
278 boost::filesystem::path ph = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
279 CDBWrapper dbw(ph, (1 << 20), true, false, false);
280 for (int x=0x00; x<10; ++x) {
281 for (int y = 0; y < 10; y++) {
282 snprintf(buf, sizeof(buf), "%d", x);
283 StringContentsSerializer key(buf);
284 for (int z = 0; z < y; z++)
285 key += key;
286 uint32_t value = x*x;
287 BOOST_CHECK(dbw.Write(key, value));
291 std::unique_ptr<CDBIterator> it(const_cast<CDBWrapper*>(&dbw)->NewIterator());
292 for (int c=0; c<2; ++c) {
293 int seek_start;
294 if (c == 0)
295 seek_start = 0;
296 else
297 seek_start = 5;
298 snprintf(buf, sizeof(buf), "%d", seek_start);
299 StringContentsSerializer seek_key(buf);
300 it->Seek(seek_key);
301 for (int x=seek_start; x<10; ++x) {
302 for (int y = 0; y < 10; y++) {
303 snprintf(buf, sizeof(buf), "%d", x);
304 std::string exp_key(buf);
305 for (int z = 0; z < y; z++)
306 exp_key += exp_key;
307 StringContentsSerializer key;
308 uint32_t value;
309 BOOST_CHECK(it->Valid());
310 if (!it->Valid()) // Avoid spurious errors about invalid iterator's key and value in case of failure
311 break;
312 BOOST_CHECK(it->GetKey(key));
313 BOOST_CHECK(it->GetValue(value));
314 BOOST_CHECK_EQUAL(key.str, exp_key);
315 BOOST_CHECK_EQUAL(value, x*x);
316 it->Next();
319 BOOST_CHECK(!it->Valid());
325 BOOST_AUTO_TEST_SUITE_END()