# vim: tabstop=4 shiftwidth=4 softtabstop=4 # Copyright 2010 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. import httplib import json import unittest import stubout import webob from glance import server from glance.common import flags from glance.registry import server as rserver from tests import stubs FLAGS = flags.FLAGS class TestRegistryAPI(unittest.TestCase): def setUp(self): """Establish a clean test environment""" self.stubs = stubout.StubOutForTesting() stubs.stub_out_registry_and_store_server(self.stubs) stubs.stub_out_registry_db_image_api(self.stubs) stubs.stub_out_filesystem_backend() def tearDown(self): """Clear the test environment""" stubs.clean_out_fake_filesystem_backend() self.stubs.UnsetAll() def test_get_root(self): """Tests that the root registry API returns "index", which is a list of public images """ fixture = {'id': 2, 'name': 'fake image #2'} req = webob.Request.blank('/') res = req.get_response(rserver.API()) res_dict = json.loads(res.body) self.assertEquals(res.status_int, 200) images = res_dict['images'] self.assertEquals(len(images), 1) for k, v in fixture.iteritems(): self.assertEquals(v, images[0][k]) def test_get_index(self): """Tests that the /images registry API returns list of public images """ fixture = {'id': 2, 'name': 'fake image #2'} req = webob.Request.blank('/images') res = req.get_response(rserver.API()) res_dict = json.loads(res.body) self.assertEquals(res.status_int, 200) images = res_dict['images'] self.assertEquals(len(images), 1) for k, v in fixture.iteritems(): self.assertEquals(v, images[0][k]) def test_get_details(self): """Tests that the /images/detail registry API returns a mapping containing a list of detailed image information """ fixture = {'id': 2, 'name': 'fake image #2', 'is_public': True, 'type': 'kernel', 'status': 'active' } req = webob.Request.blank('/images/detail') res = req.get_response(rserver.API()) res_dict = json.loads(res.body) self.assertEquals(res.status_int, 200) images = res_dict['images'] self.assertEquals(len(images), 1) for k, v in fixture.iteritems(): self.assertEquals(v, images[0][k]) def test_create_image(self): """Tests that the /images POST registry API creates the image""" fixture = {'name': 'fake public image', 'is_public': True, 'type': 'kernel' } req = webob.Request.blank('/images') req.method = 'POST' req.body = json.dumps(dict(image=fixture)) res = req.get_response(rserver.API()) self.assertEquals(res.status_int, 200) res_dict = json.loads(res.body) for k, v in fixture.iteritems(): self.assertEquals(v, res_dict['image'][k]) # Test ID auto-assigned properly self.assertEquals(3, res_dict['image']['id']) # Test status was updated properly self.assertEquals('active', res_dict['image']['status']) def test_create_image_with_bad_status(self): """Tests proper exception is raised if a bad status is set""" fixture = {'id': 3, 'name': 'fake public image', 'is_public': True, 'type': 'kernel', 'status': 'bad status' } req = webob.Request.blank('/images') req.method = 'POST' req.body = json.dumps(dict(image=fixture)) # TODO(jaypipes): Port Nova's Fault infrastructure # over to Glance to support exception catching into # standard HTTP errors. res = req.get_response(rserver.API()) self.assertEquals(res.status_int, webob.exc.HTTPBadRequest.code) def test_update_image(self): """Tests that the /images PUT registry API updates the image""" fixture = {'name': 'fake public image #2', 'type': 'ramdisk' } req = webob.Request.blank('/images/2') req.method = 'PUT' req.body = json.dumps(dict(image=fixture)) res = req.get_response(rserver.API()) self.assertEquals(res.status_int, 200) res_dict = json.loads(res.body) for k, v in fixture.iteritems(): self.assertEquals(v, res_dict['image'][k]) def test_update_image_not_existing(self): """Tests proper exception is raised if attempt to update non-existing image""" fixture = {'id': 3, 'name': 'fake public image', 'is_public': True, 'type': 'kernel', 'status': 'bad status' } req = webob.Request.blank('/images/3') req.method = 'PUT' req.body = json.dumps(dict(image=fixture)) # TODO(jaypipes): Port Nova's Fault infrastructure # over to Glance to support exception catching into # standard HTTP errors. res = req.get_response(rserver.API()) self.assertEquals(res.status_int, webob.exc.HTTPNotFound.code) def test_delete_image(self): """Tests that the /images DELETE registry API deletes the image""" # Grab the original number of images req = webob.Request.blank('/images') res = req.get_response(rserver.API()) res_dict = json.loads(res.body) self.assertEquals(res.status_int, 200) orig_num_images = len(res_dict['images']) # Delete image #2 req = webob.Request.blank('/images/2') req.method = 'DELETE' res = req.get_response(rserver.API()) self.assertEquals(res.status_int, 200) # Verify one less image req = webob.Request.blank('/images') res = req.get_response(rserver.API()) res_dict = json.loads(res.body) self.assertEquals(res.status_int, 200) new_num_images = len(res_dict['images']) self.assertEquals(new_num_images, orig_num_images - 1) def test_delete_image_not_existing(self): """Tests proper exception is raised if attempt to delete non-existing image""" req = webob.Request.blank('/images/3') req.method = 'DELETE' # TODO(jaypipes): Port Nova's Fault infrastructure # over to Glance to support exception catching into # standard HTTP errors. res = req.get_response(rserver.API()) self.assertEquals(res.status_int, webob.exc.HTTPNotFound.code) class TestGlanceAPI(unittest.TestCase): def setUp(self): """Establish a clean test environment""" self.stubs = stubout.StubOutForTesting() stubs.stub_out_registry_and_store_server(self.stubs) stubs.stub_out_registry_db_image_api(self.stubs) stubs.stub_out_filesystem_backend() self.orig_filesystem_store_datadir = FLAGS.filesystem_store_datadir FLAGS.filesystem_store_datadir = stubs.FAKE_FILESYSTEM_ROOTDIR def tearDown(self): """Clear the test environment""" FLAGS.filesystem_store_datadir = self.orig_filesystem_store_datadir stubs.clean_out_fake_filesystem_backend() self.stubs.UnsetAll() def test_add_image_no_location_no_image_as_body(self): """Tests creates a queued image for no body and no loc header""" fixture_headers = {'x-image-meta-store': 'file', 'x-image-meta-name': 'fake image #3'} req = webob.Request.blank("/images") req.method = 'POST' for k, v in fixture_headers.iteritems(): req.headers[k] = v res = req.get_response(server.API()) self.assertEquals(res.status_int, httplib.OK) res_body = json.loads(res.body)['image'] self.assertEquals('queued', res_body['status']) def test_add_image_bad_store(self): """Tests raises BadRequest for invalid store header""" fixture_headers = {'x-image-meta-store': 'bad', 'x-image-meta-name': 'fake image #3'} req = webob.Request.blank("/images") req.method = 'POST' for k, v in fixture_headers.iteritems(): req.headers[k] = v req.headers['Content-Type'] = 'application/octet-stream' req.body = "chunk00000remainder" res = req.get_response(server.API()) self.assertEquals(res.status_int, webob.exc.HTTPBadRequest.code) def test_add_image_basic_file_store(self): """Tests raises BadRequest for invalid store header""" fixture_headers = {'x-image-meta-store': 'file', 'x-image-meta-name': 'fake image #3'} req = webob.Request.blank("/images") req.method = 'POST' for k, v in fixture_headers.iteritems(): req.headers[k] = v req.headers['Content-Type'] = 'application/octet-stream' req.body = "chunk00000remainder" res = req.get_response(server.API()) self.assertEquals(res.status_int, 200) res_body = json.loads(res.body)['image'] self.assertEquals(res_body['location'], 'file:///tmp/glance-tests/3') def test_image_meta(self): """Test for HEAD /images/""" expected_headers = {'x-image-meta-id': 2, 'x-image-meta-name': 'fake image #2'} req = webob.Request.blank("/images/2") req.method = 'HEAD' res = req.get_response(server.API()) self.assertEquals(res.status_int, 200) for key, value in expected_headers.iteritems(): self.assertEquals(value, res.headers[key]) def test_show_image_basic(self): req = webob.Request.blank("/images/2") res = req.get_response(server.API()) self.assertEqual('chunk00000remainder', res.body) def test_show_non_exists_image(self): req = webob.Request.blank("/images/42") res = req.get_response(server.API()) self.assertEquals(res.status_int, webob.exc.HTTPNotFound.code) def test_delete_image(self): req = webob.Request.blank("/images/2") req.method = 'DELETE' res = req.get_response(server.API()) self.assertEquals(res.status_int, 200) req = webob.Request.blank("/images/2") req.method = 'GET' res = req.get_response(server.API()) self.assertEquals(res.status_int, webob.exc.HTTPNotFound.code, res.body) def test_delete_non_exists_image(self): req = webob.Request.blank("/images/42") req.method = 'DELETE' res = req.get_response(server.API()) self.assertEquals(res.status_int, webob.exc.HTTPNotFound.code)