def test_sequential_flow_iter_suspend_resume(self): flow = lf.Flow('flow-2').add( utils.ProgressingTask(name='task1'), utils.ProgressingTask(name='task2') ) lb, fd = p_utils.temporary_flow_detail(self.backend) engine = self._make_engine(flow, flow_detail=fd) with utils.CaptureListener(engine, capture_flow=False) as capturer: it = engine.run_iter() gathered_states = [] suspend_it = None while True: try: s = it.send(suspend_it) gathered_states.append(s) if s == states.WAITING: # Stop it before task2 runs/starts. suspend_it = True except StopIteration: break self.assertTrue(len(gathered_states) > 0) expected = ['task1.t RUNNING', 'task1.t SUCCESS(5)'] self.assertEqual(expected, capturer.values) self.assertEqual(states.SUSPENDED, engine.storage.get_flow_state()) # Attempt to resume it and see what runs now... with utils.CaptureListener(engine, capture_flow=False) as capturer: gathered_states = list(engine.run_iter()) self.assertTrue(len(gathered_states) > 0) expected = ['task2.t RUNNING', 'task2.t SUCCESS(5)'] self.assertEqual(expected, capturer.values) self.assertEqual(states.SUCCESS, engine.storage.get_flow_state())
def test_revert_ok_for_unordered_in_linear(self): flow = lf.Flow('p-root').add( utils.ProgressingTask(name='task1'), utils.ProgressingTask(name='task2'), uf.Flow('p-inner').add( utils.ProgressingTask(name='task3'), utils.FailingTask('fail') ) ) engine = self._make_engine(flow) with utils.CaptureListener(engine, capture_flow=False) as capturer: self.assertFailuresRegexp(RuntimeError, '^Woot', engine.run) # NOTE(imelnikov): we don't know if task 3 was run, but if it was, # it should have been reverted in correct order. possible_values_no_task3 = [ 'task1.t RUNNING', 'task2.t RUNNING', 'fail.t FAILURE(Failure: RuntimeError: Woot!)', 'task2.t REVERTED', 'task1.t REVERTED' ] self.assertIsSuperAndSubsequence(capturer.values, possible_values_no_task3) if 'task3' in capturer.values: possible_values_task3 = [ 'task1.t RUNNING', 'task2.t RUNNING', 'task3.t RUNNING', 'task3.t REVERTED', 'task2.t REVERTED', 'task1.t REVERTED' ] self.assertIsSuperAndSubsequence(capturer.values, possible_values_task3)
def test_retry_tasks_that_has_not_been_reverted(self): flow = lf.Flow('flow-1', retry.Times(3, 'r1', provides='x')).add( utils.ConditionalTask('c'), utils.ProgressingTask('t1') ) engine = self._make_engine(flow) engine.storage.inject({'y': 2}) with utils.CaptureListener(engine) as capturer: engine.run() expected = ['flow-1.f RUNNING', 'r1.r RUNNING', 'r1.r SUCCESS(1)', 'c.t RUNNING', 'c.t FAILURE(Failure: RuntimeError: Woot!)', 'c.t REVERTING', 'c.t REVERTED', 'r1.r RETRYING', 'c.t PENDING', 'r1.r RUNNING', 'r1.r SUCCESS(2)', 'c.t RUNNING', 'c.t SUCCESS(None)', 't1.t RUNNING', 't1.t SUCCESS(5)', 'flow-1.f SUCCESS'] self.assertEqual(capturer.values, expected)
def test_resume_flow_that_should_be_retried(self): flow = lf.Flow('flow-1', retry.Times(3, 'r1')).add( utils.ProgressingTask('t1'), utils.ProgressingTask('t2') ) engine = self._make_engine(flow) engine.compile() engine.prepare() with utils.CaptureListener(engine) as capturer: engine.storage.set_atom_intention('r1', st.RETRY) engine.storage.set_atom_state('r1', st.SUCCESS) engine.storage.set_atom_state('t1', st.REVERTED) engine.storage.set_atom_state('t2', st.REVERTED) engine.run() expected = ['flow-1.f RUNNING', 'r1.r RETRYING', 't1.t PENDING', 't2.t PENDING', 'r1.r RUNNING', 'r1.r SUCCESS(1)', 't1.t RUNNING', 't1.t SUCCESS(5)', 't2.t RUNNING', 't2.t SUCCESS(5)', 'flow-1.f SUCCESS'] self.assertEqual(expected, capturer.values)
def test_revert_all_retry(self): flow = lf.Flow('flow-1', retry.Times(3, 'r1', provides='x')).add( utils.ProgressingTask("task1"), lf.Flow('flow-2', retry.AlwaysRevertAll('r2')).add( utils.ConditionalTask("task2")) ) engine = self._make_engine(flow) engine.storage.inject({'y': 2}) with utils.CaptureListener(engine) as capturer: self.assertRaisesRegexp(RuntimeError, '^Woot', engine.run) self.assertEqual(engine.storage.fetch_all(), {'y': 2}) expected = ['flow-1.f RUNNING', 'r1.r RUNNING', 'r1.r SUCCESS(1)', 'task1.t RUNNING', 'task1.t SUCCESS(5)', 'r2.r RUNNING', 'r2.r SUCCESS(None)', 'task2.t RUNNING', 'task2.t FAILURE(Failure: RuntimeError: Woot!)', 'task2.t REVERTING', 'task2.t REVERTED', 'r2.r REVERTING', 'r2.r REVERTED', 'task1.t REVERTING', 'task1.t REVERTED', 'r1.r REVERTING', 'r1.r REVERTED', 'flow-1.f REVERTED'] self.assertEqual(expected, capturer.values)
def test_unordered_flow_task_fails_parallel_tasks_should_be_reverted(self): flow = uf.Flow('flow-1', retry.Times(3, 'r', provides='x')).add( utils.ProgressingTask("task1"), utils.ConditionalTask("task2") ) engine = self._make_engine(flow) engine.storage.inject({'y': 2}) with utils.CaptureListener(engine) as capturer: engine.run() self.assertEqual(engine.storage.fetch_all(), {'y': 2, 'x': 2}) expected = ['flow-1.f RUNNING', 'r.r RUNNING', 'r.r SUCCESS(1)', 'task1.t RUNNING', 'task2.t RUNNING', 'task1.t SUCCESS(5)', 'task2.t FAILURE(Failure: RuntimeError: Woot!)', 'task2.t REVERTING', 'task1.t REVERTING', 'task2.t REVERTED', 'task1.t REVERTED', 'r.r RETRYING', 'task1.t PENDING', 'task2.t PENDING', 'r.r RUNNING', 'r.r SUCCESS(2)', 'task1.t RUNNING', 'task2.t RUNNING', 'task1.t SUCCESS(5)', 'task2.t SUCCESS(None)', 'flow-1.f SUCCESS'] self.assertItemsEqual(capturer.values, expected)
def test_when_subflow_fails_revert_running_tasks(self): waiting_task = utils.WaitForOneFromTask('task1', 'task2', [st.SUCCESS, st.FAILURE]) flow = uf.Flow('flow-1', retry.Times(3, 'r', provides='x')).add( waiting_task, utils.ConditionalTask('task2') ) engine = self._make_engine(flow) engine.task_notifier.register('*', waiting_task.callback) engine.storage.inject({'y': 2}) with utils.CaptureListener(engine, capture_flow=False) as capturer: engine.run() self.assertEqual(engine.storage.fetch_all(), {'y': 2, 'x': 2}) expected = ['r.r RUNNING', 'r.r SUCCESS(1)', 'task1.t RUNNING', 'task2.t RUNNING', 'task2.t FAILURE(Failure: RuntimeError: Woot!)', 'task2.t REVERTING', 'task2.t REVERTED', 'task1.t SUCCESS(5)', 'task1.t REVERTING', 'task1.t REVERTED', 'r.r RETRYING', 'task1.t PENDING', 'task2.t PENDING', 'r.r RUNNING', 'r.r SUCCESS(2)', 'task1.t RUNNING', 'task2.t RUNNING', 'task2.t SUCCESS(None)', 'task1.t SUCCESS(5)'] self.assertItemsEqual(capturer.values, expected)
def test_nested_provides_graph_reverts_correctly(self): flow = gf.Flow("test").add( utils.ProgressingTask('a', requires=['x']), lf.Flow("test2", retry=retry.Times(2)).add( utils.ProgressingTask('b', provides='x'), utils.FailingTask('c'))) engine = self._make_engine(flow) engine.compile() engine.prepare() engine.storage.save('test2_retry', 1) engine.storage.save('b', 11) engine.storage.save('a', 10) with utils.CaptureListener(engine, capture_flow=False) as capturer: self.assertRaisesRegexp(RuntimeError, '^Woot', engine.run) expected = ['c.t RUNNING', 'c.t FAILURE(Failure: RuntimeError: Woot!)', 'a.t REVERTING', 'c.t REVERTING', 'a.t REVERTED', 'c.t REVERTED', 'b.t REVERTING', 'b.t REVERTED'] self.assertItemsEqual(capturer.values[:8], expected) # Task 'a' was or was not executed again, both cases are ok. self.assertIsSuperAndSubsequence(capturer.values[8:], [ 'b.t RUNNING', 'c.t FAILURE(Failure: RuntimeError: Woot!)', 'b.t REVERTED', ]) self.assertEqual(engine.storage.get_flow_state(), st.REVERTED)
def test_run_task_as_flow(self): flow = utils.ProgressingTask(name='task1') engine = self._make_engine(flow) with utils.CaptureListener(engine, capture_flow=False) as capturer: engine.run() expected = ['task1.t RUNNING', 'task1.t SUCCESS(5)'] self.assertEqual(expected, capturer.values)
def test_nested_flow_reverts_parent_retries(self): retry1 = retry.Times(3, 'r1', provides='x') retry2 = retry.Times(0, 'r2', provides='x2') flow = lf.Flow('flow-1', retry1).add( utils.ProgressingTask("task1"), lf.Flow('flow-2', retry2).add(utils.ConditionalTask("task2"))) engine = self._make_engine(flow) engine.storage.inject({'y': 2}) with utils.CaptureListener(engine) as capturer: engine.run() self.assertEqual(engine.storage.fetch_all(), {'y': 2, 'x': 2, 'x2': 1}) expected = [ 'flow-1.f RUNNING', 'r1.r RUNNING', 'r1.r SUCCESS(1)', 'task1.t RUNNING', 'task1.t SUCCESS(5)', 'r2.r RUNNING', 'r2.r SUCCESS(1)', 'task2.t RUNNING', 'task2.t FAILURE(Failure: RuntimeError: Woot!)', 'task2.t REVERTING', 'task2.t REVERTED', 'r2.r REVERTING', 'r2.r REVERTED', 'task1.t REVERTING', 'task1.t REVERTED', 'r1.r RETRYING', 'task1.t PENDING', 'r2.r PENDING', 'task2.t PENDING', 'r1.r RUNNING', 'r1.r SUCCESS(2)', 'task1.t RUNNING', 'task1.t SUCCESS(5)', 'r2.r RUNNING', 'r2.r SUCCESS(1)', 'task2.t RUNNING', 'task2.t SUCCESS(None)', 'flow-1.f SUCCESS' ] self.assertEqual(expected, capturer.values)
def test_states_retry_failure_parent_flow_fails(self): flow = lf.Flow('flow-1', retry.Times(3, 'r1', provides='x1')).add( utils.TaskNoRequiresNoReturns("task1"), lf.Flow('flow-2', retry.Times(3, 'r2', provides='x2')).add( utils.TaskNoRequiresNoReturns("task2"), utils.TaskNoRequiresNoReturns("task3")), utils.ConditionalTask("task4", rebind={'x': 'x1'})) engine = self._make_engine(flow) engine.storage.inject({'y': 2}) with utils.CaptureListener(engine) as capturer: engine.run() self.assertEqual(engine.storage.fetch_all(), { 'y': 2, 'x1': 2, 'x2': 1 }) expected = [ 'flow-1.f RUNNING', 'r1.r RUNNING', 'r1.r SUCCESS(1)', 'task1.t RUNNING', 'task1.t SUCCESS(None)', 'r2.r RUNNING', 'r2.r SUCCESS(1)', 'task2.t RUNNING', 'task2.t SUCCESS(None)', 'task3.t RUNNING', 'task3.t SUCCESS(None)', 'task4.t RUNNING', 'task4.t FAILURE(Failure: RuntimeError: Woot!)', 'task4.t REVERTING', 'task4.t REVERTED', 'task3.t REVERTING', 'task3.t REVERTED', 'task2.t REVERTING', 'task2.t REVERTED', 'r2.r REVERTING', 'r2.r REVERTED', 'task1.t REVERTING', 'task1.t REVERTED', 'r1.r RETRYING', 'task1.t PENDING', 'r2.r PENDING', 'task2.t PENDING', 'task3.t PENDING', 'task4.t PENDING', 'r1.r RUNNING', 'r1.r SUCCESS(2)', 'task1.t RUNNING', 'task1.t SUCCESS(None)', 'r2.r RUNNING', 'r2.r SUCCESS(1)', 'task2.t RUNNING', 'task2.t SUCCESS(None)', 'task3.t RUNNING', 'task3.t SUCCESS(None)', 'task4.t RUNNING', 'task4.t SUCCESS(None)', 'flow-1.f SUCCESS' ] self.assertEqual(expected, capturer.values)
def test_graph_flow_one_task(self): flow = gf.Flow('g-1').add(utils.ProgressingTask(name='task1')) engine = self._make_engine(flow) with utils.CaptureListener(engine, capture_flow=False) as capturer: engine.run() expected = ['task1.t RUNNING', 'task1.t SUCCESS(5)'] self.assertEqual(expected, capturer.values)
def test_revert_raises_for_unordered_in_linear(self): flow = lf.Flow('p-root').add( utils.ProgressingTask(name='task1'), utils.ProgressingTask(name='task2'), uf.Flow('p-inner').add( utils.ProgressingTask(name='task3'), utils.NastyFailingTask(name='nasty') ) ) engine = self._make_engine(flow) with utils.CaptureListener(engine, capture_flow=False, skip_tasks=['nasty']) as capturer: self.assertFailuresRegexp(RuntimeError, '^Gotcha', engine.run) # NOTE(imelnikov): we don't know if task 3 was run, but if it was, # it should have been reverted in correct order. possible_values = ['task1.t RUNNING', 'task1.t SUCCESS(5)', 'task2.t RUNNING', 'task2.t SUCCESS(5)', 'task3.t RUNNING', 'task3.t SUCCESS(5)', 'task3.t REVERTING', 'task3.t REVERTED'] self.assertIsSuperAndSubsequence(possible_values, capturer.values) possible_values_no_task3 = ['task1.t RUNNING', 'task2.t RUNNING'] self.assertIsSuperAndSubsequence(capturer.values, possible_values_no_task3)
def test_graph_flow_four_tasks_revert(self): flow = gf.Flow('g-4-failing').add( utils.ProgressingTask(name='task4', provides='d', requires=['c']), utils.ProgressingTask(name='task2', provides='b', requires=['a']), utils.FailingTask(name='task3', provides='c', requires=['b']), utils.ProgressingTask(name='task1', provides='a')) engine = self._make_engine(flow) with utils.CaptureListener(engine, capture_flow=False) as capturer: self.assertFailuresRegexp(RuntimeError, '^Woot', engine.run) expected = ['task1.t RUNNING', 'task1.t SUCCESS(5)', 'task2.t RUNNING', 'task2.t SUCCESS(5)', 'task3.t RUNNING', 'task3.t FAILURE(Failure: RuntimeError: Woot!)', 'task3.t REVERTING', 'task3.t REVERTED', 'task2.t REVERTING', 'task2.t REVERTED', 'task1.t REVERTING', 'task1.t REVERTED'] self.assertEqual(expected, capturer.values) self.assertEqual(engine.storage.get_flow_state(), states.REVERTED)
def test_suspend_linear_flow_on_revert(self): flow = lf.Flow('linear').add( utils.ProgressingTask('a'), utils.ProgressingTask('b'), utils.FailingTask('c') ) engine = self._make_engine(flow) with SuspendingListener(engine, task_name='b', task_state=states.REVERTED) as capturer: engine.run() self.assertEqual(engine.storage.get_flow_state(), states.SUSPENDED) expected = ['a.t RUNNING', 'a.t SUCCESS(5)', 'b.t RUNNING', 'b.t SUCCESS(5)', 'c.t RUNNING', 'c.t FAILURE(Failure: RuntimeError: Woot!)', 'c.t REVERTING', 'c.t REVERTED', 'b.t REVERTING', 'b.t REVERTED'] self.assertEqual(expected, capturer.values) with utils.CaptureListener(engine, capture_flow=False) as capturer: self.assertRaisesRegexp(RuntimeError, '^Woot', engine.run) self.assertEqual(engine.storage.get_flow_state(), states.REVERTED) expected = ['a.t REVERTING', 'a.t REVERTED'] self.assertEqual(expected, capturer.values)
def test_states_retry_success_linear_flow(self): flow = lf.Flow('flow-1', retry.Times(4, 'r1', provides='x')).add( utils.ProgressingTask("task1"), utils.ConditionalTask("task2") ) engine = self._make_engine(flow) engine.storage.inject({'y': 2}) with utils.CaptureListener(engine) as capturer: engine.run() self.assertEqual(engine.storage.fetch_all(), {'y': 2, 'x': 2}) expected = ['flow-1.f RUNNING', 'r1.r RUNNING', 'r1.r SUCCESS(1)', 'task1.t RUNNING', 'task1.t SUCCESS(5)', 'task2.t RUNNING', 'task2.t FAILURE(Failure: RuntimeError: Woot!)', 'task2.t REVERTING', 'task2.t REVERTED', 'task1.t REVERTING', 'task1.t REVERTED', 'r1.r RETRYING', 'task1.t PENDING', 'task2.t PENDING', 'r1.r RUNNING', 'r1.r SUCCESS(2)', 'task1.t RUNNING', 'task1.t SUCCESS(5)', 'task2.t RUNNING', 'task2.t SUCCESS(None)', 'flow-1.f SUCCESS'] self.assertEqual(expected, capturer.values)
def test_suspend_and_revert_even_if_task_is_gone(self): flow = lf.Flow('linear').add(utils.ProgressingTask('a'), utils.ProgressingTask('b'), utils.FailingTask('c')) engine = self._make_engine(flow) with SuspendingListener(engine, task_name='b', task_state=states.REVERTED) as capturer: engine.run() expected = [ 'a.t RUNNING', 'a.t SUCCESS(5)', 'b.t RUNNING', 'b.t SUCCESS(5)', 'c.t RUNNING', 'c.t FAILURE(Failure: RuntimeError: Woot!)', 'c.t REVERTING', 'c.t REVERTED(None)', 'b.t REVERTING', 'b.t REVERTED(None)' ] self.assertEqual(expected, capturer.values) # pretend we are resuming, but task 'c' gone when flow got updated flow2 = lf.Flow('linear').add( utils.ProgressingTask('a'), utils.ProgressingTask('b'), ) engine2 = self._make_engine(flow2, engine.storage._flowdetail) with utils.CaptureListener(engine2, capture_flow=False) as capturer2: self.assertRaisesRegex(RuntimeError, '^Woot', engine2.run) self.assertEqual(states.REVERTED, engine2.storage.get_flow_state()) expected = ['a.t REVERTING', 'a.t REVERTED(None)'] self.assertEqual(expected, capturer2.values)
def test_nested_provides_graph_retried_correctly(self): flow = gf.Flow("test").add( utils.ProgressingTask('a', requires=['x']), lf.Flow("test2", retry=retry.Times(2)).add( utils.ProgressingTask('b', provides='x'), utils.ProgressingTask('c'))) engine = self._make_engine(flow) engine.compile() engine.prepare() engine.storage.save('test2_retry', 1) engine.storage.save('b', 11) # pretend that 'c' failed fail = failure.Failure.from_exception(RuntimeError('Woot!')) engine.storage.save('c', fail, st.FAILURE) with utils.CaptureListener(engine, capture_flow=False) as capturer: engine.run() expected = ['c.t REVERTING', 'c.t REVERTED', 'b.t REVERTING', 'b.t REVERTED'] self.assertItemsEqual(capturer.values[:4], expected) expected = ['test2_retry.r RETRYING', 'b.t PENDING', 'c.t PENDING', 'test2_retry.r RUNNING', 'test2_retry.r SUCCESS(2)', 'b.t RUNNING', 'b.t SUCCESS(5)', 'a.t RUNNING', 'c.t RUNNING', 'a.t SUCCESS(5)', 'c.t SUCCESS(5)'] self.assertItemsEqual(expected, capturer.values[4:]) self.assertEqual(engine.storage.get_flow_state(), st.SUCCESS)
def test_parameterized_for_each_with_set(self): values = ([3, 2, 5]) retry1 = retry.ParameterizedForEach('r1', provides='x') flow = lf.Flow('flow-1', retry1).add(utils.FailingTaskWithOneArg('t1')) engine = self._make_engine(flow) engine.storage.inject({'values': values, 'y': 1}) with utils.CaptureListener(engine) as capturer: self.assertRaisesRegexp(RuntimeError, '^Woot', engine.run) expected = ['flow-1.f RUNNING', 'r1.r RUNNING', 'r1.r SUCCESS(3)', 't1.t RUNNING', 't1.t FAILURE(Failure: RuntimeError: Woot with 3)', 't1.t REVERTING', 't1.t REVERTED', 'r1.r RETRYING', 't1.t PENDING', 'r1.r RUNNING', 'r1.r SUCCESS(2)', 't1.t RUNNING', 't1.t FAILURE(Failure: RuntimeError: Woot with 2)', 't1.t REVERTING', 't1.t REVERTED', 'r1.r RETRYING', 't1.t PENDING', 'r1.r RUNNING', 'r1.r SUCCESS(5)', 't1.t RUNNING', 't1.t FAILURE(Failure: RuntimeError: Woot with 5)', 't1.t REVERTING', 't1.t REVERTED', 'r1.r REVERTING', 'r1.r REVERTED', 'flow-1.f REVERTED'] self.assertItemsEqual(capturer.values, expected)
def test_basic_do_not_capture(self): flow = lf.Flow("test") flow.add(test_utils.ProgressingTask("task1")) e = self._make_engine(flow) with test_utils.CaptureListener(e, capture_task=False) as capturer: e.run() expected = ['test.f RUNNING', 'test.f SUCCESS'] self.assertEqual(expected, capturer.values)
def test_parallel_flow_one_task(self): flow = uf.Flow('p-1').add( utils.ProgressingTask(name='task1', provides='a')) engine = self._make_engine(flow) with utils.CaptureListener(engine, capture_flow=False) as capturer: engine.run() expected = ['task1.t RUNNING', 'task1.t SUCCESS(5)'] self.assertEqual(expected, capturer.values) self.assertEqual(engine.storage.fetch_all(), {'a': 5})
def test_revert_raises_for_linear_in_unordered(self): flow = uf.Flow('p-root').add( utils.ProgressingTask(name='task1'), lf.Flow('p-inner').add(utils.ProgressingTask(name='task2'), utils.NastyFailingTask())) engine = self._make_engine(flow) with utils.CaptureListener(engine, capture_flow=False) as capturer: self.assertFailuresRegexp(RuntimeError, '^Gotcha', engine.run) self.assertNotIn('task2.t REVERTED', capturer.values)
def test_failing_task_with_notifications(self): values = [] flow = utils.FailingTask('fail') engine = self._make_engine(flow) expected = ['fail.f RUNNING', 'fail.t RUNNING', 'fail.t FAILURE(Failure: RuntimeError: Woot!)', 'fail.t REVERTING', 'fail.t REVERTED', 'fail.f REVERTED'] with utils.CaptureListener(engine, values=values) as capturer: self.assertFailuresRegexp(RuntimeError, '^Woot', engine.run) self.assertEqual(expected, capturer.values) self.assertEqual(engine.storage.get_flow_state(), states.REVERTED) with utils.CaptureListener(engine, values=values) as capturer: self.assertFailuresRegexp(RuntimeError, '^Woot', engine.run) now_expected = list(expected) now_expected.extend(['fail.t PENDING', 'fail.f PENDING']) now_expected.extend(expected) self.assertEqual(now_expected, values) self.assertEqual(engine.storage.get_flow_state(), states.REVERTED)
def test_parallel_revert(self): flow = uf.Flow('p-r-3').add( utils.TaskNoRequiresNoReturns(name='task1'), utils.FailingTask(name='fail'), utils.TaskNoRequiresNoReturns(name='task2')) engine = self._make_engine(flow) with utils.CaptureListener(engine, capture_flow=False) as capturer: self.assertFailuresRegexp(RuntimeError, '^Woot', engine.run) self.assertIn('fail.t FAILURE(Failure: RuntimeError: Woot!)', capturer.values)
def test_resumption_on_crash_after_revert_scheduled(self): engine = self._pretend_to_run_a_flow_and_crash('revert scheduled') with utils.CaptureListener(engine) as capturer: engine.run() expected = [ 'task1.t REVERTED', 'flow-1_retry.r RETRYING', 'task1.t PENDING', 'flow-1_retry.r RUNNING', 'flow-1_retry.r SUCCESS(2)', 'task1.t RUNNING', 'task1.t SUCCESS(5)', 'flow-1.f SUCCESS' ] self.assertEqual(capturer.values, expected)
def test_parallel_flow_two_tasks(self): flow = uf.Flow('p-2').add( utils.ProgressingTask(name='task1'), utils.ProgressingTask(name='task2') ) engine = self._make_engine(flow) with utils.CaptureListener(engine, capture_flow=False) as capturer: engine.run() expected = set(['task2.t SUCCESS(5)', 'task2.t RUNNING', 'task1.t RUNNING', 'task1.t SUCCESS(5)']) self.assertEqual(expected, set(capturer.values))
def test_sequential_flow_nested_blocks(self): flow = lf.Flow('nested-1').add( utils.ProgressingTask('task1'), lf.Flow('inner-1').add(utils.ProgressingTask('task2'))) engine = self._make_engine(flow) with utils.CaptureListener(engine, capture_flow=False) as capturer: engine.run() expected = [ 'task1.t RUNNING', 'task1.t SUCCESS(5)', 'task2.t RUNNING', 'task2.t SUCCESS(5)' ] self.assertEqual(expected, capturer.values)
def test_revert_not_run_task_is_not_reverted(self): flow = lf.Flow('revert-not-run').add( utils.FailingTask('fail'), utils.NeverRunningTask(), ) engine = self._make_engine(flow) with utils.CaptureListener(engine, capture_flow=False) as capturer: self.assertFailuresRegexp(RuntimeError, '^Woot', engine.run) expected = ['fail.t RUNNING', 'fail.t FAILURE(Failure: RuntimeError: Woot!)', 'fail.t REVERTING', 'fail.t REVERTED'] self.assertEqual(expected, capturer.values)
def test_sequential_flow_two_tasks(self): flow = lf.Flow('flow-2').add( utils.ProgressingTask(name='task1'), utils.ProgressingTask(name='task2') ) engine = self._make_engine(flow) with utils.CaptureListener(engine, capture_flow=False) as capturer: engine.run() expected = ['task1.t RUNNING', 'task1.t SUCCESS(5)', 'task2.t RUNNING', 'task2.t SUCCESS(5)'] self.assertEqual(expected, capturer.values) self.assertEqual(len(flow), 2)
def test_default_times_retry(self): flow = lf.Flow('flow-1', retry.Times(3, 'r1')).add( utils.ProgressingTask('t1'), utils.FailingTask('t2')) engine = self._make_engine(flow) with utils.CaptureListener(engine) as capturer: self.assertRaisesRegexp(RuntimeError, '^Woot', engine.run) expected = ['flow-1.f RUNNING', 'r1.r RUNNING', 'r1.r SUCCESS(1)', 't1.t RUNNING', 't1.t SUCCESS(5)', 't2.t RUNNING', 't2.t FAILURE(Failure: RuntimeError: Woot!)', 't2.t REVERTING', 't2.t REVERTED', 't1.t REVERTING', 't1.t REVERTED', 'r1.r RETRYING', 't1.t PENDING', 't2.t PENDING', 'r1.r RUNNING', 'r1.r SUCCESS(2)', 't1.t RUNNING', 't1.t SUCCESS(5)', 't2.t RUNNING', 't2.t FAILURE(Failure: RuntimeError: Woot!)', 't2.t REVERTING', 't2.t REVERTED', 't1.t REVERTING', 't1.t REVERTED', 'r1.r RETRYING', 't1.t PENDING', 't2.t PENDING', 'r1.r RUNNING', 'r1.r SUCCESS(3)', 't1.t RUNNING', 't1.t SUCCESS(5)', 't2.t RUNNING', 't2.t FAILURE(Failure: RuntimeError: Woot!)', 't2.t REVERTING', 't2.t REVERTED', 't1.t REVERTING', 't1.t REVERTED', 'r1.r REVERTING', 'r1.r REVERTED', 'flow-1.f REVERTED'] self.assertEqual(expected, capturer.values)