Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Faster headers implementation #544

Merged
merged 30 commits into from
Feb 19, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
78d5eca
Faster headers implementation
Feb 4, 2015
d0c884c
Full test coverage for _collection
Feb 5, 2015
65376ed
Python3 fixes
Feb 5, 2015
9406a8a
Fix coverage for py3
Feb 5, 2015
caf73bd
Ready made header objects not copied within response
Feb 5, 2015
ed4c805
Alternative implementation of headers
Feb 6, 2015
5fbedcc
self.items() with preserved headers
Feb 6, 2015
c8c9b9e
Testcase for full coverage added
Feb 6, 2015
223f7b9
Fixed non-equal comparison; rename update_add to extend
Feb 7, 2015
fc5cb83
from_httplib removed; extend used by default in constructor
Feb 8, 2015
f867e96
Checking header name before creating multiheader
Feb 8, 2015
d9640af
Faster headers implementation
Feb 4, 2015
b493eeb
Full test coverage for _collection
Feb 5, 2015
328d129
Python3 fixes
Feb 5, 2015
ab94c82
Fix coverage for py3
Feb 5, 2015
1262d12
Ready made header objects not copied within response
Feb 5, 2015
5e73e72
Alternative implementation of headers
Feb 6, 2015
66a5141
self.items() with preserved headers
Feb 6, 2015
c72e428
Testcase for full coverage added
Feb 6, 2015
dc946a0
Fixed non-equal comparison; rename update_add to extend
Feb 7, 2015
49c4727
from_httplib removed; extend used by default in constructor
Feb 8, 2015
7115efd
Checking header name before creating multiheader
Feb 8, 2015
f82bb6f
Merge branch 'header_rework' of github.com:ml31415/urllib3 into heade…
Feb 11, 2015
cb6372f
.pop() fixed; py2 header parsing fixed
Feb 12, 2015
8e43f8e
.items() returns now list including duplicates identical to PY3 behav…
Feb 12, 2015
a5e6206
Fixing py2.6; renaming of import
Feb 12, 2015
fc8627b
Forgot one line, grmbl
Feb 12, 2015
a54ac68
Further python2.6 unittest gotcha fixed
Feb 12, 2015
971f590
One more ...
Feb 12, 2015
c1bb27c
Merge branch 'master' into header_rework
Feb 18, 2015
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
146 changes: 120 additions & 26 deletions test/test_collections.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from urllib3.packages import six
xrange = six.moves.xrange

from nose.plugins.skip import SkipTest

class TestLRUContainer(unittest.TestCase):
def test_maxsize(self):
Expand Down Expand Up @@ -125,62 +126,155 @@ def test_iter(self):
self.assertRaises(NotImplementedError, d.__iter__)


class NonMappingHeaderContainer(object):
def __init__(self, **kwargs):
self._data = {}
self._data.update(kwargs)

def keys(self):
return self._data.keys()

def __getitem__(self, key):
return self._data[key]


class TestHTTPHeaderDict(unittest.TestCase):
def setUp(self):
self.d = HTTPHeaderDict(A='foo')
self.d.add('a', 'bar')
self.d = HTTPHeaderDict(Cookie='foo')
self.d.add('cookie', 'bar')

def test_overwriting_with_setitem_replaces(self):
d = HTTPHeaderDict()

d['A'] = 'foo'
self.assertEqual(d['a'], 'foo')
d['Cookie'] = 'foo'
self.assertEqual(d['cookie'], 'foo')

d['a'] = 'bar'
self.assertEqual(d['A'], 'bar')
d['cookie'] = 'bar'
self.assertEqual(d['Cookie'], 'bar')

def test_copy(self):
h = self.d.copy()
self.assertTrue(self.d is not h)
self.assertEqual(self.d, h)

def test_add(self):
def test_add_multiple_allowed(self):
d = HTTPHeaderDict()

d['A'] = 'foo'
d.add('a', 'bar')

self.assertEqual(d['a'], 'foo, bar')
self.assertEqual(d['A'], 'foo, bar')
d['Cookie'] = 'foo'
d.add('cookie', 'bar')

self.assertEqual(d['cookie'], 'foo, bar')
self.assertEqual(d['Cookie'], 'foo, bar')

d.add('cookie', 'asdf')
self.assertEqual(d['cookie'], 'foo, bar, asdf')

def test_add_multiple_not_allowed(self):
self.d.add('notmulti', 'should be overwritten on next add call')
self.d.add('notmulti', 'new val')
self.assertEqual(self.d['notmulti'], 'new val')

def test_extend(self):
self.d.extend([('set-cookie', '100'), ('set-cookie', '200'), ('set-cookie', '300')])
self.assertEqual(self.d['set-cookie'], '100, 200, 300')

self.d.extend(dict(cookie='asdf'), b='100')
self.assertEqual(self.d['cookie'], 'foo, bar, asdf')
self.assertEqual(self.d['b'], '100')
self.d.add('cookie', 'with, comma')
self.assertEqual(self.d.getlist('cookie'), ['foo', 'bar', 'asdf', 'with, comma'])

header_object = NonMappingHeaderContainer(e='foofoo')
self.d.extend(header_object)
self.assertEqual(self.d['e'], 'foofoo')

def test_getlist(self):
self.assertEqual(self.d.getlist('a'), ['foo', 'bar'])
self.assertEqual(self.d.getlist('A'), ['foo', 'bar'])
self.assertEqual(self.d.getlist('cookie'), ['foo', 'bar'])
self.assertEqual(self.d.getlist('Cookie'), ['foo', 'bar'])
self.assertEqual(self.d.getlist('b'), [])
self.d.add('b', 'asdf')
self.assertEqual(self.d.getlist('b'), ['asdf'])

def test_update(self):
d = HTTPHeaderDict()
d.update(self.d)
d.add('a', 'with, comma')
self.assertEqual(d.getlist('a'), ['foo', 'bar', 'with, comma'])
self.d.update(dict(cookie='with, comma'))
self.assertEqual(self.d.getlist('cookie'), ['with, comma'])

def test_delitem(self):
del self.d['a']
self.assertFalse('a' in self.d)
self.assertFalse('A' in self.d)
del self.d['cookie']
self.assertFalse('cookie' in self.d)
self.assertFalse('COOKIE' in self.d)

def test_equal(self):
b = HTTPHeaderDict({'a': 'foo, bar'})
b = HTTPHeaderDict(cookie='foo, bar')
c = NonMappingHeaderContainer(cookie='foo, bar')
self.assertEqual(self.d, b)
c = [('a', 'foo, bar')]
self.assertNotEqual(self.d, c)
self.assertEqual(self.d, c)
self.assertNotEqual(self.d, 2)

def test_not_equal(self):
b = HTTPHeaderDict(cookie='foo, bar')
c = NonMappingHeaderContainer(cookie='foo, bar')
self.assertFalse(self.d != b)
self.assertFalse(self.d != c)
self.assertNotEqual(self.d, 2)

def test_pop(self):
key = 'Cookie'
a = self.d[key]
b = self.d.pop(key)
self.assertEqual(a, b)
self.assertFalse(key in self.d)
self.assertRaises(KeyError, self.d.pop, key)
dummy = object()
self.assertTrue(dummy is self.d.pop(key, dummy))

def test_discard(self):
self.d.discard('cookie')
self.assertFalse('cookie' in self.d)
self.d.discard('cookie')

def test_len(self):
self.assertEqual(len(self.d), 1)

def test_repr(self):
rep = "HTTPHeaderDict({'A': 'foo, bar'})"
rep = "HTTPHeaderDict({'Cookie': 'foo, bar'})"
self.assertEqual(repr(self.d), rep)

def test_items(self):
items = self.d.items()
self.assertEqual(len(items), 2)
self.assertEqual(items[0][0], 'Cookie')
self.assertEqual(items[0][1], 'foo')
self.assertEqual(items[1][0], 'Cookie')
self.assertEqual(items[1][1], 'bar')

def test_items_preserving_case(self):
# Should not be tested only in connectionpool
HEADERS = {'Content-Length': '0', 'Content-type': 'text/plain',
'Server': 'TornadoServer/1.2.3'}
h = dict(HTTPHeaderDict(HEADERS).items())
self.assertEqual(HEADERS, h) # to preserve case sensitivity

def test_from_httplib(self):
if six.PY3:
raise SkipTest()
from httplib import HTTPMessage
from StringIO import StringIO

msg = """
Server: nginx
Content-Type: text/html; charset=windows-1251
Connection: keep-alive
Set-Cookie: bb_lastvisit=1348253375; expires=Sat, 21-Sep-2013 18:49:35 GMT; path=/
Set-Cookie: bb_lastactivity=0; expires=Sat, 21-Sep-2013 18:49:35 GMT; path=/

"""
msg = HTTPMessage(StringIO(msg.lstrip().replace('\n', '\r\n')))
d = HTTPHeaderDict.from_httplib(msg)
self.assertEqual(d['server'], 'nginx')
cookies = d.getlist('set-cookie')
self.assertEqual(len(cookies), 2)
self.assertTrue(cookies[0].startswith("bb_lastvisit"))
self.assertTrue(cookies[1].startswith("bb_lastactivity"))

if __name__ == '__main__':
unittest.main()
Loading