commit 0fe7930b924c4bea37dce2cfcbdc9f6bef29aa7e
parent d70851bdcb5dcde1d0f88eb775d077d15a48e09d
Author: triesap <triesap@radroots.dev>
Date: Mon, 19 Jan 2026 18:43:09 +0000
app: add keystore health check
- add keystore health check helper for nostr stores
- treat empty keystore results as ok status
- add keystore tests with async stub coverage
- export helper and add async-trait dev dependency
Diffstat:
4 files changed, 71 insertions(+), 0 deletions(-)
diff --git a/Cargo.toml b/Cargo.toml
@@ -23,6 +23,7 @@ wasm-bindgen = "=0.2.100"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
futures = "0.3"
+async-trait = "0.1.89"
getrandom = "0.2"
js-sys = "0.3.77"
gloo-timers = "0.3"
diff --git a/app/Cargo.toml b/app/Cargo.toml
@@ -17,3 +17,4 @@ serde.workspace = true
[dev-dependencies]
futures.workspace = true
+async-trait.workspace = true
diff --git a/app/src/health.rs b/app/src/health.rs
@@ -80,6 +80,7 @@ use crate::{
AppKeyMapConfig,
};
use radroots_app_core::datastore::RadrootsClientDatastore;
+use radroots_app_core::keystore::{RadrootsClientKeystoreError, RadrootsClientKeystoreNostr};
pub fn app_health_check_key_maps(key_maps: &AppKeyMapConfig) -> AppHealthCheckResult {
match app_key_maps_validate(key_maps) {
@@ -133,6 +134,16 @@ pub async fn app_health_check_datastore_roundtrip<T: RadrootsClientDatastore>(
AppHealthCheckResult::ok()
}
+pub async fn app_health_check_keystore_access<T: RadrootsClientKeystoreNostr>(
+ keystore: &T,
+) -> AppHealthCheckResult {
+ match keystore.keys().await {
+ Ok(_) => AppHealthCheckResult::ok(),
+ Err(RadrootsClientKeystoreError::NostrNoResults) => AppHealthCheckResult::ok(),
+ Err(err) => AppHealthCheckResult::error(err.to_string()),
+ }
+}
+
#[cfg(test)]
mod tests {
use super::{
@@ -140,12 +151,20 @@ mod tests {
app_health_check_bootstrap_app_data,
app_health_check_bootstrap_config,
app_health_check_datastore_roundtrip,
+ app_health_check_keystore_access,
AppHealthCheckResult,
AppHealthCheckStatus,
AppHealthReport,
};
use crate::AppKeyMapConfig;
+ use async_trait::async_trait;
use radroots_app_core::datastore::RadrootsClientWebDatastore;
+ use radroots_app_core::keystore::{
+ RadrootsClientKeystoreError,
+ RadrootsClientKeystoreNostr,
+ RadrootsClientKeystoreResult,
+ RadrootsClientWebKeystoreNostr,
+ };
#[test]
fn health_status_as_str() {
@@ -209,4 +228,53 @@ mod tests {
futures::executor::block_on(app_health_check_datastore_roundtrip(&datastore));
assert_eq!(result.status, AppHealthCheckStatus::Error);
}
+
+ struct TestKeystore {
+ result: RadrootsClientKeystoreResult<Vec<String>>,
+ }
+
+ #[async_trait(?Send)]
+ impl RadrootsClientKeystoreNostr for TestKeystore {
+ async fn generate(&self) -> RadrootsClientKeystoreResult<String> {
+ Err(RadrootsClientKeystoreError::IdbUndefined)
+ }
+
+ async fn add(&self, _secret_key: &str) -> RadrootsClientKeystoreResult<String> {
+ Err(RadrootsClientKeystoreError::IdbUndefined)
+ }
+
+ async fn read(&self, _public_key: &str) -> RadrootsClientKeystoreResult<String> {
+ Err(RadrootsClientKeystoreError::IdbUndefined)
+ }
+
+ async fn keys(&self) -> RadrootsClientKeystoreResult<Vec<String>> {
+ self.result.clone()
+ }
+
+ async fn remove(&self, _public_key: &str) -> RadrootsClientKeystoreResult<String> {
+ Err(RadrootsClientKeystoreError::IdbUndefined)
+ }
+
+ async fn reset(&self) -> RadrootsClientKeystoreResult<()> {
+ Err(RadrootsClientKeystoreError::IdbUndefined)
+ }
+ }
+
+ #[test]
+ fn health_check_keystore_maps_empty_ok() {
+ let keystore = TestKeystore {
+ result: Err(RadrootsClientKeystoreError::NostrNoResults),
+ };
+ let result =
+ futures::executor::block_on(app_health_check_keystore_access(&keystore));
+ assert_eq!(result.status, AppHealthCheckStatus::Ok);
+ }
+
+ #[test]
+ fn health_check_keystore_maps_idb_errors() {
+ let keystore = RadrootsClientWebKeystoreNostr::new(None);
+ let result =
+ futures::executor::block_on(app_health_check_keystore_access(&keystore));
+ assert_eq!(result.status, AppHealthCheckStatus::Error);
+ }
}
diff --git a/app/src/lib.rs b/app/src/lib.rs
@@ -23,6 +23,7 @@ pub use health::{
app_health_check_bootstrap_app_data,
app_health_check_bootstrap_config,
app_health_check_datastore_roundtrip,
+ app_health_check_keystore_access,
app_health_check_key_maps,
AppHealthCheckResult,
AppHealthCheckStatus,