Skip to main content

kvdb_shared_tests/
lib.rs

1// Copyright 2020 Parity Technologies
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9//! Shared tests for kvdb functionality, to be executed against actual implementations.
10
11use kvdb::{IoStatsKind, KeyValueDB};
12use std::io;
13
14/// A test for `KeyValueDB::get`.
15pub fn test_put_and_get(db: &dyn KeyValueDB) -> io::Result<()> {
16	let key1 = b"key1";
17
18	let mut transaction = db.transaction();
19	transaction.put(0, key1, b"horse");
20	db.write(transaction)?;
21	assert_eq!(&*db.get(0, key1)?.unwrap(), b"horse");
22	Ok(())
23}
24
25/// A test for `KeyValueDB::get`.
26pub fn test_delete_and_get(db: &dyn KeyValueDB) -> io::Result<()> {
27	let key1 = b"key1";
28
29	let mut transaction = db.transaction();
30	transaction.put(0, key1, b"horse");
31	db.write(transaction)?;
32	assert_eq!(&*db.get(0, key1)?.unwrap(), b"horse");
33
34	let mut transaction = db.transaction();
35	transaction.delete(0, key1);
36	db.write(transaction)?;
37	assert!(db.get(0, key1)?.is_none());
38	Ok(())
39}
40
41/// A test for `KeyValueDB::get`.
42/// Assumes the `db` has only 1 column.
43pub fn test_get_fails_with_non_existing_column(db: &dyn KeyValueDB) -> io::Result<()> {
44	assert!(db.get(1, &[]).is_err());
45	Ok(())
46}
47
48/// A test for `KeyValueDB::write`.
49pub fn test_write_clears_buffered_ops(db: &dyn KeyValueDB) -> io::Result<()> {
50	let mut batch = db.transaction();
51	batch.put(0, b"foo", b"bar");
52	db.write(batch)?;
53
54	assert_eq!(db.get(0, b"foo")?.unwrap(), b"bar");
55
56	let mut batch = db.transaction();
57	batch.put(0, b"foo", b"baz");
58	db.write(batch)?;
59
60	assert_eq!(db.get(0, b"foo")?.unwrap(), b"baz");
61	Ok(())
62}
63
64/// A test for `KeyValueDB::iter`.
65pub fn test_iter(db: &dyn KeyValueDB) -> io::Result<()> {
66	let key1 = b"key1";
67	let key2 = b"key2";
68
69	let mut transaction = db.transaction();
70	transaction.put(0, key1, key1);
71	transaction.put(0, key2, key2);
72	db.write(transaction)?;
73
74	let contents: Vec<_> = db.iter(0).into_iter().map(Result::unwrap).collect();
75	assert_eq!(contents.len(), 2);
76	assert_eq!(&*contents[0].0, key1);
77	assert_eq!(&*contents[0].1, key1);
78	assert_eq!(&*contents[1].0, key2);
79	assert_eq!(&*contents[1].1, key2);
80	Ok(())
81}
82
83/// A test for `KeyValueDB::iter_with_prefix`.
84pub fn test_iter_with_prefix(db: &dyn KeyValueDB) -> io::Result<()> {
85	let key1 = b"0";
86	let key2 = b"ab";
87	let key3 = b"abc";
88	let key4 = b"abcd";
89
90	let mut batch = db.transaction();
91	batch.put(0, key1, key1);
92	batch.put(0, key2, key2);
93	batch.put(0, key3, key3);
94	batch.put(0, key4, key4);
95	db.write(batch)?;
96
97	// empty prefix
98	let contents: Vec<_> = db.iter_with_prefix(0, b"").into_iter().map(Result::unwrap).collect();
99	assert_eq!(contents.len(), 4);
100	assert_eq!(&*contents[0].0, key1);
101	assert_eq!(&*contents[1].0, key2);
102	assert_eq!(&*contents[2].0, key3);
103	assert_eq!(&*contents[3].0, key4);
104
105	// prefix a
106	let contents: Vec<_> = db.iter_with_prefix(0, b"a").into_iter().map(Result::unwrap).collect();
107	assert_eq!(contents.len(), 3);
108	assert_eq!(&*contents[0].0, key2);
109	assert_eq!(&*contents[1].0, key3);
110	assert_eq!(&*contents[2].0, key4);
111
112	// prefix abc
113	let contents: Vec<_> = db.iter_with_prefix(0, b"abc").into_iter().map(Result::unwrap).collect();
114	assert_eq!(contents.len(), 2);
115	assert_eq!(&*contents[0].0, key3);
116	assert_eq!(&*contents[1].0, key4);
117
118	// prefix abcde
119	let contents: Vec<_> = db.iter_with_prefix(0, b"abcde").into_iter().map(Result::unwrap).collect();
120	assert_eq!(contents.len(), 0);
121
122	// prefix 0
123	let contents: Vec<_> = db.iter_with_prefix(0, b"0").into_iter().map(Result::unwrap).collect();
124	assert_eq!(contents.len(), 1);
125	assert_eq!(&*contents[0].0, key1);
126	Ok(())
127}
128
129/// The number of columns required to run `test_io_stats`.
130pub const IO_STATS_NUM_COLUMNS: u32 = 3;
131
132/// A test for `KeyValueDB::io_stats`.
133/// Assumes that the `db` has at least 3 columns.
134pub fn test_io_stats(db: &dyn KeyValueDB) -> io::Result<()> {
135	let key1 = b"kkk";
136	let mut batch = db.transaction();
137	batch.put(0, key1, key1);
138	batch.put(1, key1, key1);
139	batch.put(2, key1, key1);
140
141	for _ in 0..10 {
142		db.get(0, key1)?;
143	}
144
145	db.write(batch)?;
146
147	let io_stats = db.io_stats(IoStatsKind::SincePrevious);
148	assert_eq!(io_stats.transactions, 1);
149	assert_eq!(io_stats.writes, 3);
150	assert_eq!(io_stats.bytes_written, 18);
151	assert_eq!(io_stats.reads, 10);
152	assert_eq!(io_stats.bytes_read, 30);
153
154	let new_io_stats = db.io_stats(IoStatsKind::SincePrevious);
155	// Since we taken previous statistic period,
156	// this is expected to be totally empty.
157	assert_eq!(new_io_stats.transactions, 0);
158
159	// but the overall should be there
160	let new_io_stats = db.io_stats(IoStatsKind::Overall);
161	assert_eq!(new_io_stats.bytes_written, 18);
162
163	let mut batch = db.transaction();
164	batch.delete(0, key1);
165	batch.delete(1, key1);
166	batch.delete(2, key1);
167
168	// transaction is not commited yet
169	assert_eq!(db.io_stats(IoStatsKind::SincePrevious).writes, 0);
170
171	db.write(batch)?;
172	// now it is, and delete is counted as write
173	assert_eq!(db.io_stats(IoStatsKind::SincePrevious).writes, 3);
174	Ok(())
175}
176
177/// The number of columns required to run `test_delete_prefix`.
178pub const DELETE_PREFIX_NUM_COLUMNS: u32 = 7;
179
180/// A test for `KeyValueDB::delete_prefix`.
181pub fn test_delete_prefix(db: &dyn KeyValueDB) -> io::Result<()> {
182	let keys = [
183		&[][..],
184		&[0u8][..],
185		&[0, 1][..],
186		&[1][..],
187		&[1, 0][..],
188		&[1, 255][..],
189		&[1, 255, 255][..],
190		&[2][..],
191		&[2, 0][..],
192		&[2, 255][..],
193		&[255; 16][..],
194	];
195	let init_db = |ix: u32| -> io::Result<()> {
196		let mut batch = db.transaction();
197		for (i, key) in keys.iter().enumerate() {
198			batch.put(ix, key, &[i as u8]);
199		}
200		db.write(batch)?;
201		Ok(())
202	};
203	let check_db = |ix: u32, content: [bool; 11]| -> io::Result<()> {
204		let mut state = [true; 11];
205		for (c, key) in keys.iter().enumerate() {
206			state[c] = db.get(ix, key)?.is_some();
207		}
208		assert_eq!(state, content, "at {}", ix);
209		Ok(())
210	};
211	let tests: [_; DELETE_PREFIX_NUM_COLUMNS as usize] = [
212		// standard
213		(&[1u8][..], [true, true, true, false, false, false, false, true, true, true, true]),
214		// edge
215		(&[1u8, 255, 255][..], [true, true, true, true, true, true, false, true, true, true, true]),
216		// none 1
217		(&[1, 2][..], [true, true, true, true, true, true, true, true, true, true, true]),
218		// none 2
219		(&[8][..], [true, true, true, true, true, true, true, true, true, true, true]),
220		// last value
221		(&[255, 255][..], [true, true, true, true, true, true, true, true, true, true, false]),
222		// last value, limit prefix
223		(&[255][..], [true, true, true, true, true, true, true, true, true, true, false]),
224		// all
225		(&[][..], [false, false, false, false, false, false, false, false, false, false, false]),
226	];
227	for (ix, test) in tests.iter().enumerate() {
228		let ix = ix as u32;
229		init_db(ix)?;
230		let mut batch = db.transaction();
231		batch.delete_prefix(ix, test.0);
232		db.write(batch)?;
233		check_db(ix, test.1)?;
234	}
235
236	Ok(())
237}
238
239/// A complex test.
240pub fn test_complex(db: &dyn KeyValueDB) -> io::Result<()> {
241	let key1 = b"02c69be41d0b7e40352fc85be1cd65eb03d40ef8427a0ca4596b1ead9a00e9fc";
242	let key2 = b"03c69be41d0b7e40352fc85be1cd65eb03d40ef8427a0ca4596b1ead9a00e9fc";
243	let key3 = b"04c00000000b7e40352fc85be1cd65eb03d40ef8427a0ca4596b1ead9a00e9fc";
244	let key4 = b"04c01111110b7e40352fc85be1cd65eb03d40ef8427a0ca4596b1ead9a00e9fc";
245	let key5 = b"04c02222220b7e40352fc85be1cd65eb03d40ef8427a0ca4596b1ead9a00e9fc";
246
247	let mut batch = db.transaction();
248	batch.put(0, key1, b"cat");
249	batch.put(0, key2, b"dog");
250	batch.put(0, key3, b"caterpillar");
251	batch.put(0, key4, b"beef");
252	batch.put(0, key5, b"fish");
253	db.write(batch)?;
254
255	assert_eq!(&*db.get(0, key1)?.unwrap(), b"cat");
256
257	let contents: Vec<_> = db.iter(0).into_iter().map(Result::unwrap).collect();
258	assert_eq!(contents.len(), 5);
259	assert_eq!(contents[0].0.to_vec(), key1.to_vec());
260	assert_eq!(&*contents[0].1, b"cat");
261	assert_eq!(contents[1].0.to_vec(), key2.to_vec());
262	assert_eq!(&*contents[1].1, b"dog");
263
264	let mut prefix_iter = db.iter_with_prefix(0, b"04c0");
265	assert_eq!(*prefix_iter.next().unwrap().unwrap().1, b"caterpillar"[..]);
266	assert_eq!(*prefix_iter.next().unwrap().unwrap().1, b"beef"[..]);
267	assert_eq!(*prefix_iter.next().unwrap().unwrap().1, b"fish"[..]);
268
269	let mut batch = db.transaction();
270	batch.delete(0, key1);
271	db.write(batch)?;
272
273	assert!(db.get(0, key1)?.is_none());
274
275	let mut batch = db.transaction();
276	batch.put(0, key1, b"cat");
277	db.write(batch)?;
278
279	let mut transaction = db.transaction();
280	transaction.put(0, key3, b"elephant");
281	transaction.delete(0, key1);
282	db.write(transaction)?;
283	assert!(db.get(0, key1)?.is_none());
284	assert_eq!(&*db.get(0, key3)?.unwrap(), b"elephant");
285
286	assert_eq!(&*db.get_by_prefix(0, key3).unwrap().unwrap(), b"elephant");
287	assert_eq!(&*db.get_by_prefix(0, key2).unwrap().unwrap(), b"dog");
288
289	let mut transaction = db.transaction();
290	transaction.put(0, key1, b"horse");
291	transaction.delete(0, key3);
292	db.write(transaction)?;
293	assert!(db.get(0, key3)?.is_none());
294	assert_eq!(&*db.get(0, key1)?.unwrap(), b"horse");
295
296	assert!(db.get(0, key3)?.is_none());
297	assert_eq!(&*db.get(0, key1)?.unwrap(), b"horse");
298	Ok(())
299}