def test_copy_from_http_nonexistent_location_url(self): # Ensure HTTP 404 response returned when try to create # image with non-existent http location URL. self.cleanup() self.start_servers(**self.__dict__.copy()) setup_http(self) uri = get_http_uri(self, 'foobar') copy_from = uri.replace('images', 'snafu') # POST /images with public image copied from HTTP (to file) headers = { 'X-Image-Meta-Name': 'copied', 'X-Image-Meta-disk_format': 'raw', 'X-Image-Meta-container_format': 'ovf', 'X-Image-Meta-Is-Public': 'True', 'X-Glance-API-Copy-From': copy_from } path = "http://%s:%d/v1/images" % ("127.0.0.1", self.api_port) http = httplib2.Http() response, content = http.request(path, 'POST', headers=headers) self.assertEqual(404, response.status, content) expected = 'HTTP datastore could not find image at URI.' self.assertIn(expected, content) self.stop_servers()
def test_copy_from_http_nonexistent_location_url(self): # Ensure HTTP 404 response returned when try to create # image with non-existent http location URL. self.cleanup() self.start_servers(**self.__dict__.copy()) setup_http(self) uri = get_http_uri(self, 'foobar') copy_from = uri.replace('images', 'snafu') # POST /images with public image copied from HTTP (to file) headers = {'X-Image-Meta-Name': 'copied', 'X-Image-Meta-disk_format': 'raw', 'X-Image-Meta-container_format': 'ovf', 'X-Image-Meta-Is-Public': 'True', 'X-Glance-API-Copy-From': copy_from} path = "http://%s:%d/v1/images" % ("127.0.0.1", self.api_port) http = httplib2.Http() response, content = http.request(path, 'POST', headers=headers) self.assertEqual(http_client.NOT_FOUND, response.status, content) expected = 'HTTP datastore could not find image at URI.' self.assertIn(expected, content) self.stop_servers()
def test_copy_from_http_exists(self): """Ensure we can copy from an external image in HTTP.""" self.cleanup() self.start_servers(**self.__dict__.copy()) setup_http(self) copy_from = get_http_uri(self, 'foobar') # POST /images with public image copied from HTTP (to file) headers = { 'X-Image-Meta-Name': 'copied', 'X-Image-Meta-disk_format': 'raw', 'X-Image-Meta-container_format': 'ovf', 'X-Image-Meta-Is-Public': 'True', 'X-Glance-API-Copy-From': copy_from } path = "http://%s:%d/v1/images" % ("127.0.0.1", self.api_port) http = httplib2.Http() response, content = http.request(path, 'POST', headers=headers) self.assertEqual(201, response.status, content) data = jsonutils.loads(content) copy_image_id = data['image']['id'] self.assertEqual('queued', data['image']['status'], content) path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port, copy_image_id) def _await_status(expected_status): for i in range(100): time.sleep(0.01) http = httplib2.Http() response, content = http.request(path, 'HEAD') self.assertEqual(200, response.status) if response['x-image-meta-status'] == expected_status: return self.fail('unexpected image status %s' % response['x-image-meta-status']) _await_status('active') # GET image and make sure image content is as expected http = httplib2.Http() response, content = http.request(path, 'GET') self.assertEqual(200, response.status) self.assertEqual(str(FIVE_KB), response['content-length']) self.assertEqual("*" * FIVE_KB, content) self.assertEqual( hashlib.md5("*" * FIVE_KB).hexdigest(), hashlib.md5(content).hexdigest()) # DELETE copied image http = httplib2.Http() response, content = http.request(path, 'DELETE') self.assertEqual(200, response.status) self.stop_servers()
def test_copy_from_http_exists(self): """Ensure we can copy from an external image in HTTP.""" self.cleanup() self.start_servers(**self.__dict__.copy()) setup_http(self) copy_from = get_http_uri(self, 'foobar') # POST /images with public image copied from HTTP (to file) headers = {'X-Image-Meta-Name': 'copied', 'X-Image-Meta-disk_format': 'raw', 'X-Image-Meta-container_format': 'ovf', 'X-Image-Meta-Is-Public': 'True', 'X-Glance-API-Copy-From': copy_from} path = "http://%s:%d/v1/images" % ("127.0.0.1", self.api_port) http = httplib2.Http() response, content = http.request(path, 'POST', headers=headers) self.assertEqual(http_client.CREATED, response.status, content) data = jsonutils.loads(content) copy_image_id = data['image']['id'] self.assertEqual('queued', data['image']['status'], content) path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port, copy_image_id) def _await_status(expected_status): for i in range(100): time.sleep(0.01) http = httplib2.Http() response, content = http.request(path, 'HEAD') self.assertEqual(http_client.OK, response.status) if response['x-image-meta-status'] == expected_status: return self.fail('unexpected image status %s' % response['x-image-meta-status']) _await_status('active') # GET image and make sure image content is as expected http = httplib2.Http() response, content = http.request(path, 'GET') self.assertEqual(http_client.OK, response.status) self.assertEqual(str(FIVE_KB), response['content-length']) self.assertEqual("*" * FIVE_KB, content) self.assertEqual(hashlib.md5("*" * FIVE_KB).hexdigest(), hashlib.md5(content).hexdigest()) # DELETE copied image http = httplib2.Http() response, content = http.request(path, 'DELETE') self.assertEqual(http_client.OK, response.status) self.stop_servers()
def _do_test_update_external_source(self, source): self.cleanup() self.start_servers(**self.__dict__.copy()) setup_http(self) api_port = self.api_port registry_port = self.registry_port # 1. Add public image with no image content headers = { 'X-Image-Meta-Name': 'MyImage', 'X-Image-Meta-disk_format': 'raw', 'X-Image-Meta-container_format': 'ovf', 'X-Image-Meta-Is-Public': 'True' } path = "http://%s:%d/v1/images" % ("0.0.0.0", api_port) http = httplib2.Http() response, content = http.request(path, 'POST', headers=headers) self.assertEqual(response.status, 201) data = json.loads(content) self.assertEqual(data['image']['name'], 'MyImage') image_id = data['image']['id'] # 2. Update image with external source source = '%s=%s' % (source, get_http_uri(self, 'foobar')) cmd = "bin/glance update %s %s -p %d" % (image_id, source, api_port) exitcode, out, err = execute(cmd, raise_error=False) self.assertEqual(0, exitcode) self.assertTrue(out.strip().endswith('Updated image %s' % image_id)) # 3. Verify image is now active and of the correct size cmd = "bin/glance --port=%d show %s" % (api_port, image_id) exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) expected_lines = [ 'URI: http://0.0.0.0:%s/v1/images/%s' % (api_port, image_id), 'Id: %s' % image_id, 'Public: Yes', 'Name: MyImage', 'Status: active', 'Size: 5120', 'Disk format: raw', 'Container format: ovf', 'Minimum Ram Required (MB): 0', 'Minimum Disk Required (GB): 0', ] lines = out.split("\n") self.assertTrue(set(lines) >= set(expected_lines)) self.stop_servers()
def test_copy_from_http(self): """ Ensure we can copy from an external image in HTTP. """ self.cleanup() self.start_servers(**self.__dict__.copy()) setup_http(self) api_port = self.api_port registry_port = self.registry_port copy_from = get_http_uri(self, 'foobar') # POST /images with public image copied HTTP (to S3) headers = { 'X-Image-Meta-Name': 'copied', 'X-Image-Meta-disk_format': 'raw', 'X-Image-Meta-container_format': 'ovf', 'X-Image-Meta-Is-Public': 'True', 'X-Glance-API-Copy-From': copy_from } path = "http://%s:%d/v1/images" % ("127.0.0.1", self.api_port) http = httplib2.Http() response, content = http.request(path, 'POST', headers=headers) self.assertEqual(response.status, 201, content) data = json.loads(content) copy_image_id = data['image']['id'] # GET image and make sure image content is as expected path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port, copy_image_id) http = httplib2.Http() response, content = http.request(path, 'GET') self.assertEqual(response.status, 200) self.assertEqual(response['content-length'], str(FIVE_KB)) self.assertEqual(content, "*" * FIVE_KB) self.assertEqual( hashlib.md5(content).hexdigest(), hashlib.md5("*" * FIVE_KB).hexdigest()) self.assertEqual(data['image']['size'], FIVE_KB) self.assertEqual(data['image']['name'], "copied") # DELETE copied image path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port, copy_image_id) http = httplib2.Http() response, content = http.request(path, 'DELETE') self.assertEqual(response.status, 200) self.stop_servers()
def _do_test_update_external_source(self, source): self.cleanup() self.start_servers(**self.__dict__.copy()) setup_http(self) api_port = self.api_port registry_port = self.registry_port # 1. Add public image with no image content headers = {'X-Image-Meta-Name': 'MyImage', 'X-Image-Meta-disk_format': 'raw', 'X-Image-Meta-container_format': 'ovf', 'X-Image-Meta-Is-Public': 'True'} path = "http://%s:%d/v1/images" % ("0.0.0.0", api_port) http = httplib2.Http() response, content = http.request(path, 'POST', headers=headers) self.assertEqual(response.status, 201) data = json.loads(content) self.assertEqual(data['image']['name'], 'MyImage') image_id = data['image']['id'] # 2. Update image with external source source = '%s=%s' % (source, get_http_uri(self, 'foobar')) cmd = "bin/glance update %s %s -p %d" % (image_id, source, api_port) exitcode, out, err = execute(cmd, raise_error=False) self.assertEqual(0, exitcode) self.assertTrue(out.strip().endswith('Updated image %s' % image_id)) # 3. Verify image is now active and of the correct size cmd = "bin/glance --port=%d show %s" % (api_port, image_id) exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) expected_lines = [ 'URI: http://0.0.0.0:%s/v1/images/%s' % (api_port, image_id), 'Id: %s' % image_id, 'Public: Yes', 'Name: MyImage', 'Status: active', 'Size: 5120', 'Disk format: raw', 'Container format: ovf', 'Minimum Ram Required (MB): 0', 'Minimum Disk Required (GB): 0', ] lines = out.split("\n") self.assertTrue(set(lines) >= set(expected_lines)) self.stop_servers()
def _do_test_update_external_source(self, source): self.cleanup() self.start_servers(**self.__dict__.copy()) setup_http(self) api_port = self.api_port registry_port = self.registry_port # 1. Add public image with no image content headers = { "X-Image-Meta-Name": "MyImage", "X-Image-Meta-disk_format": "raw", "X-Image-Meta-container_format": "ovf", "X-Image-Meta-Is-Public": "True", } path = "http://%s:%d/v1/images" % ("0.0.0.0", api_port) http = httplib2.Http() response, content = http.request(path, "POST", headers=headers) self.assertEqual(response.status, 201) data = json.loads(content) self.assertEqual(data["image"]["name"], "MyImage") image_id = data["image"]["id"] # 2. Update image with external source source = "%s=%s" % (source, get_http_uri(self, "foobar")) cmd = "bin/glance update %s %s -p %d" % (image_id, source, api_port) exitcode, out, err = execute(cmd, raise_error=False) self.assertEqual(0, exitcode) self.assertTrue(out.strip().endswith("Updated image %s" % image_id)) # 3. Verify image is now active and of the correct size cmd = "bin/glance --port=%d show %s" % (api_port, image_id) exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) expected_lines = [ "URI: http://0.0.0.0:%s/v1/images/%s" % (api_port, image_id), "Id: %s" % image_id, "Public: Yes", "Name: MyImage", "Status: active", "Size: 5120", "Disk format: raw", "Container format: ovf", "Minimum Ram Required (MB): 0", "Minimum Disk Required (GB): 0", ] lines = out.split("\n") self.assertTrue(set(lines) >= set(expected_lines))
def test_copy_from_http(self): """ Ensure we can copy from an external image in HTTP. """ self.cleanup() self.start_servers(**self.__dict__.copy()) setup_http(self) api_port = self.api_port registry_port = self.registry_port copy_from = get_http_uri(self, 'foobar') # POST /images with public image copied HTTP (to Swift) headers = {'X-Image-Meta-Name': 'copied', 'X-Image-Meta-disk_format': 'raw', 'X-Image-Meta-container_format': 'ovf', 'X-Image-Meta-Is-Public': 'True', 'X-Glance-API-Copy-From': copy_from} path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port) http = httplib2.Http() response, content = http.request(path, 'POST', headers=headers) self.assertEqual(response.status, 201, content) data = json.loads(content) copy_image_id = data['image']['id'] # GET image and make sure image content is as expected path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port, copy_image_id) http = httplib2.Http() response, content = http.request(path, 'GET') self.assertEqual(response.status, 200) self.assertEqual(response['content-length'], str(FIVE_KB)) self.assertEqual(content, "*" * FIVE_KB) self.assertEqual(hashlib.md5(content).hexdigest(), hashlib.md5("*" * FIVE_KB).hexdigest()) self.assertEqual(data['image']['size'], FIVE_KB) self.assertEqual(data['image']['name'], "copied") # DELETE copied image path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port, copy_image_id) http = httplib2.Http() response, content = http.request(path, 'DELETE') self.assertEqual(response.status, 200) self.stop_servers()
def test_copy_from_http(self): """ Ensure we can copy from an external image in HTTP. """ self.cleanup() self.start_servers(**self.__dict__.copy()) setup_http(self) api_port = self.api_port registry_port = self.registry_port copy_from = get_http_uri(self, "foobar") # POST /images with public image copied HTTP (to S3) headers = { "X-Image-Meta-Name": "copied", "X-Image-Meta-disk_format": "raw", "X-Image-Meta-container_format": "ovf", "X-Image-Meta-Is-Public": "True", "X-Glance-API-Copy-From": copy_from, } path = "http://%s:%d/v1/images" % ("127.0.0.1", self.api_port) http = httplib2.Http() response, content = http.request(path, "POST", headers=headers) self.assertEqual(response.status, 201, content) data = json.loads(content) copy_image_id = data["image"]["id"] # GET image and make sure image content is as expected path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port, copy_image_id) http = httplib2.Http() response, content = http.request(path, "GET") self.assertEqual(response.status, 200) self.assertEqual(response["content-length"], str(FIVE_KB)) self.assertEqual(content, "*" * FIVE_KB) self.assertEqual(hashlib.md5(content).hexdigest(), hashlib.md5("*" * FIVE_KB).hexdigest()) self.assertEqual(data["image"]["size"], FIVE_KB) self.assertEqual(data["image"]["name"], "copied") # DELETE copied image path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port, copy_image_id) http = httplib2.Http() response, content = http.request(path, "DELETE") self.assertEqual(response.status, 200) self.stop_servers()
def test_add_copying_from(self): self.cleanup() self.start_servers(**self.__dict__.copy()) setup_http(self) api_port = self.api_port registry_port = self.registry_port # 0. Verify no public images cmd = "bin/glance --port=%d index" % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) self.assertEqual('', out.strip()) # 1. Add public image suffix = 'copy_from=%s' % get_http_uri(self, 'foobar') cmd = minimal_add_command(api_port, 'MyImage', suffix) exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) self.assertTrue(out.strip().startswith('Added new image with ID:')) # 2. Verify image added as public image cmd = "bin/glance --port=%d index" % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) lines = out.split("\n")[2:-1] self.assertEqual(1, len(lines)) line = lines[0] image_id, name, disk_format, container_format, size = \ [c.strip() for c in line.split()] self.assertEqual('MyImage', name) self.assertEqual( '5120', size, "Expected image to be 5120 bytes " " in size, but got %s. " % size) self.stop_servers()
def test_cache_remote_image(self): """ We test that caching is no longer broken for remote images """ self.cleanup() self.start_servers(**self.__dict__.copy()) setup_http(self) api_port = self.api_port registry_port = self.registry_port # Add a remote image and verify a 201 Created is returned remote_uri = get_http_uri(self, '2') headers = { 'X-Image-Meta-Name': 'Image2', 'X-Image-Meta-disk_format': 'raw', 'X-Image-Meta-container_format': 'ovf', 'X-Image-Meta-Is-Public': 'True', 'X-Image-Meta-Location': remote_uri } path = "http://%s:%d/v1/images" % ("127.0.0.1", self.api_port) http = httplib2.Http() response, content = http.request(path, 'POST', headers=headers) self.assertEqual(response.status, 201) data = json.loads(content) self.assertEqual(data['image']['size'], FIVE_KB) image_id = data['image']['id'] path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port, image_id) # Grab the image http = httplib2.Http() response, content = http.request(path, 'GET') self.assertEqual(response.status, 200) # Grab the image again to ensure it can be served out from # cache with the correct size http = httplib2.Http() response, content = http.request(path, 'GET') self.assertEqual(response.status, 200) self.assertEqual(int(response['content-length']), FIVE_KB) self.stop_servers()
def test_cache_remote_image(self): """ We test that caching is no longer broken for remote images """ self.cleanup() self.start_servers(**self.__dict__.copy()) setup_http(self) api_port = self.api_port registry_port = self.registry_port # Add a remote image and verify a 201 Created is returned remote_uri = get_http_uri(self, "2") headers = { "X-Image-Meta-Name": "Image2", "X-Image-Meta-disk_format": "raw", "X-Image-Meta-container_format": "ovf", "X-Image-Meta-Is-Public": "True", "X-Image-Meta-Location": remote_uri, } path = "http://%s:%d/v1/images" % ("127.0.0.1", self.api_port) http = httplib2.Http() response, content = http.request(path, "POST", headers=headers) self.assertEqual(response.status, 201) data = json.loads(content) self.assertEqual(data["image"]["size"], FIVE_KB) image_id = data["image"]["id"] path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port, image_id) # Grab the image http = httplib2.Http() response, content = http.request(path, "GET") self.assertEqual(response.status, 200) # Grab the image again to ensure it can be served out from # cache with the correct size http = httplib2.Http() response, content = http.request(path, "GET") self.assertEqual(response.status, 200) self.assertEqual(int(response["content-length"]), FIVE_KB) self.stop_servers()
def test_add_copying_from(self): self.cleanup() self.start_servers(**self.__dict__.copy()) setup_http(self) api_port = self.api_port registry_port = self.registry_port # 0. Verify no public images cmd = "bin/glance --port=%d index" % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) self.assertEqual('', out.strip()) # 1. Add public image suffix = 'copy_from=%s' % get_http_uri(self, 'foobar') cmd = minimal_add_command(api_port, 'MyImage', suffix) exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) self.assertTrue(out.strip().startswith('Added new image with ID:')) # 2. Verify image added as public image cmd = "bin/glance --port=%d index" % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) lines = out.split("\n")[2:-1] self.assertEqual(1, len(lines)) line = lines[0] image_id, name, disk_format, container_format, size = \ [c.strip() for c in line.split()] self.assertEqual('MyImage', name) self.assertEqual('5120', size, "Expected image to be 5120 bytes " " in size, but got %s. " % size) self.stop_servers()
def test_cache_remote_image(self): """ We test that caching is no longer broken for remote images """ self.cleanup() self.start_servers(**self.__dict__.copy()) setup_http(self) api_port = self.api_port registry_port = self.registry_port # Add a remote image and verify a 201 Created is returned remote_uri = get_http_uri(self, '2') headers = {'X-Image-Meta-Name': 'Image2', 'X-Image-Meta-disk_format': 'raw', 'X-Image-Meta-container_format': 'ovf', 'X-Image-Meta-Is-Public': 'True', 'X-Image-Meta-Location': remote_uri} path = "http://%s:%d/v1/images" % ("127.0.0.1", self.api_port) http = httplib2.Http() response, content = http.request(path, 'POST', headers=headers) self.assertEqual(response.status, 201) data = json.loads(content) self.assertEqual(data['image']['size'], FIVE_KB) image_id = data['image']['id'] path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port, image_id) # Grab the image http = httplib2.Http() response, content = http.request(path, 'GET') self.assertEqual(response.status, 200) # Grab the image again to ensure it can be served out from # cache with the correct size http = httplib2.Http() response, content = http.request(path, 'GET') self.assertEqual(response.status, 200) self.assertEqual(int(response['content-length']), FIVE_KB) self.stop_servers()
def _do_test_copy_from_http(self, exists): """ Ensure we can copy from an external image in HTTP. :param exists: True iff the external source image exists """ self.cleanup() self.start_servers(**self.__dict__.copy()) setup_http(self) api_port = self.api_port registry_port = self.registry_port uri = get_http_uri(self, 'foobar') copy_from = uri if exists else uri.replace('images', 'snafu') # POST /images with public image copied from HTTP (to file) headers = { 'X-Image-Meta-Name': 'copied', 'X-Image-Meta-disk_format': 'raw', 'X-Image-Meta-container_format': 'ovf', 'X-Image-Meta-Is-Public': 'True', 'X-Glance-API-Copy-From': copy_from } path = "http://%s:%d/v1/images" % ("127.0.0.1", self.api_port) http = httplib2.Http() response, content = http.request(path, 'POST', headers=headers) self.assertEqual(response.status, 201, content) data = json.loads(content) copy_image_id = data['image']['id'] self.assertEqual(data['image']['status'], 'queued', content) path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port, copy_image_id) def _await_status(expected_status): for i in xrange(100): time.sleep(0.01) http = httplib2.Http() response, content = http.request(path, 'HEAD') self.assertEqual(response.status, 200) if response['x-image-meta-status'] == expected_status: return self.fail('unexpected image status %s' % response['x-image-meta-status']) _await_status('active' if exists else 'killed') # GET image and make sure image content is as expected http = httplib2.Http() response, content = http.request(path, 'GET') self.assertEqual(response.status, 200 if exists else 404) if exists: self.assertEqual(response['content-length'], str(FIVE_KB)) self.assertEqual(content, "*" * FIVE_KB) self.assertEqual( hashlib.md5(content).hexdigest(), hashlib.md5("*" * FIVE_KB).hexdigest()) # DELETE copied image http = httplib2.Http() response, content = http.request(path, 'DELETE') self.assertEqual(response.status, 200) self.stop_servers()
def _do_test_copy_from_http(self, exists): """ Ensure we can copy from an external image in HTTP. :param exists: True iff the external source image exists """ self.cleanup() self.start_servers(**self.__dict__.copy()) setup_http(self) api_port = self.api_port registry_port = self.registry_port uri = get_http_uri(self, 'foobar') copy_from = uri if exists else uri.replace('images', 'snafu') # POST /images with public image copied from HTTP (to file) headers = {'X-Image-Meta-Name': 'copied', 'X-Image-Meta-disk_format': 'raw', 'X-Image-Meta-container_format': 'ovf', 'X-Image-Meta-Is-Public': 'True', 'X-Glance-API-Copy-From': copy_from} path = "http://%s:%d/v1/images" % ("127.0.0.1", self.api_port) http = httplib2.Http() response, content = http.request(path, 'POST', headers=headers) self.assertEqual(response.status, 201, content) data = json.loads(content) copy_image_id = data['image']['id'] self.assertEqual(data['image']['status'], 'queued', content) path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port, copy_image_id) def _await_status(expected_status): for i in xrange(100): time.sleep(0.01) http = httplib2.Http() response, content = http.request(path, 'HEAD') self.assertEqual(response.status, 200) if response['x-image-meta-status'] == expected_status: return self.fail('unexpected image status %s' % response['x-image-meta-status']) _await_status('active' if exists else 'killed') # GET image and make sure image content is as expected http = httplib2.Http() response, content = http.request(path, 'GET') self.assertEqual(response.status, 200 if exists else 404) if exists: self.assertEqual(response['content-length'], str(FIVE_KB)) self.assertEqual(content, "*" * FIVE_KB) self.assertEqual(hashlib.md5(content).hexdigest(), hashlib.md5("*" * FIVE_KB).hexdigest()) # DELETE copied image http = httplib2.Http() response, content = http.request(path, 'DELETE') self.assertEqual(response.status, 200) self.stop_servers()