Skip to content

Commit

Permalink
PYTHON-4038 [v4.6]: Ensure retryable read OperationFailures re-rais…
Browse files Browse the repository at this point in the history
…e exception when 0 or NoneType error code is provided. (#1425) (#1429)
  • Loading branch information
Jibola committed Nov 16, 2023
1 parent 8e25ce1 commit 995365c
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 1 deletion.
3 changes: 2 additions & 1 deletion pymongo/mongo_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -2329,7 +2329,8 @@ def run(self) -> T:
# ConnectionFailures do not supply a code property
exc_code = getattr(exc, "code", None)
if self._is_not_eligible_for_retry() or (
exc_code and exc_code not in helpers._RETRYABLE_ERROR_CODES
isinstance(exc, OperationFailure)
and exc_code not in helpers._RETRYABLE_ERROR_CODES
):
raise
self._retrying = True
Expand Down
28 changes: 28 additions & 0 deletions test/mockupdb/test_cursor.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@
from __future__ import annotations

import unittest
from test import PyMongoTestCase

from mockupdb import MockupDB, OpMsg, going

from bson.objectid import ObjectId
from pymongo import MongoClient
from pymongo.errors import OperationFailure


class TestCursor(unittest.TestCase):
Expand Down Expand Up @@ -57,5 +59,31 @@ def test_getmore_load_balanced(self):
request.replies({"cursor": {"id": cursor_id, "nextBatch": [{}]}})


class TestRetryableErrorCodeCatch(PyMongoTestCase):
def _test_fail_on_operation_failure_with_code(self, code):
"""Test reads on error codes that should not be retried"""
server = MockupDB()
server.run()
self.addCleanup(server.stop)
server.autoresponds("ismaster", maxWireVersion=6)

client = MongoClient(server.uri)

with going(lambda: server.receives(OpMsg({"find": "collection"})).command_err(code=code)):
cursor = client.db.collection.find()
with self.assertRaises(OperationFailure) as ctx:
cursor.next()
self.assertEqual(ctx.exception.code, code)

def test_fail_on_operation_failure_none(self):
self._test_fail_on_operation_failure_with_code(None)

def test_fail_on_operation_failure_zero(self):
self._test_fail_on_operation_failure_with_code(0)

def test_fail_on_operation_failure_one(self):
self._test_fail_on_operation_failure_with_code(1)


if __name__ == "__main__":
unittest.main()

0 comments on commit 995365c

Please sign in to comment.