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