def test_pause_on_fail(self): # First shutdown the default setup trail. self.trail_client.shutdown(dry_run=False) def failing_action_function(trail_env, context): raise Exception('mock failure') step_a = Step(failing_action_function) step_b = Step(action_function_b) # Trail definition: The following example trail represents the following DAG: # step_a ----> step_b test_trail_definition = [(step_a, step_b)] context = Context(42) self.trail_server = TrailServer(test_trail_definition, delay=0.1, context=context) self.trail_server.serve(threaded=True) self.trail_client = TrailClient(self.trail_server.socket_file) self.trail_client.start() self.wait_till('failing_action_function', Step.PAUSED_ON_FAIL) self.check_step_attributes( StatusField.STATE, { 'failing_action_function': Step.PAUSED_ON_FAIL, 'action_function_b': Step.WAIT, }) self.check_step_attributes(StatusField.RETURN_VALUE, { 'failing_action_function': 'mock failure', 'action_function_b': None, })
def test_message_passing(self): # First shutdown the default setup trail. self.trail_client.shutdown(dry_run=False) def io_action_function(trail_env, context): reply = trail_env.input('Prompting user') trail_env.output('Reply received: {}'.format(reply)) def slow_action_function(trail_env, context): sleep(0.2) step_a = Step(io_action_function) step_b = Step(slow_action_function) # Trail definition: The following example trail represents the following DAG: # step_a ----> step_b # test_trail_definition = [(step_a, step_b)] context = Context(42) self.trail_server = TrailServer(test_trail_definition, delay=0.1, context=context) self.trail_server.serve(threaded=True) self.trail_client = TrailClient(self.trail_server.socket_file) self.trail_client.start() self.wait_till('io_action_function', Step.RUN) statuses = self.trail_client.status(name='io_action_function') self.assertEqual(len(statuses), 1) prompt_message = statuses[0][StatusField.UNREPLIED_PROMPT_MESSAGE] self.assertEqual(prompt_message, 'Prompting user') # Reply to steps self.trail_client.send_message_to_steps(name='io_action_function', message='Done', dry_run=False) self.wait_till('io_action_function', Step.SUCCESS) # Check reply statuses = self.trail_client.status( name='io_action_function', fields=[StatusField.OUTPUT_MESSAGES]) self.assertEqual(len(statuses), 1) output_messages = statuses[0][StatusField.OUTPUT_MESSAGES] self.assertEqual(output_messages, ['Reply received: Done'])
def test_interrupt(self): # First shutdown the default setup trail. self.trail_client.shutdown(dry_run=False) # We need a long running step to be able to invoke interrupt on it. def long_running_action_function(trail_env, context): sleep(3) return "This is action A. Value from context: {}".format( context.value) step_a = Step(long_running_action_function) step_b = Step(action_function_b) # Define a trail with slightly long running steps. # The following example trail represents the following DAG: # step_a ----> step_b test_trail_definition = [(step_a, step_b)] context = Context(42) self.trail_server = TrailServer(test_trail_definition, delay=0.1, context=context) self.trail_server.serve(threaded=True) self.trail_client = TrailClient(self.trail_server.socket_file) self.trail_client.start() self.wait_till('long_running_action_function', Step.RUN) # long_running_action_function is a long running step (5 seconds), so terminate it. affected_steps = self.trail_client.interrupt(dry_run=False) self.check_affected_steps(affected_steps, ['long_running_action_function']) self.check_step_attributes( StatusField.STATE, { 'long_running_action_function': Step.INTERRUPTED, 'action_function_b': Step.WAIT, }) # Make sure interrupted is a state that can be resumed from (re-run). affected_steps = self.trail_client.resume() self.check_affected_steps(affected_steps, ['long_running_action_function'])
def setUp(self): self.step_a = Step(action_function_a) self.step_b = Step(action_function_b, foo='bar') self.step_c = Step(action_function_c) self.step_d = Step(action_function_d) self.step_e = Step(action_function_e) self.step_f = Step(action_function_f, foo='bar') self.step_g = Step(action_function_g) # Trail definition # The following example trail represents the following DAG: # The run-time (in seconds) of each step is mentioned below the step name. # +----> step_b ----> step_c ----> step_d ----+ # | 1 1 1 | # step_a -| +----> step_g # 1 | 1 1 | 1 # +----> step_e -----------------> step_f ----+ # test_trail_definition = [ (self.step_a, self.step_b), (self.step_a, self.step_e), # First branch (self.step_b, self.step_c), (self.step_c, self.step_d), (self.step_d, self.step_g), # Second branch (self.step_e, self.step_f), (self.step_f, self.step_g), ] # Adding this for convenience in tests. self.step_list = [ self.step_a, self.step_b, self.step_c, self.step_d, self.step_e, self.step_f, self.step_g, ] # Setup trail to run automatically (non-interactively) context = Context(42) self.trail_server = TrailServer(test_trail_definition, delay=0.1, context=context) self.trail_server.serve(threaded=True) self.trail_client = TrailClient(self.trail_server.socket_file)
return "This is action E. Value from context: {}".format(context.value) @accepts_context def action_function_f(context): sleep(1) return "This is action F. Value from context: {}".format(context.value) @accepts_context def action_function_g(context): sleep(10) return "This is action G. Value from context: {}".format(context.value) step_a = Step(action_function_a) step_b = Step(action_function_b) step_c = Step(action_function_c, foo='bar') step_d = Step(action_function_d) step_e = Step(action_function_e) step_f = Step(action_function_f, foo='bar') step_g = Step(action_function_g) # Trail definition # The following example trail represents the following DAG: # The run-time (in seconds) of each step is mentioned below the step name. # +----> step_b ----> step_c ----> step_d ----+ # | 10 1 10 | # step_a -| +----> step_g # 5 | 5 1 | 10
if sleep_time > 5: return 'I have slept well.' else: return 'You woke me up too early, I am coming after you.' def ending_point(action): return '[Here is how I feel] -- {}'.format(action) # Now that we have the functions defined, we need to define action functions and wrap them in Steps. # Below you will see the use of extraction_wrapper and create_conditional_step, two useful helpers that will allow # us to easily convert the above functions into steps with behaviour that we want them to exhibit. # Let us start with the most trivial case where we convert the starting_point function into a step. start_the_day = Step(starting_point) # If we had not used the @accepts_nothing decorator at the function defintion, we could have simply done: # Step(accepts_nothing(starting_point)) # Now lets look at te "lazy" function. # It has the following behaviour: # 1. Accepts a string for branch choice. # 2. If it matches BranchChoice.lazy, returns a string. # 3. If it does not, then raises BranchNotChosen exception. # # We need to modify this behaviour to doing the following: # 1. Accept TrailEnvironment and Context objects. # 2. Extract the branch choice from the Context object using context.get_branch_choice method. # 3. Call "lazy" function with the branch choice. # 4. Use the return value as the return value of the step. # 5. Use the exception raised as the return value of the step.
import os from time import sleep from autotrail import (TrailServer, TrailClient, InteractiveTrail, interactive, Step, StatusField, Instruction, make_simple_templating_function) logging.basicConfig(level=logging.DEBUG, filename=os.path.join('/', 'tmp', 'example_trail_server.log')) # Action function and Step definitions step_a = Step( Instruction( 'step_a', make_simple_templating_function( 'Check who are you using: /bin/whoami'))) step_b = Step( Instruction( 'step_b', make_simple_templating_function( 'Check the current directory with: /bin/pwd'))) step_c = Step( Instruction('step_c', make_simple_templating_function('List files using: ls -l'))) step_d = Step( Instruction(
sleep(5) return value + 5 def action_function_f(value): sleep(1) return value + 6 def action_function_g(value): sleep(10) return value + 7 step_a = Step(action_function_a, pre_processor=pre_processor, post_processor=post_processor) step_b = Step(action_function_b, pre_processor=pre_processor, post_processor=post_processor) step_c = Step(action_function_c, pre_processor=pre_processor, post_processor=post_processor, foo='bar') step_d = Step(action_function_d, pre_processor=pre_processor, post_processor=post_processor) step_e = Step(action_function_e, pre_processor=pre_processor, post_processor=post_processor) step_f = Step(action_function_f,