Skip to content

Commit

Permalink
feat: add expiration date field in credits_available serializer
Browse files Browse the repository at this point in the history
fixed failing tests

fixing failing tests

fixed tests

fix lint failures

fixed isort failures
  • Loading branch information
Sameen Fatima authored and Sameen Fatima committed Aug 17, 2023
1 parent 9221b48 commit 6449350
Show file tree
Hide file tree
Showing 7 changed files with 136 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,7 @@ class SubsidyAccessPolicyCreditsAvailableResponseSerializer(SubsidyAccessPolicyR
"""
remaining_balance_per_user = serializers.SerializerMethodField()
remaining_balance = serializers.SerializerMethodField()
subsidy_end_date = serializers.SerializerMethodField()

def get_remaining_balance_per_user(self, obj):
lms_user_id = self.context.get('lms_user_id')
Expand All @@ -423,6 +424,9 @@ def get_remaining_balance_per_user(self, obj):
def get_remaining_balance(self, obj):
return obj.remaining_balance()

def get_subsidy_end_date(self, obj):
return obj.subsidy_expiration_datetime


class SubsidyAccessPolicyCanRedeemReasonResponseSerializer(serializers.Serializer):
"""
Expand Down
53 changes: 52 additions & 1 deletion enterprise_access/apps/api/tests/test_serializers.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
"""
Tests for the serializers in the API.
"""
from unittest import mock
from uuid import uuid4

from django.conf import settings
from django.test import TestCase
from django.urls import reverse

from enterprise_access.apps.api.serializers.subsidy_access_policy import SubsidyAccessPolicyRedeemableResponseSerializer
from enterprise_access.apps.api.serializers.subsidy_access_policy import (
SubsidyAccessPolicyCreditsAvailableResponseSerializer,
SubsidyAccessPolicyRedeemableResponseSerializer
)
from enterprise_access.apps.subsidy_access_policy.tests.factories import (
PerLearnerEnrollmentCapLearnerCreditAccessPolicyFactory
)
Expand Down Expand Up @@ -35,3 +41,48 @@ def test_get_policy_redemption_url(self):
expected_url = f"{settings.ENTERPRISE_ACCESS_URL}/api/v1/policy-redemption/" \
f"{self.non_redeemable_policy.uuid}/redeem/"
self.assertEqual(data["policy_redemption_url"], expected_url)


class TestSubsidyAccessPolicyCreditsAvailableResponseSerializer(TestCase):
"""
Tests for the SubsidyAccessPolicyCreditsAvailableResponseSerializer.
"""
def setUp(self):
self.user_id = 24
self.enterprise_uuid = uuid4()
self.redeemable_policy = PerLearnerEnrollmentCapLearnerCreditAccessPolicyFactory(
enterprise_customer_uuid=self.enterprise_uuid,
spend_limit=300,
active=True
)

@mock.patch('enterprise_access.apps.subsidy_access_policy.models.SubsidyAccessPolicy.transactions_for_learner')
@mock.patch('enterprise_access.apps.subsidy_access_policy.models.get_and_cache_subsidy_record')
def test_get_subsidy_end_date(self, mock_subsidy_record, mock_transactions_for_learner):
"""
Test that the get_subsidy_end_date method returns the correct
subsidy expiration date.
"""
mock_transactions_for_learner.return_value = {
'transactions': [],
'aggregates': {
'total_quantity': 0,
},
}
subsidy_exp_date = '2030-01-01 12:00:00Z'
mock_subsidy_record.return_value = {
'uuid': str(uuid4()),
'title': 'Test Subsidy',
'enterprise_customer_uuid': str(self.enterprise_uuid),
'expiration_datetime': subsidy_exp_date,
'active_datetime': '2020-01-01 12:00:00Z',
'current_balance': '1000',
}
serializer = SubsidyAccessPolicyCreditsAvailableResponseSerializer(
[self.redeemable_policy],
many=True,
context={'lms_user_id': self.user_id}
)
data = serializer.data
self.assertIn('subsidy_end_date', data[0])
self.assertEqual(data[0].get('subsidy_end_date'), subsidy_exp_date)
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,13 @@ def setup_subsidy_mocks(self):
'expiration_datetime': self.tomorrow,
'is_active': True,
}
subsidy_client_patcher = patch.object(
SubsidyAccessPolicy, 'subsidy_client'
subsidy_record_patcher = patch.object(
SubsidyAccessPolicy, 'subsidy_record'
)
self.mock_subsidy_client = subsidy_client_patcher.start()
self.mock_subsidy_client.retrieve_subsidy.return_value = mock_subsidy
self.mock_subsidy_record = subsidy_record_patcher.start()
self.mock_subsidy_record.return_value = mock_subsidy

self.addCleanup(subsidy_client_patcher.stop)
self.addCleanup(subsidy_record_patcher.stop)


@ddt.ddt
Expand Down Expand Up @@ -1067,10 +1067,20 @@ def test_redeem_policy_redemption_idempotency_key_versions(
assert new_idempotency_key_sent == baseline_idempotency_key

@mock.patch('enterprise_access.apps.subsidy_access_policy.models.get_and_cache_transactions_for_learner')
def test_credits_available_endpoint(self, mock_transactions_cache_for_learner):
@mock.patch('enterprise_access.apps.subsidy_access_policy.models.get_and_cache_subsidy_record')
def test_credits_available_endpoint(self, mock_subsidy_record, mock_transactions_cache_for_learner):
"""
Verify that SubsidyAccessPolicyViewset credits_available returns credit based policies with redeemable credit.
"""
mock_subsidy_record.return_value = {
'uuid': str(uuid4()),
'title': 'Test Subsidy',
'enterprise_customer_uuid': str(self.enterprise_uuid),
'expiration_datetime': '2030-01-01 12:00:00Z',
'active_datetime': '2020-01-01 12:00:00Z',
'current_balance': '1000',
}

mock_transaction_record = {
'uuid': str(uuid4()),
'state': TransactionStateChoices.COMMITTED,
Expand Down
4 changes: 2 additions & 2 deletions enterprise_access/apps/subsidy_access_policy/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
)
from .content_metadata_api import get_and_cache_catalog_contains_content, get_and_cache_content_metadata
from .exceptions import ContentPriceNullException, SubsidyAccessPolicyLockAttemptFailed, SubsidyAPIHTTPError
from .subsidy_api import get_and_cache_transactions_for_learner
from .subsidy_api import get_and_cache_subsidy_record, get_and_cache_transactions_for_learner
from .utils import ProxyAwareHistoricalRecords, create_idempotency_key_for_transaction, get_versioned_subsidy_client

POLICY_LOCK_RESOURCE_NAME = "subsidy_access_policy"
Expand Down Expand Up @@ -220,7 +220,7 @@ def __new__(cls, *args, **kwargs):
return super().__new__(proxy_class) # pylint: disable=lost-exception

def subsidy_record(self):
return self.subsidy_client.retrieve_subsidy(subsidy_uuid=self.subsidy_uuid)
return get_and_cache_subsidy_record(subsidy_uuid=self.subsidy_uuid)

def subsidy_balance(self):
"""
Expand Down
19 changes: 19 additions & 0 deletions enterprise_access/apps/subsidy_access_policy/subsidy_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,25 @@ def learner_transaction_cache_key(subsidy_uuid, lms_user_id):
return versioned_cache_key('get_transactions_for_learner', subsidy_uuid, lms_user_id)


def subsidy_record_cache_key(subsidy_uuid):
return versioned_cache_key('get_subsidy_record', subsidy_uuid)


def get_and_cache_subsidy_record(subsidy_uuid):
"""
Get a subsidy record associated with a policy.
"""
cache_key = subsidy_record_cache_key(subsidy_uuid)
cached_response = request_cache().get_cached_response(cache_key)
if cached_response.is_found:
return cached_response.value

client = get_versioned_subsidy_client()
response = client.retrieve_subsidy(subsidy_uuid=subsidy_uuid)
request_cache().set(cache_key, response)
return response


def get_and_cache_transactions_for_learner(subsidy_uuid, lms_user_id):
"""
Get all transactions for a learner in a given subsidy. This can
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
Tests for subsidy_access_policy models.
"""
from datetime import datetime, timedelta
from unittest import mock
from unittest.mock import patch
from uuid import uuid4

Expand Down Expand Up @@ -541,7 +542,8 @@ def test_content_would_exceed_limit_positive_spent_amount(self):
with self.assertRaisesRegex(Exception, 'Expected a sum of transaction quantities <= 0'):
self.per_learner_enroll_policy.content_would_exceed_limit(10, 100, 15)

def test_mock_subsidy_datetimes(self):
@mock.patch('enterprise_access.apps.subsidy_access_policy.models.get_and_cache_subsidy_record')
def test_mock_subsidy_datetimes(self, mock_subsidy_record):
yesterday = datetime.utcnow() - timedelta(days=1)
tomorrow = datetime.utcnow() + timedelta(days=1)
mock_subsidy = {
Expand All @@ -550,7 +552,7 @@ def test_mock_subsidy_datetimes(self):
'expiration_datetime': tomorrow,
'is_active': True,
}
self.mock_subsidy_client.retrieve_subsidy.return_value = mock_subsidy
mock_subsidy_record.return_value = mock_subsidy
policy = PerLearnerEnrollmentCapLearnerCreditAccessPolicyFactory.create()
assert policy.subsidy_record() == mock_subsidy

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@

from django.test import TestCase

from ..subsidy_api import get_and_cache_transactions_for_learner, get_redemptions_by_content_and_policy_for_learner
from ..subsidy_api import (
get_and_cache_subsidy_record,
get_and_cache_transactions_for_learner,
get_redemptions_by_content_and_policy_for_learner
)
from .factories import PerLearnerSpendCapLearnerCreditAccessPolicyFactory


Expand Down Expand Up @@ -149,3 +153,37 @@ def test_redemptions_by_content_and_policy(self, mock_transaction_cache):
},
result,
)


class SubsidyRecordForPolicyTests(TestCase):
"""
Tests the ``get_and_cache_subsidy_record`` function.
"""
@mock.patch('enterprise_access.apps.subsidy_access_policy.subsidy_api.get_versioned_subsidy_client')
def test_request_caching_works(self, mock_client_getter):
"""
Test that we utilize the request cache.
"""
subsidy_uuid = str(uuid.uuid4())
expected_response_payload = {
'uuid': subsidy_uuid,
'title': 'Test Subsidy',
'enterprise_customer_uuid': str(subsidy_uuid),
'expiration_datetime': '2030-01-01 12:00:00Z',
'active_datetime': '2020-01-01 12:00:00Z',
'current_balance': '1000',
}
mock_client = mock_client_getter.return_value
mock_client.retrieve_subsidy.return_value = expected_response_payload

result = get_and_cache_subsidy_record(subsidy_uuid)

self.assertEqual(result, expected_response_payload)

# call it again, should be using the cache this time
next_result = get_and_cache_subsidy_record(subsidy_uuid)

self.assertEqual(next_result, expected_response_payload)

# we should only have used the client in the first call
mock_client.retrieve_subsidy.assert_called_once_with(subsidy_uuid=subsidy_uuid)

0 comments on commit 6449350

Please sign in to comment.