use rusqlite::ErrorCode;
use super::IndexOpenError;
use crate::sqlite_support::is_lock_contention;
fn sqlite_failure(code: ErrorCode) -> rusqlite::Error {
rusqlite::Error::SqliteFailure(
rusqlite::ffi::Error {
code,
extended_code: 0,
},
None,
)
}
#[test]
fn migration_lock_contention_is_retryable() {
let errors = [
anyhow::Error::from(sqlite_failure(ErrorCode::DatabaseBusy)),
anyhow::Error::from(sqlite_failure(ErrorCode::DatabaseLocked)),
anyhow::anyhow!("unsupported session index schema 9"),
];
let retryable = errors.map(|error| is_lock_contention(&IndexOpenError::from_migration(error)));
assert_eq!(retryable, [true, true, false]);
}
#[cfg(unix)]
#[test]
fn durability_flush_targets_the_live_wal() {
use std::path::PathBuf;
use super::super::tests::insert_placeholder_session;
use super::{open_index, wal_path};
let temp = tempfile::TempDir::new().unwrap();
let base = temp.path().canonicalize().unwrap();
let symlinked = base.join("symlinked");
std::fs::create_dir(&symlinked).unwrap();
std::fs::write(symlinked.join("catalog.sqlite3"), b"").unwrap();
std::os::unix::fs::symlink(
symlinked.join("catalog.sqlite3"),
symlinked.join("index.sqlite3"),
)
.unwrap();
#[cfg_attr(target_os = "macos", allow(unused_mut))]
let mut cases = vec![(symlinked.clone(), symlinked.join("catalog.sqlite3-wal"))];
#[cfg(not(target_os = "macos"))]
{
use std::{ffi::OsStr, os::unix::ffi::OsStrExt};
let non_utf8 = base.join(OsStr::from_bytes(b"caf\xe9"));
cases.push((non_utf8.clone(), non_utf8.join("index.sqlite3-wal")));
}
let resolved: Vec<(PathBuf, bool)> = cases
.iter()
.map(|(root, _)| {
let connection = open_index(root).unwrap();
let connection = connection.lock().unwrap();
insert_placeholder_session(&connection, "id");
let wal = wal_path(&connection).unwrap();
let exists = wal.exists();
(wal, exists)
})
.collect();
let expected: Vec<(PathBuf, bool)> = cases.into_iter().map(|(_, wal)| (wal, true)).collect();
assert_eq!(resolved, expected);
}