def _test_window(self, total, window): atom = .1 tolerance = 8 # more or less % in terms of overall time s = PureScheduler(jobs_window=window) for i in range(1, total + 1): s.add(PrintJob("{}-th {}s job".format(i, atom), sleep=atom)) beg = time.time() ok = s.run() ok or s.debrief(details=True) end = time.time() duration = end - beg # estimate global time # unwindowed: overall duration is atom # otherwise a multiple of it (assuming total = k*window) expected = atom if not window else (total / window) * atom print('overall expected {} - measured {}'.format(expected, duration)) distortion = duration / expected time_ok = 1 - tolerance / 100 <= distortion <= 1 + tolerance / 100 if not time_ok: print("_test_window - window = {} :" "wrong execution time {} - not within {}% of {}".format( window, end - beg, tolerance, expected)) self.assertTrue(time_ok) self.assertTrue(ok)
def test_sequence6(self): "adding a sequence" sched = PureScheduler() a1 = J(sl(0.1), label=1) a2 = J(sl(0.1), label=2) a3 = J(sl(0.1), label=3) sched.add(Seq(a1, a2, a3)) self.assertTrue(sched.run())
def test_nesting3(self): """ same as test_nesting2 but using a Scheduler instance 2 sub schedulers run in parallel while the third main one controls them both """ # main scheduler - total approx # 0.5 + max(0.5, 1) + 0.5 = 2 s expected_duration = 2 watch = Watch('test_nesting3') main_sched = PureScheduler(verbose=True, watch=watch) main_sched.label = "main3" mainj1 = Job(co_print_sleep(watch, 0.5, "mainj1"), label="mainj1", scheduler=main_sched) # sub-scheduler 2 - total approx 0.5 s sub_sched2 = diamond_scheduler(watch, 0.5, "SUB2") main_sched.add(sub_sched2) sub_sched2.requires(mainj1) sub_sched2.label = "sub_sched2" sub_sched2.verbose = True # sub-scheduler 3 - total approx 1 s sub_sched3 = diamond_scheduler(watch, 1, "SUB3") main_sched.add(sub_sched3) sub_sched3.requires(mainj1) sub_sched3.label = "sub_sched3" sub_sched3.verbose = True # last job in main scheduler Job(co_print_sleep(watch, 0.5, "mainj4"), label="mainj4", required=(sub_sched2, sub_sched3), scheduler=main_sched) for s in main_sched, sub_sched2, sub_sched3: if not s.sanitize(): print(f"OOPS, had to sanitize sched {s.label}") print("===== test_nesting3", "LIST without details") main_sched.list(details=False) produce_png(main_sched, "test_nesting3") watch.reset() print("---run") ok = main_sched.run() if not ok: main_sched.debrief() self.assertTrue(ok) # allow for a small variation around 2s of course duration = watch.seconds() self.assertAlmostEqual(duration, expected_duration, delta=0.05)
def test_display(self): class FakeTask: def __init__(self): self._result = 0 self._exception = None def annotate_job_with_fake_task(job, state, boom): task = FakeTask() if state == "done": task._state = asyncio.futures._FINISHED job._task = task job._running = True elif state == "running": task._state = "NONE" job._task = task job._running = True elif state == "scheduled": task._state = "NONE" job._task = task job._running = False else: pass # here we assume that a job that has raised an exception is # necessarily done if boom: if state in ("idle", "scheduled", "running"): print("incompatible combination boom x idle - ignored") return else: job._task._exception = True return job class AJ(AbstractJob): pass sched = PureScheduler() previous = None for state in "idle", "scheduled", "running", "done": for boom in True, False: for critical in True, False: for forever in True, False: j = AJ(critical=critical, forever=forever, label="forever={} crit.={} status={} boom={}". format(forever, critical, state, boom), required=previous) if annotate_job_with_fake_task(j, state, boom): sched.add(j) previous = j sched.list()
def test_graph2(self): class TextJob(Job): def __init__(self, text, *args, **kwds): self.text = text super().__init__(*args, **kwds) def text_label(self): return "[[TextJob {}]]".format(self.text[::-1]) def details(self): return f"TextJob details say\n" \ f"that initial text was {self.text}" class GraphJob(Job): def __init__(self, graph, *args, **kwds): self.graph = graph super().__init__(*args, **kwds) def graph_label(self): return "[[GraphJob\n{}]]".format(self.graph[::-1]) def details(self): return f"GraphJob details\nare even more verbose and say\n" \ f"that initial graph message\nwas {self.graph}" watch = Watch() s = PureScheduler() s.add( Sequence( TextJob('textjob-with', co_print_sleep(watch, 0.1, 'textjob, no label ')), TextJob('textjob-without', co_print_sleep(watch, 0.1, 'textjob, with label '), label='TextLabel'), GraphJob('graphjob-with', co_print_sleep(watch, 0.1, 'graphjob, no label ')), GraphJob('graphjob-without', co_print_sleep(watch, 0.1, 'graphjob, with label '), label='GraphLabel'), )) print("test_graph2 NO DETAILS") s.list() print("test_graph2 WITH DETAILS") s.list(details=True) print("GRAPH") self.assertEqual(len(s), 4) produce_png(s, "test_graph2")
def test_graph1(self): watch = Watch() s = PureScheduler() s.add( Sequence( Job(co_print_sleep(watch, .25, 'begin')), Job(co_print_sleep(watch, 1., 'middle'), label='middle'), Job(co_print_sleep(watch, .25, 'end')), )) print("test_graph1 NO DETAILS") s.list() print("test_graph1 WITH DETAILS") s.list(details=True) print("GRAPH") self.assertEqual(len(s), 3) s.run() self.assertAlmostEqual(watch.seconds(), 1.5, delta=0.05) produce_png(s, "test_graph1")