Skip to content

Commit 2f89b8a

Browse files
committed
Added async api classes and telemetry api tests
1 parent efdc027 commit 2f89b8a

File tree

11 files changed

+906
-87
lines changed

11 files changed

+906
-87
lines changed

splitio/api/auth.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,49 @@ def authenticate(self):
5656
_LOGGER.error('Exception raised while authenticating')
5757
_LOGGER.debug('Exception information: ', exc_info=True)
5858
raise APIException('Could not perform authentication.') from exc
59+
60+
class AuthAPIAsync(object): # pylint: disable=too-few-public-methods
61+
"""Async Class that uses an httpClient to communicate with the SDK Auth Service API."""
62+
63+
def __init__(self, client, sdk_key, sdk_metadata, telemetry_runtime_producer):
64+
"""
65+
Class constructor.
66+
67+
:param client: HTTP Client responsble for issuing calls to the backend.
68+
:type client: HttpClient
69+
:param sdk_key: User sdk key.
70+
:type sdk_key: string
71+
:param sdk_metadata: SDK version & machine name & IP.
72+
:type sdk_metadata: splitio.client.util.SdkMetadata
73+
"""
74+
self._client = client
75+
self._sdk_key = sdk_key
76+
self._metadata = headers_from_metadata(sdk_metadata)
77+
self._telemetry_runtime_producer = telemetry_runtime_producer
78+
self._client.set_telemetry_data(HTTPExceptionsAndLatencies.TOKEN, self._telemetry_runtime_producer)
79+
80+
async def authenticate(self):
81+
"""
82+
Perform authentication.
83+
84+
:return: Json representation of an authentication.
85+
:rtype: splitio.models.token.Token
86+
"""
87+
try:
88+
response = await self._client.get(
89+
'auth',
90+
'v2/auth',
91+
self._sdk_key,
92+
extra_headers=self._metadata,
93+
)
94+
if 200 <= response.status_code < 300:
95+
payload = json.loads(response.body)
96+
return from_raw(payload)
97+
else:
98+
if (response.status_code >= 400 and response.status_code < 500):
99+
await self._telemetry_runtime_producer.record_auth_rejections()
100+
raise APIException(response.body, response.status_code, response.headers)
101+
except HttpClientException as exc:
102+
_LOGGER.error('Exception raised while authenticating')
103+
_LOGGER.debug('Exception information: ', exc_info=True)
104+
raise APIException('Could not perform authentication.') from exc

splitio/api/events.py

Lines changed: 69 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,25 +10,8 @@
1010
_LOGGER = logging.getLogger(__name__)
1111

1212

13-
class EventsAPI(object): # pylint: disable=too-few-public-methods
14-
"""Class that uses an httpClient to communicate with the events API."""
15-
16-
def __init__(self, http_client, sdk_key, sdk_metadata, telemetry_runtime_producer):
17-
"""
18-
Class constructor.
19-
20-
:param http_client: HTTP Client responsble for issuing calls to the backend.
21-
:type http_client: HttpClient
22-
:param sdk_key: sdk key.
23-
:type sdk_key: string
24-
:param sdk_metadata: SDK version & machine name & IP.
25-
:type sdk_metadata: splitio.client.util.SdkMetadata
26-
"""
27-
self._client = http_client
28-
self._sdk_key = sdk_key
29-
self._metadata = headers_from_metadata(sdk_metadata)
30-
self._telemetry_runtime_producer = telemetry_runtime_producer
31-
self._client.set_telemetry_data(HTTPExceptionsAndLatencies.EVENT, self._telemetry_runtime_producer)
13+
class EventsAPIBase(object): # pylint: disable=too-few-public-methods
14+
"""Base Class that uses an httpClient to communicate with the events API."""
3215

3316
@staticmethod
3417
def _build_bulk(events):
@@ -53,6 +36,27 @@ def _build_bulk(events):
5336
for event in events
5437
]
5538

39+
40+
class EventsAPI(EventsAPIBase): # pylint: disable=too-few-public-methods
41+
"""Class that uses an httpClient to communicate with the events API."""
42+
43+
def __init__(self, http_client, sdk_key, sdk_metadata, telemetry_runtime_producer):
44+
"""
45+
Class constructor.
46+
47+
:param http_client: HTTP Client responsble for issuing calls to the backend.
48+
:type http_client: HttpClient
49+
:param sdk_key: sdk key.
50+
:type sdk_key: string
51+
:param sdk_metadata: SDK version & machine name & IP.
52+
:type sdk_metadata: splitio.client.util.SdkMetadata
53+
"""
54+
self._client = http_client
55+
self._sdk_key = sdk_key
56+
self._metadata = headers_from_metadata(sdk_metadata)
57+
self._telemetry_runtime_producer = telemetry_runtime_producer
58+
self._client.set_telemetry_data(HTTPExceptionsAndLatencies.EVENT, self._telemetry_runtime_producer)
59+
5660
def flush_events(self, events):
5761
"""
5862
Send events to the backend.
@@ -78,3 +82,49 @@ def flush_events(self, events):
7882
_LOGGER.error('Error posting events because an exception was raised by the HTTPClient')
7983
_LOGGER.debug('Error: ', exc_info=True)
8084
raise APIException('Events not flushed properly.') from exc
85+
86+
class EventsAPIAsync(EventsAPIBase): # pylint: disable=too-few-public-methods
87+
"""Async Class that uses an httpClient to communicate with the events API."""
88+
89+
def __init__(self, http_client, sdk_key, sdk_metadata, telemetry_runtime_producer):
90+
"""
91+
Class constructor.
92+
93+
:param http_client: HTTP Client responsble for issuing calls to the backend.
94+
:type http_client: HttpClient
95+
:param sdk_key: sdk key.
96+
:type sdk_key: string
97+
:param sdk_metadata: SDK version & machine name & IP.
98+
:type sdk_metadata: splitio.client.util.SdkMetadata
99+
"""
100+
self._client = http_client
101+
self._sdk_key = sdk_key
102+
self._metadata = headers_from_metadata(sdk_metadata)
103+
self._telemetry_runtime_producer = telemetry_runtime_producer
104+
self._client.set_telemetry_data(HTTPExceptionsAndLatencies.EVENT, self._telemetry_runtime_producer)
105+
106+
async def flush_events(self, events):
107+
"""
108+
Send events to the backend.
109+
110+
:param events: Events bulk
111+
:type events: list
112+
113+
:return: True if flush was successful. False otherwise
114+
:rtype: bool
115+
"""
116+
bulk = self._build_bulk(events)
117+
try:
118+
response = await self._client.post(
119+
'events',
120+
'events/bulk',
121+
self._sdk_key,
122+
body=bulk,
123+
extra_headers=self._metadata,
124+
)
125+
if not 200 <= response.status_code < 300:
126+
raise APIException(response.body, response.status_code)
127+
except HttpClientException as exc:
128+
_LOGGER.error('Error posting events because an exception was raised by the HTTPClient')
129+
_LOGGER.debug('Error: ', exc_info=True)
130+
raise APIException('Events not flushed properly.') from exc

splitio/api/impressions.py

Lines changed: 93 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,23 +12,8 @@
1212
_LOGGER = logging.getLogger(__name__)
1313

1414

15-
class ImpressionsAPI(object): # pylint: disable=too-few-public-methods
16-
"""Class that uses an httpClient to communicate with the impressions API."""
17-
18-
def __init__(self, client, sdk_key, sdk_metadata, telemetry_runtime_producer, mode=ImpressionsMode.OPTIMIZED):
19-
"""
20-
Class constructor.
21-
22-
:param client: HTTP Client responsble for issuing calls to the backend.
23-
:type client: HttpClient
24-
:param sdk_key: sdk key.
25-
:type sdk_key: string
26-
"""
27-
self._client = client
28-
self._sdk_key = sdk_key
29-
self._metadata = headers_from_metadata(sdk_metadata)
30-
self._metadata['SplitSDKImpressionsMode'] = mode.name
31-
self._telemetry_runtime_producer = telemetry_runtime_producer
15+
class ImpressionsAPIBase(object): # pylint: disable=too-few-public-methods
16+
"""Base Class that uses an httpClient to communicate with the impressions API."""
3217

3318
@staticmethod
3419
def _build_bulk(impressions):
@@ -84,6 +69,25 @@ def _build_counters(counters):
8469
]
8570
}
8671

72+
73+
class ImpressionsAPI(ImpressionsAPIBase): # pylint: disable=too-few-public-methods
74+
"""Class that uses an httpClient to communicate with the impressions API."""
75+
76+
def __init__(self, client, sdk_key, sdk_metadata, telemetry_runtime_producer, mode=ImpressionsMode.OPTIMIZED):
77+
"""
78+
Class constructor.
79+
80+
:param client: HTTP Client responsble for issuing calls to the backend.
81+
:type client: HttpClient
82+
:param sdk_key: sdk key.
83+
:type sdk_key: string
84+
"""
85+
self._client = client
86+
self._sdk_key = sdk_key
87+
self._metadata = headers_from_metadata(sdk_metadata)
88+
self._metadata['SplitSDKImpressionsMode'] = mode.name
89+
self._telemetry_runtime_producer = telemetry_runtime_producer
90+
8791
def flush_impressions(self, impressions):
8892
"""
8993
Send impressions to the backend.
@@ -136,3 +140,75 @@ def flush_counters(self, counters):
136140
)
137141
_LOGGER.debug('Error: ', exc_info=True)
138142
raise APIException('Impressions not flushed properly.') from exc
143+
144+
145+
class ImpressionsAPIAsync(ImpressionsAPIBase): # pylint: disable=too-few-public-methods
146+
"""Async Class that uses an httpClient to communicate with the impressions API."""
147+
148+
def __init__(self, client, sdk_key, sdk_metadata, telemetry_runtime_producer, mode=ImpressionsMode.OPTIMIZED):
149+
"""
150+
Class constructor.
151+
152+
:param client: HTTP Client responsble for issuing calls to the backend.
153+
:type client: HttpClient
154+
:param sdk_key: sdk key.
155+
:type sdk_key: string
156+
"""
157+
self._client = client
158+
self._sdk_key = sdk_key
159+
self._metadata = headers_from_metadata(sdk_metadata)
160+
self._metadata['SplitSDKImpressionsMode'] = mode.name
161+
self._telemetry_runtime_producer = telemetry_runtime_producer
162+
163+
async def flush_impressions(self, impressions):
164+
"""
165+
Send impressions to the backend.
166+
167+
:param impressions: Impressions bulk
168+
:type impressions: list
169+
"""
170+
bulk = self._build_bulk(impressions)
171+
self._client.set_telemetry_data(HTTPExceptionsAndLatencies.IMPRESSION, self._telemetry_runtime_producer)
172+
try:
173+
response = await self._client.post(
174+
'events',
175+
'testImpressions/bulk',
176+
self._sdk_key,
177+
body=bulk,
178+
extra_headers=self._metadata,
179+
)
180+
if not 200 <= response.status_code < 300:
181+
raise APIException(response.body, response.status_code)
182+
except HttpClientException as exc:
183+
_LOGGER.error(
184+
'Error posting impressions because an exception was raised by the HTTPClient'
185+
)
186+
_LOGGER.debug('Error: ', exc_info=True)
187+
raise APIException('Impressions not flushed properly.') from exc
188+
189+
async def flush_counters(self, counters):
190+
"""
191+
Send impressions to the backend.
192+
193+
:param impressions: Impressions bulk
194+
:type impressions: list
195+
"""
196+
bulk = self._build_counters(counters)
197+
self._client.set_telemetry_data(HTTPExceptionsAndLatencies.IMPRESSION_COUNT, self._telemetry_runtime_producer)
198+
try:
199+
response = await self._client.post(
200+
'events',
201+
'testImpressions/count',
202+
self._sdk_key,
203+
body=bulk,
204+
extra_headers=self._metadata,
205+
)
206+
if not 200 <= response.status_code < 300:
207+
raise APIException(response.body, response.status_code)
208+
except HttpClientException as exc:
209+
_LOGGER.error(
210+
'Error posting impressions counters because an exception was raised by the '
211+
'HTTPClient'
212+
)
213+
_LOGGER.debug('Error: ', exc_info=True)
214+
raise APIException('Impressions not flushed properly.') from exc

splitio/api/segments.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,61 @@ def fetch_segment(self, segment_name, change_number, fetch_options):
6969
)
7070
_LOGGER.debug('Error: ', exc_info=True)
7171
raise APIException('Segments not fetched properly.') from exc
72+
73+
74+
class SegmentsAPIAsync(object): # pylint: disable=too-few-public-methods
75+
"""Async Class that uses an httpClient to communicate with the segments API."""
76+
77+
def __init__(self, http_client, sdk_key, sdk_metadata, telemetry_runtime_producer):
78+
"""
79+
Class constructor.
80+
81+
:param client: HTTP Client responsble for issuing calls to the backend.
82+
:type client: client.HttpClient
83+
:param sdk_key: User sdk_key token.
84+
:type sdk_key: string
85+
:param sdk_metadata: SDK version & machine name & IP.
86+
:type sdk_metadata: splitio.client.util.SdkMetadata
87+
88+
"""
89+
self._client = http_client
90+
self._sdk_key = sdk_key
91+
self._metadata = headers_from_metadata(sdk_metadata)
92+
self._telemetry_runtime_producer = telemetry_runtime_producer
93+
self._client.set_telemetry_data(HTTPExceptionsAndLatencies.SEGMENT, self._telemetry_runtime_producer)
94+
95+
async def fetch_segment(self, segment_name, change_number, fetch_options):
96+
"""
97+
Fetch splits from backend.
98+
99+
:param segment_name: Name of the segment to fetch changes for.
100+
:type segment_name: str
101+
102+
:param change_number: Last known timestamp of a segment modification.
103+
:type change_number: int
104+
105+
:param fetch_options: Fetch options for getting segment definitions.
106+
:type fetch_options: splitio.api.commons.FetchOptions
107+
108+
:return: Json representation of a segmentChange response.
109+
:rtype: dict
110+
"""
111+
try:
112+
query, extra_headers = build_fetch(change_number, fetch_options, self._metadata)
113+
response = await self._client.get(
114+
'sdk',
115+
'segmentChanges/{segment_name}'.format(segment_name=segment_name),
116+
self._sdk_key,
117+
extra_headers=extra_headers,
118+
query=query,
119+
)
120+
if 200 <= response.status_code < 300:
121+
return json.loads(response.body)
122+
raise APIException(response.body, response.status_code)
123+
except HttpClientException as exc:
124+
_LOGGER.error(
125+
'Error fetching %s because an exception was raised by the HTTPClient',
126+
segment_name
127+
)
128+
_LOGGER.debug('Error: ', exc_info=True)
129+
raise APIException('Segments not fetched properly.') from exc

0 commit comments

Comments
 (0)