def test_describe_resource_authenticated_resource_with_fallback(self): # When the resource requires authentication, but has a fallback # anonymous handler, both are described. The resource name is taken # from the authenticated handler. self.patch(ExampleHandler, "anonymous", ExampleFallbackHandler) resource = OperationsResource(ExampleHandler, sentinel.auth) expected = { "anon": describe_handler(ExampleFallbackHandler), "auth": describe_handler(ExampleHandler), "name": "ExampleHandler", } self.assertEqual(expected, describe_resource(resource))
def test_describe_handler_with_maas_handler(self): # Ensure that describe_handler() yields something sensible with a # "real" MAAS API handler. from maasserver.api import NodeHandler as handler description = describe_handler(handler) # The RUD of CRUD actions are still available, but the C(reate) action # has been overridden with custom non-ReSTful operations. expected_actions = { "DELETE delete op=None restful=True", "GET read op=None restful=True", "GET details op=details restful=False", "POST start op=start restful=False", "POST stop op=stop restful=False", "POST release op=release restful=False", "POST commission op=commission restful=False", "PUT update op=None restful=True", } observed_actions = { "%(method)s %(name)s op=%(op)s restful=%(restful)s" % action for action in description["actions"] } self.assertSetEqual(expected_actions, observed_actions) self.assertSetEqual({"system_id"}, set(description["params"])) # The path is a URI Template <http://tools.ietf.org/html/rfc6570>, the # components of which correspond to the parameters declared. self.assertEqual( "/api/1.0/nodes/{system_id}/", description["path"])
def test_describe_handler(self): # describe_handler() returns a description of a handler that can be # readily serialised into JSON, for example. expected_actions = [ {"doc": getdoc(ExampleHandler.idempotent_operation), "method": "GET", "name": "idempotent_operation", "op": "idempotent_operation", "restful": False}, {"doc": getdoc(ExampleHandler.non_idempotent_operation), "method": "POST", "name": "non_idempotent_operation", "op": "non_idempotent_operation", "restful": False}, {"doc": None, "method": "PUT", "name": "update", "op": None, "restful": True}, ] observed = describe_handler(ExampleHandler) # The description contains several entries. self.assertSetEqual( {"actions", "doc", "name", "params", "path"}, set(observed)) self.assertEqual(ExampleHandler.__doc__, observed["doc"]) self.assertEqual(ExampleHandler.__name__, observed["name"]) self.assertEqual(["p_foo", "p_bar"], observed["params"]) self.assertItemsEqual(expected_actions, observed["actions"])
def test_describe_handler_with_maas_handler(self): # Ensure that describe_handler() yields something sensible with a # "real" MAAS API handler. from maasserver.api import NodeHandler as handler description = describe_handler(handler) # The RUD of CRUD actions are still available, but the C(reate) action # has been overridden with custom non-ReSTful operations. expected_actions = { "DELETE delete op=None restful=True", "GET read op=None restful=True", "GET details op=details restful=False", "POST start op=start restful=False", "POST stop op=stop restful=False", "POST release op=release restful=False", "POST commission op=commission restful=False", "PUT update op=None restful=True", } observed_actions = { "%(method)s %(name)s op=%(op)s restful=%(restful)s" % action for action in description["actions"] } self.assertSetEqual(expected_actions, observed_actions) self.assertSetEqual({"system_id"}, set(description["params"])) # The path is a URI Template <http://tools.ietf.org/html/rfc6570>, the # components of which correspond to the parameters declared. self.assertEqual("/api/1.0/nodes/{system_id}/", description["path"])
def test_describe_handler(self): # describe_handler() returns a description of a handler that can be # readily serialised into JSON, for example. expected_actions = [ { "doc": getdoc(ExampleHandler.idempotent_operation), "method": "GET", "name": "idempotent_operation", "op": "idempotent_operation", "restful": False }, { "doc": getdoc(ExampleHandler.non_idempotent_operation), "method": "POST", "name": "non_idempotent_operation", "op": "non_idempotent_operation", "restful": False }, { "doc": None, "method": "PUT", "name": "update", "op": None, "restful": True }, ] observed = describe_handler(ExampleHandler) # The description contains several entries. self.assertSetEqual({"actions", "doc", "name", "params", "path"}, set(observed)) self.assertEqual(ExampleHandler.__doc__, observed["doc"]) self.assertEqual(ExampleHandler.__name__, observed["name"]) self.assertEqual(["p_foo", "p_bar"], observed["params"]) self.assertItemsEqual(expected_actions, observed["actions"])
def test_describe_resource_authenticated_resource(self): # When the resource requires authentication, but has no fallback # anonymous handler, the first is described. The resource name comes # from this handler. resource = OperationsResource(ExampleHandler, sentinel.auth) expected = { "anon": None, "auth": describe_handler(ExampleHandler), "name": "ExampleHandler", } self.assertEqual(expected, describe_resource(resource))
def test_describe_resource_anonymous_resource(self): # When the resource does not require authentication, any configured # fallback is ignored, and only the resource's handler is described. # The resource name comes from this handler. self.patch(ExampleHandler, "anonymous", ExampleFallbackHandler) resource = OperationsResource(ExampleHandler) expected = { "anon": describe_handler(ExampleHandler), "auth": None, "name": "ExampleHandler", } self.assertEqual(expected, describe_resource(resource))