# vim: tabstop=4 shiftwidth=4 softtabstop=4 # Copyright 2011 OpenStack, LLC # All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. """Functional test case that utilizes httplib2 against the API server""" import hashlib import httplib2 import json import os from tests import functional from tests.utils import execute FIVE_KB = 5 * 1024 FIVE_GB = 5 * 1024 * 1024 * 1024 class TestApiHttplib2(functional.FunctionalTest): """Functional tests using httplib2 against the API server""" def test_001_get_head_simple_post(self): """ We test the following sequential series of actions: 0. GET /images - Verify no public images 1. GET /images/detail - Verify no public images 2. HEAD /images/1 - Verify 404 returned 3. POST /images with public image named Image1 with a location attribute and no custom properties - Verify 201 returned 4. HEAD /images/1 - Verify HTTP headers have correct information we just added 5. GET /images/1 - Verify all information on image we just added is correct 6. GET /images - Verify the image we just added is returned 7. GET /images/detail - Verify the image we just added is returned 8. PUT /images/1 with custom properties of "distro" and "arch" - Verify 200 returned 9. GET /images/1 - Verify updated information about image was stored 10. PUT /images/1 - Remove a previously existing property. 11. PUT /images/1 - Add a previously deleted property. """ self.cleanup() self.start_servers() # 0. GET /images # Verify no public images path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port) http = httplib2.Http() response, content = http.request(path, 'GET') self.assertEqual(response.status, 200) self.assertEqual(content, '{"images": []}') # 1. GET /images/detail # Verify no public images path = "http://%s:%d/v1/images/detail" % ("0.0.0.0", self.api_port) http = httplib2.Http() response, content = http.request(path, 'GET') self.assertEqual(response.status, 200) self.assertEqual(content, '{"images": []}') # 2. HEAD /images/1 # Verify 404 returned path = "http://%s:%d/v1/images/1" % ("0.0.0.0", self.api_port) http = httplib2.Http() response, content = http.request(path, 'HEAD') self.assertEqual(response.status, 404) # 3. POST /images with public image named Image1 # attribute and no custom properties. Verify a 200 OK is returned image_data = "*" * FIVE_KB headers = {'Content-Type': 'application/octet-stream', 'X-Image-Meta-Name': 'Image1', 'X-Image-Meta-Is-Public': 'True'} path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port) http = httplib2.Http() response, content = http.request(path, 'POST', headers=headers, body=image_data) self.assertEqual(response.status, 201) data = json.loads(content) self.assertEqual(data['image']['checksum'], hashlib.md5(image_data).hexdigest()) self.assertEqual(data['image']['size'], FIVE_KB) self.assertEqual(data['image']['name'], "Image1") self.assertEqual(data['image']['is_public'], True) # 4. HEAD /images/1 # Verify image found now path = "http://%s:%d/v1/images/1" % ("0.0.0.0", self.api_port) http = httplib2.Http() response, content = http.request(path, 'HEAD') self.assertEqual(response.status, 200) self.assertEqual(response['x-image-meta-name'], "Image1") # 5. GET /images/1 # Verify all information on image we just added is correct path = "http://%s:%d/v1/images/1" % ("0.0.0.0", self.api_port) http = httplib2.Http() response, content = http.request(path, 'GET') self.assertEqual(response.status, 200) expected_image_headers = { 'x-image-meta-id': '1', 'x-image-meta-name': 'Image1', 'x-image-meta-is_public': 'True', 'x-image-meta-status': 'active', 'x-image-meta-disk_format': '', 'x-image-meta-container_format': '', 'x-image-meta-size': str(FIVE_KB), 'x-image-meta-location': 'file://%s/1' % self.api_server.image_dir} expected_std_headers = { 'content-length': str(FIVE_KB), 'content-type': 'text/html; charset=UTF-8, application/octet-stream'} for expected_key, expected_value in expected_image_headers.items(): self.assertEqual(response[expected_key], expected_value, "For key '%s' expected header value '%s'. Got '%s'" % (expected_key, expected_value, response[expected_key])) for expected_key, expected_value in expected_std_headers.items(): self.assertEqual(response[expected_key], expected_value, "For key '%s' expected header value '%s'. Got '%s'" % (expected_key, expected_value, response[expected_key])) self.assertEqual(content, "*" * FIVE_KB) self.assertEqual(hashlib.md5(content).hexdigest(), hashlib.md5("*" * FIVE_KB).hexdigest()) # 6. GET /images # Verify no public images path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port) http = httplib2.Http() response, content = http.request(path, 'GET') self.assertEqual(response.status, 200) expected_result = {"images": [ {"container_format": None, "disk_format": None, "id": 1, "name": "Image1", "checksum": "c2e5db72bd7fd153f53ede5da5a06de3", "size": 5120}]} self.assertEqual(json.loads(content), expected_result) # 7. GET /images/detail # Verify image and all its metadata path = "http://%s:%d/v1/images/detail" % ("0.0.0.0", self.api_port) http = httplib2.Http() response, content = http.request(path, 'GET') self.assertEqual(response.status, 200) expected_image = { "status": "active", "name": "Image1", "deleted": False, "container_format": None, "disk_format": None, "id": 1, "location": "file://%s/1" % self.api_server.image_dir, "is_public": True, "deleted_at": None, "properties": {}, "size": 5120} image = json.loads(content) for expected_key, expected_value in expected_image.items(): self.assertEqual(expected_value, expected_image[expected_key], "For key '%s' expected header value '%s'. Got '%s'" % (expected_key, expected_value, image['images'][0][expected_key])) # 8. PUT /images/1 with custom properties of "distro" and "arch" # Verify 200 returned headers = {'X-Image-Meta-Property-Distro': 'Ubuntu', 'X-Image-Meta-Property-Arch': 'x86_64'} path = "http://%s:%d/v1/images/1" % ("0.0.0.0", self.api_port) http = httplib2.Http() response, content = http.request(path, 'PUT', headers=headers) self.assertEqual(response.status, 200) data = json.loads(content) self.assertEqual(data['image']['properties']['arch'], "x86_64") self.assertEqual(data['image']['properties']['distro'], "Ubuntu") # 9. GET /images/detail # Verify image and all its metadata path = "http://%s:%d/v1/images/detail" % ("0.0.0.0", self.api_port) http = httplib2.Http() response, content = http.request(path, 'GET') self.assertEqual(response.status, 200) expected_image = { "status": "active", "name": "Image1", "deleted": False, "container_format": None, "disk_format": None, "id": 1, "location": "file://%s/1" % self.api_server.image_dir, "is_public": True, "deleted_at": None, "properties": {'distro': 'Ubuntu', 'arch': 'x86_64'}, "size": 5120} image = json.loads(content) for expected_key, expected_value in expected_image.items(): self.assertEqual(expected_value, expected_image[expected_key], "For key '%s' expected header value '%s'. Got '%s'" % (expected_key, expected_value, image['images'][0][expected_key])) # 10. PUT /images/1 and remove a previously existing property. headers = {'X-Image-Meta-Property-Arch': 'x86_64'} path = "http://%s:%d/v1/images/1" % ("0.0.0.0", self.api_port) http = httplib2.Http() response, content = http.request(path, 'PUT', headers=headers) self.assertEqual(response.status, 200) path = "http://%s:%d/v1/images/detail" % ("0.0.0.0", self.api_port) response, content = http.request(path, 'GET') self.assertEqual(response.status, 200) data = json.loads(content)['images'][0] self.assertEqual(len(data['properties']), 1) self.assertEqual(data['properties']['arch'], "x86_64") # 11. PUT /images/1 and add a previously deleted property. headers = {'X-Image-Meta-Property-Distro': 'Ubuntu', 'X-Image-Meta-Property-Arch': 'x86_64'} path = "http://%s:%d/v1/images/1" % ("0.0.0.0", self.api_port) http = httplib2.Http() response, content = http.request(path, 'PUT', headers=headers) self.assertEqual(response.status, 200) data = json.loads(content) path = "http://%s:%d/v1/images/detail" % ("0.0.0.0", self.api_port) response, content = http.request(path, 'GET') self.assertEqual(response.status, 200) data = json.loads(content)['images'][0] self.assertEqual(len(data['properties']), 2) self.assertEqual(data['properties']['arch'], "x86_64") self.assertEqual(data['properties']['distro'], "Ubuntu") self.stop_servers()