Skip to content

Commit

Permalink
feat: add missing fields to register_feedback
Browse files Browse the repository at this point in the history
  • Loading branch information
figueredo committed Jul 19, 2024
1 parent 7552141 commit 2778c2f
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 7 deletions.
20 changes: 17 additions & 3 deletions incognia/api.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import datetime as dt
from typing import Optional, List

from .datetime_util import total_milliseconds_since_epoch
from .datetime_util import total_milliseconds_since_epoch, has_timezone
from .endpoints import Endpoints
from .exceptions import IncogniaHTTPError, IncogniaError
from .json_util import encode
Expand Down Expand Up @@ -57,9 +57,18 @@ def register_feedback(self,
signup_id: Optional[str] = None,
account_id: Optional[str] = None,
installation_id: Optional[str] = None,
session_token: Optional[str] = None) -> None:
session_token: Optional[str] = None,
request_token: Optional[str] = None,
occurred_at: dt.datetime = None,
expires_at: dt.datetime = None) -> None:
if not event:
raise IncogniaError('event is required.')
if timestamp is not None and not has_timezone(timestamp):
raise IncogniaError('timestamp must have timezone')
if occurred_at is not None and not has_timezone(occurred_at):
raise IncogniaError('occurred_at must have timezone')
if expires_at is not None and not has_timezone(expires_at):
raise IncogniaError('expires_at must have timezone')

try:
headers = self.__get_authorization_header()
Expand All @@ -72,10 +81,15 @@ def register_feedback(self,
'signup_id': signup_id,
'account_id': account_id,
'installation_id': installation_id,
'session_token': session_token
'session_token': session_token,
'request_token': request_token
}
if timestamp is not None:
body['timestamp'] = total_milliseconds_since_epoch(timestamp)
if occurred_at is not None:
body['occurred_at'] = occurred_at.isoformat()
if expires_at is not None:
body['expires_at'] = expires_at.isoformat()
data = encode(body)
return self.__request.post(Endpoints.FEEDBACKS, headers=headers, data=data)

Expand Down
6 changes: 5 additions & 1 deletion incognia/datetime_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,8 @@


def total_milliseconds_since_epoch(t: dt.datetime) -> int:
return int((t - dt.datetime.utcfromtimestamp(0)).total_seconds() * 1000.0)
return int((t - dt.datetime.fromtimestamp(0, dt.timezone.utc)).total_seconds() * 1000.0)


def has_timezone(d: dt.datetime) -> bool:
return d.tzinfo is not None and d.tzinfo.utcoffset(d) is not None
57 changes: 54 additions & 3 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class TestIncogniaAPI(TestCase):
CLIENT_SECRET: Final[str] = 'ANY_SECRET'
INSTALLATION_ID: Final[str] = 'ANY_INSTALLATION_ID'
SESSION_TOKEN: Final[str] = 'ANY_SESSION_TOKEN'
REQUEST_TOKEN: Final[str] = 'ANY_REQUEST_TOKEN'
INVALID_INSTALLATION_ID: Final[str] = 'INVALID_INSTALLATION_ID'
INVALID_SESSION_TOKEN: Final[str] = 'INVALID_SESSION_TOKEN'
ACCOUNT_ID: Final[str] = 'ANY_ACCOUNT_ID'
Expand Down Expand Up @@ -71,7 +72,8 @@ class TestIncogniaAPI(TestCase):
CLIENT_ERROR_CODE: Final[int] = 400
VALID_EVENT_FEEDBACK_TYPE: Final[str] = 'valid_event_feedback_type'
INVALID_EVENT_FEEDBACK_TYPE: Final[str] = 'invalid_event_feedback_type'
TIMESTAMP: Final[dt.datetime] = dt.datetime.now()
TIMESTAMP: Final[dt.datetime] = dt.datetime.now(dt.timezone.utc)
TIMESTAMP_WITHOUT_TIMEZONE: Final[dt.datetime] = dt.datetime.now()
LOGIN_ID: Final[str] = 'ANY_LOGIN_ID'
PAYMENT_ID: Final[str] = 'ANY_PAYMENT_ID'
REGISTER_VALID_FEEDBACK_DATA: Final[bytes] = encode({
Expand All @@ -86,7 +88,11 @@ class TestIncogniaAPI(TestCase):
'account_id': f'{ACCOUNT_ID}',
'installation_id': f'{INSTALLATION_ID}',
'session_token': f'{SESSION_TOKEN}',
'timestamp': int((TIMESTAMP - dt.datetime.utcfromtimestamp(0)).total_seconds() * 1000.0)
'request_token': f'{REQUEST_TOKEN}',
'timestamp': int((
TIMESTAMP - dt.datetime.fromtimestamp(0, dt.timezone.utc)).total_seconds() * 1000.0),
'occurred_at': TIMESTAMP.isoformat(),
'expires_at': TIMESTAMP.isoformat(),
})
REGISTER_INVALID_FEEDBACK_DATA: Final[bytes] = encode({
'event': f'{INVALID_EVENT_FEEDBACK_TYPE}'
Expand Down Expand Up @@ -211,13 +217,16 @@ def test_register_feedback_when_all_fields_are_valid_should_work(

api.register_feedback(self.VALID_EVENT_FEEDBACK_TYPE,
timestamp=self.TIMESTAMP,
occurred_at=self.TIMESTAMP,
expires_at=self.TIMESTAMP,
external_id=self.EXTERNAL_ID,
login_id=self.LOGIN_ID,
payment_id=self.PAYMENT_ID,
signup_id=self.SIGNUP_ID,
account_id=self.ACCOUNT_ID,
installation_id=self.INSTALLATION_ID,
session_token=self.SESSION_TOKEN)
session_token=self.SESSION_TOKEN,
request_token=self.REQUEST_TOKEN)

mock_token_manager_get.assert_called()
mock_base_request_post.assert_called_with(Endpoints.FEEDBACKS,
Expand All @@ -235,6 +244,48 @@ def test_register_feedback_when_event_is_empty_should_raise_an_IncogniaError(
mock_token_manager_get.assert_not_called()
mock_base_request_post.assert_not_called()

@patch.object(BaseRequest, 'post')
@patch.object(TokenManager, 'get', return_value=TOKEN_VALUES)
def test_register_feedback_when_timestamp_does_not_have_timezone_should_raise_IncogniaError(
self, mock_token_manager_get: Mock, mock_base_request_post: Mock):
api = IncogniaAPI(self.CLIENT_ID, self.CLIENT_SECRET)

self.assertRaises(IncogniaError,
api.register_feedback,
event=self.VALID_EVENT_FEEDBACK_TYPE,
timestamp=self.TIMESTAMP_WITHOUT_TIMEZONE)

mock_token_manager_get.assert_not_called()
mock_base_request_post.assert_not_called()

@patch.object(BaseRequest, 'post')
@patch.object(TokenManager, 'get', return_value=TOKEN_VALUES)
def test_register_feedback_when_occurred_at_does_not_have_timezone_should_raise_IncogniaError(
self, mock_token_manager_get: Mock, mock_base_request_post: Mock):
api = IncogniaAPI(self.CLIENT_ID, self.CLIENT_SECRET)

self.assertRaises(IncogniaError,
api.register_feedback,
event=self.VALID_EVENT_FEEDBACK_TYPE,
occurred_at=self.TIMESTAMP_WITHOUT_TIMEZONE)

mock_token_manager_get.assert_not_called()
mock_base_request_post.assert_not_called()

@patch.object(BaseRequest, 'post')
@patch.object(TokenManager, 'get', return_value=TOKEN_VALUES)
def test_register_feedback_when_expires_at_does_not_have_timezone_should_raise_IncogniaError(
self, mock_token_manager_get: Mock, mock_base_request_post: Mock):
api = IncogniaAPI(self.CLIENT_ID, self.CLIENT_SECRET)

self.assertRaises(IncogniaError,
api.register_feedback,
event=self.VALID_EVENT_FEEDBACK_TYPE,
expires_at=self.TIMESTAMP_WITHOUT_TIMEZONE)

mock_token_manager_get.assert_not_called()
mock_base_request_post.assert_not_called()

@patch.object(BaseRequest, 'post')
@patch.object(TokenManager, 'get', return_value=TOKEN_VALUES)
def test_register_feedback_when_required_fields_are_invalid_should_raise_an_IncogniaHTTPError(
Expand Down

0 comments on commit 2778c2f

Please sign in to comment.