Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions googleapiclient/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -1825,6 +1825,33 @@ def request(
content = content.encode("utf-8")
return httplib2.Response(resp), content

def close(self):
"""Closes httplib2 connections.

This is a no-op for HttpMockSequence since it doesn't hold
real network connections, but is required for compatibility
with the context manager protocol used by discovery.build().

Example:
http = HttpMockSequence([({'status': '200'}, '{}')])

# Using context manager (recommended)
with build('drive', 'v3', http=http) as service:
service.files().list().execute()

# Or manual close
service = build('drive', 'v3', http=http)
# ... use service ...
service.close()

See Also:
- HttpMock.close() for the similar implementation
- https://github.com/googleapis/google-api-python-client/issues/2359
"""
# No-op: HttpMockSequence doesn't hold real connections
pass



def set_user_agent(http, user_agent):
"""Set the user-agent on every request.
Expand Down
53 changes: 53 additions & 0 deletions tests/test_http.py
Original file line number Diff line number Diff line change
Expand Up @@ -1732,3 +1732,56 @@ def test_build_http_default_308_is_excluded_as_redirect(self):
if __name__ == "__main__":
logging.getLogger().setLevel(logging.ERROR)
unittest.main()


class TestHttpMockSequenceClose(unittest.TestCase):
"""Tests for HttpMockSequence.close() method (Issue #2359)."""

def test_http_mock_sequence_has_close_method(self):
"""Verify HttpMockSequence has close() method."""
http = HttpMockSequence([({'status': '200'}, b'OK')])

# Should have close() method
self.assertTrue(hasattr(http, 'close'))
self.assertTrue(callable(http.close))

def test_http_mock_sequence_close_does_not_raise(self):
"""Verify close() can be called without raising."""
http = HttpMockSequence([({'status': '200'}, b'OK')])

# Should not raise
http.close()

def test_http_mock_sequence_close_is_no_op(self):
"""Verify close() is safe to call multiple times."""
http = HttpMockSequence([({'status': '200'}, b'OK')])

# Multiple calls should be safe
http.close()
http.close()
http.close()

# Mock should still be usable after close
resp, content = http.request('http://example.com')
self.assertEqual(resp.status, 200)
self.assertEqual(content, b'OK')

def test_http_mock_sequence_close_returns_none(self):
"""Verify close() returns None like HttpMock."""
http = HttpMockSequence([({'status': '200'}, b'OK')])

result = http.close()
self.assertIsNone(result)

def test_http_mock_sequence_consistency_with_http_mock(self):
"""Verify HttpMockSequence.close() behaves like HttpMock.close()."""
http_mock = HttpMock(headers={'status': '200'})
http_sequence = HttpMockSequence([({'status': '200'}, b'OK')])

# Both should have close()
self.assertTrue(hasattr(http_mock, 'close'))
self.assertTrue(hasattr(http_sequence, 'close'))

# Both should return None
self.assertIsNone(http_mock.close())
self.assertIsNone(http_sequence.close())
Loading