Skip to content

Commit

Permalink
Feat: system enrollment error - 500 error during /token (#2089)
Browse files Browse the repository at this point in the history
  • Loading branch information
angela-tran committed May 22, 2024
2 parents 7f1878f + 3769a00 commit c238834
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 2 deletions.
14 changes: 14 additions & 0 deletions benefits/enrollment/analytics.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,15 @@ def __init__(self, request, status, error=None, payment_group=None):
self.update_event_properties(payment_group=payment_group)


class FailedAccessTokenRequestEvent(core.Event):
"""Analytics event representing a failure to acquire an access token for card tokenization."""

def __init__(self, request, status_code=None):
super().__init__(request, "failed access token request")
if status_code is not None:
self.update_event_properties(status_code=status_code)


def returned_error(request, error):
"""Send the "returned enrollment" analytics event with an error status and message."""
core.send_event(ReturnedEnrollmentEvent(request, status="error", error=error))
Expand All @@ -29,3 +38,8 @@ def returned_retry(request):
def returned_success(request, payment_group):
"""Send the "returned enrollment" analytics event with a success status."""
core.send_event(ReturnedEnrollmentEvent(request, status="success", payment_group=payment_group))


def failed_access_token_request(request, status_code=None):
"""Send the "failed access token request" analytics event with the response status code."""
core.send_event(FailedAccessTokenRequestEvent(request, status_code=status_code))
6 changes: 6 additions & 0 deletions benefits/enrollment/templates/enrollment/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ <h1 class="pb-lg-8 pb-4">
$.ajax({ dataType: "script", attrs: { nonce: "{{ request.csp_nonce }}"}, url: "{{ card_tokenize_url }}" })
.done(function() {
$.get("{{ access_token_url }}", function(data) {
if (data.redirect) {
// https://stackoverflow.com/a/42469170
// use 'assign' because 'replace' was giving strange Back button behavior
window.location.assign(data.redirect);
}

$(".loading").remove();
// remove invisible and add back visible, so we aren't left with
// a div with an empty class attribute
Expand Down
1 change: 1 addition & 0 deletions benefits/enrollment/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@
path("reenrollment-error", views.reenrollment_error, name="reenrollment-error"),
path("retry", views.retry, name="retry"),
path("success", views.success, name="success"),
path("error", views.system_error, name="system-error"),
]
19 changes: 17 additions & 2 deletions benefits/enrollment/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
ROUTE_REENROLLMENT_ERROR = "enrollment:reenrollment-error"
ROUTE_RETRY = "enrollment:retry"
ROUTE_SUCCESS = "enrollment:success"
ROUTE_SYSTEM_ERROR = "enrollment:system-error"
ROUTE_TOKEN = "enrollment:token"

TEMPLATE_RETRY = "enrollment/retry.html"
Expand All @@ -44,8 +45,22 @@ def token(request):
audience=payment_processor.audience,
)
client.oauth.ensure_active_token(client.token)
response = client.request_card_tokenization_access()
session.update(request, enrollment_token=response.get("access_token"), enrollment_token_exp=response.get("expires_at"))

try:
response = client.request_card_tokenization_access()
except Exception as e:
sentry_sdk.capture_exception(e)

if isinstance(e, HTTPError) and e.response.status_code >= 500:
analytics.failed_access_token_request(request, e.response.status_code)
data = {"redirect": reverse(ROUTE_SYSTEM_ERROR)}
return JsonResponse(data)
else:
raise e
else:
session.update(
request, enrollment_token=response.get("access_token"), enrollment_token_exp=response.get("expires_at")
)

data = {"token": session.enrollment_token(request)}

Expand Down
10 changes: 10 additions & 0 deletions tests/pytest/enrollment/test_analytics.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import pytest

from benefits.enrollment.analytics import FailedAccessTokenRequestEvent


@pytest.mark.django_db
def test_FailedAccessTokenRequestEvent_sets_status_code(app_request):
event = FailedAccessTokenRequestEvent(app_request, 500)

assert event.event_properties["status_code"] == 500
29 changes: 29 additions & 0 deletions tests/pytest/enrollment/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
ROUTE_REENROLLMENT_ERROR,
ROUTE_RETRY,
ROUTE_SUCCESS,
ROUTE_SYSTEM_ERROR,
ROUTE_TOKEN,
TEMPLATE_SYSTEM_ERROR,
TEMPLATE_RETRY,
Expand Down Expand Up @@ -102,6 +103,34 @@ def test_token_valid(mocker, client):
assert data["token"] == "enrollment_token"


@pytest.mark.django_db
@pytest.mark.usefixtures("mocked_session_agency", "mocked_session_eligibility")
def test_token_http_error_500(mocker, client, mocked_analytics_module, mocked_sentry_sdk_module):
mocker.patch("benefits.core.session.enrollment_token_valid", return_value=False)

mock_client_cls = mocker.patch("benefits.enrollment.views.Client")
mock_client = mock_client_cls.return_value

mock_error = {"message": "Mock error message"}
mock_error_response = mocker.Mock(status_code=500, **mock_error)
mock_error_response.json.return_value = mock_error
mock_client.request_card_tokenization_access.side_effect = HTTPError(
response=mock_error_response,
)

path = reverse(ROUTE_TOKEN)
response = client.get(path)

assert response.status_code == 200
data = response.json()
assert "token" not in data
assert "redirect" in data
assert data["redirect"] == reverse(ROUTE_SYSTEM_ERROR)
mocked_analytics_module.failed_access_token_request.assert_called_once()
assert 500 in mocked_analytics_module.failed_access_token_request.call_args.args
mocked_sentry_sdk_module.capture_exception.assert_called_once()


@pytest.mark.django_db
@pytest.mark.usefixtures("mocked_session_agency", "mocked_session_verifier", "mocked_session_eligibility")
def test_index_eligible_get(client, model_EligibilityType):
Expand Down

0 comments on commit c238834

Please sign in to comment.