def removeTestingData(): """ Delete L{User}s, L{Namespace}s and L{Tag}s used for testing purposes. """ admin = getUser(u'fluiddb') logging.info('Deleting testing tags.') result = TagAPI(admin).get(TESTING_DATA[u'tags']) if result: TagAPI(admin).delete(result.keys()) logging.info('Deleting testing namespaces.') result = NamespaceAPI(admin).get(TESTING_DATA[u'namespaces']) # we must delete namespaces one by one, otherwise we'll get NotEmptyError. for path in sorted(result.keys(), reverse=True): NamespaceAPI(admin).delete([path]) logging.info('Deleting testing users.') result = UserAPI().get(TESTING_DATA[u'users']) if result: for username in result: path = '%s/private' % username try: NamespaceAPI(admin).delete([path]) except FeatureError: # FIXME This is a bit crap, but it's faster than checking to # see if the namespace exists before attempting to delete it. continue if result: UserAPI().delete(result.keys()) getMainStore().commit()
def setUp(self): super(NamespaceAPITest, self).setUp() self.system = createSystemData() UserAPI().create([(u'username', u'password', u'User', u'*****@*****.**')]) self.user = getUser(u'username') self.namespaces = NamespaceAPI(self.user) self.permissions = PermissionAPI(self.user)
def testPrepareForTestingCreatesNamespaces(self): """ L{prepareForTesting} creates all the necessary testing L{Namespace}s. """ prepareForTesting() paths = [u'fluiddb/testing/testing', u'testuser1/testing/testing', u'testuser2/testing/testing'] namespaces = NamespaceAPI(self.admin).get(paths) self.assertEqual(paths, sorted(namespaces.iterkeys()))
def testDeleteNamespace(self): """L{Facade.deleteNamespace} deletes a L{Namespace}.""" namespaces = NamespaceAPI(self.user) namespaces.create([(u'username/name', u'A namespace.')]) self.store.commit() with login(u'username', self.user.objectID, self.transact) as session: yield self.facade.deleteNamespace(session, u'username/name') self.store.rollback() self.assertEqual({}, namespaces.get([u'username/name']))
def testPrepareForTestingCreatesNamespaces(self): """ L{prepareForTesting} creates all the necessary testing L{Namespace}s. """ prepareForTesting() paths = [ u'fluiddb/testing/testing', u'testuser1/testing/testing', u'testuser2/testing/testing' ] namespaces = NamespaceAPI(self.admin).get(paths) self.assertEqual(paths, sorted(namespaces.iterkeys()))
def testGetNamespaceWithDescription(self): """ L{Facade.getNamespace} includes the L{Namespace.description}, if it was requested. """ namespaces = NamespaceAPI(self.user) namespaces.create([(u'username/name', u'A namespace.')]) self.store.commit() with login(u'username', self.user.objectID, self.transact) as session: result = yield self.facade.getNamespace(session, u'username/name', True, False, False) self.assertEqual(u'A namespace.', result.description)
def testGetNamespaceWithNamespaces(self): """ L{Facade.getNamespace} includes child L{Namespace.name}s, if they were requested. """ namespaces = NamespaceAPI(self.user) namespaces.create([(u'username/name', u'A namespace.')]) self.store.commit() with login(u'username', self.user.objectID, self.transact) as session: result = yield self.facade.getNamespace(session, u'username', False, True, False) self.assertEqual([u'name', u'private'], sorted(result.namespaces))
def testDeleteNamespaceWithData(self): """ L{Facade.deleteNamespace} raises a L{TNamespaceNotEmpty} exception if the requested L{Namespace} has child data such as other L{Namespace}s or L{Tag}s. """ namespaces = NamespaceAPI(self.user) namespaces.create([(u'username/parent', u'A parent namespace.')]) namespaces.create([(u'username/parent/child', u'A child namespace.')]) self.store.commit() with login(u'username', self.user.objectID, self.transact) as session: deferred = self.facade.deleteNamespace(session, u'username/parent') yield self.assertFailure(deferred, TNamespaceNotEmpty)
def testDeleteIsDenied(self): """ L{Facade.deleteNamespace} raises a L{TPathPermissionDenied} exception if the user doesn't have C{DELETE} permissions on the specified L{Namespace}. """ namespaces = NamespaceAPI(self.user) namespaces.create([(u'username/test', u'description')]) self.permissions.set([(u'username/test', Operation.DELETE_NAMESPACE, Policy.OPEN, [u'username'])]) self.store.commit() with login(u'username', self.user.objectID, self.transact) as session: deferred = self.facade.deleteNamespace(session, u'username/test') yield self.assertFailure(deferred, TPathPermissionDenied)
def apply(store): # Using model code in a patch isn't ideal, but writing this patch with # pure SQL will be heinous. for user in getUsers(): if user.username in ('fluiddb', 'anon'): continue namespaces = NamespaceAPI(user) path = '%s/private' % user.username if not namespaces.get([path]): namespaces.create([ (path, u'Private namespace for user %s' % user.username) ]) namespace = getNamespaces(paths=[path]).one() permission = namespace.permission permission.set(Operation.LIST_NAMESPACE, Policy.CLOSED, [user.id])
class NamespaceAPITest(NamespaceAPITestMixin, FluidinfoTestCase): resources = [('config', ConfigResource()), ('store', DatabaseResource())] def setUp(self): super(NamespaceAPITest, self).setUp() self.system = createSystemData() UserAPI().create([(u'username', u'password', u'User', u'*****@*****.**')]) self.user = getUser(u'username') self.namespaces = NamespaceAPI(self.user) self.permissions = PermissionAPI(self.user) def testCreateWithoutData(self): """ L{NamespaceAPI.create} returns an empty C{list} if no L{Namespace} data is available. """ result = self.namespaces.create([]) self.assertEqual([], result) ignored = ( self.system.namespaces.keys() + [u'username', u'username/private']) result = self.store.find(Namespace, Not(Namespace.path.is_in(ignored))) self.assertIdentical(None, result.one()) def testPermissionsAreNotCreatedIfCreateFails(self): """ If L{NamespaceAPI.create} fails, no permissions should be created. """ self.assertRaises(MalformedPathError, self.namespaces.create, [(u'!!!!/test', u'description')]) result = getNamespacePermissions([u'username/test']) self.assertTrue(result.is_empty())
def testCheckIntegrityChecksErrorInAllRows(self): """ L{checkIntegrity} should check for integrity errors in L{Namespace}s, L{Tag}s, L{User}s, L{AboutTagValue}s and L{TagValue}s. """ createSystemData() [(userObjectID, _)] = UserAPI().create([(u'user', u'pass', u'Name', u'*****@*****.**')]) user = getUser(u'user') result = NamespaceAPI(user).create([(u'user/namespace', u'description') ]) [(namespaceObjectID, _)] = result [(tagObjectID, _)] = TagAPI(user).create([(u'user/tag', u'description') ]) objectID1 = uuid4() objectID2 = uuid4() createAboutTagValue(objectID1, u'Bad about tag') TagValueAPI(user).set({objectID2: {u'fluiddb/about': 'about value'}}) TagValueAPI(user).delete([(userObjectID, u'fluiddb/users/username')]) TagValueAPI(user).delete([(namespaceObjectID, u'fluiddb/namespaces/path')]) TagValueAPI(user).delete([(tagObjectID, u'fluiddb/tags/description')]) checkIntegrity() self.assertEqual( "Integrity Error in namespace u'user/namespace': " 'Path tag is missing.\n' "Integrity Error in tag u'user/tag': Description tag is missing.\n" "Integrity Error in user u'user': Username tag is missing.\n" "Integrity Error in object %s: AboutTagValue doesn't have an " 'associated TagValue.\n' "Integrity Error in object %s: fluiddb/about TagValue doesn't " 'have an associated AboutTagValue.\n' % (objectID1, objectID2), self.log.getvalue())
class NamespaceAPITest(NamespaceAPITestMixin, FluidinfoTestCase): resources = [('config', ConfigResource()), ('store', DatabaseResource())] def setUp(self): super(NamespaceAPITest, self).setUp() self.system = createSystemData() UserAPI().create([(u'username', u'password', u'User', u'*****@*****.**')]) self.user = getUser(u'username') self.namespaces = NamespaceAPI(self.user) self.permissions = PermissionAPI(self.user) def testCreateWithoutData(self): """ L{NamespaceAPI.create} returns an empty C{list} if no L{Namespace} data is available. """ result = self.namespaces.create([]) self.assertEqual([], result) ignored = (self.system.namespaces.keys() + [u'username', u'username/private']) result = self.store.find(Namespace, Not(Namespace.path.is_in(ignored))) self.assertIdentical(None, result.one()) def testPermissionsAreNotCreatedIfCreateFails(self): """ If L{NamespaceAPI.create} fails, no permissions should be created. """ self.assertRaises(MalformedPathError, self.namespaces.create, [(u'!!!!/test', u'description')]) result = getNamespacePermissions([u'username/test']) self.assertTrue(result.is_empty())
def testUpdateNamespace(self): """ L{Facade.updateNamespace} updates the description for an existing L{Namespace}. """ namespaces = NamespaceAPI(self.user) namespaces.create([(u'username/name', u'A namespace.')]) self.store.commit() with login(u'username', self.user.objectID, self.transact) as session: yield self.facade.updateNamespace(session, u'username/name', u'A new description.') self.store.rollback() result = namespaces.get([u'username/name'], withDescriptions=True) self.assertEqual(u'A new description.', result[u'username/name']['description'])
def testRemoveTestingDataWithPartialData(self): """ L{removeTestingData} only tries to remove testing data that exists. """ UserAPI().create([(u'testuser1', 'secret', u'Test user', u'*****@*****.**')]) NamespaceAPI(self.admin).delete([u'testuser1/private']) removeTestingData() users = UserAPI().get([u'testuser1', u'testuser2']) self.assertEquals({}, users)
class CachingNamespaceAPI(object): """The public API to cached namespace-related logic in the model. @param user: The L{User} to perform operations on behalf of. """ def __init__(self, user): self._api = NamespaceAPI(user, factory=CachingAPIFactory()) def create(self, values): """See L{NamespaceAPI.create}.""" return self._api.create(values) def delete(self, paths): """See L{NamespaceAPI.delete}. Permissions for deleted L{Namespace}s are removed from the cache. """ if isgenerator(paths): paths = list(paths) cache = PermissionCache() cache.clearNamespacePermissions(paths) return self._api.delete(paths) def get(self, paths, withDescriptions=None, withNamespaces=None, withTags=None): """See L{NamespaceAPI.get}.""" return self._api.get(paths, withDescriptions=withDescriptions, withNamespaces=withNamespaces, withTags=withTags) def set(self, values): """Set or update L{Namespace}s. @param values: A C{dict} mapping L{Namespace.path}s to descriptions. @return: A C{list} of C{(objectID, Namespace.path)} 2-tuples representing the L{Namespace}s that were updated. """ return self._api.set(values)
def testRemoveTestingDataRemovesNamespaces(self): """L{removeTestingData} removes all the testing L{Namespace}s.""" prepareForTesting() removeTestingData() paths = [ u'fluiddb/testing/testing', u'testuser1/testing/testing', u'testuser2/testing/testing' ] namespaces = NamespaceAPI(self.admin).get(paths) self.assertEqual({}, namespaces)
def testCreateRootNamespace(self): """ L{NamespaceAPI.create} creates new root L{Namespace}s based on the provided data. """ superuser = self.system.users[u'fluiddb'] values = [(u'root-namespace', u'A description.')] NamespaceAPI(superuser).create(values) result = self.store.find(Namespace, Namespace.path == u'root-namespace') namespace = result.one() self.assertEqual(u'root-namespace', namespace.path) self.assertEqual(u'root-namespace', namespace.name) self.assertIdentical(None, namespace.parent)
def prepareForTesting(): """ Create a set of L{User}s, L{Namespace}s and L{Tag}s for testing purposes. """ admin = getUser(u'fluiddb') logging.info('Creating testing users.') UserAPI().create([(username, 'secret', u'Test user', u'*****@*****.**') for username in TESTING_DATA[u'users']]) logging.info('Creating testing namespaces.') NamespaceAPI(admin).create([(namespace, u'Used for testing purposes.') for namespace in TESTING_DATA[u'namespaces']]) logging.info('Creating testing tags.') TagAPI(admin).create([(tag, u'Used for testing purposes.') for tag in TESTING_DATA[u'tags']]) getMainStore().commit()
def testCheckWithSuperuser(self): """ L{checkPermissions} always grants access if the user is superuser. """ TagAPI(self.user).create([(u'username/path', u'description')]) NamespaceAPI(self.user).create([(u'username/path', u'description')]) superuser = self.system.users[u'fluiddb'] # Close all permissions for the tag values = [(u'username/path', operation, Policy.CLOSED, []) for operation in Operation.PATH_OPERATIONS] self.permissions.set(values) values = [(u'username/path', operation) for operation in Operation.PATH_OPERATIONS] deniedOperations = checkPermissions(superuser, values) self.assertEqual([], deniedOperations)
def testDeleteRemovesSystemTags(self): """ L{UserAPI.delete} removes the C{fluiddb/users/*} tag values stored for deleted L{User}s. """ self.users.create([(u'user', u'pass', u'User', u'*****@*****.**')]) user = getUser(u'user') NamespaceAPI(user).delete([u'user/private']) [(objectID, _)] = self.users.delete([u'user']) tagValues = TagValueAPI(self.system.users[u'fluiddb']) result = tagValues.get(objectIDs=[objectID], paths=[ u'fluiddb/users/username', u'fluiddb/users/name', u'fluiddb/users/email', u'fluiddb/users/role' ]) self.assertEqual({}, result)
def testCheckWithSuperuserWithMissingPermission(self): """ L{checkPermissions} always grants access if the user is superuser, even if there is no permission defined for the entity for which access is requested. """ TagAPI(self.user).create([(u'username/path', u'description')]) NamespaceAPI(self.user).create([(u'username/path', u'description')]) superuser = self.system.users[u'fluiddb'] # Close all permissions for the tag values = [(u'username/path', operation, Policy.CLOSED, []) for operation in Operation.NAMESPACE_OPERATIONS] self.permissions.set(values) values = [(u'username/path', operation) for operation in Operation.NAMESPACE_OPERATIONS] deniedOperations = checkPermissions(superuser, values) self.assertEqual([], deniedOperations)
def testCheckAnonymousForbiddenOperations(self): """ L{checkPermissions} always denies C{CREATE}, C{UPDATE}, or C{DELETE} operations if the user is anonymous. """ TagAPI(self.user).create([(u'username/path', u'description')]) NamespaceAPI(self.user).create([(u'username/path', u'description')]) anonymous = self.system.users[u'anon'] forbiddenOperations = (Operation.TAG_OPERATIONS + Operation.NAMESPACE_OPERATIONS + Operation.USER_OPERATIONS + Operation.CONTROL_OPERATIONS + [Operation.CREATE_OBJECT]) for operation in Operation.ALLOWED_ANONYMOUS_OPERATIONS: forbiddenOperations.remove(operation) values = [(u'username/path', operation) for operation in forbiddenOperations] deniedOperations = checkPermissions(anonymous, values) self.assertEqual(sorted(values), sorted(deniedOperations))
def testRemoveTestingDataWithNonexistentData(self): """ L{removeTestingData} doesn't remove anything it the testing data doesn't exist. """ removeTestingData() paths = [ u'fluiddb/testing/test1', u'fluiddb/testing/test2', u'testuser1/testing/test1', u'testuser1/testing/test2', u'testuser2/testing/test1', u'testuser2/testing/test2' ] tags = TagAPI(self.admin).get(paths) self.assertEqual({}, tags) paths = [ u'fluiddb/testing/testing', u'testuser1/testing/testing', u'testuser2/testing/testing' ] namespaces = NamespaceAPI(self.admin).get(paths) self.assertEqual({}, namespaces) users = UserAPI().get([u'testuser1', u'testuser2']) self.assertEquals({}, users)
def testCheckIntegrityGetsAllRowsUsingMultipleQueries(self): """ L{checkIntegrity} should check all the rows of a given object using multiple queries if the C{maxRowsPerQuery} argument is smaller than the total number of rows for a given object. """ createSystemData() UserAPI().create([(u'user', u'pass', u'Name', u'*****@*****.**')]) user = getUser(u'user') paths = [u'user/namespace%d' % i for i in xrange(10)] values = [(path, u'description') for path in paths] NamespaceAPI(user).create(values) namespaces = getNamespaces(paths=paths) values = [(namespace.objectID, u'fluiddb/namespaces/path') for namespace in namespaces] TagValueAPI(user).delete(values) checkIntegrity(maxRowsPerQuery=2) error = 'Integrity Error in namespace %r: Path tag is missing.' expectedErrors = '\n'.join(error % path for path in paths) + '\n' self.assertEqual(expectedErrors, self.log.getvalue())
def __init__(self, user): self._api = NamespaceAPI(user, factory=CachingAPIFactory())
def namespaces(self, user): """Get a new L{NamespaceAPI} instance.""" from fluiddb.model.namespace import NamespaceAPI return NamespaceAPI(user)