def test_email_sent_for_invalid_num_queries(self, is_valid, mock_api_client): """ Tests that an email is sent to ECS in the case that an invalid number of distinct CatalogQuery IDs are found to be used for all subscription customers. Tests that no email is sent if the valid number of distinct CatalogQuery IDs are found. """ # Arbitrary number of subscriptions ("correct" number) num_subs = 3 SubscriptionPlanFactory.create_batch(num_subs) if is_valid: log_level = 'INFO' num_queries_found = num_subs else: log_level = 'ERROR' num_queries_found = num_subs - 1 with self.assertLogs(level=log_level) as log: catalog_query_ids = {} for _ in range(num_queries_found): catalog_query_ids[str(uuid.uuid4())] = [str(uuid.uuid4())] mock_api_client.return_value.get_distinct_catalog_queries.return_value = { 'num_distinct_query_ids': num_queries_found, 'catalog_uuids_by_catalog_query_id': catalog_query_ids, } if is_valid: call_command(self.command_name) assert 'SUCCESS' in log.output[0] else: with self.assertRaises(InvalidCatalogQueryMappingError): call_command(self.command_name) assert 'ERROR' in log.output[0]
def test_2_subscriptions_expiring_within_range( self, mock_license_expiration_task): """ Verifies that all expired subscriptions within the expired range have their license uuids sent to edx-enterprise """ expired_subscription_1 = SubscriptionPlanFactory.create( start_date=datetime.strptime('2013-1-01', '%Y-%m-%d'), expiration_date=datetime.strptime('2014-1-01', '%Y-%m-%d'), ) expired_subscription_2 = SubscriptionPlanFactory.create( start_date=datetime.strptime('2015-1-01', '%Y-%m-%d'), expiration_date=datetime.strptime('2016-1-01', '%Y-%m-%d'), ) # Create an activated license on each subscription expired_license_1 = LicenseFactory.create( status=ACTIVATED, subscription_plan=expired_subscription_1) expired_license_2 = LicenseFactory.create( status=ACTIVATED, subscription_plan=expired_subscription_2) call_command(self.command_name, "--expired-after=2013-1-01", "--expired-before=2016-1-01") actual_args = mock_license_expiration_task.call_args_list[0][0][0] assert sorted(actual_args) == sorted( [str(expired_license_1.uuid), str(expired_license_2.uuid)])
def test_1_subscription_expiring_outside_date_range( self, mock_license_expiration_task): """ Verifies that only expired subscriptions within the expired range have their license uuids sent to edx-enterprise """ # A recently expired subscription that should be processed expired_subscription = SubscriptionPlanFactory.create( start_date=self.today - timedelta(days=7), expiration_date=self.today, ) # An expired subscription that expired about a month ago older_expired_subscription = SubscriptionPlanFactory.create( start_date=self.today - timedelta(days=60), expiration_date=self.today - timedelta(days=30), ) # Create an activated license on each subscription license_to_expire_enrollments = LicenseFactory.create( status=ACTIVATED, subscription_plan=expired_subscription) LicenseFactory.create(status=ACTIVATED, subscription_plan=older_expired_subscription) call_command(self.command_name) mock_license_expiration_task.assert_called_with( [str(license_to_expire_enrollments.uuid)])
def setUp(self): super().setUp() customer_agreement = CustomerAgreementFactory() self.active_subscription_plans = SubscriptionPlanFactory.create_batch( 2, customer_agreement=customer_agreement) self.inactive_subscription_plans = SubscriptionPlanFactory.create_batch( 3, customer_agreement=customer_agreement, is_active=False) self.customer_agreement = customer_agreement
def setUpTestData(cls): super().setUpTestData() # technically this will be off on leap years, but we just need something later than now, so it's not a problem ONE_YEAR_FROM_NOW = localized_datetime_from_datetime(datetime.now() + timedelta(days=365)) TWO_YEARS_FROM_NOW = localized_datetime_from_datetime(datetime.now() + timedelta(days=730)) cls.user_email = '*****@*****.**' cls.enterprise_customer_uuid = uuid.uuid4() cls.customer_agreement = CustomerAgreementFactory.create( enterprise_customer_uuid=cls.enterprise_customer_uuid, ) cls.subscription_plan = SubscriptionPlanFactory() cls.active_current_plan = SubscriptionPlanFactory.create( customer_agreement=cls.customer_agreement, is_active=True, start_date=localized_datetime(2021, 1, 1), expiration_date=ONE_YEAR_FROM_NOW, ) cls.active_current_license = LicenseFactory.create( user_email=cls.user_email, subscription_plan=cls.active_current_plan, ) cls.inactive_current_plan = SubscriptionPlanFactory.create( customer_agreement=cls.customer_agreement, is_active=False, start_date=localized_datetime(2021, 1, 1), expiration_date=ONE_YEAR_FROM_NOW, ) cls.inactive_current_license = LicenseFactory.create( user_email=cls.user_email, subscription_plan=cls.inactive_current_plan, ) cls.non_current_active_plan = SubscriptionPlanFactory.create( customer_agreement=cls.customer_agreement, is_active=True, start_date=ONE_YEAR_FROM_NOW, expiration_date=TWO_YEARS_FROM_NOW, ) cls.non_current_active_license = LicenseFactory.create( user_email=cls.user_email, subscription_plan=cls.non_current_active_plan, ) cls.non_current_inactive_plan = SubscriptionPlanFactory.create( customer_agreement=cls.customer_agreement, is_active=False, start_date=ONE_YEAR_FROM_NOW, expiration_date=TWO_YEARS_FROM_NOW, ) cls.non_current_inactive_license = LicenseFactory.create( user_email=cls.user_email, subscription_plan=cls.non_current_inactive_plan, )
def setUpTestData(cls): super().setUpTestData() cls.customer_agreement = CustomerAgreementFactory() cls.subscription_plan_a = SubscriptionPlanFactory( expiration_date=localized_datetime(2020, 1, 1), customer_agreement=cls.customer_agreement, ) cls.subscription_plan_b = SubscriptionPlanFactory( expiration_date=localized_datetime(2021, 1, 1), customer_agreement=cls.customer_agreement )
def setUpTestData(cls): super().setUpTestData() customer_agreement = CustomerAgreementFactory() subscription_plan_1 = SubscriptionPlanFactory( customer_agreement=customer_agreement) subscription_plan_2 = SubscriptionPlanFactory( customer_agreement=customer_agreement) cls.customer_agreement = customer_agreement cls.subscription_plan_1 = subscription_plan_1 cls.subscription_plan_2 = subscription_plan_2
def test_prior_renewals(self): renewed_subscription_plan_1 = SubscriptionPlanFactory.create() renewed_subscription_plan_2 = SubscriptionPlanFactory.create() renewal_1 = SubscriptionPlanRenewalFactory.create( prior_subscription_plan=self.subscription_plan, renewed_subscription_plan=renewed_subscription_plan_1 ) renewal_2 = SubscriptionPlanRenewalFactory.create( prior_subscription_plan=renewed_subscription_plan_1, renewed_subscription_plan=renewed_subscription_plan_2 ) self.assertEqual(renewed_subscription_plan_2.prior_renewals, [renewal_1, renewal_2])
def test_1_subscription_expiring_today(self, mock_license_expiration_task): """ When there is a subscription expiring verify only the assigned and activated licenses are sent to edx-enterprise """ expired_subscription = SubscriptionPlanFactory.create( start_date=self.today - timedelta(days=7), expiration_date=self.today, ) # Create licenses with a variety of statuses LicenseFactory.create_batch(3, subscription_plan=expired_subscription) LicenseFactory.create_batch(2, status=ASSIGNED, subscription_plan=expired_subscription) LicenseFactory.create(status=ACTIVATED, subscription_plan=expired_subscription) LicenseFactory.create(status=REVOKED, subscription_plan=expired_subscription) call_command(self.command_name) expired_license_uuids = [ str(license.uuid) for license in expired_subscription.licenses.filter( status__in=[ASSIGNED, ACTIVATED]) ] mock_license_expiration_task.assert_called_with(expired_license_uuids)
def setUp(self): super().setUp() self.activated_user = UserFactory() self.assigned_user = UserFactory() self.unlicensed_user = UserFactory() self.enterprise_customer_uuid = uuid4() self.enterprise_catalog_uuid = uuid4() self.course_key = 'testX' self.customer_agreement = CustomerAgreementFactory( enterprise_customer_uuid=self.enterprise_customer_uuid, ) self.active_subscription_for_customer = SubscriptionPlanFactory.create( customer_agreement=self.customer_agreement, enterprise_catalog_uuid=self.enterprise_catalog_uuid, is_active=True, ) self.activated_license = LicenseFactory.create( status=constants.ACTIVATED, user_email=self.activated_user.email, subscription_plan=self.active_subscription_for_customer, ) self.assigned_license = LicenseFactory.create( status=constants.ASSIGNED, user_email=self.assigned_user.email, subscription_plan=self.active_subscription_for_customer, )
def _create_expired_plan_with_licenses(self, unassigned_licenses_count=1, assigned_licenses_count=2, activated_licenses_count=3, revoked_licenses_count=4, start_date=today - timedelta(days=7), expiration_date=today, expiration_processed=False): """ Creates a plan with licenses. The plan is expired by default. """ expired_plan = SubscriptionPlanFactory.create( start_date=start_date, expiration_date=expiration_date, expiration_processed=expiration_processed) LicenseFactory.create_batch(unassigned_licenses_count, status=UNASSIGNED, subscription_plan=expired_plan) LicenseFactory.create_batch(assigned_licenses_count, status=ASSIGNED, subscription_plan=expired_plan) LicenseFactory.create_batch(activated_licenses_count, status=ACTIVATED, subscription_plan=expired_plan) LicenseFactory.create_batch(revoked_licenses_count, status=REVOKED, subscription_plan=expired_plan) return expired_plan
def test_renewal_processed_with_no_existing_future_plan(self): prior_plan = SubscriptionPlanFactory() original_activated_licenses = [ LicenseFactory.create( subscription_plan=prior_plan, status=constants.ACTIVATED, user_email='activated_user_{}@example.com'.format(i)) for i in range(5) ] original_assigned_licenses = [ LicenseFactory.create( subscription_plan=prior_plan, status=constants.ASSIGNED, user_email='assigned_user_{}@example.com'.format(i)) for i in range(5) ] original_licenses = original_activated_licenses + original_assigned_licenses renewal = SubscriptionPlanRenewalFactory( prior_subscription_plan=prior_plan, number_of_licenses=10, license_types_to_copy=constants.LicenseTypesToRenew. ASSIGNED_AND_ACTIVATED) with freezegun.freeze_time(NOW): api.renew_subscription(renewal) renewal.refresh_from_db() original_plan = renewal.prior_subscription_plan future_plan = renewal.renewed_subscription_plan self.assertTrue(renewal.processed) self.assertEqual(renewal.processed_datetime, NOW) self.assertEqual(original_plan.product_id, future_plan.product_id) self.assertEqual(future_plan.num_licenses, renewal.number_of_licenses) self._assert_all_licenses_renewed(future_plan)
def test_select_subscription_for_auto_applied_licenses( mock_toggle_auto_apply_licenses): """ Verify that selecting a SubscriptionPlan on a CustomerAgreement calls toggle_auto_apply_licenses. """ customer_agreement_admin = CustomerAgreementAdmin(CustomerAgreement, AdminSite()) request = RequestFactory() request.user = UserFactory() customer_agreement = CustomerAgreementFactory() subscription_plan = SubscriptionPlanFactory( customer_agreement=customer_agreement) customer_agreement_uuid = str(customer_agreement.uuid) subscription_uuid = str(subscription_plan.uuid) request.resolver_match = mock.Mock( kwargs={'object_id': customer_agreement_uuid}) form = make_bound_customer_agreement_form( customer_agreement=customer_agreement, subscription_for_auto_applied_licenses=subscription_uuid) obj = form.save( ) # Get the object returned from saving the form to save to the database change = True customer_agreement_admin.save_model(request, obj, form, change) args = mock_toggle_auto_apply_licenses.call_args[0] assert args[0] is customer_agreement_uuid assert args[1] is subscription_uuid
def test_renewal_future_plan_auto_applies_licenses( self, should_auto_apply_licenses): customer_agreement = CustomerAgreementFactory.create() prior_plan = SubscriptionPlanFactory( customer_agreement=customer_agreement, should_auto_apply_licenses=should_auto_apply_licenses) renewal = SubscriptionPlanRenewalFactory( prior_subscription_plan=prior_plan, number_of_licenses=1, license_types_to_copy=constants.LicenseTypesToRenew. ASSIGNED_AND_ACTIVATED, effective_date=NOW) with freezegun.freeze_time(NOW): api.renew_subscription(renewal) renewal.refresh_from_db() future_plan = renewal.renewed_subscription_plan if should_auto_apply_licenses: self.assertTrue(future_plan.should_auto_apply_licenses) self.assertEqual(customer_agreement.auto_applicable_subscription, future_plan) else: assert future_plan.should_auto_apply_licenses is None assert customer_agreement.auto_applicable_subscription is None
def test_delete_unassigned_licenses_post_freeze(self): subscription_plan = SubscriptionPlanFactory( can_freeze_unused_licenses=True) LicenseFactory.create_batch( 5, subscription_plan=subscription_plan, status=constants.UNASSIGNED, ) LicenseFactory.create_batch( 2, subscription_plan=subscription_plan, status=constants.ASSIGNED, ) LicenseFactory.create_batch( 1, subscription_plan=subscription_plan, status=constants.ACTIVATED, ) with freezegun.freeze_time(NOW): api.delete_unused_licenses_post_freeze(subscription_plan) assert subscription_plan.unassigned_licenses.count() == 0 assert subscription_plan.assigned_licenses.count() == 2 assert subscription_plan.activated_licenses.count() == 1 assert subscription_plan.last_freeze_timestamp == NOW
def test_activated_license_is_revoked( self, is_revocation_cap_enabled, ): agreement = CustomerAgreementFactory.create( enterprise_customer_uuid=uuid.UUID( '00000000-1111-2222-3333-444444444444'), ) subscription_plan = SubscriptionPlanFactory.create( customer_agreement=agreement, is_revocation_cap_enabled=is_revocation_cap_enabled, num_revocations_applied=0, revoke_max_percentage=100, ) original_license = LicenseFactory.create( status=constants.ACTIVATED, subscription_plan=subscription_plan, lms_user_id=123, ) with freezegun.freeze_time(NOW): api.revoke_license(original_license) original_license.refresh_from_db() self.assertEqual(original_license.status, constants.REVOKED) self.assertEqual(original_license.revoked_date, NOW) # There should now be 1 unassigned license self.assertEqual(subscription_plan.unassigned_licenses.count(), 1)
def make_test_email_data(): """ Returns a dictionary of data needed to send emails """ # Create a SubscriptionPlan and associate a batch of licenses using Factories subscription = SubscriptionPlanFactory() licenses = LicenseFactory.create_batch(6) subscription.licenses.set(licenses) custom_template_text = { 'greeting': 'Hello', 'closing': 'Goodbye', } email_recipient_list = [ '*****@*****.**', '*****@*****.**', '*****@*****.**', ] # Use emails from list created above to create assigned licenses for lic, email in zip(licenses, email_recipient_list): lic.user_email = email lic.status = ASSIGNED lic.save() return { 'subscription_plan': subscription, 'licenses': licenses, 'custom_template_text': custom_template_text, 'email_recipient_list': email_recipient_list }
def test_cannot_freeze_plan_with_freezing_unsupported(self): subscription_plan = SubscriptionPlanFactory() expected_message = 'The plan does not support freezing unused licenses.' with self.assertRaisesRegex( exceptions.UnprocessableSubscriptionPlanFreezeError, expected_message): api.delete_unused_licenses_post_freeze(subscription_plan)
def test_is_locked_for_renewal_processing(self, is_locked_for_renewal_processing): today = localized_utcnow() with freezegun.freeze_time(today): renewed_subscription_plan = SubscriptionPlanFactory.create(expiration_date=today) renewal_kwargs = {'prior_subscription_plan': renewed_subscription_plan} if is_locked_for_renewal_processing: renewal_kwargs.update({'effective_date': renewed_subscription_plan.expiration_date}) SubscriptionPlanRenewalFactory.create(**renewal_kwargs) self.assertEqual(renewed_subscription_plan.is_locked_for_renewal_processing, is_locked_for_renewal_processing)
def test_invalid_start_date_before_today(self): prior_subscription_plan = SubscriptionPlanFactory.create() form = make_bound_subscription_plan_renewal_form( prior_subscription_plan=prior_subscription_plan, effective_date=localized_utcnow() - timedelta(1), renewed_expiration_date=prior_subscription_plan.expiration_date + timedelta(366), ) assert not form.is_valid()
def test_valid_start_and_expiration_dates(self): prior_subscription_plan = SubscriptionPlanFactory.create() form = make_bound_subscription_plan_renewal_form( prior_subscription_plan=prior_subscription_plan, effective_date=prior_subscription_plan.expiration_date + timedelta(1), renewed_expiration_date=prior_subscription_plan.expiration_date + timedelta(366), ) assert form.is_valid()
def test_populate_subscription_for_auto_applied_licenses_choices(self): customer_agreement = CustomerAgreementFactory() active_subscription_plan = SubscriptionPlanFactory( customer_agreement=customer_agreement) SubscriptionPlanFactory(customer_agreement=customer_agreement, is_active=False) form = make_bound_customer_agreement_form( customer_agreement=customer_agreement, subscription_for_auto_applied_licenses=None) field = form.fields['subscription_for_auto_applied_licenses'] choices = field.choices self.assertEqual(len(choices), 2) self.assertEqual(choices[0], ('', '------')) self.assertEqual( choices[1], (active_subscription_plan.uuid, active_subscription_plan.title)) self.assertEqual(field.initial, ('', '------'))
def test_subscription_factory_licenses(self): """ Verify a subscription plan factory can have licenses associated with it. """ subscription = SubscriptionPlanFactory() licenses = LicenseFactory.create_batch(5) subscription.licenses.set(licenses) # Verify the subscription plan uuid is correctly set on the licenses license = subscription.licenses.first() self.assertEqual(subscription.uuid, license.subscription_plan.uuid)
def create_subscription_with_renewal(self, effective_date, processed=False): prior_subscription_plan = SubscriptionPlanFactory.create( start_date=self.now - timedelta(days=7), expiration_date=self.now, ) renewed_subscription_plan = SubscriptionPlanFactory.create( start_date=self.now, expiration_date=self.now + timedelta(days=7), ) SubscriptionPlanRenewalFactory.create( prior_subscription_plan=prior_subscription_plan, renewed_subscription_plan=renewed_subscription_plan, effective_date=effective_date, processed=processed) return (prior_subscription_plan)
def test_populate_subscription_for_auto_applied_licenses_plans_outside_agreement_not_included( self): customer_agreement_1 = CustomerAgreementFactory() customer_agreement_2 = CustomerAgreementFactory() sub_for_customer_agreement_1 = SubscriptionPlanFactory( customer_agreement=customer_agreement_1, should_auto_apply_licenses=False) SubscriptionPlanFactory(customer_agreement=customer_agreement_2, should_auto_apply_licenses=True) form = make_bound_customer_agreement_form( customer_agreement=customer_agreement_1, subscription_for_auto_applied_licenses=None) field = form.fields['subscription_for_auto_applied_licenses'] choices = field.choices self.assertEqual(len(choices), 2) self.assertEqual(choices[0], ('', '------')) self.assertEqual(choices[1], (sub_for_customer_agreement_1.uuid, sub_for_customer_agreement_1.title)) self.assertEqual(field.initial, choices[0], ('', '------'))
def test_auto_applied_licenses_count_since(self): """ Tests that the correct auto-applied license count is returned. """ subscription_plan = SubscriptionPlanFactory.create(should_auto_apply_licenses=True) timestamp_1 = localized_utcnow() LicenseFactory.create_batch(1, subscription_plan=subscription_plan, auto_applied=True, activation_date=timestamp_1) LicenseFactory.create_batch(3, subscription_plan=subscription_plan, auto_applied=False, activation_date=timestamp_1) self.assertEqual(subscription_plan.auto_applied_licenses_count_since(), 1) timestamp_2 = timestamp_1 + timedelta(seconds=1) self.assertEqual(subscription_plan.auto_applied_licenses_count_since(timestamp_2), 0) LicenseFactory.create_batch(5, subscription_plan=subscription_plan, auto_applied=True, activation_date=timestamp_2) self.assertEqual(subscription_plan.auto_applied_licenses_count_since(timestamp_2), 5)
def test_renewal_processed_with_existing_future_plan(self): prior_plan = SubscriptionPlanFactory() original_licenses = [ LicenseFactory.create( subscription_plan=prior_plan, status=constants.ACTIVATED, user_email='activated_user_{}@example.com'.format(i)) for i in range(5) ] # create some revoked original licenses that should not be renewed LicenseFactory.create_batch( 67, subscription_plan=prior_plan, status=constants.REVOKED, ) future_plan = SubscriptionPlanFactory() LicenseFactory.create_batch( 10, subscription_plan=future_plan, status=constants.UNASSIGNED, ) renewal = SubscriptionPlanRenewalFactory( prior_subscription_plan=prior_plan, renewed_subscription_plan=future_plan, number_of_licenses=10, ) with freezegun.freeze_time(NOW): api.renew_subscription(renewal) future_plan.refresh_from_db() self.assertTrue(renewal.processed) self.assertEqual(renewal.processed_datetime, NOW) self.assertEqual(future_plan.num_licenses, renewal.number_of_licenses) self._assert_all_licenses_renewed(future_plan)
def test_expiring_10k_licenses_batched(self, mock_license_expiration_task): """ Verifies that all expired subscriptions within the expired range have their license uuids sent to edx-enterprise """ # A recently expired subscription that should be processed expired_subscription_1 = SubscriptionPlanFactory.create( start_date=self.today - timedelta(days=7), expiration_date=self.today, ) expired_subscription_2 = SubscriptionPlanFactory.create( start_date=self.today - timedelta(days=7), expiration_date=self.today, ) LicenseFactory.create_batch(500, status=ACTIVATED, subscription_plan=expired_subscription_1) LicenseFactory.create_batch(500, status=ACTIVATED, subscription_plan=expired_subscription_2) call_command(self.command_name) expected_call_count = math.ceil(1000 / LICENSE_EXPIRATION_BATCH_SIZE) assert expected_call_count == mock_license_expiration_task.call_count
def test_auto_apply_licenses_turned_on_at(self): """ Tests that auto_apply_licenses_turned_on_at returns the correct time. """ subscription_plan = SubscriptionPlanFactory.create() subscription_plan.should_auto_apply_licenses = True subscription_plan.save() auto_apply_licenses_turned_on_at = subscription_plan.history.latest().history_date subscription_plan.is_active = True subscription_plan.save() latest_history_date = subscription_plan.history.latest().history_date self.assertEqual(subscription_plan.auto_apply_licenses_turned_on_at, auto_apply_licenses_turned_on_at) self.assertNotEqual(subscription_plan.auto_apply_licenses_turned_on_at, latest_history_date)
def test_track_event_via_braze_alias(mock_braze_client): test_email = '*****@*****.**' assigned_license = LicenseFactory.create( subscription_plan=SubscriptionPlanFactory.create(), lms_user_id=5, user_email=test_email, status=ASSIGNED, auto_applied=True) test_event_name = 'test-event-name' test_event_properties = { 'license_uuid': str(assigned_license.uuid), 'enterprise_customer_slug': assigned_license.subscription_plan.customer_agreement. enterprise_customer_slug, } expected_user_alias = { "alias_name": test_email, "alias_label": ENTERPRISE_BRAZE_ALIAS_LABEL, } expected_attributes = { "user_alias": expected_user_alias, "email": test_email, "is_enterprise_learner": True, "_update_existing_only": False, "license_uuid": str(assigned_license.uuid), "enterprise_customer_slug": assigned_license.subscription_plan.customer_agreement. enterprise_customer_slug, } expected_event = { "user_alias": expected_user_alias, "name": test_event_name, "time": _iso_8601_format_string(localized_utcnow()), "properties": test_event_properties, "_update_existing_only": False, } _track_event_via_braze_alias(test_email, test_event_name, test_event_properties) mock_braze_client().create_braze_alias.assert_any_call( [test_email], ENTERPRISE_BRAZE_ALIAS_LABEL) mock_braze_client().track_user.assert_any_call( attributes=[expected_attributes], events=[expected_event])