|
|
@ -292,12 +292,12 @@ fn test_bad_stt_open() -> Result<(), Box<dyn Error>> { |
|
|
|
remove_dir_all(&dir.0)?; |
|
|
|
remove_dir_all(&dir.0)?; |
|
|
|
assert!(store |
|
|
|
assert!(store |
|
|
|
.bulk_loader() |
|
|
|
.bulk_loader() |
|
|
|
.load_quads(once(Quad { |
|
|
|
.load_quads(once(Quad::new( |
|
|
|
subject: NamedNode::new_unchecked("http://example.com/s").into(), |
|
|
|
NamedNode::new_unchecked("http://example.com/s"), |
|
|
|
predicate: NamedNode::new_unchecked("http://example.com/p"), |
|
|
|
NamedNode::new_unchecked("http://example.com/p"), |
|
|
|
object: NamedNode::new_unchecked("http://example.com/o").into(), |
|
|
|
NamedNode::new_unchecked("http://example.com/o"), |
|
|
|
graph_name: GraphName::DefaultGraph |
|
|
|
GraphName::DefaultGraph |
|
|
|
})) |
|
|
|
))) |
|
|
|
.is_err()); |
|
|
|
.is_err()); |
|
|
|
Ok(()) |
|
|
|
Ok(()) |
|
|
|
} |
|
|
|
} |
|
|
@ -305,12 +305,12 @@ fn test_bad_stt_open() -> Result<(), Box<dyn Error>> { |
|
|
|
#[test] |
|
|
|
#[test] |
|
|
|
#[cfg(not(target_family = "wasm"))] |
|
|
|
#[cfg(not(target_family = "wasm"))] |
|
|
|
fn test_backup() -> Result<(), Box<dyn Error>> { |
|
|
|
fn test_backup() -> Result<(), Box<dyn Error>> { |
|
|
|
let quad = QuadRef { |
|
|
|
let quad = QuadRef::new( |
|
|
|
subject: NamedNodeRef::new_unchecked("http://example.com/s").into(), |
|
|
|
NamedNodeRef::new_unchecked("http://example.com/s"), |
|
|
|
predicate: NamedNodeRef::new_unchecked("http://example.com/p"), |
|
|
|
NamedNodeRef::new_unchecked("http://example.com/p"), |
|
|
|
object: NamedNodeRef::new_unchecked("http://example.com/o").into(), |
|
|
|
NamedNodeRef::new_unchecked("http://example.com/o"), |
|
|
|
graph_name: GraphNameRef::DefaultGraph, |
|
|
|
GraphNameRef::DefaultGraph, |
|
|
|
}; |
|
|
|
); |
|
|
|
let store_dir = TempDir::default(); |
|
|
|
let store_dir = TempDir::default(); |
|
|
|
let backup_dir = TempDir::default(); |
|
|
|
let backup_dir = TempDir::default(); |
|
|
|
|
|
|
|
|
|
|
@ -371,76 +371,119 @@ fn test_backward_compatibility() -> Result<(), Box<dyn Error>> { |
|
|
|
|
|
|
|
|
|
|
|
#[test] |
|
|
|
#[test] |
|
|
|
#[cfg(not(target_family = "wasm"))] |
|
|
|
#[cfg(not(target_family = "wasm"))] |
|
|
|
fn test_secondary_and_readonly() -> Result<(), Box<dyn Error>> { |
|
|
|
fn test_secondary() -> Result<(), Box<dyn Error>> { |
|
|
|
let s = NamedNodeRef::new_unchecked("http://example.com/s"); |
|
|
|
let quad = QuadRef::new( |
|
|
|
let p = NamedNodeRef::new_unchecked("http://example.com/p"); |
|
|
|
NamedNodeRef::new_unchecked("http://example.com/s"), |
|
|
|
let g = NamedNodeRef::new_unchecked("http://example.com/g"); |
|
|
|
NamedNodeRef::new_unchecked("http://example.com/p"), |
|
|
|
let first_quad = QuadRef::new(s, p, NamedNodeRef::new_unchecked("http://example.com/o"), g); |
|
|
|
NamedNodeRef::new_unchecked("http://example.com/o"), |
|
|
|
let second_quad = QuadRef::new( |
|
|
|
GraphNameRef::DefaultGraph, |
|
|
|
s, |
|
|
|
|
|
|
|
p, |
|
|
|
|
|
|
|
NamedNodeRef::new_unchecked("http://example.com/o2"), |
|
|
|
|
|
|
|
g, |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
let second_quad_secondary = QuadRef::new( |
|
|
|
|
|
|
|
s, |
|
|
|
|
|
|
|
p, |
|
|
|
|
|
|
|
NamedNodeRef::new_unchecked("http://example.com/o2secondary"), |
|
|
|
|
|
|
|
g, |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
let second_quad_read_only = QuadRef::new( |
|
|
|
|
|
|
|
s, |
|
|
|
|
|
|
|
p, |
|
|
|
|
|
|
|
NamedNodeRef::new_unchecked("http://example.com/o2read_only"), |
|
|
|
|
|
|
|
g, |
|
|
|
|
|
|
|
); |
|
|
|
); |
|
|
|
let store_dir = TempDir::default(); |
|
|
|
let primary_dir = TempDir::default(); |
|
|
|
let secondary_dir = TempDir::default(); |
|
|
|
let secondary_dir = TempDir::default(); |
|
|
|
|
|
|
|
|
|
|
|
// primary store with read & write access
|
|
|
|
// We open the store
|
|
|
|
let primary = Store::open(store_dir.0.clone())?; |
|
|
|
let primary = Store::open(&primary_dir)?; |
|
|
|
primary.insert(first_quad)?; |
|
|
|
let secondary = Store::open_secondary(&primary_dir, &secondary_dir)?; |
|
|
|
primary.flush()?; |
|
|
|
|
|
|
|
// TODO: optimize should not be necessary here?
|
|
|
|
|
|
|
|
// if removed opening the readonly/secondary database throws an corruption error.
|
|
|
|
|
|
|
|
primary.optimize()?; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// create additional stores
|
|
|
|
// We insert a quad
|
|
|
|
// read_only will not update after creation, so it's important we create it after insertion of
|
|
|
|
primary.insert(quad)?; |
|
|
|
// data.
|
|
|
|
primary.flush()?; |
|
|
|
let read_only = Store::open_read_only(&store_dir)?; |
|
|
|
|
|
|
|
let secondary = Store::open_secondary(&store_dir, &secondary_dir)?; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// see if we can read the data on all three stores:
|
|
|
|
// It is readable from both stores
|
|
|
|
for store in &[&primary, &secondary, &read_only] { |
|
|
|
for store in &[&primary, &secondary] { |
|
|
|
|
|
|
|
assert!(store.contains(quad)?); |
|
|
|
assert_eq!( |
|
|
|
assert_eq!( |
|
|
|
store.iter().collect::<Result<Vec<_>, _>>()?, |
|
|
|
store.iter().collect::<Result<Vec<_>, _>>()?, |
|
|
|
vec![first_quad.into_owned()] |
|
|
|
vec![quad.into_owned()] |
|
|
|
); |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// now we add data to the primary store
|
|
|
|
// We validate the states
|
|
|
|
primary.insert(second_quad)?; |
|
|
|
primary.validate()?; |
|
|
|
// we expect that adding data is not possible with secondary or read_only.
|
|
|
|
secondary.validate()?; |
|
|
|
assert!(secondary.insert(second_quad_secondary).is_err()); |
|
|
|
|
|
|
|
assert!(read_only.insert(second_quad_read_only).is_err()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// see if we can read the new data from primary and secondary
|
|
|
|
// We close the primary store and remove its content
|
|
|
|
for store in &[&primary, &secondary] { |
|
|
|
drop(primary); |
|
|
|
assert_eq!( |
|
|
|
remove_dir_all(&primary_dir)?; |
|
|
|
store.iter().collect::<Result<Vec<_>, _>>()?, |
|
|
|
|
|
|
|
vec![first_quad.into_owned(), second_quad.into_owned()] |
|
|
|
// We secondary store is still readable
|
|
|
|
); |
|
|
|
assert!(secondary.contains(quad)?); |
|
|
|
|
|
|
|
secondary.validate()?; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Ok(()) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[test] |
|
|
|
|
|
|
|
#[cfg(not(target_family = "wasm"))] |
|
|
|
|
|
|
|
fn test_open_secondary_bad_dir() -> Result<(), Box<dyn Error>> { |
|
|
|
|
|
|
|
let primary_dir = TempDir::default(); |
|
|
|
|
|
|
|
let secondary_dir = TempDir::default(); |
|
|
|
|
|
|
|
create_dir(&primary_dir.0)?; |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
File::create(primary_dir.0.join("CURRENT"))?.write_all(b"foo")?; |
|
|
|
} |
|
|
|
} |
|
|
|
// readonly will not be updated, so here we see just the first document
|
|
|
|
assert!(Store::open_secondary(&primary_dir, &secondary_dir).is_err()); |
|
|
|
|
|
|
|
Ok(()) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[test] |
|
|
|
|
|
|
|
#[cfg(not(target_family = "wasm"))] |
|
|
|
|
|
|
|
fn test_read_only() -> Result<(), Box<dyn Error>> { |
|
|
|
|
|
|
|
let s = NamedNodeRef::new_unchecked("http://example.com/s"); |
|
|
|
|
|
|
|
let p = NamedNodeRef::new_unchecked("http://example.com/p"); |
|
|
|
|
|
|
|
let first_quad = QuadRef::new( |
|
|
|
|
|
|
|
s, |
|
|
|
|
|
|
|
p, |
|
|
|
|
|
|
|
NamedNodeRef::new_unchecked("http://example.com/o"), |
|
|
|
|
|
|
|
GraphNameRef::DefaultGraph, |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
let second_quad = QuadRef::new( |
|
|
|
|
|
|
|
s, |
|
|
|
|
|
|
|
p, |
|
|
|
|
|
|
|
NamedNodeRef::new_unchecked("http://example.com/o2"), |
|
|
|
|
|
|
|
GraphNameRef::DefaultGraph, |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
let store_dir = TempDir::default(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// We write to the store and close it
|
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
let read_write = Store::open(&store_dir)?; |
|
|
|
|
|
|
|
read_write.insert(first_quad)?; |
|
|
|
|
|
|
|
read_write.flush()?; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// We open as read-only
|
|
|
|
|
|
|
|
let read_only = Store::open_read_only(&store_dir)?; |
|
|
|
|
|
|
|
assert!(read_only.contains(first_quad)?); |
|
|
|
assert_eq!( |
|
|
|
assert_eq!( |
|
|
|
read_only.iter().collect::<Result<Vec<_>, _>>()?, |
|
|
|
read_only.iter().collect::<Result<Vec<_>, _>>()?, |
|
|
|
vec![first_quad.into_owned()] |
|
|
|
vec![first_quad.into_owned()] |
|
|
|
); |
|
|
|
); |
|
|
|
|
|
|
|
read_only.validate()?; |
|
|
|
|
|
|
|
|
|
|
|
primary.validate()?; |
|
|
|
// We open as read-write again
|
|
|
|
secondary.validate()?; |
|
|
|
let read_write = Store::open(&store_dir)?; |
|
|
|
|
|
|
|
read_write.insert(second_quad)?; |
|
|
|
|
|
|
|
read_write.flush()?; |
|
|
|
|
|
|
|
read_write.optimize()?; // Makes sure it's well flushed
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// The new quad is in the read-write instance but not the read-only instance
|
|
|
|
|
|
|
|
assert!(read_write.contains(second_quad)?); |
|
|
|
|
|
|
|
assert!(!read_only.contains(second_quad)?); |
|
|
|
read_only.validate()?; |
|
|
|
read_only.validate()?; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Ok(()) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[test] |
|
|
|
|
|
|
|
#[cfg(not(target_family = "wasm"))] |
|
|
|
|
|
|
|
fn test_open_read_only_bad_dir() -> Result<(), Box<dyn Error>> { |
|
|
|
|
|
|
|
let dir = TempDir::default(); |
|
|
|
|
|
|
|
create_dir(&dir.0)?; |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
File::create(dir.0.join("CURRENT"))?.write_all(b"foo")?; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
assert!(Store::open_read_only(&dir).is_err()); |
|
|
|
Ok(()) |
|
|
|
Ok(()) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|