def test_node_lineage_not_loaded_new_parent(self, db_session, root, events): from kotti.resources import Node from kotti.resources import get_root from kotti.events import ObjectEvent from kotti.events import objectevent_listeners # We want to guarantee that an object event handler can call # get_root(), which is only possible if our event handler # avoids flushing: objectevent_listeners[(ObjectEvent, Node)].append( lambda event: get_root()) parent = root['parent'] = Node() child1 = parent['child-1'] = Node() db_session.flush() child1_id = child1.id db_session.expunge_all() child2 = Node(name=u'child-2') child3 = Node(name=u'child-3') child1 = db_session.query(Node).get(child1_id) child3.parent = child2 child2.parent = child1 assert child3.path == u"/parent/child-1/child-2/child-3/"
def test_clear(self, db_session): from kotti import DBSession from kotti.resources import get_root from kotti.resources import Node child = get_root()['child'] = Node() assert DBSession.query(Node).filter(Node.name == u'child').all() == [ child ] get_root().clear() assert DBSession.query(Node).filter(Node.name == u'child').all() == []
def test_parent_copied(self, db_session, root, events, flush): from kotti.resources import Node c1 = root["c1"] = Node() c2 = c1["c2"] = Node() c2["c3"] = Node() if flush: db_session.flush() c1copy = root["c1copy"] = c1.copy() assert c1copy.path == "/c1copy/" assert c1copy["c2"].path == "/c1copy/c2/" assert c1copy["c2"]["c3"].path == "/c1copy/c2/c3/" c2copy = c2["c2copy"] = c2.copy() assert c2copy.path == "/c1/c2/c2copy/" assert c2copy["c3"].path == "/c1/c2/c2copy/c3/"
def test_query_api(self, db_session, root, events): from kotti.resources import Node child1 = root['child-1'] = Node() child2 = child1['child-2'] = Node() subchild = child2['subchild'] = Node() assert db_session.query(Node).filter( Node.path.startswith(u'/')).count() == 4 assert db_session.query(Node).filter( Node.path.startswith(u'/child-1/')).count() == 3 objs = db_session.query(Node).filter( Node.path.startswith(u'/child-1/child-2/')).all() assert len(objs) == 2 assert subchild in objs assert child2 in objs db_session.query(Node).filter( Node.path.startswith(u'/child-1/child-3/')).count() == 0
def test_node_copy_variants(self, db_session, root): from kotti.resources import Node child1 = root['child1'] = Node() child1['grandchild'] = Node() child2 = root['child2'] = Node() # first way; circumventing the Container API child2.children.append(child1.copy()) # second way; canonical way child2['child2'] = child1.copy() # third way; this is necessary in cases when copy() will # attempt to put the new node into the db already, e.g. when # the copy is already being back-referenced by some other # object in the db. child1.copy(parent=child2, name=u'child3') assert [child.name for child in child2.children ] == ['child1', 'child2', 'child3']
def test_node_copy_with_local_groups(self, db_session, root): from kotti.resources import Node from kotti.resources import LocalGroup child1 = root['child1'] = Node() local_group1 = LocalGroup(child1, u'joe', u'role:admin') db_session.add(local_group1) db_session.flush() child2 = root['child2'] = child1.copy() db_session.flush() assert child2.local_groups == []
def test_container_methods(self, db_session, root): from kotti.resources import Node # Test some of Node's container methods: assert root.keys() == [] child1 = Node(name='child1', parent=root) db_session.add(child1) assert root.keys() == ['child1'] assert root['child1'] == child1 del root['child1'] assert root.keys() == [] # When we delete a parent node, all its child nodes will be # released as well: root['child2'] = Node() root['child2']['subchild'] = Node() assert (db_session.query(Node).filter( Node.name == 'subchild').count() == 1) del root['child2'] assert (db_session.query(Node).filter( Node.name == 'subchild').count() == 0) # We can pass a tuple as the key to more efficiently reach # down to child objects: root['child3'] = Node() subchild33 = Node(name='subchild33', parent=root['child3']) db_session.add(subchild33) del root.__dict__['_children'] # force a different code path assert root['child3', 'subchild33'] is root['child3']['subchild33'] assert root[('child3', 'subchild33')] is subchild33 assert root[('child3', 'subchild33')] is subchild33 with raises(KeyError): # noinspection PyStatementEffect root['child3', 'bad-name'] # noinspection PyStatementEffect root.children # force a different code path with raises(KeyError): # noinspection PyStatementEffect root['child3', 'bad-name'] del root['child3'] # Overwriting an existing Node is an error; first delete manually! child4 = Node(name='child4', parent=root) db_session.add(child4) assert root.keys() == ['child4'] child44 = Node(name='child4') db_session.add(child44) with raises(SQLAlchemyError): root['child4'] = child44 db_session.flush()
def test_query_api(self, db_session, root, events): from kotti.resources import Node child1 = root["child-1"] = Node() child2 = child1["child-2"] = Node() subchild = child2["subchild"] = Node() assert db_session.query(Node).filter( Node.path.startswith("/")).count() == 4 assert (db_session.query(Node).filter( Node.path.startswith("/child-1/")).count() == 3) objs = (db_session.query(Node).filter( Node.path.startswith("/child-1/child-2/")).all()) assert len(objs) == 2 assert subchild in objs assert child2 in objs db_session.query(Node).filter( Node.path.startswith("/child-1/child-3/")).count() == 0
def test_container_methods(self): from kotti import DBSession from kotti.resources import get_root from kotti.resources import Node # Test some of Node's container methods: root = get_root() self.assertEquals(root.keys(), []) child1 = Node(name=u'child1', parent=root) DBSession.add(child1) self.assertEquals(root.keys(), [u'child1']) self.assertEquals(root[u'child1'], child1) del root[u'child1'] self.assertEquals(root.keys(), []) # When we delete a parent node, all its child nodes will be # released as well: root[u'child2'] = Node() root[u'child2'][u'subchild'] = Node() self.assertEquals( DBSession.query(Node).filter(Node.name == u'subchild').count(), 1) del root[u'child2'] self.assertEquals( DBSession.query(Node).filter(Node.name == u'subchild').count(), 0) # We can pass a tuple as the key to more efficiently reach # down to child objects: root[u'child3'] = Node() subchild33 = Node(name=u'subchild33', parent=root[u'child3']) DBSession.add(subchild33) del root.__dict__['_children'] # force a different code path self.assertTrue( root[u'child3', u'subchild33'] is root[u'child3'][u'subchild33']) self.assertTrue( root[(u'child3', u'subchild33')] is subchild33) self.assertTrue( root[(u'child3', u'subchild33')] is subchild33) self.assertRaises(KeyError, root.__getitem__, (u'child3', u'bad-name')) root.children # force a different code path self.assertRaises(KeyError, root.__getitem__, (u'child3', u'bad-name')) del root[u'child3'] # Overwriting an existing Node is an error; first delete manually! child4 = Node(name=u'child4', parent=root) DBSession.add(child4) self.assertEquals(root.keys(), [u'child4']) child44 = Node(name=u'child4') DBSession.add(child44) root[u'child4'] = child44 self.assertRaises(SQLAlchemyError, DBSession.flush)
def test_works_with_auth(self, db_session, root): from kotti.resources import Node from kotti.security import get_principals from kotti.security import list_groups_callback from kotti.security import set_groups child = root[u'child'] = Node() db_session.flush() request = DummyRequest() auth = CallbackAuthenticationPolicy() auth.unauthenticated_userid = lambda *args: 'bob' auth.callback = list_groups_callback request.context = root assert ( # user doesn't exist yet auth.effective_principals(request) == ['system.Everyone']) get_principals()[u'bob'] = dict(name=u'bob') assert (auth.effective_principals(request) == [ 'system.Everyone', 'system.Authenticated', 'bob' ]) # Define that bob belongs to bobsgroup on the root level: set_groups('bob', root, ['group:bobsgroup']) request.context = child assert (set(auth.effective_principals(request)) == { 'system.Everyone', 'system.Authenticated', 'bob', 'group:bobsgroup' }) # define that bob belongs to franksgroup in the user db: get_principals()[u'bob'].groups = [u'group:franksgroup'] set_groups('group:franksgroup', child, ['group:anothergroup']) assert (set(auth.effective_principals(request)) == { 'system.Everyone', 'system.Authenticated', 'bob', 'group:bobsgroup', 'group:franksgroup', 'group:anothergroup' }) # And lastly test that circular group defintions are not a # problem here either: get_principals()[u'group:franksgroup'] = dict( name=u'group:franksgroup', title=u"Frank's group", groups=[u'group:funnygroup', u'group:bobsgroup'], ) assert (set(auth.effective_principals(request)) == { 'system.Everyone', 'system.Authenticated', 'bob', 'group:bobsgroup', 'group:franksgroup', 'group:anothergroup', 'group:funnygroup' })
def add_some_groups(): from kotti import DBSession from kotti.resources import get_root from kotti.resources import Node from kotti.security import set_groups root = get_root() child = root[u'child'] = Node() grandchild = child[u'grandchild'] = Node() DBSession.flush() # root: # bob -> group:bobsgroup # frank -> group:franksgroup # group:franksgroup -> role:editor # child: # group:bobsgroup -> group:franksgroup # grandchild: # group:franksgroup -> role:admin # group:franksgroup -> group:bobsgroup # bob and frank are a site-wide members of their respective groups: set_groups('bob', root, ['group:bobsgroup']) set_groups('frank', root, ['group:franksgroup']) # franksgroup has a site-wide editor role: set_groups('group:franksgroup', root, ['role:editor']) # bobsgroup is part of franksgroup on the child level: set_groups('group:bobsgroup', child, ['group:franksgroup']) # franksgroup has the admin role on the grandchild. # and finally, to test recursion, we make franksgroup part of # bobsgroup on the grandchild level: set_groups('group:franksgroup', grandchild, ['role:owner', 'group:bobsgroup'])
def test_node_copy_with_local_groups(self): from kotti import DBSession from kotti.resources import get_root from kotti.resources import Node from kotti.resources import LocalGroup root = get_root() child1 = root['child1'] = Node() local_group1 = LocalGroup(child1, u'joe', u'role:admin') DBSession.add(local_group1) DBSession.flush() child2 = root['child2'] = child1.copy() DBSession.flush() assert child2.local_groups == []
def test_append_to_empty_acl(self, db_session, root): from kotti.resources import Node node = root["child"] = Node() node.__acl__ = [] db_session.flush() db_session.expire_all() node.__acl__.append(("Allow", "system.Authenticated", ["edit"])) db_session.flush() db_session.expire_all() assert node.__acl__ == [ ("Allow", "role:admin", ALL_PERMISSIONS), ("Allow", "system.Authenticated", ["edit"]), ]
def test_local_roles_db_cascade(self, db_session, root): from kotti.resources import LocalGroup from kotti.resources import Node from kotti.security import set_groups child = root["child"] = Node() db_session.flush() # We set a local group on child and delete child. We then # expect the LocalGroup entry to have been deleted from the # database: assert db_session.query(LocalGroup).count() == 0 set_groups("group:bobsgroup", child, ["role:editor"]) assert db_session.query(LocalGroup).count() == 1 del root["child"] db_session.flush() assert db_session.query(LocalGroup).count() == 0
def test_append_to_empty_acl(self, db_session, root): from kotti.resources import Node node = root['child'] = Node() node.__acl__ = [] db_session.flush() db_session.expire_all() node.__acl__.append(('Allow', 'system.Authenticated', ['edit'])) db_session.flush() db_session.expire_all() assert node.__acl__ == [ ('Allow', 'role:admin', ALL_PERMISSIONS), ('Allow', 'system.Authenticated', ['edit']), ]
def test_groups_from_users(self, db_session, root): from kotti.resources import Node from kotti.security import list_groups from kotti.security import set_groups self.make_bob() child = root[u'child'] = Node() db_session.flush() assert list_groups('bob', root) == ['group:bobsgroup'] set_groups('group:bobsgroup', root, ['role:editor']) set_groups('role:editor', child, ['group:foogroup']) assert (set(list_groups('bob', root)) == set( ['group:bobsgroup', 'role:editor'])) assert (set(list_groups('bob', child)) == set( ['group:bobsgroup', 'role:editor', 'group:foogroup']))
def test_inherit(self, db_session, root): from kotti.resources import Node from kotti.security import list_groups from kotti.security import list_groups_raw from kotti.security import set_groups child = root["child"] = Node() db_session.flush() assert list_groups("bob", child) == [] set_groups("bob", root, ["role:editor"]) assert list_groups("bob", child) == ["role:editor"] # Groups from the child are added: set_groups("bob", child, ["group:somegroup"]) assert set(list_groups("bob", child)) == {"group:somegroup", "role:editor"} # We can ask to list only those groups that are defined locally: assert list_groups_raw("bob", child) == {"group:somegroup"}
def test_groups_from_users(self, db_session, root): from kotti.resources import Node from kotti.security import list_groups from kotti.security import set_groups self.make_bob() child = root["child"] = Node() db_session.flush() assert list_groups("bob", root) == ["group:bobsgroup"] set_groups("group:bobsgroup", root, ["role:editor"]) set_groups("role:editor", child, ["group:foogroup"]) assert set(list_groups("bob", root)) == {"group:bobsgroup", "role:editor"} assert set(list_groups("bob", child)) == { "group:bobsgroup", "role:editor", "group:foogroup", }
def test_local_roles_db_cascade(self): from kotti import DBSession from kotti.resources import get_root from kotti.resources import LocalGroup from kotti.resources import Node from kotti.security import set_groups root = get_root() child = root[u'child'] = Node() DBSession.flush() # We set a local group on child and delete child. We then # expect the LocalGroup entry to have been deleted from the # database: self.assertEqual(DBSession.query(LocalGroup).count(), 0) set_groups('group:bobsgroup', child, ['role:editor']) self.assertEqual(DBSession.query(LocalGroup).count(), 1) del root[u'child'] DBSession.flush() self.assertEqual(DBSession.query(LocalGroup).count(), 0)
def test_inherit(self, db_session, root): from kotti.resources import Node from kotti.security import list_groups from kotti.security import list_groups_raw from kotti.security import set_groups child = root[u'child'] = Node() db_session.flush() assert list_groups('bob', child) == [] set_groups('bob', root, ['role:editor']) assert list_groups('bob', child) == ['role:editor'] # Groups from the child are added: set_groups('bob', child, ['group:somegroup']) assert (set(list_groups('bob', child)) == {'group:somegroup', 'role:editor'}) # We can ask to list only those groups that are defined locally: assert list_groups_raw(u'bob', child) == {'group:somegroup'}
def test_groups_from_users(self): from kotti import DBSession from kotti.resources import get_root from kotti.resources import Node from kotti.security import list_groups from kotti.security import set_groups self.make_bob() root = get_root() child = root[u'child'] = Node() DBSession.flush() self.assertEqual(list_groups('bob', root), ['group:bobsgroup']) set_groups('group:bobsgroup', root, ['role:editor']) set_groups('role:editor', child, ['group:foogroup']) self.assertEqual(set(list_groups('bob', root)), set(['group:bobsgroup', 'role:editor'])) self.assertEqual( set(list_groups('bob', child)), set(['group:bobsgroup', 'role:editor', 'group:foogroup']))
def test_inherit(self): from kotti import DBSession from kotti.resources import get_root from kotti.resources import Node from kotti.security import list_groups from kotti.security import list_groups_raw from kotti.security import set_groups root = get_root() child = root[u'child'] = Node() DBSession.flush() self.assertEqual(list_groups('bob', child), []) set_groups('bob', root, ['role:editor']) self.assertEqual(list_groups('bob', child), ['role:editor']) # Groups from the child are added: set_groups('bob', child, ['group:somegroup']) self.assertEqual(set(list_groups('bob', child)), set(['group:somegroup', 'role:editor'])) # We can ask to list only those groups that are defined locally: self.assertEqual(list_groups_raw(u'bob', child), set(['group:somegroup']))
def test_principals_with_local_roles(self, db_session, root): from kotti.resources import Node from kotti.security import map_principals_with_local_roles from kotti.security import principals_with_local_roles from kotti.security import set_groups child = root[u'child'] = Node() db_session.flush() assert principals_with_local_roles(root) == [] assert principals_with_local_roles(child) == [] assert map_principals_with_local_roles(root) == [] assert map_principals_with_local_roles(child) == [] set_groups('group:bobsgroup', child, ['role:editor']) set_groups('bob', root, ['group:bobsgroup']) set_groups('group:franksgroup', root, ['role:editor']) assert (set(principals_with_local_roles(child)) == set( ['bob', 'group:bobsgroup', 'group:franksgroup'])) assert (set(principals_with_local_roles(child, inherit=False)) == set( ['group:bobsgroup'])) assert (set(principals_with_local_roles(root)) == set( ['bob', 'group:franksgroup']))
def test_works_with_auth(self, db_session, root): from kotti.resources import Node from kotti.security import get_principals from kotti.security import list_groups_callback from kotti.security import set_groups child = root["child"] = Node() db_session.flush() request = DummyRequest() auth = CallbackAuthenticationPolicy() auth.unauthenticated_userid = lambda *args: "bob" auth.callback = list_groups_callback request.context = root assert auth.effective_principals( request) == [ # user doesn't exist yet "system.Everyone" ] get_principals()["bob"] = dict(name="bob") assert auth.effective_principals(request) == [ "system.Everyone", "system.Authenticated", "bob", ] # Define that bob belongs to bobsgroup on the root level: set_groups("bob", root, ["group:bobsgroup"]) request.context = child assert set(auth.effective_principals(request)) == { "system.Everyone", "system.Authenticated", "bob", "group:bobsgroup", } # define that bob belongs to franksgroup in the user db: get_principals()["bob"].groups = ["group:franksgroup"] set_groups("group:franksgroup", child, ["group:anothergroup"]) assert set(auth.effective_principals(request)) == { "system.Everyone", "system.Authenticated", "bob", "group:bobsgroup", "group:franksgroup", "group:anothergroup", } # And lastly test that circular group defintions are not a # problem here either: get_principals()["group:franksgroup"] = dict( name="group:franksgroup", title="Frank's group", groups=["group:funnygroup", "group:bobsgroup"], ) assert set(auth.effective_principals(request)) == { "system.Everyone", "system.Authenticated", "bob", "group:bobsgroup", "group:franksgroup", "group:anothergroup", "group:funnygroup", }
def test_replace_root(self, db_session, root, events): from kotti.resources import Node db_session.delete(root) new_root = Node(u'') db_session.add(new_root) assert new_root.path == '/'
def test_object_moved(self, db_session, root, events): from kotti.resources import Node child = root['child-1'] = Node() subchild = child['subchild'] = Node() subchild.parent = root assert subchild.path == '/subchild/'