|
13 | 13 | TExecuteStatementResp,
|
14 | 14 | TOperationHandle,
|
15 | 15 | THandleIdentifier,
|
| 16 | + TOperationState, |
16 | 17 | TOperationType,
|
17 | 18 | )
|
18 | 19 | from databricks.sql.thrift_backend import ThriftBackend
|
|
23 | 24 | from databricks.sql.exc import RequestError, CursorAlreadyClosedError
|
24 | 25 | from databricks.sql.types import Row
|
25 | 26 |
|
| 27 | +from databricks.sql.utils import ExecuteResponse |
26 | 28 | from tests.unit.test_fetches import FetchTests
|
27 | 29 | from tests.unit.test_thrift_backend import ThriftBackendTestSuite
|
28 | 30 | from tests.unit.test_arrow_queue import ArrowQueueSuite
|
@@ -168,22 +170,78 @@ def test_useragent_header(self, mock_client_class):
|
168 | 170 | http_headers = mock_client_class.call_args[0][3]
|
169 | 171 | self.assertIn(user_agent_header_with_entry, http_headers)
|
170 | 172 |
|
171 |
| - @patch("%s.client.ThriftBackend" % PACKAGE_NAME, ThriftBackendMockFactory.new()) |
172 |
| - @patch("%s.client.ResultSet" % PACKAGE_NAME) |
173 |
| - def test_closing_connection_closes_commands(self, mock_result_set_class): |
174 |
| - # Test once with has_been_closed_server side, once without |
| 173 | + @patch("databricks.sql.client.ThriftBackend") |
| 174 | + def test_closing_connection_closes_commands(self, mock_thrift_client_class): |
| 175 | + """Test that closing a connection properly closes commands. |
| 176 | +
|
| 177 | + This test verifies that when a connection is closed: |
| 178 | + 1. the active result set is marked as closed server-side |
| 179 | + 2. The operation state is set to CLOSED |
| 180 | + 3. backend.close_command is called only for commands that weren't already closed |
| 181 | +
|
| 182 | + Args: |
| 183 | + mock_thrift_client_class: Mock for ThriftBackend class |
| 184 | + """ |
175 | 185 | for closed in (True, False):
|
176 | 186 | with self.subTest(closed=closed):
|
177 |
| - mock_result_set_class.return_value = Mock() |
178 |
| - connection = databricks.sql.connect(**self.DUMMY_CONNECTION_ARGS) |
| 187 | + # Set initial state based on whether the command is already closed |
| 188 | + initial_state = ( |
| 189 | + TOperationState.FINISHED_STATE |
| 190 | + if not closed |
| 191 | + else TOperationState.CLOSED_STATE |
| 192 | + ) |
| 193 | + |
| 194 | + # Mock the execute response with controlled state |
| 195 | + mock_execute_response = Mock(spec=ExecuteResponse) |
| 196 | + mock_execute_response.status = initial_state |
| 197 | + mock_execute_response.has_been_closed_server_side = closed |
| 198 | + mock_execute_response.is_staging_operation = False |
| 199 | + |
| 200 | + # Mock the backend that will be used |
| 201 | + mock_backend = Mock(spec=ThriftBackend) |
| 202 | + mock_thrift_client_class.return_value = mock_backend |
| 203 | + |
| 204 | + # Create connection and cursor |
| 205 | + connection = databricks.sql.connect( |
| 206 | + server_hostname="foo", |
| 207 | + http_path="dummy_path", |
| 208 | + access_token="tok", |
| 209 | + ) |
179 | 210 | cursor = connection.cursor()
|
180 |
| - cursor.execute("SELECT 1;") |
| 211 | + |
| 212 | + # Mock execute_command to return our execute response |
| 213 | + cursor.thrift_backend.execute_command = Mock( |
| 214 | + return_value=mock_execute_response |
| 215 | + ) |
| 216 | + |
| 217 | + # Execute a command |
| 218 | + cursor.execute("SELECT 1") |
| 219 | + |
| 220 | + # Get the active result set for later assertions |
| 221 | + active_result_set = cursor.active_result_set |
| 222 | + |
| 223 | + # Close the connection |
181 | 224 | connection.close()
|
182 | 225 |
|
183 |
| - self.assertTrue( |
184 |
| - mock_result_set_class.return_value.has_been_closed_server_side |
| 226 | + # Verify the close logic worked: |
| 227 | + # 1. has_been_closed_server_side should always be True after close() |
| 228 | + assert active_result_set.has_been_closed_server_side is True |
| 229 | + |
| 230 | + # 2. op_state should always be CLOSED after close() |
| 231 | + assert ( |
| 232 | + active_result_set.op_state |
| 233 | + == connection.thrift_backend.CLOSED_OP_STATE |
185 | 234 | )
|
186 |
| - mock_result_set_class.return_value.close.assert_called_once_with() |
| 235 | + |
| 236 | + # 3. Backend close_command should be called appropriately |
| 237 | + if not closed: |
| 238 | + # Should have called backend.close_command during the close chain |
| 239 | + mock_backend.close_command.assert_called_once_with( |
| 240 | + mock_execute_response.command_handle |
| 241 | + ) |
| 242 | + else: |
| 243 | + # Should NOT have called backend.close_command (already closed) |
| 244 | + mock_backend.close_command.assert_not_called() |
187 | 245 |
|
188 | 246 | @patch("%s.client.ThriftBackend" % PACKAGE_NAME)
|
189 | 247 | def test_cant_open_cursor_on_closed_connection(self, mock_client_class):
|
|
0 commit comments