Skip to content

Commit f548949

Browse files
authored
Merge pull request #97 from livechat/API-11719_billing_api
Adding Billing API
2 parents 10b021c + 570564a commit f548949

File tree

7 files changed

+500
-0
lines changed

7 files changed

+500
-0
lines changed

changelog.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ All notable changes to this project will be documented in this file.
44
## [0.3.6] - TBA
55

66
### Added
7+
8+
- Added support for billing-api.
79
- New `highest_available` option for `customer_monitoring_level` in agent-api `login` method.
810

911
### Bugfixes

livechat/billing/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# pylint: disable=C0114
2+
from livechat.billing.base import BillingApi

livechat/billing/api/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# pylint: disable=C0114
2+
from .v1 import BillingApiV1

livechat/billing/api/v1.py

Lines changed: 351 additions & 0 deletions
Large diffs are not rendered by default.

livechat/billing/base.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
''' Module with base class that allows retrieval of client for specific
2+
Billing API version. '''
3+
4+
# pylint: disable=W0613,W0622,C0103,R0913,R0903
5+
6+
from __future__ import annotations
7+
8+
from livechat.config import CONFIG
9+
10+
from .api import BillingApiV1
11+
12+
billing_url = CONFIG.get('billing_url')
13+
billing_version = CONFIG.get('billing_version')
14+
15+
16+
class BillingApi:
17+
''' Base class that allows retrieval of client for specific
18+
Billing API version. '''
19+
@staticmethod
20+
def get_client(token: str,
21+
version: str = billing_version,
22+
base_url: str = billing_url,
23+
http2: bool = False,
24+
proxies: dict = None,
25+
verify: bool = True) -> BillingApiV1:
26+
''' Returns client for specific Billing API version.
27+
28+
Args:
29+
token (str): Full token with type Bearer that will be
30+
used as `Authorization` header in requests to API.
31+
version (str): Billing API's version. Defaults to the v1 version of Billing.
32+
base_url (str): API's base url. Defaults to API's production URL.
33+
http2 (bool): A boolean indicating if HTTP/2 support should be
34+
enabled. Defaults to `False`.
35+
proxies (dict): A dictionary mapping proxy keys to proxy URLs.
36+
verify (bool): SSL certificates (a.k.a CA bundle) used to
37+
verify the identity of requested hosts. Either `True` (default CA bundle),
38+
a path to an SSL certificate file, an `ssl.SSLContext`, or `False`
39+
(which will disable verification). Defaults to `True`.
40+
41+
Returns:
42+
BillingApi: API client object for specified version.
43+
44+
Raises:
45+
ValueError: If the specified version does not exist.
46+
'''
47+
client = {
48+
'1': BillingApiV1(token, base_url, http2, proxies, verify),
49+
}.get(version)
50+
if not client:
51+
raise ValueError('Provided version does not exist.')
52+
return client

livechat/config.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
CONFIG = {
44
'url': 'api.livechatinc.com',
5+
'billing_url': 'billing.livechatinc.com',
56
'stable': '3.5',
67
'dev': '3.6',
8+
'billing_version': '1'
79
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
''' Tests for Billing API client. '''
2+
3+
# pylint: disable=E1120,W0621
4+
5+
import pytest
6+
7+
from livechat.billing.base import BillingApi
8+
from livechat.config import CONFIG
9+
10+
billing_url = CONFIG.get('billing_url')
11+
billing_version = CONFIG.get('billing_version')
12+
13+
14+
@pytest.fixture
15+
def billing_api_client():
16+
''' Fixture returning Billing API client. '''
17+
return BillingApi.get_client(token='test')
18+
19+
20+
def test_get_client_without_args():
21+
''' Test if TypeError raised without args. '''
22+
with pytest.raises(TypeError) as exception:
23+
BillingApi.get_client()
24+
assert str(
25+
exception.value
26+
) == "get_client() missing 1 required positional argument: 'token'"
27+
28+
29+
def test_get_client_without_access_token():
30+
''' Test if TypeError raised without access_token. '''
31+
with pytest.raises(TypeError) as exception:
32+
BillingApi.get_client(version='test')
33+
assert str(
34+
exception.value
35+
) == "get_client() missing 1 required positional argument: 'token'"
36+
37+
38+
def test_get_client_with_non_existing_version():
39+
''' Test if ValueError raised for non-existing version. '''
40+
with pytest.raises(ValueError) as exception:
41+
BillingApi.get_client(token='test', version='test')
42+
assert str(exception.value) == 'Provided version does not exist.'
43+
44+
45+
def test_get_client_with_valid_args(billing_api_client):
46+
''' Test if production API URL is used and token is added to headers for valid args. '''
47+
assert billing_api_client.api_url == f'https://{billing_url}/v{billing_version}'
48+
assert billing_api_client.session.headers.get('Authorization') == 'test'
49+
50+
51+
def test_send_request(billing_api_client):
52+
''' Test if it's possible to send a basic request via Billing API
53+
client with arbitrary chosen method. '''
54+
assert billing_api_client.create_direct_charge().json() == {
55+
'error':
56+
'invalid_request',
57+
'error_description':
58+
'The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed.'
59+
}
60+
61+
62+
def test_modify_header(billing_api_client):
63+
''' Test if Billing API object header can be updated with custom value. '''
64+
assert 'test' not in billing_api_client.get_headers()
65+
billing_api_client.modify_header({'test': '1234'})
66+
assert 'test' in billing_api_client.get_headers()
67+
68+
69+
def test_remove_header(billing_api_client):
70+
''' Test if header can be removed from Billing API object. '''
71+
billing_api_client.modify_header({'test2': '1234'})
72+
assert 'test2' in billing_api_client.get_headers()
73+
billing_api_client.remove_header('test2')
74+
assert 'test2' not in billing_api_client.get_headers()
75+
76+
77+
def test_custom_headers_within_the_request(billing_api_client):
78+
''' Test if custom headers can be added to the session headers
79+
only within the particular request. '''
80+
headers = {'x-test': 'enabled'}
81+
response = billing_api_client.create_direct_charge(headers=headers)
82+
assert headers.items() <= response.request.headers.items()
83+
assert 'x-test' not in billing_api_client.get_headers()
84+
85+
86+
def test_client_supports_http_1():
87+
''' Test if client supports HTTP/1.1 protocol. '''
88+
client = BillingApi.get_client(token='test')
89+
assert client.create_direct_charge().http_version == 'HTTP/1.1'

0 commit comments

Comments
 (0)