def testSimpleAboutJSONP(self): basicAuth = 'Basic %s' % b64encode('%s:%s' % ('testuser1', 'secret')) headers = {'accept': 'application/json', 'authorization': basicAuth} uri = '%s/%s' % (self.endpoint, defaults.httpObjectCategoryName) aboutStr = 'random string' data = {'about': aboutStr} callback = 'foo' payload = json.dumps(data) params = { 'callback': callback, 'verb': 'POST', 'payload': payload, 'payload-type': 'application/json', 'payload-length': len(payload), } uriCB = uri + '?' + urlencode(params) status, responseHeaders, responseCB = yield getPage(uriCB, headers=headers) m = re.match('%s\((.*)\)' % callback, responseCB) self.assertNotEqual(None, m) # XXX JSON hardcoded d = json.loads(m.group(1)) # XXX hardcoded id field oid = str(d['id']) uriValue = defaults.sep.join( [uri, oid, defaults.sep.join(paths.aboutPath())]) status, responseHeaders, responseValue = yield getPage(uriValue) # XXX JSON hardcoded self.assertEqual(aboutStr, json.loads(responseValue))
def testHasJSONP(self): objectId = yield self.createObject() yield self.setTagValue('fluiddb/testing/test1', objectId, 'a string') try: headers = {} self.addBasicAuthHeader(headers) params = { 'query': 'has fluiddb/testing/test1'.encode('utf-8'), } uri = '%s/%s' % (self.endpoint, defaults.httpObjectCategoryName) uriNoCB = uri + '?' + urlencode(params) status, responseHeaders, responseNoCB = yield getPage( uriNoCB, headers=headers) callback = 'foo' params['callback'] = callback.encode('utf-8') uriCB = uri + '?' + urlencode(params) status, responseHeaders, responseCB = yield getPage( uriCB, headers=headers) self.assertEqual('%s(%s)' % (callback, responseNoCB), responseCB) finally: yield self.deleteTagValue('fluiddb/testing/test1', objectId)
def hasTagValue(self, path, objectId, requesterUsername=None, requesterPassword=None): headers = {} self.addBasicAuthHeader(headers, requesterUsername, requesterPassword) uri = '%s/%s/%s/%s' % (self.endpoint, defaults.httpObjectCategoryName, str(objectId), path) d = http.getPage(uri, headers=headers, method='HEAD') def checkPayloadEmpty(result): self.assertEqual(result[2], '') return result def has(result): self.checkHeaders( result, dict.fromkeys(['content-type', 'content-length'])) status = result[0] self.assertEqual(status, str(txHttp.OK)) return True def hasnot(failure): if failure.value.status == str(txHttp.NOT_FOUND): return False else: return failure d.addCallback(checkPayloadEmpty) d.addCallbacks(has, hasnot) return d
def testAsAdminNoPayloadLengthJSONP(self): name = 'test' parentPath = defaults.adminUsername headers = {} self.addBasicAuthHeader(headers) uri = '%s/%s/%s' % (self.endpoint, defaults.httpTagCategoryName, parentPath) data = { 'description': 'some description', 'indexed': False, 'name': name, } payload = json.dumps(data) params = { 'verb': 'POST', 'payload': payload, 'payload-type': 'application/json', } uriTag = uri + '?' + urlencode(params) try: yield wsfe_http.getPage(uriTag, headers=headers) except Exception, e: self.assertEqual(http.BAD_REQUEST, int(e.status)) self.assertEqual('ContentLengthMismatch', e.response_headers['x-fluiddb-error-class'][0])
def testAsAdminJSONPBase64(self): import base64 name = 'test' parentPath = defaults.adminUsername headers = {} self.addBasicAuthHeader(headers) uri = '%s/%s/%s' % (self.endpoint, defaults.httpTagCategoryName, parentPath) data = { 'description': 'some description', 'indexed': False, 'name': name, } payload = base64.standard_b64encode(json.dumps(data)) params = { 'verb': 'POST', 'payload': payload, 'payload-type': 'application/json', 'payload-encoding': 'base64', 'payload-length': len(payload), } uriTag = uri + '?' + urlencode(params) yield wsfe_http.getPage(uriTag, headers=headers) yield self.deleteTag(defaults.sep.join([parentPath, name]))
def getPage(self, URISuffix='', queryDict=None, *args, **kw): if URISuffix and not URISuffix.startswith('/'): URISuffix = '/' + URISuffix if 'method' not in kw: kw['method'] = self.verb if queryDict is None: query = '' else: qlist = [] for k, v in queryDict.items(): kStr = urllib.quote_plus(str(k)) if v is None: qlist.append(kStr) elif isinstance(v, (types.ListType, types.TupleType)): for val in v: qlist.append( '%s=%s' % (kStr, urllib.quote_plus(str(val)))) else: qlist.append('%s=%s' % (kStr, urllib.quote_plus(str(v)))) query = '?' + '&'.join(qlist) uri = '%s/%s%s%s' % (self.endpoint, self.toplevel, URISuffix, query) d = http.getPage(uri, *args, **kw) # TODO: We're not checking error headers because nginx doesn't send them. # Uncomment this line as soon as we fix that. See bug #676940. # d.addErrback(self._checkFluidDBErrorHeaders) return d
def testSimpleJSONP(self): basicAuth = 'Basic %s' % b64encode('%s:%s' % ('testuser1', 'secret')) headers = {'accept': 'application/json', 'authorization': basicAuth} uri = '%s/%s' % (self.endpoint, defaults.httpObjectCategoryName) callback = 'foo' params = { 'callback': callback, 'verb': 'POST', } uriCB = uri + '?' + urlencode(params) status, responseHeaders, responseCB = yield getPage(uriCB, headers=headers) m = re.match('%s\((.*)\)' % callback, responseCB) self.assertNotEqual(None, m) # XXX JSON hardcoded d = json.loads(m.group(1)) # XXX hardcoded id field # Test that the id can be turned into a UUID import uuid self.assertNotEqual(None, uuid.UUID(d['id']))
def getObject(self, objectId, showAbout=False, requesterUsername=None, requesterPassword=None, omitShowAboutInURI=False, accept=None): accept = accept or 'application/json' headers = { 'accept': accept, } self.addBasicAuthHeader(headers, requesterUsername, requesterPassword) uri = '%s/%s/%s' % (self.endpoint, defaults.httpObjectCategoryName, objectId) # omitShowAboutInURI can be used to have the request go with no # showAbout arg in the URI. That lets us test the default case. if not omitShowAboutInURI: uri += '?showAbout=%s' % showAbout d = http.getPage(uri, headers=headers) d.addCallback(self.checkStatus, txHttp.OK) expectedFields = ['tagPaths'] if showAbout: expectedFields.append('about') else: d.addCallback(self.checkPayloadHasNot, ['about']) d.addCallback(self.checkPayloadHas, dict.fromkeys(expectedFields)) result = yield d payload = result[2] dictionary = json.loads(payload) defer.returnValue(dictionary)
def testAdminNewBinaryTagOnNewObjectJSONP(self): def randBinary(n): # Make a random binary string of length n. values = '\x00\x01\x02\x03\x04'.split() return ''.join([random.choice(values) for _ in xrange(n)]) path = 'fluiddb/testing/test1' objectId = yield self.createObject() headers = {} self.addBasicAuthHeader(headers) try: for contentType in ('application/octet-stream', 'hello/world'): size = random.randint(1, 1000) value = randBinary(size) yield self.setTagValue(path, objectId, value, contentType=contentType) uri = '%s/%s' % (self.endpoint, defaults.httpObjectCategoryName) # Request a tag value without a callback arg uriValue = defaults.sep.join([uri, str(objectId), path]) status, responseHeaders, responseValueNoCB = yield getPage( uriValue, headers=headers) self.assertEqual(responseValueNoCB, value) self.assertEqual(responseHeaders['content-type'][0], contentType) # Request the same tag value with a callback arg callbackValue = 'bar' uriValueCB = uriValue + '?' + urllib.urlencode( {'callback': callbackValue}) try: status, responseHeaders, responseValueCB = yield getPage( uriValueCB, headers=headers) self.fail("This should have failed, binary values can't " "be retrieved using a callback") except HTTPError, e: h = e.response_headers self.assertEqual(h['x-fluiddb-error-class'][0], 'UnwrappableBlob') finally: yield self.deleteTagValue(path, objectId)
def testNotAllowed(self): """ POST to /values is not allowed. Confirm that's the case. """ headers = {} self.addBasicAuthHeader(headers) uri = '%s/%s' % (self.endpoint, httpValueCategoryName) d = wsfe_http.getPage(uri, headers=headers, method='POST') d.addErrback(self.checkErrorStatus, http.NOT_ALLOWED) self.failUnlessFailure(d, Error) yield d
def testNoAcceptHeader(self): headers = {} self.addBasicAuthHeader(headers) q = '%s = "xxx"' % defaults.sep.join(paths.aboutPath()) d = getPage('%s/%s?query=%s' % (self.endpoint, defaults.httpObjectCategoryName, urllib.quote_plus(q)), headers=headers, method='GET') d.addCallback(self.checkHeaders, {'content-type': 'application/json'}) return d
def deleteTagValue(self, path, objectId, requesterUsername=None, requesterPassword=None): headers = {} self.addBasicAuthHeader(headers, requesterUsername, requesterPassword) uri = '%s/%s/%s/%s' % (self.endpoint, defaults.httpObjectCategoryName, str(objectId), path) d = http.getPage(uri, headers=headers, method='DELETE') d.addCallback(self.checkStatus, txHttp.NO_CONTENT) return d
def testNoAboutNoPayload(self): headers = { 'accept': 'application/json', 'content-type': 'application/json', } self.addBasicAuthHeader(headers) d = getPage('%s/%s' % (self.endpoint, defaults.httpObjectCategoryName), headers=headers, method='POST') d.addCallback(self.checkStatus, http.CREATED) return d
def testUnknownUser(self): import uuid username = str(uuid.uuid4()) password = str(uuid.uuid4()) uri = '%s/%s/%s' % (self.endpoint, defaults.httpUserCategoryName, defaults.adminUsername) headers = {} self.addBasicAuthHeader(headers, username=username, password=password) try: yield getPage(uri, headers=headers) except HTTPError, e: self.assertEqual(http.UNAUTHORIZED, int(e.status))
def deleteTag(self, path, requesterUsername=None, requesterPassword=None): headers = {} self.addBasicAuthHeader(headers, requesterUsername, requesterPassword) d = http.getPage( '%s/%s/%s' % (self.endpoint, defaults.httpTagCategoryName, urllib.quote(path.encode('utf-8'))), headers=headers, method='DELETE') d.addCallback(self.checkStatus, txHttp.NO_CONTENT) d.addCallback(self.checkNoPayload) return d
def testNoAcceptHeader(self): headers = { 'content-type': 'application/json', } self.addBasicAuthHeader(headers) data = { 'about': 'wee-hoo', } d = getPage('%s/%s' % (self.endpoint, defaults.httpObjectCategoryName), headers=headers, method='POST', postdata=json.dumps(data)) d.addCallback(self.checkHeaders, {'content-type': 'application/json'}) return d
def testNoQuery(self): headers = { 'accept': 'application/json', } self.addBasicAuthHeader(headers) d = getPage('%s/%s' % (self.endpoint, defaults.httpObjectCategoryName), headers=headers, method='GET') d.addErrback(self.checkErrorStatus, http.BAD_REQUEST) d.addErrback( self.checkErrorHeaders, {buildHeader('Error-Class'): error.MissingArgument.__name__}) self.failUnlessFailure(d, Error) return d
def testNoAbout(self): headers = { 'accept': 'application/json', 'content-type': 'application/json', } self.addBasicAuthHeader(headers) data = {} d = getPage('%s/%s' % (self.endpoint, defaults.httpObjectCategoryName), headers=headers, method='POST', postdata=json.dumps(data)) d.addCallback(self.checkStatus, http.CREATED) d.addCallback(self.checkPayloadHas, dict.fromkeys(['id', 'URI'])) d.addCallback(self.checkHeaders, dict.fromkeys(['location'])) return d
def testPayloadWithNoContentType(self): headers = {} self.addBasicAuthHeader(headers) objectId = yield self.createObject() uri = '%s/%s/%s/dummy' % ( self.endpoint, defaults.httpObjectCategoryName, str(objectId)) d = getPage(uri, headers=headers, postdata=json.dumps('x'), method='PUT') d.addErrback(self.checkErrorStatus, http.BAD_REQUEST) d.addErrback( self.checkErrorHeaders, {buildHeader('Error-Class'): error.NoContentTypeHeader.__name__}) self.failUnlessFailure(d, Error) yield d
def query(self, query, requesterUsername=None, requesterPassword=None): headers = { 'accept': 'application/json', } self.addBasicAuthHeader(headers, requesterUsername, requesterPassword) d = http.getPage( '%s/%s?query=%s' % (self.endpoint, defaults.httpObjectCategoryName, urllib.quote(query.encode('utf-8'))), headers=headers, method='GET') d.addCallback(self.checkStatus, txHttp.OK) d.addCallback(self.checkPayloadHas, dict.fromkeys(['ids'])) result = yield d payload = result[2] dictionary = json.loads(payload) defer.returnValue(dictionary['ids'])
def createRandomUser(self, username=None, password=None, name=None, email=None, persistent=False, requesterUsername=None, requesterPassword=None): u = RandomUser(self.endpoint, self.adminUsername, self.adminPassword, username, password, name, email) def _cb((status, headers, page)): self.users.append(u) if persistent: self.persistentUsers.append(u) return u headers = { 'accept': 'application/json', 'content-type': 'application/json', } self.addBasicAuthHeader(headers, requesterUsername, requesterPassword) data = { 'username': u.username, 'name': u.name, 'password': u.password, 'email': u.email, } d = http.getPage( '%s/%s' % (self.endpoint, defaults.httpUserCategoryName), headers=headers, method='POST', postdata=json.dumps(data)) d.addCallback(self.checkStatus, txHttp.CREATED) d.addCallback(self.checkPayloadHas, dict.fromkeys(['id', 'URI'])) d.addCallback(self.checkHeaders, dict.fromkeys(['content-length', 'location'])) d.addCallback(_cb) # This is a nasty hack to always delete the <username>/private # namespace created for new users. Not doing this causes (weird) # breakage that spreads through the integration tests. def removePrivateNamespace(user): def deleted(ignored): return user deferred = self.deleteNamespace('/'.join([u.username, 'private'])) return deferred.addCallback(deleted) d.addCallback(removePrivateNamespace) return d
def getTagValueGeneral(self, path, objectId, accept='*/*', requesterUsername=None, requesterPassword=None): headers = {} self.addBasicAuthHeader(headers, requesterUsername, requesterPassword) if accept is not None: headers['accept'] = accept uri = '%s/%s/%s/%s' % ( self.endpoint, defaults.httpObjectCategoryName, str(objectId), path) d = http.getPage(uri, headers=headers) d.addCallback(self.checkStatus, txHttp.OK) d.addCallback(self.checkHeaders, {'content-type': None, 'last-modified': None}) d.addCallback(self.checkLastModifiedHeader) return d
def checkUserDetails(self, ign, username, name): """A callback that checks that doing a GET on username results in a payload with the passed values of name. This is used to (partly) check that a PUT or POST has done its job properly.""" headers = { 'accept': 'application/json', 'content-type': 'application/json', } self.addBasicAuthHeader(headers) d = http.getPage( '%s/%s/%s' % (self.endpoint, defaults.httpUserCategoryName, urllib.quote(username.encode('utf-8'))), headers=headers, method='GET') d.addCallback(self.checkStatus, txHttp.OK) d.addCallback(self.checkPayloadHas, {'name': name, 'id': None}) return d
def testUnknownPayloadField(self): headers = { 'accept': 'application/json', 'content-type': 'application/json', } self.addBasicAuthHeader(headers) data = { 'xxx_about': 'wee-hoo', } d = getPage('%s/%s' % (self.endpoint, defaults.httpObjectCategoryName), headers=headers, method='POST', postdata=json.dumps(data)) d.addErrback(self.checkErrorStatus, http.BAD_REQUEST) d.addErrback( self.checkErrorHeaders, {buildHeader('Error-Class'): error.UnknownPayloadField.__name__}) self.failUnlessFailure(d, Error) return d
def getPermissions(self, path, action, requesterUsername=None, requesterPassword=None): headers = { 'accept': 'application/json', } self.addBasicAuthHeader(headers, requesterUsername, requesterPassword) d = http.getPage( '%s/%s/%s?action=%s' % (self.endpoint, defaults.httpPermissionCategoryName, urllib.quote(path.encode('utf-8')), urllib.quote_plus(action)), headers=headers, method='GET') d.addCallback(self.checkStatus, txHttp.OK) d.addCallback(self.checkPayloadHas, dict.fromkeys(['policy', 'exceptions'])) result = yield d payload = result[2] dictionary = json.loads(payload) defer.returnValue((dictionary['policy'], dictionary['exceptions']))
def testAsAdminNoPayloadJSONP(self): parentPath = defaults.adminUsername headers = {} self.addBasicAuthHeader(headers) uri = '%s/%s/%s' % (self.endpoint, defaults.httpTagCategoryName, parentPath) params = { 'verb': 'POST', 'payload-length': 0, 'payload-type': 'application/json', } uriTag = uri + '?' + urlencode(params) try: yield wsfe_http.getPage(uriTag, headers=headers) except Exception, e: self.assertEqual(http.BAD_REQUEST, int(e.status)) self.assertEqual('MissingPayload', e.response_headers['x-fluiddb-error-class'][0])
def updatePermissions(self, path, action, policy, exceptions, requesterUsername=None, requesterPassword=None): headers = { 'accept': 'application/json', 'content-type': 'application/json', } self.addBasicAuthHeader(headers, requesterUsername, requesterPassword) data = { 'policy': policy, 'exceptions': exceptions, } d = http.getPage( '%s/%s/%s?action=%s' % (self.endpoint, defaults.httpPermissionCategoryName, urllib.quote(path.encode('utf-8')), urllib.quote_plus(action)), headers=headers, postdata=json.dumps(data), method='PUT') d.addCallback(self.checkStatus, txHttp.NO_CONTENT) d.addCallback(self.checkNoPayload) return d
def setTagValue(self, path, objectId, value, contentType=defaults.contentTypeForPrimitiveJSON, requesterUsername=None, requesterPassword=None): uri = '%s/%s/%s/%s' % ( self.endpoint, defaults.httpObjectCategoryName, str(objectId), urllib.quote(path.encode('utf-8'))) headers = {'content-type': contentType} self.addBasicAuthHeader(headers, requesterUsername, requesterPassword) try: serializer = _primitiveTypeSerializer[contentType] except KeyError: payload = value else: payload = serializer(value) d = http.getPage(uri, headers=headers, method='PUT', postdata=payload) d.addCallback(self.checkStatus, txHttp.NO_CONTENT) return d
def createNamespace(self, name, parentPath, description='', requesterUsername=None, requesterPassword=None): headers = { 'accept': 'application/json', 'content-type': 'application/json', } self.addBasicAuthHeader(headers, requesterUsername, requesterPassword) data = { 'name': name, 'description': description, } d = http.getPage( '%s/%s/%s' % (self.endpoint, defaults.httpNamespaceCategoryName, urllib.quote(parentPath.encode('utf-8'))), headers=headers, method='POST', postdata=json.dumps(data)) d.addCallback(self.checkStatus, txHttp.CREATED) d.addCallback(self.checkPayloadHas, dict.fromkeys(['id', 'URI'])) d.addCallback(self.checkHeaders, dict.fromkeys(['content-length', 'location'])) return d
def delete(self, requesterUsername=None, requesterPassword=None): if self.deleted: return defer.succeed(None) else: self.deleted = True def _cb((status, headers, page)): assert status == str(txHttp.NO_CONTENT) requesterUsername = requesterUsername or self.adminUsername requesterPassword = requesterPassword or self.adminPassword headers = {} _addBasicAuthHeader(headers, requesterUsername, requesterPassword) d = http.getPage( '%s/%s/%s' % (self.endpoint, defaults.httpUserCategoryName, urllib.quote(self.username.encode('utf-8'))), headers=headers, method='DELETE') d.addCallback(_cb) return d
def testAsAdminMissingRequiredPayloadFieldJSONP(self): """ Send a POST request to create a tag, but omit the 'indexed' key from the payload. Test that we get a Bad Request response, with the X-FluidDB-Error-Class header set to PayloadFieldMissing and X-FluidDB-Fieldname with containing 'indexed'. """ name = 'test' parentPath = defaults.adminUsername headers = {} self.addBasicAuthHeader(headers) uri = '%s/%s/%s' % (self.endpoint, defaults.httpTagCategoryName, parentPath) data = { 'description': 'some description', 'name': name, } payload = json.dumps(data) params = { 'verb': 'POST', 'payload': payload, 'payload-type': 'application/json', 'payload-length': len(payload), } uriTag = uri + '?' + urlencode(params) try: yield wsfe_http.getPage(uriTag, headers=headers) except Exception, e: self.assertEqual(http.BAD_REQUEST, int(e.status)) self.assertEqual('PayloadFieldMissing', e.response_headers['x-fluiddb-error-class'][0]) self.assertEqual('indexed', e.response_headers['x-fluiddb-fieldname'][0])