Merge pull request #3199 from quay/fix-registry-tests
Fix registry tests to not terminate prematurely when looking for errors
This commit is contained in:
commit
805e928dff
4 changed files with 42 additions and 20 deletions
|
@ -437,6 +437,13 @@ def put_image_json(namespace, repository, image_id):
|
||||||
abort(404, 'Repository does not exist: %(namespace)s/%(repository)s', issue='no-repo',
|
abort(404, 'Repository does not exist: %(namespace)s/%(repository)s', issue='no-repo',
|
||||||
namespace=namespace, repository=repository)
|
namespace=namespace, repository=repository)
|
||||||
|
|
||||||
|
parent_id = data.get('parent', None)
|
||||||
|
if parent_id:
|
||||||
|
logger.debug('Looking up parent image')
|
||||||
|
if model.docker_v1_metadata(namespace, repository, parent_id) is None:
|
||||||
|
abort(400, 'Image %(image_id)s depends on non existing parent image %(parent_id)s',
|
||||||
|
issue='invalid-request', image_id=image_id, parent_id=parent_id)
|
||||||
|
|
||||||
v1_metadata = model.docker_v1_metadata(namespace, repository, image_id)
|
v1_metadata = model.docker_v1_metadata(namespace, repository, image_id)
|
||||||
if v1_metadata is None:
|
if v1_metadata is None:
|
||||||
username = get_authenticated_user() and get_authenticated_user().username
|
username = get_authenticated_user() and get_authenticated_user().username
|
||||||
|
@ -451,13 +458,6 @@ def put_image_json(namespace, repository, image_id):
|
||||||
model.create_temp_hidden_tag(namespace, repository, image_id,
|
model.create_temp_hidden_tag(namespace, repository, image_id,
|
||||||
app.config['PUSH_TEMP_TAG_EXPIRATION_SEC'])
|
app.config['PUSH_TEMP_TAG_EXPIRATION_SEC'])
|
||||||
|
|
||||||
parent_id = data.get('parent', None)
|
|
||||||
if parent_id:
|
|
||||||
logger.debug('Looking up parent image')
|
|
||||||
if model.docker_v1_metadata(namespace, repository, parent_id) is None:
|
|
||||||
abort(400, 'Image %(image_id)s depends on non existing parent image %(parent_id)s',
|
|
||||||
issue='invalid-request', image_id=image_id, parent_id=parent_id)
|
|
||||||
|
|
||||||
logger.debug('Checking if image already exists')
|
logger.debug('Checking if image already exists')
|
||||||
if v1_metadata and not model.is_image_uploading(namespace, repository, image_id):
|
if v1_metadata and not model.is_image_uploading(namespace, repository, image_id):
|
||||||
exact_abort(409, 'Image already exists')
|
exact_abort(409, 'Image already exists')
|
||||||
|
|
|
@ -13,6 +13,7 @@ class V1ProtocolSteps(Enum):
|
||||||
PUT_IMAGES = 'put-images'
|
PUT_IMAGES = 'put-images'
|
||||||
GET_IMAGES = 'get-images'
|
GET_IMAGES = 'get-images'
|
||||||
PUT_TAG = 'put-tag'
|
PUT_TAG = 'put-tag'
|
||||||
|
PUT_IMAGE_JSON = 'put-image-json'
|
||||||
|
|
||||||
|
|
||||||
class V1Protocol(RegistryProtocol):
|
class V1Protocol(RegistryProtocol):
|
||||||
|
@ -34,6 +35,9 @@ class V1Protocol(RegistryProtocol):
|
||||||
Failures.DISALLOWED_LIBRARY_NAMESPACE: 400,
|
Failures.DISALLOWED_LIBRARY_NAMESPACE: 400,
|
||||||
Failures.NAMESPACE_DISABLED: 400,
|
Failures.NAMESPACE_DISABLED: 400,
|
||||||
},
|
},
|
||||||
|
V1ProtocolSteps.PUT_IMAGE_JSON: {
|
||||||
|
Failures.INVALID_IMAGES: 400,
|
||||||
|
},
|
||||||
V1ProtocolSteps.PUT_TAG: {
|
V1ProtocolSteps.PUT_TAG: {
|
||||||
Failures.MISSING_TAG: 404,
|
Failures.MISSING_TAG: 404,
|
||||||
Failures.INVALID_TAG: 400,
|
Failures.INVALID_TAG: 400,
|
||||||
|
@ -77,7 +81,7 @@ class V1Protocol(RegistryProtocol):
|
||||||
headers = {'X-Docker-Token': 'true'}
|
headers = {'X-Docker-Token': 'true'}
|
||||||
result = self.conduct(session, 'GET', prefix + 'images', auth=auth, headers=headers,
|
result = self.conduct(session, 'GET', prefix + 'images', auth=auth, headers=headers,
|
||||||
expected_status=(200, expected_failure, V1ProtocolSteps.GET_IMAGES))
|
expected_status=(200, expected_failure, V1ProtocolSteps.GET_IMAGES))
|
||||||
if expected_failure is not None:
|
if result.status_code != 200:
|
||||||
return
|
return
|
||||||
|
|
||||||
headers = {}
|
headers = {}
|
||||||
|
@ -91,6 +95,10 @@ class V1Protocol(RegistryProtocol):
|
||||||
assert len(image_ids.values()) == len(tag_names)
|
assert len(image_ids.values()) == len(tag_names)
|
||||||
|
|
||||||
for tag_name in tag_names:
|
for tag_name in tag_names:
|
||||||
|
if tag_name not in image_ids:
|
||||||
|
assert expected_failure == Failures.UNKNOWN_TAG
|
||||||
|
return None
|
||||||
|
|
||||||
tag_image_id = image_ids[tag_name]
|
tag_image_id = image_ids[tag_name]
|
||||||
if not options.munge_shas:
|
if not options.munge_shas:
|
||||||
# Ensure we have a matching image ID.
|
# Ensure we have a matching image ID.
|
||||||
|
@ -133,8 +141,7 @@ class V1Protocol(RegistryProtocol):
|
||||||
expected_status=(201, expected_failure, V1ProtocolSteps.PUT_IMAGES),
|
expected_status=(201, expected_failure, V1ProtocolSteps.PUT_IMAGES),
|
||||||
json_data={},
|
json_data={},
|
||||||
auth=auth)
|
auth=auth)
|
||||||
|
if result.status_code != 201:
|
||||||
if expected_failure is not None:
|
|
||||||
return
|
return
|
||||||
|
|
||||||
headers = {}
|
headers = {}
|
||||||
|
@ -152,8 +159,12 @@ class V1Protocol(RegistryProtocol):
|
||||||
if image.config is not None:
|
if image.config is not None:
|
||||||
image_json_data['config'] = image.config
|
image_json_data['config'] = image.config
|
||||||
|
|
||||||
self.conduct(session, 'PUT', '/v1/images/%s/json' % image.id,
|
response = self.conduct(session, 'PUT', '/v1/images/%s/json' % image.id,
|
||||||
json_data=image_json_data, headers=headers)
|
json_data=image_json_data, headers=headers,
|
||||||
|
expected_status=(200, expected_failure,
|
||||||
|
V1ProtocolSteps.PUT_IMAGE_JSON))
|
||||||
|
if response.status_code != 200:
|
||||||
|
break
|
||||||
|
|
||||||
# PUT /v1/images/{imageID}/layer
|
# PUT /v1/images/{imageID}/layer
|
||||||
self.conduct(session, 'PUT', '/v1/images/%s/layer' % image.id,
|
self.conduct(session, 'PUT', '/v1/images/%s/layer' % image.id,
|
||||||
|
|
|
@ -18,6 +18,7 @@ class V2ProtocolSteps(Enum):
|
||||||
MOUNT_BLOB = 'mount-blob'
|
MOUNT_BLOB = 'mount-blob'
|
||||||
CATALOG = 'catalog'
|
CATALOG = 'catalog'
|
||||||
LIST_TAGS = 'list-tags'
|
LIST_TAGS = 'list-tags'
|
||||||
|
START_UPLOAD = 'start-upload'
|
||||||
|
|
||||||
|
|
||||||
class V2Protocol(RegistryProtocol):
|
class V2Protocol(RegistryProtocol):
|
||||||
|
@ -36,15 +37,21 @@ class V2Protocol(RegistryProtocol):
|
||||||
},
|
},
|
||||||
V2ProtocolSteps.GET_MANIFEST: {
|
V2ProtocolSteps.GET_MANIFEST: {
|
||||||
Failures.UNKNOWN_TAG: 404,
|
Failures.UNKNOWN_TAG: 404,
|
||||||
Failures.UNAUTHORIZED: 403,
|
Failures.UNAUTHORIZED: 401,
|
||||||
|
Failures.DISALLOWED_LIBRARY_NAMESPACE: 400,
|
||||||
|
},
|
||||||
|
V2ProtocolSteps.BLOB_HEAD_CHECK: {
|
||||||
|
Failures.DISALLOWED_LIBRARY_NAMESPACE: 400,
|
||||||
|
},
|
||||||
|
V2ProtocolSteps.START_UPLOAD: {
|
||||||
Failures.DISALLOWED_LIBRARY_NAMESPACE: 400,
|
Failures.DISALLOWED_LIBRARY_NAMESPACE: 400,
|
||||||
},
|
},
|
||||||
V2ProtocolSteps.PUT_MANIFEST: {
|
V2ProtocolSteps.PUT_MANIFEST: {
|
||||||
Failures.DISALLOWED_LIBRARY_NAMESPACE: 400,
|
Failures.DISALLOWED_LIBRARY_NAMESPACE: 400,
|
||||||
Failures.MISSING_TAG: 404,
|
Failures.MISSING_TAG: 404,
|
||||||
Failures.INVALID_TAG: 400,
|
Failures.INVALID_TAG: 404,
|
||||||
Failures.INVALID_IMAGES: 400,
|
Failures.INVALID_IMAGES: 400,
|
||||||
Failures.INVALID_BLOB: 400,
|
Failures.INVALID_BLOB: 404,
|
||||||
Failures.UNSUPPORTED_CONTENT_TYPE: 415,
|
Failures.UNSUPPORTED_CONTENT_TYPE: 415,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -103,8 +110,9 @@ class V2Protocol(RegistryProtocol):
|
||||||
|
|
||||||
response = self.conduct(session, 'GET', '/v2/auth', params=params, auth=auth,
|
response = self.conduct(session, 'GET', '/v2/auth', params=params, auth=auth,
|
||||||
expected_status=(200, expected_failure, V2ProtocolSteps.AUTH))
|
expected_status=(200, expected_failure, V2ProtocolSteps.AUTH))
|
||||||
|
expect_token = (expected_failure is None or
|
||||||
if expected_failure is None:
|
not V2Protocol.FAILURE_CODES[V2ProtocolSteps.AUTH].get(expected_failure))
|
||||||
|
if expect_token:
|
||||||
assert response.json().get('token') is not None
|
assert response.json().get('token') is not None
|
||||||
return response.json().get('token'), response
|
return response.json().get('token'), response
|
||||||
|
|
||||||
|
@ -123,6 +131,7 @@ class V2Protocol(RegistryProtocol):
|
||||||
token, _ = self.auth(session, credentials, namespace, repo_name, scopes=scopes,
|
token, _ = self.auth(session, credentials, namespace, repo_name, scopes=scopes,
|
||||||
expected_failure=expected_failure)
|
expected_failure=expected_failure)
|
||||||
if token is None:
|
if token is None:
|
||||||
|
assert V2Protocol.FAILURE_CODES[V2ProtocolSteps.AUTH].get(expected_failure)
|
||||||
return
|
return
|
||||||
|
|
||||||
headers = {
|
headers = {
|
||||||
|
@ -182,8 +191,11 @@ class V2Protocol(RegistryProtocol):
|
||||||
# Start a new upload of the layer data.
|
# Start a new upload of the layer data.
|
||||||
response = self.conduct(session, 'POST',
|
response = self.conduct(session, 'POST',
|
||||||
'/v2/%s/blobs/uploads/' % self.repo_name(namespace, repo_name),
|
'/v2/%s/blobs/uploads/' % self.repo_name(namespace, repo_name),
|
||||||
expected_status=202,
|
expected_status=(202, expected_failure,
|
||||||
|
V2ProtocolSteps.START_UPLOAD),
|
||||||
headers=headers)
|
headers=headers)
|
||||||
|
if response.status_code != 202:
|
||||||
|
continue
|
||||||
|
|
||||||
upload_uuid = response.headers['Docker-Upload-UUID']
|
upload_uuid = response.headers['Docker-Upload-UUID']
|
||||||
new_upload_location = response.headers['Location']
|
new_upload_location = response.headers['Location']
|
||||||
|
|
|
@ -341,7 +341,7 @@ def test_push_library_with_support_disabled(pusher, basic_images, liveserver_ses
|
||||||
should fail.
|
should fail.
|
||||||
"""
|
"""
|
||||||
credentials = ('devtable', 'password')
|
credentials = ('devtable', 'password')
|
||||||
|
|
||||||
with FeatureFlagValue('LIBRARY_SUPPORT', False, registry_server_executor.on(liveserver)):
|
with FeatureFlagValue('LIBRARY_SUPPORT', False, registry_server_executor.on(liveserver)):
|
||||||
# Attempt to push a new repository.
|
# Attempt to push a new repository.
|
||||||
pusher.push(liveserver_session, '', 'newrepo', 'latest', basic_images,
|
pusher.push(liveserver_session, '', 'newrepo', 'latest', basic_images,
|
||||||
|
@ -527,7 +527,6 @@ def test_expiration_label(label_value, expected_expiration, manifest_protocol, l
|
||||||
@pytest.mark.parametrize('content_type', [
|
@pytest.mark.parametrize('content_type', [
|
||||||
'application/vnd.oci.image.manifest.v1+json',
|
'application/vnd.oci.image.manifest.v1+json',
|
||||||
'application/vnd.docker.distribution.manifest.v2+json',
|
'application/vnd.docker.distribution.manifest.v2+json',
|
||||||
'application/vnd.foo.bar',
|
|
||||||
])
|
])
|
||||||
def test_unsupported_manifest_content_type(content_type, manifest_protocol, basic_images,
|
def test_unsupported_manifest_content_type(content_type, manifest_protocol, basic_images,
|
||||||
liveserver_session, app_reloader):
|
liveserver_session, app_reloader):
|
||||||
|
|
Reference in a new issue