Esempio n. 1
0
 def setUp(self):
     self.merchant_id = 'merchant_id'
     self.secret_key = 'secret_key'
     self.client = BokuClient(self.merchant_id, self.secret_key)
     self.patched_get = mock.patch('requests.get')
     self.mock_get = self.patched_get.start()
     self.addCleanup(self.patched_get.stop)
Esempio n. 2
0
 def setUp(self):
     self.merchant_id = 'merchant_id'
     self.secret_key = 'secret_key'
     self.client = BokuClient(self.merchant_id, self.secret_key)
     self.patched_get = mock.patch('requests.get')
     self.mock_get = self.patched_get.start()
     self.addCleanup(self.patched_get.stop)
Esempio n. 3
0
class BokuClientTests(test_utils.TestCase):
    def setUp(self):
        self.merchant_id = 'merchant_id'
        self.secret_key = 'secret_key'
        self.client = BokuClient(self.merchant_id, self.secret_key)
        self.patched_get = mock.patch('requests.get')
        self.mock_get = self.patched_get.start()
        self.addCleanup(self.patched_get.stop)

    def start_transaction(self,
                          service_id='service id',
                          consumer_id='consumer',
                          price_row=1,
                          external_id='external id',
                          callback_url='http://test/',
                          forward_url='http://test/success',
                          country='MX'):
        return self.client.start_transaction(service_id=service_id,
                                             consumer_id=consumer_id,
                                             price_row=price_row,
                                             external_id=external_id,
                                             callback_url=callback_url,
                                             forward_url=forward_url,
                                             country=country)

    def test_client_uses_signed_request(self):
        params = {
            'merchant-id': self.merchant_id,
            'param': 'value',
            'timestamp': int(time.time()),
        }
        signature = get_boku_request_signature(self.secret_key, params)

        try:
            self.client.api_call('/path', params)
        except:
            pass

        call_url = self.mock_get.call_args[0][0]
        sig_param = 'sig={signature}'.format(signature=signature)
        ok_(sig_param in call_url)

    def test_client_raises_exception_on_non_200_http_response(self):
        response = mock.Mock()
        response.status_code = 400
        self.mock_get.return_value = response

        with assert_raises(BokuException) as context:
            self.client.api_call('/path', {})

        eq_(context.exception.message, 'Request Failed: 400')

    def test_client_raises_exception_on_invalid_xml(self):
        response = mock.Mock()
        response.status_code = 200
        response.content = '<invalid xml'
        self.mock_get.return_value = response

        with assert_raises(BokuException) as context:
            self.client.api_call('/path', {})

        ok_(
            'XML Parse Error' in context.exception.message,
            'XML Parse Error not found in {message}'.format(
                message=context.exception.message))

    def test_client_raises_exception_when_response_code_not_present(self):
        response = mock.Mock()
        response.status_code = 200
        response.content = sample_xml.empty
        self.mock_get.return_value = response

        with assert_raises(BokuException) as context:
            self.client.api_call('/path', {})

        eq_(context.exception.message,
            'Unable to determine API call result code')

    def test_client_raises_exception_on_non_zero_response_code(self):
        result_code = 1
        result_message = 'Failure!'

        response = mock.Mock()
        response.status_code = 200
        response.content = sample_xml.billing_request.format(
            result_code=result_code, result_message=result_message)
        self.mock_get.return_value = response

        with assert_raises(BokuException) as context:
            self.client.api_call('/path', {})

        eq_(
            context.exception.message,
            'API Error: {result_code} {result_message}'.format(
                result_code=result_code, result_message=result_message))
        eq_(context.exception.result_code, result_code)
        eq_(context.exception.result_msg, result_message)

    def test_client_get_pricing_calls_api_with_correct_params(self):
        country = 'CA'

        with mock.patch('lib.boku.client.BokuClient.api_call') as mock_client:
            try:
                self.client.get_pricing(country)
            except BokuException:
                pass

            mock_client.assert_called_with('/billing/request', {
                'action': 'price',
                'country': country,
            })

    def test_client_get_pricing_calls_returns_pricing_json(self):
        response = mock.Mock()
        response.status_code = 200
        response.content = sample_xml.pricing_request
        self.mock_get.return_value = response

        prices = self.client.get_pricing('CA', currency='CDN')
        eq_(prices, [{
            'status': '1',
            'receivable-gross': '465',
            'currency-decimal-places': '2',
            'reference-amount': '115',
            'exchange': '13.01193',
            'currency-symbol-orientation': 'l',
            'country': 'CA',
            'display-price': '$15.00',
            'reference-receivable-gross': '36',
            'reference-receivable-net': '32',
            'price-ex-salestax': '1293',
            'currency': 'CDN',
            'amount': '1500',
            'reference-price-inc-salestax': '115',
            'currency-symbol': '$',
            'price-inc-salestax': '1500',
            'reference-price-ex-salestax': '99',
            'receivable-net': '419',
            'number-billed-messages': '1'
        }])

    def test_client_start_transaction_calls_api_with_correct_params(self):
        service_id = 'service id'
        consumer_id = 'consumer'
        price_row = 1
        external_id = 'external id'
        callback_url = 'http://test/'
        forward_url = 'http://test/success'
        country = 'MX'

        with mock.patch('lib.boku.client.BokuClient.api_call') as mock_client:
            try:
                self.start_transaction(
                    callback_url=callback_url,
                    forward_url=forward_url,
                    consumer_id=consumer_id,
                    external_id=external_id,
                    price_row=price_row,
                    service_id=service_id,
                    country=country,
                )
            except BokuException:
                pass

            mock_client.assert_called_with(
                '/billing/request', {
                    'action': 'prepare',
                    'callback-url': callback_url,
                    'fwdurl': forward_url,
                    'consumer-id': consumer_id,
                    'param': external_id,
                    'row-ref': price_row,
                    'service-id': service_id,
                    'country': country,
                })

    def test_client_start_transaction_returns_start_transaction_json(self):
        transaction_id = 'abc123'
        response = mock.Mock()
        response.status_code = 200
        response.content = sample_xml.prepare_request.format(
            transaction_id=transaction_id)
        self.mock_get.return_value = response

        transaction = self.start_transaction()
        eq_(
            transaction, {
                'buy_url': 'http://example_buy_url/',
                'transaction_id': transaction_id,
            })

    def test_client_check_transaction_calls_api_with_correct_params(self):
        transaction_id = 'abc123'

        with mock.patch('lib.boku.client.BokuClient.api_call') as mock_client:
            try:
                self.client.check_transaction(transaction_id)
            except Exception:
                pass

            mock_client.assert_called_with('/billing/request', {
                'action': 'verify-trx-id',
                'trx-id': transaction_id,
            })

    def test_client_check_transaction_returns_check_transaction_json(self):
        transaction_id = 'abc123'
        amount = 100

        response = mock.Mock()
        response.status_code = 200
        response.content = sample_xml.transaction_request.format(
            transaction_id=transaction_id)
        self.mock_get.return_value = response

        transaction = self.client.check_transaction(transaction_id)
        eq_(transaction, {'amount': amount, 'paid': amount})
Esempio n. 4
0
class BokuClientTests(test_utils.TestCase):

    def setUp(self):
        self.merchant_id = 'merchant_id'
        self.secret_key = 'secret_key'
        self.client = BokuClient(self.merchant_id, self.secret_key)
        self.patched_get = mock.patch('requests.get')
        self.mock_get = self.patched_get.start()
        self.addCleanup(self.patched_get.stop)

    def test_client_uses_signed_request(self):
        params = {
            'merchant-id': self.merchant_id,
            'param': 'value',
            'timestamp': int(time.time()),
        }
        signature = get_boku_request_signature(self.secret_key, params)

        try:
            self.client.api_call('/path', params)
        except:
            pass

        call_url = self.mock_get.call_args[0][0]
        sig_param = 'sig={signature}'.format(signature=signature)
        ok_(sig_param in call_url)

    def test_client_raises_exception_on_non_200_http_response(self):
        response = mock.Mock()
        response.status_code = 400
        self.mock_get.return_value = response

        with assert_raises(BokuException) as context:
            self.client.api_call('/path', {})

        eq_(context.exception.message, 'Request Failed: 400')

    def test_client_raises_exception_on_invalid_xml(self):
        response = mock.Mock()
        response.status_code = 200
        response.content = '<invalid xml'
        self.mock_get.return_value = response

        with assert_raises(BokuException) as context:
            self.client.api_call('/path', {})

        ok_(
            'XML Parse Error' in context.exception.message,
            'XML Parse Error not found in {message}'.format(
                message=context.exception.message
            )
        )

    def test_client_raises_exception_when_response_code_not_present(self):
        response = mock.Mock()
        response.status_code = 200
        response.content = sample_xml.empty
        self.mock_get.return_value = response

        with assert_raises(BokuException) as context:
            self.client.api_call('/path', {})

        eq_(
            context.exception.message,
            'Unable to determine API call result code'
        )

    def test_client_raises_exception_on_non_zero_response_code(self):
        result_code = 1
        result_message = 'Failure!'

        response = mock.Mock()
        response.status_code = 200
        response.content = sample_xml.billing_request.format(
            result_code=result_code,
            result_message=result_message
        )
        self.mock_get.return_value = response

        with assert_raises(BokuException) as context:
            self.client.api_call('/path', {})

        eq_(
            context.exception.message,
            'API Error: {result_code} {result_message}'.format(
                result_code=result_code,
                result_message=result_message
            )
        )
        eq_(context.exception.result_code, result_code)
        eq_(context.exception.result_msg, result_message)

    def test_client_get_pricing_calls_api_with_correct_params(self):
        country = 'CA'

        with mock.patch('lib.boku.client.BokuClient.api_call') as MockClient:
            try:
                self.client.get_pricing(country)
            except BokuException:
                pass

            MockClient.assert_called_with('/billing/request', {
                'action': 'price',
                'country': country,
            })

    def test_client_get_pricing_calls_returns_pricing_json(self):
        response = mock.Mock()
        response.status_code = 200
        response.content = sample_xml.pricing_request
        self.mock_get.return_value = response

        prices = self.client.get_pricing('CA', currency='CDN')
        eq_(
            prices, [{
                'status': '1',
                'receivable-gross': '465',
                'currency-decimal-places': '2',
                'reference-amount': '115',
                'exchange': '13.01193',
                'currency-symbol-orientation': 'l',
                'country': 'CA',
                'display-price': '$15.00',
                'reference-receivable-gross': '36',
                'reference-receivable-net': '32',
                'price-ex-salestax': '1293',
                'currency': 'CDN',
                'amount': '1500',
                'reference-price-inc-salestax': '115',
                'currency-symbol': '$',
                'price-inc-salestax': '1500',
                'reference-price-ex-salestax': '99',
                'receivable-net': '419',
                'number-billed-messages': '1'
            }]
        )

    def test_client_start_transaction_calls_api_with_correct_params(self):
        service_id = 'service id'
        consumer_id = 'consumer'
        price_row = 1
        external_id = 'external id'
        callback_url = 'http://test/'

        with mock.patch('lib.boku.client.BokuClient.api_call') as MockClient:
            try:
                self.client.start_transaction(
                    callback_url=callback_url,
                    consumer_id=consumer_id,
                    external_id=external_id,
                    price_row=price_row,
                    service_id=service_id,
                )
            except BokuException:
                pass

            MockClient.assert_called_with('/billing/request', {
                'action': 'prepare',
                'callback-url': callback_url,
                'consumer-id': consumer_id,
                'param': external_id,
                'row-ref': price_row,
                'service-id': service_id,
            })

    def test_client_start_transaction_returns_start_transaction_json(self):
        service_id = 'service id'
        consumer_id = 'consumer'
        price_row = 1
        external_id = 'external id'
        callback_url = 'http://test/'
        transaction_id = 'abc123'

        response = mock.Mock()
        response.status_code = 200
        response.content = sample_xml.prepare_request.format(
            transaction_id=transaction_id
        )
        self.mock_get.return_value = response

        transaction = self.client.start_transaction(
            callback_url=callback_url,
            consumer_id=consumer_id,
            external_id=external_id,
            price_row=price_row,
            service_id=service_id,
        )
        eq_(
            transaction, {
                'buy_url': 'http://example_buy_url/',
                'transaction_id': transaction_id,
            }
        )

    def test_client_check_transaction_calls_api_with_correct_params(self):
        transaction_id = 'abc123'

        with mock.patch('lib.boku.client.BokuClient.api_call') as MockClient:
            try:
                self.client.check_transaction(transaction_id)
            except Exception:
                pass

            MockClient.assert_called_with('/billing/request', {
                'action': 'verify-trx-id',
                'trx-id': transaction_id,
            })

    def test_client_check_transaction_returns_check_transaction_json(self):
        transaction_id = 'abc123'
        amount = 100

        response = mock.Mock()
        response.status_code = 200
        response.content = sample_xml.transaction_request.format(
            transaction_id=transaction_id
        )
        self.mock_get.return_value = response

        transaction = self.client.check_transaction(transaction_id)
        eq_(transaction, {'amount': amount, 'paid': amount})
Esempio n. 5
0
class BokuClientTests(test.TestCase):

    def setUp(self):
        self.merchant_id = 'merchant_id'
        self.secret_key = 'secret_key'
        self.client = BokuClient(self.merchant_id, self.secret_key)
        self.patched_get = mock.patch('requests.get')
        self.mock_get = self.patched_get.start()
        self.addCleanup(self.patched_get.stop)

    def start_transaction(self, service_id='service id',
                          consumer_id='consumer', price=Decimal('15.00'),
                          external_id='external id', currency='MXN',
                          callback_url='http://test/',
                          forward_url='http://test/success',
                          product_name='Django Pony',
                          country='MX'):
        return self.client.start_transaction(service_id=service_id,
                                             consumer_id=consumer_id,
                                             price=price,
                                             currency=currency,
                                             external_id=external_id,
                                             callback_url=callback_url,
                                             forward_url=forward_url,
                                             product_name=product_name,
                                             country=country)

    def test_doesnt_add_timestamp(self):
        response = mock.Mock()
        response.content = ''
        response.status_code = 204
        self.mock_get.return_value = response

        self.client.api_call('/path', {})
        assert 'timestamp' in self.mock_get.call_args[0][0]

        self.client.api_call('/path', {}, add_timestamp=False)
        assert 'timestamp' not in self.mock_get.call_args[0][0]

    def test_doesnt_parse_204(self):
        response = mock.Mock()
        response.content = ''
        response.status_code = 204
        self.mock_get.return_value = response

        # If the 204 check wasn't there to return None, this would fail.
        assert not self.client.api_call('/path', {})

    @raises(AssertionError)
    def test_204_with_body_error(self):
        response = mock.Mock()
        response.content = 'wat'
        response.status_code = 204
        self.mock_get.return_value = response

        self.client.api_call('/path', {})

    def test_client_uses_signed_request(self):
        params = {
            'merchant-id': self.merchant_id,
            'param': 'value',
            'timestamp': int(time.time()),
        }
        signature = get_boku_request_signature(self.secret_key, params)

        try:
            self.client.api_call('/path', params)
        except:
            pass

        call_url = self.mock_get.call_args[0][0]
        sig_param = 'sig={signature}'.format(signature=signature)
        ok_(sig_param in call_url)

    def test_client_raises_exception_on_non_200_http_response(self):
        response = mock.Mock()
        response.status_code = 400
        self.mock_get.return_value = response

        with assert_raises(BokuException) as context:
            self.client.api_call('/path', {})

        eq_(context.exception.message, 'Request Failed: 400')

    def test_client_raises_exception_on_invalid_xml(self):
        response = mock.Mock()
        response.status_code = 200
        response.content = '<invalid xml'
        self.mock_get.return_value = response

        with assert_raises(BokuException) as context:
            self.client.api_call('/path', {})

        ok_(
            'XML Parse Error' in context.exception.message,
            'XML Parse Error not found in {message}'.format(
                message=context.exception.message
            )
        )

    def test_client_raises_exception_when_response_code_not_present(self):
        response = mock.Mock()
        response.status_code = 200
        response.content = sample_xml.empty
        self.mock_get.return_value = response

        with assert_raises(BokuException) as context:
            self.client.api_call('/path', {})

        eq_(
            context.exception.message,
            'Unable to determine API call result code'
        )

    def test_client_raises_exception_on_non_zero_response_code(self):
        result_code = 1
        result_message = 'Failure!'

        response = mock.Mock()
        response.status_code = 200
        response.content = sample_xml.billing_request.format(
            result_code=result_code,
            result_message=result_message
        )
        self.mock_get.return_value = response

        with assert_raises(BokuException) as context:
            self.client.api_call('/path', {})

        eq_(
            context.exception.message,
            'API Error: {result_code} {result_message}'.format(
                result_code=result_code,
                result_message=result_message
            )
        )
        eq_(context.exception.result_code, result_code)
        eq_(context.exception.result_msg, result_message)

    def test_client_get_pricing_calls_api_with_correct_params(self):
        country = 'CA'

        with mock.patch('lib.boku.client.BokuClient.api_call') as mock_client:
            try:
                self.client.get_pricing(country)
            except BokuException:
                pass

            mock_client.assert_called_with('/billing/request', {
                'action': 'price',
                'country': country,
            })

    def test_client_get_pricing_calls_returns_pricing_json(self):
        response = mock.Mock()
        response.status_code = 200
        response.content = sample_xml.pricing_request
        self.mock_get.return_value = response

        prices = self.client.get_pricing('CA', currency='CDN')
        eq_(
            prices, [{
                'status': '1',
                'receivable-gross': '465',
                'currency-decimal-places': '2',
                'reference-amount': '115',
                'exchange': '13.01193',
                'currency-symbol-orientation': 'l',
                'country': 'CA',
                'display-price': '$15.00',
                'reference-receivable-gross': '36',
                'reference-receivable-net': '32',
                'price-ex-salestax': '1293',
                'currency': 'CDN',
                'amount': '1500',
                'reference-price-inc-salestax': '115',
                'currency-symbol': '$',
                'price-inc-salestax': '1500',
                'reference-price-ex-salestax': '99',
                'receivable-net': '419',
                'number-billed-messages': '1'
            }]
        )

    def test_client_get_price_rows_returns_row_ref(self):
        response = mock.Mock()
        response.status_code = 200
        response.content = sample_xml.pricing_request
        self.mock_get.return_value = response

        price_rows = self.client.get_price_rows('CA')
        eq_(price_rows[Decimal('15.00')], 0)

    def test_client_start_transaction_calls_api_with_correct_params(self):
        service_id = 'service id'
        consumer_id = 'consumer'
        currency = 'MXN'
        price = Decimal('15.00')
        external_id = 'external id'
        callback_url = 'http://test/'
        forward_url = 'http://test/success'
        product_name = 'Unicorn Dust'
        country = 'MX'

        with mock.patch('lib.boku.client.BokuClient.api_call') as mock_client:
            try:
                self.start_transaction(
                    callback_url=callback_url,
                    forward_url=forward_url,
                    consumer_id=consumer_id,
                    external_id=external_id,
                    currency=currency,
                    price=price,
                    product_name=product_name,
                    service_id=service_id,
                    country=country,
                )
            except BokuException:
                pass

            mock_client.assert_called_with('/billing/request', {
                'action': 'prepare',
                'callback-url': callback_url,
                'fwdurl': forward_url,
                'consumer-id': consumer_id,
                'param': external_id,
                'desc': product_name,
                'sub-merchant-name': 'Marketplace',
                'price-inc-salestax': 1500,
                'currency': currency,
                'service-id': service_id,
                'country': country,
            })

    def test_long_product_names(self):
        product_name = u'Unicorn Dust From A Majestic \u2603'

        with mock.patch('lib.boku.client.BokuClient.api_call') as mock_client:
            self.start_transaction(product_name=product_name)
            # The name is not truncated by us but we issue some log warnings.
            # This covers some code to make sure there are no exceptions.
            eq_(mock_client.call_args[0][1]['desc'], 'Unicorn Dust From A ')

    def test_non_ascii_names(self):
        product_name = u'Ivan Krsti\u0107'

        with mock.patch('lib.boku.client.BokuClient.api_call') as mock_client:
            self.start_transaction(product_name=product_name)
            eq_(mock_client.call_args[0][1]['desc'], product_name)

    def test_client_start_transaction_returns_start_transaction_json(self):
        transaction_id = 'abc123'
        response = mock.Mock()
        response.status_code = 200
        response.content = sample_xml.prepare_request.format(
            transaction_id=transaction_id
        )
        self.mock_get.return_value = response

        transaction = self.start_transaction()
        eq_(
            transaction, {
                'buy_url': 'http://example_buy_url/',
                'transaction_id': transaction_id,
            }
        )

    def test_client_check_transaction_calls_api_with_correct_params(self):
        transaction_id = 'abc123'

        with mock.patch('lib.boku.client.BokuClient.api_call') as mock_client:
            try:
                self.client.check_transaction(transaction_id)
            except Exception:
                pass

            mock_client.assert_called_with('/billing/request', {
                'action': 'verify-trx-id',
                'trx-id': transaction_id,
            })

    def test_client_check_transaction_returns_check_transaction_json(self):
        transaction_id = 'abc123'
        amount = 100

        response = mock.Mock()
        response.status_code = 200
        response.content = sample_xml.transaction_request.format(
            transaction_id=transaction_id
        )
        self.mock_get.return_value = response

        transaction = self.client.check_transaction(transaction_id)
        eq_(transaction, {'amount': amount, 'paid': amount})