|
19 | 19 | from tests.utils.object_assertions import assert_match_object, assert_object_lists_match |
20 | 20 | from typesense import exceptions |
21 | 21 | from typesense.sync.api_call import ApiCall, RequestHandler |
| 22 | +from typesense.async_.api_call import AsyncApiCall |
22 | 23 | from typesense.configuration import Configuration, Node |
23 | 24 | from typesense.logger import logger |
24 | 25 |
|
@@ -634,3 +635,61 @@ def test_max_retries_no_last_exception(fake_api_call: ApiCall) -> None: |
634 | 635 | num_retries=10, |
635 | 636 | last_exception=None, |
636 | 637 | ) |
| 638 | + |
| 639 | + |
| 640 | +@pytest.mark.parametrize( |
| 641 | + "client_side_error", |
| 642 | + [ |
| 643 | + httpx.PoolTimeout("Pool timeout"), |
| 644 | + httpx.LocalProtocolError("Local protocol error"), |
| 645 | + httpx.DecodingError("Decoding error"), |
| 646 | + httpx.TooManyRedirects("Too many redirects"), |
| 647 | + ], |
| 648 | +) |
| 649 | +def test_client_side_error_does_not_mark_node_unhealthy( |
| 650 | + fake_api_call: ApiCall, |
| 651 | + client_side_error: httpx.HTTPError, |
| 652 | +) -> None: |
| 653 | + """Test that client-side httpx errors propagate without failing over.""" |
| 654 | + with respx.mock: |
| 655 | + respx.get("http://nearest:8108/").mock(side_effect=client_side_error) |
| 656 | + node0_route = respx.get("http://node0:8108/").mock( |
| 657 | + return_value=httpx.Response(200, json={"key": "value"}), |
| 658 | + ) |
| 659 | + |
| 660 | + with pytest.raises(type(client_side_error)): |
| 661 | + fake_api_call.get("/", entity_type=typing.Dict[str, str]) |
| 662 | + |
| 663 | + assert len(respx.calls) == 1 |
| 664 | + assert not node0_route.called |
| 665 | + |
| 666 | + assert fake_api_call.config.nearest_node.healthy is True |
| 667 | + |
| 668 | + |
| 669 | +@pytest.mark.parametrize( |
| 670 | + "client_side_error", |
| 671 | + [ |
| 672 | + httpx.PoolTimeout("Pool timeout"), |
| 673 | + httpx.LocalProtocolError("Local protocol error"), |
| 674 | + httpx.DecodingError("Decoding error"), |
| 675 | + httpx.TooManyRedirects("Too many redirects"), |
| 676 | + ], |
| 677 | +) |
| 678 | +async def test_async_client_side_error_does_not_mark_node_unhealthy( |
| 679 | + fake_async_api_call: AsyncApiCall, |
| 680 | + client_side_error: httpx.HTTPError, |
| 681 | +) -> None: |
| 682 | + """Test that client-side httpx errors propagate without failing over (async).""" |
| 683 | + with respx.mock: |
| 684 | + respx.get("http://nearest:8108/").mock(side_effect=client_side_error) |
| 685 | + node0_route = respx.get("http://node0:8108/").mock( |
| 686 | + return_value=httpx.Response(200, json={"key": "value"}), |
| 687 | + ) |
| 688 | + |
| 689 | + with pytest.raises(type(client_side_error)): |
| 690 | + await fake_async_api_call.get("/", entity_type=typing.Dict[str, str]) |
| 691 | + |
| 692 | + assert len(respx.calls) == 1 |
| 693 | + assert not node0_route.called |
| 694 | + |
| 695 | + assert fake_async_api_call.config.nearest_node.healthy is True |
0 commit comments