コード例 #1
0
ファイル: stub_service.py プロジェクト: olivierh59500/pysoa
    def __call__(self, action_request):
        response_body = self.run(action_request)

        if response_body is not None:
            return ActionResponse(action=action_request.action,
                                  body=response_body)
        else:
            return ActionResponse(action=action_request.action)
コード例 #2
0
    def execute_job(self, job_request):
        """
        Processes and runs the ActionRequests on the Job.
        """
        # Run the Job's Actions
        job_response = JobResponse()
        job_switches = RequestSwitchSet(job_request['context']['switches'])
        for i, raw_action_request in enumerate(job_request['actions']):
            action_request = EnrichedActionRequest(
                action=raw_action_request['action'],
                body=raw_action_request.get('body', None),
                switches=job_switches,
                context=job_request['context'],
                control=job_request['control'],
                client=job_request['client'],
            )
            if action_request.action in self.action_class_map:
                # Get action to run
                action = self.action_class_map[action_request.action](
                    self.settings)
                # Wrap it in middleware
                wrapper = self.make_middleware_stack(
                    [m.action for m in self.middleware],
                    action,
                )
                # Execute the middleware stack
                try:
                    action_response = wrapper(action_request)
                except ActionError as e:
                    # Error: an error was thrown while running the Action (or Action middleware)
                    action_response = ActionResponse(
                        action=action_request.action,
                        errors=e.errors,
                    )
            else:
                # Error: Action not found.
                action_response = ActionResponse(
                    action=action_request.action,
                    errors=[
                        Error(
                            code=ERROR_CODE_UNKNOWN,
                            message=
                            'The action "{}" was not found on this server.'.
                            format(action_request.action),
                            field='action',
                        )
                    ],
                )

            job_response.actions.append(action_response)
            if (action_response.errors and not job_request['control'].get(
                    'continue_on_error', False)):
                # Quit running Actions if an error occurred and continue_on_error is False
                break

        return job_response
コード例 #3
0
    def __call__(
            self,
            action_request):  # type: (EnrichedActionRequest) -> ActionResponse
        response_body = self.run(action_request)

        if response_body is not None:
            return ActionResponse(action=action_request.action,
                                  body=response_body)
        else:
            return ActionResponse(action=action_request.action)
コード例 #4
0
def test_raises_only_error_codes_unexpected(test_error, auth_missing_error):
    errors = [test_error, auth_missing_error]
    with pytest.raises(pytest.raises.Exception):
        with raises_only_error_codes(['AUTH_MISSING']):
            raise Client.CallActionError(
                actions=[ActionResponse(action='', errors=errors)]
            )
コード例 #5
0
def test_raises_error_codes_on_match(test_error):
    errors = [test_error]
    with raises_error_codes('TEST') as exc_info:
        raise Client.CallActionError(
            actions=[ActionResponse(action='', errors=errors)])

    assert exc_info.soa_errors == errors
コード例 #6
0
def test_raises_call_action_error_on_error(test_error):
    errors = [test_error]
    with raises_call_action_error() as exc_info:
        raise Client.CallActionError(
            actions=[ActionResponse(action='', errors=errors)])

    assert exc_info.soa_errors == errors
コード例 #7
0
 def action_logic(
         request):  # type: (EnrichedActionRequest) -> ActionResponse
     return ActionResponse(action='one',
                           body={
                               'animal_response': request.body['animal'],
                               'settings': settings
                           })
コード例 #8
0
def test_raises_field_errors_on_match(invalid_event_id_field_error):
    errors = [invalid_event_id_field_error]
    with raises_field_errors({'event_id': 'INVALID'}) as exc_info:
        raise Client.CallActionError(
            actions=[ActionResponse(action='', errors=errors)])

    assert exc_info.soa_errors == errors
コード例 #9
0
def test_raises_error_only_codes_unexpected_missing(test_error,
                                                    auth_missing_error):
    errors = [test_error, auth_missing_error]
    with pytest.raises(pytest.raises.Exception):
        with raises_only_error_codes('UNAUTHORIZED'):
            raise Client.CallActionError(
                actions=[ActionResponse(action='', errors=errors)])
コード例 #10
0
def test_raises_error_only_codes_unexpected_field_error(
        invalid_event_id_field_error, auth_missing_error):
    errors = [invalid_event_id_field_error, auth_missing_error]
    with pytest.raises(pytest.raises.Exception):
        with raises_only_error_codes('AUTH_MISSING'):
            raise Client.CallActionError(
                actions=[ActionResponse(action='', errors=errors)])
コード例 #11
0
def test_raises_only_error_codes_match(test_error, auth_missing_error):
    errors = [test_error, auth_missing_error]
    with raises_only_error_codes(['AUTH_MISSING', 'TEST']) as exc_info:
        raise Client.CallActionError(
            actions=[ActionResponse(action='', errors=errors)])

    assert exc_info.soa_errors == errors
コード例 #12
0
def test_raises_error_codes_missing(codes):
    errors = [Error(code=code, message='bam') for code in codes]
    with pytest.raises(pytest.raises.Exception):
        with raises_error_codes(['AUTH_MISSING']):
            raise Client.CallActionError(
                actions=[ActionResponse(action='', errors=errors)]
            )
コード例 #13
0
    def test_two_stubs_with_parallel_calls_and_action_response_errors_not_raised(
        self,
        stub_test_action_1,
        stub_test_action_2,
    ):
        stub_test_action_1.return_value = ActionResponse(
            action='test_action_1',
            errors=[Error(code='BAD_ACTION', message='You are a bad actor')],
        )

        job_responses = self.client.call_jobs_parallel(
            [
                {'service_name': 'test_service', 'actions': [{'action': 'test_action_1', 'body': {'a': 'b'}}]},
                {'service_name': 'test_service', 'actions': [{'action': 'test_action_2', 'body': {'c': 'd'}}]},
            ],
            raise_action_errors=False,
        )

        self.assertIsNotNone(job_responses)
        self.assertEqual(2, len(job_responses))
        self.assertEqual(1, len(job_responses[0].actions))
        self.assertEqual([Error(code='BAD_ACTION', message='You are a bad actor')], job_responses[0].actions[0].errors)
        self.assertEqual(1, len(job_responses[1].actions))
        self.assertEqual({'three': 'four'}, job_responses[1].actions[0].body)

        stub_test_action_1.assert_called_once_with({'a': 'b'})
        stub_test_action_2.assert_called_once_with({'c': 'd'})
コード例 #14
0
def test_raises_error_codes_multiple(codes):
    errors = [Error(code=code, message='bam') for code in codes]
    with raises_error_codes(['TEST', 'AUTH_MISSING']) as exc_info:
        raise Client.CallActionError(
            actions=[ActionResponse(action='', errors=errors)])

    assert exc_info.soa_errors == errors
コード例 #15
0
def test_raises_field_errors_missing(code, field):
    errors = [
        Error(code=code, message='test fail', field=field),
    ]
    with pytest.raises(pytest.raises.Exception):
        with raises_field_errors({'event_id': 'UNKNOWN'}):
            raise Client.CallActionError(
                actions=[ActionResponse(action='', errors=errors)])
コード例 #16
0
def test_raises_field_errors_match_multiple(codes):
    errors = [Error(code=code, field=field, message='bam') for field, code in codes]
    with raises_field_errors({'event_id': 'UNKNOWN', 'organization_id': 'INVALID'}) as exc_info:
        raise Client.CallActionError(
            actions=[ActionResponse(action='', errors=errors)]
        )

    assert exc_info.soa_errors == errors
コード例 #17
0
    def __call__(self, action_request):  # type: (EnrichedActionRequest) -> ActionResponse
        """
        Main entry point for actions from the `Server` (or potentially from tests). Validates that the request matches
        the `request_schema`, then calls `validate()`, then calls `run()` if `validate()` raised no errors, and then
        validates that the return value from `run()` matches the `response_schema` before returning it in an
        `ActionResponse`.

        :param action_request: The request object

        :return: The response object

        :raise: ActionError, ResponseValidationError
        """
        # Validate the request
        if self.request_schema:
            errors = [
                Error(
                    code=error.code,
                    message=error.message,
                    field=error.pointer,
                    is_caller_error=True,
                )
                for error in (self.request_schema.errors(action_request.body) or [])
            ]
            if errors:
                raise ActionError(errors=errors, set_is_caller_error_to=None)
        # Run any custom validation
        self.validate(action_request)
        # Run the body of the action
        response_body = self.run(action_request)
        # Validate the response body. Errors in a response are the problem of
        # the service, and so we just raise a Python exception and let error
        # middleware catch it. The server will return a SERVER_ERROR response.
        if self.response_schema:
            conformity_errors = self.response_schema.errors(response_body)
            if conformity_errors:
                raise ResponseValidationError(action=action_request.action, errors=conformity_errors)
        # Make an ActionResponse and return it
        if response_body is not None:
            return ActionResponse(
                action=action_request.action,
                body=response_body,
            )
        else:
            return ActionResponse(action=action_request.action)
コード例 #18
0
class ErrorServer(Server):
    service_name = 'error_service'

    # noinspection PyTypeChecker
    action_class_map = {
        'job_error': lambda *_, **__: (_ for _ in ()).throw(
            JobError(errors=[Error(code='BAD_JOB', message='You are a bad job')])
        ),
        'okay_action': lambda *_, **__: lambda *_, **__: ActionResponse(action='okay_action', body={'no_error': True}),
    }
コード例 #19
0
def test_raises_field_errors_unexpected_only(invalid_event_id_field_error,
                                             unknown_event_id_field_error):
    errors = [
        invalid_event_id_field_error,
        unknown_event_id_field_error,
    ]
    with pytest.raises(pytest.raises.Exception):
        with raises_field_errors({'event_id': ['UNKNOWN']}, only=True):
            raise Client.CallActionError(
                actions=[ActionResponse(action='', errors=errors)])
コード例 #20
0
def test_raises_only_field_errors_unexpected_error(
        auth_missing_error, invalid_organization_id_field_error):
    errors = [
        auth_missing_error,
        invalid_organization_id_field_error,
    ]
    with pytest.raises(pytest.raises.Exception):
        with raises_only_field_errors({'organization_id': 'INVALID'}):
            raise Client.CallActionError(
                actions=[ActionResponse(action='', errors=errors)])
コード例 #21
0
def test_raises_only_field_errors_unexpected_missing(
        unknown_event_id_field_error, invalid_organization_id_field_error):
    errors = [
        unknown_event_id_field_error,
        invalid_organization_id_field_error,
    ]
    with pytest.raises(pytest.raises.Exception):
        with raises_only_field_errors({'event_id': 'MISSING'}):
            raise Client.CallActionError(
                actions=[ActionResponse(action='', errors=errors)])
コード例 #22
0
def test_raises_only_field_errors_match(invalid_event_id_field_error, unknown_event_id_field_error):
    errors = [
        invalid_event_id_field_error,
        unknown_event_id_field_error,
    ]
    with raises_only_field_errors({'event_id': ['UNKNOWN', 'INVALID']}) as exc_info:
        raise Client.CallActionError(
            actions=[ActionResponse(action='', errors=errors)]
        )

    assert exc_info.soa_errors == errors
コード例 #23
0
    def test_call_local_action_super_enriched_request(self):
        action = mock.MagicMock()
        action.return_value.return_value = ActionResponse(
            action='another_foo', body={'sweet': 'success'})

        server = mock.MagicMock()
        server.settings = {'a_setting': 'a_value'}
        server.action_class_map = {'another_foo': action}

        logger = logging.getLogger('test')

        r = SuperEnrichedActionRequest(
            action='foo',
            body={'bar': 'baz'},
            context={
                'auth_token': 'def456',
                'auth': 'original'
            },
            control={'repeat': True},
            metrics='A custom object',
            analytics_logger=logger,
        )
        r._server = server

        response = r.call_local_action('another_foo',
                                       {'entity_id': '1a8t27oh'},
                                       context={
                                           'auth': 'new',
                                           'foo': 'bar'
                                       })
        assert response.action == 'another_foo'
        assert response.body == {'sweet': 'success'}

        action.assert_called_once_with(server.settings)
        assert action.return_value.call_count == 1

        other_r = action.return_value.call_args[0][0]
        assert isinstance(other_r, SuperEnrichedActionRequest)
        assert other_r is not r
        assert other_r != r
        assert other_r.action == 'another_foo'
        assert other_r.body == {'entity_id': '1a8t27oh'}
        assert other_r.context == {
            'auth_token': 'def456',
            'auth': 'new',
            'foo': 'bar'
        }
        assert other_r.control == {'repeat': True}
        assert other_r.metrics == 'A custom object'
        assert other_r.analytics_logger is logger
        assert getattr(other_r, '_server') is server
コード例 #24
0
    def test_call_local_action_other_request_details(self):
        action = mock.MagicMock()
        action.return_value.return_value = ActionResponse(
            action='another_foo', errors=[Error('BAR', 'Bar error')])

        server = mock.MagicMock()
        server.settings = {'a_setting': 'a_value'}
        server.action_class_map = {'another_foo': action}

        r = EnrichedActionRequest(action='foo',
                                  body={'bar': 'baz'},
                                  context={'auth': 'abc123'},
                                  control={'speed': 5})
        r._server = server

        with pytest.raises(ActionError) as error_context:
            r.call_local_action('another_foo', {'height': '10m'})

        assert error_context.value.errors[0].code == 'BAR'

        action.assert_called_once_with(server.settings)
        assert action.return_value.call_count == 1

        other_r = action.return_value.call_args[0][0]
        assert other_r is not r
        assert other_r != r
        assert other_r.action == 'another_foo'
        assert other_r.body == {'height': '10m'}
        assert other_r.context == {'auth': 'abc123'}
        assert other_r.control == {'speed': 5}
        assert getattr(other_r, '_server') is server

        action.reset_mock()

        response = r.call_local_action('another_foo', {'height': '10m'},
                                       raise_action_errors=False)
        assert response.action == 'another_foo'
        assert response.errors
        assert response.errors[0].code == 'BAR'

        action.assert_called_once_with(server.settings)
        assert action.return_value.call_count == 1

        other_r = action.return_value.call_args[0][0]
        assert other_r is not r
        assert other_r != r
        assert other_r.action == 'another_foo'
        assert other_r.body == {'height': '10m'}
        assert other_r.context == {'auth': 'abc123'}
        assert other_r.control == {'speed': 5}
        assert getattr(other_r, '_server') is server
コード例 #25
0
ファイル: base.py プロジェクト: guoyu07/pysoa
 def __call__(self, action_request):
     """
     Main entry point for Actions from the Server (or potentially from tests)
     """
     # Validate the request
     if self.request_schema:
         errors = [
             Error(
                 code=ERROR_CODE_INVALID,
                 message=error.message,
                 field=error.pointer,
             ) for error in (
                 self.request_schema.errors(action_request.body) or [])
         ]
         if errors:
             raise ActionError(errors=errors)
     # Run any custom validation
     self.validate(action_request)
     # Run the body of the action
     response_body = self.run(action_request)
     # Validate the response body. Errors in a response are the problem of
     # the service, and so we just raise a Python exception and let error
     # middleware catch it. The server will return a SERVER_ERROR response.
     if self.response_schema:
         errors = self.response_schema.errors(response_body)
         if errors:
             raise ResponseValidationError(action=action_request.action,
                                           errors=errors)
     # Make an ActionResponse and return it
     if response_body is not None:
         return ActionResponse(
             action=action_request.action,
             body=response_body,
         )
     else:
         return ActionResponse(action=action_request.action)
コード例 #26
0
    def execute_job(self, job_request):
        """
        Processes and runs the action requests contained in the job and returns a `JobResponse`.

        :param job_request: The job request
        :type job_request: dict

        :return: A `JobResponse` object
        :rtype: JobResponse
        """
        # Run the Job's Actions
        job_response = JobResponse()
        job_switches = RequestSwitchSet(job_request['context']['switches'])
        for i, raw_action_request in enumerate(job_request['actions']):
            action_request = EnrichedActionRequest(
                action=raw_action_request['action'],
                body=raw_action_request.get('body', None),
                switches=job_switches,
                context=job_request['context'],
                control=job_request['control'],
                client=job_request['client'],
                async_event_loop=job_request['async_event_loop'],
            )
            action_in_class_map = action_request.action in self.action_class_map
            if action_in_class_map or action_request.action in ('status', 'introspect'):
                # Get action to run
                if action_in_class_map:
                    action = self.action_class_map[action_request.action](self.settings)
                elif action_request.action == 'introspect':
                    from pysoa.server.action.introspection import IntrospectionAction
                    action = IntrospectionAction(server=self)
                else:
                    if not self._default_status_action_class:
                        from pysoa.server.action.status import make_default_status_action_class
                        self._default_status_action_class = make_default_status_action_class(self.__class__)
                    action = self._default_status_action_class(self.settings)
                # Wrap it in middleware
                wrapper = self.make_middleware_stack(
                    [m.action for m in self.middleware],
                    action,
                )
                # Execute the middleware stack
                try:
                    action_response = wrapper(action_request)
                except ActionError as e:
                    # Error: an error was thrown while running the Action (or Action middleware)
                    action_response = ActionResponse(
                        action=action_request.action,
                        errors=e.errors,
                    )
            else:
                # Error: Action not found.
                action_response = ActionResponse(
                    action=action_request.action,
                    errors=[Error(
                        code=ERROR_CODE_UNKNOWN,
                        message='The action "{}" was not found on this server.'.format(action_request.action),
                        field='action',
                    )],
                )

            job_response.actions.append(action_response)
            if (
                action_response.errors and
                not job_request['control'].get('continue_on_error', False)
            ):
                # Quit running Actions if an error occurred and continue_on_error is False
                break

        return job_response
コード例 #27
0
ファイル: stub_service.py プロジェクト: olivierh59500/pysoa
        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
コード例 #28
0
ファイル: stub_service.py プロジェクト: olivierh59500/pysoa
    def __enter__(self):
        self._wrapped_client_send_request = Client.send_request
        self._wrapped_client_get_all_responses = Client.get_all_responses
        self._services_with_calls_sent_to_wrapped_client = set()

        mock_action = self._MockAction(
            name='{}.{}'.format(self.service, self.action))

        if self.body or self.errors:
            mock_action.side_effect = lambda _: ActionResponse(
                self.action, errors=self.errors, body=self.body)

        @wraps(Client.send_request)
        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

        wrapped_send_request.description = '<stub {service}.{action} wrapper around {wrapped}>'.format(
            service=self.service,
            action=self.action,
            wrapped=getattr(Client.send_request, 'description',
                            Client.send_request.__repr__()),
        )  # This description is a helpful debugging tool

        @wraps(Client.get_all_responses)
        def wrapped_get_all_responses(client, service_name, *args, **kwargs):
            if service_name in self._services_with_calls_sent_to_wrapped_client:
                # Check if the any requests were actually sent wrapped client for this service; we do this because
                # the service may exist solely as a stubbed service, and calling the wrapped get_all_responses
                # will result in an error in this case.
                for request_id, response in self._wrapped_client_get_all_responses(
                        client, service_name, *args, **kwargs):
                    if request_id in self._stub_action_responses_to_merge[
                            service_name]:
                        request_id, continue_on_error = self._stub_action_responses_to_merge[
                            service_name].pop(request_id, )
                        response_to_merge = self._stub_action_responses_outstanding[
                            service_name].pop(request_id)

                        if isinstance(response_to_merge, Exception):
                            raise response_to_merge

                        for i, action_response in six.iteritems(
                                response_to_merge.actions):
                            response.actions.insert(i, action_response)

                        if not continue_on_error:
                            # Simulate the server job halting on the first action error
                            first_error_index = -1
                            for i, action_result in enumerate(
                                    response.actions):
                                if action_result.errors:
                                    first_error_index = i
                                    break
                            if first_error_index >= 0:
                                response.actions = response.actions[:
                                                                    first_error_index
                                                                    + 1]

                        response.errors.extend(response_to_merge.errors)
                    yield request_id, response

            if self._stub_action_responses_to_merge[service_name]:
                raise Exception(
                    'Something very bad happened, and there are still stubbed responses to merge!'
                )

            for request_id, response in six.iteritems(
                    self._stub_action_responses_outstanding[service_name]):
                if isinstance(response, Exception):
                    raise response
                yield request_id, response

            self._stub_action_responses_outstanding[service_name] = {}

        wrapped_get_all_responses.description = '<stub {service}.{action} wrapper around {wrapped}>'.format(
            service=self.service,
            action=self.action,
            wrapped=getattr(Client.get_all_responses, 'description',
                            Client.get_all_responses.__repr__()),
        )  # This description is a helpful debugging tool

        # Wrap Client.send_request, whose original version was saved in self._wrapped_client_send_request (which itself
        # might be another wrapper if we have stubbed multiple actions).
        Client.send_request = wrapped_send_request

        # Wrap Client.get_all_responses, whose original version was saved in self._wrapped_client_get_all_responses
        # (which itself might be another wrapper if we have stubbed multiple actions).
        Client.get_all_responses = wrapped_get_all_responses

        self.enabled = True
        return mock_action
コード例 #29
0
 def action_logic(
         request):  # type: (EnrichedActionRequest) -> ActionResponse
     return ActionResponse(
         action='one', body={'building_response': request.body['building']})
コード例 #30
0
 def action_logic(request):
     return ActionResponse(
         action='one', body={'building_response': request.body['building']})