Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 53
FIX: forward connection timeout to bulkcopy pycore connection#650
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
f46c1df8f7a0374645b9aca19b2acc92033413c93878c3ca2File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -10,6 +10,7 @@ | ||
| """ | ||
| import secrets | ||
| from enum import IntEnum | ||
| from unittest.mock import MagicMock, patch | ||
| SAMPLE_TOKEN = secrets.token_hex(44) | ||
| @@ -26,6 +27,7 @@ | ||
| cursor = Cursor.__new__(Cursor) | ||
| cursor._connection = mock_conn | ||
| cursor._timeout = 0 | ||
| cursor.closed = False | ||
| cursor.hstmt = None | ||
| return cursor | ||
| @@ -108,3 +110,94 @@ | ||
| assert "access_token" not in captured_context | ||
| assert captured_context.get("user_name") == "sa" | ||
| assert captured_context.get("password") == "mypwd" | ||
| def _capture_bulkcopy_context(cursor): | ||
| """Run bulkcopy with a mocked pycore module and return the captured context.""" | ||
| captured_context = {} | ||
| mock_pycore_cursor = MagicMock() | ||
| mock_pycore_cursor.bulkcopy.return_value = { | ||
| "rows_copied": 1, | ||
| "batch_count": 1, | ||
| "elapsed_time": 0.1, | ||
| } | ||
| mock_pycore_conn = MagicMock() | ||
| mock_pycore_conn.cursor.return_value = mock_pycore_cursor | ||
| def capture_context(ctx, **kwargs): | ||
| captured_context.update(ctx) | ||
| return mock_pycore_conn | ||
| mock_pycore_module = MagicMock() | ||
| mock_pycore_module.PyCoreConnection = capture_context | ||
| with patch.dict("sys.modules", {"mssql_py_core": mock_pycore_module}): | ||
| cursor.bulkcopy("dbo.test_table", [(1, "row")], timeout=10) | ||
| return captured_context | ||
| class TestBulkcopyConnectTimeout: | ||
| """Verify cursor.bulkcopy forwards the cursor timeout to pycore (issue #626).""" | ||
| @patch("mssql_python.cursor.logger") | ||
| def test_positive_timeout_forwarded(self, mock_logger): | ||
| """cursor._timeout > 0 ⇒ connect_timeout reaches pycore, overriding 15s.""" | ||
| mock_logger.is_debug_enabled = False | ||
| cursor = _make_cursor("Server=localhost;Database=testdb;UID=sa;PWD=pwd", None) | ||
| cursor._timeout = 30 | ||
| captured = _capture_bulkcopy_context(cursor) | ||
| assert captured.get("connect_timeout") == 30 | ||
| @patch("mssql_python.cursor.logger") | ||
| def test_zero_timeout_not_forwarded(self, mock_logger): | ||
| """cursor._timeout == 0 ⇒ no override, pycore keeps its default.""" | ||
| mock_logger.is_debug_enabled = False | ||
| cursor = _make_cursor("Server=localhost;Database=testdb;UID=sa;PWD=pwd", None) | ||
bewithgaurav marked this conversation as resolved.
Dismissed
Uh oh!There was an error while loading. Please reload this page. | ||
| cursor._timeout = 0 | ||
| captured = _capture_bulkcopy_context(cursor) | ||
| assert "connect_timeout" not in captured | ||
| @patch("mssql_python.cursor.logger") | ||
| def test_uses_cursor_snapshot_not_live_connection(self, mock_logger): | ||
| """timeout is the cursor snapshot; later connection changes don't apply.""" | ||
| mock_logger.is_debug_enabled = False | ||
| cursor = _make_cursor("Server=localhost;Database=testdb;UID=sa;PWD=pwd", None) | ||
bewithgaurav marked this conversation as resolved.
Dismissed
Uh oh!There was an error while loading. Please reload this page. | ||
| cursor._timeout = 45 | ||
| cursor._connection.timeout = 99 # changed after cursor creation, must be ignored | ||
| captured = _capture_bulkcopy_context(cursor) | ||
| assert captured.get("connect_timeout") == 45 | ||
| @patch("mssql_python.cursor.logger") | ||
| def test_intenum_timeout_forwarded_as_plain_int(self, mock_logger): | ||
| """IntEnum (accepted by the public setter) is forwarded, normalised to int.""" | ||
| mock_logger.is_debug_enabled = False | ||
| class _T(IntEnum): | ||
| thirty = 30 | ||
| cursor = _make_cursor("Server=localhost;Database=testdb;UID=sa;PWD=pwd", None) | ||
saurabh500 marked this conversation as resolved.
Dismissed
Uh oh!There was an error while loading. Please reload this page. | ||
| cursor._timeout = _T.thirty | ||
| captured = _capture_bulkcopy_context(cursor) | ||
| assert captured.get("connect_timeout") == 30 | ||
| assert type(captured.get("connect_timeout")) is int | ||
| @patch("mssql_python.cursor.logger") | ||
| def test_bool_timeout_not_forwarded(self, mock_logger): | ||
| """bool is a subclass of int but must not be treated as a timeout.""" | ||
| mock_logger.is_debug_enabled = False | ||
| cursor = _make_cursor("Server=localhost;Database=testdb;UID=sa;PWD=pwd", None) | ||
bewithgaurav marked this conversation as resolved.
Dismissed
Uh oh!There was an error while loading. Please reload this page. | ||
| cursor._timeout = True | ||
| captured = _capture_bulkcopy_context(cursor) | ||
| assert "connect_timeout" not in captured | ||
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.