def test_store(self): conn = self.db.open() try: app = conn.root()['Application'] f = Folder() f.id = 'Holidays' app._setObject(f.id, f, set_owner=0) transaction.commit() f2 = Folder() f2.id = 'Christmas' f._setObject(f2.id, f2, set_owner=0) transaction.commit() f3 = Folder() f3.id = 'Eve' f2._setObject(f3.id, f3, set_owner=0) transaction.commit() conn2 = self.db.open() try: app = conn2.root()['Application'] self.assert_(hasattr(app, 'Holidays')) self.assert_(hasattr(app.Holidays, 'Christmas')) self.assert_(hasattr(app.Holidays.Christmas, 'Eve')) # Verify the same OID is seen in both connections. self.assertEqual(app.Holidays._p_oid, f._p_oid) finally: conn2.close() finally: conn.close()
def testGenerateIdDenialOfServicePrevention(self): for n in range(10): item = Folder() item.id = "item%d" % n self.f._setOb(item.id, item) self.f.generateId("item", rand_ceiling=20) # Shouldn't be a problem self.assertRaises(ExhaustedUniqueIdsError, self.f.generateId, "item", rand_ceiling=9)
def manage_doCustomize(self, folder_path, RESPONSE=None): ''' Makes a Folder with the same properties. ''' custFolder = self.getCustomizableObject() fpath = tuple(split(folder_path, '/')) folder = self.restrictedTraverse(fpath) id = self.getId() obj = Folder(id) map = [] for p in self._properties: # This should be secure since the properties come # from the filesystem. setattr(obj, p['id'], getattr(self, p['id'])) map.append({ 'id': p['id'], 'type': p['type'], 'mode': 'wd', }) obj._properties = tuple(map) obj.id = id folder._verifyObjectPaste(obj, validate_src=0) folder._setObject(id, obj) if RESPONSE is not None: RESPONSE.redirect('%s/%s/manage_propertiesForm' % (folder.absolute_url(), id))
def test_store_properties(self): conn = self.db.open() try: app = conn.root()['Application'] f = Folder() f.id = 'Holidays' f.title = 'Holiday Calendar' app._setObject(f.id, f, set_owner=0) transaction.commit() f._setProperty('pi', 3.14, 'float') f._setProperty('stuff', ['a', 'bc', 'd'], 'lines') transaction.commit() conn2 = self.db.open() try: app = conn2.root()['Application'] self.assert_(hasattr(app, 'Holidays')) got = 0 for k, v in app.Holidays.propertyItems(): if k == 'title': got += 1 self.assertEqual(v, 'Holiday Calendar') elif k == 'pi': got += 1 self.assertEqual(v, 3.14) elif k == 'stuff': got += 1 self.assertEqual(tuple(v), ('a', 'bc', 'd')) self.assertEqual(got, 3) finally: conn2.close() finally: conn.close()
def manage_addMounts(dispatcher, paths=(), create_mount_points=True, REQUEST=None): """Adds MountedObjects at the requested paths. """ count = 0 app = dispatcher.getPhysicalRoot() for path in paths: mo = MountedObject(path) mo._create_mount_points = not not create_mount_points # Raise an error now if there is any problem. mo._test(app) blazer = SimpleTrailblazer(app) container = blazer.traverseOrConstruct(path, omit_final=1) container._p_jar.add(mo) loaded = mo.__of__(container) # Add a faux object to avoid generating manage_afterAdd() events # while appeasing OFS.ObjectManager._setObject(), then discreetly # replace the faux object with a MountedObject. faux = Folder() faux.id = mo.id faux.meta_type = loaded.meta_type container._setObject(faux.id, faux) # DM 2005-05-17: we want to keep our decision about automatic # mount point creation #del mo._create_mount_points container._setOb(faux.id, mo) setMountPoint(container, faux.id, mo) count += 1 if REQUEST is not None: REQUEST['RESPONSE'].redirect(REQUEST['URL1'] + ('/manage_main?manage_tabs_message=' 'Added %d mount points.' % count))
def test_upo_state_after_deactivate(self): # An unmanaged persistent object that gets deactivated # and reactivated should have the most recent state. self.db.setCacheSize(10) # Don't flush the objects at commit conn = self.db.open() try: app = conn.root()['Application'] f = Folder() f.id = 'Holidays' f.stowaway = Folder() f.stowaway.id = 'stowaway' f.stowaway._prop = 'value1' app._setObject(f.id, f, set_owner=0) transaction.commit() self.assertEqual(f._p_changed, 0) self.assertEqual(f.stowaway._p_oid, 'unmanaged') f.stowaway._prop = 'value2' transaction.commit() self.assertEqual(f._p_changed, 0) del f.stowaway._p_changed self.assertEqual(f.stowaway._p_changed, None) self.assertEqual(f.stowaway._prop, 'value2') finally: conn.close()
def test_btreefolder2(self): from Products.BTreeFolder2.BTreeFolder2 import BTreeFolder2 conn = self.db.open() try: app = conn.root()['Application'] f = BTreeFolder2('Holidays') f.id = 'Holidays' app._setObject(f.id, f, set_owner=0) f2 = Folder() f2.id = 'Easter' app.Holidays._setObject(f2.id, f2) transaction.commit() # Verify serialize() found the unmanaged subobjects. self.assertEqual(app.Holidays._tree._p_oid, 'unmanaged') # Sanity check self.assertEqual(app.Holidays.objectCount(), 1) conn2 = self.db.open() try: app2 = conn2.root()['Application'] self.assert_(app2.Holidays._tree.has_key('Easter')) self.assert_(not app2.Holidays.__dict__.has_key('Easter')) # Verify deserialize() found the unmanaged subobjects. self.assertEqual(app2.Holidays._tree._p_oid, 'unmanaged') app2.Holidays._delObject('Easter') transaction.commit() finally: conn2.close() # The deletion should be seen by both connections. conn.sync() self.assertEqual(app.Holidays.objectCount(), 0) finally: conn.close()
def manage_addMounts(dispatcher, paths=(), create_mount_points=True, REQUEST=None): """Adds MountedObjects at the requested paths. """ count = 0 app = dispatcher.getPhysicalRoot() for path in paths: mo = MountedObject(path) mo._create_mount_points = not not create_mount_points # Raise an error now if there is any problem. mo._test(app) blazer = SimpleTrailblazer(app) container = blazer.traverseOrConstruct(path, omit_final=1) container._p_jar.add(mo) loaded = mo.__of__(container) # Add a faux object to avoid generating manage_afterAdd() events # while appeasing OFS.ObjectManager._setObject(), then discreetly # replace the faux object with a MountedObject. faux = Folder() faux.id = mo.id faux.meta_type = loaded.meta_type container._setObject(faux.id, faux) # DM 2005-05-17: we want to keep our decision about automatic # mount point creation #del mo._create_mount_points container._setOb(faux.id, mo) setMountPoint(container, faux.id, mo) count += 1 if REQUEST is not None: REQUEST['RESPONSE'].redirect( REQUEST['URL1'] + ('/manage_main?manage_tabs_message=' 'Added %d mount points.' % count))
def testQueueProcessingLimit(self): # Don't try to process too many items at once. app = self.app for n in range(100): f = Folder() f.id = 'f%d' % n setattr(app, f.id, f) f = getattr(app, f.id) app.queue_cat.catalog_object(f) # None of the items should be in the meta_type index yet. res = app.queue_cat.searchResults(meta_type='Folder') self.assertEqual(len(res), 0) # Process only 10 of the items. app.queue_cat.process(max=10) # There should now be 10 items in the results. res = app.queue_cat.searchResults(meta_type='Folder') self.assertEqual(len(res), 10) # Process another 25. app.queue_cat.process(max=25) # There should now be 35 items in the results. res = app.queue_cat.searchResults(meta_type='Folder') self.assertEqual(len(res), 35) # Finish. app.queue_cat.process() res = app.queue_cat.searchResults(meta_type='Folder') self.assertEqual(len(res), 100)
def test_rename(self): conn = self.db.open() try: app = conn.root()['Application'] f = Folder() f.id = 'Holidays' app._setObject(f.id, f, set_owner=0) transaction.commit() # Do what manage_rename does, without the security checks ob = app.Holidays.aq_base app._delObject('Holidays') ob._setId('HolidayCalendar') app._setObject(ob.id, ob, set_owner=0) transaction.commit() self.assert_(hasattr(app, 'HolidayCalendar')) self.assert_(not hasattr(app, 'Holidays')) conn2 = self.db.open() try: app = conn2.root()['Application'] self.assert_(hasattr(app, 'HolidayCalendar')) self.assert_(not hasattr(app, 'Holidays')) finally: conn2.close() finally: conn.close()
def test_anyfolder_storage(self): # Try to store a folderish object of an otherwise unknown class conn = self.db.open() try: app = conn.root()['Application'] f = Folder() f.id = 'Holidays' app._setObject(f.id, f, set_owner=0) transaction.commit() f2 = TestFolder("New Year's Eve") f2.id = 'NewYear' f._setObject(f2.id, f2, set_owner=0) transaction.commit() # Verify the object is in its own database record self.assertNotEqual(f2._p_oid, None) f2._p_changed = None self.assert_(f2._p_changed is None) # Verify the ability to load it conn2 = self.db.open() try: app2 = conn2.root()['Application'] ff = app2.Holidays.NewYear self.assertEqual(ff.title, "New Year's Eve") self.assertEqual(ff.__class__, TestFolder) finally: conn2.close() finally: conn.close()
def testGenerateIdDenialOfServicePrevention(self): for n in range(10): item = Folder() item.id = 'item%d' % n self.f._setOb(item.id, item) self.f.generateId('item', rand_ceiling=20) # Shouldn't be a problem self.assertRaises(ExhaustedUniqueIdsError, self.f.generateId, 'item', rand_ceiling=9)
def testReplace(self): old_f = Folder() old_f.id = 'item' inner_f = HBTreeFolder2('inner') old_f._setObject(inner_f.id, inner_f) self.ff._populateFromFolder(old_f) self.assertEqual(self.ff.objectCount(), 1) self.assert_(self.ff.has_key('inner')) self.assertEqual(self.getBase(self.ff._getOb('inner')), inner_f)
def setUp(self): f1 = Folder() f1.id = 'f1' self.f1 = f1 f2 = Folder() f2.id = 'f2' self.f1.f2 = f2 f3 = Folder() f3.id = 'f3' self.f1.f2.f3 = f3 f4 = Folder() f4.id = 'f4' self.f1.f2.f4 = f4 f4_1 = Folder() f4_1.id = 'f4' self.f1.f4 = f4_1 f1.portal_url = URLTool() f1.refs = ReferenceCollection()
def testReplace(self): old_f = Folder() old_f.id = 'item' inner_f = BTreeFolder2('inner') old_f._setObject(inner_f.id, inner_f) self.ff._populateFromFolder(old_f) self.assertEqual(self.ff.objectCount(), 1) self.assert_('inner' in self.ff) self.assertEqual(self.getBase(self.ff._getOb('inner')), inner_f)
def createTileContainer(self, tileContainerName=None): """ create a container for the next group of tiles within the data container """ if hasattr(self._v_saveFolderObject, tileContainerName): # allow for tiles to be updated from a changed image self._v_saveFolderObject._delObject(tileContainerName) if not hasattr(self._v_saveFolderObject, tileContainerName): newFolder = Folder() newFolder.id = tileContainerName self._v_saveFolderObject._setObject(tileContainerName, newFolder) transaction.savepoint() return
def testObjectIdsWithMetaType(self): f2 = Folder() f2.id = "subfolder" self.f._setOb(f2.id, f2) mt1 = self.ff.meta_type mt2 = Folder.meta_type self.assertEqual(list(self.f.objectIds(mt1)), ["item"]) self.assertEqual(list(self.f.objectIds((mt1,))), ["item"]) self.assertEqual(list(self.f.objectIds(mt2)), ["subfolder"]) lst = list(self.f.objectIds([mt1, mt2])) lst.sort() self.assertEqual(lst, ["item", "subfolder"]) self.assertEqual(list(self.f.objectIds("blah")), [])
def testObjectIdsWithMetaType(self): f2 = Folder() f2.id = 'subfolder' self.f._setOb(f2.id, f2) mt1 = self.ff.meta_type mt2 = Folder.meta_type self.assertEqual(list(self.f.objectIds(mt1)), ['item']) self.assertEqual(list(self.f.objectIds((mt1, ))), ['item']) self.assertEqual(list(self.f.objectIds(mt2)), ['subfolder']) lst = list(self.f.objectIds([mt1, mt2])) lst.sort() self.assertEqual(lst, ['item', 'subfolder']) self.assertEqual(list(self.f.objectIds('blah')), [])
def createDataContainer(self): """ create a folder that contains all the tiles of the image """ self._v_saveToLocation = str(self._v_imageObject.getId()) + "_data" parent = self._v_imageObject.aq_parent if hasattr(parent, self._v_saveToLocation): # allow for tiles to be updated from a changed image parent._delObject(self._v_saveToLocation) if not hasattr(parent, self._v_saveToLocation): newFolder = Folder() newFolder.id = self._v_saveToLocation parent._setObject(self._v_saveToLocation, newFolder) self._v_saveFolderObject = parent[self._v_saveToLocation] transaction.savepoint() return
def createDataContainer(self): """ create a folder that contains all the tiles of the image """ self._v_saveToLocation = str(self._v_imageObject.getId()) + '_data' parent = self._v_imageObject.aq_parent if hasattr(parent, self._v_saveToLocation): # allow for tiles to be updated from a changed image parent._delObject(self._v_saveToLocation) if not hasattr(parent, self._v_saveToLocation): newFolder = Folder() newFolder.id = self._v_saveToLocation parent._setObject(self._v_saveToLocation, newFolder) self._v_saveFolderObject = parent[self._v_saveToLocation] transaction.savepoint() return
def _createZODBClone(self): """Create a ZODB (editable) equivalent of this object.""" # Create a Folder to hold the properties. obj = Folder() obj.id = self.getId() map = [] for p in self._properties: # This should be secure since the properties come # from the filesystem. setattr(obj, p['id'], getattr(self, p['id'])) map.append({'id': p['id'], 'type': p['type'], 'mode': 'wd',}) obj._properties = tuple(map) return obj
def _createZODBClone(self): """Create a ZODB (editable) equivalent of this object.""" # Create a Folder to hold the properties. obj = Folder() obj.id = self.getId() map = [] for p in self._properties: # This should be secure since the properties come # from the filesystem. setattr(obj, p['id'], getattr(self, p['id'])) map.append({'id': p['id'], 'type': p['type'], 'mode': 'wd', }) obj._properties = tuple(map) return obj
def addWikiFromFs(self, new_id, title='', wiki_type='zwikidotorg', REQUEST=None): """ Create a new zwiki web from the specified template on the filesystem. """ parent = self.Destination() # Go with a BTreeFolder from the start to avoid hassle with large # wikis on low-memory hosted servers ? #parent.manage_addProduct['BTreeFolder2'].manage_addBTreeFolder( #str(new_id),str(title)) # No - the standard folder's UI is more useful for small wikis, # and more importantly BTreeFolder2 isn't standard until 2.8.0b2 f = Folder() f.id, f.title = str(new_id), str(title) new_id = parent._setObject(f.id, f) f = parent[new_id] # add objects from wiki template # cataloging really slows this down! dir = os.path.join(package_home(globals()),'wikis',wiki_type) filenames = os.listdir(dir) for filename in filenames: if re.match(r'(?:\..*|CVS|_darcs)', filename): continue m = re.search(r'(.+)\.(.+)',filename) id, type = filename, '' if m: id, type = m.groups() text = open(dir + os.sep + filename, 'r').read() if type == 'dtml': addDTMLMethod(f, filename[:-5], title='', file=text) elif re.match(r'(?:(?:stx|html|latex)(?:dtml)?|txt)', type): addZWikiPage(f,id,title='',page_type=type,file=text) elif type == 'pt': f._setObject(id, ZopePageTemplate(id, text, 'text/html')) elif type == 'py': f._setObject(id, PythonScript(id)) f._getOb(id).write(text) elif type == 'zexp' or type == 'xml': connection = self.getPhysicalRoot()._p_jar f._setObject(id, connection.importFile(dir + os.sep + filename, customImporters=customImporters)) #self._getOb(id).manage_changeOwnershipType(explicit=0) elif re.match(r'(?:jpe?g|gif|png)', type): f._setObject(filename, Image(filename, '', text)) else: id = f._setObject(filename, File(filename, '', text)) if type == 'css': f[filename].content_type = 'text/css' f.objectValues(spec='ZWiki Page')[0].updatecontents()
def testImmediateDeletion(self): app = self.app app.test_cat = QueueCatalog(1000) # 1000 buckets to prevent collisions app.test_cat.id = 'test_cat' app.test_cat.manage_edit(location='/real_cat', immediate_indexes=['id'], immediate_removal=1) for n in range(20): f = Folder() f.id = 'f%d' % n setattr(app, f.id, f) f = getattr(app, f.id) app.test_cat.catalog_object(f) self.assertEqual(app.test_cat.manage_size(), 20) # "Delete" one. This should be processed immediately (including # the add-event) app.test_cat.uncatalog_object(getattr(app, 'f1').getPhysicalPath()) self.assertEqual(app.test_cat.manage_size(), 19) del app.test_cat
def test_store_property_types(self): # Test that Ape restores properties to the correct types. from DateTime import DateTime now = DateTime() conn = self.db.open() try: app = conn.root()['Application'] f = Folder() f.id = 'Holidays' app._setObject(f.id, f, set_owner=0) transaction.commit() f._setProperty('string1', 's', 'string') f._setProperty('float1', 3.14, 'float') f._setProperty('int1', 5, 'int') f._setProperty('long1', 2L**33, 'long') f._setProperty('date1', now, 'date') f._setProperty('date2', now, 'date_international') f._setProperty('text1', 'abc\ndef', 'text') f._setProperty('boolean0', 0, 'boolean') f._setProperty('boolean1', 1, 'boolean') transaction.commit() conn2 = self.db.open() try: app2 = conn2.root()['Application'] f2 = app2.Holidays self.assertEqual(f2.string1, 's') self.assertEqual(f2.float1, 3.14) self.assertEqual(f2.int1, 5) self.assertEqual(f2.long1, 2L**33) self.assertEqual(f2.date1.ISO(), now.ISO()) self.assertEqual(f2.date2.ISO(), now.ISO()) self.assertEqual(f2.text1, 'abc\ndef') self.assertEqual(f2.boolean0, 0) self.assertEqual(f2.boolean1, 1) finally: conn2.close() finally: conn.close()
def test_write_with_ghosts(self): # It should be possible to write a container even if one # or more of its subobjects are ghosts. conn = self.db.open() try: root = conn.root() root['foo'] = 1 f = Folder() f.id = 'bar' root['bar'] = f transaction.commit() conn2 = self.db.open() try: root2 = conn2.root() root2['foo'] = 2 self.assertEqual(root2['bar']._p_changed, None) transaction.commit() finally: conn2.close() finally: conn.close()
def test_store_selection_properties(self): conn = self.db.open() try: app = conn.root()['Application'] f = Folder() f.id = 'Holidays' f.title = 'Holiday Calendar' app._setObject(f.id, f, set_owner=0) transaction.commit() f._setProperty('choices', ['alpha', 'omega', 'delta'], 'lines') f._setProperty('greek', 'choices', 'multiple selection') f._setProperty('hebrew', 'choices', 'selection') f.greek = ['alpha', 'omega'] f.hebrew = 'alpha' transaction.commit() conn2 = self.db.open() try: app = conn2.root()['Application'] self.assert_(hasattr(app, 'Holidays')) got = 0 for k, v in app.Holidays.propertyItems(): if k == 'greek': got += 1 self.assertEqual(tuple(v), ('alpha', 'omega')) if k == 'hebrew': got += 1 self.assertEqual(v, 'alpha') self.assertEqual(got, 2) # Be sure the select_variable got restored. dict = app.Holidays.propdict() self.assertEqual(dict['greek']['select_variable'], 'choices') self.assertEqual(dict['hebrew']['select_variable'], 'choices') finally: conn2.close() finally: conn.close()
def manage_doCustomize(self, folder_path, RESPONSE=None): ''' Makes a Folder with the same properties. ''' custFolder = self.getCustomizableObject() fpath = tuple(split(folder_path, '/')) folder = self.restrictedTraverse(fpath) id = self.getId() obj = Folder(id) map = [] for p in self._properties: # This should be secure since the properties come # from the filesystem. setattr(obj, p['id'], getattr(self, p['id'])) map.append({'id': p['id'], 'type': p['type'], 'mode': 'wd',}) obj._properties = tuple(map) obj.id = id folder._verifyObjectPaste(obj, validate_src=0) folder._setObject(id, obj) if RESPONSE is not None: RESPONSE.redirect('%s/%s/manage_propertiesForm' % ( folder.absolute_url(), id))
def test_deactivate_unmanaged_persistent(self): # Some Zope code deactivates unmanaged persistent objects. # Verify that Ape can handle it. conn = self.db.open() try: app = conn.root()['Application'] f = Folder() f.id = 'Holidays' f.stowaway = Folder() f.stowaway.id = 'stowaway' f.stowaway._prop = 'value1' app._setObject(f.id, f, set_owner=0) transaction.commit() f.stowaway._p_deactivate() self.assertEqual(f.stowaway._prop, 'value1') # Check aborting changes to an unmanaged object. f.stowaway._prop = 'value2' self.assertEqual(f._p_changed, 1) transaction.abort() self.assertEqual(f.stowaway._prop, 'value1') self.assertEqual(f._p_changed, 0) finally: conn.close()
def test_security_attributes(self): conn = self.db.open() try: app = conn.root()['Application'] f = Folder() f.id = 'Holidays' app._setObject(f.id, f, set_owner=0) f = app.Holidays u = UserFolder() u.id = 'acl_users' f._setObject(u.id, u, set_owner=0) u._doAddUser('shane', 'abcdefg', ('Elder', ), ()) f._owner = (['Holidays', 'acl_users'], 'shane') f.__ac_roles__ = ['Elder', 'Manager', 'Missionary'] f.__ac_local_roles__ = {'shane': ['Missionary']} f._proxy_roles = ['Manager'] f._View_Permission = ('Owner', 'Elder') f._Add_Folders_Permission = ['Elder'] transaction.commit() conn2 = self.db.open() try: # Verify that loading works app = conn2.root()['Application'] f2 = app.Holidays user = f2.getOwner() self.assertEqual(user.getUserName(), 'shane') self.assert_('Elder' in user.getRoles()) self.assertEqual(list(f2.__ac_roles__), ['Elder', 'Manager', 'Missionary']) roles = {} for role in list(user.getRolesInContext(f2)): if role != 'Authenticated' and role != 'Anonymous': roles[role] = 1 self.assertEqual(roles, {'Elder': 1, 'Missionary': 1}) self.assertEqual(tuple(f2._proxy_roles), ('Manager', )) self.assert_(isinstance(f2._View_Permission, TupleType), "View permission should not be acquired") self.assert_(isinstance(f2._Add_Folders_Permission, ListType), "Add Folders permission should be acquired") roles = {} for role in list(f2._View_Permission): roles[role] = 1 self.assertEqual(roles, {'Elder': 1, 'Owner': 1}) # Write some changes to verify that changes work f2._owner = None del f2._proxy_roles f2.__ac_roles__ += ('Teacher', ) transaction.commit() finally: conn2.close() # Make sure the changes are seen conn.sync() self.assert_(f.getOwner() is None, f.getOwner()) self.assert_(not hasattr(f, '_proxy_roles')) self.assertEqual(list(f.__ac_roles__), ['Elder', 'Manager', 'Missionary', 'Teacher']) finally: conn.close()
def test_security_attributes(self): conn = self.db.open() try: app = conn.root()['Application'] f = Folder() f.id = 'Holidays' app._setObject(f.id, f, set_owner=0) f = app.Holidays u = UserFolder() u.id = 'acl_users' f._setObject(u.id, u, set_owner=0) u._doAddUser('shane', 'abcdefg', ('Elder',), ()) f._owner = (['Holidays', 'acl_users'], 'shane') f.__ac_roles__ = ['Elder', 'Manager', 'Missionary'] f.__ac_local_roles__ = {'shane': ['Missionary']} f._proxy_roles = ['Manager'] f._View_Permission = ('Owner', 'Elder') f._Add_Folders_Permission = ['Elder'] transaction.commit() conn2 = self.db.open() try: # Verify that loading works app = conn2.root()['Application'] f2 = app.Holidays user = f2.getOwner() self.assertEqual(user.getUserName(), 'shane') self.assert_('Elder' in user.getRoles()) self.assertEqual( list(f2.__ac_roles__), ['Elder', 'Manager', 'Missionary']) roles = {} for role in list(user.getRolesInContext(f2)): if role != 'Authenticated' and role != 'Anonymous': roles[role] = 1 self.assertEqual(roles, {'Elder':1, 'Missionary':1}) self.assertEqual(tuple(f2._proxy_roles), ('Manager',)) self.assert_(isinstance(f2._View_Permission, TupleType), "View permission should not be acquired") self.assert_(isinstance(f2._Add_Folders_Permission, ListType), "Add Folders permission should be acquired") roles = {} for role in list(f2._View_Permission): roles[role] = 1 self.assertEqual(roles, {'Elder':1, 'Owner':1}) # Write some changes to verify that changes work f2._owner = None del f2._proxy_roles f2.__ac_roles__ += ('Teacher',) transaction.commit() finally: conn2.close() # Make sure the changes are seen conn.sync() self.assert_(f.getOwner() is None, f.getOwner()) self.assert_(not hasattr(f, '_proxy_roles')) self.assertEqual( list(f.__ac_roles__), ['Elder', 'Manager', 'Missionary', 'Teacher']) finally: conn.close()