diff --git a/test/registry_tests.py b/test/registry_tests.py index 9f74bb7cb..58dc961e7 100644 --- a/test/registry_tests.py +++ b/test/registry_tests.py @@ -78,16 +78,28 @@ class TestFeature(object): headers={'Content-Type': 'application/json'}) -class V1RegistryMixin(object): - def conduct(self, method, url, headers=None, data=None, auth=None, expected_code=200): - headers = headers or {} - headers['X-Docker-Token'] = self.docker_token +class BaseRegistryMixin(object): + def conduct(self, method, url, headers=None, data=None, auth=None, params=None, expected_code=200): + params = params or {} + params['_csrf_token'] = self.csrf_token - if self.signature and not auth: - headers['Authorization'] = 'token ' + self.signature + headers = headers or {} + auth_tuple = None + + if self.docker_token: + headers['X-Docker-Token'] = self.docker_token + + if auth == 'sig': + if self.signature: + headers['Authorization'] = 'token ' + self.signature + elif auth == 'jwt': + if self.jwt: + headers['Authorization'] = 'Bearer ' + self.jwt + elif auth: + auth_tuple = auth response = self.session.request(method, self.get_server_url() + url, headers=headers, data=data, - auth=auth, params=dict(_csrf_token=self.csrf_token)) + auth=auth_tuple, params=params) if response.status_code != expected_code: print response.text @@ -100,14 +112,24 @@ class V1RegistryMixin(object): self.assertEquals(response.status_code, expected_code) return response - def ping(self): + + def clearSession(self): + self.signature = None + self.docker_token = 'true' + self.jwt = None + + +class V1RegistryMixin(BaseRegistryMixin): + def v1_ping(self): self.conduct('GET', '/v1/_ping') + +class V1RegistryPushMixin(V1RegistryMixin): def do_push(self, namespace, repository, username, password, images): auth = (username, password) # Ping! - self.ping() + self.v1_ping() # PUT /v1/repositories/{namespace}/{repository}/ data = [{"id": image['id']} for image in images] @@ -117,7 +139,8 @@ class V1RegistryMixin(object): for image in images: # PUT /v1/images/{imageID}/json - self.conduct('PUT', '/v1/images/%s/json' % image['id'], data=json.dumps(image)) + self.conduct('PUT', '/v1/images/%s/json' % image['id'], + data=json.dumps(image), auth='sig') # PUT /v1/images/{imageID}/layer tar_file_info = tarfile.TarInfo(name='image_name') @@ -133,30 +156,35 @@ class V1RegistryMixin(object): layer_bytes = layer_data.getvalue() layer_data.close() - self.conduct('PUT', '/v1/images/%s/layer' % image['id'], data=StringIO(layer_bytes)) + self.conduct('PUT', '/v1/images/%s/layer' % image['id'], + data=StringIO(layer_bytes), auth='sig') # PUT /v1/images/{imageID}/checksum checksum = compute_simple(StringIO(layer_bytes), json.dumps(image)) self.conduct('PUT', '/v1/images/%s/checksum' % image['id'], - headers={'X-Docker-Checksum-Payload': checksum}) + headers={'X-Docker-Checksum-Payload': checksum}, + auth='sig') # PUT /v1/repositories/{namespace}/{repository}/tags/latest self.conduct('PUT', '/v1/repositories/%s/%s/tags/latest' % (namespace, repository), - data='"' + images[0]['id'] + '"') + data='"' + images[0]['id'] + '"', + auth='sig') # PUT /v1/repositories/{namespace}/{repository}/images self.conduct('PUT', '/v1/repositories/%s/%s/images' % (namespace, repository), - expected_code=204) + expected_code=204, + auth='sig') +class V1RegistryPullMixin(V1RegistryMixin): def do_pull(self, namespace, repository, username=None, password='password', expected_code=200): auth = None if username: auth = (username, password) # Ping! - self.ping() + self.v1_ping() prefix = '/v1/repositories/%s/%s/' % (namespace, repository) @@ -166,39 +194,20 @@ class V1RegistryMixin(object): return # GET /v1/repositories/{namespace}/{repository}/ - result = json.loads(self.conduct('GET', prefix + 'tags').text) + result = json.loads(self.conduct('GET', prefix + 'tags', auth='sig').text) for image_id in result.values(): # /v1/images/{imageID}/{ancestry, json, layer} image_prefix = '/v1/images/%s/' % image_id - self.conduct('GET', image_prefix + 'ancestry') - self.conduct('GET', image_prefix + 'json') - self.conduct('GET', image_prefix + 'layer') - - def clearSession(self): - self.signature = None - self.docker_token = 'true' + self.conduct('GET', image_prefix + 'ancestry', auth='sig') + self.conduct('GET', image_prefix + 'json', auth='sig') + self.conduct('GET', image_prefix + 'layer', auth='sig') -class V2RegistryMixin(object): - def conduct(self, method, url, headers=None, params=None, data=None, auth=None, expected_code=200): - headers = headers or {} - params = params or {} - params['_csrf_token'] = self.csrf_token - if self.docker_token and not auth: - headers['Authorization'] = 'Bearer ' + self.docker_token - - response = self.session.request(method, self.get_server_url() + url, headers=headers, data=data, - auth=auth, params=params) - if response.status_code != expected_code: - print response.text - - self.assertEquals(response.status_code, expected_code) - return response - - def ping(self): - self.conduct('GET', '/v2/', expected_code=200 if self.docker_token else 401) +class V2RegistryMixin(BaseRegistryMixin): + def v2_ping(self): + self.conduct('GET', '/v2/', expected_code=200 if self.jwt else 401, auth='jwt') def do_auth(self, username, password, namespace, repository, expected_code=200, scopes=[]): @@ -215,12 +224,13 @@ class V2RegistryMixin(object): if expected_code == 200: response_json = json.loads(response.text) self.assertIsNotNone(response_json.get('token')) - self.docker_token = response_json['token'] + self.jwt = response_json['token'] +class V2RegistryPushMixin(V2RegistryMixin): def do_push(self, namespace, repository, username, password, images): # Ping! - self.ping() + self.v2_ping() # Auth. self.do_auth(username, password, namespace, repository, scopes=['push', 'pull']) @@ -239,19 +249,19 @@ class V2RegistryMixin(object): # Layer data should not yet exist. checksum = 'sha256:' + hashlib.sha256(contents).hexdigest() self.conduct('HEAD', '/v2/%s/%s/blobs/%s' % (namespace, repository, checksum), - expected_code=404) + expected_code=404, auth='jwt') # Start a new upload of the layer data. response = self.conduct('POST', '/v2/%s/%s/blobs/uploads/' % (namespace, repository), - expected_code=202) + expected_code=202, auth='jwt') location = response.headers['Location'][len(self.get_server_url()):] # PATCH the image data into the layer. - self.conduct('PATCH', location, data=contents, expected_code=204) + self.conduct('PATCH', location, data=contents, expected_code=204, auth='jwt') # Finish the layer upload with a PUT. - self.conduct('PUT', location, params=dict(digest=checksum), expected_code=201) + self.conduct('PUT', location, params=dict(digest=checksum), expected_code=201, auth='jwt') # Write the manifest. new_key = RSA.generate(2048) @@ -260,16 +270,13 @@ class V2RegistryMixin(object): self.conduct('PUT', '/v2/%s/%s/manifests/%s' % (namespace, repository, tag_name), data=manifest.bytes, expected_code=202, - headers={'Content-Type': 'application/json'}) + headers={'Content-Type': 'application/json'}, auth='jwt') +class V2RegistryPullMixin(V2RegistryMixin): def do_pull(self, namespace, repository, username=None, password='password', expected_code=200): - auth = None - if username: - auth = (username, password) - # Ping! - self.ping() + self.v2_ping() # Auth. self.do_auth(username, password, namespace, repository, scopes=['pull'], @@ -279,16 +286,15 @@ class V2RegistryMixin(object): # Retrieve the manifest for the tag. tag_name = 'latest' - response = self.conduct('GET', '/v2/%s/%s/manifests/%s' % (namespace, repository, tag_name)) + response = self.conduct('GET', '/v2/%s/%s/manifests/%s' % (namespace, repository, tag_name), + auth='jwt') manifest_data = json.loads(response.text) for layer in manifest_data['fsLayers']: blob_id = layer['blobSum'] - self.conduct('GET', '/v2/%s/%s/blobs/%s' % (namespace, repository, blob_id), expected_code=200) + self.conduct('GET', '/v2/%s/%s/blobs/%s' % (namespace, repository, blob_id), + expected_code=200, auth='jwt') - def clearSession(self): - self.docker_token = None - class RegistryTestCaseMixin(object): maxDiff = None @@ -500,12 +506,21 @@ class RegistryTestsMixin(object): self.do_pull('buynlarge', 'newrepo', 'devtable', 'password') -class V1RegistryTests(V1RegistryMixin, RegistryTestsMixin, RegistryTestCaseMixin, LiveServerTestCase): +class V1RegistryTests(V1RegistryPullMixin, V1RegistryPushMixin, RegistryTestsMixin, + RegistryTestCaseMixin, LiveServerTestCase): """ Tests for V1 registry. """ -class V2RegistryTests(V2RegistryMixin, RegistryTestsMixin, RegistryTestCaseMixin, LiveServerTestCase): +class V2RegistryTests(V2RegistryPullMixin, V2RegistryPushMixin, RegistryTestsMixin, + RegistryTestCaseMixin, LiveServerTestCase): """ Tests for V2 registry. """ +class V1PushV2PullRegistryTests(V2RegistryPullMixin, V1RegistryPushMixin, RegistryTestsMixin, + RegistryTestCaseMixin, LiveServerTestCase): + """ Tests for V1 push, V2 pull registry. """ + +class V1PullV2PushRegistryTests(V1RegistryPullMixin, V2RegistryPushMixin, RegistryTestsMixin, + RegistryTestCaseMixin, LiveServerTestCase): + """ Tests for V1 pull, V2 push registry. """ if __name__ == '__main__': unittest.main()