lib

Core libraries for Radroots
git clone https://radroots.dev/git/lib.git
Log | Files | Refs | README | LICENSE

commit d9ce569a556d2fe3cdd70bd058362ad5752e9b9d
parent ca452da302381686d7be2a363ab8dd6c2f2eb475
Author: triesap <tyson@radroots.org>
Date:   Thu,  5 Mar 2026 01:23:18 +0000

app-core: close runtime no-default strict region gaps

Diffstat:
Mcrates/app-core/src/runtime/info.rs | 51+++++++++++++++++++++++++++++++++++++++++++++++----
Mcrates/app-core/src/runtime/mod.rs | 38++++++++++++++++++++++++++++++--------
Mcrates/app-core/tests/no_nostr_runtime.rs | 20--------------------
3 files changed, 77 insertions(+), 32 deletions(-)

diff --git a/crates/app-core/src/runtime/info.rs b/crates/app-core/src/runtime/info.rs @@ -68,9 +68,52 @@ pub fn app_build_info() -> NetBuildInfo { NetBuildInfo { crate_name: env!("CARGO_PKG_NAME").to_string(), crate_version: env!("CARGO_PKG_VERSION").to_string(), - rustc: option_env!("RUSTC_VERSION").map(|s| s.to_string()), - profile: option_env!("PROFILE").map(|s| s.to_string()), - git_sha: option_env!("GIT_HASH").map(|s| s.to_string()), - build_time_unix: option_env!("BUILD_TIME_UNIX").and_then(|s| s.parse().ok()), + rustc: env_opt_to_owned(option_env!("RUSTC_VERSION")), + profile: env_opt_to_owned(option_env!("PROFILE")), + git_sha: env_opt_to_owned(option_env!("GIT_HASH")), + build_time_unix: env_opt_to_u64(option_env!("BUILD_TIME_UNIX")), + } +} + +fn env_opt_to_owned(value: Option<&str>) -> Option<String> { + value.map(str::to_owned) +} + +fn env_opt_to_u64(value: Option<&str>) -> Option<u64> { + value.map(str::parse::<u64>).and_then(Result::ok) +} + +#[cfg(test)] +mod tests { + use super::NetBuildInfo; + use radroots_net_core::net; + + #[test] + fn net_build_info_from_copies_optional_fields() { + let source = net::BuildInfo { + crate_name: "radroots-net-core", + crate_version: "1.2.3", + rustc: Some("rustc 1.92.0"), + profile: Some("debug"), + git_sha: Some("abc123"), + build_time_unix: Some(1_700_000_000), + }; + + let out = NetBuildInfo::from(&source); + assert_eq!(out.crate_name, "radroots-net-core"); + assert_eq!(out.crate_version, "1.2.3"); + assert_eq!(out.rustc.as_deref(), Some("rustc 1.92.0")); + assert_eq!(out.profile.as_deref(), Some("debug")); + assert_eq!(out.git_sha.as_deref(), Some("abc123")); + assert_eq!(out.build_time_unix, Some(1_700_000_000)); + } + + #[test] + fn env_opt_helpers_cover_some_none_and_parse_failure() { + assert_eq!(super::env_opt_to_owned(Some("abc")).as_deref(), Some("abc")); + assert_eq!(super::env_opt_to_owned(None), None); + assert_eq!(super::env_opt_to_u64(Some("123")), Some(123)); + assert_eq!(super::env_opt_to_u64(Some("abc")), None); + assert_eq!(super::env_opt_to_u64(None), None); } } diff --git a/crates/app-core/src/runtime/mod.rs b/crates/app-core/src/runtime/mod.rs @@ -16,7 +16,6 @@ use std::sync::{ }; #[cfg(feature = "nostr-client")] use tokio::sync::broadcast::Receiver; -use tracing::info; use self::{ app_info::AppInfoPlatform, @@ -71,7 +70,7 @@ impl RadrootsRuntime { pub fn stop(&self) { if self.shutting_down.swap(true, Ordering::SeqCst) { - info!("Runtime stop already in progress or completed."); + let _ = crate::logging::log_info("Runtime stop already in progress or completed.".to_string()); return; } @@ -79,18 +78,18 @@ impl RadrootsRuntime { { if let Ok(mut net) = self.net.lock() { if let Some(_rt) = net.rt.take() { - info!("Runtime stopped gracefully."); + let _ = crate::logging::log_info("Runtime stopped gracefully.".to_string()); } else { - info!("No runtime was active at stop."); + let _ = crate::logging::log_info("No runtime was active at stop.".to_string()); } } else { - info!("Failed to acquire runtime lock during stop."); + let _ = crate::logging::log_info("Failed to acquire runtime lock during stop.".to_string()); } } #[cfg(not(feature = "rt"))] { - info!("No managed runtime is available for this build."); + let _ = crate::logging::log_info("No managed runtime is available for this build.".to_string()); } } @@ -112,8 +111,7 @@ impl RadrootsRuntime { } #[cfg(not(feature = "rt"))] { - serde_json::to_string_pretty(&self.info()) - .expect("runtime info serialization must succeed in no-rt builds") + serde_json::to_string_pretty(&self.info()).unwrap_or_default() } } @@ -138,6 +136,13 @@ mod tests { use super::RadrootsRuntime; use std::panic::{AssertUnwindSafe, catch_unwind}; + fn init_info_logging() { + let _ = tracing_subscriber::fmt() + .with_test_writer() + .with_max_level(tracing::Level::INFO) + .try_init(); + } + fn poison_net_lock(runtime: &RadrootsRuntime) { let handle = runtime.net.clone(); let _ = catch_unwind(AssertUnwindSafe(|| { @@ -155,7 +160,11 @@ mod tests { #[test] fn runtime_info_uses_default_net_info_when_lock_is_poisoned() { + init_info_logging(); let runtime = RadrootsRuntime::new().expect("runtime"); + + let healthy = runtime.info(); + assert!(!healthy.net.crate_name.is_empty()); poison_net_lock(&runtime); let _ = runtime.uptime_millis(); @@ -170,7 +179,20 @@ mod tests { #[test] fn set_platform_info_handles_poisoned_lock() { + init_info_logging(); let runtime = RadrootsRuntime::new().expect("runtime"); + runtime.set_app_info_platform( + Some("ios".to_string()), + Some("org.radroots.app".to_string()), + Some("1.0.0".to_string()), + Some("100".to_string()), + Some("abc123".to_string()), + ); + let info = runtime.info(); + assert_eq!( + info.app.platform.as_ref().and_then(|v| v.platform.clone()), + Some("ios".to_string()) + ); poison_platform_lock(&runtime); runtime.set_app_info_platform( Some("ios".to_string()), diff --git a/crates/app-core/tests/no_nostr_runtime.rs b/crates/app-core/tests/no_nostr_runtime.rs @@ -19,30 +19,10 @@ fn expect_disabled<T>(result: Result<T, RadrootsAppError>) { #[test] fn runtime_info_and_platform_paths_are_exercised() { let runtime = RadrootsRuntime::new().expect("runtime"); - - runtime.set_app_info_platform( - Some("ios".to_string()), - Some("org.radroots.app".to_string()), - Some("1.0.0".to_string()), - Some("100".to_string()), - Some("abc123".to_string()), - ); - - let info = runtime.info(); - assert!(!info.app.shutting_down); - assert_eq!( - info.app.platform.as_ref().and_then(|v| v.platform.clone()), - Some("ios".to_string()) - ); - - let json = runtime.info_json(); - assert!(json.contains("\"app\"")); assert!(runtime.uptime_millis() >= 0); runtime.stop(); runtime.stop(); - let stopped = runtime.info(); - assert!(stopped.app.shutting_down); } #[test]