thirdparty/google_appengine/lib/webob/tests/test_response.txt
author Mario Ferraro <fadinlight@gmail.com>
Sun, 15 Nov 2009 22:12:20 +0100
changeset 3093 d1be59b6b627
parent 109 620f9b141567
permissions -rw-r--r--
GMaps related JS changed to use new google namespace. Google is going to change permanently in the future the way to load its services, so better stay safe. Also this commit shows uses of the new melange.js module. Fixes Issue 634.

This demonstrates how the Response object works, and tests it at the
same time.

    >>> from dtopt import ELLIPSIS
    >>> from webob import Response, UTC
    >>> from datetime import datetime
    >>> res = Response('Test', status='200 OK')

This is a minimal response object.  We can do things like get and set
the body:

    >>> res.body
    'Test'
    >>> res.body = 'Another test'
    >>> res.body
    'Another test'
    >>> res.body = 'Another'
    >>> res.write(' test')
    >>> res.app_iter
    ['Another test']
    >>> res.content_length
    12
    >>> res.headers['content-length']
    '12'
    
Content-Length is only applied when setting the body to a string; you
have to set it manually otherwise.  There are also getters and setters
for the various pieces:

    >>> res.app_iter = ['test']
    >>> print res.content_length
    None
    >>> res.content_length = 4
    >>> res.status
    '200 OK'
    >>> res.status_int
    200
    >>> res.headers
    HeaderDict([('content-type', 'text/html; charset=utf8'), ('Content-Length', '4')])
    >>> res.headerlist
    [('content-type', 'text/html; charset=utf8'), ('Content-Length', '4')]

Content-type and charset are handled separately as properties, though
they are both in the ``res.headers['content-type']`` header:

    >>> res.content_type
    'text/html'
    >>> res.content_type = 'text/html'
    >>> res.content_type
    'text/html'
    >>> res.charset
    'utf8'
    >>> res.charset = 'iso-8859-1'
    >>> res.charset
    'iso-8859-1'
    >>> res.content_type
    'text/html'
    >>> res.headers['content-type']
    'text/html; charset=iso-8859-1'

Cookie handling is done through methods:

    >>> res.set_cookie('test', 'value')
    >>> res.headers['set-cookie']
    'test=value; Path=/'
    >>> res.set_cookie('test2', 'value2', max_age=10000)
    >>> res.headers['set-cookie'] # We only see the last header
    'test2=value2; Max-Age=10000; Path=/'
    >>> res.headers.getall('set-cookie')
    ['test=value; Path=/', 'test2=value2; Max-Age=10000; Path=/']
    >>> res.unset_cookie('test')
    >>> res.headers.getall('set-cookie')
    ['test2=value2; Max-Age=10000; Path=/']

Most headers are available in a parsed getter/setter form through
properties:

    >>> res.age = 10
    >>> res.age, res.headers['age']
    (10, '10')
    >>> res.allow = ['GET', 'PUT']
    >>> res.allow, res.headers['allow']
    (['GET', 'PUT'], 'GET, PUT')
    >>> res.cache_control
    <CacheControl ''>
    >>> print res.cache_control.max_age
    None
    >>> res.cache_control.properties['max-age'] = None
    >>> print res.cache_control.max_age
    -1
    >>> res.cache_control.max_age = 10
    >>> res.cache_control
    <CacheControl 'max-age=10'>
    >>> res.headers['cache-control']
    'max-age=10'
    >>> res.cache_control.max_stale = 10
    Traceback (most recent call last):
        ...
    AttributeError: The property max-stale only applies to request Cache-Control
    >>> res.cache_control = {}
    >>> res.cache_control
    <CacheControl ''>
    >>> res.content_encoding = 'gzip'
    >>> (res.content_encoding, res.headers['content-encoding'])
    ('gzip', 'gzip')
    >>> res.content_language = 'en'
    >>> (res.content_language, res.headers['content-language'])
    (['en'], 'en')
    >>> res.content_location = 'http://localhost:8080'
    >>> res.headers['content-location']
    'http://localhost:8080'
    >>> res.content_range = (0, 100, 1000)
    >>> (res.content_range, res.headers['content-range'])
    (<ContentRange bytes 0-101/1000>, 'bytes 0-101/1000')
    >>> res.date = datetime(2005, 1, 1, 12, 0, tzinfo=UTC)
    >>> (res.date, res.headers['date'])
    (datetime.datetime(2005, 1, 1, 12, 0, tzinfo=UTC), 'Sat, 01 Jan 2005 12:00:00 GMT')
    >>> print res.etag
    None
    >>> res.etag = 'foo'
    >>> (res.etag, res.headers['etag'])
    ('foo', 'foo')
    >>> res.expires = res.date
    >>> res.retry_after = 120 # two minutes
    >>> res.retry_after
    datetime.datetime(...)
    >>> res.server = 'Python/foo'
    >>> res.headers['server']
    'Python/foo'
    >>> res.vary = ['Cookie']
    >>> (res.vary, res.headers['vary'])
    (['Cookie'], 'Cookie')

The location header will try to absolutify itself if you have a
request object attached.

    >>> res.location = '/test.html'
    >>> from webob import Request
    >>> res.request = Request.blank('/')
    >>> res.location
    'http://localhost/test.html'
    >>> res.request = None
    >>> res.location
    '/test.html'
    >>> res.request = Request.blank('/')
    >>> res.location = '/test2.html'
    >>> res.request = None
    >>> res.location
    'http://localhost/test2.html'

There's some conditional response handling too (you have to turn on
conditioanl_response)::

    >>> res = Response(conditional_response=True)
    >>> req = Request.blank('/')
    >>> res.etag = 'tag'
    >>> req.if_none_match = 'tag'
    >>> req.get_response(res)
    <Response ... 304 Not Modified>
    >>> res.etag = 'other-tag'
    >>> req.get_response(res)
    <Response ... 200 OK>
    >>> del req.if_none_match
    >>> req.if_modified_since = datetime(2005, 1, 1, 12, 1, tzinfo=UTC)
    >>> res.last_modified = datetime(2005, 1, 1, 12, 1, tzinfo=UTC)
    >>> req.get_response(res)
    <Response ... 304 Not Modified>
    >>> res.last_modified = datetime(2006, 1, 1, 12, 1, tzinfo=UTC)
    >>> req.get_response(res)
    <Response ... 200 OK>
    >>> res.last_modified = None
    >>> req.get_response(res)
    <Response ... 200 OK>

Also range response::

    >>> res = Response(conditional_response=True)
    >>> req = Request.blank('/')
    >>> res.body = '0123456789'
    >>> req.range = (1, 5)
    >>> result = req.get_response(res)
    >>> result.body
    '1234'
    >>> result.content_range
    <ContentRange bytes 1-6/10>
    >>> tuple(result.content_range)
    (1, 5, 10)
    >>> # Now an invalid range:
    >>> req.range = (0, 20)
    >>> str(req.range)
    'bytes=0-21'
    >>> result = req.get_response(res)
    >>> result.body
    '0123456789'
    >>> print result.content_range
    None

That was easier; we'll try it with a iterator for the body::

    >>> res = Response(conditional_response=True)
    >>> res.app_iter = ['01234', '567', '89']
    >>> req = Request.blank('/')
    >>> req.range = (1, 5)
    >>> result = req.get_response(res)
    >>> # Because we don't know the length of the app_iter, this
    >>> # doesn't work:
    >>> result.body
    '0123456789'
    >>> print result.content_range
    None
    >>> req.range = (5, None)
    >>> result = req.get_response(res)
    >>> result.body
    '56789'
    >>> result.content_range
    <ContentRange bytes 5-*/10>
    >>> # If we set Content-Length then we can use it with an app_iter
    >>> res.content_length = 10
    >>> req.range = (1, 5)
    >>> result = req.get_response(res)
    >>> result.body
    '1234'
    >>> result.content_range
    <ContentRange bytes 1-6/10>
    >>> # And trying If-modified-since
    >>> res.etag = 'foobar'
    >>> req.if_range = 'foobar'
    >>> req.if_range
    <IfRange etag=foobar, date=*>
    >>> result = req.get_response(res)
    >>> result.content_range
    <ContentRange bytes 1-6/10>
    >>> req.if_range = 'blah'
    >>> result = req.get_response(res)
    >>> result.content_range
    >>> req.if_range = datetime(2005, 1, 1, 12, 0, tzinfo=UTC)
    >>> res.last_modified = datetime(2005, 1, 1, 12, 0, tzinfo=UTC)
    >>> result = req.get_response(res)
    >>> result.content_range
    <ContentRange bytes 1-6/10>
    >>> res.last_modified = datetime(2006, 1, 1, 12, 0, tzinfo=UTC)
    >>> result = req.get_response(res)
    >>> result.content_range

Some tests of exceptions::

    >>> from webob import exc
    >>> res = exc.HTTPNotFound('Not found!')
    >>> res.exception.content_type = 'text/plain'
    >>> res.content_type
    'text/plain'
    >>> res = exc.HTTPNotModified()
    >>> res.headers
    HeaderDict([])