tests: Add missing locks to tests
[bitcoinplatinum.git] / src / test / dbwrapper_tests.cpp
blobc1625cf47617c2a3ea3ac666f641532ee4fbb4b6
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/test/unit_test.hpp>
12 // Test if a string consists entirely of null characters
13 bool is_null_key(const std::vector<unsigned char>& key) {
14 bool isnull = true;
16 for (unsigned int i = 0; i < key.size(); i++)
17 isnull &= (key[i] == '\x00');
19 return isnull;
22 BOOST_FIXTURE_TEST_SUITE(dbwrapper_tests, BasicTestingSetup)
24 BOOST_AUTO_TEST_CASE(dbwrapper)
26 // Perform tests both obfuscated and non-obfuscated.
27 for (bool obfuscate : {false, true}) {
28 fs::path ph = fs::temp_directory_path() / fs::unique_path();
29 CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate);
30 char key = 'k';
31 uint256 in = InsecureRand256();
32 uint256 res;
34 // Ensure that we're doing real obfuscation when obfuscate=true
35 BOOST_CHECK(obfuscate != is_null_key(dbwrapper_private::GetObfuscateKey(dbw)));
37 BOOST_CHECK(dbw.Write(key, in));
38 BOOST_CHECK(dbw.Read(key, res));
39 BOOST_CHECK_EQUAL(res.ToString(), in.ToString());
43 // Test batch operations
44 BOOST_AUTO_TEST_CASE(dbwrapper_batch)
46 // Perform tests both obfuscated and non-obfuscated.
47 for (bool obfuscate : {false, true}) {
48 fs::path ph = fs::temp_directory_path() / fs::unique_path();
49 CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate);
51 char key = 'i';
52 uint256 in = InsecureRand256();
53 char key2 = 'j';
54 uint256 in2 = InsecureRand256();
55 char key3 = 'k';
56 uint256 in3 = InsecureRand256();
58 uint256 res;
59 CDBBatch batch(dbw);
61 batch.Write(key, in);
62 batch.Write(key2, in2);
63 batch.Write(key3, in3);
65 // Remove key3 before it's even been written
66 batch.Erase(key3);
68 dbw.WriteBatch(batch);
70 BOOST_CHECK(dbw.Read(key, res));
71 BOOST_CHECK_EQUAL(res.ToString(), in.ToString());
72 BOOST_CHECK(dbw.Read(key2, res));
73 BOOST_CHECK_EQUAL(res.ToString(), in2.ToString());
75 // key3 should've never been written
76 BOOST_CHECK(dbw.Read(key3, res) == false);
80 BOOST_AUTO_TEST_CASE(dbwrapper_iterator)
82 // Perform tests both obfuscated and non-obfuscated.
83 for (bool obfuscate : {false, true}) {
84 fs::path ph = fs::temp_directory_path() / fs::unique_path();
85 CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate);
87 // The two keys are intentionally chosen for ordering
88 char key = 'j';
89 uint256 in = InsecureRand256();
90 BOOST_CHECK(dbw.Write(key, in));
91 char key2 = 'k';
92 uint256 in2 = InsecureRand256();
93 BOOST_CHECK(dbw.Write(key2, in2));
95 std::unique_ptr<CDBIterator> it(const_cast<CDBWrapper&>(dbw).NewIterator());
97 // Be sure to seek past the obfuscation key (if it exists)
98 it->Seek(key);
100 char key_res;
101 uint256 val_res;
103 it->GetKey(key_res);
104 it->GetValue(val_res);
105 BOOST_CHECK_EQUAL(key_res, key);
106 BOOST_CHECK_EQUAL(val_res.ToString(), in.ToString());
108 it->Next();
110 it->GetKey(key_res);
111 it->GetValue(val_res);
112 BOOST_CHECK_EQUAL(key_res, key2);
113 BOOST_CHECK_EQUAL(val_res.ToString(), in2.ToString());
115 it->Next();
116 BOOST_CHECK_EQUAL(it->Valid(), false);
120 // Test that we do not obfuscation if there is existing data.
121 BOOST_AUTO_TEST_CASE(existing_data_no_obfuscate)
123 // We're going to share this fs::path between two wrappers
124 fs::path ph = fs::temp_directory_path() / fs::unique_path();
125 create_directories(ph);
127 // Set up a non-obfuscated wrapper to write some initial data.
128 std::unique_ptr<CDBWrapper> dbw = MakeUnique<CDBWrapper>(ph, (1 << 10), false, false, false);
129 char key = 'k';
130 uint256 in = InsecureRand256();
131 uint256 res;
133 BOOST_CHECK(dbw->Write(key, in));
134 BOOST_CHECK(dbw->Read(key, res));
135 BOOST_CHECK_EQUAL(res.ToString(), in.ToString());
137 // Call the destructor to free leveldb LOCK
138 dbw.reset();
140 // Now, set up another wrapper that wants to obfuscate the same directory
141 CDBWrapper odbw(ph, (1 << 10), false, false, true);
143 // Check that the key/val we wrote with unobfuscated wrapper exists and
144 // is readable.
145 uint256 res2;
146 BOOST_CHECK(odbw.Read(key, res2));
147 BOOST_CHECK_EQUAL(res2.ToString(), in.ToString());
149 BOOST_CHECK(!odbw.IsEmpty()); // There should be existing data
150 BOOST_CHECK(is_null_key(dbwrapper_private::GetObfuscateKey(odbw))); // The key should be an empty string
152 uint256 in2 = InsecureRand256();
153 uint256 res3;
155 // Check that we can write successfully
156 BOOST_CHECK(odbw.Write(key, in2));
157 BOOST_CHECK(odbw.Read(key, res3));
158 BOOST_CHECK_EQUAL(res3.ToString(), in2.ToString());
161 // Ensure that we start obfuscating during a reindex.
162 BOOST_AUTO_TEST_CASE(existing_data_reindex)
164 // We're going to share this fs::path between two wrappers
165 fs::path ph = fs::temp_directory_path() / fs::unique_path();
166 create_directories(ph);
168 // Set up a non-obfuscated wrapper to write some initial data.
169 std::unique_ptr<CDBWrapper> dbw = MakeUnique<CDBWrapper>(ph, (1 << 10), false, false, false);
170 char key = 'k';
171 uint256 in = InsecureRand256();
172 uint256 res;
174 BOOST_CHECK(dbw->Write(key, in));
175 BOOST_CHECK(dbw->Read(key, res));
176 BOOST_CHECK_EQUAL(res.ToString(), in.ToString());
178 // Call the destructor to free leveldb LOCK
179 dbw.reset();
181 // Simulate a -reindex by wiping the existing data store
182 CDBWrapper odbw(ph, (1 << 10), false, true, true);
184 // Check that the key/val we wrote with unobfuscated wrapper doesn't exist
185 uint256 res2;
186 BOOST_CHECK(!odbw.Read(key, res2));
187 BOOST_CHECK(!is_null_key(dbwrapper_private::GetObfuscateKey(odbw)));
189 uint256 in2 = InsecureRand256();
190 uint256 res3;
192 // Check that we can write successfully
193 BOOST_CHECK(odbw.Write(key, in2));
194 BOOST_CHECK(odbw.Read(key, res3));
195 BOOST_CHECK_EQUAL(res3.ToString(), in2.ToString());
198 BOOST_AUTO_TEST_CASE(iterator_ordering)
200 fs::path ph = fs::temp_directory_path() / fs::unique_path();
201 CDBWrapper dbw(ph, (1 << 20), true, false, false);
202 for (int x=0x00; x<256; ++x) {
203 uint8_t key = x;
204 uint32_t value = x*x;
205 if (!(x & 1)) BOOST_CHECK(dbw.Write(key, value));
208 // Check that creating an iterator creates a snapshot
209 std::unique_ptr<CDBIterator> it(const_cast<CDBWrapper&>(dbw).NewIterator());
211 for (int x=0x00; x<256; ++x) {
212 uint8_t key = x;
213 uint32_t value = x*x;
214 if (x & 1) BOOST_CHECK(dbw.Write(key, value));
217 for (int seek_start : {0x00, 0x80}) {
218 it->Seek((uint8_t)seek_start);
219 for (int x=seek_start; x<255; ++x) {
220 uint8_t key;
221 uint32_t value;
222 BOOST_CHECK(it->Valid());
223 if (!it->Valid()) // Avoid spurious errors about invalid iterator's key and value in case of failure
224 break;
225 BOOST_CHECK(it->GetKey(key));
226 if (x & 1) {
227 BOOST_CHECK_EQUAL(key, x + 1);
228 continue;
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 explicit 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 fs::path ph = fs::temp_directory_path() / fs::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 seek_start : {0, 5}) {
293 snprintf(buf, sizeof(buf), "%d", seek_start);
294 StringContentsSerializer seek_key(buf);
295 it->Seek(seek_key);
296 for (int x=seek_start; x<10; ++x) {
297 for (int y = 0; y < 10; y++) {
298 snprintf(buf, sizeof(buf), "%d", x);
299 std::string exp_key(buf);
300 for (int z = 0; z < y; z++)
301 exp_key += exp_key;
302 StringContentsSerializer key;
303 uint32_t value;
304 BOOST_CHECK(it->Valid());
305 if (!it->Valid()) // Avoid spurious errors about invalid iterator's key and value in case of failure
306 break;
307 BOOST_CHECK(it->GetKey(key));
308 BOOST_CHECK(it->GetValue(value));
309 BOOST_CHECK_EQUAL(key.str, exp_key);
310 BOOST_CHECK_EQUAL(value, x*x);
311 it->Next();
314 BOOST_CHECK(!it->Valid());
320 BOOST_AUTO_TEST_SUITE_END()