def test_submit_after_shutdown(self): executor = FluxExecutor() executor.shutdown(wait=True) with self.assertRaises(RuntimeError): executor.submit(JobspecV1.from_command(["true"])) with self.assertRaises(RuntimeError): executor.submit(None)
def test_broken_executor(self): with FluxExecutor() as executor: executor._broken_event.set() with self.assertRaisesRegex(RuntimeError, "Executor is broken.*"): executor.submit(JobspecV1.from_command(["/not/a/real/app"])) with self.assertRaisesRegex(RuntimeError, "Executor is broken.*"): executor.attach(25979)
def test_bad_arguments(self): with FluxExecutor() as executor: submit_future = executor.submit(None) # not a valid jobspec attach_future = executor.attach(None) # not a valid job ID attach_future2 = executor.attach( -1) # invalid, immediately rejected # invalid job IDs but rejected only in callback zero_jobids = [executor.attach(0) for _ in range(5)] # all futures should be fulfilled after exiting context manager with self.assertRaisesRegex(RuntimeError, r"job could not be submitted.*"): # trying to fetch jobid should raise an error submit_future.jobid() with self.assertRaises(OSError): submit_future.result(timeout=0) self.assertIsInstance(submit_future.exception(), OSError) self.assertEqual(attach_future.jobid(), None) with self.assertRaises(TypeError): attach_future.result(timeout=0) self.assertEqual(attach_future2.jobid(), -1) with self.assertRaises(OverflowError): attach_future2.result(timeout=0) for future in zero_jobids: self.assertEqual(future.jobid(), 0) with self.assertRaisesRegex(ValueError, r".*does not match any job.*"): future.result(timeout=0) self.assertFalse(executor._broken_event.is_set())
def test_bad_jobspec(self): with FluxExecutor() as executor: future = executor.submit(None) # not a valid jobspec with self.assertRaises(OSError): # future should be fulfilled after shutdown future.result(timeout=0) self.assertIsInstance(future.exception(), OSError)
def test_as_completed(self): with FluxExecutor() as executor: jobspec = JobspecV1.from_command(["true"]) futures = [executor.submit(jobspec) for _ in range(3)] for fut in cf.as_completed(futures): self.assertEqual(fut.result(timeout=0), 0) self.assertIsNone(fut.exception())
def test_exception_event(self): with FluxExecutor() as executor: flag = threading.Event() future = executor.submit(JobspecV1.from_command(["/not/a/real/app"])) future.add_event_callback("exception", lambda fut, event: flag.set()) self.assertIsInstance(future.exception(), JobException) self.assertTrue(flag.is_set())
def test_executor_event_callbacks(self): with FluxExecutor() as executor: expected_events = set(["start", "finish", "depend", "priority", "free"]) future = executor.submit(JobspecV1.from_command(["false"])) for event in executor.EVENTS: future.add_event_callback( event, lambda fut, event: expected_events.discard(event.name) ) self.assertFalse(expected_events) # no more expected events
def test_wait(self): with FluxExecutor(threads=3) as executor: jobspec = JobspecV1.from_command(["false"]) futures = [executor.submit(jobspec) for _ in range(3)] done, not_done = cf.wait(futures, return_when=cf.FIRST_COMPLETED) self._check_done(done) done, not_done = cf.wait(futures, return_when=cf.FIRST_EXCEPTION) self._check_done(done) done, not_done = cf.wait(futures) self._check_done(done) self.assertEqual(len(not_done), 0)
def test_failed_submit(self): with FluxExecutor(thread_name_prefix="foobar") as executor: jobspec = JobspecV1.from_command(["false"]) future = executor.submit(jobspec).add_jobid_callback( lambda future: event.set() ) event = threading.Event() jobid = future.jobid() self.assertGreater(jobid, 0) self.assertTrue(event.is_set()) self.assertEqual(future.result(), 1) self.assertIsNone(future.exception())
def test_as_completed(self): with FluxExecutor() as executor: jobspec = JobspecV1.from_command(["true"]) futures = [executor.submit(jobspec) for _ in range(3)] attach_futures = [] for fut in cf.as_completed(futures): self.assertEqual(fut.result(timeout=0), 0) self.assertIsNone(fut.exception()) attach_fut = executor.attach(fut.jobid()) self.assertEqual(fut.jobid(), attach_fut.jobid()) attach_futures.append(attach_fut) for attach_fut in cf.as_completed(attach_futures): self.assertEqual(attach_fut.result(timeout=0), 0) self.assertIsNone(attach_fut.exception()) self.assertFalse(executor._broken_event.is_set())
def test_cancel(self): with FluxExecutor() as executor: jobspec = JobspecV1.from_command(["false"]) for _ in range(3): future = executor.submit(jobspec) if future.cancel(): self.assertFalse(future.running()) self.assertTrue(future.cancelled()) with self.assertRaises(cf.CancelledError): future.jobid() with self.assertRaises(cf.CancelledError): future.exception() else: self.assertEqual(future.result(), 1) self.assertIsNone(future.exception())
def test_cancel_attach(self): with FluxExecutor() as executor: jobspec = JobspecV1.from_command(["true"]) jobid = executor.submit(jobspec).jobid() for _ in range(3): future = executor.attach(jobid) if future.cancel(): self.assertFalse(future.running()) self.assertTrue(future.cancelled()) self.assertEqual(future.jobid(), jobid) with self.assertRaises(cf.CancelledError): future.exception() else: self.assertEqual(future.result(), 0) self.assertIsNone(future.exception()) self.assertFalse(executor._broken_event.is_set())
def test_exception_event(self): with FluxExecutor() as executor: flag = threading.Event() future = executor.submit( JobspecV1.from_command(["/not/a/real/app"])) future.add_event_callback("exception", lambda fut, event: flag.set()) self.assertIsInstance(future.exception(), JobException) self.assertTrue(flag.is_set()) # repeat the test, attaching to the same job jobid = future.jobid() flag = threading.Event() future = executor.attach(jobid) self.assertEqual(jobid, future.jobid()) future.add_event_callback("exception", lambda fut, event: flag.set()) self.assertIsInstance(future.exception(), JobException) self.assertTrue(flag.is_set()) self.assertFalse(executor._broken_event.is_set())
def test_submit_after_shutdown(self): executor = FluxExecutor() executor.shutdown(wait=True) with self.assertRaises(RuntimeError): executor.submit(JobspecV1.from_command(["true"])) with self.assertRaises(RuntimeError): executor.submit(None) with self.assertRaises(RuntimeError): executor.attach(5) with self.assertRaises(RuntimeError): executor.attach(None) self.assertFalse(executor._broken_event.is_set())