diff --git a/crates/server/src/service.rs b/crates/server/src/service.rs index 42c1cbc..ccaf11b 100644 --- a/crates/server/src/service.rs +++ b/crates/server/src/service.rs @@ -319,4 +319,37 @@ mod tests { assert_eq!(results["a.se"], ProviderResult::NoData); assert!(matches!(results["b.se"], ProviderResult::Ok { .. })); } + + /// Provider whose parse() panics — must be contained by spawn_blocking. + struct PanickingProvider; + + impl ProviderHandle for PanickingProvider { + fn name(&self) -> &str { + "panic.se" + } + + fn requests(&self, number: &str) -> Result, HostError> { + Ok(vec![format!("https://example.test/{number}")]) + } + + fn parse(&self, _number: &str, _responses: &[FetchedResponse]) -> ParseOutcome { + panic!("provider blew up"); + } + } + + #[tokio::test] + async fn provider_panic_is_contained_and_isolated() { + let panicking = Arc::new(PanickingProvider); + let healthy = Arc::new(FakeProvider { + name: "ok.se", + outcome: || ParseOutcome::Ok(entry()), + }); + let fetcher = Arc::new(FakeFetcher::new(false)); + let svc = service(vec![panicking, healthy], fetcher); + + let results = svc.lookup("0700000000").await; + + assert_eq!(results["panic.se"], ProviderResult::ParseFailed); + assert!(matches!(results["ok.se"], ProviderResult::Ok { .. })); + } }