예제 #1
0
def test_vendor_http_error(response_with_error):
    """Check that HttpError correctly returns
       an instance of BusinessGatewayError
    """

    logging.debug('First run')
    http_error = HttpError('Foo bar', response_with_error)
    assert isinstance(http_error, HttpError)
    assert str(http_error) == 'Foo bar'

    logging.debug('Second run')
    HttpError.VendorType = SAP.BusinessGatewayError
    sap_error = HttpError('Another foo bar', response_with_error)
    assert isinstance(sap_error, SAP.BusinessGatewayError)
    assert str(sap_error) == 'Gateway Error'
예제 #2
0
        def changeset_handler(changeset, parts):
            """Gets changeset response from HTTP response"""

            logging.getLogger(LOGGER_NAME).debug('Changeset handler called for changeset %s', changeset.id)

            result = []

            # check if changeset response consists of parts, this is important
            # to distinguish cases when server responds with single HTTP response
            # for whole request
            if not isinstance(parts[0], list):
                # raise error (even for successfull status codes) since such changeset response
                # always means something wrong happened on server
                response = ODataHttpResponse.from_string(parts[0])
                raise HttpError('Changeset cannot be processed due to single response received, status code: {}'.format(
                    response.status_code), response)

            for part, req in zip(parts, changeset.requests):
                logging.getLogger(LOGGER_NAME).debug('Changeset handler is processing part %s for request %s', part,
                                                     req)

                if isinstance(req, MultipartRequest):
                    raise PyODataException('Changeset cannot contain nested multipart content')

                # part represents single request, we have to parse
                # content (without checking Content type for binary/http)
                response = ODataHttpResponse.from_string(part[0])

                result.append(req.handler(response))

            return result
예제 #3
0
        def value_get_handler(key, response):
            """Gets property value from HTTP Response"""

            if response.status_code != requests.codes.ok:
                raise HttpError('HTTP GET for $value of Entity {0} failed with status code {1}'
                                .format(key, response.status_code), response)

            return response
예제 #4
0
        def stream_handler(response):
            """Returns $value from HTTP Response"""

            if response.status_code != requests.codes.ok:
                raise HttpError('HTTP GET for $value failed with status code {2}'
                                .format(response.status_code), response)

            return response
예제 #5
0
        def proprty_get_handler(key, proprty, response):
            """Gets property value from HTTP Response"""

            if response.status_code != requests.codes.ok:
                raise HttpError('HTTP GET for Attribute {0} of Entity {1} failed with status code {2}'
                                .format(proprty.name, key, response.status_code), response)

            data = response.json()['d']
            return proprty.typ.traits.from_json(data[proprty.name])
예제 #6
0
    def test_create_http_error(self):
        resp = Mock()
        resp.status_code = 400
        connection = MagicMock()
        connection.client.entity_sets.Repositories.get_entity().execute = Mock(
            side_effect=HttpError('MSG', resp))

        with self.assertRaises(HttpError):
            sap.cli.bsp.create(connection, get_sample_create_args())
예제 #7
0
    def __new__(cls, url, connection, odata_version=ODATA_VERSION_2):
        """Create instance of the OData Client for given URL"""

        logger = logging.getLogger('pyodata.client')

        if odata_version == Client.ODATA_VERSION_2:

            # sanitize url
            url = url.rstrip('/') + '/'

            # download metadata
            logger.info('Fetching metadata')
            resp = connection.get(url + '$metadata')

            logger.debug(
                'Retrieved the response:\n%s\n%s', '\n'.join(
                    (f'H: {key}: {value}'
                     for key, value in resp.headers.items())), resp.content)

            if resp.status_code != 200:
                raise HttpError(
                    'Metadata request failed, status code: {}, body:\n{}'.
                    format(resp.status_code, resp.content), resp)

            mime_type = resp.headers['content-type']
            if not any((typ in ['application/xml', 'text/xml']
                        for typ in mime_type.split(';'))):
                raise HttpError(
                    'Metadata request did not return XML, MIME type: {}, body:\n{}'
                    .format(mime_type, resp.content), resp)

            # create model instance from received metadata
            logger.info('Creating OData Schema (version: %d)', odata_version)
            schema = pyodata.v2.model.schema_from_xml(resp.content)

            # create service instance based on model we have
            logger.info('Creating OData Service (version: %d)', odata_version)
            service = pyodata.v2.service.Service(url, schema, connection)

            return service

        raise PyODataException(
            'No implementation for selected odata version {}'.format(
                odata_version))
예제 #8
0
        def get_entity_handler(parent, nav_property, navigation_entity_set, response):
            """Gets entity from HTTP response"""

            if response.status_code != requests.codes.ok:
                raise HttpError('HTTP GET for Entity {0} failed with status code {1}'
                                .format(self._name, response.status_code), response)

            entity = response.json()['d']

            return NavEntityProxy(parent, nav_property, navigation_entity_set.entity_type, entity)
예제 #9
0
    def test_stat_not_found(self):
        resp = Mock()
        resp.status_code = 404
        connection = MagicMock()
        connection.client.entity_sets.Repositories.get_entity().execute = Mock(
            side_effect=HttpError('MSG', resp))

        result = sap.cli.bsp.stat(connection, get_sample_stat_args())

        self.assertEqual(result, 10)
예제 #10
0
    def test_delete_not_found(self):
        resp = Mock()
        resp.status_code = 404
        connection = MagicMock()
        connection.client.entity_sets.Repositories.delete_entity().custom().execute = Mock(
            side_effect=HttpError('MSG', resp))

        sap.cli.bsp.delete(connection, get_sample_delete_args())

        self.assertEqual(connection.client.entity_sets.Repositories.delete_entity.call_count, 2)
예제 #11
0
        def create_entity_handler(response):
            """Gets newly created entity encoded in HTTP Response"""

            if response.status_code != return_code:
                raise HttpError('HTTP POST for Entity Set {0} failed with status code {1}'
                                .format(self._name, response.status_code), response)

            entity_props = response.json()['d']

            return EntityProxy(self._service, self._entity_set, self._entity_set.entity_type, entity_props)
예제 #12
0
        def get_entity_handler(response):
            """Gets entity from HTTP response"""

            if response.status_code != requests.codes.ok:
                raise HttpError('HTTP GET for Entity {0} failed with status code {1}'
                                .format(self._name, response.status_code), response)

            entity = response.json()['d']

            return EntityProxy(self._service, self._entity_set, self._entity_set.entity_type, entity)
예제 #13
0
    def test_create_ok(self):
        resp = Mock()
        resp.status_code = 404
        connection = MagicMock()
        connection.client.entity_sets.Repositories.get_entity().execute = Mock(
            side_effect=HttpError('MSG', resp))

        sap.cli.bsp.create(connection, get_sample_create_args())

        connection.client.entity_sets.Repositories.create_entity.assert_called_once()
예제 #14
0
def _fetch_metadata(connection, url, logger):
    # download metadata
    logger.info('Fetching metadata')
    resp = connection.get(url + '$metadata')

    logger.debug('Retrieved the response:\n%s\n%s',
                 '\n'.join((f'H: {key}: {value}' for key, value in resp.headers.items())),
                 resp.content)

    if resp.status_code != 200:
        raise HttpError(
            'Metadata request failed, status code: {}, body:\n{}'.format(resp.status_code, resp.content), resp)

    mime_type = resp.headers['content-type']
    if not any((typ in ['application/xml', 'text/xml'] for typ in mime_type.split(';'))):
        raise HttpError(
            'Metadata request did not return XML, MIME type: {}, body:\n{}'.format(mime_type, resp.content),
            resp)

    return resp.content
예제 #15
0
    def test_create_error_creating(self, log_patch):
        resp = Mock()
        resp.status_code = 404
        resp.text = '{"a":"b"}'
        connection = MagicMock()
        connection.client.entity_sets.Repositories.get_entity().execute = Mock(
            side_effect=HttpError('MSG', resp))
        create_request = connection.client.entity_sets.Repositories.create_entity().custom().custom().custom()
        create_request.execute = Mock(side_effect=HttpError('MSG', resp))

        with self.assertRaises(HttpError):
            sap.cli.bsp.create(connection, get_sample_create_args())

        create_request.set.assert_called_once_with(**{
            'Name': 'BSP',
            'Package': 'PKG',
            'ZipArchive': base64.b64encode(b'SOME_DATA').decode('utf8')
        })

        log_patch.return_value.info.assert_called_once_with("{'a': 'b'}")
예제 #16
0
    def http_response_handler(request, response):
        """Process HTTP response to mutipart HTTP request"""

        if response.status_code != 202:  # 202 Accepted
            raise HttpError('HTTP POST for multipart request {0} failed with status code {1}'
                            .format(request.id, response.status_code), response)

        logging.getLogger(LOGGER_NAME).debug('Generic multipart http response request handler called')

        # get list of all parts (headers + body)
        decoded = decode_multipart(response.content.decode('utf-8'), response.headers['Content-Type'])

        return request.handler(request, decoded)
예제 #17
0
        def function_import_handler(fimport, response):
            """Get function call response from HTTP Response"""

            if response.status_code != requests.codes.ok:
                raise HttpError('Function import call failed with status code {0}'.format(response.status_code),
                                response)

            response_data = response.json()['d']

            # 1. if return types is "entity type", return instance of appropriate entity proxy
            if isinstance(fimport.return_type, model.EntityType):
                entity_set = self._service.schema.entity_set(fimport.entity_set_name)
                return EntityProxy(self._service, entity_set, fimport.return_type, response_data)

            # 2. return raw data for all other return types (primitives, complex types encoded in dicts, etc.)
            return response_data
예제 #18
0
        def get_entities_handler(response):
            """Gets entity set from HTTP Response"""

            if response.status_code != requests.codes.ok:
                raise HttpError('HTTP GET for Entity Set {0} failed with status code {1}'
                                .format(self._name, response.status_code), response)

            content = response.json()

            if isinstance(content, int):
                return content

            entities = content['d']['results']

            result = []
            for props in entities:
                entity = EntityProxy(self._service, self._entity_set, self._entity_set.entity_type, props)
                result.append(entity)

            return result
예제 #19
0
def add_btp_token_to_session(session, key, user, password):
    """Using the provided credentials, the function tries to add the
       necessary token for establishing a connection to an OData service
       coming from SAP BTP, ABAP environment.

       If any of the provided credentials are invalid, the server will
       respond with 401, and the function will raise HttpError.
    """
    token_url = key['uaa'][
        'url'] + f'/oauth/token?grant_type=password&username={user}&password={password}'
    token_response = session.post(token_url,
                                  auth=(key['uaa']['clientid'],
                                        key['uaa']['clientsecret']))

    if token_response.status_code != 200:
        raise HttpError(
            f'Token request failed, status code: {token_response.status_code}, body:\n{token_response.content}',
            token_response)

    token_response = json.loads(token_response.text)
    token = token_response['id_token']

    session.headers.update({'Authorization': f'Bearer {token}'})
    return session
예제 #20
0
    def __new__(cls,
                url,
                connection,
                odata_version=ODATA_VERSION_2,
                namespaces=None,
                config: pyodata.v2.model.Config = None):
        """Create instance of the OData Client for given URL"""

        logger = logging.getLogger('pyodata.client')

        if odata_version == Client.ODATA_VERSION_2:

            # sanitize url
            url = url.rstrip('/') + '/'

            # download metadata
            logger.info('Fetching metadata')
            resp = connection.get(url + '$metadata')

            logger.debug(
                'Retrieved the response:\n%s\n%s', '\n'.join(
                    (f'H: {key}: {value}'
                     for key, value in resp.headers.items())), resp.content)

            if resp.status_code != 200:
                raise HttpError(
                    'Metadata request failed, status code: {}, body:\n{}'.
                    format(resp.status_code, resp.content), resp)

            mime_type = resp.headers['content-type']
            if not any((typ in ['application/xml', 'text/xml']
                        for typ in mime_type.split(';'))):
                raise HttpError(
                    'Metadata request did not return XML, MIME type: {}, body:\n{}'
                    .format(mime_type, resp.content), resp)

            if config is not None and namespaces is not None:
                raise PyODataException(
                    'You cannot pass namespaces and config at the same time')

            if config is None:
                config = pyodata.v2.model.Config()

            if namespaces is not None:
                warnings.warn(
                    "Passing namespaces directly is deprecated. Use class Config instead",
                    DeprecationWarning)
                config.namespaces = namespaces

            # create model instance from received metadata
            logger.info('Creating OData Schema (version: %d)', odata_version)
            schema = pyodata.v2.model.MetadataBuilder(resp.content,
                                                      config=config).build()

            # create service instance based on model we have
            logger.info('Creating OData Service (version: %d)', odata_version)
            service = pyodata.v2.service.Service(url, schema, connection)

            return service

        raise PyODataException(
            'No implementation for selected odata version {}'.format(
                odata_version))
예제 #21
0
        def update_entity_handler(response):
            """Gets modified entity encoded in HTTP Response"""

            if response.status_code != 204:
                raise HttpError('HTTP modify request for Entity Set {} failed with status code {}'
                                .format(self._name, response.status_code), response)