helpers.py 6.69 KB
Newer Older
1 2 3 4
import json

from django.contrib.auth.models import User
from django.core.urlresolvers import reverse
5
from django.test import TestCase
6
from django.test.client import RequestFactory
7

8 9
from courseware.access import has_access, COURSE_OVERVIEW_SUPPORTED_ACTIONS
from openedx.core.djangoapps.content.course_overviews.models import CourseOverview
10 11 12
from student.models import Registration


13 14 15 16
def get_request_for_user(user):
    """Create a request object for user."""
    request = RequestFactory()
    request.user = user
17
    request.COOKIES = {}
18 19 20
    request.META = {}
    request.is_secure = lambda: True
    request.get_host = lambda: "edx.org"
21
    request.method = 'GET'
22
    return request
23 24 25


class LoginEnrollmentTestCase(TestCase):
26 27 28 29
    """
    Provides support for user creation,
    activation, login, and course enrollment.
    """
30 31
    user = None

32 33 34 35 36 37 38
    def setup_user(self):
        """
        Create a user account, activate, and log in.
        """
        self.email = 'foo@test.com'
        self.password = 'bar'
        self.username = 'test'
39 40 41 42 43
        self.user = self.create_account(
            self.username,
            self.email,
            self.password,
        )
44 45 46
        self.activate_user(self.email)
        self.login(self.email, self.password)

47 48 49 50 51 52 53 54 55 56 57 58 59
    def assert_request_status_code(self, status_code, url, method="GET", **kwargs):
        make_request = getattr(self.client, method.lower())
        response = make_request(url, **kwargs)
        self.assertEqual(
            response.status_code, status_code,
            "{method} request to {url} returned status code {actual}, "
            "expected status code {expected}".format(
                method=method, url=url,
                actual=response.status_code, expected=status_code
            )
        )
        return response

60 61 62 63 64 65
    # ============ User creation and login ==============

    def login(self, email, password):
        """
        Login, check that the corresponding view's response has a 200 status code.
        """
66 67
        resp = self.client.post(reverse('login'),
                                {'email': email, 'password': password})
68 69 70 71 72 73
        self.assertEqual(resp.status_code, 200)
        data = json.loads(resp.content)
        self.assertTrue(data['success'])

    def logout(self):
        """
74 75
        Logout; check that the HTTP response code indicates redirection
        as expected.
76 77
        """
        # should redirect
78
        self.assert_request_status_code(302, reverse('logout'))
79 80 81 82 83

    def create_account(self, username, email, password):
        """
        Create the account and check that it worked.
        """
84 85
        url = reverse('create_account')
        request_data = {
86 87 88 89 90 91
            'username': username,
            'email': email,
            'password': password,
            'name': 'username',
            'terms_of_service': 'true',
            'honor_code': 'true',
92 93
        }
        resp = self.assert_request_status_code(200, url, method="POST", data=request_data)
94 95 96
        data = json.loads(resp.content)
        self.assertEqual(data['success'], True)
        # Check both that the user is created, and inactive
97 98 99
        user = User.objects.get(email=email)
        self.assertFalse(user.is_active)
        return user
100 101 102 103 104 105 106 107

    def activate_user(self, email):
        """
        Look up the activation key for the user, then hit the activate view.
        No error checking.
        """
        activation_key = Registration.objects.get(user__email=email).activation_key
        # and now we try to activate
108 109
        url = reverse('activate', kwargs={'key': activation_key})
        self.assert_request_status_code(200, url)
110 111 112 113 114 115
        # Now make sure that the user is now actually activated
        self.assertTrue(User.objects.get(email=email).is_active)

    def enroll(self, course, verify=False):
        """
        Try to enroll and return boolean indicating result.
116
        `course` is an instance of CourseDescriptor.
117
        `verify` is an optional boolean parameter specifying whether we
118 119 120 121 122
        want to verify that the student was successfully enrolled
        in the course.
        """
        resp = self.client.post(reverse('change_enrollment'), {
            'enrollment_action': 'enroll',
123
            'course_id': course.id.to_deprecated_string(),
Julia Hansbrough committed
124
            'check_access': True,
125 126 127 128 129 130 131 132 133
        })
        result = resp.status_code == 200
        if verify:
            self.assertTrue(result)
        return result

    def unenroll(self, course):
        """
        Unenroll the currently logged-in user, and check that it worked.
134
        `course` is an instance of CourseDescriptor.
135
        """
136 137
        url = reverse('change_enrollment')
        request_data = {
138
            'enrollment_action': 'unenroll',
139 140 141
            'course_id': course.id.to_deprecated_string(),
        }
        self.assert_request_status_code(200, url, method="POST", data=request_data)
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188


class CourseAccessTestMixin(TestCase):
    """
    Utility mixin for asserting access (or lack thereof) to courses.
    If relevant, also checks access for courses' corresponding CourseOverviews.
    """

    def assertCanAccessCourse(self, user, action, course):
        """
        Assert that a user has access to the given action for a given course.

        Test with both the given course and, if the action is supported, with
        a CourseOverview of the given course.

        Arguments:
            user (User): a user.
            action (str): type of access to test.
                See access.py:COURSE_OVERVIEW_SUPPORTED_ACTIONS.
            course (CourseDescriptor): a course.
        """
        self.assertTrue(has_access(user, action, course))
        if action in COURSE_OVERVIEW_SUPPORTED_ACTIONS:
            self.assertTrue(has_access(user, action, CourseOverview.get_from_id(course.id)))

    def assertCannotAccessCourse(self, user, action, course):
        """
        Assert that a user lacks access to the given action the given course.

        Test with both the given course and, if the action is supported, with
        a CourseOverview of the given course.

        Arguments:
            user (User): a user.
            action (str): type of access to test.
                See access.py:COURSE_OVERVIEW_SUPPORTED_ACTIONS.
            course (CourseDescriptor): a course.

        Note:
            It may seem redundant to have one method for testing access
            and another method for testing lack thereof (why not just combine
            them into one method with a boolean flag?), but it makes reading
            stack traces of failed tests easier to understand at a glance.
        """
        self.assertFalse(has_access(user, action, course))
        if action in COURSE_OVERVIEW_SUPPORTED_ACTIONS:
            self.assertFalse(has_access(user, action, CourseOverview.get_from_id(course.id)))