class AuthBackendTestCase(TestCase): def setUp(self): self.user = UserFactory(email='*****@*****.**', is_staff=True) self.user.set_password('letmein') self.user.save() self.backend = EmailBackend() @unittest.skipUnless(django.VERSION < (1, 11), "for Django <1.11 only") def test_authentication_method_signature_pre_django_1_11(self): auth_result = self.backend.authenticate('*****@*****.**', 'letmein') self.assertEqual(auth_result, self.user) @unittest.skipUnless(django.VERSION >= (1, 11), "for Django >=1.11 only") def test_authentication_method_signature_post_django_1_11(self): auth_result = self.backend.authenticate(None, '*****@*****.**', 'letmein') self.assertEqual(auth_result, self.user) def test_inactive_users_cannot_authenticate(self): self.user.is_active = False self.user.save() auth_result = self.backend.authenticate(None, '*****@*****.**', 'letmein') self.assertIsNone(auth_result)
class AuthBackendTestCase(TestCase): def setUp(self): self.user = UserFactory(email='*****@*****.**', is_staff=True) self.user.set_password('letmein') self.user.save() self.backend = EmailBackend() def test_authentication_method_signature_post_django_1_11(self): auth_result = self.backend.authenticate(None, '*****@*****.**', 'letmein') self.assertEqual(auth_result, self.user) def test_inactive_users_cannot_authenticate(self): self.user.is_active = False self.user.save() auth_result = self.backend.authenticate(None, '*****@*****.**', 'letmein') self.assertIsNone(auth_result)
class EdxOrderPlacementMixinTests(BusinessIntelligenceMixin, PaymentEventsMixin, RefundTestMixin, TestCase): """ Tests validating generic behaviors of the EdxOrderPlacementMixin. """ def setUp(self): super(EdxOrderPlacementMixinTests, self).setUp() self.user = UserFactory() self.order = self.create_order(status=ORDER.OPEN) def test_handle_payment_logging(self, __): """ Ensure that we emit a log entry upon receipt of a payment notification, and create Source and PaymentEvent objects. """ basket = create_basket(owner=self.user, site=self.site) mixin = EdxOrderPlacementMixin() mixin.payment_processor = DummyProcessor(self.site) processor_name = DummyProcessor.NAME total = basket.total_incl_tax reference = basket.id with LogCapture(LOGGER_NAME) as l: mixin.handle_payment({}, basket) l.check(( LOGGER_NAME, 'INFO', 'payment_received: amount="{}", basket_id="{}", currency="{}", ' 'processor_name="{}", reference="{}", user_id="{}"'.format( total, basket.id, basket.currency, processor_name, reference, self.user.id))) # pylint: disable=protected-access # Validate a payment Source was created source_type = SourceType.objects.get(code=processor_name) label = self.user.username self.assert_basket_matches_source(basket, mixin._payment_sources[-1], source_type, reference, label) # Validate the PaymentEvent was created paid_type = PaymentEventType.objects.get(code='paid') self.assert_valid_payment_event_fields(mixin._payment_events[-1], total, paid_type, processor_name, reference) def test_order_number_collision(self, _mock_track): """ Verify that an attempt to create an order with the same number as an existing order causes an exception to be raised. """ order_placement_mixin = EdxOrderPlacementMixin() basket = self.order.basket shipping_method = NoShippingRequired() shipping_charge = shipping_method.calculate(basket) order_total = OrderTotalCalculator().calculate(basket, shipping_charge) with self.assertRaises(ValueError): order_placement_mixin.handle_order_placement( self.order.number, self.user, basket, None, shipping_method, shipping_charge, None, order_total, ) def test_handle_successful_order(self, mock_track): """ Ensure that tracking events are fired with correct content when order placement event handling is invoked. """ tracking_context = { 'ga_client_id': 'test-client-id', 'lms_user_id': 'test-user-id', 'lms_ip': '127.0.0.1' } self.user.tracking_context = tracking_context self.user.save() with LogCapture(LOGGER_NAME) as l: EdxOrderPlacementMixin().handle_successful_order(self.order) # ensure event is being tracked self.assertTrue(mock_track.called) # ensure event data is correct self.assert_correct_event( mock_track, self.order, tracking_context['lms_user_id'], tracking_context['ga_client_id'], tracking_context['lms_ip'], self.order.number, self.order.currency, self.order.user.email, self.order.total_excl_tax, self.order. total_excl_tax # value for revenue field is same as total. ) l.check(( LOGGER_NAME, 'INFO', 'order_placed: amount="{}", basket_id="{}", contains_coupon="{}", currency="{}",' ' order_number="{}", user_id="{}"'.format( self.order.total_excl_tax, self.order.basket.id, self.order.contains_coupon, self.order.currency, self.order.number, self.order.user.id))) def test_handle_post_order_for_bulk_purchase(self, __): """ Ensure that the bulk purchase order is linked to the provided business client when the method `handle_post_order` is invoked. """ toggle_switch(ENROLLMENT_CODE_SWITCH, True) course = CourseFactory(partner=self.partner) course.create_or_update_seat('verified', True, 50, create_enrollment_code=True) enrollment_code = Product.objects.get( product_class__name=ENROLLMENT_CODE_PRODUCT_CLASS_NAME) user = UserFactory() basket = BasketFactory(owner=user, site=self.site) basket.add_product(enrollment_code, quantity=1) order = create_order(number=1, basket=basket, user=user) request_data = {'organization': 'Dummy Business Client'} # Manually add organization attribute on the basket for testing basket_add_organization_attribute(basket, request_data) EdxOrderPlacementMixin().handle_post_order(order) # Now verify that a new business client has been created in current # order is now linked with that client through Invoice model. business_client = BusinessClient.objects.get( name=request_data['organization']) assert Invoice.objects.get( order=order).business_client == business_client def test_handle_post_order_for_seat_purchase(self, __): """ Ensure that the single seat purchase order is not linked any business client when the method `handle_post_order` is invoked. """ toggle_switch(ENROLLMENT_CODE_SWITCH, False) course = CourseFactory(partner=self.partner) verified_product = course.create_or_update_seat('verified', True, 50) user = UserFactory() basket = BasketFactory(owner=user, site=self.site) basket.add_product(verified_product, quantity=1) order = create_order(number=1, basket=basket, user=user) request_data = {'organization': 'Dummy Business Client'} # Manually add organization attribute on the basket for testing basket_add_organization_attribute(basket, request_data) EdxOrderPlacementMixin().handle_post_order(order) # Now verify that the single seat order is not linked to business # client by checking that there is no record for BusinessClient. assert not BusinessClient.objects.all() def test_handle_successful_order_no_context(self, mock_track): """ Ensure that expected values are substituted when no tracking_context was available. """ EdxOrderPlacementMixin().handle_successful_order(self.order) # ensure event is being tracked self.assertTrue(mock_track.called) # ensure event data is correct self.assert_correct_event( mock_track, self.order, ECOM_TRACKING_ID_FMT.format(self.user.id), None, None, self.order.number, self.order.currency, self.order.user.email, self.order.total_excl_tax, self.order. total_excl_tax # value for revenue field is same as total. ) def test_handle_successful_order_no_segment_key(self, mock_track): """ Ensure that tracking events do not fire when there is no Segment key configured. """ self.site.siteconfiguration.segment_key = None EdxOrderPlacementMixin().handle_successful_order(self.order) # ensure no event was fired self.assertFalse(mock_track.called) def test_handle_successful_order_segment_error(self, mock_track): """ Ensure that exceptions raised while emitting tracking events are logged, but do not otherwise interrupt program flow. """ with mock.patch('ecommerce.extensions.analytics.utils.logger.exception' ) as mock_log_exc: mock_track.side_effect = Exception("clunk") EdxOrderPlacementMixin().handle_successful_order(self.order) # ensure that analytics.track was called, but the exception was caught self.assertTrue(mock_track.called) # ensure we logged a warning. self.assertTrue( mock_log_exc.called_with( "Failed to emit tracking event upon order placement.")) def test_handle_successful_async_order(self, __): """ Verify that a Waffle Sample can be used to control async order fulfillment. """ sample, created = Sample.objects.get_or_create( name='async_order_fulfillment', defaults={ 'percent': 100.0, 'note': 'Determines what percentage of orders are fulfilled asynchronously.', }) if not created: sample.percent = 100.0 sample.save() with mock.patch( 'ecommerce.extensions.checkout.mixins.fulfill_order.delay' ) as mock_delay: EdxOrderPlacementMixin().handle_successful_order(self.order) mock_delay.assert_called_once_with( self.order.number, site_code=self.partner.short_code, email_opt_in=False) def test_handle_successful_order_no_email_opt_in(self, _): """ Verify that the post checkout defaults email_opt_in to false. """ with mock.patch( 'ecommerce.extensions.checkout.mixins.post_checkout.send' ) as mock_send: mixin = EdxOrderPlacementMixin() mixin.handle_successful_order(self.order) send_arguments = { 'sender': mixin, 'order': self.order, 'request': None, 'email_opt_in': False } mock_send.assert_called_once_with(**send_arguments) @ddt.data(True, False) def test_handle_successful_order_with_email_opt_in(self, expected_opt_in, _): """ Verify that the post checkout sets email_opt_in if it is given. """ BasketAttribute.objects.get_or_create( basket=self.order.basket, attribute_type=BasketAttributeType.objects.get( name=EMAIL_OPT_IN_ATTRIBUTE), value_text=expected_opt_in, ) with mock.patch( 'ecommerce.extensions.checkout.mixins.post_checkout.send' ) as mock_send: mixin = EdxOrderPlacementMixin() mixin.handle_successful_order(self.order) send_arguments = { 'sender': mixin, 'order': self.order, 'request': None, 'email_opt_in': expected_opt_in, } mock_send.assert_called_once_with(**send_arguments) def test_place_free_order(self, __): """ Verify an order is placed and the basket is submitted. """ basket = create_basket(empty=True) basket.add_product(ProductFactory(stockrecords__price_excl_tax=0)) order = EdxOrderPlacementMixin().place_free_order(basket) self.assertIsNotNone(order) self.assertEqual(basket.status, Basket.SUBMITTED) def test_non_free_basket_order(self, __): """ Verify an error is raised for non-free basket. """ basket = create_basket(empty=True) basket.add_product(ProductFactory(stockrecords__price_excl_tax=10)) with self.assertRaises(BasketNotFreeError): EdxOrderPlacementMixin().place_free_order(basket) def test_send_confirmation_message(self, __): """ Verify the send confirmation message override functions as expected """ factory = RequestFactory() request = factory.get('example.com') user = self.create_user() user.email = '*****@*****.**' request.user = user site_from_email = '*****@*****.**' site_configuration = SiteConfigurationFactory( partner__name='Tester', from_email=site_from_email) request.site = site_configuration.site order = create_order() order.user = user mixin = EdxOrderPlacementMixin() mixin.request = request # Happy path mixin.send_confirmation_message(order, 'ORDER_PLACED', request.site) self.assertEqual(mail.outbox[0].from_email, site_from_email) mail.outbox = [] # Invalid code path (graceful exit) mixin.send_confirmation_message(order, 'INVALID_CODE', request.site) self.assertEqual(len(mail.outbox), 0) # Invalid messages container path (graceful exit) with mock.patch( 'ecommerce.extensions.checkout.mixins.CommunicationEventType.objects.get' ) as mock_get: mock_event_type = mock.Mock() mock_event_type.get_messages.return_value = {} mock_get.return_value = mock_event_type mixin.send_confirmation_message(order, 'ORDER_PLACED', request.site) self.assertEqual(len(mail.outbox), 0) mock_event_type.get_messages.return_value = {'body': None} mock_get.return_value = mock_event_type mixin.send_confirmation_message(order, 'ORDER_PLACED', request.site) self.assertEqual(len(mail.outbox), 0) def test_valid_payment_segment_logging(self, mock_track): """ Verify the "Payment Info Entered" Segment event is fired after payment info is validated """ tracking_context = { 'ga_client_id': 'test-client-id', 'lms_user_id': 'test-user-id', 'lms_ip': '127.0.0.1' } self.user.tracking_context = tracking_context self.user.save() basket = create_basket(owner=self.user, site=self.site) mixin = EdxOrderPlacementMixin() mixin.payment_processor = DummyProcessor(self.site) user_tracking_id, ga_client_id, lms_ip = parse_tracking_context( self.user) context = { 'ip': lms_ip, 'Google Analytics': { 'clientId': ga_client_id }, 'page': { 'url': 'https://testserver.fake/' }, } mixin.handle_payment({}, basket) # Verify the correct events are fired to Segment calls = [] properties = translate_basket_line_for_segment(basket.lines.first()) properties['cart_id'] = basket.id calls.append( mock.call(user_tracking_id, 'Product Added', properties, context=context)) properties = { 'checkout_id': basket.order_number, 'step': 1, 'payment_method': 'Visa | ' + DummyProcessor.NAME, } calls.append( mock.call(user_tracking_id, 'Checkout Step Completed', properties, context=context)) properties['step'] = 2 calls.append( mock.call(user_tracking_id, 'Checkout Step Viewed', properties, context=context)) calls.append( mock.call(user_tracking_id, 'Checkout Step Completed', properties, context=context)) properties = {'checkout_id': basket.order_number} calls.append( mock.call(user_tracking_id, 'Payment Info Entered', properties, context=context)) mock_track.assert_has_calls(calls) def test_update_assigned_voucher_offer_assignment(self, __): """ Verify the "update_assigned_voucher_offer_assignment" works as expected. """ enterprise_offer = EnterpriseOfferFactory() voucher = VoucherFactory() voucher.offers.add(enterprise_offer) basket = create_basket(owner=self.user, site=self.site) basket.vouchers.add(voucher) order = create_order(user=self.user, basket=basket) voucher_application = VoucherApplication.objects.create( voucher=voucher, user=self.user, order=order) offer_assignment = OfferAssignmentFactory(offer=enterprise_offer, code=voucher.code, user_email=self.user.email) EdxOrderPlacementMixin().update_assigned_voucher_offer_assignment( order) offer_assignment = OfferAssignment.objects.get(id=offer_assignment.id) assert offer_assignment.status == OFFER_REDEEMED assert offer_assignment.voucher_application == voucher_application