Use a tempfile instead of a StringIO object

This provides a socket.fileno(), so
libraries that call select.poll() work properly.
Also supports mocking huge responses larger than memory, if needed.
This commit is contained in:
Walter Huf 2016-02-03 00:26:56 -06:00
parent a77921aaa2
commit 3b09b51ff7
3 changed files with 23 additions and 10 deletions

View File

@ -36,6 +36,7 @@ import traceback
import json
import contextlib
import threading
import tempfile
from .compat import (
@ -236,10 +237,17 @@ class HTTPrettyRequestEmpty(object):
headers = EmptyRequestHeaders()
class FakeSockFile(StringIO):
class FakeSockFile(object):
def __init__(self):
self.file = tempfile.TemporaryFile()
self._fileno = self.file.fileno()
def close(self):
self.socket.close()
StringIO.close(self)
self.file.close()
def fileno(self):
return self._fileno
def __getattr__(self, name):
return getattr(self.file, name)
class FakeSSLSocket(object):
@ -322,6 +330,11 @@ class fakesock(object):
else:
raise UnmockedError()
def fileno(self):
if self.truesock:
return self.truesock.fileno()
return self.fd.fileno()
def close(self):
if not (self.is_http and self._closed):
if self.truesock:
@ -329,7 +342,7 @@ class fakesock(object):
self._closed = True
def makefile(self, mode='r', bufsize=-1):
"""Returns this fake socket's own StringIO buffer.
"""Returns this fake socket's own tempfile buffer.
If there is an entry associated with the socket, the file
descriptor gets filled in with the entry data before being
@ -358,7 +371,7 @@ class fakesock(object):
when HTTPretty identifies that someone is trying to send
non-http data.
The received bytes are written in this socket's StringIO
The received bytes are written in this socket's tempfile
buffer so that HTTPretty can return it accordingly when
necessary.
"""

View File

@ -322,7 +322,7 @@ def test_fakesock_socket_real_sendall(old_socket):
real_socket.recv.called.should.be.false
# And the buffer is empty
socket.fd.getvalue().should.equal(b'')
socket.fd.read().should.equal(b'')
# And connect was never called
real_socket.connect.called.should.be.false
@ -356,7 +356,7 @@ def test_fakesock_socket_real_sendall_when_http(old_socket):
])
# And the buffer should contain the data from the server
socket.fd.getvalue().should.equal(b"response from server")
socket.fd.read().should.equal(b"response from server")
# And connect was called
real_socket.connect.called.should.be.true
@ -391,7 +391,7 @@ def test_fakesock_socket_real_sendall_continue_eagain_when_http(socket, old_sock
])
# And the buffer should contain the data from the server
socket.fd.getvalue().should.equal(b"after error")
socket.fd.read().should.equal(b"after error")
# And connect was called
real_socket.connect.called.should.be.true
@ -424,7 +424,7 @@ def test_fakesock_socket_real_sendall_socket_error_when_http(socket, old_socket)
real_socket.recv.assert_called_once_with(socket._bufsize)
# And the buffer should contain the data from the server
socket.fd.getvalue().should.equal(b"")
socket.fd.read().should.equal(b"")
# And connect was called
real_socket.connect.called.should.be.true
@ -464,7 +464,7 @@ def test_fakesock_socket_real_sendall_when_http(POTENTIAL_HTTP_PORTS, old_socket
])
# And the buffer should contain the data from the server
socket.fd.getvalue().should.equal(b"response from foobar :)")
socket.fd.read().should.equal(b"response from foobar :)")
@patch('httpretty.core.old_socket')

View File

@ -272,7 +272,7 @@ def test_Entry_class_counts_multibyte_characters_in_bytes():
entry = Entry(HTTPretty.GET, 'http://example.com', 'こんにちは')
buf = FakeSockFile()
entry.fill_filekind(buf)
response = buf.getvalue()
response = buf.read()
expect(b'content-length: 15\n').to.be.within(response)