//! This contains test scenarios that a given [PathInfoService] needs to pass.
//! We use [rstest] and [rstest_reuse] to provide all services we want to test
//! against, and then apply this template to all test functions.
use futures::TryStreamExt;
use rstest::*;
use rstest_reuse::{self, *};
use super::PathInfoService;
use crate::pathinfoservice::MemoryPathInfoService;
use crate::pathinfoservice::SledPathInfoService;
use crate::proto::PathInfo;
use crate::tests::fixtures::DUMMY_PATH_DIGEST;
use tvix_castore::proto as castorepb;
mod utils;
pub use self::utils::make_grpc_path_info_service_client;
#[cfg(all(feature = "cloud", feature = "integration"))]
use self::utils::make_bigtable_path_info_service;
#[template]
#[rstest]
#[case::memory(MemoryPathInfoService::default())]
#[case::grpc({
let (_, _, svc) = make_grpc_path_info_service_client().await;
svc
})]
#[case::sled(SledPathInfoService::new_temporary().unwrap())]
#[cfg_attr(all(feature = "cloud",feature="integration"), case::bigtable(make_bigtable_path_info_service().await))]
pub fn path_info_services(#[case] svc: impl PathInfoService) {}
// FUTUREWORK: add more tests rejecting invalid PathInfo messages.
// A subset of them should also ensure references to other PathInfos, or
// elements in {Blob,Directory}Service do exist.
/// Trying to get a non-existent PathInfo should return Ok(None).
#[apply(path_info_services)]
#[tokio::test]
async fn not_found(svc: impl PathInfoService) {
assert!(svc
.get(DUMMY_PATH_DIGEST)
.await
.expect("must succeed")
.is_none());
}
/// Put a PathInfo into the store, get it back.
#[apply(path_info_services)]
#[tokio::test]
async fn put_get(svc: impl PathInfoService) {
let path_info = PathInfo {
node: Some(castorepb::Node {
node: Some(castorepb::node::Node::Symlink(castorepb::SymlinkNode {
name: "00000000000000000000000000000000-foo".into(),
target: "doesntmatter".into(),
})),
}),
..Default::default()
};
// insert
let resp = svc.put(path_info.clone()).await.expect("must succeed");
// expect the returned PathInfo to be equal (for now)
// in the future, some stores might add additional fields/signatures.
assert_eq!(path_info, resp);
// get it back
let resp = svc.get(DUMMY_PATH_DIGEST).await.expect("must succeed");
assert_eq!(Some(path_info.clone()), resp);
// Ensure the listing endpoint works, and returns the same path_info.
// FUTUREWORK: split this, some impls might (rightfully) not support listing
let pathinfos: Vec<PathInfo> = svc.list().try_collect().await.expect("must succeed");
// We should get a single pathinfo back, the one we inserted.
assert_eq!(vec![path_info], pathinfos);
}