From d6cc851ee6bb846cf1739769b406996b264632b2 Mon Sep 17 00:00:00 2001 From: Al Liu Date: Sat, 10 Dec 2022 16:01:16 +0800 Subject: [PATCH] Error handle and consume self in connect function (#11) * use &self for connect function * more &mut self to &self * error handle * add DynError * remove except, return error * add error handle for ServiceState trait --- Cargo.lock | 120 ++++++++++++++++++++++++++ examples/waku-chat/src/chat.rs | 7 +- examples/waku-chat/src/main.rs | 3 +- examples/waku-chat/src/network/mod.rs | 9 +- overwatch-derive/src/lib.rs | 27 +++--- overwatch-rs/Cargo.toml | 1 + overwatch-rs/src/lib.rs | 2 + overwatch-rs/src/overwatch/mod.rs | 44 +++++++--- overwatch-rs/src/services/handle.rs | 26 +++--- overwatch-rs/src/services/mod.rs | 4 +- overwatch-rs/src/services/relay.rs | 2 +- overwatch-rs/src/services/state.rs | 20 +++-- overwatch-rs/tests/print_service.rs | 9 +- overwatch-rs/tests/settings_update.rs | 9 +- overwatch-rs/tests/state_handling.rs | 25 ++++-- 15 files changed, 238 insertions(+), 70 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e6d1d43..12c6fc2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,21 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "aead" version = "0.5.1" @@ -80,6 +95,21 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "backtrace" +version = "0.3.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab84319d616cfb654d03394f38ab7e6f0919e181b1b57e1fd15e7fb4077d9a7" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + [[package]] name = "base64" version = "0.13.1" @@ -245,6 +275,33 @@ dependencies = [ "os_str_bytes", ] +[[package]] +name = "color-eyre" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a667583cca8c4f8436db8de46ea8233c42a7d9ae424a82d338f2e4675229204" +dependencies = [ + "backtrace", + "color-spantrace", + "eyre", + "indenter", + "once_cell", + "owo-colors", + "tracing-error", +] + +[[package]] +name = "color-spantrace" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ba75b3d9449ecdccb27ecbc479fdc0b87fa2dd43d2f8298f9bf0e59aacc8dce" +dependencies = [ + "once_cell", + "owo-colors", + "tracing-core", + "tracing-error", +] + [[package]] name = "const-str" version = "0.3.2" @@ -348,6 +405,16 @@ dependencies = [ "termcolor", ] +[[package]] +name = "eyre" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c2b6b5a29c02cdc822728b7d7b8ae1bab3e3b05d44522770ddd49722eeac7eb" +dependencies = [ + "indenter", + "once_cell", +] + [[package]] name = "form_urlencoded" version = "1.1.0" @@ -477,6 +544,12 @@ dependencies = [ "polyval", ] +[[package]] +name = "gimli" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d" + [[package]] name = "glob" version = "0.3.0" @@ -526,6 +599,12 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "indenter" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" + [[package]] name = "indexmap" version = "1.9.1" @@ -600,6 +679,15 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" +[[package]] +name = "miniz_oxide" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96590ba8f175222643a85693f33d26e9c8a015f599c216509b1a6894af675d34" +dependencies = [ + "adler", +] + [[package]] name = "multiaddr" version = "0.14.0" @@ -673,6 +761,15 @@ dependencies = [ "libc", ] +[[package]] +name = "object" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" version = "1.15.0" @@ -714,6 +811,7 @@ name = "overwatch-rs" version = "0.1.0" dependencies = [ "async-trait", + "color-eyre", "const-str", "futures", "overwatch-derive", @@ -723,6 +821,12 @@ dependencies = [ "tracing", ] +[[package]] +name = "owo-colors" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" + [[package]] name = "peeking_take_while" version = "0.1.2" @@ -865,6 +969,12 @@ version = "0.6.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" +[[package]] +name = "rustc-demangle" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" + [[package]] name = "rustc-hash" version = "1.1.0" @@ -1174,6 +1284,16 @@ dependencies = [ "valuable", ] +[[package]] +name = "tracing-error" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e" +dependencies = [ + "tracing", + "tracing-subscriber", +] + [[package]] name = "tracing-log" version = "0.1.3" diff --git a/examples/waku-chat/src/chat.rs b/examples/waku-chat/src/chat.rs index 44871bb..05e3571 100644 --- a/examples/waku-chat/src/chat.rs +++ b/examples/waku-chat/src/chat.rs @@ -29,11 +29,11 @@ impl ServiceData for ChatService { #[async_trait] impl ServiceCore for ChatService { - fn init(service_state: ServiceStateHandle) -> Self { - Self { service_state } + fn init(service_state: ServiceStateHandle) -> Result { + Ok(Self { service_state }) } - async fn run(self) { + async fn run(self) -> Result<(), overwatch_rs::DynError> { let Self { mut service_state, .. } = self; @@ -89,5 +89,6 @@ impl ServiceCore for ChatService { } } } + Ok(()) } } diff --git a/examples/waku-chat/src/main.rs b/examples/waku-chat/src/main.rs index 7d85e17..0888767 100644 --- a/examples/waku-chat/src/main.rs +++ b/examples/waku-chat/src/main.rs @@ -41,7 +41,8 @@ fn main() { network: NetworkConfig { peers, port }, }, None, - ); + ) + .unwrap(); app.wait_finished(); } diff --git a/examples/waku-chat/src/network/mod.rs b/examples/waku-chat/src/network/mod.rs index 54f9e60..d1fd765 100644 --- a/examples/waku-chat/src/network/mod.rs +++ b/examples/waku-chat/src/network/mod.rs @@ -49,16 +49,16 @@ impl ServiceData for NetworkService { #[async_trait] impl ServiceCore for NetworkService { - fn init(mut service_state: ServiceStateHandle) -> Self { - Self { + fn init(mut service_state: ServiceStateHandle) -> Result { + Ok(Self { implem: ::new( service_state.settings_reader.get_updated_settings(), ), service_state, - } + }) } - async fn run(mut self) { + async fn run(mut self) -> Result<(), overwatch_rs::DynError> { let Self { service_state, mut implem, @@ -71,6 +71,7 @@ impl ServiceCore for NetworkService { NetworkMsg::Subscribe { kind: _, sender } => implem.subscribe(sender), } } + Ok(()) } } diff --git a/overwatch-derive/src/lib.rs b/overwatch-derive/src/lib.rs index a5c19f4..5b6ccc2 100644 --- a/overwatch-derive/src/lib.rs +++ b/overwatch-derive/src/lib.rs @@ -145,14 +145,14 @@ fn generate_new_impl(fields: &Punctuated) -> proc_macro2::TokenStr let manager = ::overwatch_rs::services::handle::ServiceHandle::<#service_type>::new( #settings_field_identifier, overwatch_handle.clone(), - ); + )?; manager } } }); quote! { - fn new(settings: Self::Settings, overwatch_handle: ::overwatch_rs::overwatch::handle::OverwatchHandle) -> Self { + fn new(settings: Self::Settings, overwatch_handle: ::overwatch_rs::overwatch::handle::OverwatchHandle) -> ::std::result::Result { let Self::Settings { #( #fields_settings ),* } = settings; @@ -161,7 +161,7 @@ fn generate_new_impl(fields: &Punctuated) -> proc_macro2::TokenStr #( #managers ),* }; - app + ::std::result::Result::Ok(app) } } } @@ -170,7 +170,7 @@ fn generate_start_all_impl(fields: &Punctuated) -> proc_macro2::To let call_start = fields.iter().map(|field| { let field_identifier = field.ident.as_ref().expect("A struct attribute identifier"); quote! { - self.#field_identifier.service_runner().run(); + self.#field_identifier.service_runner().run()?; } }); @@ -178,7 +178,8 @@ fn generate_start_all_impl(fields: &Punctuated) -> proc_macro2::To #[::tracing::instrument(skip(self), err)] fn start_all(&mut self) -> Result<(), ::overwatch_rs::overwatch::Error> { #( #call_start )* - Ok(()) + + ::std::result::Result::Ok(()) } } } @@ -189,8 +190,8 @@ fn generate_start_impl(fields: &Punctuated) -> proc_macro2::TokenS let type_id = utils::extract_type_from(&field.ty); quote! { <#type_id as ::overwatch_rs::services::ServiceData>::SERVICE_ID => { - self.#field_identifier.service_runner().run(); - Ok(()) + self.#field_identifier.service_runner().run()?; + ::std::result::Result::Ok(()) } } }); @@ -200,7 +201,7 @@ fn generate_start_impl(fields: &Punctuated) -> proc_macro2::TokenS fn start(&mut self, service_id: ::overwatch_rs::services::ServiceId) -> Result<(), ::overwatch_rs::overwatch::Error> { match service_id { #( #cases ),* - service_id => Err(::overwatch_rs::overwatch::Error::Unavailable { service_id }) + service_id => ::std::result::Result::Err(::overwatch_rs::overwatch::Error::Unavailable { service_id }) } } } @@ -221,7 +222,7 @@ fn generate_stop_impl(fields: &Punctuated) -> proc_macro2::TokenSt fn stop(&mut self, service_id: ::overwatch_rs::services::ServiceId) -> Result<(), ::overwatch_rs::overwatch::Error> { match service_id { #( #cases ),* - service_id => Err(::overwatch_rs::overwatch::Error::Unavailable { service_id }) + service_id => ::std::result::Result::Err(::overwatch_rs::overwatch::Error::Unavailable { service_id }) } } } @@ -233,10 +234,10 @@ fn generate_request_relay_impl(fields: &Punctuated) -> proc_macro2 let type_id = utils::extract_type_from(&field.ty); quote! { <#type_id as ::overwatch_rs::services::ServiceData>::SERVICE_ID => { - Ok(::std::boxed::Box::new( + ::std::result::Result::Ok(::std::boxed::Box::new( self.#field_identifier .relay_with() - .expect("An open relay to service is established") + .ok_or(::overwatch_rs::services::relay::RelayError::AlreadyConnected)? ) as ::overwatch_rs::services::relay::AnyMessage) } } @@ -248,7 +249,7 @@ fn generate_request_relay_impl(fields: &Punctuated) -> proc_macro2 { match service_id { #( #cases )* - service_id => Err(::overwatch_rs::services::relay::RelayError::Unavailable { service_id }) + service_id => ::std::result::Result::Err(::overwatch_rs::services::relay::RelayError::Unavailable { service_id }) } } } @@ -281,7 +282,7 @@ fn generate_update_settings_impl(fields: &Punctuated) -> proc_macr #( #update_settings_call )* - Ok(()) + ::std::result::Result::Ok(()) } } } diff --git a/overwatch-rs/Cargo.toml b/overwatch-rs/Cargo.toml index 393d830..a0b5257 100644 --- a/overwatch-rs/Cargo.toml +++ b/overwatch-rs/Cargo.toml @@ -22,6 +22,7 @@ exclude = [ [dependencies] overwatch-derive = { path = "../overwatch-derive" } const-str = "0.3" +color-eyre = "0.6" async-trait = "0.1" futures = "0.3" thiserror = "1.0" diff --git a/overwatch-rs/src/lib.rs b/overwatch-rs/src/lib.rs index 713f3b6..c19ceaf 100644 --- a/overwatch-rs/src/lib.rs +++ b/overwatch-rs/src/lib.rs @@ -27,3 +27,5 @@ pub mod overwatch; pub mod services; pub mod utils; + +pub type DynError = Box; diff --git a/overwatch-rs/src/overwatch/mod.rs b/overwatch-rs/src/overwatch/mod.rs index 492a3ae..54a2b24 100644 --- a/overwatch-rs/src/overwatch/mod.rs +++ b/overwatch-rs/src/overwatch/mod.rs @@ -34,6 +34,21 @@ pub enum Error { #[error("Service {service_id} is unavailable")] Unavailable { service_id: ServiceId }, + + #[error(transparent)] + Any(super::DynError), +} + +impl Error { + pub fn any(err: T) -> Self { + Self::Any(Box::new(err)) + } +} + +impl From for Error { + fn from(err: super::DynError) -> Self { + Self::Any(err) + } } /// Signal sent so overwatch finish execution @@ -45,7 +60,7 @@ pub type AnySettings = Box; /// An overwatch run anything that implements this trait /// An implementor of this trait would have to handle the inner [`ServiceCore`](crate::services::ServiceCore) #[async_trait] -pub trait Services: Send + Sync { +pub trait Services: Sized + Send + Sync { /// Inner [`ServiceCore::Settings`](crate::services::ServiceCore) grouping type. /// Normally this will be a settings object that group all the inner services settings. type Settings: Debug + Send + 'static; @@ -54,7 +69,10 @@ pub trait Services: Send + Sync { /// It returns a `(ServiceId, Runtime)` where Runtime is the `tokio::runtime::Runtime` attached for each /// service. /// It also returns an instance of the implementing type. - fn new(settings: Self::Settings, overwatch_handle: OverwatchHandle) -> Self; + fn new( + settings: Self::Settings, + overwatch_handle: OverwatchHandle, + ) -> std::result::Result; /// Start a services attached to the trait implementer fn start(&mut self, service_id: ServiceId) -> Result<(), Error>; @@ -96,24 +114,27 @@ where /// It creates the `tokio::runtime::Runtime`, initialize the [`Services`] and start listening for /// Overwatch related tasks. /// Returns the [`Overwatch`] instance that handles this runner. - pub fn run(settings: S::Settings, runtime: Option) -> Overwatch { + pub fn run( + settings: S::Settings, + runtime: Option, + ) -> std::result::Result { let runtime = runtime.unwrap_or_else(default_multithread_runtime); let (finish_signal_sender, finish_runner_signal) = tokio::sync::oneshot::channel(); let (commands_sender, commands_receiver) = tokio::sync::mpsc::channel(16); let handle = OverwatchHandle::new(runtime.handle().clone(), commands_sender); - let services = S::new(settings, handle.clone()); + let services = S::new(settings, handle.clone())?; let runner = OverwatchRunner { services, handle: handle.clone(), finish_signal_sender, }; runtime.spawn(async move { runner.run_(commands_receiver).await }); - Overwatch { + Ok(Overwatch { runtime, handle, finish_runner_signal, - } + }) } #[instrument(name = "overwatch-run", skip_all)] @@ -237,8 +258,11 @@ mod test { impl Services for EmptyServices { type Settings = (); - fn new(_settings: Self::Settings, _overwatch_handle: OverwatchHandle) -> Self { - EmptyServices + fn new( + _settings: Self::Settings, + _overwatch_handle: OverwatchHandle, + ) -> Result> { + Ok(EmptyServices) } fn start(&mut self, service_id: ServiceId) -> Result<(), Error> { @@ -264,7 +288,7 @@ mod test { #[test] fn run_overwatch_then_stop() { - let overwatch = OverwatchRunner::::run((), None); + let overwatch = OverwatchRunner::::run((), None).unwrap(); let handle = overwatch.handle().clone(); overwatch.spawn(async move { @@ -277,7 +301,7 @@ mod test { #[test] fn run_overwatch_then_kill() { - let overwatch = OverwatchRunner::::run((), None); + let overwatch = OverwatchRunner::::run((), None).unwrap(); let handle = overwatch.handle().clone(); overwatch.spawn(async move { diff --git a/overwatch-rs/src/services/handle.rs b/overwatch-rs/src/services/handle.rs index e490a30..fb3573a 100644 --- a/overwatch-rs/src/services/handle.rs +++ b/overwatch-rs/src/services/handle.rs @@ -1,7 +1,6 @@ // crates use futures::future::{abortable, AbortHandle}; use tokio::runtime::Handle; -use tracing::instrument; // internal use crate::overwatch::handle::OverwatchHandle; use crate::services::relay::{relay, InboundRelay, OutboundRelay}; @@ -45,17 +44,16 @@ pub struct ServiceRunner { } impl ServiceHandle { - pub fn new(settings: S::Settings, overwatch_handle: OverwatchHandle) -> Self { - let initial_state: S::State = S::State::from_settings(&settings); - - let settings = SettingsUpdater::new(settings); - - Self { + pub fn new( + settings: S::Settings, + overwatch_handle: OverwatchHandle, + ) -> Result::Error> { + S::State::from_settings(&settings).map(|initial_state| Self { outbound_relay: None, - settings, - initial_state, overwatch_handle, - } + settings: SettingsUpdater::new(settings), + initial_state, + }) } pub fn id(&self) -> ServiceId { @@ -120,8 +118,8 @@ impl ServiceStateHandle { impl ServiceRunner { /// Spawn the service main loop and handle it lifecycle /// Return a handle to abort execution manually - #[instrument(skip(self), fields(service_id=S::SERVICE_ID))] - pub fn run(self) -> AbortHandle { + + pub fn run(self) -> Result { let ServiceRunner { service_state, state_handle, @@ -129,7 +127,7 @@ impl ServiceRunner { } = self; let runtime = service_state.overwatch_handle.runtime().clone(); - let service = S::init(service_state); + let service = S::init(service_state)?; let (runner, abortable_handle) = abortable(service.run()); runtime.spawn(runner); @@ -137,6 +135,6 @@ impl ServiceRunner { // TODO: Handle service lifecycle // TODO: this handle should not scape this scope, it should actually be handled in the lifecycle part mentioned above - abortable_handle + Ok(abortable_handle) } } diff --git a/overwatch-rs/src/services/mod.rs b/overwatch-rs/src/services/mod.rs index 5c8e5c0..3ec51a4 100644 --- a/overwatch-rs/src/services/mod.rs +++ b/overwatch-rs/src/services/mod.rs @@ -43,10 +43,10 @@ pub trait ServiceData { #[async_trait] pub trait ServiceCore: ServiceData + Send + Sized + 'static { /// Initialize the service with the given state - fn init(service_state: ServiceStateHandle) -> Self; + fn init(service_state: ServiceStateHandle) -> Result; /// Service main loop - async fn run(mut self); + async fn run(mut self) -> Result<(), super::DynError>; } #[derive(Error, Debug)] diff --git a/overwatch-rs/src/services/relay.rs b/overwatch-rs/src/services/relay.rs index a23e94d..55beb38 100644 --- a/overwatch-rs/src/services/relay.rs +++ b/overwatch-rs/src/services/relay.rs @@ -141,7 +141,7 @@ impl Relay { } #[instrument(skip(self), err(Debug))] - pub async fn connect(&self) -> Result, RelayError> { + pub async fn connect(self) -> Result, RelayError> { let (reply, receiver) = oneshot::channel(); self.request_relay(reply).await; self.handle_relay_response(receiver).await diff --git a/overwatch-rs/src/services/state.rs b/overwatch-rs/src/services/state.rs index 385c151..56e5351 100644 --- a/overwatch-rs/src/services/state.rs +++ b/overwatch-rs/src/services/state.rs @@ -15,11 +15,13 @@ use tracing::error; /// It defines what is needed for a service state to be initialized. /// Need what set of settings information is required for it to be initialized [`ServiceState::Settings`] /// which usually is bound to the service itself [`crate::services::ServiceData::Settings`] -pub trait ServiceState: Send + Sync + 'static { +pub trait ServiceState: Sized + Send + Sync + 'static { /// Settings object that the state can be initialized from type Settings; + /// Errors that can occur during state initialization + type Error; /// Initialize a stage upon the provided settings - fn from_settings(settings: &Self::Settings) -> Self; + fn from_settings(settings: &Self::Settings) -> Result; } /// A state operator is an entity that can handle a state in a point of time @@ -70,8 +72,10 @@ impl Clone for NoState { impl ServiceState for NoState { type Settings = Settings; - fn from_settings(_settings: &Self::Settings) -> Self { - Self(Default::default()) + type Error = crate::DynError; + + fn from_settings(_settings: &Self::Settings) -> Result { + Ok(Self(Default::default())) } } @@ -197,9 +201,9 @@ mod test { impl ServiceState for UsizeCounter { type Settings = (); - - fn from_settings(_settings: &Self::Settings) -> Self { - Self(0) + type Error = crate::DynError; + fn from_settings(_settings: &Self::Settings) -> Result { + Ok(Self(0)) } } @@ -231,7 +235,7 @@ mod test { StateHandle, StateUpdater, ) = StateHandle::new( - UsizeCounter::from_settings(&()), + UsizeCounter::from_settings(&()).unwrap(), PanicOnGreaterThanTen::from_settings(()), ); tokio::task::spawn(async move { diff --git a/overwatch-rs/tests/print_service.rs b/overwatch-rs/tests/print_service.rs index 3616241..b206a98 100644 --- a/overwatch-rs/tests/print_service.rs +++ b/overwatch-rs/tests/print_service.rs @@ -28,11 +28,11 @@ impl ServiceData for PrintService { #[async_trait] impl ServiceCore for PrintService { - fn init(state: ServiceStateHandle) -> Self { - Self { state } + fn init(state: ServiceStateHandle) -> Result { + Ok(Self { state }) } - async fn run(mut self) { + async fn run(mut self) -> Result<(), overwatch_rs::DynError> { use tokio::io::{self, AsyncWriteExt}; let Self { @@ -74,6 +74,7 @@ impl ServiceCore for PrintService { }; select(Box::pin(print), Box::pin(idle)).await; + Ok(()) } } @@ -85,7 +86,7 @@ struct TestApp { #[test] fn derive_print_service() { let settings: TestAppServiceSettings = TestAppServiceSettings { print_service: () }; - let overwatch = OverwatchRunner::::run(settings, None); + let overwatch = OverwatchRunner::::run(settings, None).unwrap(); let handle = overwatch.handle().clone(); let print_service_relay = handle.relay::(); diff --git a/overwatch-rs/tests/settings_update.rs b/overwatch-rs/tests/settings_update.rs index 209ed9f..ebe0c46 100644 --- a/overwatch-rs/tests/settings_update.rs +++ b/overwatch-rs/tests/settings_update.rs @@ -29,11 +29,11 @@ impl ServiceData for SettingsService { #[async_trait] impl ServiceCore for SettingsService { - fn init(state: ServiceStateHandle) -> Self { - Self { state } + fn init(state: ServiceStateHandle) -> Result { + Ok(Self { state }) } - async fn run(mut self) { + async fn run(mut self) -> Result<(), overwatch_rs::DynError> { let Self { state: ServiceStateHandle { settings_reader, .. @@ -55,6 +55,7 @@ impl ServiceCore for SettingsService { assert!(asserted); }; print.await; + Ok(()) } } @@ -68,7 +69,7 @@ fn settings_service_update_settings() { let mut settings: TestAppServiceSettings = TestAppServiceSettings { settings_service: SettingsServiceSettings::default(), }; - let overwatch = OverwatchRunner::::run(settings.clone(), None); + let overwatch = OverwatchRunner::::run(settings.clone(), None).unwrap(); let handle = overwatch.handle().clone(); let handle2 = handle.clone(); settings.settings_service = "New settings".to_string(); diff --git a/overwatch-rs/tests/state_handling.rs b/overwatch-rs/tests/state_handling.rs index 0bb0e6c..5bc30c2 100644 --- a/overwatch-rs/tests/state_handling.rs +++ b/overwatch-rs/tests/state_handling.rs @@ -18,6 +18,17 @@ pub struct UpdateStateServiceMessage(String); impl RelayMessage for UpdateStateServiceMessage {} +#[derive(Debug)] +pub struct UnitError; + +impl core::fmt::Display for UnitError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "UnitError") + } +} + +impl std::error::Error for UnitError {} + #[derive(Clone)] pub struct CounterState { value: usize, @@ -25,9 +36,10 @@ pub struct CounterState { impl ServiceState for CounterState { type Settings = (); + type Error = UnitError; - fn from_settings(_settings: &Self::Settings) -> Self { - Self { value: 0 } + fn from_settings(_settings: &Self::Settings) -> Result { + Ok(Self { value: 0 }) } } @@ -63,11 +75,11 @@ impl ServiceData for UpdateStateService { #[async_trait] impl ServiceCore for UpdateStateService { - fn init(state: ServiceStateHandle) -> Self { - Self { state } + fn init(state: ServiceStateHandle) -> Result { + Ok(Self { state }) } - async fn run(mut self) { + async fn run(mut self) -> Result<(), overwatch_rs::DynError> { let Self { state: ServiceStateHandle { state_updater, .. }, } = self; @@ -75,6 +87,7 @@ impl ServiceCore for UpdateStateService { state_updater.update(CounterState { value }); sleep(Duration::from_millis(50)).await; } + Ok(()) } } @@ -88,7 +101,7 @@ fn state_update_service() { let settings: TestAppServiceSettings = TestAppServiceSettings { update_state_service: (), }; - let overwatch = OverwatchRunner::::run(settings, None); + let overwatch = OverwatchRunner::::run(settings, None).unwrap(); let handle = overwatch.handle().clone(); overwatch.spawn(async move {