Code Monkey home page Code Monkey logo

httpretty's Introduction

HTTPretty 1.1.4

image

HTTP Client mocking tool for Python created by Gabriel Falcão . It provides a full fake TCP socket module. Inspired by FakeWeb

Python Support:

  • 3.6
  • 3.7
  • 3.8
  • 3.9

image

image

image

image

image

image

image

image

image

image

image

image

image

Install

pip install httpretty

Common Use Cases

  • Test-driven development of API integrations
  • Fake responses of external APIs
  • Record and playback HTTP requests

Simple Example

import sure
import httpretty
import requests


@httpretty.activate(verbose=True, allow_net_connect=False)
def test_httpbin():
    httpretty.register_uri(
        httpretty.GET,
        "https://httpbin.org/ip",
        body='{"origin": "127.0.0.1"}'
    )

    response = requests.get('https://httpbin.org/ip')
    response.json().should.equal({'origin': '127.0.0.1'})

    httpretty.latest_requests().should.have.length_of(1)
    httpretty.last_request().should.equal(httpretty.latest_requests()[0])
    httpretty.last_request().body.should.equal('{"origin": "127.0.0.1"}')

checking multiple responses

@httpretty.activate(verbose=True, allow_net_connect=False)
def test_post_bodies():
    url = 'http://httpbin.org/post'
    httpretty.register_uri(httpretty.POST, url, status=200)
    httpretty.register_uri(httpretty.POST, url, status=400)
    requests.post(url, data={'foo': 'bar'})
    requests.post(url, data={'zoo': 'zoo'})
    assert 'foo=bar' in httpretty.latest_requests()[0].body
    assert 'zoo=bar' in httpretty.latest_requests()[1].body

License

<HTTPretty - HTTP client mock for Python>
Copyright (C) <2011-2021> Gabriel Falcão <[email protected]>

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

Main contributors

HTTPretty has received many contributions but some folks made remarkable contributions and deserve extra credit:

httpretty's People

Contributors

adamwill avatar almet avatar andresriancho avatar andrewgross avatar chris-martin avatar cyrilroelandtenovance avatar dupuy avatar erwinjunge avatar evasdk avatar frankamp avatar gabrielfalcao avatar gcetusic avatar grahamc avatar hroncok avatar hufman avatar igorsobreira avatar jmcarp avatar kouk avatar luqmaan avatar mardiros avatar mgorny avatar mhluongo avatar oschwald avatar pidelport avatar rdlukaszsz avatar spulec avatar timcowlishaw avatar toumorokoshi avatar vphilippon avatar z4r avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

httpretty's Issues

Query string aren't parsed when fakesocket is called

Say you have:

FAKE_HOST = "dummyhost.com"
DUMMY_PATH = "/"
DUMMY_URL = "http://%s%s" % (FAKE_HOST, DUMMY_PATH)
DUMMY_CONTENT = "Hello World"
DUMMY_PARAMS = {'msg': DUMMY_CONTENT}

url = "%s?%s" % (DUMMY_URL, urllib.urlencode(DUMMY_PARAMS)),
HTTPretty.register_uri(HTTPretty.GET,  url, body=DUMMY_CONTENT,  status=200)

Requesting the url will fail because it won't parse the query-string from the fakesock object. This is easyli fixed:

@@ -223,7 +223,10 @@ class fakesock(object):
                         logging.error(traceback.format_exc(e))
                         return self._true_sendall(data, *args, **kw)

+            query = ''
             method, path, version = re.split('\s+', verb.strip(), 3)
+            if '?' in path:
+                path, query = path.split('?')

             request = HTTPretty.historify_request(data)


             info = URIInfo(hostname=self._host, port=self._port, path=path,
-                           last_request=request)
+                           query=query, last_request=request)

             entries = []
             for key, value in HTTPretty._entries.items():

RuntimeError: HTTPretty intercepted and unexpected socket method call. (amqp/pika/rabbitmq)

httpretty instructed me to report a bug.

Try this simple script:

import pika
import httpretty

@httpretty.activate
def test_me():
        parameters = pika.URLParameters('amqp://guest:guest@localhost:5672/%2F')
        connection = pika.BlockingConnection(parameters)
        channel = connection.channel()
        channel.exchange_declare(exchange='e', durable=True, type='direct')
        channel.queue_declare(queue='q', durable=True, exclusive=False,
                              auto_delete=False)
        channel.queue_bind(exchange='e', queue='q', routing_key='q')
        channel.close()
        connection.close()

test_me()

returns the following traceback:

[' File "", line 1, in \n', ' File "/home/andy/flywheel/buildout-scripzo-backend/eggs/httpretty-0.6.3-py2.7.egg/httpretty/core.py", line 807, in wrapper\n return test(_args, *_kw)\n', ' File "", line 4, in test_me\n', ' File "/home/andy/flywheel/buildout-scripzo-backend/eggs/pika-0.9.9-py2.7.egg/pika/adapters/base_connection.py", line 61, in init\n super(BaseConnection, self).init(parameters, on_open_callback)\n', ' File "/home/andy/flywheel/buildout-scripzo-backend/eggs/pika-0.9.9-py2.7.egg/pika/connection.py", line 513, in init\n self._connect()\n', ' File "/home/andy/flywheel/buildout-scripzo-backend/eggs/pika-0.9.9-py2.7.egg/pika/connection.py", line 809, in _connect\n self._adapter_connect()\n', ' File "/home/andy/flywheel/buildout-scripzo-backend/eggs/pika-0.9.9-py2.7.egg/pika/adapters/blocking_connection.py", line 186, in _adapter_connect\n self._on_connected()\n', ' File "/home/andy/flywheel/buildout-scripzo-backend/eggs/pika-0.9.9-py2.7.egg/pika/connection.py", line 1041, in _on_connected\n self._send_frame(frame.ProtocolHeader())\n', ' File "/home/andy/flywheel/buildout-scripzo-backend/eggs/pika-0.9.9-py2.7.egg/pika/adapters/blocking_connection.py", line 294, in _send_frame\n super(BlockingConnection, self)._send_frame(frame_value)\n', ' File "/home/andy/flywheel/buildout-scripzo-backend/eggs/pika-0.9.9-py2.7.egg/pika/connection.py", line 1326, in _send_frame\n self._flush_outbound()\n', ' File "/home/andy/flywheel/buildout-scripzo-backend/eggs/pika-0.9.9-py2.7.egg/pika/adapters/blocking_connection.py", line 253, in _flush_outbound\n if self._handle_write():\n', ' File "/home/andy/flywheel/buildout-scripzo-backend/eggs/pika-0.9.9-py2.7.egg/pika/adapters/base_connection.py", line 315, in _handle_write\n bytes_written = self.socket.send(self.outbound_buffer.read())\n', ' File "/home/andy/flywheel/buildout-scripzo-backend/eggs/httpretty-0.6.3-py2.7.egg/httpretty/core.py", line 299, in debug\n lines = map(utf8, traceback.format_stack(frame))\n']

On line 315 of pika.base_connection.BaseConnection:
bytes_written = self.socket.send(self.outbound_buffer.read())

The value of self.outbound_buffer.read() is:
'AMQP\x00\x00\t\x01'

Add ability to validate requests.

So far, HTTPretty only returns a response based on URI and HTTP method. A useful feature would be to return a response based on request headers (ex. 'X-Auth-Token').

HTTPretty breaking other URLs

With the following test

@httprettified
def test_httpretty_should_not_override_other_urls():
    u"HTTPretty shouldn't break other URLs"

    HTTPretty.register_uri(HTTPretty.GET, "http://github.com/foo",
                           body="<root><baz /</root>")

    response = requests.get('http://google.com/')
    expect(response.status_code).to.equal(200)

I get

  File "HTTPretty/tests/functional/test_requests.py", line 153, in test_httpretty_should_not_override_other_urls
    response = requests.get('http://google.com/')
  File "HTTPretty/lib/python2.7/site-packages/requests/api.py", line 55, in get
    return request('get', url, **kwargs)
  File "HTTPretty/lib/python2.7/site-packages/requests/api.py", line 44, in request
    return session.request(method=method, url=url, **kwargs)
  File "HTTPretty/lib/python2.7/site-packages/requests/sessions.py", line 289, in request
    history = [r for r in gen] if allow_redirects else []
  File "HTTPretty/lib/python2.7/site-packages/requests/sessions.py", line 133, in resolve_redirects
    proxies=proxies
  File "HTTPretty/lib/python2.7/site-packages/requests/sessions.py", line 279, in request
    resp = self.send(prep, stream=stream, timeout=timeout, verify=verify, cert=cert, proxies=proxies)
  File "HTTPretty/lib/python2.7/site-packages/requests/sessions.py", line 374, in send
    r = adapter.send(request, **kwargs)
  File "HTTPretty/lib/python2.7/site-packages/requests/adapters.py", line 222, in send
    r.content
  File "HTTPretty/lib/python2.7/site-packages/requests/models.py", line 550, in content
    self._content = bytes().join(self.iter_content(CONTENT_CHUNK_SIZE)) or bytes()
  File "HTTPretty/lib/python2.7/site-packages/requests/models.py", line 496, in generate
    chunk = self.raw.read(chunk_size)
  File "HTTPretty/lib/python2.7/site-packages/requests/packages/urllib3/response.py", line 148, in read
    return self._fp.read(amt)
  File "python2.7/httplib.py", line 541, in read
    return self._read_chunked(amt)
  File "python2.7/httplib.py", line 592, in _read_chunked
    value.append(self._safe_read(amt))
  File "python2.7/httplib.py", line 649, in _safe_read
    raise IncompleteRead(''.join(s), amt)
IncompleteRead: IncompleteRead(532 bytes read)

rotating responses

In the section "rotating responses" you may want to mention that you can register more than two responses. Something like "you can register as many responses as needed." The wording of the documentation led me to believe that two is the limit.

Feature request: query string parameters

It would be a nice feature to be able to specify query string arguments that a mocked request should expect. Further, it would be even nicer if you could specify just a subset of the parameters you expect to be passed.

Use case: I'm testing an OAuth implementation. I want to validate that the library is calling various REST endpoints, and I want to validate that it's passing some static query parameters like oauth_token and oauth_consumer_key. But I don't want to validate values for non-static fields like oauth_timestamp.

Streaming data broken with regexs

The following test hangs on the request.post

@httprettified
def test_httpretty_should_allow_registering_regexes_with_streaming_responses():
    u"HTTPretty should allow registering regexes with requests"

    HTTPretty.register_uri(
        HTTPretty.POST,
        re.compile("https://api.yipit.com/v1/deal;brand=(?P<brand_name>\w+)"),
        body="Found brand",
    )

    def gen():
        yield 'hi'
        yield 'there'

    response = requests.post(
        'https://api.yipit.com/v1/deal;brand=gap?first_name=chuck&last_name=norris',
        data=gen(),
    )
    expect(response.text).to.equal('Found brand')
    expect(HTTPretty.last_request.method).to.equal('POST')
    expect(HTTPretty.last_request.path).to.equal('/v1/deal;brand=gap?first_name=chuck&last_name=norris')

The offending lines are

is_parsing_headers = False

if self._host not in hostnames:
    return self._true_sendall(data)

Regex URIMatchers don't have hostnames so hostnames here will just be [None].

I think that the correct fix is to iterate through all the entries and try to do a regex search for self._host within them. If I get some time, I'll put together a patch.

On Python 2.6.6 it breaks smtplib.SMTP (socket has different method signatures)

One problem has to do with socket.makefile ... the signature in Python 2.6.6 has both mode and bufsize as optional parameters.

After I fixed that, setting bufsize to a default of -1 (which should be the system's default), then I started to receive "connection quit unexpectedly".

Haven't experimented with a different setting or not or looked at your code really carefully, but breaking the default socket functionality for other protocols is not OK.

RuntimeError: HTTPretty intercepted and unexpected socket method call.

ERROR: test_change_prefix (dynamodb-test.AWSDynamoDBTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/dilshod/source-code/somecode/star/site-packages/somelib/tests/dynamodb-test.py", line 283, in test_change_prefix
    ddb = somelib.connect_dynamodb('something_completely_different')
  File "/home/dilshod/source-code/somecode/star/site-packages/somelib/dynamodb.py", line 376, in connect_dynamodb
    return MemcacheConnection(prefix)
  File "/home/dilshod/source-code/somecode/star/site-packages/somelib/dynamodb.py", line 152, in __init__
    self.mc.set('test', 'ok')
  File "/home/dilshod/source-code/somecode/star/site-packages/somelib/memcache.py", line 41, in set
    err = memcache.Client.set(self, key, val, time)
  File "/home/dilshod/pyenv/somecode-star/local/lib/python2.7/site-packages/memcache.py", line 565, in set
    return self._set("set", key, val, time, min_compress_len)
  File "/home/dilshod/pyenv/somecode-star/local/lib/python2.7/site-packages/memcache.py", line 802, in _set
    return _unsafe_set()
  File "/home/dilshod/pyenv/somecode-star/local/lib/python2.7/site-packages/memcache.py", line 795, in _unsafe_set
    return(server.expect("STORED") == "STORED")
  File "/home/dilshod/pyenv/somecode-star/local/lib/python2.7/site-packages/memcache.py", line 1136, in expect
    line = self.readline()
  File "/home/dilshod/pyenv/somecode-star/local/lib/python2.7/site-packages/memcache.py", line 1125, in readline
    data = recv(4096)
  File "/home/dilshod/pyenv/somecode-star/local/lib/python2.7/site-packages/moto/packages/httpretty.py", line 356, in debug
    raise RuntimeError("\n".join(message))
RuntimeError: HTTPretty intercepted and unexpected socket method call.
Please open an issue at 'https://github.com/gabrielfalcao/HTTPretty/issues'
And paste the following traceback:

['  File "/home/dilshod/pyenv/somecode-star/bin/nosetests", line 8, in <module>\n    load_entry_point(\'nose==1.2.1\', \'console_scripts\', \'nosetests\')()\n', '  File "/home/dilshod/pyenv/somecode-star/local/lib/python2.7/site-packages/nose/core.py", line 118, in __init__\n    **extra_args)\n', '  File "/usr/lib/python2.7/unittest/main.py", line 95, in __init__\n    self.runTests()\n', '  File "/home/dilshod/pyenv/somecode-star/local/lib/python2.7/site-packages/nose/core.py", line 197, in runTests\n    result = self.testRunner.run(self.test)\n', '  File "/home/dilshod/pyenv/somecode-star/local/lib/python2.7/site-packages/nose/core.py", line 61, in run\n    test(result)\n', '  File "/home/dilshod/pyenv/somecode-star/local/lib/python2.7/site-packages/nose/suite.py", line 176, in __call__\n    return self.run(*arg, **kw)\n', '  File "/home/dilshod/pyenv/somecode-star/local/lib/python2.7/site-packages/nose/suite.py", line 223, in run\n    test(orig)\n', '  File "/home/dilshod/pyenv/somecode-star/local/lib/python2.7/site-packages/nose/suite.py", line 176, in __call__\n    return self.run(*arg, **kw)\n', '  File "/home/dilshod/pyenv/somecode-star/local/lib/python2.7/site-packages/nose/suite.py", line 223, in run\n    test(orig)\n', '  File "/home/dilshod/pyenv/somecode-star/local/lib/python2.7/site-packages/nose/suite.py", line 176, in __call__\n    return self.run(*arg, **kw)\n', '  File "/home/dilshod/pyenv/somecode-star/local/lib/python2.7/site-packages/nose/suite.py", line 223, in run\n    test(orig)\n', '  File "/home/dilshod/pyenv/somecode-star/local/lib/python2.7/site-packages/nose/case.py", line 45, in __call__\n    return self.run(*arg, **kwarg)\n', '  File "/home/dilshod/pyenv/somecode-star/local/lib/python2.7/site-packages/nose/case.py", line 133, in run\n    self.runTest(result)\n', '  File "/home/dilshod/pyenv/somecode-star/local/lib/python2.7/site-packages/nose/case.py", line 151, in runTest\n    test(result)\n', '  File "/usr/lib/python2.7/unittest/case.py", line 396, in __call__\n    return self.run(*args, **kwds)\n', '  File "/usr/lib/python2.7/unittest/case.py", line 332, in run\n    testMethod()\n', '  File "/home/dilshod/source-code/somecode/star/site-packages/somelib/tests/dynamodb-test.py", line 283, in test_change_prefix\n    ddb = somelib.connect_dynamodb(\'something_completely_different\')\n', '  File "/home/dilshod/source-code/somecode/star/site-packages/somelib/dynamodb.py", line 376, in connect_dynamodb\n    return MemcacheConnection(prefix)\n', '  File "/home/dilshod/source-code/somecode/star/site-packages/somelib/dynamodb.py", line 152, in __init__\n    self.mc.set(\'test\', \'ok\')\n', '  File "/home/dilshod/source-code/somecode/star/site-packages/somelib/memcache.py", line 41, in set\n    err = memcache.Client.set(self, key, val, time)\n', '  File "/home/dilshod/pyenv/somecode-star/local/lib/python2.7/site-packages/memcache.py", line 565, in set\n    return self._set("set", key, val, time, min_compress_len)\n', '  File "/home/dilshod/pyenv/somecode-star/local/lib/python2.7/site-packages/memcache.py", line 802, in _set\n    return _unsafe_set()\n', '  File "/home/dilshod/pyenv/somecode-star/local/lib/python2.7/site-packages/memcache.py", line 795, in _unsafe_set\n    return(server.expect("STORED") == "STORED")\n', '  File "/home/dilshod/pyenv/somecode-star/local/lib/python2.7/site-packages/memcache.py", line 1136, in expect\n    line = self.readline()\n', '  File "/home/dilshod/pyenv/somecode-star/local/lib/python2.7/site-packages/memcache.py", line 1125, in readline\n    data = recv(4096)\n', '  File "/home/dilshod/pyenv/somecode-star/local/lib/python2.7/site-packages/moto/packages/httpretty.py", line 347, in debug\n    lines = map(utf8, traceback.format_stack(frame))\n']

Querystring and unicode

I'm experiencing problems with unicode in querystrings under python 2.6 with latest httpretty. Here is a failing functional test I wrote to show what I think is wrong.

@httprettified
def test_unicode_querystrings():
    HTTPretty.register_uri(HTTPretty.GET, "http://yipit.com/login",
                           body="Find the best daily deals")
    requests.get('http://yipit.com/login?user=Gabriel+Falcão')
    expect(HTTPretty.last_request.querystring['user'][0]).should.be.equal('Gabriel Falcão')
AssertionError: given
X = u'Gabriel Falc\xc3\xa3o'
    and
Y = u'Gabriel Falc\xe3o'
X is u'Gabriel Falc\xc3\xa3o' whereas Y is u'Gabriel Falc\xe3o'

It would be awesome if someone pointed me where to start.
My guess it's from __future__ import unicode_literals, but I'm not sure

Create an Enforced mode where everything must be mocked.

Whilst this shouldn't apply all the time if i'm mocking my HTTP traffic then chances are I want all my HTTP traffic mocked.

There should be a way to tell HTTPretty that if you receive a call that is not mocked throw an error rather than pass it on to the real source.

Context manager and recording/playback.

Hey guys, love love love this library (we Zapier folk do a lot of API stuff).

What I'd like to see is a pattern like this (I haven't had a chance to dive into the code much yet, so please forgive odd naming and such):

# serializes any request made within the context into a JSON format
with HTTPretty.record('/path/to/hello-world.json'):
    response = requests.post('http://httpbin.org/post', {'hello': 'world!'}) # live!

Now, located in /path/to/hello-world.json would be written a JSON file like the one below.

{
    "request": {
        "method": "POST",
        "uri": "http://httpbin.org/post"
    },
    "response": {
        "status": 200,
        "headers": {
            "Content-Type": "application/json"
        },
        "body": "{\n  \"origin\": \"123.123.123.123\",\n  \"files\": {},\n  \"form\": {\n    \"hello\": \"world!\"\n  },\n  \"url\": \"http://httpbin.org/post\",\n  \"args\": {},\n  \"headers\": {\n    \"Content-Length\": \"14\",\n    \"Accept-Encoding\": \"gzip, deflate, compress\",\n    \"Connection\": \"keep-alive\",\n    \"Accept\": \"*/*\",\n    \"User-Agent\": \"python-requests/0.14.2 CPython/2.7.1 Darwin/11.4.0\",\n    \"Host\": \"httpbin.org\",\n    \"Content-Type\": \"application/x-www-form-urlencoded\"\n  },\n  \"json\": null,\n  \"data\": \"\"\n}"
    }
}

I didn't bother to show full request/response serialization as it would probably be recorded, but I assume it could be partially defined with sensible defaults if you feel like hand rolling JSON and saving a few (a lot) of characters.

# unserialize requests from JSON format and mock requests
with HTTPretty.playback('/path/to/hello-world.json'):
    response = requests.post('http://httpbin.org/post', {'hello': 'world!'}) # fake!

    assert 200 is response.status_code
    assert 'application/json' is response.headers['Content-Type']
    assert 'origin' in response.json
    assert 'form' in response.json

As long as you guys are cool with such a pattern and have no particular pointers on implementation, I'll dig in and make this happen. Its gonna be incredibly useful!

Mocking a 301 with requests

Hello,

I am trying to mock url shorteners such as tinyurl.com. Unfortunately, it makes requests hang. Here is the code I wrote:

@httprettified
def test_expand_tiny(self):
    url = 'http://tinyurl.com/deadbeef'
    target = 'http://google.fr/'
    HTTPretty.register_uri(HTTPretty.GET, url,
                           status=301,
                           location=target,
                           )

    # urllib2

    import urllib2
    import cookielib

    class NoRedirection(urllib2.HTTPErrorProcessor):

        def http_response(self, request, response):
            code, msg, hdrs = response.code, response.msg, response.info()

            return response

        https_response = http_response

    opener = urllib2.build_opener(NoRedirection)
    response = opener.open(url)
    location = response.info()['Location']
    self.assertEqual(location, target)

    # requests

    import requests

    r = requests.get(url)
    self.assertEqual(r.url, target)

(note the simplicity of the requests code)

I tried the following variant as you mentioned in the README that requests can be confused when Content-Length is missing (though I didn't use forcing_headers in my original example).

    HTTPretty.register_uri(HTTPretty.GET, url,
                           status=301,
                           body='',
                           forcing_headers={'Location': target, 
                                            'Content-Length': '0',
                                            'Content-Type': 'text/plain',
                                            } 
                           )

I also tried to copy/paste the actual response from curl, but the problem persists (with or without the "Connection: close" line).

    headers = {
        'X-Powered-By': 'PHP/5.4.7',
        'Set-Cookie': 'tinyUUID=0d1bfe87dd2d84e3551eccf4; expires=Thu, 19-Dec-2013 13:23:47 GMT; path=/; domain=.tinyurl.com',
        'Location': target,
        'X-tiny': 'cache 0.0024998188018799',
        'Content-type': 'text/html',
        'Connection': 'close',
        'Date': 'Wed, 19 Dec 2012 13:23:47 GMT',
        'Server': 'TinyURL/1.6',
        }

    HTTPretty.register_uri(HTTPretty.GET, url,
                           status=301,
                           forcing_headers=headers,
                           body = ''
                        )

As the problem is that requests blocks while trying to receive data, I assumed that it was a bug on requests' side, but since it blocks with the same headers, I'm a bit puzzled.

Thanks for this great library. Apart from that, it works great!

please get rid of module global HTTPretty.enable()

Hi,

I really like the idea of this library, but it currently has one ugly wart:
https://github.com/gabrielfalcao/HTTPretty/blob/master/httpretty/__init__.py#L493

There's no way that should be there, explicit is better than implicit and all that, and the docs should give examples of both HTTPretty.enable() and HTTPretty.disable() is setUp and tearDown methods.

Related: it would be cool if HTTPPretty could be used as a context manager and decorator, I've found both very powerful for my own library of test fixtures, eg:

http://packages.python.org/testfixtures/files.html#the-context-manager
http://packages.python.org/testfixtures/files.html#the-decorator

That said, thanks for the awesome library!

Chris

HTTPretty breaks paramiko

I thought that the work you had done last week should make it so that HTTPretty no longer breaks things like this. Feel free to just close this if it just isn't supposed to be supported at this time.

['  File "/usr/local/Cellar/python/2.7.3/Frameworks/Python.framework/Versions/2.7/lib/python2.7/threading.py", line 524, in __bootstrap\n    self.__bootstrap_inner()\n', '  

File "/usr/local/Cellar/python/2.7.3/Frameworks/Python.framework/Versions/2.7/lib/python2.7/threading.py", line 551, in __bootstrap_inner\n    self.run()\n', ' 

File "../lib/python2.7/site-packages/paramiko/transport.py", line 1554, in run\n    self.packetizer.write_all(self.local_version + \'\\r\\n\')\n', ' 

File "../lib/python2.7/site-packages/paramiko/packet.py", line 248, in write_all\n    n = self.__socket.send(out)\n', ' 

File "/usr/local/lib/python2.7/site-packages/httpretty/__init__.py", line 347, in debug\n    lines = map(utf8, traceback.format_stack(frame))\n']

Lack of trailing slash hangs on _d = self.truesock.recv(16)

Prerequisites:

python 2.7.3
requests 1.2.0
httpretty 0.5.10

How to reproduce:

#test.py
import requests
from unittest2 import TestCase
from httpretty import httprettified, HTTPretty

class Test(TestCase):
    @httprettified
    def test(self):
        url = 'http://www.youtube.com'
        HTTPretty.register_uri(HTTPretty.GET, url, body='')
        response = requests.get(url)
        self.assertEqual(response.status_code, 200)

nosestests test.py will hang until you interrupt it, which will return

 File ".../httpretty/__init__.py", line 258, in _true_sendall
    _d = self.truesock.recv(16)
KeyboardInterrupt

Workaround:

  • add trailing slash to the url

FakeSockFile doesn't have the _sock attribute, breaks code that depends on it

I discovered this issue while testing code that uses Python Twitter Tools. I mock the URL like this:

httpretty.register_uri(httpretty.GET,                                                                                  
        'https://stream.twitter.com/1.1/statuses/filter.json',                                                         
        body=gen(), streaming=True)  

And use twitter's TwitterStream like this:

client = TwitterStream(auth=OAuth(...))
stream = client.statuses.filter(track='keyword')
for t in stream:
    pass

TwitterStream then explodes with an error:

  File ".../site-packages/twitter/stream.py", line 27, in __iter__
    sock = self.handle.fp._sock.fp._sock
AttributeError: FakeSockFile instance has no attribute '_sock'

Where self.handle is a file-like object returned by urllib2.urlopen(). The unpatched socket file object does indeed have the attribute:

>>> import urllib2
>>> h = urllib2.urlopen('http://google.com')
>>> h.fp
<socket._fileobject object at 0xb6ed51ec>
>>> h.fp._sock
<httplib.HTTPResponse instance at 0xb6ee464c>
>>> h.fp._sock.fp
<socket._fileobject object at 0xb7420dac>
>>> h.fp._sock.fp._sock
<socket object, fd=3, family=2, type=1, protocol=6>

While HTTPretty's FakeSockFile doesn't:

>>> httpretty.enable()
>>> h = urllib2.urlopen('http://google.com')
>>> h.fp
<socket._fileobject object at 0xb6e8996c>
>>> h.fp._sock
<httplib.HTTPResponse instance at 0xb6dc256c>
>>> h.fp._sock.fp
<httpretty.core.FakeSockFile instance at 0xb6dc25ac>
>>> h.fp._sock.fp._sock
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: FakeSockFile instance has no attribute '_sock'

So in a way, that's broken socket emulating by HTTPretty. Though I wonder how one should go about defining the _sock attribute on FakeSockFile as it is now only a subclass of StringIO and doesn't seem to have any relation to the actual emulated socket.

An ANY method that matches any method

Particularly when using regexps the method is passed as a parameter to the callback function.

It'd be really useful if i could have a way of stubbing ALL or a list of methods that would be matched.

eg.

httpretty.register_uri(httpretty.ALL, re.compile('http://localhost/.*'), _my_callback)
or
httpretty.register_uri([httpretty.GET, httpretty.POST], ....)

Add more JSON support

It'd be nice to be able to HTTPretty.register_uri(..., json={'my': 'object'}), and similarly inspect the json of a request.

Should be a way to flag a registered URI as dependent on the querystring

I'd like to return a different result dependent on the querystring. Perhaps httpretty.register_uri could take a "use_querystring" kwarg, and pass that on until it gets to the part where it does the regex match.

For now I'm using a callable body, but that's confusing and messy for this purpose.

New version (0.6.2) was released twice w/o version number change

Not sure why it was done, but it seems a bit wrong to me.

I.e. there were two 0.6.2 versions released, this is even document in ChangeLog: https://github.com/gabrielfalcao/HTTPretty/blob/master/NEWS.md

I was kinda surprised when our build failed (because we were applying patches, etc.) - but we didn't change requirements.

This is not an issue per se, but something of a inconvenience.

Anyway, enough with bashing, it is a nice piece of software otherwise :)

HTTPretty overwrites socket.inet_aton method globally.

Standard:

>>> import socket
>>> socket.inet_aton("127.0.0.1")
>>> '\x7f\x00\x00\x01'

After mocking some stuff somewhere (different TestCase) with HTTPretty, we try again:

>>> socket.inet_aton("127.0.0.1")
>>> '127.0.0.1'

I think you should fix this.

Actual place in code is here

Support for regular expressions in registered urls

One of the features I use with fakeweb is the ability to use a regular expression when registering a URL. This allows me to register one base URL and have all calls being under that base URL be matched. I can then assert the call history as needed with proper error messages instead of:

ConnectionError: HTTPConnectionPool(host='testhost', port=8080): Max retries exceeded 
with url: /testurl (Caused by <class 'socket.gaierror'>: [Errno 8] nodename nor servname 
provided, or not known)

whenever a url failed to match

This is especially important when testing an interface against a web service which uses matrix parameters on the form http://testhost:8080/resource;color=blue;shape=rectangle as the matrix remains part of the path inside HTTPretty and the ordering of the argument becomes important to the matching.

Using a regexp is not possible today in HTTPretty as the path comparison is done using unicode strings. How do you view adding this as a feature?

Carriage Return Line Feed

Hi Gabriel,
whether for business or for pleasure, I like to develop Rest API.
And in the last days I'm moving all my tests to the HTTPretty solution.

But I have some problem with multiline and multipart.

I tried to highlight two issues in these two snippets:

# MULTILINE
import requests
from httpretty import HTTPretty, httprettified
from sure import expect

URL = 'http://httpbin.org/post'
DATA = 'content=Action: comment\nText: Comment with attach\n with multiline\n to test'
HEADERS = {'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8', 'Accept': 'text/plain'}

@httprettified 
def test_multiline(body):
    HTTPretty.register_uri(HTTPretty.POST, URL, body=body)
    response = requests.post(URL, data=DATA, headers=HEADERS)
    expect(response.status_code).to.equal(200)

response = requests.post(URL, data=DATA, headers=HEADERS)
print response.text
test_multiline(response.text)

# MULTIPART
import requests
from httpretty import HTTPretty, httprettified
from sure import expect

URL = 'http://httpbin.org/post'
DATA = '--xXXxXXyYYzzz\r\nContent-Disposition: form-data; name="content"\r\nContent-Type: text/plain; charset=utf-8\r\nContent-Length: 68\r\n\r\nAction: comment\nText: Comment with attach\nAttachment: x1.txt, x2.txt\r\n--xXXxXXyYYzzz\r\nContent-Disposition: form-data; name="attachment_2"; filename="x.txt"\r\nContent-Type: text/plain\r\nContent-Length: 4\r\n\r\nbye\n\r\n--xXXxXXyYYzzz\r\nContent-Disposition: form-data; name="attachment_1"; filename="x.txt"\r\nContent-Type: text/plain\r\nContent-Length: 4\r\n\r\nbye\n\r\n--xXXxXXyYYzzz--\r\n'
HEADERS = {'Content-Length': '495', 'Content-Type': 'multipart/form-data; boundary=xXXxXXyYYzzz', 'Accept': 'text/plain'}

@httprettified 
def test_multipart(body):
    HTTPretty.register_uri(HTTPretty.POST, URL, body=body)
    response = requests.post(URL, data=DATA, headers=HEADERS)
    expect(response.status_code).to.equal(200)

response = requests.post(URL, data=DATA, headers=HEADERS)
print response.text
test_multipart(response.text)

I guess the problem is related to the \n and \r, but they are legitimate characters in POST.

If you have any question you are welcome.

Thanks again.

[Errno 32] Broken pipe when using httplib

     Failure/Error: [Errno 32] Broken pipe

     Traceback:
     ...
     File "/usr/local/lib/python2.7/site-packages/httpretty/core.py", line 807, in wrapper
         return test(*args, **kw)
     File "src/integrationtest/python/reconciliation_spec.py", line 61, in involves_uploading_the_photo_and_marking_the_photo_as_mapped
         hidden=2)
     File "/usr/local/lib/python2.7/site-packages/flickr_api/upload.py", line 92, in upload
         r = post(UPLOAD_URL,auth.AUTH_HANDLER,args,photo_file)
     File "/usr/local/lib/python2.7/site-packages/flickr_api/upload.py", line 52, in post
         r = multipart.posturl(url,fields,files)
     File "/usr/local/lib/python2.7/site-packages/flickr_api/multipart.py", line 19, in posturl
         return post_multipart(urlparts[1], urlparts[2], fields,files)
     File "/usr/local/lib/python2.7/site-packages/flickr_api/multipart.py", line 33, in post_multipart
         h.send(body)
     File "/usr/local/Cellar/python/2.7.5/Frameworks/Python.framework/Versions/2.7/lib/python2.7/httplib.py", line 805, in send
         self.sock.sendall(data)
     File "/usr/local/lib/python2.7/site-packages/httpretty/core.py", line 243, in sendall
         return self._true_sendall(data)
     File "/usr/local/lib/python2.7/site-packages/httpretty/core.py", line 216, in _true_sendall
         self.truesock.sendall(data, *args, **kw)
     File "/usr/local/Cellar/python/2.7.5/Frameworks/Python.framework/Versions/2.7/lib/python2.7/socket.py", line 224, in meth
         return getattr(self._sock,name)(*args)

The test is actually uploading a photo file to the server in this case, so it looks like httpretty is closing the 'connection' prematurely. Give it some time for the transfer to actually complete before sending a response!

See my SO question for further details.

Mock content length

If you want to test whether a certain content length is handled properly, you would write

HTTPretty.register_uri(
            HTTPretty.GET,'http://example.com',
            content_length=MAX_CONTENT_LENGTH + 1,
            content_type='application/json')

Which leads to the following error:

HTTPrettyError: HTTPretty got inconsistent parameters. The header Content-Length you registered expects size "10485761" but the body you registered for that has actually length "12".

What is the correct way to mock the content-length?

regular expressions on POST url does not work

Hi,

I think I found a bug with regular expression in url on POST request,

When I try to refactorize my code from:

HTTPretty.register_uri(HTTPretty.POST, "http://localhost/api/testmodel/",
                       body='{"item": {"status": "OK", "etag": "sqdqsd"}}',
                       content_type="application/json")

HTTPretty.register_uri(HTTPretty.POST, "http://localhost/api/history/",
                       body='{"item": {"status": "OK", "etag": "sqdqsd"}}',
                       content_type="application/json")

to

HTTPretty.register_uri(HTTPretty.POST, re.compile("http://localhost/api/(\w+)/"),
                       body='{"item": {"status": "OK", "etag": "sqdqsd"}}',
                       content_type="application/json")

I got this error:

  File "/work/opensource/peewee-eve-sync/peewee_eve_sync/model.py", line 120, in sync_push
    etag = post_resource(history.model, history.pk, history.data, raw_history=history._data)
  File "/work/opensource/peewee-eve-sync/peewee_eve_sync/remote.py", line 77, in post_resource
    r = requests.get(call_url)
  File "/home/thomas/virtualenvs/bakthat/local/lib/python2.7/site-packages/requests/api.py", line 55, in get
    return request('get', url, **kwargs)
  File "/home/thomas/virtualenvs/bakthat/local/lib/python2.7/site-packages/requests/api.py", line 44, in request
    return session.request(method=method, url=url, **kwargs)
  File "/home/thomas/virtualenvs/bakthat/local/lib/python2.7/site-packages/requests/sessions.py", line 279, in request
    resp = self.send(prep, stream=stream, timeout=timeout, verify=verify, cert=cert, proxies=proxies)
  File "/home/thomas/virtualenvs/bakthat/local/lib/python2.7/site-packages/requests/sessions.py", line 374, in send
    r = adapter.send(request, **kwargs)
  File "/home/thomas/virtualenvs/bakthat/local/lib/python2.7/site-packages/requests/adapters.py", line 174, in send
    timeout=timeout
  File "/home/thomas/virtualenvs/bakthat/local/lib/python2.7/site-packages/requests/packages/urllib3/connectionpool.py", line 422, in urlopen
    body=body, headers=headers)
  File "/home/thomas/virtualenvs/bakthat/local/lib/python2.7/site-packages/requests/packages/urllib3/connectionpool.py", line 274, in _make_request
    conn.request(method, url, **httplib_request_kw)
  File "/usr/lib/python2.7/httplib.py", line 962, in request
    self._send_request(method, url, body, headers)
  File "/usr/lib/python2.7/httplib.py", line 996, in _send_request
    self.endheaders(body)
  File "/usr/lib/python2.7/httplib.py", line 958, in endheaders
    self._send_output(message_body)
  File "/usr/lib/python2.7/httplib.py", line 818, in _send_output
    self.send(msg)
  File "/usr/lib/python2.7/httplib.py", line 794, in send
    self.sock.sendall(data)
  File "/home/thomas/virtualenvs/bakthat/local/lib/python2.7/site-packages/httpretty/core.py", line 285, in sendall
    self._entry = matcher.get_next_entry(method)
  File "/home/thomas/virtualenvs/bakthat/local/lib/python2.7/site-packages/httpretty/core.py", line 622, in get_next_entry
    % (method, self))
ValueError: I have no entries for method GET: URLMatcher(http://localhost/api/(\w+)/)

Any thoughts ?

Thanks!!

Unicode string literals breaks HTTPretty in Python 3.2

The value of the author keyword in setup.py is a unicode string literal, which isn't supported in py3k until version 3.3. Minor issue for me since I can just use Python 3.3, but perhaps easy to fix too.

Otherwise, thanks for an awesome tool! It's a pleasure to use.

License placement?

Seems rather odd to have the license in each and every file. Most Python libs & GitHub repos just place them in a root level LICENSE and keep source clean.

Just thought I'd ask, definitely a minor thing.

Incorrect socket.socket __init__ signature

When using httpretty in a project that uses scapy I get the following:

  File "/usr/local/lib/python2.7/dist-packages/w3af-1.5-py2.7.egg/w3af/plugins/infrastructure/http_vs_https_dist.py", line 24, in <module>
    from scapy.all import traceroute
  File "/usr/lib/python2.7/dist-packages/scapy/all.py", line 16, in <module>
    from arch import *
  File "/usr/lib/python2.7/dist-packages/scapy/arch/__init__.py", line 71, in <module>
    from linux import *
  File "/usr/lib/python2.7/dist-packages/scapy/arch/linux.py", line 513, in <module>
    conf.iface = get_working_if()
  File "/usr/lib/python2.7/dist-packages/scapy/arch/linux.py", line 103, in get_working_if
    ifflags = struct.unpack("16xH14x",get_if(i,SIOCGIFFLAGS))[0]
  File "/usr/lib/python2.7/dist-packages/scapy/arch/linux.py", line 268, in get_if
    s=socket.socket()
TypeError: __init__() takes at least 3 arguments (1 given)

According to the python documentation scapy is doing something valid, since socket.socket docs say:

socket.socket([family[, type[, proto]]])
Create a new socket using the given address family, socket type and protocol number. The address family should be AF_INET (the default), AF_INET6 or AF_UNIX. The socket type should be SOCK_STREAM (the default), SOCK_DGRAM or perhaps one of the other SOCK_ constants. The protocol number is usually zero and may be omitted in that case.

Basically: All arguments are optional.

The problem seems to be here

Python 2.6 POST callbacks get called twice

It looks like POST callbacks get called twice on python 2.6. I believe this is a result of a change in httplib between 2.6 and 2.7, but have not had the time to do a bisect yet.

@httprettified
def test_py26_callback_response():
    ("HTTPretty should call a callback function *once* and set its return value"
    " as the body of the response requests")

    from mock import Mock
    def _request_callback(request, uri, headers):
        return [200, headers,"The {0} response from {1}".format(decode_utf8(request.method), uri)]

    request_callback = Mock()
    request_callback.side_effect = _request_callback

    HTTPretty.register_uri(
        HTTPretty.POST, "https://api.yahoo.com/test_post",
        body=request_callback)

    response = requests.post(
        "https://api.yahoo.com/test_post",
        {"username": "gabrielfalcao"}
    )
    expect(request_callback.call_count).equal(1)

results in

FAIL: HTTPretty should call a callback function and set its return value as the body of the response requests
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/lib/python2.6/site-packages/nose/case.py", line 197, in runTest
    self.test(*self.arg)
  File "/HTTPretty/httpretty/core.py", line 825, in wrapper
    return test(*args, **kw)
  File "HTTPretty/tests/functional/test_requests.py", line 420, in test_callback_response
    expect(request_callback.call_count).equal(1)
  File "/lib/python2.6/site-packages/sure/__init__.py", line 375, in wrapper
    value = func(self, *args, **kw)
  File "/lib/python2.6/site-packages/sure/__init__.py", line 605, in equal
    raise error
AssertionError: given
X = 2
    and
Y = 1
X is 2 whereas Y is 1

Can't use file like object for data in python3

I'm using requests and want to use httpretty for a PUT request that uses a file like object for the data arg. This works in python2, but not in python3.

The following script works in python2:

import json
from pprint import pprint

import requests

import httpretty


def test_real():
    _test()

@httpretty.activate
def test_fake():
    httpretty.register_uri(httpretty.PUT, 'http://httpbin.org/put',
                           body='["foo"]', content_type='application/json')
    _test()


def _test():
    response = requests.put('http://httpbin.org/put',
                            data=open('/tmp/somefile.txt', 'rb'))
    print(response.status_code)
    pprint(json.loads(response.content.decode('utf-8')))


print("REAL:")
test_real()
print("\nFAKE:")
test_fake()

Running this in python3 with the latest httpretty/requests I get:

Traceback (most recent call last):
  File "/tmp/repro.py", line 29, in <module>
    test_fake()
  File ".virtualenvs/30299b7f43f6b05d/lib/python3.3/site-packages/httpretty/core.py", line 807, in wrapper
    return test(*args, **kw)
  File "/tmp/repro.py", line 16, in test_fake
    _test()
  File "/tmp/repro.py", line 21, in _test
    data=open('/tmp/somefile.txt', 'rb'))
  File ".virtualenvs/30299b7f43f6b05d/lib/python3.3/site-packages/requests/api.py", line 99, in put
    return request('put', url, data=data, **kwargs)
  File ".virtualenvs/30299b7f43f6b05d/lib/python3.3/site-packages/requests/api.py", line 44, in request
    return session.request(method=method, url=url, **kwargs)
  File ".virtualenvs/30299b7f43f6b05d/lib/python3.3/site-packages/requests/sessions.py", line 335, in request
    resp = self.send(prep, **send_kwargs)
  File ".virtualenvs/30299b7f43f6b05d/lib/python3.3/site-packages/requests/sessions.py", line 438, in send
    r = adapter.send(request, **kwargs)
  File ".virtualenvs/30299b7f43f6b05d/lib/python3.3/site-packages/requests/adapters.py", line 292, in send
    timeout=timeout
  File ".virtualenvs/30299b7f43f6b05d/lib/python3.3/site-packages/requests/packages/urllib3/connectionpool.py", line 428, in urlopen
    body=body, headers=headers)
  File ".virtualenvs/30299b7f43f6b05d/lib/python3.3/site-packages/requests/packages/urllib3/connectionpool.py", line 280, in _make_request
    conn.request(method, url, **httplib_request_kw)
  File "/usr/local/Cellar/python3/3.3.1/Frameworks/Python.framework/Versions/3.3/lib/python3.3/http/client.py", line 1061, in request
    self._send_request(method, url, body, headers)
  File "/usr/local/Cellar/python3/3.3.1/Frameworks/Python.framework/Versions/3.3/lib/python3.3/http/client.py", line 1099, in _send_request
    self.endheaders(body)
  File "/usr/local/Cellar/python3/3.3.1/Frameworks/Python.framework/Versions/3.3/lib/python3.3/http/client.py", line 1057, in endheaders
    self._send_output(message_body)
  File "/usr/local/Cellar/python3/3.3.1/Frameworks/Python.framework/Versions/3.3/lib/python3.3/http/client.py", line 906, in _send_output
    self.send(message_body)
  File "/usr/local/Cellar/python3/3.3.1/Frameworks/Python.framework/Versions/3.3/lib/python3.3/http/client.py", line 871, in send
    self.sock.sendall(data)
  File ".virtualenvs/30299b7f43f6b05d/lib/python3.3/site-packages/httpretty/core.py", line 235, in sendall
    requestline, _ = data.split(b'\r\n', 1)
AttributeError: '_io.BufferedReader' object has no attribute 'split'

Connection reset by peer error on URL's with parameters

When using HTTPretty with URL with parameters, the connection will eventually die and return with an error that says:

ConnectionError: [Errno 54] Connection reset by peer

Note: this is when using the Requests library. However, if the URL does not have any parameters, then HTTPretty works fine.

# Fails
HTTPretty.register_uri(HTTPretty.GET, 'http://example.com/index.php?id=10', body='example response', status=200)
r = requests.get('http://example.com/index.php?id=10')

# Works
HTTPretty.register_uri(HTTPretty.GET, 'http://example.com/index.php', body='example response', status=200)
r = requests.get('http://example.com/index.php')

I wish I knew enough Python to offer a pull request. Anyway, it's a great library, but this one bug is preventing me from using it. Thank you!

ssl requests do not get passed through correctly

As demonstrated by the shell session below, there is a bug in how ssl is handled when passing through HTTPretty. I didn't see a note in the readme about it having this limitation.

>>> import requests
>>> from httpretty import HTTPretty
>>> url = 'https://www.cloudflare.com/ips'
>>> 
>>> response = requests.get(url)
>>> original_content = response.content
>>> 
>>> HTTPretty.reset()
>>> HTTPretty.enable()
>>> 
>>> response = requests.get(url)
>>> new_content = response.content
>>> print new_content == original_content
False
>>> 
>>> HTTPretty.disable()
>>> response = requests.get(url)
>>> newer_content = response.content
>>> print newer_content == original_content
True
>>> print new_content
<html>
<head><title>400 The plain HTTP request was sent to HTTPS port</title></head>
<body bgcolor="white">
<center><h1>400 Bad Request</h1></center>
<center>The plain HTTP request was sent to HTTPS port</center>

Headers is broken

Code to reproduce:

import httpretty
import requests

@httpretty.activate
def test_redirect_in_site():
    httpretty.register_uri(httpretty.GET, "http://target.com/",
                           body='',
                           status=302,
                           headers={'Location': 'http://target.com/a',})
    response = requests.get("http://target.com/")

    assert 'location' in response.headers

How to run the code:

andres@box:~$ nosetests -s header_test.py 
F
======================================================================
FAIL: Pass validation when redirected inside the same site and the last
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/nose/case.py", line 197, in runTest
    self.test(*self.arg)
  File "/usr/local/lib/python2.7/dist-packages/httpretty/core.py", line 799, in wrapper
    return test(*args, **kw)
  File "/home/andres/header_test.py", line 16, in test_redirect_in_site
    assert 'location' in response.headers
AssertionError: 

And if we see what's in headers:

CaseInsensitiveDict({'status': '302', 'content-length': '0', 'server': 'Python/HTTPretty',
'headers': "{'Location': 'http://target.com/a'}",
'connection': 'close', 'date': 'Thu, 13 Jun 2013 02:04:31 GMT',
'content-type': 'text/plain; charset=utf-8'})

For some reason the headers are added as a header with "header" as key and str() of whatever you send to it.

registering content-length different than the actual body should have 2 different behaviours

The first behaviour is:

import HTTPretty
HTTPretty.register_uri(HTTPretty.GET, "http://github.com/gabrielfalcao",
                       body="this is supposed to be the response",
                       adding_headers={
                           'Server': 'Apache',
                           'Content-Length': '23456789',
                           'Content-Type': 'application/json',
                       })

The expected content-length is 23456789 but the actual expected body has len 35

The DEFAULT behaviour is to raise an exception that says:

HTTPretty got inconsistent parameters. The header content-length expects size `23456789` 
but the body you registered for that has length `35`
Fix that, or if you really want that, call register_uri with "fill_with" callback. See the documentation for more.

Then the person can set the kwarg fill_with=lambda filedescriptor: "foobar", for example.
Or even use builtin callbacks such as:

import HTTPretty
HTTPretty.register_uri(HTTPretty.GET, "http://github.com/gabrielfalcao",
                       body="this is supposed to be the response",
                       fill_with=HTTPretty.zeros,
                       adding_headers={
                           'Server': 'Apache',
                           'Content-Length': '23456789',
                           'Content-Type': 'application/json',
                       })

Add proxies for body data

The Request.querystring is great for GET data, but not so good for POST - it'd be nice to at that in a 'native' form as well. This is kinda linked to #39 but more general as it applies to form-encoded data as well.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.