You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
synctv/synctv-core/tests/settings_repository_tests.rs

222 lines
6.2 KiB
Rust

use synctv_core::repository::SettingsRepository;
use synctv_core_testing::create_test_pool;
fn ok<T, E: std::fmt::Debug>(result: Result<T, E>, context: &str) -> T {
match result {
Ok(value) => value,
Err(error) => std::panic::panic_any(format!("{context}: {error:?}")),
}
}
fn err<T: std::fmt::Debug, E>(result: Result<T, E>, context: &str) -> E {
match result {
Ok(value) => std::panic::panic_any(format!("{context}: {value:?}")),
Err(error) => error,
}
}
#[tokio::test]
#[ignore = "Requires Docker"]
async fn test_get_nonexistent_key_returns_error() {
let (_container, pool) = create_test_pool().await;
let repo = SettingsRepository::new(pool.clone());
let result = repo.get("this_key_does_not_exist_at_all").await;
assert!(
result.is_err(),
"Getting a non-existent key should return an error"
);
}
#[tokio::test]
#[ignore = "Requires Docker"]
async fn test_get_all_ordering_by_group_name() {
let (_container, pool) = create_test_pool().await;
let repo = SettingsRepository::new(pool.clone());
ok(
sqlx::query!(
"INSERT INTO settings (key, group_name, value) VALUES ($1, $2, $3) ON CONFLICT (key) DO NOTHING",
"z_test.key1",
"z_group",
"value1"
)
.execute(&pool)
.await,
"insert key1",
);
ok(
sqlx::query!(
"INSERT INTO settings (key, group_name, value) VALUES ($1, $2, $3) ON CONFLICT (key) DO NOTHING",
"a_test.key2",
"a_group",
"value2"
)
.execute(&pool)
.await,
"insert key2",
);
ok(
sqlx::query!(
"INSERT INTO settings (key, group_name, value) VALUES ($1, $2, $3) ON CONFLICT (key) DO NOTHING",
"m_test.key3",
"m_group",
"value3"
)
.execute(&pool)
.await,
"insert key3",
);
let all = ok(repo.get_all().await, "settings should load");
assert!(all.len() >= 3, "Should have at least 3 settings");
let our_groups: Vec<String> = all
.iter()
.filter(|s| {
s.group_name == "a_group" || s.group_name == "m_group" || s.group_name == "z_group"
})
.map(|s| s.group_name.clone())
.collect();
assert_eq!(our_groups, vec!["a_group", "m_group", "z_group"]);
}
#[tokio::test]
#[ignore = "Requires Docker"]
async fn test_get_all_returns_empty_when_no_settings() {
let (_container, pool) = create_test_pool().await;
let repo = SettingsRepository::new(pool.clone());
ok(
sqlx::query!("DELETE FROM settings").execute(&pool).await,
"settings should delete",
);
let all = ok(repo.get_all().await, "settings should load");
assert!(all.is_empty());
}
#[tokio::test]
#[ignore = "Requires Docker"]
async fn test_get_and_update_round_trip() {
let (_container, pool) = create_test_pool().await;
let repo = SettingsRepository::new(pool.clone());
ok(
sqlx::query!(
"INSERT INTO settings (key, group_name, value) VALUES ($1, $2, $3) ON CONFLICT (key) DO NOTHING",
"roundtrip_key",
"test_group",
"original_value"
)
.execute(&pool)
.await,
"roundtrip setting insert",
);
let setting = ok(
repo.get("roundtrip_key").await,
"roundtrip setting should load",
);
assert_eq!(setting.value, "original_value");
assert_eq!(setting.group_name, "test_group");
let updated = ok(
repo.update("roundtrip_key", "new_value").await,
"roundtrip setting should update",
);
assert_eq!(updated.value, "new_value");
assert!(updated.updated_at >= setting.updated_at);
let re_read = ok(
repo.get("roundtrip_key").await,
"roundtrip setting should reload",
);
assert_eq!(re_read.value, "new_value");
}
#[tokio::test]
#[ignore = "Requires Docker"]
async fn test_update_with_version_increments_version() {
let (_container, pool) = create_test_pool().await;
let repo = SettingsRepository::new(pool.clone());
ok(
sqlx::query!(
"INSERT INTO settings (key, group_name, value) VALUES ($1, $2, $3) ON CONFLICT (key) DO NOTHING",
"version_test_key",
"test_group",
"value_v0"
)
.execute(&pool)
.await,
"version setting insert",
);
let v0 = ok(
repo.get("version_test_key").await,
"version setting should load",
);
assert_eq!(v0.version, 0, "Initial version should be 0");
let v1 = ok(
repo.update_with_version("version_test_key", "value_v1", 0)
.await,
"version update v1",
);
assert_eq!(v1.version, 1, "Version should increment to 1");
let v2 = ok(
repo.update_with_version("version_test_key", "value_v2", 1)
.await,
"version update v2",
);
assert_eq!(v2.version, 2, "Version should increment to 2");
let result = repo
.update_with_version("version_test_key", "value_stale", 0)
.await;
assert!(result.is_err(), "Update with stale version should fail");
assert!(
matches!(
err(result, "stale version update should fail"),
synctv_core::Error::OptimisticLockConflict
),
"Error should be OptimisticLockConflict"
);
}
#[tokio::test]
#[ignore = "Requires Docker"]
async fn test_update_with_wrong_version_fails() {
let (_container, pool) = create_test_pool().await;
let repo = SettingsRepository::new(pool.clone());
ok(
sqlx::query!(
"INSERT INTO settings (key, group_name, value) VALUES ($1, $2, $3) ON CONFLICT (key) DO NOTHING",
"wrong_version_key",
"test_group",
"original"
)
.execute(&pool)
.await,
"wrong version setting insert",
);
let result = repo
.update_with_version("wrong_version_key", "new_value", 999)
.await;
assert!(result.is_err(), "Update with wrong version should fail");
assert!(
matches!(
err(result, "wrong version update should fail"),
synctv_core::Error::OptimisticLockConflict
),
"Error should be OptimisticLockConflict"
);
}