Refactor SLO If-Match / HEAD tests
Previously, we didn't make any assertions about the backend requests but rather just verified the user-visible behavior. Change-Id: Iddd4b705ee9b724a4a8a88c6fbaff36cca9612cf
This commit is contained in:
parent
27ca0fb2a8
commit
30f672e720
@ -21,7 +21,6 @@ import json
|
|||||||
import time
|
import time
|
||||||
import unittest
|
import unittest
|
||||||
from mock import patch
|
from mock import patch
|
||||||
from hashlib import md5
|
|
||||||
from StringIO import StringIO
|
from StringIO import StringIO
|
||||||
from swift.common import swob, utils
|
from swift.common import swob, utils
|
||||||
from swift.common.exceptions import ListingIterError, SegmentError
|
from swift.common.exceptions import ListingIterError, SegmentError
|
||||||
@ -415,14 +414,20 @@ class TestSloPutManifest(SloTestCase):
|
|||||||
'/v1/AUTH_test/c/man?multipart-manifest=put',
|
'/v1/AUTH_test/c/man?multipart-manifest=put',
|
||||||
environ={'REQUEST_METHOD': 'PUT'}, headers={'Accept': 'test'},
|
environ={'REQUEST_METHOD': 'PUT'}, headers={'Accept': 'test'},
|
||||||
body=test_json_data)
|
body=test_json_data)
|
||||||
self.assertTrue('X-Static-Large-Object' not in req.headers)
|
self.assertNotIn('X-Static-Large-Object', req.headers)
|
||||||
|
|
||||||
def my_fake_start_response(*args, **kwargs):
|
def my_fake_start_response(*args, **kwargs):
|
||||||
gen_etag = '"' + md5('etagoftheobjectsegment').hexdigest() + '"'
|
gen_etag = '"' + md5hex('etagoftheobjectsegment') + '"'
|
||||||
self.assertTrue(('Etag', gen_etag) in args[1])
|
self.assertTrue(('Etag', gen_etag) in args[1])
|
||||||
|
|
||||||
self.slo(req.environ, my_fake_start_response)
|
self.slo(req.environ, my_fake_start_response)
|
||||||
self.assertTrue('X-Static-Large-Object' in req.headers)
|
self.assertIn('X-Static-Large-Object', req.headers)
|
||||||
|
self.assertEqual(req.headers['X-Static-Large-Object'], 'True')
|
||||||
|
self.assertIn('Content-Type', req.headers)
|
||||||
|
self.assertTrue(
|
||||||
|
req.headers['Content-Type'].endswith(';swift_bytes=100'),
|
||||||
|
'Content-Type %r does not end with swift_bytes=100' %
|
||||||
|
req.headers['Content-Type'])
|
||||||
|
|
||||||
def test_handle_multipart_put_disallow_empty_first_segment(self):
|
def test_handle_multipart_put_disallow_empty_first_segment(self):
|
||||||
test_json_data = json.dumps([{'path': '/cont/object',
|
test_json_data = json.dumps([{'path': '/cont/object',
|
||||||
@ -676,8 +681,8 @@ class TestSloPutManifest(SloTestCase):
|
|||||||
'/v1/AUTH_test/checktest/man_3?multipart-manifest=put',
|
'/v1/AUTH_test/checktest/man_3?multipart-manifest=put',
|
||||||
environ={'REQUEST_METHOD': 'PUT'}, body=good_data)
|
environ={'REQUEST_METHOD': 'PUT'}, body=good_data)
|
||||||
status, headers, body = self.call_slo(req)
|
status, headers, body = self.call_slo(req)
|
||||||
expected_etag = '"%s"' % md5('ab:1-1;b:0-0;etagoftheobjectsegment:'
|
expected_etag = '"%s"' % md5hex('ab:1-1;b:0-0;etagoftheobjectsegment:'
|
||||||
'10-40;').hexdigest()
|
'10-40;')
|
||||||
self.assertEqual(expected_etag, dict(headers)['Etag'])
|
self.assertEqual(expected_etag, dict(headers)['Etag'])
|
||||||
self.assertEqual([
|
self.assertEqual([
|
||||||
('HEAD', '/v1/AUTH_test/checktest/a_1'),
|
('HEAD', '/v1/AUTH_test/checktest/a_1'),
|
||||||
@ -1070,10 +1075,11 @@ class TestSloDeleteManifest(SloTestCase):
|
|||||||
|
|
||||||
|
|
||||||
class TestSloHeadManifest(SloTestCase):
|
class TestSloHeadManifest(SloTestCase):
|
||||||
|
slo_etag = md5hex("seg01-hashseg02-hash")
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestSloHeadManifest, self).setUp()
|
super(TestSloHeadManifest, self).setUp()
|
||||||
|
manifest_json = json.dumps([
|
||||||
self._manifest_json = json.dumps([
|
|
||||||
{'name': '/gettest/seg01',
|
{'name': '/gettest/seg01',
|
||||||
'bytes': '100',
|
'bytes': '100',
|
||||||
'hash': 'seg01-hash',
|
'hash': 'seg01-hash',
|
||||||
@ -1084,34 +1090,64 @@ class TestSloHeadManifest(SloTestCase):
|
|||||||
'hash': 'seg02-hash',
|
'hash': 'seg02-hash',
|
||||||
'content_type': 'text/plain',
|
'content_type': 'text/plain',
|
||||||
'last_modified': '2013-11-19T11:33:45.137447'}])
|
'last_modified': '2013-11-19T11:33:45.137447'}])
|
||||||
|
manifest_headers = {
|
||||||
|
'Content-Length': str(len(manifest_json)),
|
||||||
|
'Content-Type': 'test/data',
|
||||||
|
'X-Static-Large-Object': 'true',
|
||||||
|
'Etag': md5hex(manifest_json)}
|
||||||
|
manifest_headers.update(getattr(self, 'extra_manifest_headers', {}))
|
||||||
self.app.register(
|
self.app.register(
|
||||||
'GET', '/v1/AUTH_test/headtest/man',
|
'GET', '/v1/AUTH_test/headtest/man',
|
||||||
swob.HTTPOk, {'Content-Length': str(len(self._manifest_json)),
|
swob.HTTPOk, manifest_headers, manifest_json)
|
||||||
'X-Static-Large-Object': 'true',
|
|
||||||
'Etag': md5(self._manifest_json).hexdigest()},
|
|
||||||
self._manifest_json)
|
|
||||||
|
|
||||||
def test_etag_is_hash_of_segment_etags(self):
|
def test_etag_is_hash_of_segment_etags(self):
|
||||||
req = Request.blank(
|
req = Request.blank(
|
||||||
'/v1/AUTH_test/headtest/man',
|
'/v1/AUTH_test/headtest/man',
|
||||||
environ={'REQUEST_METHOD': 'HEAD'})
|
environ={'REQUEST_METHOD': 'HEAD'})
|
||||||
status, headers, body = self.call_slo(req)
|
status, headers, body = self.call_slo(req)
|
||||||
headers = HeaderKeyDict(headers)
|
|
||||||
|
|
||||||
self.assertEqual(status, '200 OK')
|
self.assertEqual(status, '200 OK')
|
||||||
self.assertEqual(headers.get('Etag', '').strip("'\""),
|
self.assertIn(('Etag', '"%s"' % self.slo_etag), headers)
|
||||||
md5("seg01-hashseg02-hash").hexdigest())
|
self.assertIn(('Content-Length', '300'), headers)
|
||||||
|
self.assertIn(('Content-Type', 'test/data'), headers)
|
||||||
self.assertEqual(body, '') # it's a HEAD request, after all
|
self.assertEqual(body, '') # it's a HEAD request, after all
|
||||||
|
|
||||||
def test_etag_matching(self):
|
expected_app_calls = [
|
||||||
etag = md5("seg01-hashseg02-hash").hexdigest()
|
('HEAD', '/v1/AUTH_test/headtest/man'),
|
||||||
|
('GET', '/v1/AUTH_test/headtest/man')]
|
||||||
|
self.assertEqual(self.app.calls, expected_app_calls)
|
||||||
|
|
||||||
|
def test_if_none_match_etag_matching(self):
|
||||||
req = Request.blank(
|
req = Request.blank(
|
||||||
'/v1/AUTH_test/headtest/man',
|
'/v1/AUTH_test/headtest/man',
|
||||||
environ={'REQUEST_METHOD': 'HEAD'},
|
environ={'REQUEST_METHOD': 'HEAD'},
|
||||||
headers={'If-None-Match': etag})
|
headers={'If-None-Match': self.slo_etag})
|
||||||
status, headers, body = self.call_slo(req)
|
status, headers, body = self.call_slo(req)
|
||||||
self.assertEqual(status, '304 Not Modified')
|
self.assertEqual(status, '304 Not Modified')
|
||||||
|
self.assertIn(('Etag', '"%s"' % self.slo_etag), headers)
|
||||||
|
self.assertIn(('Content-Length', '0'), headers)
|
||||||
|
self.assertIn(('Content-Type', 'test/data'), headers)
|
||||||
|
|
||||||
|
expected_app_calls = [
|
||||||
|
('HEAD', '/v1/AUTH_test/headtest/man'),
|
||||||
|
('GET', '/v1/AUTH_test/headtest/man')]
|
||||||
|
self.assertEqual(self.app.calls, expected_app_calls)
|
||||||
|
|
||||||
|
def test_if_match_etag_not_matching(self):
|
||||||
|
req = Request.blank(
|
||||||
|
'/v1/AUTH_test/headtest/man',
|
||||||
|
environ={'REQUEST_METHOD': 'HEAD'},
|
||||||
|
headers={'If-Match': 'zzz'})
|
||||||
|
status, headers, body = self.call_slo(req)
|
||||||
|
self.assertEqual(status, '412 Precondition Failed')
|
||||||
|
self.assertIn(('Etag', '"%s"' % self.slo_etag), headers)
|
||||||
|
self.assertIn(('Content-Length', '0'), headers)
|
||||||
|
self.assertIn(('Content-Type', 'test/data'), headers)
|
||||||
|
|
||||||
|
expected_app_calls = [
|
||||||
|
('HEAD', '/v1/AUTH_test/headtest/man'),
|
||||||
|
('GET', '/v1/AUTH_test/headtest/man')]
|
||||||
|
self.assertEqual(self.app.calls, expected_app_calls)
|
||||||
|
|
||||||
|
|
||||||
class TestSloGetRawManifest(SloTestCase):
|
class TestSloGetRawManifest(SloTestCase):
|
||||||
@ -1303,7 +1339,7 @@ class TestSloGetManifest(SloTestCase):
|
|||||||
'GET', '/v1/AUTH_test/gettest/manifest-abcd',
|
'GET', '/v1/AUTH_test/gettest/manifest-abcd',
|
||||||
swob.HTTPOk, {'Content-Type': 'application/json',
|
swob.HTTPOk, {'Content-Type': 'application/json',
|
||||||
'X-Static-Large-Object': 'true',
|
'X-Static-Large-Object': 'true',
|
||||||
'Etag': md5(_abcd_manifest_json).hexdigest()},
|
'Etag': md5hex(_abcd_manifest_json)},
|
||||||
_abcd_manifest_json)
|
_abcd_manifest_json)
|
||||||
|
|
||||||
# A submanifest segment is created using the response headers from a
|
# A submanifest segment is created using the response headers from a
|
||||||
@ -1331,7 +1367,7 @@ class TestSloGetManifest(SloTestCase):
|
|||||||
'GET', '/v1/AUTH_test/gettest/manifest-abcd-alt',
|
'GET', '/v1/AUTH_test/gettest/manifest-abcd-alt',
|
||||||
swob.HTTPOk, {'Content-Type': 'application/json',
|
swob.HTTPOk, {'Content-Type': 'application/json',
|
||||||
'X-Static-Large-Object': 'true',
|
'X-Static-Large-Object': 'true',
|
||||||
'Etag': md5(_abcd_manifest_json_alt).hexdigest()},
|
'Etag': md5hex(_abcd_manifest_json_alt)},
|
||||||
_abcd_manifest_json_alt)
|
_abcd_manifest_json_alt)
|
||||||
|
|
||||||
_abcdefghijkl_manifest_json = json.dumps(
|
_abcdefghijkl_manifest_json = json.dumps(
|
||||||
@ -1364,7 +1400,7 @@ class TestSloGetManifest(SloTestCase):
|
|||||||
swob.HTTPOk, {
|
swob.HTTPOk, {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'X-Static-Large-Object': 'true',
|
'X-Static-Large-Object': 'true',
|
||||||
'Etag': md5(_abcdefghijkl_manifest_json).hexdigest()},
|
'Etag': md5hex(_abcdefghijkl_manifest_json)},
|
||||||
_abcdefghijkl_manifest_json)
|
_abcdefghijkl_manifest_json)
|
||||||
|
|
||||||
self.manifest_abcd_etag = md5hex(
|
self.manifest_abcd_etag = md5hex(
|
||||||
@ -1543,7 +1579,7 @@ class TestSloGetManifest(SloTestCase):
|
|||||||
'GET', '/v1/AUTH_test/gettest/manifest-aabbccdd',
|
'GET', '/v1/AUTH_test/gettest/manifest-aabbccdd',
|
||||||
swob.HTTPOk, {'Content-Type': 'application/json',
|
swob.HTTPOk, {'Content-Type': 'application/json',
|
||||||
'X-Static-Large-Object': 'true',
|
'X-Static-Large-Object': 'true',
|
||||||
'Etag': md5(_aabbccdd_manifest_json).hexdigest()},
|
'Etag': md5hex(_aabbccdd_manifest_json)},
|
||||||
_aabbccdd_manifest_json)
|
_aabbccdd_manifest_json)
|
||||||
|
|
||||||
req = Request.blank(
|
req = Request.blank(
|
||||||
@ -1631,67 +1667,6 @@ class TestSloGetManifest(SloTestCase):
|
|||||||
self.assertEqual(status, '200 OK') # sanity check
|
self.assertEqual(status, '200 OK') # sanity check
|
||||||
self.assertEqual(sleeps, [2.0, 2.0, 2.0])
|
self.assertEqual(sleeps, [2.0, 2.0, 2.0])
|
||||||
|
|
||||||
def test_if_none_match_matches(self):
|
|
||||||
req = Request.blank(
|
|
||||||
'/v1/AUTH_test/gettest/manifest-abcd',
|
|
||||||
environ={'REQUEST_METHOD': 'GET'},
|
|
||||||
headers={'If-None-Match': self.manifest_abcd_etag})
|
|
||||||
status, headers, body = self.call_slo(req)
|
|
||||||
headers = HeaderKeyDict(headers)
|
|
||||||
|
|
||||||
self.assertEqual(status, '304 Not Modified')
|
|
||||||
self.assertEqual(headers['Content-Length'], '0')
|
|
||||||
self.assertEqual(body, '')
|
|
||||||
|
|
||||||
def test_if_none_match_does_not_match(self):
|
|
||||||
req = Request.blank(
|
|
||||||
'/v1/AUTH_test/gettest/manifest-abcd',
|
|
||||||
environ={'REQUEST_METHOD': 'GET'},
|
|
||||||
headers={'If-None-Match': "not-%s" % self.manifest_abcd_etag})
|
|
||||||
status, headers, body = self.call_slo(req)
|
|
||||||
headers = HeaderKeyDict(headers)
|
|
||||||
|
|
||||||
self.assertEqual(status, '200 OK')
|
|
||||||
self.assertEqual(
|
|
||||||
body, 'aaaaabbbbbbbbbbcccccccccccccccdddddddddddddddddddd')
|
|
||||||
|
|
||||||
def test_if_match_matches(self):
|
|
||||||
req = Request.blank(
|
|
||||||
'/v1/AUTH_test/gettest/manifest-abcd',
|
|
||||||
environ={'REQUEST_METHOD': 'GET'},
|
|
||||||
headers={'If-Match': self.manifest_abcd_etag})
|
|
||||||
status, headers, body = self.call_slo(req)
|
|
||||||
headers = HeaderKeyDict(headers)
|
|
||||||
|
|
||||||
self.assertEqual(status, '200 OK')
|
|
||||||
self.assertEqual(
|
|
||||||
body, 'aaaaabbbbbbbbbbcccccccccccccccdddddddddddddddddddd')
|
|
||||||
|
|
||||||
def test_if_match_does_not_match(self):
|
|
||||||
req = Request.blank(
|
|
||||||
'/v1/AUTH_test/gettest/manifest-abcd',
|
|
||||||
environ={'REQUEST_METHOD': 'GET'},
|
|
||||||
headers={'If-Match': "not-%s" % self.manifest_abcd_etag})
|
|
||||||
status, headers, body = self.call_slo(req)
|
|
||||||
headers = HeaderKeyDict(headers)
|
|
||||||
|
|
||||||
self.assertEqual(status, '412 Precondition Failed')
|
|
||||||
self.assertEqual(headers['Content-Length'], '0')
|
|
||||||
self.assertEqual(body, '')
|
|
||||||
|
|
||||||
def test_if_match_matches_and_range(self):
|
|
||||||
req = Request.blank(
|
|
||||||
'/v1/AUTH_test/gettest/manifest-abcd',
|
|
||||||
environ={'REQUEST_METHOD': 'GET'},
|
|
||||||
headers={'If-Match': self.manifest_abcd_etag,
|
|
||||||
'Range': 'bytes=3-6'})
|
|
||||||
status, headers, body = self.call_slo(req)
|
|
||||||
headers = HeaderKeyDict(headers)
|
|
||||||
|
|
||||||
self.assertEqual(status, '206 Partial Content')
|
|
||||||
self.assertEqual(headers['Content-Length'], '4')
|
|
||||||
self.assertEqual(body, 'aabb')
|
|
||||||
|
|
||||||
def test_get_manifest_with_submanifest(self):
|
def test_get_manifest_with_submanifest(self):
|
||||||
req = Request.blank(
|
req = Request.blank(
|
||||||
'/v1/AUTH_test/gettest/manifest-abcd',
|
'/v1/AUTH_test/gettest/manifest-abcd',
|
||||||
@ -1905,7 +1880,7 @@ class TestSloGetManifest(SloTestCase):
|
|||||||
'GET', '/v1/AUTH_test/gettest/big_manifest',
|
'GET', '/v1/AUTH_test/gettest/big_manifest',
|
||||||
swob.HTTPOk, {'Content-Type': 'application/octet-stream',
|
swob.HTTPOk, {'Content-Type': 'application/octet-stream',
|
||||||
'X-Static-Large-Object': 'true',
|
'X-Static-Large-Object': 'true',
|
||||||
'Etag': md5(big_manifest).hexdigest()},
|
'Etag': md5hex(big_manifest)},
|
||||||
big_manifest)
|
big_manifest)
|
||||||
|
|
||||||
req = Request.blank(
|
req = Request.blank(
|
||||||
@ -2780,6 +2755,184 @@ class TestSloGetManifest(SloTestCase):
|
|||||||
'ERROR: An error occurred while retrieving segments'))
|
'ERROR: An error occurred while retrieving segments'))
|
||||||
|
|
||||||
|
|
||||||
|
class TestSloConditionalGetManifest(SloTestCase):
|
||||||
|
slo_data = [
|
||||||
|
{'name': '/gettest/a_5', 'hash': md5hex("a" * 5),
|
||||||
|
'content_type': 'text/plain', 'bytes': '5'},
|
||||||
|
{'name': '/gettest/manifest-bc', 'sub_slo': True,
|
||||||
|
'content_type': 'application/json',
|
||||||
|
'hash': md5hex(md5hex("b" * 10) + md5hex("c" * 15)),
|
||||||
|
'bytes': 25},
|
||||||
|
{'name': '/gettest/d_20', 'hash': md5hex("d" * 20),
|
||||||
|
'content_type': 'text/plain', 'bytes': '20'}]
|
||||||
|
slo_etag = md5hex(''.join(seg['hash'] for seg in slo_data))
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestSloConditionalGetManifest, self).setUp()
|
||||||
|
|
||||||
|
# some plain old objects
|
||||||
|
self.app.register(
|
||||||
|
'GET', '/v1/AUTH_test/gettest/a_5',
|
||||||
|
swob.HTTPOk, {'Content-Length': '5',
|
||||||
|
'Etag': md5hex('a' * 5)},
|
||||||
|
'a' * 5)
|
||||||
|
self.app.register(
|
||||||
|
'GET', '/v1/AUTH_test/gettest/b_10',
|
||||||
|
swob.HTTPOk, {'Content-Length': '10',
|
||||||
|
'Etag': md5hex('b' * 10)},
|
||||||
|
'b' * 10)
|
||||||
|
self.app.register(
|
||||||
|
'GET', '/v1/AUTH_test/gettest/c_15',
|
||||||
|
swob.HTTPOk, {'Content-Length': '15',
|
||||||
|
'Etag': md5hex('c' * 15)},
|
||||||
|
'c' * 15)
|
||||||
|
self.app.register(
|
||||||
|
'GET', '/v1/AUTH_test/gettest/d_20',
|
||||||
|
swob.HTTPOk, {'Content-Length': '20',
|
||||||
|
'Etag': md5hex('d' * 20)},
|
||||||
|
'd' * 20)
|
||||||
|
|
||||||
|
_bc_manifest_json = json.dumps(
|
||||||
|
[{'name': '/gettest/b_10', 'hash': md5hex('b' * 10), 'bytes': '10',
|
||||||
|
'content_type': 'text/plain'},
|
||||||
|
{'name': '/gettest/c_15', 'hash': md5hex('c' * 15), 'bytes': '15',
|
||||||
|
'content_type': 'text/plain'}])
|
||||||
|
self.app.register(
|
||||||
|
'GET', '/v1/AUTH_test/gettest/manifest-bc',
|
||||||
|
swob.HTTPOk, {'Content-Type': 'application/json',
|
||||||
|
'X-Static-Large-Object': 'true',
|
||||||
|
'X-Object-Meta-Plant': 'Ficus',
|
||||||
|
'Etag': md5hex(_bc_manifest_json)},
|
||||||
|
_bc_manifest_json)
|
||||||
|
|
||||||
|
_abcd_manifest_json = json.dumps(self.slo_data)
|
||||||
|
manifest_headers = {
|
||||||
|
'Content-Length': str(len(_abcd_manifest_json)),
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-Static-Large-Object': 'true',
|
||||||
|
'Etag': md5hex(_abcd_manifest_json)}
|
||||||
|
manifest_headers.update(getattr(self, 'extra_manifest_headers', {}))
|
||||||
|
self.app.register(
|
||||||
|
'GET', '/v1/AUTH_test/gettest/manifest-abcd',
|
||||||
|
swob.HTTPOk, manifest_headers,
|
||||||
|
_abcd_manifest_json)
|
||||||
|
|
||||||
|
def test_if_none_match_matches(self):
|
||||||
|
req = Request.blank(
|
||||||
|
'/v1/AUTH_test/gettest/manifest-abcd',
|
||||||
|
environ={'REQUEST_METHOD': 'GET'},
|
||||||
|
headers={'If-None-Match': self.slo_etag})
|
||||||
|
status, headers, body = self.call_slo(req)
|
||||||
|
|
||||||
|
self.assertEqual(status, '304 Not Modified')
|
||||||
|
self.assertIn(('Content-Length', '0'), headers)
|
||||||
|
self.assertIn(('Etag', '"%s"' % self.slo_etag), headers)
|
||||||
|
self.assertEqual(body, '')
|
||||||
|
|
||||||
|
expected_app_calls = [
|
||||||
|
('GET', '/v1/AUTH_test/gettest/manifest-abcd'),
|
||||||
|
# Need to verify the first segment
|
||||||
|
('GET', '/v1/AUTH_test/gettest/manifest-bc'),
|
||||||
|
('GET', '/v1/AUTH_test/gettest/a_5?multipart-manifest=get'),
|
||||||
|
]
|
||||||
|
self.assertEqual(self.app.calls, expected_app_calls)
|
||||||
|
|
||||||
|
def test_if_none_match_does_not_match(self):
|
||||||
|
req = Request.blank(
|
||||||
|
'/v1/AUTH_test/gettest/manifest-abcd',
|
||||||
|
environ={'REQUEST_METHOD': 'GET'},
|
||||||
|
headers={'If-None-Match': "not-%s" % self.slo_etag})
|
||||||
|
status, headers, body = self.call_slo(req)
|
||||||
|
|
||||||
|
self.assertEqual(status, '200 OK')
|
||||||
|
self.assertIn(('Content-Length', '50'), headers)
|
||||||
|
self.assertIn(('Etag', '"%s"' % self.slo_etag), headers)
|
||||||
|
self.assertEqual(
|
||||||
|
body, 'aaaaabbbbbbbbbbcccccccccccccccdddddddddddddddddddd')
|
||||||
|
|
||||||
|
expected_app_calls = [
|
||||||
|
('GET', '/v1/AUTH_test/gettest/manifest-abcd'),
|
||||||
|
('GET', '/v1/AUTH_test/gettest/manifest-bc'),
|
||||||
|
('GET', '/v1/AUTH_test/gettest/a_5?multipart-manifest=get'),
|
||||||
|
('GET', '/v1/AUTH_test/gettest/b_10?multipart-manifest=get'),
|
||||||
|
('GET', '/v1/AUTH_test/gettest/c_15?multipart-manifest=get'),
|
||||||
|
('GET', '/v1/AUTH_test/gettest/d_20?multipart-manifest=get'),
|
||||||
|
]
|
||||||
|
self.assertEqual(self.app.calls, expected_app_calls)
|
||||||
|
|
||||||
|
def test_if_match_matches(self):
|
||||||
|
req = Request.blank(
|
||||||
|
'/v1/AUTH_test/gettest/manifest-abcd',
|
||||||
|
environ={'REQUEST_METHOD': 'GET'},
|
||||||
|
headers={'If-Match': self.slo_etag})
|
||||||
|
status, headers, body = self.call_slo(req)
|
||||||
|
|
||||||
|
self.assertEqual(status, '200 OK')
|
||||||
|
self.assertIn(('Content-Length', '50'), headers)
|
||||||
|
self.assertIn(('Etag', '"%s"' % self.slo_etag), headers)
|
||||||
|
self.assertEqual(
|
||||||
|
body, 'aaaaabbbbbbbbbbcccccccccccccccdddddddddddddddddddd')
|
||||||
|
|
||||||
|
expected_app_calls = [
|
||||||
|
('GET', '/v1/AUTH_test/gettest/manifest-abcd'),
|
||||||
|
# Manifest never matches -> got back a 412; need to re-fetch
|
||||||
|
('GET', '/v1/AUTH_test/gettest/manifest-abcd'),
|
||||||
|
('GET', '/v1/AUTH_test/gettest/manifest-bc'),
|
||||||
|
('GET', '/v1/AUTH_test/gettest/a_5?multipart-manifest=get'),
|
||||||
|
('GET', '/v1/AUTH_test/gettest/b_10?multipart-manifest=get'),
|
||||||
|
('GET', '/v1/AUTH_test/gettest/c_15?multipart-manifest=get'),
|
||||||
|
('GET', '/v1/AUTH_test/gettest/d_20?multipart-manifest=get'),
|
||||||
|
]
|
||||||
|
self.assertEqual(self.app.calls, expected_app_calls)
|
||||||
|
|
||||||
|
def test_if_match_does_not_match(self):
|
||||||
|
req = Request.blank(
|
||||||
|
'/v1/AUTH_test/gettest/manifest-abcd',
|
||||||
|
environ={'REQUEST_METHOD': 'GET'},
|
||||||
|
headers={'If-Match': "not-%s" % self.slo_etag})
|
||||||
|
status, headers, body = self.call_slo(req)
|
||||||
|
|
||||||
|
self.assertEqual(status, '412 Precondition Failed')
|
||||||
|
self.assertIn(('Content-Length', '0'), headers)
|
||||||
|
self.assertIn(('Etag', '"%s"' % self.slo_etag), headers)
|
||||||
|
self.assertEqual(body, '')
|
||||||
|
|
||||||
|
expected_app_calls = [
|
||||||
|
('GET', '/v1/AUTH_test/gettest/manifest-abcd'),
|
||||||
|
# Manifest never matches -> got back a 412; need to re-fetch
|
||||||
|
('GET', '/v1/AUTH_test/gettest/manifest-abcd'),
|
||||||
|
# We need to verify the first segment
|
||||||
|
('GET', '/v1/AUTH_test/gettest/manifest-bc'),
|
||||||
|
('GET', '/v1/AUTH_test/gettest/a_5?multipart-manifest=get'),
|
||||||
|
]
|
||||||
|
self.assertEqual(self.app.calls, expected_app_calls)
|
||||||
|
|
||||||
|
def test_if_match_matches_and_range(self):
|
||||||
|
req = Request.blank(
|
||||||
|
'/v1/AUTH_test/gettest/manifest-abcd',
|
||||||
|
environ={'REQUEST_METHOD': 'GET'},
|
||||||
|
headers={'If-Match': self.slo_etag,
|
||||||
|
'Range': 'bytes=3-6'})
|
||||||
|
status, headers, body = self.call_slo(req)
|
||||||
|
|
||||||
|
self.assertEqual(status, '206 Partial Content')
|
||||||
|
self.assertIn(('Content-Length', '4'), headers)
|
||||||
|
# We intentionally drop Etag for ranged requests.
|
||||||
|
# Presumably because of broken clients?
|
||||||
|
self.assertNotIn('etag', [h.lower() for h, v in headers])
|
||||||
|
self.assertEqual(body, 'aabb')
|
||||||
|
|
||||||
|
expected_app_calls = [
|
||||||
|
('GET', '/v1/AUTH_test/gettest/manifest-abcd'),
|
||||||
|
# Needed to re-fetch because Range (and, for old manifests, 412)
|
||||||
|
('GET', '/v1/AUTH_test/gettest/manifest-abcd'),
|
||||||
|
('GET', '/v1/AUTH_test/gettest/manifest-bc'),
|
||||||
|
('GET', '/v1/AUTH_test/gettest/a_5?multipart-manifest=get'),
|
||||||
|
('GET', '/v1/AUTH_test/gettest/b_10?multipart-manifest=get'),
|
||||||
|
]
|
||||||
|
self.assertEqual(self.app.calls, expected_app_calls)
|
||||||
|
|
||||||
|
|
||||||
class TestSloBulkLogger(unittest.TestCase):
|
class TestSloBulkLogger(unittest.TestCase):
|
||||||
def test_reused_logger(self):
|
def test_reused_logger(self):
|
||||||
slo_mware = slo.filter_factory({})('fake app')
|
slo_mware = slo.filter_factory({})('fake app')
|
||||||
|
Loading…
Reference in New Issue
Block a user