def test_cull_orphan_uids(self): # The reserved REST API needs to cull entries from the uid table that # are not associated with actual entries in the user table. manager = getUtility(IUserManager) uids = set() for i in range(10): user = manager.create_user() uids.add(user.user_id) # The testing infrastructure does not record the UIDs for new user # objects, so do that now to mimic the real system. UID.record(user.user_id) self.assertEqual(len(uids), 10) # Now add some orphan uids. orphans = set() for i in range(100, 113): uid = UID.record(uuid.UUID(int=i)) orphans.add(uid.uid) self.assertEqual(len(orphans), 13) # Normally we wouldn't do a query in a test, since we'd want the model # object to expose this, but we actually don't support exposing all # the UIDs to the rest of Mailman. all_uids = set(row[0] for row in config.db.store.query(UID.uid)) self.assertEqual(all_uids, uids | orphans) # Now, cull all the UIDs that aren't associated with users. Do use # the model API for this. UID.cull_orphans() non_orphans = set(row[0] for row in config.db.store.query(UID.uid)) self.assertEqual(uids, non_orphans) # And all the users still exist. non_orphans = set(user.user_id for user in manager.users) self.assertEqual(uids, non_orphans)
def test_delete_orphans(self): # When users are deleted, their UIDs are generally not deleted. We # never delete rows from that table in order to guarantee no # duplicates. However, some external testing frameworks want to be # able to reset the UID table, so they can use this interface to do # so. See LP: #1420083. # # Create some users. manager = getUtility(IUserManager) users_by_uid = {} with transaction(): for i in range(10): user = manager.create_user() users_by_uid[user.user_id] = user # The testing infrastructure does not record the UIDs for new # user options, so do that now to mimic the real system. UID.record(user.user_id) # We now have 10 unique uids. self.assertEqual(len(users_by_uid), 10) # Now delete all the users. with transaction(): for user in list(users_by_uid.values()): manager.delete_user(user) # There are still 10 unique uids in the database. self.assertEqual(UID.get_total_uid_count(), 10) # Cull the orphan UIDs. content, response = call_api( 'http://localhost:9001/3.0/reserved/uids/orphans', method='DELETE') self.assertEqual(response.status, 204) # Now there are no uids in the table. config.db.abort() self.assertEqual(UID.get_total_uid_count(), 0)
def _next_unpredictable_id(self): """Return a new UID. :return: The new uid :rtype: uuid.UUID """ while True: uid = uuid.uuid4() with suppress(ValueError): UID.record(uid) return uid
def new_uid(self): """Return a new UID. :return: The new uid :rtype: int """ if layers.is_testing(): # When in testing mode we want to produce predictable id, but we # need to coordinate this among separate processes. We could use # the database, but I don't want to add schema just to handle this # case, and besides transactions could get aborted, causing some # ids to be recycled. So we'll use a data file with a lock. This # may still not be ideal due to race conditions, but I think the # tests will be serialized enough (and the ids reset between # tests) that it will not be a problem. Maybe. return self._next_uid() while True: uid = uuid.uuid4() try: UID.record(uid) except ValueError: pass else: return uid
def on_delete(self, request, response): if self._resource_path != 'uids/orphans': not_found(response) return UID.cull_orphans() no_content(response)
def test_longs(self): # In a non-test environment, the uuid will be a long int. my_uuid = uuid.uuid4() UID.record(my_uuid) self.assertRaises(ValueError, UID.record, my_uuid)
def test_record(self): # Test that the .record() method works. UID.record(uuid.UUID(int=11)) UID.record(uuid.UUID(int=99)) self.assertRaises(ValueError, UID.record, uuid.UUID(int=11))
def test_get_total_uid_count(self): # The reserved REST API needs this. for i in range(10): UID.record(uuid.uuid4()) self.assertEqual(UID.get_total_uid_count(), 10)
def test_repr(self): uid = UID(uuid.UUID(int=1)) self.assertTrue(repr(uid).startswith( '<UID 00000000-0000-0000-0000-000000000001 at ')) self.assertTrue(repr(uid).endswith('>'))