Skip to content

Commit 06ee7cc

Browse files
Introduce integration tests
- Move some of the existing tests to tests/db.rs - Split out an internal "kirunadb_test_helpers" crate for code shared between unit and integration tests. - Make transaction_manager module public, for integration tests, fix the new Clippy warnings. - Add "rlib" crate type for kirunadb so that the integration tests could actually import it. This is rust-lang/cargo#6659 and it can be removed once that issue is fixed.
1 parent 2b60170 commit 06ee7cc

File tree

6 files changed

+252
-219
lines changed

6 files changed

+252
-219
lines changed

Cargo.toml

+4-2
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,16 @@ repository = "https://github.com/laurynas-biveinis/kirunadb"
1212
edition = "2021"
1313

1414
[lib]
15-
crate-type=["staticlib", "cdylib"]
15+
crate-type=["rlib", "staticlib", "cdylib"]
1616

1717
[dependencies]
18-
tempfile = "3.5"
1918
cap-std = "1.0"
2019
cxx = "1.0"
2120
num_enum = "0.6"
2221
thiserror = "1.0.40"
2322

2423
[build-dependencies]
2524
cxx-build = "1.0"
25+
26+
[dev-dependencies]
27+
kirunadb_test_helpers = { path = "kirunadb_test_helpers" }

kirunadb_test_helpers/Cargo.toml

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[package]
2+
name = "kirunadb_test_helpers"
3+
version = "0.0.1"
4+
edition = "2021"
5+
authors = ["Laurynas Biveinis <laurynas.biveinis@gmail.com>"]
6+
license = "MIT OR Apache-2.0"
7+
description = "An internal KirunaDB crate"
8+
homepage = "https://github.com/laurynas-biveinis/kirunadb"
9+
repository = "https://github.com/laurynas-biveinis/kirunadb"
10+
11+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
12+
13+
[dependencies]
14+
kirunadb = { path = ".." }
15+
tempfile = "3.5"

kirunadb_test_helpers/src/lib.rs

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright(C) 2023 Laurynas Biveinis
2+
#![deny(clippy::pedantic)]
3+
4+
use kirunadb::Db;
5+
use std::path::Path;
6+
use tempfile::TempDir;
7+
8+
pub fn get_temp_dir() -> TempDir {
9+
TempDir::new().unwrap()
10+
}
11+
12+
pub fn open_db_err(path: &Path) {
13+
let db = Db::open(path);
14+
assert!(db.is_err());
15+
}

src/lib.rs

+4-215
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
mod buffer_manager;
55
mod ffi_cxx;
66
mod log;
7-
mod transaction_manager;
7+
pub mod transaction_manager;
88

99
use crate::log::Log;
1010
use buffer_manager::BufferManager;
@@ -102,16 +102,11 @@ impl Db {
102102

103103
#[cfg(test)]
104104
mod tests {
105-
use crate::transaction_manager::Transaction;
106105
use crate::Db;
107-
use std::fs::{self, File, OpenOptions};
108-
use std::io::{Read, Seek, SeekFrom, Write};
106+
use std::fs;
109107
use std::path::Path;
110-
use tempfile::TempDir;
111-
112-
fn get_temp_dir() -> TempDir {
113-
TempDir::new().unwrap()
114-
}
108+
use kirunadb_test_helpers::get_temp_dir;
109+
use kirunadb_test_helpers::open_db_err;
115110

116111
fn make_path_read_only(path: &Path) {
117112
let mut path_permissions = path.metadata().unwrap().permissions();
@@ -124,50 +119,6 @@ mod tests {
124119
assert!(db.is_ok());
125120
}
126121

127-
fn open_db_err(path: &Path) {
128-
let db = Db::open(path);
129-
assert!(db.is_err());
130-
}
131-
132-
fn commit_ok(mut t: Transaction) {
133-
let commit_result = t.commit();
134-
assert!(commit_result.is_ok());
135-
}
136-
137-
fn open_log_for_corruption(db_path: &Path) -> File {
138-
let log_path = db_path.join("LOG");
139-
OpenOptions::new()
140-
.read(true)
141-
.write(true)
142-
.create(false)
143-
.open(log_path)
144-
.unwrap()
145-
}
146-
147-
fn expect_u64(file: &mut File, offset: u64, value: u64) {
148-
file.seek(SeekFrom::Start(offset)).unwrap();
149-
let mut u64_buf = [0; 8];
150-
file.read_exact(&mut u64_buf).unwrap();
151-
let existing = u64::from_ne_bytes(u64_buf);
152-
assert_eq!(existing, value);
153-
}
154-
155-
fn replace_u64(file: &mut File, offset: u64, expected: u64, new: u64) {
156-
expect_u64(file, offset, expected);
157-
file.seek(SeekFrom::Start(offset)).unwrap();
158-
file.write_all(&new.to_ne_bytes()).unwrap();
159-
}
160-
161-
fn replace_u8(file: &mut File, offset: u64, expected: u8, new: u8) {
162-
file.seek(SeekFrom::Start(offset)).unwrap();
163-
let mut u8_buf = [0; 1];
164-
file.read_exact(&mut u8_buf).unwrap();
165-
let existing = u8::from_ne_bytes(u8_buf);
166-
assert_eq!(existing, expected);
167-
file.seek(SeekFrom::Start(offset)).unwrap();
168-
file.write_all(&new.to_ne_bytes()).unwrap();
169-
}
170-
171122
#[test]
172123
fn create_db_in_existing_empty_dir() {
173124
let temp_dir = get_temp_dir();
@@ -253,167 +204,5 @@ mod tests {
253204
let _transaction = db.begin_transaction();
254205
}
255206

256-
#[test]
257-
fn sequential_transaction_ids() {
258-
let temp_dir = get_temp_dir();
259-
let path = temp_dir.path();
260-
let mut db = Db::open(path).unwrap();
261-
let t1 = db.begin_transaction();
262-
let t1_id = t1.id();
263-
commit_ok(t1);
264-
let t2 = db.begin_transaction();
265-
let t2_id = t2.id();
266-
commit_ok(t2);
267-
assert_ne!(t1_id, t2_id);
268-
}
269-
270-
#[test]
271-
fn interleaved_transaction_ids() {
272-
let temp_dir = get_temp_dir();
273-
let path = temp_dir.path();
274-
let mut db = Db::open(path).unwrap();
275-
let t1 = db.begin_transaction();
276-
let t1_id = t1.id();
277-
let t2 = db.begin_transaction();
278-
let t2_id = t2.id();
279-
commit_ok(t1);
280-
commit_ok(t2);
281-
assert_ne!(t1_id, t2_id);
282-
}
283-
284-
#[test]
285-
fn transaction_new_node() {
286-
let temp_dir = get_temp_dir();
287-
let path = temp_dir.path();
288-
let mut db = Db::open(path).unwrap();
289-
let mut transaction = db.begin_transaction();
290-
let _new_node_id = transaction.new_art_descriptor_node();
291-
commit_ok(transaction);
292-
}
293-
294-
#[test]
295-
fn transaction_two_new_nodes() {
296-
let temp_dir = get_temp_dir();
297-
let path = temp_dir.path();
298-
let mut db = Db::open(path).unwrap();
299-
let mut t1 = db.begin_transaction();
300-
let t1_new_node_id = t1.new_art_descriptor_node();
301-
commit_ok(t1);
302-
let mut t2 = db.begin_transaction();
303-
let t2_new_node_id = t2.new_art_descriptor_node();
304-
commit_ok(t2);
305-
assert_ne!(t1_new_node_id, t2_new_node_id);
306-
}
307-
308-
#[test]
309-
fn node_id_assignment_consistent_on_reopen() {
310-
let temp_dir = get_temp_dir();
311-
let path = temp_dir.path();
312-
let n1_id;
313-
{
314-
let mut created_db = Db::open(path).unwrap();
315-
let mut transaction = created_db.begin_transaction();
316-
n1_id = transaction.new_art_descriptor_node();
317-
commit_ok(transaction);
318-
}
319-
{
320-
let mut opened_db = Db::open(path).unwrap();
321-
let mut transaction = opened_db.begin_transaction();
322-
let n2_id = transaction.new_art_descriptor_node();
323-
commit_ok(transaction);
324-
assert_ne!(n1_id, n2_id);
325-
}
326-
}
327-
328-
#[test]
329-
fn node_id_assignment_consistent_on_reopen_two_ids() {
330-
let temp_dir = get_temp_dir();
331-
let path = temp_dir.path();
332-
let n1_id;
333-
let n2_id;
334-
{
335-
let mut created_db = Db::open(path).unwrap();
336-
let mut t1 = created_db.begin_transaction();
337-
n1_id = t1.new_art_descriptor_node();
338-
commit_ok(t1);
339-
let mut t2 = created_db.begin_transaction();
340-
n2_id = t2.new_art_descriptor_node();
341-
commit_ok(t2);
342-
}
343-
{
344-
let mut opened_db = Db::open(path).unwrap();
345-
let mut transaction = opened_db.begin_transaction();
346-
let n3_id = transaction.new_art_descriptor_node();
347-
commit_ok(transaction);
348-
assert_ne!(n1_id, n3_id);
349-
assert_ne!(n2_id, n3_id);
350-
}
351-
}
352-
353-
#[test]
354-
fn node_id_assignment_consistent_on_reopen_two_ids_lower_id_committed_later() {
355-
let temp_dir = get_temp_dir();
356-
let path = temp_dir.path();
357-
let n1_id;
358-
let n2_id;
359-
{
360-
let mut created_db = Db::open(path).unwrap();
361-
let mut t1 = created_db.begin_transaction();
362-
n1_id = t1.new_art_descriptor_node();
363-
let mut t2 = created_db.begin_transaction();
364-
n2_id = t2.new_art_descriptor_node();
365-
commit_ok(t2);
366-
commit_ok(t1);
367-
}
368-
{
369-
let mut opened_db = Db::open(path).unwrap();
370-
let mut transaction = opened_db.begin_transaction();
371-
let n3_id = transaction.new_art_descriptor_node();
372-
commit_ok(transaction);
373-
assert_ne!(n1_id, n3_id);
374-
assert_ne!(n2_id, n3_id);
375-
}
376-
}
377-
378-
#[test]
379-
fn node_id_assignment_corruption_repeated_id() {
380-
let temp_dir = get_temp_dir();
381-
let path = temp_dir.path();
382-
let n1_id;
383-
let n2_id;
384-
{
385-
let mut created_db = Db::open(path).unwrap();
386-
let mut t1 = created_db.begin_transaction();
387-
n1_id = t1.new_art_descriptor_node();
388-
commit_ok(t1);
389-
let mut t2 = created_db.begin_transaction();
390-
n2_id = t2.new_art_descriptor_node();
391-
commit_ok(t2);
392-
}
393-
{
394-
let mut log_file = open_log_for_corruption(path);
395-
expect_u64(&mut log_file, 1, n1_id);
396-
replace_u64(&mut log_file, 10, n2_id, n1_id);
397-
}
398-
open_db_err(path);
399-
}
400-
401-
#[test]
402-
fn log_corruption_unknown_type() {
403-
let temp_dir = get_temp_dir();
404-
let path = temp_dir.path();
405-
{
406-
let mut created_db = Db::open(path).unwrap();
407-
let mut transaction = created_db.begin_transaction();
408-
transaction.new_art_descriptor_node();
409-
commit_ok(transaction);
410-
}
411-
{
412-
let mut log_file = open_log_for_corruption(path);
413-
replace_u8(&mut log_file, 0, 0, 0xBD);
414-
}
415-
open_db_err(path);
416-
}
417-
418207
// TODO(laurynas): missing VERSION tests
419208
}

src/transaction_manager.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ impl TransactionChangeNewNode {
2323
}
2424

2525
#[inline]
26-
pub fn node_id(&self) -> u64 {
26+
#[must_use] pub fn node_id(&self) -> u64 {
2727
self.node_id
2828
}
2929
}
@@ -44,6 +44,8 @@ impl Transaction {
4444
}
4545
}
4646

47+
/// # Errors
48+
/// Will return `io::Error` if it encounters any.
4749
pub fn commit(&mut self) -> Result<(), io::Error> {
4850
self.manager.borrow_mut().log_append(&self.changes)
4951
}
@@ -57,7 +59,7 @@ impl Transaction {
5759
new_node_id
5860
}
5961

60-
pub fn id(&self) -> u64 {
62+
#[must_use] pub fn id(&self) -> u64 {
6163
self.id
6264
}
6365
}

0 commit comments

Comments
 (0)