def __init__(self, registry=None): if registry is None: self.registry = NonePersistentRegistry() elif isinstance(registry, Registry): self.registry = registry else: raise AttributeError('Registry needs to derive from abstract' \ ' class \'Registry\'') self.registry.set_renderer('text/occi', TextOcciRendering(self.registry)) self.registry.set_renderer('text/plain', TextPlainRendering(self.registry)) self.registry.set_renderer('text/uri-list', TextUriListRendering(self.registry)) self.registry.set_renderer('text/html', HTMLRendering(self.registry)) application = tornado.web.Application([ (r"/-/", QueryHandler, dict(registry=self.registry)), (r"/.well-known/org/ogf/occi/-/", QueryHandler, dict(registry=self.registry)), (r"(.*)/", CollectionHandler, dict(registry=self.registry)), (r"(.*)", ResourceHandler, dict(registry=self.registry)), ]) self.http_server = tornado.httpserver.HTTPServer(application)
class TestTextURIListRendering(unittest.TestCase): ''' Test the uri-list rendering. ''' registry = NonePersistentRegistry() def setUp(self): self.rendering = TextUriListRendering(self.registry) def test_from_entities_for_sanity(self): ''' Test uri listings... ''' res = Resource('/foo/123', None, []) entities = [res] heads, body = self.rendering.from_entities(entities, 'foo') self.assertTrue(heads == {}) self.assertTrue(res.identifier in body) def test_not_support_thrown_for_success(self): ''' Tests is attr-exp are thrown for unsupported operations. ''' self.assertRaises(AttributeError, self.rendering.to_entity, None, None, None) self.assertRaises(AttributeError, self.rendering.from_entity, None) self.assertRaises(AttributeError, self.rendering.to_entities, None, None) self.assertRaises(AttributeError, self.rendering.from_categories, None) self.assertRaises(AttributeError, self.rendering.to_action, None, None) self.assertRaises(AttributeError, self.rendering.to_mixins, None, None) self.assertRaises(AttributeError, self.rendering.get_filters, None, None)
class TestTextPlainRendering(unittest.TestCase): ''' Test the text / plain rendering. This is simple since it's derived from text/occi rendering. ''' registry = NonePersistentRegistry() def setUp(self): self.rendering = TextPlainRendering(self.registry) def test_data_routines_for_sanity(self): ''' Test if set and get data are overwritten and work properly ''' headers = {} body = 'Category: foo\n' \ 'Category: foo,bar\n' \ 'Link: bar\n' \ 'Link: foo,bar\n' \ 'X-OCCI-Location: foo,bar\n' \ 'X-OCCI-Location: bar\n' \ 'X-OCCI-Attribute: foo\n' \ 'X-OCCI-Attribute: bar,foo\n' data = self.rendering.get_data(headers, body) headers, body = self.rendering.set_data(data) self.assertTrue(body.count('Category') == 3) self.assertTrue(body.count('Link') == 3) self.assertTrue(body.count('X-OCCI-Attribute') == 3) self.assertTrue(body.count('X-OCCI-Location') == 3)
class CategoryRegistryTest(unittest.TestCase): ''' Test the capabilities to retrieve categories. ''' registry = NonePersistentRegistry() def setUp(self): self.kind1 = Kind('http://example.com#', '1') self.kind2 = Kind('http://example.com#', '2', location='/foo/') self.registry.set_backend(self.kind1, KindBackend()) self.registry.set_backend(self.kind2, DummyBackend()) def tearDown(self): for item in self.registry.get_categories(): self.registry.delete_mixin(item) def test_get_category_for_sanity(self): ''' Test if the category can be retrieved from a URN. ''' result = self.registry.get_category('/1/') self.assertTrue(self.kind1 == result) result = self.registry.get_category('/foo/') self.assertTrue(self.kind2 == result) result = self.registry.get_category('/bar/') self.assertTrue(result == None)
def test_init_for_success(self): ''' Test init... ''' parser = HTMLRendering(NonePersistentRegistry(), css='body {background: #d00;}') self.assertEquals(parser.css, 'body {background: #d00;}')
class TestService(unittest.TestCase): ''' Test the service extension point. ''' registry = NonePersistentRegistry() def setUp(self): self.service = OCCI() def test_init_for_sanity(self): ''' Test constructor and initialization of service. ''' self.assertTrue(self.registry.get_renderer('text/occi')) self.assertTrue(self.registry.get_renderer('text/plain')) self.assertTrue(self.registry.get_renderer('text/uri-list')) self.assertTrue(self.registry.get_renderer('text/html')) OCCI(registry=NonePersistentRegistry()) def test_register_backend_for_failure(self): ''' Test registration. ''' back = ActionBackend() self.assertRaises(AttributeError, self.service.register_backend, COMPUTE, back) try: OCCI(registry=dict()) except AttributeError: pass else: self.assertFalse(True, 'Exception not thrown...') def test_register_backend_for_sanity(self): ''' Test registration. ''' back = KindBackend() back1 = MixinBackend() back2 = ActionBackend() self.service.register_backend(COMPUTE, back) self.service.register_backend(IPNETWORKINTERFACE, back1) self.service.register_backend(START, back2) self.assertTrue(self.registry.get_backend(COMPUTE) == back) self.assertTrue(self.registry.get_backend(IPNETWORKINTERFACE) == back1) self.assertTrue(self.registry.get_backend(START) == back2) def test_start_for_success(self): ''' Just here to reach 100% code coverage :-) ''' self.service.http_server.listen = fake_listen tornado.ioloop.IOLoop.instance = fake_ioloop self.service.start(1010)
def __init__(self, application, request, **kwargs): super(BaseHandler, self).__init__(application, request, **kwargs) # This ensures that at least one registry is loaded in case initialize # is not called for some reason... self.registry = NonePersistentRegistry() if self.registry.get_hostname() == '': self.registry.set_hostname(self.request.protocol + '://' + self.request.host)
def test_init_for_sanity(self): ''' Test constructor and initialization of service. ''' self.assertTrue(self.registry.get_renderer('text/occi')) self.assertTrue(self.registry.get_renderer('text/plain')) self.assertTrue(self.registry.get_renderer('text/uri-list')) self.assertTrue(self.registry.get_renderer('text/html')) OCCI(registry=NonePersistentRegistry())
class TestHTMLRendering(unittest.TestCase): ''' Just some simple calls on the HTML rendering. ''' parser = HTMLRendering(NonePersistentRegistry()) def setUp(self): action = Action('http://example.com/foo#', 'action') self.kind = Kind('http://example.com/foo#', 'bar', 'http://schemeas.ogf.org/occi/core#', [action], 'Some bla bla', {'foo': 'required', 'foo2': 'immutable', 'bar': ''}, '/foo/') mixin = Mixin('http://example.com/foo#', 'mixin') action = Action('http://example.com/foo#', 'action') self.target = Resource('/foo/target', self.kind, [], []) self.source = Resource('/foo/src', self.kind, [mixin], []) self.link = Link('/link/foo', self.kind, [], self.source, self.target) self.source.links = [self.link] self.source.actions = [action] #========================================================================== # Success #========================================================================== def test_init_for_success(self): ''' Test init... ''' parser = HTMLRendering(NonePersistentRegistry(), css='body {background: #d00;}') self.assertEquals(parser.css, 'body {background: #d00;}') def test_from_entity_for_success(self): ''' Test from entity... ''' self.parser.from_entity(self.source) self.parser.from_entity(self.link) def test_from_entities_for_success(self): ''' Test from entities... ''' self.parser.from_entities([self.source], '/foo/') self.parser.from_entities([], '/') def test_from_categories_for_success(self): ''' Test from categories... ''' self.parser.from_categories([self.kind])
class TestParserRegistry(unittest.TestCase): ''' Test if parser can be found... ''' registry = NonePersistentRegistry() def setUp(self): self.registry.set_renderer('text/plain', DummyRendering(self.registry)) self.registry.set_renderer('text/occi', DummyRendering(self.registry)) def tearDown(self): for item in self.registry.get_categories(): self.registry.delete_mixin(item) def test_get_parser_for_success(self): ''' Test retrieval of parsers. ''' self.registry.get_renderer('text/plain') self.registry.get_renderer('text/occi') def test_get_parser_for_failure(self): ''' Test failure handling of retrieval. ''' self.assertRaises(HTTPError, self.registry.get_renderer, 'foo') def test_set_parser_for_failure(self): ''' Test failure handling of setting a renderer. ''' self.assertRaises(AttributeError, self.registry.set_renderer, 'foo', None) def test_get_parser_for_sanity(self): ''' Some sanity checks. ''' parser1 = self.registry.get_renderer('text/plain') parser2 = self.registry.get_renderer('text/plain;q=0.9') parser3 = self.registry.get_renderer('*/*') self.assertEquals(parser1, parser3) self.assertEquals(parser2, parser3)
class TestMisc(unittest.TestCase): ''' Several other tests... ''' registry = NonePersistentRegistry() def setUp(self): self.app = Application([(r"(.*)", ResourceWrapper)]) def test_get_error_html_for_success(self): ''' Test retrieval of Error codes... ''' handler = BaseHandler(self.app, create_request('GET', {}, ''), registry=self.registry) handler.get_error_html(200)
class ResourcesTest(unittest.TestCase): ''' Tests the reigstry's resource handling. ''' registry = NonePersistentRegistry() def setUp(self): self.res1 = Resource('foo', None, None) self.res2 = Resource('bar', None, None) def tearDown(self): for resource in self.registry.get_resources(): self.registry.delete_resource(resource.identifier) def test_get_resource_for_sanity(self): ''' Test if added resource can be retrieved. ''' self.registry.add_resource('foo', self.res1) self.assertEquals(self.res1, self.registry.get_resource('foo')) def test_delete_resource_for_sanity(self): ''' Test if delete resource cannot be retrieved. ''' self.registry.add_resource('foo', self.res1) self.registry.delete_resource('foo') self.assertRaises(KeyError, self.registry.get_resource, 'foo') def test_resources_for_sanity(self): ''' Test is all resources and all keys can be retrieved. ''' self.registry.add_resource('foo', self.res1) self.registry.add_resource('bar', self.res2) self.assertTrue(len(self.registry.get_resources()) == 2) self.assertTrue(len(self.registry.get_resource_keys()) == 2)
class TestRendering(unittest.TestCase): ''' Test for the abstract Rendering class. ''' registry = NonePersistentRegistry() def test_if_not_implemented_is_thrown(self): ''' Just to check the abstract class. ''' rendering = Rendering(self.registry) self.assertRaises(NotImplementedError, rendering.to_entity, None, None, None) self.assertRaises(NotImplementedError, rendering.to_action, None, None) self.assertRaises(NotImplementedError, rendering.to_entities, None, None) self.assertRaises(NotImplementedError, rendering.to_mixins, None, None) self.assertRaises(NotImplementedError, rendering.get_filters, None, None) self.assertRaises(NotImplementedError, rendering.from_entity, None) self.assertRaises(NotImplementedError, rendering.from_categories, None) self.assertRaises(NotImplementedError, rendering.from_entities, None, None)
class TestCollectionCapabilites(unittest.TestCase): ''' Test the collection handler. ''' registry = NonePersistentRegistry() def setUp(self): self.registry.set_hostname('http://127.0.0.1') self.app = Application([(r"(.*)/", CollectionWrapper)]) self.registry.set_renderer('text/plain', TextPlainRendering(self.registry)) self.registry.set_renderer('text/occi', TextOcciRendering(self.registry)) self.registry.set_renderer('text/uri-list', TextUriListRendering(self.registry)) self.mixin = Mixin('foo', 'mystuff') self.compute = Resource('/compute/1', COMPUTE, []) self.compute.attributes = {'foo2': 'bar2'} self.network = Resource('/network/1', NETWORK, [IPNETWORK]) self.network_interface = Link('/network/interface/1', NETWORKINTERFACE, [IPNETWORKINTERFACE], self.compute, self.network) self.registry.set_backend(COMPUTE, SimpleComputeBackend()) self.registry.set_backend(NETWORK, KindBackend()) self.registry.set_backend(self.mixin, MixinBackend()) self.registry.set_backend(START, SimpleComputeBackend()) self.registry.add_resource(self.compute.identifier, self.compute) self.registry.add_resource(self.network.identifier, self.network) self.registry.add_resource(self.network_interface.identifier, self.network_interface) def tearDown(self): for item in self.registry.get_resources(): self.registry.delete_resource(item.identifier) #========================================================================== # Failure #========================================================================== def test_retrieve_for_failure(self): ''' Do a get with garbeage as filter... ''' headers = {'Content-Type': 'text/occi', 'Category': 'asdf'} request = create_request('GET', headers, '') handler = CollectionWrapper(self.app, request) self.assertRaises(HTTPError, handler.get, '') def test_action_for_failure(self): ''' Tests if actions can be triggered with garbage as content ''' headers = {'Content-Type': 'text/occi', 'Category': 'foobar'} request = create_request('POST', headers, '', '/compute/?action=start') handler = CollectionWrapper(self.app, request) self.assertRaises(HTTPError, handler.post, '') def test_update_mixin_collection_for_failure(self): ''' Add mixins to resources. ''' headers = { 'Content-Type': 'text/occi', 'X-Occi-Location': self.compute.identifier } request = create_request('POST', headers, '') handler = CollectionWrapper(self.app, request) self.assertRaises(HTTPError, handler.post, '/bla') def test_remove_entities_from_collection_for_failure(self): ''' Add mixins to resources. ''' headers = { 'Content-Type': 'text/occi', 'X-Occi-Location': self.compute.identifier } request = create_request('DELETE', headers, '') handler = CollectionWrapper(self.app, request) self.assertRaises(HTTPError, handler.delete, '/bla/') headers = { 'Content-Type': 'text/xml', 'X-Occi-Location': self.compute.identifier } request = create_request('DELETE', headers, '') handler = CollectionWrapper(self.app, request) self.assertRaises(HTTPError, handler.delete, '/bla/') def test_replace_mixin_collection_for_failure(self): ''' Add mixins to resources. ''' headers = { 'Content-Type': 'text/occi', 'X-Occi-Location': self.network.identifier } request = create_request('PUT', headers, '') handler = CollectionWrapper(self.app, request) self.assertRaises(HTTPError, handler.put, '/bla') def test_create_entity_for_failure(self): ''' Simple test - more complex one in TestResourceHandler... ''' headers = { 'Content-Type': 'text/xml', 'Categories': parser.get_category_str(COMPUTE) } request = create_request('POST', headers, '') handler = CollectionWrapper(self.app, request) self.assertRaises(HTTPError, handler.post, '/compute') headers = { 'Content-Type': 'text/occi', 'Categories': parser.get_category_str(COMPUTE) } request = create_request('POST', headers, '') handler = CollectionWrapper(self.app, request) self.assertRaises(HTTPError, handler.post, '/compute') #========================================================================== # Sanity #========================================================================== def test_retrieve_state_of_ns_for_sanity(self): ''' Test GET with uri-list ''' headers = {'Accept': 'text/uri-list'} request = create_request('GET', headers, '') handler = CollectionWrapper(self.app, request) handler.get('') headers, body = handler.get_output() self.assertTrue(headers['Content-Type'] == 'text/uri-list') self.assertTrue(len(body) == 98) def test_retrieve_for_sanity(self): ''' Test GET with uri-list ''' headers = {'Accept': 'text/occi'} request = create_request('GET', headers, '') handler = CollectionWrapper(self.app, request) handler.get('/compute/') headers, body = handler.get_output() self.assertTrue(headers['Content-Type'] == 'text/occi') self.assertTrue(self.compute.identifier in headers['X-OCCI-Location']) # filter on category headers = { 'Accept': 'text/occi', 'Content-Type': 'text/occi', 'Category': parser.get_category_str(self.compute.kind) } request = create_request('GET', headers, '') handler = CollectionWrapper(self.app, request) handler.get('/') headers, body = handler.get_output() self.assertTrue(headers['Content-Type'] == 'text/occi') self.assertTrue(self.compute.identifier in headers['X-OCCI-Location']) self.assertFalse(self.network.identifier in headers['X-OCCI-Location']) # filter on attr... headers = { 'Accept': 'text/occi', 'Content-Type': 'text/occi', 'X-Occi-Attribute': 'foo2="bar2"' } request = create_request('GET', headers, '') handler = CollectionWrapper(self.app, request) handler.get('/') headers, body = handler.get_output() self.assertTrue(headers['Content-Type'] == 'text/occi') self.assertTrue(self.compute.identifier in headers['X-OCCI-Location']) self.assertFalse(self.network.identifier in headers['X-OCCI-Location']) def test_delete_for_sanity(self): ''' Tests if complete resource collection can be removed. ''' request = create_request('DELETE', {}, '') handler = CollectionWrapper(self.app, request) handler.delete('/compute') self.assertFalse(self.compute in self.registry.get_resources()) def test_action_for_sanity(self): ''' Tests if actions can be triggered on a resource set. ''' headers = { 'Content-Type': 'text/occi', 'Category': parser.get_category_str(START) } request = create_request('POST', headers, '', '/compute/?action=start') handler = CollectionWrapper(self.app, request) handler.post('/compute/') self.assertTrue( self.compute.attributes['occi.compute.state'] == 'active') def test_update_mixin_collection_for_sanity(self): ''' Add mixins to resources. ''' headers = { 'Content-Type': 'text/occi', 'X-Occi-Location': self.compute.identifier } request = create_request('POST', headers, '') handler = CollectionWrapper(self.app, request) handler.post('/mystuff/') self.assertTrue(self.mixin in self.compute.mixins) def test_remove_entities_from_collection_for_sanity(self): ''' Add mixins to resources. ''' headers = { 'Content-Type': 'text/occi', 'X-Occi-Location': self.compute.identifier } request = create_request('POST', headers, '') handler = CollectionWrapper(self.app, request) handler.post('/mystuff/') headers = { 'Content-Type': 'text/occi', 'X-Occi-Location': self.compute.identifier } request = create_request('DELETE', headers, '') handler = CollectionWrapper(self.app, request) handler.delete('/mystuff/') self.assertTrue(self.mixin not in self.compute.mixins) def test_replace_mixin_collection_for_sanity(self): ''' Add mixins to resources. ''' headers = { 'Content-Type': 'text/occi', 'X-Occi-Location': self.compute.identifier } request = create_request('POST', headers, '') handler = CollectionWrapper(self.app, request) handler.post('/mystuff/') headers = { 'Content-Type': 'text/occi', 'X-Occi-Location': self.network.identifier } request = create_request('PUT', headers, '') handler = CollectionWrapper(self.app, request) handler.put('/mystuff/') self.assertTrue(self.mixin not in self.compute.mixins) self.assertTrue(self.mixin in self.network.mixins) def test_create_entity_for_sanity(self): ''' Simple test - more complex one in TestResourceHandler... ''' headers = { 'Content-Type': 'text/occi', 'Category': parser.get_category_str(COMPUTE) } request = create_request('POST', headers, '') handler = CollectionWrapper(self.app, request) handler.post('/compute/') self.assertTrue(len(self.registry.get_resources()) == 4)
class TestBackendsRegistry(unittest.TestCase): ''' Test for the registry. ''' registry = NonePersistentRegistry() def setUp(self): self.kind1 = Kind('http://example.com#', '1') self.kind2 = Kind('http://example.com#', '2') self.action = Action('http://example.com#', 'action') self.mixin = Mixin('http://example.com#', 'mixin') self.registry.set_backend(self.kind1, KindBackend()) self.registry.set_backend(self.kind2, DummyBackend()) self.registry.set_backend(self.action, ActionBackend()) self.registry.set_backend(self.mixin, MixinBackend()) self.entity = Resource('foo', self.kind1, [self.kind2]) def tearDown(self): for item in self.registry.get_categories(): self.registry.delete_mixin(item) #========================================================================== # Success #========================================================================== def test_get_backend_for_success(self): ''' Test if backend can be retrieved... ''' self.registry.get_backend(self.kind1) self.registry.get_backend(self.kind2) self.registry.get_backend(self.action) self.registry.get_backend(self.mixin) #========================================================================== # Failure #========================================================================== def test_get_backend_for_failure(self): ''' Test if backend can be retrieved... ''' self.assertRaises(AttributeError, self.registry.get_backend, Kind('foo', 'bar')) #========================================================================== # Sanity #========================================================================== def test_get_backend_for_sanity(self): ''' Test if backend can be retrieved... ''' back1 = self.registry.get_backend(self.kind1) back2 = self.registry.get_backend(self.kind2) self.assertTrue(isinstance(back1, KindBackend)) self.assertTrue(isinstance(back2, DummyBackend)) def test_get_all_backends_for_sanity(self): ''' Test if all backends can be retrieved... ''' backs = self.registry.get_all_backends(self.entity) self.assertTrue(len(backs) == 2)
class CollectionWorkflowTest(unittest.TestCase): ''' Test the workflow on operations on collections... ''' registry = NonePersistentRegistry() def setUp(self): self.kind = Kind('http://example.com/foo#', 'bar') self.link_kind = Kind('http://example.com/foo#', 'link') self.mixin = Mixin('http://example.com/foo#', 'mixin') target = Resource('/foo/target', self.kind, [], []) source = Resource('/foo/src', self.kind, [self.mixin], []) source.attributes = {'foo': 'bar'} link = Link('/link/foo', self.link_kind, [], source, target) link.attributes = {'foo': 'bar'} source.links = [link] self.resources = [source, target, link] for item in self.resources: self.registry.add_resource(item.identifier, item) self.registry.set_backend(self.kind, KindBackend()) self.registry.set_backend(self.mixin, MixinBackend()) def tearDown(self): for item in self.registry.get_resources(): self.registry.delete_resource(item.identifier) for item in self.registry.get_categories(): self.registry.delete_mixin(item) #========================================================================== # Success #========================================================================== def test_get_entities_for_success(self): ''' Tests retrieval of resources. ''' lst = workflow.get_entities_under_path('/', self.registry) self.assertTrue(self.resources[0] in lst) def test_filter_entities_for_success(self): ''' Call the filter test. ''' workflow.filter_entities(self.resources, [], {}) workflow.filter_entities(self.resources, [self.kind], {}) workflow.filter_entities(self.resources, [], {'foo': 'bar'}) #========================================================================== # Failure #========================================================================== def test_update_collection_for_failure(self): ''' Check if the update functionalities are implemented correctly. ''' self.assertRaises(AttributeError, workflow.update_collection, self.kind, [], [], self.registry) def test_replace_collection_for_failure(self): ''' Check if the replace functionalities are implemented correctly. ''' self.assertRaises(AttributeError, workflow.replace_collection, self.kind, [], [], self.registry) def test_delete_from_collection_for_failure(self): ''' Check if the delete functionalities are implemented correctly. ''' self.assertRaises(AttributeError, workflow.delete_from_collection, self.kind, [], self.registry) #========================================================================== # Sanity #========================================================================== def test_get_entities_for_sanity(self): ''' Test if correct entities are returned. ''' lst = workflow.get_entities_under_path('/link/', self.registry) self.assertTrue(self.resources[2] in lst) self.assertTrue(len(lst) == 1) lst = workflow.get_entities_under_path('/bar/', self.registry) self.assertTrue(self.resources[0] in lst) self.assertTrue(self.resources[1] in lst) self.assertTrue(len(lst) == 2) def test_update_collection_for_sanity(self): ''' Check if the update functionalities are implemented correctly. ''' res1 = Resource('/foo/target', self.kind, [self.mixin], []) res2 = Resource('/foo/target', self.kind, [], []) workflow.update_collection(self.mixin, [res1], [res2], self.registry) self.assertTrue(self.mixin in res1.mixins) self.assertTrue(self.mixin in res2.mixins) def test_replace_collection_for_sanity(self): ''' Check if the replace functionalities are implemented correctly. ''' res1 = Resource('/foo/target', self.kind, [self.mixin], []) res2 = Resource('/foo/target', self.kind, [], []) workflow.replace_collection(self.mixin, [res1], [res2], self.registry) self.assertTrue(self.mixin not in res1.mixins) self.assertTrue(self.mixin in res2.mixins) def test_delete_from_collection_for_sanity(self): ''' Check if the delete functionalities are implemented correctly. ''' res1 = Resource('/foo/1', self.kind, [self.mixin], []) res2 = Resource('/foo/2', self.kind, [self.mixin], []) self.registry.add_resource('/foo/1', res1) self.registry.add_resource('/foo/2', res2) workflow.delete_from_collection(self.mixin, [res2], self.registry) self.assertTrue(self.mixin not in res2.mixins) self.assertTrue(self.mixin in res1.mixins) def test_filter_entities_for_sanity(self): ''' Check if the filter operates correctly. ''' # return all res = workflow.filter_entities(self.resources, [], {}) self.assertTrue(self.resources[0] in res) self.assertTrue(self.resources[1] in res) self.assertTrue(self.resources[2] in res) self.assertTrue(len(res) == 3) # return just the two resources res = workflow.filter_entities(self.resources, [self.kind], {}) self.assertTrue(self.resources[0] in res) self.assertTrue(self.resources[1] in res) self.assertTrue(len(res) == 2) # return source and link res = workflow.filter_entities(self.resources, [], {'foo': 'bar'}) self.assertTrue(self.resources[0] in res) self.assertTrue(self.resources[2] in res) self.assertTrue(len(res) == 2) # return just the source res = workflow.filter_entities(self.resources, [self.mixin], {}) self.assertTrue(self.resources[0] in res) self.assertTrue(len(res) == 1) # return just the source and link res = workflow.filter_entities(self.resources, [self.mixin, self.link_kind], {}) self.assertTrue(self.resources[0] in res) self.assertTrue(self.resources[2] in res) self.assertTrue(len(res) == 2) # return just the link... res = workflow.filter_entities(self.resources, [self.kind], {'foo': 'bar'}) self.assertTrue(self.resources[0] in res) self.assertTrue(len(res) == 1)
class QueriyInterfaceTest(unittest.TestCase): ''' Tests the QI routines. ''' registry = NonePersistentRegistry() def setUp(self): self.kind1 = Kind('http://www.example.com#', 'foo') self.kind2 = Kind('http://www.example.com#', 'bar') self.mixin = Mixin('http://www.example.com#', 'mixin') self.registry.set_backend(self.kind1, KindBackend()) self.registry.set_backend(self.kind2, KindBackend()) def tearDown(self): for item in self.registry.get_categories(): self.registry.delete_mixin(item) #========================================================================== # Failure #========================================================================== def test_append_mixins_for_failure(self): ''' Test if exception is thrown. ''' # is not a mixin self.assertRaises(AttributeError, workflow.append_mixins, [self.kind2], self.registry) # location collision mixin = Mixin('http://www.new.com#', 'mixin', location="/foo/") self.assertRaises(AttributeError, workflow.append_mixins, [mixin], self.registry) # name collision mixin = Mixin('http://www.example.com#', 'foo', location="/stuff/") self.assertRaises(AttributeError, workflow.append_mixins, [mixin], self.registry) def test_remove_mixins_for_failure(self): ''' Test if only correct mixin get removed... ''' mixin = Mixin('http://www.new.com#', 'mixin') self.registry.set_backend(mixin, MixinBackend()) # not userdefined backend self.assertRaises(HTTPError, workflow.remove_mixins, [mixin], self.registry) # not registeres self.assertRaises(HTTPError, workflow.remove_mixins, [self.mixin], self.registry) # kind self.assertRaises(AttributeError, workflow.remove_mixins, [self.kind1], self.registry) #========================================================================== # Sanity #========================================================================== def test_filter_categories_for_sanity(self): ''' Test the simple filter options. ''' res = workflow.filter_categories([], self.registry) self.assertTrue(self.kind1 in res) self.assertTrue(self.kind2 in res) self.assertTrue(len(res) == 2) res = workflow.filter_categories([self.kind1], self.registry) self.assertTrue(self.kind1 in res) self.assertFalse(self.kind2 in res) self.assertTrue(len(res) == 1) def test_append_mixins_for_sanity(self): ''' Test if mixins get appended. ''' workflow.append_mixins([self.mixin], self.registry) self.assertTrue(self.mixin in self.registry.get_categories()) self.assertTrue( isinstance(self.registry.get_backend(self.mixin), MixinBackend)) def test_remove_mixins_for_sanity(self): ''' Test if mixin get removed. ''' workflow.append_mixins([self.mixin], self.registry) res = Resource('/foo/1', self.kind1, [self.mixin]) self.registry.add_resource('/foo/1', res) workflow.remove_mixins([self.mixin], self.registry) self.assertFalse(self.mixin in self.registry.get_categories()) self.assertFalse(self.mixin in res.mixins)
class OCCI(object): ''' A OCCI compatible service. ''' # disabling 'Method could be func' pylint check (this is for extension) # pylint: disable=R0201 def __init__(self, registry=None): if registry is None: self.registry = NonePersistentRegistry() elif isinstance(registry, Registry): self.registry = registry else: raise AttributeError('Registry needs to derive from abstract' \ ' class \'Registry\'') self.registry.set_renderer('text/occi', TextOcciRendering(self.registry)) self.registry.set_renderer('text/plain', TextPlainRendering(self.registry)) self.registry.set_renderer('text/uri-list', TextUriListRendering(self.registry)) self.registry.set_renderer('text/html', HTMLRendering(self.registry)) application = tornado.web.Application([ (r"/-/", QueryHandler, dict(registry=self.registry)), (r"/.well-known/org/ogf/occi/-/", QueryHandler, dict(registry=self.registry)), (r"(.*)/", CollectionHandler, dict(registry=self.registry)), (r"(.*)", ResourceHandler, dict(registry=self.registry)), ]) self.http_server = tornado.httpserver.HTTPServer(application) def register_backend(self, category, backend): ''' Register a backend. Verifies that correct 'parent' backends are used. category -- The category the backend defines. backend -- The backend which handles the given category. ''' allow = False if repr(category) == 'kind' and isinstance(backend, KindBackend): allow = True elif repr(category) == 'mixin' and isinstance(backend, MixinBackend): allow = True elif repr(category) == 'action' and isinstance(backend, ActionBackend): allow = True if allow: self.registry.set_backend(category, backend) else: raise AttributeError('Backends handling kinds need to derive' \ ' from KindBackend; Backends handling' \ ' actions need to derive from' \ ' ActionBackend and backends handling' \ ' mixins need to derive from MixinBackend.') def start(self, port): ''' Start the service. ''' self.http_server.listen(port) tornado.ioloop.IOLoop.instance().start()
class TestQueryCapabilites(unittest.TestCase): ''' Test the QI. ''' registry = NonePersistentRegistry() def setUp(self): self.app = Application([(r"/-/", QueryWrapper)]) self.registry.set_renderer('text/occi', TextOcciRendering(self.registry)) backend = KindBackend() self.registry.set_backend(COMPUTE, backend) self.registry.set_backend(STORAGE, backend) self.registry.set_backend(NETWORK, backend) def tearDown(self): for item in self.registry.get_categories(): self.registry.delete_mixin(item) #========================================================================== # Failure #========================================================================== def test_retrieval_for_failure(self): ''' Tests failure handling on retrieval... ''' # faulty accept header headers = {'Content-Type': 'text/occi', 'Category': 'sldkfj'} request = create_request('GET', headers, '') handler = QueryWrapper(self.app, request) self.assertRaises(HTTPError, handler.get) def test_add_mixin_for_failure(self): ''' Test failure handling off adding mixins. ''' # missing locaction -> reject headers = { 'Accept': 'text/occi', 'Content-Type': 'text/occi', 'Category': 'foo; scheme="http://example.com#"' } request = create_request('GET', headers, '') handler = QueryWrapper(self.app, request) self.assertRaises(HTTPError, handler.post) # existing location -> reject headers = {'Accept': 'text/occi', 'Content-Type': 'text/occi', 'Category': 'foo; scheme="http://example.com#";' \ ' location="/compute/"'} request = create_request('GET', headers, '') handler = QueryWrapper(self.app, request) self.assertRaises(HTTPError, handler.post) # faulty location -> reject headers = {'Accept': 'text/occi', 'Content-Type': 'text/occi', 'Category': 'foo; scheme="http://example.com#";' \ ' location="/sdf"'} request = create_request('GET', headers, '') handler = QueryWrapper(self.app, request) self.assertRaises(HTTPError, handler.post) # already existing... headers = {'Accept': 'text/occi', 'Content-Type': 'text/occi', 'Category': 'compute; scheme="http://schemas.ogf.org' \ '/occi/infrastructure#";' \ ' location="/bla/"'} request = create_request('GET', headers, '') handler = QueryWrapper(self.app, request) self.assertRaises(HTTPError, handler.post) def test_remove_mixin_for_failure(self): ''' Test failure handling off removing mixins. ''' # missing locaction -> reject headers = { 'Accept': 'text/occi', 'Content-Type': 'text/occi', 'Category': 'foo; scheme="http://example.com#"' } request = create_request('DELETE', headers, '') handler = QueryWrapper(self.app, request) self.assertRaises(HTTPError, handler.delete) # not available headers = {'Accept': 'text/occi', 'Content-Type': 'text/occi', 'Category': 'foo2; scheme="http://example.com#";' \ ' location="/foo/"'} request = create_request('DELETE', headers, '') handler = QueryWrapper(self.app, request) self.assertRaises(HTTPError, handler.delete) #========================================================================== # Sanity #========================================================================== def test_retrieval_for_sanity(self): ''' Test HTTP GET on QI. ''' # tests if all 3 kinds can be retrieved. headers = {'Accept': 'text/occi'} request = create_request('GET', headers, '') handler = QueryWrapper(self.app, request) handler.get() headers, body = handler.get_output() self.assertTrue(len(headers['Category'].split(',')) == 3) # test the filtering... headers = { 'Accept': 'text/occi', 'Content-Type': 'text/occi', 'Category': parser.get_category_str(COMPUTE) } request = create_request('GET', headers, '') handler = QueryWrapper(self.app, request) handler.get() headers, body = handler.get_output() self.assertTrue(len(headers['Category'].split(',')) == 1) def test_mixin_for_sanity(self): ''' Test if a user defined mixin can be added. ''' # add a mixin. headers = {'Accept': 'text/occi', 'Content-Type': 'text/occi', 'Category': 'foo; scheme="http://example.com#";' \ ' location="/foo/"'} request = create_request('POST', headers, '') handler = QueryWrapper(self.app, request) handler.post() headers, body = handler.get_output() self.assertTrue(body == 'OK') # remove the mixin. headers = {'Accept': 'text/occi', 'Content-Type': 'text/occi', 'Category': 'foo; scheme="http://example.com#";' \ ' location="/foo/"'} request = create_request('DELETE', headers, '') handler = QueryWrapper(self.app, request) handler.delete() headers, body = handler.get_output() self.assertTrue(body == 'OK')
class TestLinkHandling(unittest.TestCase): ''' Tests links and do request in body for a change :-) ''' registry = NonePersistentRegistry() def setUp(self): self.app = Application([(r"(.*)", ResourceWrapper)]) self.registry.set_renderer('text/plain', TextPlainRendering(self.registry)) self.registry.set_renderer('text/occi', TextOcciRendering(self.registry)) self.registry.set_backend(COMPUTE, SimpleComputeBackend()) self.registry.set_backend(NETWORK, KindBackend()) self.registry.set_backend(NETWORKINTERFACE, KindBackend()) self.registry.set_backend(START, SimpleComputeBackend()) self.compute = Resource('/compute/1', COMPUTE, []) self.network = Resource('/network/1', NETWORK, [IPNETWORK]) self.registry.add_resource('/compute/1', self.compute) self.registry.add_resource('/network/1', self.network) def tearDown(self): for item in self.registry.get_resources(): self.registry.delete_resource(item.identifier) #========================================================================== # Sanity #========================================================================== def test_inline_creation_for_sanity(self): ''' Test creation of compute with a link to network (inline)... ''' headers = {'Content-Type': 'text/occi', 'Category': parser.get_category_str(COMPUTE), 'Link': '</network/1>;' \ 'rel="http://schemas.ogf.org/occi/infrastructure#' \ 'network";' \ 'category="http://schemas.ogf.org/occi/infrastructure#' \ 'networkinterface";' \ 'occi.networkinterface.interface="eth0";' \ 'occi.networkinterface.mac="00:11:22:33:44:55";'} request = create_request('PUT', headers, '') handler = ResourceWrapper(self.app, request) handler.put('/compute/2') self.assertTrue('/compute/2' in self.registry.get_resource_keys()) self.assertTrue(len(self.registry.get_resources()) == 4) compute = self.registry.get_resource('/compute/2') self.assertTrue(len(compute.links) == 1) request = create_request('GET', {}, '') handler = ResourceWrapper(self.app, request) handler.get('/compute/2') heads, body = handler.get_output() self.assertTrue('Link: ' in body) self.assertTrue('self=' in body) def test_link_creation_for_sanity(self): ''' Test creation for sanity... ''' headers = {'Content-Type': 'text/plain'} body = 'Category: ' + parser.get_category_str(NETWORKINTERFACE) + '\n' body += 'X-OCCI-Attribute: occi.core.source="/compute/1"\n' body += 'X-OCCI-Attribute: occi.core.target="/network/1"' request = create_request('PUT', headers, body) handler = ResourceWrapper(self.app, request) handler.put('/link/2') self.assertTrue('/link/2' in self.registry.get_resource_keys()) link = self.registry.get_resource('/link/2') self.assertTrue(link in link.source.links) request = create_request('GET', {}, '') handler = ResourceWrapper(self.app, request) handler.get('/link/2') heads, body = handler.get_output() self.assertTrue('occi.core.target' in body) self.assertTrue('occi.core.source' in body)
class EntityWorkflowTest(unittest.TestCase): ''' Simple tests to test the commands on entities. ''' registry = NonePersistentRegistry() def setUp(self): self.test_kind = Kind('http://example.com#', 'test') self.link_kind = Kind('http://example.com#link', 'link') mixins = [] self.action = Action('http://example.com#', 'action') self.src_entity = Resource(None, self.test_kind, mixins, []) self.trg_entity = Resource('/foo/trg', self.test_kind, mixins, []) self.link1 = Link('/link/1', self.link_kind, [], self.src_entity, self.trg_entity) self.src_entity.links = [self.link1] self.registry.add_resource(self.trg_entity.identifier, self.trg_entity) self.registry.set_backend(self.test_kind, KindBackend()) self.registry.set_backend(self.link_kind, KindBackend()) self.registry.set_backend(self.action, ActionBackend()) def tearDown(self): for item in self.registry.get_resources(): self.registry.delete_resource(item.identifier) #========================================================================== # Success #========================================================================== def test_replace_entity_for_success(self): ''' Test replace... ''' # not much to verify here - just calls backends... workflow.replace_entity(self.src_entity, self.trg_entity, self.registry) def test_update_entity_for_success(self): ''' Test replace... ''' # not much to verify here - just calls backends... workflow.update_entity(self.src_entity, self.trg_entity, self.registry) def test_retrieve_entity_for_success(self): ''' Test replace... ''' # not much to verify here - just calls backends... workflow.retrieve_entity(self.src_entity, self.registry) workflow.retrieve_entity(self.link1, self.registry) def test_action_entity_for_success(self): ''' Test replace... ''' # not much to verify here - just calls backends... workflow.action_entity(self.src_entity, self.action, self.registry) workflow.action_entity(self.link1, self.action, self.registry) #========================================================================== # Failure #========================================================================== def test_create_resource_for_failure(self): ''' Test if create behaves correct on faulty create calls... ''' # the id of this link already exists... link2 = Link('/link/1', self.link_kind, [], self.src_entity, self.trg_entity) self.src_entity.links.append(link2) self.assertRaises(AttributeError, workflow.create_entity, '/foo/bar', self.src_entity, self.registry) def test_replace_entity_for_failure(self): ''' Test replace for failure. ''' self.trg_entity.links = [self.link1] # new entity should not have links... self.assertRaises(HTTPError, workflow.replace_entity, self.src_entity, self.trg_entity, self.registry) # cannot replace reouce with link self.assertRaises(AttributeError, workflow.replace_entity, self.src_entity, self.link1, self.registry) def test_update_entity_for_failure(self): ''' Test update for failure. ''' self.trg_entity.links = [self.link1] # new entity should not have links... self.assertRaises(HTTPError, workflow.update_entity, self.src_entity, self.trg_entity, self.registry) #========================================================================== # Sanity #========================================================================== def test_create_resource_link_ids_for_sanity(self): ''' Test creation... ''' # Check if an id get's set for the link... self.link1.identifier = None workflow.create_entity('/foo/src', self.src_entity, self.registry) self.assertTrue(self.link1.identifier is not None) def test_create_resource_for_sanity(self): ''' Test creation... ''' workflow.create_entity('/foo/src', self.src_entity, self.registry) # id needs to be set self.assertEqual(self.src_entity.identifier, '/foo/src') # entity needs to be available self.assertTrue(self.src_entity in self.registry.get_resources()) # link entity needs to be available... self.assertTrue(self.link1 in self.registry.get_resources()) self.assertTrue(len(self.src_entity.links) == 1) def test_create_link_for_sanity(self): ''' Test creation... ''' link2 = Link(None, self.link_kind, [], self.src_entity, self.trg_entity) workflow.create_entity('/link/2', link2, self.registry) # id needs to be set self.assertEqual(link2.identifier, '/link/2') # entity needs to be available self.assertTrue(link2 in self.registry.get_resources()) # link needs to be added to the src entity self.assertTrue(link2 in self.src_entity.links) self.assertTrue(len(self.src_entity.links) == 2) def test_delete_resource_for_sanity(self): ''' Test deletion... ''' workflow.create_entity('/foo/src', self.src_entity, self.registry) workflow.delete_entity(self.src_entity, self.registry) # ensure that both the resource and it's links are removed... self.assertFalse(self.src_entity in self.registry.get_resources()) self.assertFalse(self.link1 in self.registry.get_resources()) def test_delete_link_for_sanity(self): ''' Test deletion... ''' workflow.create_entity('/foo/src', self.src_entity, self.registry) workflow.delete_entity(self.link1, self.registry) self.assertFalse(self.link1 in self.src_entity.links) self.assertFalse(self.link1 in self.registry.get_resources())
class TestParser(unittest.TestCase): ''' Test for the parser. ''' start_action = Action('http://schemas.ogf.org/occi/infrastructure#', 'start') compute = Kind('http://schemas.ogf.org/occi/infrastructure#', 'compute', title='A OCCI compute...', attributes={ 'occi.compute.cores': '', 'occi.compute.state': 'immutable', 'occi.compute.memory': 'required' }, related=[Resource.kind], actions=[start_action]) network_link = Kind('http://schemas.ogf.org/occi/infrastructure#', 'networkinterface', related=[Link.kind]) source = Resource('/1', compute, []) target = Resource('/2', compute, []) link1 = Link('/link/1', network_link, [], source, target) link2 = Link(None, network_link, [], source, target) registry = NonePersistentRegistry() def setUp(self): self.registry.add_resource(self.source.identifier, self.source) self.registry.add_resource(self.target.identifier, self.target) self.registry.set_backend(self.start_action, None) self.registry.set_backend(self.compute, None) self.registry.set_backend(self.network_link, None) self.link1.attributes = {'foo': 'bar'} def tearDown(self): for item in self.registry.get_categories(): self.registry.delete_mixin(item) #========================================================================== # Success #========================================================================== def test_get_category_for_success(self): ''' Tests if a mixin can be created. ''' # disabling 'Method could be func' pylint check (pyunit fault :-)) # pylint: disable=R0201 # mixin check... tmp = 'foo; scheme="http://example.com#"; location="/foo_bar/"' parser.get_category(tmp, self.registry.get_categories(), is_mixin=True) #========================================================================== # Failure #========================================================================== def test_get_category_for_failure(self): ''' Test with faulty category. ''' self.assertRaises(AttributeError, parser.get_category, 'some crap', self.registry.get_categories()) self.assertRaises(AttributeError, parser.get_category, 'foo; scheme="bar"', self.registry.get_categories()) # mixin with msg location check... tmp = 'foo; scheme="http://example.com#"' self.assertRaises(AttributeError, parser.get_category, tmp, self.registry.get_categories(), True) # mixin with faulty location check... tmp = 'foo; scheme="http://example.com#"; location="sdf"' self.assertRaises(AttributeError, parser.get_category, tmp, self.registry.get_categories(), True) def test_get_link_for_failure(self): ''' Test with msg category. ''' # no valid string... self.assertRaises(AttributeError, parser.get_link, 'some crap', None, self.registry.get_categories()) # no target... link_string = parser.get_link_str(self.link1) self.registry.delete_resource(self.target.identifier) self.assertRaises(AttributeError, parser.get_link, link_string, None, self.registry) def test_get_attributes_for_failure(self): ''' Verifies the parsing of attributes. ''' self.assertRaises(AttributeError, parser.get_attributes, 'bla blub') #========================================================================== # Sanity #========================================================================== def test_get_category_for_sanity(self): ''' Simple sanity check... ''' res = parser.get_category(parser.get_category_str(self.compute), self.registry.get_categories()) self.assertEqual(res, self.compute) def test_get_link_for_sanity(self): ''' Verifies that source and target are set... ''' link_string = parser.get_link_str(self.link1) link = parser.get_link(link_string, self.source, self.registry) self.assertEquals(link.kind, self.network_link) self.assertEquals(link.source, self.source) self.assertEquals(link.target, self.target) # 4 = 1 attr + core.id + core.src + core.target self.assertTrue(len(link.attributes) == 4) # identifier checks... link_string = parser.get_link_str(self.link1) link = parser.get_link(link_string, self.source, self.registry) self.assertEquals(link.identifier, '/link/1') tmp = link_string.split('; ') tmp.pop(2) link_string = '; '.join(tmp) link = parser.get_link(link_string, self.source, self.registry) self.assertEquals(link.identifier, None) def test_strip_all_for_sanity(self): ''' Tests if information get's stripped correctly. ''' self.assertEqual('bla', parser._strip_all('bla')) self.assertEqual('bla', parser._strip_all('"bla"')) self.assertEqual('bla', parser._strip_all(' bla ')) self.assertEqual('bla', parser._strip_all('"bla')) self.assertEqual('bla', parser._strip_all('bla" ')) self.assertEqual(' bla', parser._strip_all('" bla" ')) self.assertEqual('some text', parser._strip_all('"some text" ')) def test_get_attributes_for_sanity(self): ''' Verifies the parsing of attributes. ''' self.assertEquals(parser.get_attributes('foo=bar'), ('foo', 'bar')) self.assertEquals(parser.get_attributes('foo=bar '), ('foo', 'bar')) self.assertEquals(parser.get_attributes('foo= "some stuff"'), ('foo', 'some stuff')) self.assertEquals(parser.get_attributes('foo = "bar"'), ('foo', 'bar'))
class TestTextOcciRendering(unittest.TestCase): ''' Simple sanity checks... ''' # disable 'Unused attr' pylint check (not needing body here) # disable 'Too many instance attributes' pyling check (It's a test :)) # pylint: disable=W0612,R0902 registry = NonePersistentRegistry() def setUp(self): self.rendering = TextOcciRendering(self.registry) # type system... self.kind = Kind('http://example.com#', 'foo', related=[Resource.kind]) self.invalid_kind = Kind('http://example.com#', 'invalid') self.link = Kind('http://example.com#', 'link', related=[Link.kind]) self.mixin = Mixin('http://example.com#', 'mixin') self.action = Action('http://example.com#', 'action') self.registry.set_backend(self.kind, KindBackend()) self.registry.set_backend(self.invalid_kind, KindBackend()) self.registry.set_backend(self.link, KindBackend()) self.registry.set_backend(self.mixin, MixinBackend()) self.registry.set_backend(self.action, ActionBackend()) # 2 linked entities self.entity = Resource('/foo/1', self.kind, [self.mixin]) trg = Resource('/foo/2', self.kind, [], []) self.link1 = Link('/link/1', self.link, [], self.entity, trg) self.entity.links = [self.link1] self.registry.add_resource('/foo/2', trg) self.registry.add_resource('/link/1', self.link1) self.registry.add_resource('/foo/1', self.entity) def tearDown(self): for res in self.registry.get_resources(): self.registry.delete_resource(res.identifier) for item in self.registry.get_categories(): self.registry.delete_mixin(item) #========================================================================== # Failure #========================================================================== def test_resource_for_failure(self): ''' Check if the correct exceptions are thrown. ''' # no kind available... res = Resource('/foo/1', self.mixin, [], links=[]) headers, body = self.rendering.from_entity(res) self.assertRaises(AttributeError, self.rendering.to_entity, headers, body, None) # kind does not relate to link or resource... res.kind = self.invalid_kind headers, body = self.rendering.from_entity(res) self.assertRaises(AttributeError, self.rendering.to_entity, headers, body, None) def test_resources_for_failure(self): ''' Tests is a set of resource can be set and retrieved. ''' heads = {'X-OCCI-Location': '/bla/bla/2'} self.assertRaises(AttributeError, self.rendering.to_entities, heads, '') def test_link_for_failure(self): ''' Test link... ''' # call creation of entity with non existing trg resource. trg = Resource('/bar/1', self.kind, [], []) link = Link('/bar/1', self.link, [], self.entity, trg) headers, body = self.rendering.from_entity(link) self.assertRaises(AttributeError, self.rendering.to_entity, headers, body, None) #========================================================================== # Sanity #========================================================================== def test_resource_for_sanity(self): ''' Test is a resource can be rendered and retrieved. ''' # basic check headers, body = self.rendering.from_entity(self.entity) new = self.rendering.to_entity(headers, body, None) self.assertEqual(self.entity.kind, new.kind) self.assertEqual(len(self.entity.links), len(new.links)) # verify that provided kind is taken kind = Kind('foo', 'bar', related=[Resource.kind]) headers, body = self.rendering.from_entity(self.entity) new = self.rendering.to_entity(headers, body, kind) self.assertEqual(new.kind, kind) self.assertEqual(len(self.entity.links), len(new.links)) # verify that actions get added self.entity.actions = [self.action] headers, body = self.rendering.from_entity(self.entity) self.assertTrue('?action' in headers['Link']) def test_resources_for_sanity(self): ''' Tests is a set of resource can be set and retrieved for sanity. ''' res = self.registry.get_resources() heads, body = self.rendering.from_entities(res, '/') entities = self.rendering.to_entities(heads, body) self.assertEqual(self.registry.get_resources(), entities) def test_link_for_sanity(self): ''' Test is a link can be rendered and retrieved. ''' headers, body = self.rendering.from_entity(self.link1) tmp = 'occi.core.target=' + self.link1.target.identifier tmp += ', occi.core.source=' + self.link1.source.identifier headers['X-OCCI-Attribute'] = tmp new = self.rendering.to_entity(headers, body, None) self.assertEqual(self.link1.kind, new.kind) # do not alter the source entity link list! self.assertTrue(len(self.entity.links) == 1) def test_qi_categories_for_sanity(self): ''' Tests QI interface rendering... ''' heads = { 'Category': 'foo; scheme="http://example.com#";' + ' location="/foo/"' } mixins = self.rendering.to_mixins(heads, '') headers, body = self.rendering.from_categories(mixins) self.assertTrue('foo' in headers['Category']) self.assertTrue('scheme="http://example.com#"' in headers['Category']) self.assertTrue('location="/foo/"' in headers['Category']) def test_action_for_sanity(self): ''' Test the to actions function... ''' heads = { 'Category': self.action.term + '; scheme="' + self.action.scheme + '"' } action = self.rendering.to_action(heads, None) self.assertEqual(action, self.action) def test_get_filters_for_sanity(self): ''' Test if filters can be retrieved... ''' headers, body = self.rendering.from_categories([self.kind]) cats, attrs = self.rendering.get_filters(headers, '') self.assertTrue(cats == [self.kind]) self.assertTrue(attrs == {}) headers['X-OCCI-Attribute'] = 'foo="bar"' cats, attrs = self.rendering.get_filters(headers, '') self.assertTrue(cats == [self.kind]) self.assertTrue(attrs['foo'] == 'bar')
class TestResourceCapabilites(unittest.TestCase): ''' Test the Resource Handler. ''' registry = NonePersistentRegistry() def setUp(self): self.app = Application([(r"(.*)", ResourceWrapper)]) self.registry.set_renderer('text/occi', TextOcciRendering(self.registry)) self.registry.set_backend(COMPUTE, SimpleComputeBackend()) self.registry.set_backend(NETWORK, KindBackend()) self.registry.set_backend(NETWORKINTERFACE, KindBackend()) self.registry.set_backend(START, SimpleComputeBackend()) def tearDown(self): for item in self.registry.get_resources(): self.registry.delete_resource(item.identifier) #========================================================================== # Failure #========================================================================== def test_create_resource_for_failure(self): ''' Put two resource and one link... ''' headers = {'Content-Type': 'text/occi', 'Category': 'garbage'} request = create_request('PUT', headers, '') handler = ResourceWrapper(self.app, request) self.assertRaises(HTTPError, handler.put, '/compute/1') def test_retrieve_resource_for_failure(self): ''' test retrieval... ''' headers = {'Accept': 'text/occi'} request = create_request('GET', headers, '') handler = ResourceWrapper(self.app, request) self.assertRaises(HTTPError, handler.get, '/bla') def test_partial_update_for_failure(self): ''' test update... ''' headers = { 'Content-Type': 'text/occi', 'X-Occi-Attribute': 'occi.compute.cores="2"' } request = create_request('POST', headers, '') handler = ResourceWrapper(self.app, request) self.assertRaises(HTTPError, handler.post, '/bla') headers = { 'Content-Type': 'text/occi', 'Category': parser.get_category_str(COMPUTE) } request = create_request('PUT', headers, '') handler = ResourceWrapper(self.app, request) handler.put('/compute/1') self.assertTrue('/compute/1' in self.registry.get_resource_keys()) headers = {'Content-Type': 'text/occi', 'X-Occi-Attribute': 'garbage'} request = create_request('POST', headers, '') handler = ResourceWrapper(self.app, request) self.assertRaises(HTTPError, handler.post, '/compute/1') def test_replace_for_failure(self): ''' test update... ''' headers = { 'Content-Type': 'text/occi', 'Category': parser.get_category_str(COMPUTE), 'X-Occi-Attribute': 'occi.compute.memory="2.0"' } request = create_request('PUT', headers, '') handler = ResourceWrapper(self.app, request) handler.put('/compute/1') self.assertTrue('/compute/1' in self.registry.get_resource_keys()) headers = {'Content-Type': 'text/occi', 'Category': 'garbage'} request = create_request('PUT', headers, '') handler = ResourceWrapper(self.app, request) self.assertRaises(HTTPError, handler.put, '/compute/1') def test_delete_for_failure(self): ''' Test delete... ''' request = create_request('DELETE', {}, '') handler = ResourceWrapper(self.app, request) self.assertRaises(HTTPError, handler.delete, '/compute/2') headers = { 'Content-Type': 'text/occi', 'Category': parser.get_category_str(COMPUTE), 'X-Occi-Attribute': 'undeletable="true"' } request = create_request('PUT', headers, '') handler = ResourceWrapper(self.app, request) handler.put('/compute/1') self.assertTrue('/compute/1' in self.registry.get_resource_keys()) request = create_request('DELETE', {}, '') handler = ResourceWrapper(self.app, request) self.assertRaises(HTTPError, handler.delete, '/compute/1') def test_trigger_action_for_failure(self): ''' Trigger an action... ''' headers = { 'Content-Type': 'text/occi', 'Category': parser.get_category_str(COMPUTE) } request = create_request('PUT', headers, '') handler = ResourceWrapper(self.app, request) handler.put('/compute/3') self.assertTrue('/compute/3' in self.registry.get_resource_keys()) headers = {'Content-Type': 'text/occi', 'Category': 'blabla'} request = create_request('POST', headers, '', '/compute/3?action=' \ 'start') handler = ResourceWrapper(self.app, request) self.assertRaises(HTTPError, handler.post, '/compute/3') headers = { 'Content-Type': 'text/occi', 'Category': parser.get_category_str(START) } request = create_request('POST', headers, '', '/compute/3?action=' \ 'start') handler = ResourceWrapper(self.app, request) self.assertRaises(HTTPError, handler.post, '/bla"') #========================================================================== # Sanity #========================================================================== def test_create_resource_for_sanity(self): ''' Put two resource and one link... ''' headers = { 'Content-Type': 'text/occi', 'Category': parser.get_category_str(COMPUTE) } request = create_request('PUT', headers, '') handler = ResourceWrapper(self.app, request) handler.put('/compute/1') self.assertTrue('/compute/1' in self.registry.get_resource_keys()) headers = { 'Content-Type': 'text/occi', 'Category': parser.get_category_str(NETWORK) } request = create_request('PUT', headers, '') handler = ResourceWrapper(self.app, request) handler.put('/network/1') self.assertTrue('/network/1' in self.registry.get_resource_keys()) headers = {'Content-Type': 'text/occi', 'Category': parser.get_category_str(NETWORKINTERFACE), 'X-Occi-Attribute': 'occi.core.source="/compute/1",' \ ' occi.core.target="/network/1"'} request = create_request('PUT', headers, '') handler = ResourceWrapper(self.app, request) handler.put('/network/link/1') self.assertTrue('/network/link/1' in self.registry.get_resource_keys()) compute = self.registry.get_resource('/compute/1') self.assertTrue(len(compute.links) == 1) heads, body = handler.get_output() self.assertTrue('/network/link/1' in heads['Location']) def test_retrieve_resource_for_sanity(self): ''' test retrieval... ''' headers = { 'Content-Type': 'text/occi', 'Category': parser.get_category_str(COMPUTE) } request = create_request('PUT', headers, '') handler = ResourceWrapper(self.app, request) handler.put('/compute/1') self.assertTrue('/compute/1' in self.registry.get_resource_keys()) headers = {'Accept': 'text/occi'} request = create_request('GET', headers, '') handler = ResourceWrapper(self.app, request) handler.get('/compute/1') heads, body = handler.get_output() self.assertTrue('"/compute/1"' in heads['X-OCCI-Attribute']) self.assertTrue('compute' in heads['Category']) self.assertTrue('text/occi' in heads['Content-Type']) def test_partial_update_for_sanity(self): ''' test update... ''' headers = { 'Content-Type': 'text/occi', 'Category': parser.get_category_str(COMPUTE) } request = create_request('PUT', headers, '') handler = ResourceWrapper(self.app, request) handler.put('/compute/1') self.assertTrue('/compute/1' in self.registry.get_resource_keys()) headers = { 'Content-Type': 'text/occi', 'X-Occi-Attribute': 'occi.compute.cores="2"' } request = create_request('POST', headers, '') handler = ResourceWrapper(self.app, request) handler.post('/compute/1') compute = self.registry.get_resource('/compute/1') self.assertTrue('occi.compute.cores' in compute.attributes.keys()) heads, body = handler.get_output() def test_replace_for_sanity(self): ''' test update... ''' headers = { 'Content-Type': 'text/occi', 'Category': parser.get_category_str(COMPUTE), 'X-Occi-Attribute': 'occi.compute.memory="2.0"' } request = create_request('PUT', headers, '') handler = ResourceWrapper(self.app, request) handler.put('/compute/1') self.assertTrue('/compute/1' in self.registry.get_resource_keys()) headers = { 'Content-Type': 'text/occi', 'Category': parser.get_category_str(COMPUTE), 'X-Occi-Attribute': 'occi.compute.cores="2"' } request = create_request('PUT', headers, '') handler = ResourceWrapper(self.app, request) handler.put('/compute/1') compute = self.registry.get_resource('/compute/1') self.assertTrue('occi.compute.memory' not in compute.attributes.keys()) self.assertTrue('occi.compute.cores' in compute.attributes.keys()) heads, body = handler.get_output() def test_delete_for_sanity(self): ''' Test delete... ''' headers = { 'Content-Type': 'text/occi', 'Category': parser.get_category_str(COMPUTE), 'X-Occi-Attribute': 'occi.compute.memory="2.0"' } request = create_request('PUT', headers, '') handler = ResourceWrapper(self.app, request) handler.put('/compute/1') self.assertTrue('/compute/1' in self.registry.get_resource_keys()) request = create_request('DELETE', {}, '') handler = ResourceWrapper(self.app, request) handler.delete('/compute/1') self.assertTrue('/compute/1' not in self.registry.get_resource_keys()) def test_trigger_action_for_sanity(self): ''' Trigger an action... ''' headers = { 'Content-Type': 'text/occi', 'Category': parser.get_category_str(COMPUTE) } request = create_request('PUT', headers, '') handler = ResourceWrapper(self.app, request) handler.put('/compute/3') self.assertTrue('/compute/3' in self.registry.get_resource_keys()) headers = { 'Content-Type': 'text/occi', 'Category': parser.get_category_str(START) } request = create_request('POST', headers, '', '/compute/3?action' \ '=start') handler = ResourceWrapper(self.app, request) handler.post('/compute/3') compute = self.registry.get_resource('/compute/3') self.assertTrue(compute.attributes['occi.compute.state'] == 'active')
class BaseHandler(tornado.web.RequestHandler): ''' General request handler. ''' def initialize(self, registry): self.registry = registry if self.registry.get_hostname() == '': self.registry.set_hostname(self.request.protocol + '://' + self.request.host) def __init__(self, application, request, **kwargs): super(BaseHandler, self).__init__(application, request, **kwargs) # This ensures that at least one registry is loaded in case initialize # is not called for some reason... self.registry = NonePersistentRegistry() if self.registry.get_hostname() == '': self.registry.set_hostname(self.request.protocol + '://' + self.request.host) def extract_http_data(self): ''' Extracts all necessary information from the HTTP envelop. Minimize the data which is carried around inside of the service. Also ensures that the names are always equal - When deployed in Apache the names of the Headers change. ''' heads = {} headers = self.request.headers if 'Category' in headers: heads['Category'] = headers['Category'] if 'X-Occi-Attribute' in headers: heads['X-OCCI-Attribute'] = headers['X-Occi-Attribute'] if 'X-Occi-Location' in headers: heads['X-OCCI-Location'] = headers['X-Occi-Location'] if 'Link' in headers: heads['Link'] = headers['Link'] if self.request.body is not '': body = self.request.body.strip() else: body = '' return heads, body def get_renderer(self, content_type): ''' Returns the proper rendering parser. content_type -- String with either either Content-Type or Accept. ''' try: return self.registry.get_renderer( self.request.headers[content_type]) except KeyError: return self.registry.get_renderer(self.registry.get_default_type()) def response(self, status, mime_type, headers, body='OK'): ''' Will create a response and send it to the client. status -- The status code. mime_type -- Sets the Content-Type of the response. headers -- The HTTP headers. body -- The text for the body (default: ok). ''' self.set_header('Server', VERSION) self.set_header('Content-Type', mime_type) self.set_status(status) if headers is not None: for item in headers.keys(): self._headers[item] = headers[item] self.write(body) self.finish('\n') def get_error_html(self, status_code, **kwargs): self.set_header('Server', VERSION) self.set_header('Content-Type', self.registry.get_default_type()) exception = sys.exc_info()[1] msg = str(exception) self.set_status(status_code) return msg def parse_action(self): ''' Retrieves the Action which was given in the request. ''' headers, body = self.extract_http_data() rendering = self.get_renderer(CONTENT_TYPE) action = rendering.to_action(headers, body) return action def parse_filter(self): ''' Retrieve any attributes or categories which where provided in the request for filtering. ''' headers, body = self.extract_http_data() attr = 'X-OCCI-Attribute' if attr not in headers and 'Category' not in headers and body == '': return [], {} rendering = self.get_renderer(CONTENT_TYPE) categories, attributes = rendering.get_filters(headers, body) return categories, attributes def parse_entity(self, def_kind=None): ''' Retrieves the entity which was rendered within the request. def_kind -- Indicates if the request can be incomplete (False). ''' headers, body = self.extract_http_data() rendering = self.get_renderer(CONTENT_TYPE) entity = rendering.to_entity(headers, body, def_kind) return entity def parse_entities(self): ''' Retrieves a set of entities which was rendered within the request. ''' headers, body = self.extract_http_data() rendering = self.get_renderer(CONTENT_TYPE) entities = rendering.to_entities(headers, body) return entities def parse_mixins(self): ''' Retrieves a mixin from a request. ''' headers, body = self.extract_http_data() rendering = self.get_renderer(CONTENT_TYPE) mixin = rendering.to_mixins(headers, body) return mixin def render_entity(self, entity): ''' Renders a single entity to the client. entity -- The entity which should be rendered. ''' rendering = self.get_renderer(ACCEPT) headers, body = rendering.from_entity(entity) self.response(200, rendering.mime_type, headers, body) def render_entities(self, entities, key): ''' Renders a list of entities to the client. entities -- The entities which should be rendered. ''' rendering = self.get_renderer(ACCEPT) headers, body = rendering.from_entities(entities, key) self.response(200, rendering.mime_type, headers, body) def render_categories(self, categories): ''' Renders a list of categories to the client. categories -- The categories which should be rendered. ''' rendering = self.get_renderer(ACCEPT) headers, body = rendering.from_categories(categories) self.response(200, rendering.mime_type, headers, body)