test_queue.py 5.53 KB
Newer Older
1 2 3 4
# -*- coding: utf-8 -*-
"""Tests for the XQueue certificates interface. """
from contextlib import contextmanager
import json
5
from mock import patch, Mock
6
from nose.plugins.attrib import attr
7 8 9 10 11

from django.test import TestCase
from django.test.utils import override_settings

from opaque_keys.edx.locator import CourseLocator
12 13 14 15
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from student.tests.factories import UserFactory, CourseEnrollmentFactory
from xmodule.modulestore.tests.factories import CourseFactory

16 17 18 19 20 21 22 23 24 25 26 27

# It is really unfortunate that we are using the XQueue client
# code from the capa library.  In the future, we should move this
# into a shared library.  We import it here so we can mock it
# and verify that items are being correctly added to the queue
# in our `XQueueCertInterface` implementation.
from capa.xqueue_interface import XQueueInterface

from certificates.queue import XQueueCertInterface
from certificates.models import ExampleCertificateSet, ExampleCertificate


28
@attr('shard_1')
29
@override_settings(CERT_QUEUE='certificates')
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
class XQueueCertInterfaceAddCertificateTest(ModuleStoreTestCase):
    """Test the "add to queue" operation of the XQueue interface. """

    def setUp(self):
        super(XQueueCertInterfaceAddCertificateTest, self).setUp()
        self.user = UserFactory.create()
        self.course = CourseFactory.create()
        self.enrollment = CourseEnrollmentFactory(
            user=self.user,
            course_id=self.course.id,
            is_active=True,
            mode="honor",
        )
        self.xqueue = XQueueCertInterface()

    def test_add_cert_callback_url(self):
        with patch('courseware.grades.grade', Mock(return_value={'grade': 'Pass', 'percent': 0.75})):
            with patch.object(XQueueInterface, 'send_to_queue') as mock_send:
                mock_send.return_value = (0, None)
                self.xqueue.add_cert(self.user, self.course.id)

        # Verify that the task was sent to the queue with the correct callback URL
        self.assertTrue(mock_send.called)
        __, kwargs = mock_send.call_args_list[0]
        actual_header = json.loads(kwargs['header'])
        self.assertIn('https://edx.org/update_certificate?key=', actual_header['lms_callback_url'])

57 58 59 60 61 62 63 64 65 66 67
    def test_no_create_action_in_queue_for_html_view_certs(self):
        """
        Tests there is no certificate create message in the queue if generate_pdf is False
        """
        with patch('courseware.grades.grade', Mock(return_value={'grade': 'Pass', 'percent': 0.75})):
            with patch.object(XQueueInterface, 'send_to_queue') as mock_send:
                self.xqueue.add_cert(self.user, self.course.id, generate_pdf=False)

        # Verify that add_cert method does not add message to queue
        self.assertFalse(mock_send.called)

68

69
@attr('shard_1')
70 71
@override_settings(CERT_QUEUE='certificates')
class XQueueCertInterfaceExampleCertificateTest(TestCase):
72 73 74 75 76 77 78 79 80
    """Tests for the XQueue interface for certificate generation. """

    COURSE_KEY = CourseLocator(org='test', course='test', run='test')

    TEMPLATE = 'test.pdf'
    DESCRIPTION = 'test'
    ERROR_MSG = 'Kaboom!'

    def setUp(self):
81
        super(XQueueCertInterfaceExampleCertificateTest, self).setUp()
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
        self.xqueue = XQueueCertInterface()

    def test_add_example_cert(self):
        cert = self._create_example_cert()
        with self._mock_xqueue() as mock_send:
            self.xqueue.add_example_cert(cert)

        # Verify that the correct payload was sent to the XQueue
        self._assert_queue_task(mock_send, cert)

        # Verify the certificate status
        self.assertEqual(cert.status, ExampleCertificate.STATUS_STARTED)

    def test_add_example_cert_error(self):
        cert = self._create_example_cert()
        with self._mock_xqueue(success=False):
            self.xqueue.add_example_cert(cert)

        # Verify the error status of the certificate
        self.assertEqual(cert.status, ExampleCertificate.STATUS_ERROR)
        self.assertIn(self.ERROR_MSG, cert.error_reason)

    def _create_example_cert(self):
        """Create an example certificate. """
        cert_set = ExampleCertificateSet.objects.create(course_key=self.COURSE_KEY)
        return ExampleCertificate.objects.create(
            example_cert_set=cert_set,
            description=self.DESCRIPTION,
            template=self.TEMPLATE
        )

    @contextmanager
    def _mock_xqueue(self, success=True):
        """Mock the XQueue method for sending a task to the queue. """
        with patch.object(XQueueInterface, 'send_to_queue') as mock_send:
            mock_send.return_value = (0, None) if success else (1, self.ERROR_MSG)
            yield mock_send

    def _assert_queue_task(self, mock_send, cert):
        """Check that the task was added to the queue. """
        expected_header = {
            'lms_key': cert.access_key,
            'lms_callback_url': 'https://edx.org/update_example_certificate?key={key}'.format(key=cert.uuid),
            'queue_name': 'certificates'
        }

        expected_body = {
            'action': 'create',
            'username': cert.uuid,
            'name': u'John Doë',
            'course_id': unicode(self.COURSE_KEY),
            'template_pdf': 'test.pdf',
            'example_certificate': True
        }

        self.assertTrue(mock_send.called)

        __, kwargs = mock_send.call_args_list[0]
        actual_header = json.loads(kwargs['header'])
        actual_body = json.loads(kwargs['body'])

        self.assertEqual(expected_header, actual_header)
        self.assertEqual(expected_body, actual_body)