@@ -365,6 +365,8 @@ class UnsuccessfulResponse:
365
365
# Expected value of Nexus-Request-Retryable header
366
366
retryable_header : Optional [bool ]
367
367
failure_message : Union [str , Callable [[str ], bool ]]
368
+ # Is the Nexus Failure expected to have the details field populated?
369
+ failure_details : bool = True
368
370
# Expected value of inverse of non_retryable attribute of exception.
369
371
retryable_exception : bool = True
370
372
# TODO(nexus-prerelease): the body of a successful response need not be JSON; test non-JSON-parseable string
@@ -429,13 +431,25 @@ def check_response(
429
431
else :
430
432
assert cls .expected .retryable_header is None
431
433
432
- if failure .exception_from_details :
434
+ if cls .expected .failure_details :
435
+ assert (
436
+ failure .exception_from_details is not None
437
+ ), "Expected exception details, but found none."
433
438
assert isinstance (failure .exception_from_details , ApplicationError )
434
- assert failure .exception_from_details .non_retryable == (
439
+
440
+ exception_from_failure_details = failure .exception_from_details
441
+ if (
442
+ exception_from_failure_details .type == "HandlerError"
443
+ and exception_from_failure_details .__cause__
444
+ ):
445
+ exception_from_failure_details = (
446
+ exception_from_failure_details .__cause__
447
+ )
448
+ assert isinstance (exception_from_failure_details , ApplicationError )
449
+
450
+ assert exception_from_failure_details .non_retryable == (
435
451
not cls .expected .retryable_exception
436
452
)
437
- else :
438
- print (f"TODO(dan): { cls } did not yield a Failure with exception details" )
439
453
440
454
441
455
class SyncHandlerHappyPath (_TestCase ):
@@ -573,6 +587,7 @@ class UpstreamTimeoutViaRequestTimeout(_FailureTestCase):
573
587
retryable_header = None ,
574
588
# This error is returned by the server; it doesn't populate metadata or details, and it
575
589
# doesn't set temporal-nexus-failure-source.
590
+ failure_details = False ,
576
591
failure_message = "upstream timeout" ,
577
592
headers = {
578
593
"content-type" : "application/json" ,
@@ -597,33 +612,40 @@ class BadRequest(_FailureTestCase):
597
612
expected = UnsuccessfulResponse (
598
613
status_code = 400 ,
599
614
retryable_header = False ,
600
- failure_message = lambda s : s .startswith ("Failed converting field" ),
615
+ failure_message = lambda s : s .startswith (
616
+ "Data converter failed to decode Nexus operation input"
617
+ ),
601
618
)
602
619
603
620
604
- class NonRetryableApplicationError (_FailureTestCase ):
605
- operation = "non_retryable_application_error"
606
- expected = UnsuccessfulResponse (
607
- status_code = 500 ,
608
- retryable_header = False ,
609
- retryable_exception = False ,
610
- failure_message = "non-retryable application error" ,
611
- )
621
+ class _ApplicationErrorTestCase (_FailureTestCase ):
622
+ """Test cases in which the operation raises an ApplicationError."""
612
623
613
624
@classmethod
614
625
def check_response (
615
626
cls , response : httpx .Response , with_service_definition : bool
616
627
) -> None :
617
628
super ().check_response (response , with_service_definition )
618
629
failure = Failure (** response .json ())
619
- err = failure .exception_from_details
630
+ assert failure .exception_from_details
631
+ assert isinstance (failure .exception_from_details , ApplicationError )
632
+ err = failure .exception_from_details .__cause__
620
633
assert isinstance (err , ApplicationError )
621
- assert err .non_retryable
622
634
assert err .type == "TestFailureType"
623
635
assert err .details == ("details arg" ,)
624
636
625
637
626
- class RetryableApplicationError (_FailureTestCase ):
638
+ class NonRetryableApplicationError (_ApplicationErrorTestCase ):
639
+ operation = "non_retryable_application_error"
640
+ expected = UnsuccessfulResponse (
641
+ status_code = 500 ,
642
+ retryable_header = False ,
643
+ retryable_exception = False ,
644
+ failure_message = "non-retryable application error" ,
645
+ )
646
+
647
+
648
+ class RetryableApplicationError (_ApplicationErrorTestCase ):
627
649
operation = "retryable_application_error"
628
650
expected = UnsuccessfulResponse (
629
651
status_code = 500 ,
@@ -638,7 +660,7 @@ class HandlerErrorInternal(_FailureTestCase):
638
660
status_code = 500 ,
639
661
# TODO(nexus-prerelease): check this assertion
640
662
retryable_header = False ,
641
- failure_message = "cause message " ,
663
+ failure_message = "deliberate internal handler error " ,
642
664
)
643
665
644
666
0 commit comments