def testFindUsage(self): class Dummy1(object): pass class Dummy2(object): pass class Dummy3(object): pass f = HTTPTopLevel('users', 'PUT') self.reg.register(f) usage1 = HTTPUsage('', "Return a list of all users.") usage1.resourceClass = Dummy1 f.addUsage(usage1) f = HTTPTopLevel('dummy', 'GET') self.reg.register(f) usage2 = HTTPUsage('', "Return a list of all dummies.") usage2.resourceClass = Dummy2 f.addUsage(usage2) # Find the usage with class Dummy1. u = self.reg.findUsage('users', 'PUT', usageResourceClass=Dummy1) self.assertTrue(u.resourceClass is usage1.resourceClass) # Find the usage with class Dummy2. u = self.reg.findUsage('dummy', 'GET', usageResourceClass=Dummy2) self.assertTrue(u.resourceClass is usage2.resourceClass) # Ask for a non-existent usage class. self.assertRaises(error.NoSuchUsage, self.reg.findUsage, 'dummy', 'GET', usageResourceClass=Dummy3) # Ask for a non-existent toplevel. self.assertRaises(error.NoSuchToplevel, self.reg.findUsage, 'sunny', 'PUT', usageResourceClass=Dummy2) # Ask for a non-existent verb. self.assertRaises(error.NoSuchVerb, self.reg.findUsage, 'dummy', 'PUT', usageResourceClass=Dummy2)
def testUsageRequestPayloadMandatory1(self): # f = HTTPTopLevel('users', 'PUT') usage = HTTPUsage('/dummy', 'Bee-bop') payload = Payload() usage.addRequestPayload(payload) field = PayloadField('f1', 'type', 'desc', mandatory=False) payload.addField(field) self.assertFalse(usage.requestPayloadMandatory()) field = PayloadField('f2', 'type', 'desc', mandatory=True) payload.addField(field) self.assertTrue(usage.requestPayloadMandatory())
def testNotes(self): f = HTTPTopLevel('users', 'PUT') usage = HTTPUsage('/dummy', 'an example of great profundity') f.addUsage(usage) note = Note('hey') usage.addNote(note) note = Note('hey') usage.addNote(note) self.assertEqual(len(usage.notes), 2) self.reg.register(f) apis = self.reg.get('users', 'PUT') self.assertEqual(apis, [['users', [('PUT', f)]]]) f = apis[0][1][0][1] self.assertEqual(len(f.usages), 1) self.assertEqual(len(f.usages[0].notes), 2)
def TestUsageExamples(self): """ Rather un-exciting test but at least the code is exercised and expected behaviour checked. """ u = HTTPUsage('/dummy', 'an example of great profundity') request = 'foo' response = 'bar' description = 'baz' example = HTTPExample(request, response, description) u.addExample(example) self.assertEqual(1, len(u.examples)) self.assertEqual('foo', u.examples[0].request) self.assertEqual('bar', u.examples[0].response) self.assertEqual('baz', u.examples[0].description)
# ------------------------------ Values GET ----------------------------- topLevel = HTTPTopLevel(httpValueCategoryName, 'GET') topLevel.description = """The GET method on values is used to retrieve tag values from objects matching a query.""" # We could here mention # href="http://doc.fluidinfo.com/fluidDB/api/draft-values-spec.html"> # /values draft spec</a>. registry.register(topLevel) # --- GET /values -------------------------------------------------------- usage = HTTPUsage( '', """Search for objects matching a Fluidinfo query, and return the value of the requested tags on the matching objects.""") usage.resourceClass = ValuesResource topLevel.addUsage(usage) usage.addArgument( Argument(queryArg, '''A query string specifying what objects to match. The Fluidinfo query language is described <a href="http://doc.fluidinfo.com/fluidDB/queries.html">here</a>.''', 'string', None, mandatory=True)) usage.addArgument( Argument(tagArg,
return AboutObjectResource(self.facadeClient, self.session, about) # ------------------------------ About POST ----------------------------- topLevel = HTTPTopLevel(httpAboutCategoryName, 'POST') topLevel.description = "Create a new object." registry.register(topLevel) # --- POST /about ------------------------------------------------------- usage = HTTPUsage('/' + apiDoc.ABOUTSTR, ('''Create a new object with the given about value. If there is already a Fluidinfo object whose ''' + apiDoc.ABOUT_TAG + ''' tag has the given value, the returned object id will be that of the pre-existing object. In this call, and all others with an about value in the URI, you must convert your about value to UTF-8 and then <a href="http://en.wikipedia.org/wiki/Percent-encoding"> percent-encode</a> it before adding it to the request URI. You must provide valid credentials for this call to succeed. For an example see the PUT request, below.''')) topLevel.addUsage(usage) usage.resourceClass = AboutObjectResource usage.successCode = http.CREATED usage.addReturn( Return(apiDoc.BAD_REQUEST, 'The ' + apiDoc.ABOUTSTR + ' argument was not valid UTF-8.')) apiDoc.addBadRequestPayload(usage)
usage = registry.findUsage(httpNamespaceCategoryName, 'DELETE', NamespacesResource) registry.checkRequest(usage, request) yield self.facadeClient.deleteNamespace(self.session, sep.join(request.postpath)) request.setResponseCode(usage.successCode) # ------------------------------ Namespaces POST -------------------------- topLevel = HTTPTopLevel(httpNamespaceCategoryName, 'POST') registry.register(topLevel) # --- POST /namespaces/NAMESPACE1/NAMESPACE2 ------------------------------ usage = HTTPUsage( apiDoc.NS_NS, 'Create a new namespace. Intermediate ' "namespaces are created automatically if they don't already " 'exist.') topLevel.addUsage(usage) usage.resourceClass = NamespacesResource usage.successCode = http.CREATED usage.addNote( Note("""The new namespace will have permissions set according to the user's defaults. There is no permission inheritance in Fluidinfo.""")) usage.addReturn( Return(apiDoc.PRECONDITION_FAILED, 'If the namespace already exists.')) usage.addReturn( Return(
returnValue(body) # API DOCUMENTATION # GET on /recent topLevel = HTTPTopLevel('recent', 'GET') topLevel.description = dedent(""" The GET method on recent is used to retrieve information about the latest updated tag values on a given object or user.""") registry.register(topLevel) # GET on /recent/objects usage = HTTPUsage( '/objects', dedent(""" To request information on the latest tag values on the objects returned by a given query""")) usage.resourceClass = RecentObjectsActivityResource usage.addArgument( Argument('query', dedent(""" A query string specifying what sorts of objects to get recent activity for. The query language is described <a href="http://doc.fluidinfo.com/fluidDB/queries.html">here</a>. You must convert your query to UTF-8 and then <a href="http://en.wikipedia.org/wiki /Percent-encoding"> percent-encode</a> it before adding it to the request URI """), 'string', default=None,
body = payloads.buildPayload(responseType, responseDict) request.setHeader('Content-length', str(len(body))) request.setHeader('Content-type', responseType) request.setHeader('Location', location) request.setResponseCode(usage.successCode) defer.returnValue(body) # ------------------------------ Users POST ------------------------------- topLevel = HTTPTopLevel(httpUserCategoryName, 'POST') topLevel.adminOnly = True registry.register(topLevel) # --- POST /users --------------------------------------------------------- usage = HTTPUsage('', 'Create a new user.') usage.adminOnly = True usage.resourceClass = UsersResource usage.successCode = http.CREATED topLevel.addUsage(usage) apiDoc.addNeedAdmin(usage, apiDoc.CREATE) usage.addReturn(Return( apiDoc.PRECONDITION_FAILED, 'If the user already exists.')) usage.addReturn(Return( apiDoc.BAD_REQUEST, """If the username is unacceptable due to syntax. Usernames may contain only letters (according to the Unicode standard), digits,
def deferred_render_DELETE(self, request): usage = registry.findUsage(httpTagCategoryName, 'DELETE', TagsResource) registry.checkRequest(usage, request) yield self.facadeClient.deleteTag(self.session, sep.join(request.postpath)) request.setResponseCode(usage.successCode) # ------------------------------ Tags POST -------------------------- topLevel = HTTPTopLevel(httpTagCategoryName, 'POST') registry.register(topLevel) # --- POST /tags/NAMESPACE1/NAMESPACE2 ------------------------ usage = HTTPUsage( apiDoc.NS_NS, 'Add a tag name to a namespace. Intermediate namespaces ' "are created automatically if they don't already exist.") topLevel.addUsage(usage) usage.resourceClass = TagsResource usage.successCode = http.CREATED requestPayload = JSONPayload() requestPayload.addField( PayloadField('name', unicode, 'The name of the new tag.')) requestPayload.addField( PayloadField('description', unicode, 'A description of the tag.', mayBeNone=True)) requestPayload.addField( PayloadField('indexed', bool,
body = payloads.buildPayload(responseType, responseDict) request.setHeader('Content-length', str(len(body))) request.setHeader('Content-type', responseType) request.setResponseCode(usage.successCode) defer.returnValue(body) # ------------------------------ Objects POST ----------------------------- topLevel = HTTPTopLevel(httpObjectCategoryName, 'POST') topLevel.description = "Create a new Fluidinfo object." registry.register(topLevel) # --- POST /objects ------------------------------------------------------- usage = HTTPUsage( '', 'Create a new object. You must provide credentials for ' 'this call to succeed.') topLevel.addUsage(usage) usage.resourceClass = ObjectsResource usage.successCode = http.CREATED apiDoc.addBadRequestPayload(usage) apiDoc.addCannotRespondWithPayload(usage) usage.addReturn( Return(apiDoc.UNAUTHORIZED, 'If valid credentials are not provided.')) usage.addReturn( Return(apiDoc.httpCode(usage.successCode), 'A new object was created without error.'))
POST is not supported on permissions, because permissions are automatically set from a user's default permissions when a namespace or tag is first created. Use PUT to adjust the permissions on a given namespace or tag. """ # TODO: Finish this sentence and add it to the description: # To change a user's defaults, do a PUT on.... what exactly? registry.register(topLevel) # ------------------------------ Permissions GET -------------------------- topLevel = HTTPTopLevel('permissions', 'GET') registry.register(topLevel) # --- GET /permissions/namespaces/NAMESPACE1/NAMESPACE2 ------------ usage = HTTPUsage( '/' + httpNamespaceCategoryName + apiDoc.NS_NS, """Get the permissions on a namespace: the open/closed policy, and the set of exceptions to the policy.""") usage.resourceClass = ConcreteNamespacePermissionResource topLevel.addUsage(usage) possibleActions = ', '.join( permissions.actionsByCategory[namespaceCategoryName]) usage.addArgument( Argument(actionArg, """The action whose permissions information is sought. Possible values are: """ + possibleActions + '.', 'string', mandatory=True)) apiDoc.addMissingIntermediateNs(usage)