use crate::errors::Result;
use crate::server::cloud::service::Service;
use pretty_assertions::assert_eq;
macro_rules! service_tests {
($service:expr) => {
fn make_pfx() -> impl Fn(&str) -> String {
let prefix = uuid::Uuid::new_v4();
move |n: &_| format!("{}-{}", prefix.as_simple(), n)
}
#[tokio::test]
async fn put_and_get() -> $crate::errors::Result<()> {
let Some(service) = $service else {
return Ok(());
};
$crate::server::cloud::test::put_and_get(service, make_pfx()).await
}
#[tokio::test]
async fn get_missing() -> $crate::errors::Result<()> {
let Some(service) = $service else {
return Ok(());
};
$crate::server::cloud::test::get_missing(service, make_pfx()).await
}
#[tokio::test]
async fn del() -> $crate::errors::Result<()> {
let Some(service) = $service else {
return Ok(());
};
$crate::server::cloud::test::del(service, make_pfx()).await
}
#[tokio::test]
async fn del_missing() -> $crate::errors::Result<()> {
let Some(service) = $service else {
return Ok(());
};
$crate::server::cloud::test::del_missing(service, make_pfx()).await
}
#[tokio::test]
async fn list() -> $crate::errors::Result<()> {
let Some(service) = $service else {
return Ok(());
};
$crate::server::cloud::test::list(service, make_pfx()).await
}
#[tokio::test]
async fn compare_and_swap_create() -> $crate::errors::Result<()> {
let Some(service) = $service else {
return Ok(());
};
$crate::server::cloud::test::compare_and_swap_create(service, make_pfx()).await
}
#[tokio::test]
async fn compare_and_swap_matches() -> $crate::errors::Result<()> {
let Some(service) = $service else {
return Ok(());
};
$crate::server::cloud::test::compare_and_swap_matches(service, make_pfx()).await
}
#[tokio::test]
async fn compare_and_swap_expected_no_file() -> $crate::errors::Result<()> {
let Some(service) = $service else {
return Ok(());
};
$crate::server::cloud::test::compare_and_swap_expected_no_file(service, make_pfx())
.await
}
#[tokio::test]
async fn compare_and_swap_old_value() -> $crate::errors::Result<()> {
let Some(service) = $service else {
return Ok(());
};
$crate::server::cloud::test::compare_and_swap_old_value(service, make_pfx()).await
}
#[tokio::test]
async fn compare_and_swap_changes() -> $crate::errors::Result<()> {
let Some(service) = $service else {
return Ok(());
};
$crate::server::cloud::test::compare_and_swap_changes(service, make_pfx()).await
}
#[tokio::test]
async fn compare_and_swap_disappears() -> $crate::errors::Result<()> {
let Some(service) = $service else {
return Ok(());
};
$crate::server::cloud::test::compare_and_swap_disappears(service, make_pfx()).await
}
#[tokio::test]
async fn compare_and_swap_appears() -> $crate::errors::Result<()> {
let Some(service) = $service else {
return Ok(());
};
$crate::server::cloud::test::compare_and_swap_appears(service, make_pfx()).await
}
};
}
pub(crate) use service_tests;
pub(super) async fn put_and_get(mut svc: impl Service, pfx: impl Fn(&str) -> String) -> Result<()> {
svc.put(&pfx("testy"), b"foo").await?;
let got = svc.get(&pfx("testy")).await?;
assert_eq!(got, Some(b"foo".to_vec()));
svc.del(&pfx("testy")).await?;
Ok(())
}
pub(super) async fn get_missing(mut svc: impl Service, pfx: impl Fn(&str) -> String) -> Result<()> {
let got = svc.get(&pfx("testy")).await?;
assert_eq!(got, None);
Ok(())
}
pub(super) async fn del(mut svc: impl Service, pfx: impl Fn(&str) -> String) -> Result<()> {
svc.put(&pfx("testy"), b"data").await?;
svc.del(&pfx("testy")).await?;
let got = svc.get(&pfx("testy")).await?;
assert_eq!(got, None);
Ok(())
}
pub(super) async fn del_missing(mut svc: impl Service, pfx: impl Fn(&str) -> String) -> Result<()> {
assert!(svc.del(&pfx("testy")).await.is_ok());
Ok(())
}
pub(super) async fn list(mut svc: impl Service, pfx: impl Fn(&str) -> String) -> Result<()> {
let mut names: Vec<_> = (0..20).map(|i| pfx(&format!("pp-{i:02}"))).collect();
names.sort();
for n in &names {
svc.put(n, b"data").await?;
}
svc.put(&pfx("xxx"), b"data").await?;
let mut got_names: Vec<_> = {
let mut got_names = Vec::new();
let prefix = &pfx("pp-");
let mut iterator = svc.list(prefix).await;
while let Some(res) = iterator.next().await {
match res {
Ok(o) => got_names.push(o.name),
Err(e) => return Err(e),
}
}
got_names
};
got_names.sort();
assert_eq!(got_names, names);
for n in got_names {
svc.del(&n).await?;
}
svc.del(&pfx("xxx")).await?;
Ok(())
}
pub(super) async fn compare_and_swap_create(
mut svc: impl Service,
pfx: impl Fn(&str) -> String,
) -> Result<()> {
assert!(
svc.compare_and_swap(&pfx("testy"), None, b"bar".to_vec())
.await?
);
let got = svc.get(&pfx("testy")).await?;
assert_eq!(got, Some(b"bar".to_vec()));
svc.del(&pfx("testy")).await?;
Ok(())
}
pub(super) async fn compare_and_swap_matches(
mut svc: impl Service,
pfx: impl Fn(&str) -> String,
) -> Result<()> {
svc.put(&pfx("testy"), b"foo1").await?;
svc.put(&pfx("testy"), b"foo2").await?;
assert!(
svc.compare_and_swap(&pfx("testy"), Some(b"foo2".to_vec()), b"bar".to_vec())
.await?
);
let got = svc.get(&pfx("testy")).await?;
assert_eq!(got, Some(b"bar".to_vec()));
svc.del(&pfx("testy")).await?;
Ok(())
}
pub(super) async fn compare_and_swap_expected_no_file(
mut svc: impl Service,
pfx: impl Fn(&str) -> String,
) -> Result<()> {
svc.put(&pfx("testy"), b"foo1").await?;
assert!(
!svc.compare_and_swap(&pfx("testy"), None, b"bar".to_vec())
.await?
);
let got = svc.get(&pfx("testy")).await?;
assert_eq!(got, Some(b"foo1".to_vec()));
svc.del(&pfx("testy")).await?;
Ok(())
}
pub(super) async fn compare_and_swap_old_value(
mut svc: impl Service,
pfx: impl Fn(&str) -> String,
) -> Result<()> {
svc.put(&pfx("testy"), b"foo1").await?;
svc.put(&pfx("testy"), b"foo2").await?;
assert!(
!svc.compare_and_swap(&pfx("testy"), Some(b"foo1".to_vec()), b"bar".to_vec())
.await?
);
let got = svc.get(&pfx("testy")).await?;
assert_eq!(got, Some(b"foo2".to_vec()));
svc.del(&pfx("testy")).await?;
Ok(())
}
pub(super) async fn compare_and_swap_changes(
mut svc: impl Service,
pfx: impl Fn(&str) -> String,
) -> Result<()> {
svc.put(&pfx("racing-put"), b"foo1").await?;
assert!(
!svc.compare_and_swap(&pfx("racing-put"), Some(b"foo1".to_vec()), b"bar".to_vec())
.await?
);
let got = svc.get(&pfx("racing-put")).await?;
assert_eq!(got, Some(b"CHANGED".to_vec()));
Ok(())
}
pub(super) async fn compare_and_swap_disappears(
mut svc: impl Service,
pfx: impl Fn(&str) -> String,
) -> Result<()> {
svc.put(&pfx("racing-delete"), b"foo1").await?;
assert!(
!svc.compare_and_swap(
&pfx("racing-delete"),
Some(b"foo1".to_vec()),
b"bar".to_vec()
)
.await?
);
let got = svc.get(&pfx("racing-delete")).await?;
assert_eq!(got, None);
Ok(())
}
pub(super) async fn compare_and_swap_appears(
mut svc: impl Service,
pfx: impl Fn(&str) -> String,
) -> Result<()> {
assert!(
!svc.compare_and_swap(&pfx("racing-put"), None, b"bar".to_vec())
.await?
);
let got = svc.get(&pfx("racing-put")).await?;
assert_eq!(got, Some(b"CHANGED".to_vec()));
Ok(())
}