def test_remove_not_running(self):
     not_running = None
     for pid in range(1000, 20000):
          if not EnforceSingleTask.check_pid(pid):
             not_running = pid
             break
     self.assertIsNotNone(not_running)
     ##
     # Create an entry 'owned' by PID of 'not_running'
     ##
     task_id = "test_remove_not_running_task_id"
     entry = SingleTaskInfo(task_id=task_id, owner_pid=not_running)
     entry.save()
     self.assertEquals(1, SingleTaskInfo.objects(task_id=task_id).count())
     retval = EnforceSingleTask.remove_not_running(task_id)
     self.assertIsNotNone(retval)
     # verify it has been removed
     self.assertEquals(0, SingleTaskInfo.objects(task_id=task_id).count())
     ##
     # Create an entry 'owned' by running PID, verify it is not removed
     ##
     entry = SingleTaskInfo(task_id=task_id, owner_pid=os.getpid())
     entry.save()
     self.assertEquals(1, SingleTaskInfo.objects(task_id=task_id).count())
     retval = EnforceSingleTask.remove_not_running(task_id)
     # verify it has _not_ been removed
     self.assertIsNone(retval)
     self.assertEquals(1, SingleTaskInfo.objects(task_id=task_id).count())
 def test_release_from_diff_pid(self):
     # Create an entry from a dummy pid
     task_id = "test_release_from_diff_pid_task_id"
     pid = os.getpid() + 1
     entry = SingleTaskInfo(task_id=task_id, owner_pid=pid)
     entry.save()
     self.assertEquals(1, SingleTaskInfo.objects(task_id=task_id).count())
     self.assertIsNone(EnforceSingleTask.release(task_id))
     # Verify the remove did nothing because our 'pid' didn't match the entrie's pid
     self.assertEquals(1, SingleTaskInfo.objects(task_id=task_id).count())
 def lock(cls, task_id, seconds_expire):
     # Rationale:
     #  It is possible that this task may run and clean an expired task yet not be able to 'obtain a lock',
     #  as another process may be able to write the entry first.  This is fine.  Our concern is simply to allow
     #  only 1 to form the lock.
     cls.remove_not_running(task_id)
     cls.remove_expired(task_id, seconds_expire)
     obj = SingleTaskInfo(task_id=task_id, owner_pid=os.getpid())
     try:
         obj.save()
     except  NotUniqueError, e:
         return False
 def _get_collection(cls):
     # We are defering when this gets called because we saw issues with resolving to the unit test database
     # when this was simply added as class level variable.
     # We need this to be invoked after the unit tests have switched over to their own database
     # Otherwise we run the risk of using 2 DBs:
     # - one for general mongoengine calls for SingleTaskInfo.save()
     # - second for pymongo find_and_modify()
     return SingleTaskInfo._get_collection()
 def test_remove_by_owner(self):
     task_id = "test_remove_by_owner_task_id"
     pid = os.getpid()
     entry = SingleTaskInfo(task_id=task_id, owner_pid=pid)
     entry.save()
     self.assertEquals(1, SingleTaskInfo.objects(task_id=task_id).count())
     retval = EnforceSingleTask.remove_by_owner(task_id, pid)
     self.assertIsNotNone(retval)
     self.assertEquals(0, SingleTaskInfo.objects(task_id=task_id).count())
     ##
     # Simulate how another process that used there own pid wouldn't
     # delete the entry
     ##
     pid = os.getpid() + 1
     entry = SingleTaskInfo(task_id=task_id, owner_pid=pid)
     entry.save()
     self.assertEquals(1, SingleTaskInfo.objects(task_id=task_id).count())
     retval = EnforceSingleTask.remove_by_owner(task_id, os.getpid())
     self.assertIsNone(retval)
     self.assertEquals(1, SingleTaskInfo.objects(task_id=task_id).count())
 def remove_not_running(cls, task_id):
     existing_task = SingleTaskInfo.objects(task_id=task_id).first()
     if existing_task:
         if not cls.check_pid(existing_task.owner_pid):
             # Rationale for why this is safe from race conditions.
             #  'remove_by_owner' will only delete the task if the entry is still 'owned' by the dead PID
             #  if another process cleans this up then the entry will be owned by a different PID and
             #  the findAndModify will not find the entry and results in no change.
             ret_val = cls.remove_by_owner(task_id, existing_task.owner_pid)
             if not ret_val:
                 _LOG.warning("Unsuccessful in removing a task info entry on '%s' from pid '%s' created on '%s'." % \
                              (task_id, existing_task.owner_pid, existing_task.created))
             return ret_val
 def test_remove_expired(self):
     # Create an 'expired' entry
     threshold=5
     task_id = "test_remove_expored_task_id"
     created = datetime.now(tzutc()) - timedelta(seconds=threshold+1)
     entry = SingleTaskInfo(task_id=task_id, owner_pid=os.getpid(), created=created)
     entry.save()
     self.assertEquals(1, SingleTaskInfo.objects(task_id=task_id).count())
     retval = EnforceSingleTask.remove_expired(task_id, seconds_expire=threshold)
     # Verify it is removed
     self.assertIsNotNone(retval)
     self.assertEquals(0, SingleTaskInfo.objects(task_id=task_id).count())
     ##
     # Create an entry that is not expired
     ##
     created = datetime.now(tzutc())
     entry = SingleTaskInfo(task_id=task_id, owner_pid=os.getpid(), created=created)
     entry.save()
     self.assertEquals(1, SingleTaskInfo.objects(task_id=task_id).count())
     retval = EnforceSingleTask.remove_expired(task_id, seconds_expire=threshold)
     # Verify it is _not_ removed
     self.assertIsNone(retval)
     self.assertEquals(1, SingleTaskInfo.objects(task_id=task_id).count())