@@ -270,7 +270,10 @@ where
270270 E : Into < anyhow:: Error > ,
271271{
272272 fn from ( source : E ) -> Self {
273- Self :: Application ( ApplicationFailure :: new ( source) . into ( ) )
273+ match source. into ( ) . downcast :: < ApplicationFailure > ( ) {
274+ Ok ( application_failure) => Self :: Application ( Box :: new ( application_failure) ) ,
275+ Err ( err) => Self :: Application ( ApplicationFailure :: new ( err) . into ( ) ) ,
276+ }
274277 }
275278}
276279
@@ -424,3 +427,52 @@ impl Debug for ActivityDefinitions {
424427 . finish ( )
425428 }
426429}
430+
431+ #[ cfg( test) ]
432+ mod test {
433+ use super :: * ;
434+ use rstest:: rstest;
435+
436+ #[ rstest]
437+ #[ case( true ) ]
438+ #[ case( false ) ]
439+ fn activity_error_conversion_is_not_lossy ( #[ case] non_retryable : bool ) {
440+ use temporalio_common:: protos:: temporal:: api:: enums:: v1:: ApplicationErrorCategory ;
441+
442+ let original = ApplicationFailure :: builder ( anyhow:: anyhow!( "big boom" ) )
443+ . type_name ( "BigBoom" . to_owned ( ) )
444+ . non_retryable ( non_retryable)
445+ . next_retry_delay ( StdDuration :: from_secs ( 3 ) )
446+ . category ( ApplicationErrorCategory :: Benign )
447+ . details ( "details" )
448+ . build ( ) ;
449+ let err = ActivityError :: from ( original) ;
450+ let ActivityError :: Application ( actual) = err else {
451+ panic ! ( "application failure should become app failure" )
452+ } ;
453+ assert_eq ! ( actual. type_name( ) , Some ( "BigBoom" ) ) ;
454+ assert_eq ! ( actual. is_non_retryable( ) , non_retryable) ;
455+ assert_eq ! ( actual. next_retry_delay( ) , Some ( StdDuration :: from_secs( 3 ) ) ) ;
456+ assert_eq ! ( actual. category( ) , ApplicationErrorCategory :: Benign ) ;
457+ assert_eq ! ( actual. to_string( ) , "big boom" ) ;
458+ }
459+
460+ #[ test]
461+ fn activity_error_from_special_err_becomes_application ( ) {
462+ #[ derive( Debug , PartialEq ) ]
463+ struct MyError ;
464+
465+ impl std:: error:: Error for MyError { }
466+ impl std:: fmt:: Display for MyError {
467+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
468+ f. write_str ( "MyError" )
469+ }
470+ }
471+
472+ let err = ActivityError :: from ( MyError ) ;
473+ let ActivityError :: Application ( actual) = err else {
474+ panic ! ( "expected application failure, got {err:?}" )
475+ } ;
476+ assert_eq ! ( actual. to_string( ) , "MyError" ) ;
477+ }
478+ }
0 commit comments