From 217ce91b115b18034daa8c51c1f54013bb404856 Mon Sep 17 00:00:00 2001 From: Gabriel Falcao Date: Mon, 7 Oct 2013 17:14:16 -0400 Subject: [PATCH] refactoring sendall --- httpretty/core.py | 32 ++++++------ tests/unit/test_core.py | 111 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 125 insertions(+), 18 deletions(-) diff --git a/httpretty/core.py b/httpretty/core.py index 72bec36..6a5dd35 100644 --- a/httpretty/core.py +++ b/httpretty/core.py @@ -332,7 +332,7 @@ class fakesock(object): self.fd.write(received) should_continue = len(received) > 0 - except socket.error as e: #TODO: TEST THIS + except socket.error as e: if e.errno == EAGAIN: continue break @@ -361,16 +361,13 @@ class fakesock(object): meta = dict(self._entry.request.headers) body = utf8(self._sent_data[-1]) if meta.get('transfer-encoding', '') == 'chunked': - if len(body) > 1 and body != '\r\n' and body != '0\r\n\r\n': + if not body.isdigit() and body != '\r\n' and body != '0\r\n\r\n': self._entry.request.body += body else: self._entry.request.body += body - try: - return httpretty.historify_request(headers, body, False) - except Exception as e: - logging.error(traceback.format_exc(e)) - return self.real_sendall(data, *args, **kw) + httpretty.historify_request(headers, body, False) + return # path might come with s = urlsplit(path) @@ -391,14 +388,7 @@ class fakesock(object): self.real_sendall(data) return - self._entry = matcher.get_next_entry(method) - # Attach more info to the entry - # So the callback can be more clever about what to do - # This does also fix the case where the callback - # would be handed a compiled regex as uri instead of the - # real uri - self._entry.info = info - self._entry.request = request + self._entry = matcher.get_next_entry(method, info, request) def debug(self, func, *a, **kw): if self.is_http: @@ -746,7 +736,7 @@ class URIMatcher(object): else: return wrap.format(self.regex.pattern) - def get_next_entry(self, method='GET'): + def get_next_entry(self, method, info, request): """Cycle through available responses, but only once. Any subsequent requests will receive the last response""" @@ -766,6 +756,14 @@ class URIMatcher(object): entry = entries_for_method[self.current_entries[method]] if self.current_entries[method] != -1: self.current_entries[method] += 1 + + # Attach more info to the entry + # So the callback can be more clever about what to do + # This does also fix the case where the callback + # would be handed a compiled regex as uri instead of the + # real uri + entry.info = info + entry.request = request return entry def __hash__(self): @@ -857,7 +855,7 @@ class httpretty(HttpBaseClass): def historify_request(cls, headers, body='', append=True): request = HTTPrettyRequest(headers, body) cls.last_request = request - if append: + if append or not cls.latest_requests: cls.latest_requests.append(request) else: cls.latest_requests[-1] = request diff --git a/tests/unit/test_core.py b/tests/unit/test_core.py index aa50c8c..e2551fb 100644 --- a/tests/unit/test_core.py +++ b/tests/unit/test_core.py @@ -377,7 +377,6 @@ def test_fakesock_socket_real_sendall_socket_error(socket, old_socket): # Given a fake socket socket = fakesock.socket() - # When I call real_sendall with data, some args and kwargs socket.real_sendall("SOMEDATA", 'some extra args...', foo='bar') @@ -458,3 +457,113 @@ def test_fakesock_socket_sendall_with_valid_requestline(POTENTIAL_HTTP_PORTS, ht # When I try to send data socket.sendall("GET /foobar HTTP/1.1\r\nContent-Type: application/json\r\n\r\n") + + +@patch('httpretty.core.old_socket') +@patch('httpretty.core.httpretty') +@patch('httpretty.core.POTENTIAL_HTTP_PORTS') +def test_fakesock_socket_sendall_with_valid_requestline(POTENTIAL_HTTP_PORTS, httpretty, old_socket): + ("fakesock.socket#sendall should create an entry if it's given a valid request line") + matcher = Mock() + info = Mock() + httpretty.match_uriinfo.return_value = (matcher, info) + httpretty.register_uri(httpretty.GET, 'http://foo.com/foobar') + + # Background: + # using a subclass of socket that mocks out real_sendall + class MySocket(fakesock.socket): + def real_sendall(self, data, *args, **kw): + raise AssertionError('should never call this...') + + # Given an instance of that socket + socket = MySocket() + + # And that is is considered http + socket.connect(('foo.com', 80)) + + # When I try to send data + socket.sendall("GET /foobar HTTP/1.1\r\nContent-Type: application/json\r\n\r\n") + + +@patch('httpretty.core.old_socket') +@patch('httpretty.core.POTENTIAL_HTTP_PORTS') +def test_fakesock_socket_sendall_with_body_data_no_entry(POTENTIAL_HTTP_PORTS, old_socket): + ("fakesock.socket#sendall should call real_sendall when not parsing headers and there is no entry") + # Background: + # Using a subclass of socket that mocks out real_sendall + class MySocket(fakesock.socket): + def real_sendall(self, data): + data.should.equal('BLABLABLABLA') + return 'cool' + + # Given an instance of that socket + socket = MySocket() + socket._entry = None + + # And that is is considered http + socket.connect(('foo.com', 80)) + + # When I try to send data + result = socket.sendall("BLABLABLABLA") + + # Then the result should be the return value from real_sendall + result.should.equal('cool') + + +@patch('httpretty.core.old_socket') +@patch('httpretty.core.POTENTIAL_HTTP_PORTS') +def test_fakesock_socket_sendall_with_body_data_with_entry(POTENTIAL_HTTP_PORTS, old_socket): + ("fakesock.socket#sendall should call real_sendall when not ") + # Background: + # Using a subclass of socket that mocks out real_sendall + class MySocket(fakesock.socket): + def real_sendall(self, data): + raise AssertionError('should have never been called') + # Using a mocked entry + entry = Mock() + entry.request.headers = {} + entry.request.body = '' + + # Given an instance of that socket + socket = MySocket() + socket._entry = entry + + + # And that is is considered http + socket.connect(('foo.com', 80)) + + # When I try to send data + socket.sendall("BLABLABLABLA") + + # Then the entry should have that body + entry.request.body.should.equal('BLABLABLABLA') + + +@patch('httpretty.core.old_socket') +@patch('httpretty.core.POTENTIAL_HTTP_PORTS') +def test_fakesock_socket_sendall_with_body_data_with_chunked_entry(POTENTIAL_HTTP_PORTS, old_socket): + ("fakesock.socket#sendall should call real_sendall when not ") + # Background: + # Using a subclass of socket that mocks out real_sendall + class MySocket(fakesock.socket): + def real_sendall(self, data): + raise AssertionError('should have never been called') + # Using a mocked entry + entry = Mock() + entry.request.headers = { + 'transfer-encoding': 'chunked', + } + entry.request.body = '' + + # Given an instance of that socket + socket = MySocket() + socket._entry = entry + + # And that is is considered http + socket.connect(('foo.com', 80)) + + # When I try to send data + socket.sendall("BLABLABLABLA") + + # Then the entry should have that body + httpretty.last_request.body.should.equal('BLABLABLABLA')