1
# Copyright (C) 2006-2010 Canonical Ltd
1
# Copyright (C) 2006-2010, 2012, 2013, 2016 Canonical Ltd
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
37
37
InvalidHttpResponse.
40
from cStringIO import StringIO
41
import http.client as http_client
42
except ImportError: # python < 3
43
import httplib as http_client
47
from bzrlib.transport.http import (
49
from ..sixish import (
52
from ..transport.http import (
51
from bzrlib.tests.file_utils import (
56
from .file_utils import (
57
62
"""A socket-like object that can be given a predefined content."""
59
64
def __init__(self, data):
60
self.readfile = StringIO(data)
65
self.readfile = BytesIO(data)
62
67
def makefile(self, mode='r', bufsize=None):
63
68
return self.readfile
83
class TestResponseFileIter(tests.TestCase):
85
def test_iter_empty(self):
86
f = response.ResponseFile('empty', BytesIO())
87
self.assertEqual([], list(f))
89
def test_iter_many(self):
90
f = response.ResponseFile('many', BytesIO(b'0\n1\nboo!\n'))
91
self.assertEqual(['0\n', '1\n', 'boo!\n'], list(f))
78
94
class TestHTTPConnection(tests.TestCase):
80
96
def test_cleanup_pipe(self):
92
108
# Now, get the response
93
109
resp = conn.getresponse()
94
110
# Read part of the response
95
self.assertEquals('0123456789\n', resp.read(11))
111
self.assertEqual('0123456789\n', resp.read(11))
96
112
# Override the thresold to force the warning emission
97
113
conn._range_warning_thresold = 6 # There are 7 bytes pending
98
114
conn.cleanup_pipe()
111
127
def test_can_read_at_first_access(self):
112
128
"""Test that the just created file can be read."""
113
self.assertEquals(self.alpha, self._file.read())
129
self.assertEqual(self.alpha, self._file.read())
115
131
def test_seek_read(self):
116
132
"""Test seek/read inside the range."""
118
134
start = self.first_range_start
119
135
# Before any use, tell() should be at the range start
120
self.assertEquals(start, f.tell())
136
self.assertEqual(start, f.tell())
121
137
cur = start # For an overall offset assertion
122
138
f.seek(start + 3)
124
self.assertEquals('def', f.read(3))
140
self.assertEqual('def', f.read(3))
125
141
cur += len('def')
128
self.assertEquals('klmn', f.read(4))
144
self.assertEqual('klmn', f.read(4))
129
145
cur += len('klmn')
130
146
# read(0) in the middle of a range
131
self.assertEquals('', f.read(0))
147
self.assertEqual('', f.read(0))
135
self.assertEquals(here, f.tell())
136
self.assertEquals(cur, f.tell())
151
self.assertEqual(here, f.tell())
152
self.assertEqual(cur, f.tell())
138
154
def test_read_zero(self):
140
start = self.first_range_start
141
self.assertEquals('', f.read(0))
156
self.assertEqual('', f.read(0))
143
self.assertEquals('', f.read(0))
158
self.assertEqual('', f.read(0))
145
160
def test_seek_at_range_end(self):
149
164
def test_read_at_range_end(self):
150
165
"""Test read behaviour at range end."""
152
self.assertEquals(self.alpha, f.read())
153
self.assertEquals('', f.read(0))
167
self.assertEqual(self.alpha, f.read())
168
self.assertEqual('', f.read(0))
154
169
self.assertRaises(errors.InvalidRange, f.read, 1)
156
171
def test_unbounded_read_after_seek(self):
159
174
# Should not cross ranges
160
self.assertEquals('yz', f.read())
175
self.assertEqual('yz', f.read())
162
177
def test_seek_backwards(self):
188
203
The semantic is unclear in case of multiple ranges. Seeking from end
189
204
exists only for the http transports, cannot be used if the file size is
190
unknown and is not used in bzrlib itself. This test must be (and is)
205
unknown and is not used in breezy itself. This test must be (and is)
191
206
overridden by daughter classes.
193
208
Reading from end makes sense only when a range has been requested from
200
self.assertEquals('yz', f.read())
215
self.assertEqual('yz', f.read())
203
218
class TestRangeFileSizeUnknown(tests.TestCase, TestRangeFileMixin):
207
222
super(TestRangeFileSizeUnknown, self).setUp()
208
223
self._file = response.RangeFile('Whole_file_size_known',
209
StringIO(self.alpha))
210
225
# We define no range, relying on RangeFile to provide default values
211
226
self.first_range_start = 0 # It's the whole file
220
235
def test_read_at_range_end(self):
221
236
"""Test read behaviour at range end."""
223
self.assertEquals(self.alpha, f.read())
224
self.assertEquals('', f.read(0))
225
self.assertEquals('', f.read(1))
238
self.assertEqual(self.alpha, f.read())
239
self.assertEqual('', f.read(0))
240
self.assertEqual('', f.read(1))
228
243
class TestRangeFileSizeKnown(tests.TestCase, TestRangeFileMixin):
232
247
super(TestRangeFileSizeKnown, self).setUp()
233
248
self._file = response.RangeFile('Whole_file_size_known',
234
StringIO(self.alpha))
235
250
self._file.set_range(0, len(self.alpha))
236
251
self.first_range_start = 0 # It's the whole file
243
258
super(TestRangeFileSingleRange, self).setUp()
244
259
self._file = response.RangeFile('Single_range_file',
245
StringIO(self.alpha))
246
261
self.first_range_start = 15
247
262
self._file.set_range(self.first_range_start, len(self.alpha))
338
353
def test_read_all_ranges(self):
340
self.assertEquals(self.alpha, f.read()) # Read first range
355
self.assertEqual(self.alpha, f.read()) # Read first range
341
356
f.seek(100) # Trigger the second range recognition
342
self.assertEquals(self.alpha, f.read()) # Read second range
343
self.assertEquals(126, f.tell())
357
self.assertEqual(self.alpha, f.read()) # Read second range
358
self.assertEqual(126, f.tell())
344
359
f.seek(126) # Start of third range which is also the current pos !
345
self.assertEquals('A', f.read(1))
360
self.assertEqual('A', f.read(1))
347
self.assertEquals('LMN', f.read(3))
362
self.assertEqual('LMN', f.read(3))
349
364
def test_seek_from_end(self):
350
365
"""See TestRangeFileMixin.test_seek_from_end."""
357
self.assertEquals('yz', f.read())
372
self.assertEqual('yz', f.read())
358
373
self.assertRaises(errors.InvalidRange, f.seek, -2, 2)
360
375
def test_seek_into_void(self):
372
387
def test_seek_across_ranges(self):
374
start = self.first_range_start
375
389
f.seek(126) # skip the two first ranges
376
self.assertEquals('AB', f.read(2))
390
self.assertEqual('AB', f.read(2))
378
392
def test_checked_read_dont_overflow_buffers(self):
380
start = self.first_range_start
381
394
# We force a very low value to exercise all code paths in _checked_read
382
395
f._discarded_buf_size = 8
383
396
f.seek(126) # skip the two first ranges
384
self.assertEquals('AB', f.read(2))
397
self.assertEqual('AB', f.read(2))
386
399
def test_seek_twice_between_ranges(self):
400
413
def test_read_at_range_end(self):
402
self.assertEquals(self.alpha, f.read())
403
self.assertEquals(self.alpha, f.read())
404
self.assertEquals(self.alpha.upper(), f.read())
415
self.assertEqual(self.alpha, f.read())
416
self.assertEqual(self.alpha, f.read())
417
self.assertEqual(self.alpha.upper(), f.read())
405
418
self.assertRaises(errors.InvalidHttpResponse, f.read, 1)
436
449
def test_seek_whence(self):
437
450
"""Test the seek whence parameter values."""
438
f = response.RangeFile('foo', StringIO('abc'))
451
f = response.RangeFile('foo', BytesIO(b'abc'))
439
452
f.set_range(0, 3)
445
458
def test_range_syntax(self):
446
459
"""Test the Content-Range scanning."""
448
f = response.RangeFile('foo', StringIO())
461
f = response.RangeFile('foo', BytesIO())
450
463
def ok(expected, header_value):
451
464
f.set_range_from_header(header_value)
452
465
# Slightly peek under the covers to get the size
453
self.assertEquals(expected, (f.tell(), f._size))
466
self.assertEqual(expected, (f.tell(), f._size))
455
468
ok((1, 10), 'bytes 1-10/11')
456
469
ok((1, 10), 'bytes 1-10/*')
701
714
class TestHandleResponse(tests.TestCase):
703
716
def _build_HTTPMessage(self, raw_headers):
704
status_and_headers = StringIO(raw_headers)
717
status_and_headers = BytesIO(raw_headers)
705
718
# Get rid of the status line
706
719
status_and_headers.readline()
707
msg = httplib.HTTPMessage(status_and_headers)
720
msg = http_client.HTTPMessage(status_and_headers)
710
723
def get_response(self, a_response):
712
725
code, raw_headers, body = a_response
713
726
msg = self._build_HTTPMessage(raw_headers)
714
727
return response.handle_response('http://foo', code, msg,
715
StringIO(a_response[2]))
728
BytesIO(a_response[2]))
717
730
def test_full_text(self):
718
731
out = self.get_response(_full_text_response)
719
# It is a StringIO from the original data
732
# It is a BytesIO from the original data
720
733
self.assertEqual(_full_text_response[2], out.read())
722
735
def test_single_range(self):
764
777
# We should not require Content-Type for a full response
765
778
code, raw_headers, body = _full_text_response_no_content_type
766
779
msg = self._build_HTTPMessage(raw_headers)
767
out = response.handle_response('http://foo', code, msg, StringIO(body))
780
out = response.handle_response('http://foo', code, msg, BytesIO(body))
768
781
self.assertEqual(body, out.read())
770
783
def test_full_text_no_content_length(self):
771
784
code, raw_headers, body = _full_text_response_no_content_length
772
785
msg = self._build_HTTPMessage(raw_headers)
773
out = response.handle_response('http://foo', code, msg, StringIO(body))
786
out = response.handle_response('http://foo', code, msg, BytesIO(body))
774
787
self.assertEqual(body, out.read())
776
789
def test_missing_content_range(self):
778
791
msg = self._build_HTTPMessage(raw_headers)
779
792
self.assertRaises(errors.InvalidHttpResponse,
780
793
response.handle_response,
781
'http://bogus', code, msg, StringIO(body))
794
'http://bogus', code, msg, BytesIO(body))
783
796
def test_multipart_no_content_range(self):
784
797
code, raw_headers, body = _multipart_no_content_range
785
798
msg = self._build_HTTPMessage(raw_headers)
786
799
self.assertRaises(errors.InvalidHttpResponse,
787
800
response.handle_response,
788
'http://bogus', code, msg, StringIO(body))
801
'http://bogus', code, msg, BytesIO(body))
790
803
def test_multipart_no_boundary(self):
791
804
out = self.get_response(_multipart_no_boundary)
803
tests.TestCase.setUp(self)
816
super(TestRangeFileSizeReadLimited, self).setUp()
804
817
# create a test datablock larger than _max_read_size.
805
818
chunk_size = response.RangeFile._max_read_size
806
819
test_pattern = '0123456789ABCDEF'