def run_workflow_2(): # Create the engine as in the previous example my_engine_2 = GenericWorkflowEngine() my_engine_2.setWorkflow(my_workflow_2) try: # Note how we don't need to keep a reference to our tokens - the engine # allows us to access them via `my_engine.objects` later. my_engine_2.process([[], [0,1], [0,1,0,1]]) except HaltProcessing: # Our engine was built to throw this exception every time an object is # completed. At this point we can inspect the object to decide what to # do next. In any case, we will ask it to move to the next object, # until it stops throwing the exception (which, in our case, means it # has finished with all objects). while True: try: # Restart the engine with the next object, starting from the # first task. my_engine_2.restart('next', 'first') except HaltProcessing: continue else: print "Done!", my_engine_2.objects break
class TestWorkflowEngine(object): """Tests using FakeTokens in place of strings""" def setup_method(self, method): self.key = '*' self.wfe = GenericWorkflowEngine() self.data = ['one', 'two', 'three', 'four', 'five'] self.tokens = [FakeToken(x, type='*') for x in self.data] def teardown_method(self, method): pass @pytest.mark.parametrize("_,tokens,exception,exception_msg", ( ("int", 49, WorkflowError, "not an iterable"), ("str", "hello", WorkflowError, "not an iterable"), ("object", object, WorkflowError, "not an iterable"), )) def test_objects_are_of_bad_type(self, _, tokens, exception, exception_msg): with pytest.raises(exception) as exc_info: self.wfe.process(tokens) assert exception_msg in exc_info.value.args[0] def test_empty_object_list_logs_warning(self): assert hasattr(self.wfe, 'log') self.wfe.log = mock.Mock() self.wfe.callbacks.replace([lambda o, e: None]) self.wfe.process([]) self.wfe.log.warning.assert_called_once_with( 'List of objects is empty. Running workflow ' 'on empty set has no effect.') def test_current_taskname_resolution(self): workflow = [m('test')] self.wfe.callbacks.replace(workflow, self.key) self.wfe.process(self.tokens) assert self.wfe.current_taskname == 'string appender' workflow = [lambda obj, eng: 1] self.wfe.callbacks.replace(workflow, self.key) self.wfe.process(self.tokens) assert self.wfe.current_taskname == '<lambda>' workflow = [ IF_ELSE( lambda obj, eng: True, [lambda obj, eng: 1], [lambda obj, eng: 2], ) ] self.wfe.callbacks.replace(workflow, self.key) # This test will break if someone changes IF_ELSE. TODO: Mock # Note: Python3 has much stronger introspection, thus the `.*`. assert re.match( r'\[<function IF_ELSE.* at 0x[0-f]+>, ' r'\[<function .*<lambda> at 0x[0-f]+>\], ' r'<function BREAK.* at 0x[0-f]+>, ' r'\[<function .*<lambda> at 0x[0-f]+>\]\]', self.wfe.current_taskname) def test_current_object_returns_correct_object(self): self.wfe.callbacks.replace([halt_processing()]) assert self.wfe.current_object is None with pytest.raises(HaltProcessing): self.wfe.process(self.tokens) assert self.wfe.current_object is self.tokens[0] with pytest.raises(HaltProcessing): self.wfe.restart('current', 'next') assert self.wfe.current_object is self.tokens[1] @pytest.mark.parametrize( "_,callbacks,expected_result", (('skips_forward_with_acceptable_increment', [ m('mouse'), [m('dog'), jump_call(2), m('cat'), m('puppy'), m('python')], m('horse'), ], 'mouse dog puppy python horse'), ('skips_forward_with_increment_that_is_too_large', [ m('mouse'), [m('dog'), jump_call(50), m('cat'), m('puppy'), m('python')], m('horse'), ], 'mouse dog horse'), ('jumps_forward_outside_of_nest', [ jump_call(3), m('mouse'), [m('dog'), m('cat'), m('puppy'), m('python')], m('horse'), ], 'horse'), ('skips_backwards_with_acceptable_decrement', [ m('mouse'), [m('dog'), jump_call(-1), m('cat'), m('puppy')], m('horse'), ], 'mouse dog dog cat puppy horse'), ('skips_backwards_with_decrement_that_is_too_large', [ m('mouse'), [m('dog'), m('cat'), jump_call(-50), m('puppy'), m('python')], m('horse'), ], 'mouse dog cat dog cat puppy python horse'), ('skips_backwards_outside_of_nest', [ m('mouse'), [m('dog'), m('cat'), m('puppy'), m('python')], m('horse'), jump_call(-2) ], 'mouse dog cat puppy python horse dog cat puppy python horse'))) def test_jump_call(self, _, callbacks, expected_result): self.wfe.callbacks.add_many(callbacks, self.key) self.wfe.process(self.tokens) t = get_first(self.tokens) assert t == expected_result # --------- complicated loop ----------- @pytest.mark.parametrize("_,workflow,expected_result", (('simple', [ m('mouse'), [ m('dog'), [m('cat'), m('puppy')], [m('python'), [m('wasp'), m('leon')]], m('horse'), ] ], 'mouse dog cat puppy python wasp leon horse'), ('with_nested_jumps', [ jump_call(2), m('mouse'), [ m('dog'), [m('cat'), m('puppy')], [m('python'), jump_call(-2), [m('wasp'), m('leon')]], m('horse'), ] ], 'dog cat puppy python python wasp leon horse'))) def test_multi_nested_workflows(self, _, workflow, expected_result): self.wfe.callbacks.add_many(workflow, self.key) self.wfe.process(self.tokens) t = get_first(self.tokens) assert t == expected_result @pytest.mark.parametrize("_,workflow,expected_result", (('simple', [ m('mouse'), [ m('dog'), [m('cat'), m('puppy')], [m('python'), break_loop(), [m('wasp'), m('leon')]], m('horse'), ] ], 'mouse dog cat puppy python horse'), ('break_loop_outside_of_nest', [ break_loop(), m('mouse'), [ m('dog'), [m('cat'), m('puppy')], [m('python'), [m('wasp'), m('leon')]], m('horse'), ] ], None))) def test_break_from_this_loop(self, _, workflow, expected_result): self.wfe.callbacks.add_many(workflow, self.key) self.wfe.process(self.tokens) t = get_first(self.tokens) assert t == expected_result # ----------- StopProcessing -------------------------- def test_engine_immediatelly_stops(self): self.wfe.callbacks.add_many([ stop_processing(), m('mouse'), [ m('dog'), [m('cat'), m('puppy')], [m('python'), [m('wasp'), m('leon')]], m('horse'), ] ], self.key) self.wfe.process(self.tokens) t = get_first(self.tokens) assert get_xth(self.tokens, 0) is None assert get_xth(self.tokens, 1) is None assert get_xth(self.tokens, 2) is None def test_engine_stops_half_way_through(self): self.wfe.callbacks.add_many([ m('mouse'), [ m('dog'), [m('cat'), m('puppy')], [ m('python'), stop_if_token_equals('four'), [m('wasp'), m('leon')] ], m('horse'), ] ], self.key) self.wfe.process(self.tokens) full_result = 'mouse dog cat puppy python wasp leon horse' result_until_stop = 'mouse dog cat puppy python' assert get_xth(self.tokens, 0) == full_result # 'one' assert get_xth(self.tokens, 1) == full_result # 'two' assert get_xth(self.tokens, 2) == full_result # 'three' assert get_xth(self.tokens, 3) == result_until_stop # 'four' assert get_xth(self.tokens, 4) is None # 'five', engine stopped # ---------- jump_token ------------- def test_engine_moves_to_next_token(self): self.wfe.callbacks.add_many([ m('mouse'), [ m('dog'), [m('cat'), m('puppy')], [m('python'), next_token(), [m('wasp'), m('leon')]], m('horse'), ] ], self.key) self.wfe.process(self.tokens) result_until_next_token = 'mouse dog cat puppy python' for i in range(5): assert get_xth(self.tokens, i) == result_until_next_token def test_workflow_09a(self): self.wfe.callbacks.add_many([ m('mouse'), [ m('dog'), if_str_token_jump('four', -2), [m('cat'), m('puppy')], m('horse'), ] ], self.key) self.wfe.process(self.tokens) t = get_first(self.tokens) r1 = 'mouse dog cat puppy horse' # one, five r2 = 'mouse dog cat puppy horse mouse dog cat puppy horse' # two, three r3 = 'mouse dog mouse dog cat puppy horse' # four assert get_xth(self.tokens, 0) == r1 assert get_xth(self.tokens, 1) == r2 assert get_xth(self.tokens, 2) == r2 assert get_xth(self.tokens, 3) == r3 assert get_xth(self.tokens, 4) == r1 def test_workflow_09b(self): self.wfe.callbacks.add_many([ m('mouse'), [ m('dog'), if_str_token_jump('two', 2), [m('cat'), m('puppy')], m('horse'), ] ], self.key) self.wfe.process(self.tokens) t = get_first(self.tokens) r1 = 'mouse dog cat puppy horse' # one, four, five r2 = 'mouse dog' # two r3 = None # three assert get_xth(self.tokens, 0) == r1 assert get_xth(self.tokens, 1) == r2 assert get_xth(self.tokens, 2) == r3 assert get_xth(self.tokens, 3) == r1 assert get_xth(self.tokens, 4) == r1 # ----------------- HaltProcessing -------------------- def test_50_halt_processing_mid_workflow(self): other_wfe = GenericWorkflowEngine() other_wfe.callbacks.add_many([ m('mouse'), [ m('dog'), [m('cat'), m('puppy')], [m('python'), halt_processing()], m('horse'), ] ], self.key) with pytest.raises(HaltProcessing): other_wfe.process(self.tokens) t = get_first(self.tokens) assert get_xth(self.tokens, 0) == 'mouse dog cat puppy python' assert get_xth(self.tokens, 1) is None assert get_xth(self.tokens, 2) is None compl = 'mouse dog cat puppy python horse' compl1 = 'mouse dog cat puppy python' @pytest.mark.parametrize( "obj,task,results", ( ('prev', 'prev', (compl + " python", compl1, None)), ('prev', 'current', (compl, compl1, None)), # current task is to halt ('prev', 'next', (compl + " horse", compl1 + " " + compl1, None)), ('prev', 'first', (compl + " " + compl1, compl1, None)), ('current', 'prev', (compl, compl1 + " python", None)), ('current', 'current', (compl, compl1, None)), ('current', 'next', (compl, compl1 + " horse", compl1)), ('current', 'first', (compl, compl1 + " " + compl1, None)), ('next', 'prev', (compl, compl1, "python")), ('next', 'current', (compl, compl1, None)), ('next', 'next', (compl, compl1, "horse")), ('next', 'first', (compl, compl1, compl1)), ('first', 'prev', (compl + " python", compl1, None)), ('first', 'current', (compl, compl1, None)), # current task is to halt ('first', 'next', (compl + " horse", compl1 + " " + compl1, None)), ('first', 'first', (compl + " " + compl1, compl1, None)), )) def test_51_workflow_restart_after_halt(self, obj, task, results): self.wfe.callbacks.add_many([ m('mouse'), [ m('dog'), [m('cat'), m('puppy')], [m('python'), halt_processing()], m('horse'), ] ], self.key) with pytest.raises(HaltProcessing): self.wfe.process(self.tokens) assert get_xth(self.tokens, 0) == 'mouse dog cat puppy python' assert get_xth(self.tokens, 1) is None assert get_xth(self.tokens, 2) is None # this should pick up from the point where we stopped with pytest.raises(HaltProcessing): self.wfe.restart('current', 'next') assert get_xth(self.tokens, 0) == 'mouse dog cat puppy python horse' assert get_xth(self.tokens, 1) == 'mouse dog cat puppy python' assert get_xth(self.tokens, 2) is None with pytest.raises(HaltProcessing): self.wfe.restart(obj, task) assert (get_xth(self.tokens, 0), get_xth(self.tokens, 1), get_xth(self.tokens, 2)) == results def test_restart_accepts_new_objects(self): workflow = [m('test')] self.wfe.callbacks.replace(workflow, self.key) self.wfe.process(self.tokens) new_data = ['a', 'b', 'c', 'd', 'e'] new_tokens = [FakeToken(x, type='*') for x in new_data] self.wfe.restart('first', 'first', objects=new_tokens) assert self.wfe.objects == new_tokens def test_has_completed(self): self.wfe.callbacks.replace([ m('mouse'), halt_processing(), m('horse'), ]) assert self.wfe.has_completed is False with pytest.raises(HaltProcessing): self.wfe.process([self.tokens[0]]) assert self.wfe.has_completed is False self.wfe.restart('current', 'next') assert self.wfe.has_completed is True def test_nested_workflow_halt(self): other_wfe = GenericWorkflowEngine() wfe = self.wfe other_wfe.callbacks.add_many([ m('mouse'), [ m('dog'), [m('cat'), m('puppy')], [m('python'), halt_processing()], m('horse'), ] ], self.key) wfe.callbacks.add_many([ m('mouse'), [ m('dog'), [m('cat'), m('puppy')], [m('python'), lambda o, e: other_wfe.process(self.tokens)], m('horse'), ] ], self.key) with pytest.raises(HaltProcessing): wfe.process(self.tokens) t = get_first(self.tokens) assert get_xth( self.tokens, 0) == 'mouse dog cat puppy python mouse dog cat puppy python' assert get_xth(self.tokens, 1) is None assert get_xth(self.tokens, 2) is None @pytest.mark.parametrize("callbacks,kwargs,result,exception", ( ( [ m('mouse'), [ m('dog'), [m('cat'), m('puppy')], [m('python'), workflow_error()], m('horse'), ] ], {}, 'mouse dog cat puppy python', WorkflowError, ), ( [ m('mouse'), [ m('dog'), [m('cat'), m('puppy')], [m('python'), workflow_error()], m('horse'), ] ], { 'stop_on_error': False, }, 'mouse dog cat puppy python', None, ), ( [ m('mouse'), [ m('dog'), [m('cat'), m('puppy')], [m('python'), halt_processing()], m('horse'), ] ], { 'stop_on_halt': False, }, 'mouse dog cat puppy python', None, ), )) def test_process_smash_through(self, callbacks, kwargs, result, exception): self.wfe.callbacks.add_many(callbacks, self.key) if exception: with pytest.raises(exception): self.wfe.process(self.tokens, **kwargs) else: self.wfe.process(self.tokens, **kwargs) for idx, dummy in enumerate(self.tokens): assert get_xth(self.tokens, idx) == result
class TestWorkflowEngine(object): """Tests using FakeTokens in place of strings""" def setup_method(self, method): self.key = '*' self.wfe = GenericWorkflowEngine() self.data = ['one', 'two', 'three', 'four', 'five'] self.tokens = [FakeToken(x, type='*') for x in self.data] def teardown_method(self, method): pass @pytest.mark.parametrize("_,tokens,exception,exception_msg", ( ("int", 49, WorkflowError, "not an iterable"), ("str", "hello", WorkflowError, "not an iterable"), ("object", object, WorkflowError, "not an iterable"), )) def test_objects_are_of_bad_type(self, _, tokens, exception, exception_msg): with pytest.raises(exception) as exc_info: self.wfe.process(tokens) assert exception_msg in exc_info.value.args[0] def test_empty_object_list_logs_warning(self): assert hasattr(self.wfe, 'log') self.wfe.log = mock.Mock() self.wfe.callbacks.replace([lambda o, e: None]) self.wfe.process([]) self.wfe.log.warning.assert_called_once_with('List of objects is empty. Running workflow ' 'on empty set has no effect.') def test_current_taskname_resolution(self): workflow = [m('test')] self.wfe.callbacks.replace(workflow, self.key) self.wfe.process(self.tokens) assert self.wfe.current_taskname == 'string appender' workflow = [lambda obj, eng: 1] self.wfe.callbacks.replace(workflow, self.key) self.wfe.process(self.tokens) assert self.wfe.current_taskname == '<lambda>' workflow = [ IF_ELSE( lambda obj, eng: True, [lambda obj, eng: 1], [lambda obj, eng: 2], ) ] self.wfe.callbacks.replace(workflow, self.key) # This test will break if someone changes IF_ELSE. TODO: Mock # Note: Python3 has much stronger introspection, thus the `.*`. assert re.match(r'\[<function IF_ELSE.* at 0x[0-f]+>, ' r'\[<function .*<lambda> at 0x[0-f]+>\], ' r'<function BREAK.* at 0x[0-f]+>, ' r'\[<function .*<lambda> at 0x[0-f]+>\]\]', self.wfe.current_taskname) def test_current_object_returns_correct_object(self): self.wfe.callbacks.replace([halt_processing()]) assert self.wfe.current_object is None with pytest.raises(HaltProcessing): self.wfe.process(self.tokens) assert self.wfe.current_object is self.tokens[0] with pytest.raises(HaltProcessing): self.wfe.restart('current', 'next') assert self.wfe.current_object is self.tokens[1] @pytest.mark.parametrize("_,callbacks,expected_result", ( ( 'skips_forward_with_acceptable_increment', [ m('mouse'), [m('dog'), jump_call(2), m('cat'), m('puppy'), m('python')], m('horse'), ], 'mouse dog puppy python horse' ), ( 'skips_forward_with_increment_that_is_too_large', [ m('mouse'), [m('dog'), jump_call(50), m('cat'), m('puppy'), m('python')], m('horse'), ], 'mouse dog horse' ), ( 'jumps_forward_outside_of_nest', [ jump_call(3), m('mouse'), [m('dog'), m('cat'), m('puppy'), m('python')], m('horse'), ], 'horse' ), ( 'skips_backwards_with_acceptable_decrement', [ m('mouse'), [m('dog'), jump_call(-1), m('cat'), m('puppy')], m('horse'), ], 'mouse dog dog cat puppy horse' ), ( 'skips_backwards_with_decrement_that_is_too_large', [ m('mouse'), [m('dog'), m('cat'), jump_call(-50), m('puppy'), m('python')], m('horse'), ], 'mouse dog cat dog cat puppy python horse' ), ( 'skips_backwards_outside_of_nest', [ m('mouse'), [m('dog'), m('cat'), m('puppy'), m('python')], m('horse'), jump_call(-2) ], 'mouse dog cat puppy python horse dog cat puppy python horse' ) )) def test_jump_call(self, _, callbacks, expected_result): self.wfe.callbacks.add_many(callbacks, self.key) self.wfe.process(self.tokens) t = get_first(self.tokens) assert t == expected_result # --------- complicated loop ----------- @pytest.mark.parametrize("_,workflow,expected_result", ( ( 'simple', [ m('mouse'), [ m('dog'), [m('cat'), m('puppy')], [m('python'), [m('wasp'), m('leon')]], m('horse'), ] ], 'mouse dog cat puppy python wasp leon horse' ), ( 'with_nested_jumps', [ jump_call(2), m('mouse'), [ m('dog'), [m('cat'), m('puppy')], [m('python'), jump_call(-2), [m('wasp'), m('leon')]], m('horse'), ] ], 'dog cat puppy python python wasp leon horse' ) )) def test_multi_nested_workflows(self, _, workflow, expected_result): self.wfe.callbacks.add_many(workflow, self.key) self.wfe.process(self.tokens) t = get_first(self.tokens) assert t == expected_result @pytest.mark.parametrize("_,workflow,expected_result", ( ( 'simple', [ m('mouse'), [ m('dog'), [m('cat'), m('puppy')], [m('python'), break_loop(), [m('wasp'), m('leon')]], m('horse'), ] ], 'mouse dog cat puppy python horse' ), ( 'break_loop_outside_of_nest', [ break_loop(), m('mouse'), [ m('dog'), [m('cat'), m('puppy')], [m('python'), [m('wasp'), m('leon')]], m('horse'), ] ], None ) )) def test_break_from_this_loop(self, _, workflow, expected_result): self.wfe.callbacks.add_many(workflow, self.key) self.wfe.process(self.tokens) t = get_first(self.tokens) assert t == expected_result # ----------- StopProcessing -------------------------- def test_engine_immediatelly_stops(self): self.wfe.callbacks.add_many([ stop_processing(), m('mouse'), [ m('dog'), [m('cat'), m('puppy')], [ m('python'), [m('wasp'), m('leon')] ], m('horse'), ] ], self.key) self.wfe.process(self.tokens) t = get_first(self.tokens) assert get_xth(self.tokens, 0) is None assert get_xth(self.tokens, 1) is None assert get_xth(self.tokens, 2) is None def test_engine_stops_half_way_through(self): self.wfe.callbacks.add_many([ m('mouse'), [ m('dog'), [m('cat'), m('puppy')], [m('python'), stop_if_token_equals('four'), [m('wasp'), m('leon')]], m('horse'), ] ], self.key) self.wfe.process(self.tokens) full_result = 'mouse dog cat puppy python wasp leon horse' result_until_stop = 'mouse dog cat puppy python' assert get_xth(self.tokens, 0) == full_result # 'one' assert get_xth(self.tokens, 1) == full_result # 'two' assert get_xth(self.tokens, 2) == full_result # 'three' assert get_xth(self.tokens, 3) == result_until_stop # 'four' assert get_xth(self.tokens, 4) is None # 'five', engine stopped # ---------- jump_token ------------- def test_engine_moves_to_next_token(self): self.wfe.callbacks.add_many( [ m('mouse'), [ m('dog'), [m('cat'), m('puppy')], [m('python'), next_token(), [m('wasp'), m('leon')]], m('horse'), ] ], self.key) self.wfe.process(self.tokens) result_until_next_token = 'mouse dog cat puppy python' for i in range(5): assert get_xth(self.tokens, i) == result_until_next_token def test_workflow_09a(self): self.wfe.callbacks.add_many([ m('mouse'), [ m('dog'), if_str_token_jump('four', -2), [m('cat'), m('puppy')], m('horse'), ] ], self.key) self.wfe.process(self.tokens) t = get_first(self.tokens) r1 = 'mouse dog cat puppy horse' # one, five r2 = 'mouse dog cat puppy horse mouse dog cat puppy horse' # two, three r3 = 'mouse dog mouse dog cat puppy horse' # four assert get_xth(self.tokens, 0) == r1 assert get_xth(self.tokens, 1) == r2 assert get_xth(self.tokens, 2) == r2 assert get_xth(self.tokens, 3) == r3 assert get_xth(self.tokens, 4) == r1 def test_workflow_09b(self): self.wfe.callbacks.add_many([ m('mouse'), [ m('dog'), if_str_token_jump('two', 2), [m('cat'), m('puppy')], m('horse'), ] ], self.key) self.wfe.process(self.tokens) t = get_first(self.tokens) r1 = 'mouse dog cat puppy horse' # one, four, five r2 = 'mouse dog' # two r3 = None # three assert get_xth(self.tokens, 0) == r1 assert get_xth(self.tokens, 1) == r2 assert get_xth(self.tokens, 2) == r3 assert get_xth(self.tokens, 3) == r1 assert get_xth(self.tokens, 4) == r1 # ----------------- HaltProcessing -------------------- def test_50_halt_processing_mid_workflow(self): other_wfe = GenericWorkflowEngine() other_wfe.callbacks.add_many([ m('mouse'), [ m('dog'), [m('cat'), m('puppy')], [m('python'), halt_processing()], m('horse'), ] ], self.key) with pytest.raises(HaltProcessing): other_wfe.process(self.tokens) t = get_first(self.tokens) assert get_xth(self.tokens, 0) == 'mouse dog cat puppy python' assert get_xth(self.tokens, 1) is None assert get_xth(self.tokens, 2) is None compl = 'mouse dog cat puppy python horse' compl1 = 'mouse dog cat puppy python' @pytest.mark.parametrize("obj,task,results", ( ('prev', 'prev', (compl + " python", compl1, None)), ('prev', 'current', (compl, compl1, None)), # current task is to halt ('prev', 'next', (compl + " horse", compl1 + " " + compl1, None)), ('prev', 'first', (compl + " " + compl1, compl1, None)), ('current', 'prev', (compl, compl1 + " python", None)), ('current', 'current', (compl, compl1, None)), ('current', 'next', (compl, compl1 + " horse", compl1)), ('current', 'first', (compl, compl1 + " " + compl1, None)), ('next', 'prev', (compl, compl1, "python")), ('next', 'current', (compl, compl1, None)), ('next', 'next', (compl, compl1, "horse")), ('next', 'first', (compl, compl1, compl1)), ('first', 'prev', (compl + " python", compl1, None)), ('first', 'current', (compl, compl1, None)), # current task is to halt ('first', 'next', (compl + " horse", compl1 + " " + compl1, None)), ('first', 'first', (compl + " " + compl1, compl1, None)), )) def test_51_workflow_restart_after_halt(self, obj, task, results): self.wfe.callbacks.add_many([ m('mouse'), [ m('dog'), [m('cat'), m('puppy')], [m('python'), halt_processing()], m('horse'), ] ], self.key) with pytest.raises(HaltProcessing): self.wfe.process(self.tokens) assert get_xth(self.tokens, 0) == 'mouse dog cat puppy python' assert get_xth(self.tokens, 1) is None assert get_xth(self.tokens, 2) is None # this should pick up from the point where we stopped with pytest.raises(HaltProcessing): self.wfe.restart('current', 'next') assert get_xth(self.tokens, 0) == 'mouse dog cat puppy python horse' assert get_xth(self.tokens, 1) == 'mouse dog cat puppy python' assert get_xth(self.tokens, 2) is None with pytest.raises(HaltProcessing): self.wfe.restart(obj, task) assert (get_xth(self.tokens, 0), get_xth(self.tokens, 1), get_xth(self.tokens, 2)) == results def test_restart_accepts_new_objects(self): workflow = [m('test')] self.wfe.callbacks.replace(workflow, self.key) self.wfe.process(self.tokens) new_data = ['a', 'b', 'c', 'd', 'e'] new_tokens = [FakeToken(x, type='*') for x in new_data] self.wfe.restart('first', 'first', objects=new_tokens) assert self.wfe.objects == new_tokens def test_has_completed(self): self.wfe.callbacks.replace([ m('mouse'), halt_processing(), m('horse'), ]) assert self.wfe.has_completed is False with pytest.raises(HaltProcessing): self.wfe.process([self.tokens[0]]) assert self.wfe.has_completed is False self.wfe.restart('current', 'next') assert self.wfe.has_completed is True def test_nested_workflow_halt(self): other_wfe = GenericWorkflowEngine() wfe = self.wfe other_wfe.callbacks.add_many([ m('mouse'), [ m('dog'), [m('cat'), m('puppy')], [m('python'), halt_processing()], m('horse'), ] ], self.key) wfe.callbacks.add_many([ m('mouse'), [ m('dog'), [m('cat'), m('puppy')], [m('python'), lambda o, e: other_wfe.process(self.tokens)], m('horse'), ] ], self.key) with pytest.raises(HaltProcessing): wfe.process(self.tokens) t = get_first(self.tokens) assert get_xth(self.tokens, 0) == 'mouse dog cat puppy python mouse dog cat puppy python' assert get_xth(self.tokens, 1) is None assert get_xth(self.tokens, 2) is None @pytest.mark.parametrize("callbacks,kwargs,result,exception", ( ( [ m('mouse'), [ m('dog'), [m('cat'), m('puppy')], [m('python'), workflow_error()], m('horse'), ] ], {}, 'mouse dog cat puppy python', WorkflowError, ), ( [ m('mouse'), [ m('dog'), [m('cat'), m('puppy')], [m('python'), workflow_error()], m('horse'), ] ], { 'stop_on_error': False, }, 'mouse dog cat puppy python', None, ), ( [ m('mouse'), [ m('dog'), [m('cat'), m('puppy')], [m('python'), halt_processing()], m('horse'), ] ], { 'stop_on_halt': False, }, 'mouse dog cat puppy python', None, ), )) def test_process_smash_through(self, callbacks, kwargs, result, exception): self.wfe.callbacks.add_many(callbacks, self.key) if exception: with pytest.raises(exception): self.wfe.process(self.tokens, **kwargs) else: self.wfe.process(self.tokens, **kwargs) for idx, dummy in enumerate(self.tokens): assert get_xth(self.tokens, idx) == result