def wrapped_send_request(client, service_name, actions, *args, **kwargs): assert isinstance( service_name, six.text_type ), 'Called service name "{}" must be unicode'.format( service_name, ) actions_to_send_to_mock = OrderedDict() actions_to_send_to_wrapped_client = [] for i, action_request in enumerate(actions): action_name = getattr(action_request, 'action', None) or action_request['action'] assert isinstance( action_name, six.text_type ), 'Called action name "{}" must be unicode'.format( action_name, ) if service_name == self.service and action_name == self.action: # If the service AND action name match, we should send the request to our mocked client if not isinstance(action_request, ActionRequest): action_request = ActionRequest(**action_request) actions_to_send_to_mock[i] = action_request else: # If the service OR action name DO NOT match, we should delegate the request to the wrapped client actions_to_send_to_wrapped_client.append(action_request) request_id = _global_stub_action_request_counter.get_next() continue_on_error = kwargs.get('continue_on_error', False) if actions_to_send_to_wrapped_client: # If any un-stubbed actions need to be sent to the original client, send them self._services_with_calls_sent_to_wrapped_client.add( service_name) unwrapped_request_id = self._wrapped_client_send_request( client, service_name, actions_to_send_to_wrapped_client, *args, **kwargs) if not actions_to_send_to_mock: # If there are no stubbed actions to mock, just return the un-stubbed request ID return unwrapped_request_id self._stub_action_responses_to_merge[service_name][ unwrapped_request_id] = ( request_id, continue_on_error, ) ordered_actions_for_merging = OrderedDict() job_response_transport_exception = None job_response = JobResponse() for i, action_request in actions_to_send_to_mock.items(): mock_response = None try: mock_response = mock_action(action_request.body or {}) if isinstance(mock_response, JobResponse): job_response.errors.extend(mock_response.errors) if mock_response.actions: mock_response = mock_response.actions[0] elif isinstance(mock_response, dict): mock_response = ActionResponse(self.action, body=mock_response) elif not isinstance(mock_response, ActionResponse): mock_response = ActionResponse(self.action) except ActionError as e: mock_response = ActionResponse(self.action, errors=e.errors) except JobError as e: job_response.errors.extend(e.errors) except (MessageReceiveError, MessageReceiveTimeout) as e: job_response_transport_exception = e if mock_response: ordered_actions_for_merging[i] = mock_response job_response.actions.append(mock_response) if not continue_on_error and mock_response.errors: break if job_response.errors: break if actions_to_send_to_wrapped_client: # If the responses will have to be merged by get_all_responses, replace the list with the ordered dict job_response.actions = ordered_actions_for_merging self._stub_action_responses_outstanding[service_name][ request_id] = (job_response_transport_exception or job_response) return request_id
def wrapped(client, service_name, actions, *args, **kwargs): assert isinstance( service_name, six.text_type ), 'Called service name "{}" must be unicode'.format( service_name, ) requests_to_send_to_mock_client = OrderedDict() requests_to_send_to_wrapped_client = [] for i, action_request in enumerate(actions): action_name = getattr(action_request, 'action', None) or action_request['action'] assert isinstance( action_name, six.text_type ), 'Called action name "{}" must be unicode'.format( action_name, ) if service_name == self.service and action_name == self.action: # If the service AND action name match, we should send the request to our mocked client if not isinstance(action_request, ActionRequest): action_request = ActionRequest(action_request) requests_to_send_to_mock_client[i] = action_request else: # If the service OR action name DO NOT match, we should delegate the request to the wrapped client requests_to_send_to_wrapped_client.append(action_request) # Hold off on raising action errors until both mock and real responses are merged raise_action_errors = kwargs.get('raise_action_errors', True) kwargs['raise_action_errors'] = False # Run the real and mocked jobs and merge the results, to simulate a single job if requests_to_send_to_wrapped_client: job_response = self._wrapped_client_call_actions_method( client, service_name, requests_to_send_to_wrapped_client, *args, **kwargs) else: job_response = JobResponse() for i, action_request in requests_to_send_to_mock_client.items(): try: mock_response = mock_action(action_request.body or {}) if isinstance(mock_response, JobResponse): mock_response = mock_response.actions[0] elif isinstance(mock_response, dict): mock_response = ActionResponse(self.action, body=mock_response) elif not isinstance(mock_response, ActionResponse): mock_response = ActionResponse(self.action) except ActionError as e: mock_response = ActionResponse(self.action, errors=e.errors) job_response.actions.insert(i, mock_response) if kwargs.get('continue_on_error', False) is False: # Simulate the server job halting on the first action error first_error_index = -1 for i, action_result in enumerate(job_response.actions): if action_result.errors: first_error_index = i break if first_error_index >= 0: job_response.actions = job_response.actions[: first_error_index + 1] if raise_action_errors: error_actions = [ action for action in job_response.actions if action.errors ] if error_actions: raise Client.CallActionError(error_actions) return job_response