def test_on_job_executed_cb(self): data = {'runs':[], 'ctx':[]} def get_context(): ctx = {'name': rand_string(), 'type':SCHEDULER.JOB_TYPE.INTERVAL_BASED} data['ctx'].append(ctx) return ctx def on_job_executed_cb(ctx): data['runs'].append(ctx) test_wait_time = 0.5 job_sleep_time = 0.1 job_max_repeats = 10 job = Job(rand_int(), 'a', SCHEDULER.JOB_TYPE.INTERVAL_BASED, Interval(seconds=0.1), max_repeats=job_max_repeats) job.wait_sleep_time = job_sleep_time job.get_context = get_context scheduler = Scheduler(get_scheduler_config(), None) scheduler.lock = RLock() scheduler.iter_cb = iter_cb scheduler.iter_cb_args = (scheduler, datetime.utcnow() + timedelta(seconds=test_wait_time)) scheduler.on_job_executed_cb = on_job_executed_cb scheduler.create(job, spawn=False) scheduler.run() self.assertEquals(len(data['runs']), len(data['ctx'])) for idx, item in enumerate(data['runs']): self.assertEquals(data['ctx'][idx], item)
def test_on_max_repeats_reached(self): test_wait_time = 0.5 job_sleep_time = 0.02 job_max_repeats = 3 data = {'job': None, 'called': 0} job = Job(rand_int(), 'a', SCHEDULER.JOB_TYPE.INTERVAL_BASED, Interval(seconds=0.1), max_repeats=job_max_repeats) job.wait_sleep_time = job_sleep_time # Just to make sure it's inactive by default. self.assertTrue(job.is_active) scheduler = Scheduler(get_scheduler_config(), None) data['old_on_max_repeats_reached'] = scheduler.on_max_repeats_reached def on_max_repeats_reached(job): data['job'] = job data['called'] += 1 data['old_on_max_repeats_reached'](job) scheduler.on_max_repeats_reached = on_max_repeats_reached scheduler.iter_cb = iter_cb scheduler.iter_cb_args = (scheduler, datetime.utcnow() + timedelta(seconds=test_wait_time)) scheduler.create(job) scheduler.run() now = datetime.utcnow() # Now the job should have reached the max_repeats limit within the now - test_wait_time period. self.assertIs(job, data['job']) self.assertEquals(1, data['called']) self.assertTrue(job.max_repeats_reached) self.assertFalse(job.keep_running) self.assertTrue(job.max_repeats_reached_at < now) self.assertTrue(job.max_repeats_reached_at >= now + timedelta(seconds=-test_wait_time)) # Having run out of max_repeats it should not be active now. self.assertFalse(job.is_active)
def test_edit(self): def callback(): pass def on_max_repeats_reached_cb(): pass start_time = datetime.utcnow() test_wait_time = 0.5 job_interval1, job_interval2 = 2, 3 job_sleep_time = 10 job_max_repeats1, job_max_repeats2 = 20, 30 scheduler = Scheduler(get_scheduler_config(), None) scheduler.lock = RLock() scheduler.iter_cb = iter_cb scheduler.iter_cb_args = (scheduler, datetime.utcnow() + timedelta(seconds=test_wait_time)) def check(scheduler, job, label): self.assertIn(job.name, scheduler.job_greenlets) self.assertIn(job, scheduler.jobs) self.assertEquals(1, len(scheduler.job_greenlets)) self.assertEquals(1, len(scheduler.jobs)) self.assertIs(job.run.im_func, scheduler.job_greenlets.values()[0]._run.im_func) clone = list(scheduler.jobs)[0] for name in 'name', 'interval', 'cb_kwargs', 'max_repeats', 'is_active': expected = getattr(job, name) given = getattr(clone, name) self.assertEquals(expected, given, '{} != {} ({})'.format(expected, given, name)) job_cb = job.callback clone_cb = clone.callback job_on_max_cb = job.on_max_repeats_reached_cb clone_on_max_cb = clone.on_max_repeats_reached_cb if label == 'first': self.assertEquals(job.start_time, clone.start_time) self.assertIs(job_cb.im_func, clone_cb.im_func) self.assertIs(job_on_max_cb.im_func, clone_on_max_cb.im_func) else: self.assertEquals(job.start_time, clone.start_time) self.assertIs(clone_cb.im_func, scheduler.on_job_executed.im_func) self.assertIs(clone_on_max_cb.im_func, scheduler.on_max_repeats_reached.im_func) job1 = Job(rand_int(), 'a', SCHEDULER.JOB_TYPE.INTERVAL_BASED, Interval(seconds=job_interval1), start_time, max_repeats=job_max_repeats1) job1.callback = callback job1.on_max_repeats_reached_cb = on_max_repeats_reached_cb job1.wait_sleep_time = job_sleep_time job2 = Job(rand_int(), 'a', SCHEDULER.JOB_TYPE.INTERVAL_BASED, Interval(seconds=job_interval2), start_time, max_repeats=job_max_repeats2) job2.callback = callback job2.on_max_repeats_reached_cb = on_max_repeats_reached_cb job2.wait_sleep_time = job_sleep_time scheduler.run() scheduler.create(job1) sleep(test_wait_time) # We have only job1 at this point check(scheduler, job1, 'first') # Removes job1 along the way .. scheduler.edit(job2) # .. so now job2 is the now removed job1. check(scheduler, job2, 'second')
def test_job_greenlets(self): data = {'spawned':[], 'stopped': []} class FakeGreenlet(object): def __init__(_self, run): _self.run = _self._run = run def kill(_self, *args, **kwargs): data['stopped'].append([_self, args, kwargs]) def spawn(scheduler_instance, job, *args, **kwargs): g = FakeGreenlet(job) data['spawned'].append(g) return g with patch('zato.scheduler.backend.Scheduler._spawn', spawn): test_wait_time = 0.5 job_sleep_time = 10 job_max_repeats = 30 job1 = Job(rand_int(), 'a', SCHEDULER.JOB_TYPE.INTERVAL_BASED, Interval(seconds=0.1), max_repeats=job_max_repeats) job1.wait_sleep_time = job_sleep_time job2 = Job(rand_int(), 'b', SCHEDULER.JOB_TYPE.INTERVAL_BASED, Interval(seconds=0.1), max_repeats=job_max_repeats) job2.wait_sleep_time = job_sleep_time scheduler = Scheduler(get_scheduler_config(), None) scheduler.lock = RLock() scheduler.iter_cb = iter_cb scheduler.iter_cb_args = (scheduler, datetime.utcnow() + timedelta(seconds=test_wait_time)) scheduler.create(job1) scheduler.create(job2) scheduler.run() self.assertEquals(scheduler.job_greenlets[job1.name]._run, job1.run) self.assertEquals(scheduler.job_greenlets[job2.name]._run, job2.run) self.assertTrue(job1.keep_running) self.assertTrue(job2.keep_running) scheduler.unschedule(job1) self.assertFalse(job1.keep_running) self.assertTrue(job2.keep_running) self.assertNotIn(job1.name, scheduler.job_greenlets) self.assertEquals(scheduler.job_greenlets[job2.name]._run, job2.run) self.assertEquals(len(data['stopped']), 1) g, args, kwargs = data['stopped'][0] self.assertIs(g.run.im_func, job1.run.im_func) # That's how we know it was job1 deleted not job2 self.assertIs(args, ()) self.assertDictEqual(kwargs, {'timeout':2.0, 'block':False})
def test_delete(self): test_wait_time = 0.5 job_sleep_time = 10 job_max_repeats = 30 job1 = Job(rand_int(), 'a', SCHEDULER.JOB_TYPE.INTERVAL_BASED, Interval(seconds=0.1), max_repeats=job_max_repeats) job1.wait_sleep_time = job_sleep_time job2 = Job(rand_int(), 'b', SCHEDULER.JOB_TYPE.INTERVAL_BASED, Interval(seconds=0.1), max_repeats=job_max_repeats) job2.wait_sleep_time = job_sleep_time scheduler = Scheduler(get_scheduler_config(), None) scheduler.lock = RLock() scheduler.iter_cb = iter_cb scheduler.iter_cb_args = (scheduler, datetime.utcnow() + timedelta(seconds=test_wait_time)) scheduler.create(job1) scheduler.create(job2) scheduler.run() scheduler.unschedule(job1) self.assertIn(job2, scheduler.jobs) self.assertNotIn(job1, scheduler.jobs) self.assertFalse(job1.keep_running) # run - 1 # create - 2 # delete - 1 # on_max_repeats_reached - 0 (because of how long it takes to run job_max_repeats with test_wait_time) # 1+2+1 = 4 self.assertEquals(scheduler.lock.called, 4)
def test_run(self): test_wait_time = 0.3 sched_sleep_time = 0.1 data = {'sleep': [], 'jobs':set()} def _sleep(value): data['sleep'].append(value) def spawn_job(job): data['jobs'].add(job) def job_run(self): pass job1, job2, job3 = [get_job(str(x)) for x in range(3)] # Already run out of max_repeats and should not be started job4 = Job(rand_int(), rand_string(), SCHEDULER.JOB_TYPE.INTERVAL_BASED, start_time=parse_datetime('1997-12-23 21:24:27'), interval=Interval(seconds=5), max_repeats=3) job1.run = job_run job2.run = job_run job3.run = job_run job4.run = job_run config = Bunch() config.on_job_executed_cb = dummy_callback config._add_startup_jobs = False config._add_scheduler_jobs = False config.startup_jobs = [] config.odb = None config.job_log_level = 'info' scheduler = Scheduler(get_scheduler_config(), None) scheduler.spawn_job = spawn_job scheduler.lock = RLock() scheduler.sleep = _sleep scheduler.sleep_time = sched_sleep_time scheduler.iter_cb = iter_cb scheduler.iter_cb_args = (scheduler, datetime.utcnow() + timedelta(seconds=test_wait_time)) scheduler.create(job1, spawn=False) scheduler.create(job2, spawn=False) scheduler.create(job3, spawn=False) scheduler.create(job4, spawn=False) scheduler.run() self.assertEquals(3, len(data['jobs'])) self.assertTrue(scheduler.lock.called) for item in data['sleep']: self.assertEquals(sched_sleep_time, item) for job in job1, job2, job3: self.assertIn(job, data['jobs']) self.assertNotIn(job4, data['jobs'])
def test_create(self): data = {'spawned_jobs': 0} def on_job_executed(*ignored): pass def job_run(*ignored): pass def spawn(scheduler_instance, func): self.assertIs(func, job_run) data['spawned_jobs'] += 1 with patch('zato.scheduler.backend.Scheduler._spawn', spawn): scheduler = Scheduler(get_scheduler_config(), None) scheduler.lock = RLock() scheduler.on_job_executed = on_job_executed job1 = get_job() job1.run = job_run job2 = get_job() job2.run = job_run job3 = get_job(name=job2.name) job3.run = job_run job4 = get_job() job5 = get_job() job6 = get_job(prefix='inactive') job6.is_active = False scheduler.create(job1) scheduler.create(job2) # These two won't be added because scheduler.jobs is a set hashed by a job's name. scheduler.create(job2) scheduler.create(job3) # The first one won't be spawned but the second one will. scheduler.create(job4, spawn=False) scheduler.create(job5, spawn=True) # Won't be added anywhere nor spawned because it's inactive. scheduler.create(job6) self.assertEquals(scheduler.lock.called, 7) self.assertEquals(len(scheduler.jobs), 5) self.assertIn(job1, scheduler.jobs) self.assertIn(job2, scheduler.jobs) self.assertIs(job1.callback, scheduler.on_job_executed) self.assertIs(job2.callback, scheduler.on_job_executed) self.assertEquals(data['spawned_jobs'], 4)