def test_re_blocks_ops_from_queue(self, stage, mocker): first_connect = pipeline_ops_base.ConnectOperation( callback=mocker.MagicMock()) first_fake_op = FakeOperation(callback=mocker.MagicMock()) second_connect = pipeline_ops_base.ReconnectOperation( callback=mocker.MagicMock()) second_fake_op = FakeOperation(callback=mocker.MagicMock()) stage.run_op(first_connect) stage.run_op(first_fake_op) stage.run_op(second_connect) stage.run_op(second_fake_op) # at this point, ops are pended waiting for the first connect to complete. Verify this and complete the connect. assert stage.next.run_op.call_count == 1 assert stage.next.run_op.call_args[0][0] == first_connect operation_flow.complete_op(stage=stage.next, op=first_connect) # The connect is complete. This passes down first_fake_op and second_connect and second_fake_op gets pended waiting i # for second_connect to complete. # Note: this isn't ideal. In a perfect world, second_connect wouldn't start until first_fake_op is complete, but we # dont have this logic in place yet. assert stage.next.run_op.call_count == 3 assert stage.next.run_op.call_args_list[1][0][0] == first_fake_op assert stage.next.run_op.call_args_list[2][0][0] == second_connect # now, complete second_connect to give second_fake_op a chance to get passed down operation_flow.complete_op(stage=stage.next, op=second_connect) assert stage.next.run_op.call_count == 4 assert stage.next.run_op.call_args_list[3][0][0] == second_fake_op
def on_twin_response(twin_op): logger.info("{}({}): Got response for GetTwinOperation".format( self.name, op.name)) map_twin_error(original_op=op, twin_op=twin_op) if not twin_op.error: op.twin = json.loads(twin_op.response_body.decode("utf-8")) operation_flow.complete_op(self, op)
def test_op_callback_raises_exception(self, stage, op, fake_exception, mocker, unhandled_error_handler): op.callback = mocker.Mock(side_effect=fake_exception) complete_op(stage, op) assert op.callback.call_count == 1 assert op.callback.call_args == mocker.call(op) assert unhandled_error_handler.call_count == 1 assert unhandled_error_handler.call_args == mocker.call(fake_exception)
def on_twin_response(twin_op): logger.info( "{}({}): Got response for PatchTwinReportedPropertiesOperation operation".format( self.name, op.name ) ) map_twin_error(original_op=op, twin_op=twin_op) operation_flow.complete_op(self, op)
def test_runs_second_op(self, mocker, stage, op, op2, op3, finally_op, callback): op.action = "pend" op2.action = "pend" run_ops_in_serial(stage, op, op2, op3, callback=callback, finally_op=finally_op) assert stage.next._run_op.call_count == 1 assert stage.next._run_op.call_args == mocker.call(op) complete_op(stage.next, op) assert stage.next._run_op.call_args_list[1] == mocker.call(op2)
def test_runs_second_op_after_first_op_succceeds(self, mocker, stage, op, op2, op3, callback): op.action = "pend" op2.action = "pend" run_ops_in_serial(stage, op, op2, op3, callback=callback) assert stage.next._run_op.call_count == 1 assert stage.next._run_op.call_args == mocker.call(op) complete_op(stage.next, op) assert stage.next._run_op.call_count == 2 assert stage.next._run_op.call_args_list[1] == mocker.call(op2)
def test_operation_complete(self, params, op, stage): stage.pipeline_root.connected = False stage.run_op(op) connect_op = stage.next.run_op.call_args[0][0] operation_flow.complete_op(stage=stage.next, op=connect_op) operation_flow.complete_op(stage=stage.next, op=op) assert_callback_succeeded(op=op)
def test_connect_failure(self, params, op, stage, fake_exception): stage.pipeline_root.connected = False stage.run_op(op) connect_op = stage.next.run_op.call_args[0][0] connect_op.error = fake_exception operation_flow.complete_op(stage=stage.next, op=connect_op) assert_callback_failed(op=op, error=fake_exception)
def test_completes_original_op_after_new_op_completes(self, stage, op, new_op, callback): op.callback = callback new_op.action = "pend" delegate_to_different_op(stage, original_op=op, new_op=new_op) assert callback.call_count == 0 # because new_op is pending complete_op(stage.next, new_op) assert_callback_succeeded(op=op)
def test_calls_third_op_after_second_op_succeeds(self, mocker, stage, op, op2, op3, callback): op2.action = "pend" run_ops_in_serial(stage, op, op2, op3, callback=callback) assert stage.next._run_op.call_count == 2 assert stage.next._run_op.call_args_list[0] == mocker.call(op) assert stage.next._run_op.call_args_list[1] == mocker.call(op2) complete_op(stage.next, op2) assert stage.next._run_op.call_count == 3 assert stage.next._run_op.call_args_list[2] == mocker.call(op3)
def test_fails_blocked_op_if_serialized_op_fails(self, params, stage, connection_op, fake_op, fake_exception): stage.pipeline_root.connected = params[ "connected_flag_required_to_run"] stage.run_op(connection_op) stage.run_op(fake_op) connection_op.error = fake_exception operation_flow.complete_op(stage=stage.next, op=connection_op) assert_callback_failed(op=fake_op, error=fake_exception)
def test_waits_for_serialized_op_to_complete_before_passing_blocked_op( self, params, stage, connection_op, fake_op): stage.pipeline_root.connected = params[ "connected_flag_required_to_run"] stage.run_op(connection_op) stage.run_op(fake_op) operation_flow.complete_op(stage=stage.next, op=connection_op) assert stage.next.run_op.call_count == 2 assert stage.next.run_op.call_args[0][0] == fake_op
def test_connect_success(self, params, op, stage): stage.pipeline_root.connected = False stage.run_op(op) assert stage.next.run_op.call_count == 1 connect_op = stage.next.run_op.call_args[0][0] operation_flow.complete_op(stage=stage.next, op=connect_op) assert stage.next.run_op.call_count == 2 assert stage.next.run_op.call_args[0][0] == op
def stage_run_op(self, op): if getattr(op, "action", None) is None or op.action == "pass": operation_flow.complete_op(self, op) elif op.action == "fail" or op.action == "exception": raise Exception() elif op.action == "base_exception": raise UnhandledException() elif op.action == "pend": pass else: assert False
def on_reconnect_complete(reconnect_op): if reconnect_op.error: op.error = reconnect_op.error logger.error( "{}({}) reconnection failed. returning error {}". format(self.name, op.name, op.error)) operation_flow.complete_op(stage=self, op=op) else: logger.debug( "{}({}) reconnection succeeded. returning success.". format(self.name, op.name)) operation_flow.complete_op(stage=self, op=op)
def test_fails_multiple_ops(self, params, stage, connection_op, fake_ops, fake_exception): stage.pipeline_root.connected = params[ "connected_flag_required_to_run"] stage.run_op(connection_op) for op in fake_ops: stage.run_op(op) connection_op.error = fake_exception operation_flow.complete_op(stage=stage.next, op=connection_op) for op in fake_ops: assert_callback_failed(op=op, error=fake_exception)
def test_unblocks_multiple_ops(self, params, stage, connection_op, fake_ops): stage.pipeline_root.connected = params[ "connected_flag_required_to_run"] stage.run_op(connection_op) for op in fake_ops: stage.run_op(op) operation_flow.complete_op(stage=stage.next, op=connection_op) assert stage.next.run_op.call_count == 1 + len(fake_ops) # zip our ops and our calls together and make sure they match run_ops = zip(fake_ops, stage.next.run_op.call_args_list[1:]) for run_op in run_ops: op = run_op[0] call_args = run_op[1] assert op == call_args[0][0]
def test_immediately_completes_second_op(self, stage, params, mocker): first_connection_op = params["first_connection_op"](mocker.MagicMock()) second_connection_op = params["second_connection_op"]( mocker.MagicMock()) stage.pipeline_root.connected = params["pre_connected_flag"] stage.run_op(first_connection_op) stage.run_op(second_connection_op) # first_connection_op has been passed down. second_connection_op is waiting for first disconnect to complete. assert stage.next.run_op.call_count == 1 assert stage.next.run_op.call_args[0][0] == first_connection_op # complete first_connection_op stage.pipeline_root.connected = params["mid_connect_flag"] operation_flow.complete_op(stage=stage.next, op=first_connection_op) # second connect_op should be completed without having been passed down. assert stage.next.run_op.call_count == 1 assert_callback_succeeded(op=second_connection_op)
def on_token_update_complete(op): op.callback = old_callback if op.error: logger.error( "{}({}) token update failed. returning failure {}". format(self.name, op.name, op.error)) operation_flow.complete_op(stage=self, op=op) else: logger.debug( "{}({}) token update succeeded. reconnecting".format( self.name, op.name)) operation_flow.pass_op_to_next_stage( stage=self, op=pipeline_ops_base.ReconnectOperation( callback=on_reconnect_complete), ) logger.debug( "{}({}): passing to next stage with updated callback.". format(self.name, op.name))
def fail_set_auth_provider(self, op): if isinstance(op, params_security_clients["set_args_op_class"]): op.error = fake_exception operation_flow.complete_op(stage=self, op=op) else: old_execute_op(self, op)
def test_op_callback_raises_base_exception(self, stage, op, fake_base_exception, mocker): op.callback = mocker.Mock(side_effect=fake_base_exception) with pytest.raises(UnhandledException): complete_op(stage, op)
def test_calls_callback_on_error(self, stage, op, callback, fake_exception): op.error = fake_exception op.callback = callback complete_op(stage, op) assert_callback_failed(op=op, error=fake_exception)
def test_calls_callback_on_success(self, stage, op, callback): op.callback = callback complete_op(stage, op) assert_callback_succeeded(op)
def fail_set_auth_provider(self, op): if isinstance(op, pipeline_stages_base.SetX509AuthProviderOperation): op.error = fake_exception operation_flow.complete_op(stage=self, op=op) else: old_execute_op(self, op)