def test_cancel_while_running(self): """Cancel batch future while running.""" self.cancelled = 0 fs = {} f1 = ProgressiveFuture() f1.task_canceller = self.cancel_task f2 = ProgressiveFuture() f2.task_canceller = self.cancel_task fs[f1] = 10 # estimated duration in seconds fs[f2] = 15 # estimated duration in seconds batch_future = ProgressiveBatchFuture(fs) # "start" the sub-task; the batch task is already started at creation f1.set_running_or_notify_cancel() self.assertEqual(self.cancelled, 0) # try to cancel while running self.assertTrue(batch_future.cancel()) self.assertTrue( batch_future.cancelled()) # check batch future cancelled for f in fs: # check all sub-futures are cancelled self.assertTrue(f.cancelled()) with self.assertRaises(CancelledError): # check result batch future batch_future.result(timeout=5) for f in fs: # check result for sub-futures with self.assertRaises(CancelledError): f.result(timeout=5) # only one sub-future should trigger the callback (the other future is not running yet or already finished) self.assertEqual(self.cancelled, 1) # one sub-futures should be cancelled
def test_cancel_while_running(self): """Test cancelling of future while running.""" self.cancelled = 0 self.start = None # for the caller self.end = None # for the caller now = time.time() # start is default time now if not specified future = ProgressiveFuture(end=now + 2) future.task_canceller = self.cancel_task # "start" the task (set the future running) future.set_running_or_notify_cancel() time.sleep(0.1) # wait a bit future.cancel() self.assertTrue(future.cancelled()) with self.assertRaises(CancelledError): future.result(timeout=5) self.assertEqual(self.cancelled, 1)
def test_cancel_pre_start(self): """Check that canceller is not called if cancelled before starting.""" self.cancelled = 0 fs = {} f1 = ProgressiveFuture() f1.task_canceller = self.cancel_task f2 = ProgressiveFuture() f2.task_canceller = self.cancel_task fs[f1] = 10 # estimated duration in seconds fs[f2] = 15 # estimated duration in seconds batch_future = ProgressiveBatchFuture(fs) self.assertEqual(self.cancelled, 0) # try to cancel before running self.assertTrue(batch_future.cancel()) self.assertTrue( batch_future.cancelled()) # check batch future cancelled for f in fs: # check all sub-futures are cancelled self.assertTrue(f.cancelled()) with self.assertRaises(CancelledError): # check result batch future batch_future.result(timeout=5) for f in fs: # check result for sub-futures with self.assertRaises(CancelledError): f.result(timeout=5) self.assertTrue(batch_future.cancel()) # it's ok to cancel twice self.assertEqual(self.cancelled, 0)
def testPF_get_progress(self): """ Tests set/get_progress of ProgressiveFuture """ f = ProgressiveFuture() now = time.time() start, end = now + 1, now + 2 # try to update progress f.set_progress(start, end) startf, endf = f.get_progress() self.assertEqual(start, startf) self.assertEqual(end, endf) # "start" the task f.set_running_or_notify_cancel() startf, endf = f.get_progress() self.assertLessEqual(startf, time.time()) self.assertEqual(end, endf) time.sleep(0.1) # "finish" the task f.set_result(None) self.assertTrue(f.done()) startf, endf = f.get_progress() self.assertLessEqual(startf, time.time()) self.assertLessEqual(endf, time.time())
def testProgressiveFuture(self): """ Only tests a simple ProgressiveFuture """ self.cancelled = 0 self.start = None self.end = None future = ProgressiveFuture() future.task_canceller = self.cancel_task now = time.time() # try to update progress future.set_progress(end=now + 1) future.add_update_callback(self.on_progress_update) future.set_progress(end=now + 2) # should say about 2 s left self.assertEqual(self.end, now + 2) # before being started, start should always be (a bit) in the future self.assertGreaterEqual(self.start, now) # "start" the task future.set_running_or_notify_cancel() self.assertTrue(0 <= time.time() - self.start < 0.1) time.sleep(0.1) now = time.time() future.set_progress(end=now + 1) self.assertTrue(0.9 <= self.end - time.time() < 1) # try to cancel while running future.cancel() self.assertTrue(future.cancelled()) self.assertRaises(CancelledError, future.result, 1) self.assertLessEqual(self.end, time.time()) self.assertEqual(self.cancelled, 1)
def testProgressiveFuture(self): """ Only tests a simple ProgressiveFuture """ self.cancelled = 0 self.past = None self.left = None future = ProgressiveFuture() future.task_canceller = self.cancel_task now = time.time() # try to update progress future.set_end_time(now + 1) future.add_update_callback(self.on_progress_update) future.set_end_time(now + 2) # should say about 2 s left self.assertTrue(1.9 <= self.left < 2) self.assertLessEqual(self.past, 0) # "start" the task future.set_running_or_notify_cancel() self.assertTrue(0 <= self.past < 0.1) time.sleep(0.1) now = time.time() future.set_end_time(now + 1) self.assertTrue(0.9 <= self.left < 1) # try to cancel while running future.cancel() self.assertTrue(future.cancelled()) self.assertRaises(CancelledError, future.result, 1) self.assertEqual(self.left, 0) self.assertEqual(self.cancelled, 1)
def test_cancel_post_end(self): """Check that canceller is not called if cancelled after end.""" self.cancelled = 0 fs = {} f1 = ProgressiveFuture() f1.task_canceller = self.cancel_task f2 = ProgressiveFuture() f2.task_canceller = self.cancel_task fs[f1] = 10 # estimated duration in seconds fs[f2] = 15 # estimated duration in seconds batch_future = ProgressiveBatchFuture(fs) # "start" the sub-tasks; the batch task is already started at creation # (Note: typically only one sub-future is run at a time) f1.set_running_or_notify_cancel() f2.set_running_or_notify_cancel() self.assertEqual(self.cancelled, 0) # "end" the sub-futures f1.set_result(1) f2.set_result(2) # check batch future automatically finished when all sub-futures finished self.assertTrue(batch_future.done()) self.assertIsNone( batch_future.result()) # result of successful batch future is None self.assertEqual(f1.result(), 1) self.assertEqual(f2.result(), 2) # try to cancel after end self.assertFalse(batch_future.cancel()) self.assertFalse( batch_future.cancelled()) # check batch future is not cancelled for f in fs: # check all sub-futures are not cancelled self.assertFalse(f.cancelled()) # The result shouldn't change self.assertIsNone(batch_future.result()) self.assertEqual(f1.result(), 1) self.assertEqual(f2.result(), 2) self.assertEqual(self.cancelled, 0)
def test_progress(self): """Test progress update of future.""" self.start = None # for the caller self.end = None # for the caller fs = {} f1 = ProgressiveFuture() f1.task_canceller = self.cancel_task f2 = ProgressiveFuture() f2.task_canceller = self.cancel_task fs[f1] = 10 # estimated duration in seconds fs[f2] = 15 # estimated duration in seconds time_creation_batch_future = time.time() batch_future = ProgressiveBatchFuture(fs) batch_future.add_update_callback(self.on_progress_update) # check estimated time for batch future is sum of estimated time for sub-futures self.assertEqual(self.end - self.start, fs[f1] + fs[f2]) # "start" the sub-tasks; the batch task is already started at creation f1.set_running_or_notify_cancel() now = time.time() f1.set_progress(end=now + 2) # update the progress on one sub-future # check that the estimated end time of the batch futures has been updated expected_end = now + fs[f2] + 2 self.assertTrue(expected_end - 0.1 <= self.end <= expected_end + 0.1) # check that the start of the batch future is after creation of batch future self.assertGreaterEqual(self.start, time_creation_batch_future) now = time.time() f1.set_result(None) # set sub-future done # check estimated time of batch future is equal to f2 expected_end = now + fs[f2] self.assertTrue(expected_end - 0.1 <= self.end <= expected_end + 0.1) f2.set_running_or_notify_cancel() # check time of batch future is still equal to f2 as future just started expected_end = now + fs[f2] self.assertTrue(expected_end - 0.1 <= self.end <= expected_end + 0.1) now = time.time() f2.set_progress(end=now + 10) # update the progress on one sub-future # check that the estimated end time of the batch futures has been updated expected_end = now + 10 self.assertTrue(expected_end - 0.1 <= self.end <= expected_end + 0.1) f2.set_result(None) # set sub-future done # check batch future automatically finished when all sub-futures finished self.assertTrue(batch_future.done()) self.assertIsNone( batch_future.result()) # result of successful batch future is None
def test_get_progress(self): """Tests retrieving the progress from the future.""" f = ProgressiveFuture() now = time.time() start, end = now + 1, now + 2 f.set_progress(start, end) # update progress start_f, end_f = f.get_progress() # retrieve progress # check progress returned is same as progress set beforehand self.assertEqual(start, start_f) self.assertEqual(end, end_f) # "start" the task (set the future running) f.set_running_or_notify_cancel() # updates start and end start_f, end_f = f.get_progress() # retrieve the progress now = time.time() # check that start is a tiny bit before now self.assertLessEqual(start_f, time.time()) # check that expected duration is still 1s as task should take 1s self.assertAlmostEqual(start_f + 1, end_f) # check that the estimated end time of the futures has been updated expected_end = now + 1 self.assertTrue(expected_end - 0.1 <= end_f <= expected_end + 0.1) # end should be 1s in the future time.sleep(0.1) # wait a bit # "finish" the task f.set_result(None) self.assertTrue(f.done()) start_f, end_f = f.get_progress() # check that start is now in the past as future started in the past self.assertLessEqual(start_f, time.time()) # check that end is also now in the past as future already finished self.assertLessEqual(end_f, time.time())
def test_progress(self): """Test progress update for future.""" self.start = None # for the caller self.end = None # for the caller now = time.time() # start is default time now if not specified future = ProgressiveFuture(end=now + 1) future.task_canceller = self.cancel_task # caller request future to indicate change in time estimation future.add_update_callback(self.on_progress_update) # update the progress future.set_progress(end=now + 2) # check end time was updated self.assertEqual(self.end, now + 2) # future not running yet, so start should be after "now" self.assertGreaterEqual(self.start, now) # "start" the task (set the future running) future.set_running_or_notify_cancel() # the progress should be updated and thus .start should be updated now with the current time expected_start = time.time() self.assertTrue(expected_start - 0.1 <= self.start <= expected_start) time.sleep(0.1) # wait a bit now = time.time() # while running, update the estimated ending time future.set_progress(end=now + 1) # the progress should be updated and thus .end should be in 1 sec from now expected_end = now + 1 self.assertTrue(expected_end - 0.1 <= self.end <= expected_end)