Skip to content

Commit e7533bf

Browse files
committed
Test that verification does verify things.
1 parent d4b5e70 commit e7533bf

File tree

3 files changed

+68
-4
lines changed

3 files changed

+68
-4
lines changed

Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/snapshot/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,4 @@ spacetimedb-schema = { path = "../schema" }
3434
anyhow.workspace = true
3535
env_logger.workspace = true
3636
pretty_assertions = { workspace = true, features = ["unstable"] }
37+
rand.workspace = true

crates/snapshot/tests/remote.rs

+66-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
use std::{sync::Arc, time::Instant};
1+
use std::{io, sync::Arc, time::Instant};
22

33
use env_logger::Env;
44
use log::info;
55
use pretty_assertions::assert_matches;
6+
use rand::seq::IndexedRandom as _;
67
use spacetimedb::{
78
db::{
89
datastore::locking_tx_datastore::datastore::Locking,
@@ -63,9 +64,6 @@ async fn can_sync_a_snapshot() -> anyhow::Result<()> {
6364
let dst_snapshot_full = dst_repo.read_snapshot(src.offset, &pool)?;
6465
Locking::restore_from_snapshot(dst_snapshot_full, pool)?;
6566

66-
// Check that `verify_snapshot` agrees.
67-
verify_snapshot(blob_provider.clone(), dst_path.clone(), src_snapshot.clone()).await?;
68-
6967
// Let's also check that running `synchronize_snapshot` again does nothing.
7068
let stats = synchronize_snapshot(blob_provider.clone(), dst_path.clone(), src_snapshot.clone()).await?;
7169
assert_eq!(stats.objects_skipped, total_objects);
@@ -112,6 +110,70 @@ async fn rejects_overwrite() -> anyhow::Result<()> {
112110
Ok(())
113111
}
114112

113+
#[tokio::test]
114+
async fn verifies_objects() -> anyhow::Result<()> {
115+
enable_logging();
116+
let tmp = tempdir()?;
117+
let src = SourceSnapshot::get_or_create().await?;
118+
119+
let dst_path = SnapshotsPath::from_path_unchecked(tmp.path());
120+
dst_path.create()?;
121+
122+
let src_snapshot = src.meta.clone();
123+
124+
synchronize_snapshot(src.objects.clone(), dst_path.clone(), src_snapshot.clone()).await?;
125+
126+
// Read objects for verification from the destination repo.
127+
let blob_provider = spawn_blocking({
128+
let dst_path = dst_path.clone();
129+
let snapshot_offset = src_snapshot.tx_offset;
130+
move || {
131+
let repo = SnapshotRepository::open(dst_path, Identity::ZERO, 0)?;
132+
let objects = SnapshotRepository::object_repo(&repo.snapshot_dir_path(snapshot_offset))?;
133+
anyhow::Ok(Arc::new(objects))
134+
}
135+
})
136+
.await
137+
.unwrap()?;
138+
// Initially, all should be good.
139+
verify_snapshot(blob_provider.clone(), dst_path.clone(), src_snapshot.clone()).await?;
140+
141+
// Pick a random object to mess with.
142+
let random_object_path = {
143+
let all_objects = src_snapshot.objects().collect::<Box<[_]>>();
144+
let random_object = all_objects.choose(&mut rand::rng()).copied().unwrap();
145+
blob_provider.file_path(random_object.as_bytes())
146+
};
147+
148+
// Truncate the object file and assert that verification fails.
149+
tokio::fs::File::options()
150+
.write(true)
151+
.open(&random_object_path)
152+
.await?
153+
.set_len(1)
154+
.await?;
155+
info!("truncated object file {}", random_object_path.display());
156+
let err = verify_snapshot(blob_provider.clone(), dst_path.clone(), src_snapshot.clone())
157+
.await
158+
.unwrap_err();
159+
assert_matches!(
160+
err,
161+
// If the object is a page, we'll get `Deserialize`,
162+
// otherwise `HashMismatch`.
163+
SnapshotError::HashMismatch { .. } | SnapshotError::Deserialize { .. }
164+
);
165+
166+
// Delete the object file and assert that verification fails.
167+
tokio::fs::remove_file(&random_object_path).await?;
168+
info!("deleted object file {}", random_object_path.display());
169+
let err = verify_snapshot(blob_provider, dst_path, src_snapshot)
170+
.await
171+
.unwrap_err();
172+
assert_matches!(err, SnapshotError::ReadObject { cause, ..} if cause.kind() == io::ErrorKind::NotFound);
173+
174+
Ok(())
175+
}
176+
115177
/// Creating a snapshot takes a long time, because we need to commit
116178
/// `SNAPSHOT_FREQUENCY` transactions to trigger one.
117179
///

0 commit comments

Comments
 (0)