test_api.py 6.7 KB
Newer Older
Nimisha Asthagiri committed
1 2 3 4
"""
Tests for Blocks api.py
"""

5 6
from itertools import product

7
import ddt
Nimisha Asthagiri committed
8
from django.test.client import RequestFactory
9

10
from openedx.core.djangoapps.content.block_structure.api import clear_course_from_cache
11
from openedx.core.djangoapps.content.block_structure.config import STORAGE_BACKING_FOR_CACHE, waffle
Nimisha Asthagiri committed
12
from student.tests.factories import UserFactory
13 14
from xmodule.modulestore import ModuleStoreEnum
from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase
15
from xmodule.modulestore.tests.factories import SampleCourseFactory, check_mongo_calls
Nimisha Asthagiri committed
16 17 18 19

from ..api import get_blocks


20
class TestGetBlocks(SharedModuleStoreTestCase):
Nimisha Asthagiri committed
21 22 23
    """
    Tests for the get_blocks function
    """
24 25 26
    @classmethod
    def setUpClass(cls):
        super(TestGetBlocks, cls).setUpClass()
27 28
        with cls.store.default_store(ModuleStoreEnum.Type.split):
            cls.course = SampleCourseFactory.create()
29 30 31 32 33 34

        # hide the html block
        cls.html_block = cls.store.get_item(cls.course.id.make_usage_key('html', 'html_x1a_1'))
        cls.html_block.visible_to_staff_only = True
        cls.store.update_item(cls.html_block, ModuleStoreEnum.UserID.test)

Nimisha Asthagiri committed
35 36 37 38 39 40 41 42
    def setUp(self):
        super(TestGetBlocks, self).setUp()
        self.user = UserFactory.create()
        self.request = RequestFactory().get("/dummy")
        self.request.user = self.user

    def test_basic(self):
        blocks = get_blocks(self.request, self.course.location, self.user)
lenacom committed
43
        self.assertEquals(blocks['root'], unicode(self.course.location))
44 45 46 47

        # subtract for (1) the orphaned course About block and (2) the hidden Html block
        self.assertEquals(len(blocks['blocks']), len(self.store.get_items(self.course.id)) - 2)
        self.assertNotIn(unicode(self.html_block.location), blocks['blocks'])
Nimisha Asthagiri committed
48 49

    def test_no_user(self):
50 51
        blocks = get_blocks(self.request, self.course.location)
        self.assertIn(unicode(self.html_block.location), blocks['blocks'])
52 53 54 55 56 57 58 59 60 61 62 63 64 65

    def test_access_before_api_transformer_order(self):
        """
        Tests the order of transformers: access checks are made before the api
        transformer is applied.
        """
        blocks = get_blocks(self.request, self.course.location, self.user, nav_depth=5, requested_fields=['nav_depth'])
        vertical_block = self.store.get_item(self.course.id.make_usage_key('vertical', 'vertical_x1a'))
        problem_block = self.store.get_item(self.course.id.make_usage_key('problem', 'problem_x1a_1'))

        vertical_descendants = blocks['blocks'][unicode(vertical_block.location)]['descendants']

        self.assertIn(unicode(problem_block.location), vertical_descendants)
        self.assertNotIn(unicode(self.html_block.location), vertical_descendants)
66 67 68 69 70

    def test_sub_structure(self):
        sequential_block = self.store.get_item(self.course.id.make_usage_key('sequential', 'sequential_y1'))

        blocks = get_blocks(self.request, sequential_block.location, self.user)
lenacom committed
71
        self.assertEquals(blocks['root'], unicode(sequential_block.location))
72 73 74 75 76 77 78 79 80 81 82 83 84
        self.assertEquals(len(blocks['blocks']), 5)

        for block_type, block_name, is_inside_of_structure in (
                ('vertical', 'vertical_y1a', True),
                ('problem', 'problem_y1a_1', True),
                ('chapter', 'chapter_y', False),
                ('sequential', 'sequential_x1', False),
        ):
            block = self.store.get_item(self.course.id.make_usage_key(block_type, block_name))
            if is_inside_of_structure:
                self.assertIn(unicode(block.location), blocks['blocks'])
            else:
                self.assertNotIn(unicode(block.location), blocks['blocks'])
85 86 87 88

    def test_filtering_by_block_types(self):
        sequential_block = self.store.get_item(self.course.id.make_usage_key('sequential', 'sequential_y1'))

lenacom committed
89
        # not filtered blocks
lenacom committed
90
        blocks = get_blocks(self.request, sequential_block.location, self.user, requested_fields=['type'])
lenacom committed
91 92
        self.assertEquals(len(blocks['blocks']), 5)
        found_not_problem = False
lenacom committed
93 94
        for block in blocks['blocks'].itervalues():
            if block['type'] != 'problem':
lenacom committed
95 96 97 98
                found_not_problem = True
        self.assertTrue(found_not_problem)

        # filtered blocks
lenacom committed
99 100
        blocks = get_blocks(self.request, sequential_block.location, self.user,
                            block_types_filter=['problem'], requested_fields=['type'])
lenacom committed
101
        self.assertEquals(len(blocks['blocks']), 3)
lenacom committed
102 103
        for block in blocks['blocks'].itervalues():
            self.assertEqual(block['type'], 'problem')
104 105 106 107 108 109 110


@ddt.ddt
class TestGetBlocksQueryCounts(SharedModuleStoreTestCase):
    """
    Tests query counts for the get_blocks function.
    """
111 112
    ENABLED_SIGNALS = ['course_published']

113 114 115 116 117 118 119 120 121 122 123 124 125 126
    def setUp(self):
        super(TestGetBlocksQueryCounts, self).setUp()

        self.user = UserFactory.create()
        self.request = RequestFactory().get("/dummy")
        self.request.user = self.user

    def _create_course(self, store_type):
        """
        Creates the sample course in the given store type.
        """
        with self.store.default_store(store_type):
            return SampleCourseFactory.create()

127
    def _get_blocks(self, course, expected_mongo_queries, expected_sql_queries):
128 129 130 131 132
        """
        Verifies the number of expected queries when calling
        get_blocks on the given course.
        """
        with check_mongo_calls(expected_mongo_queries):
133
            with self.assertNumQueries(expected_sql_queries):
134 135
                get_blocks(self.request, course.location, self.user)

136 137 138 139 140 141 142 143
    @ddt.data(
        *product(
            (ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split),
            (True, False),
        )
    )
    @ddt.unpack
    def test_query_counts_cached(self, store_type, with_storage_backing):
144
        with waffle().override(STORAGE_BACKING_FOR_CACHE, active=with_storage_backing):
145 146 147 148
            course = self._create_course(store_type)
            self._get_blocks(
                course,
                expected_mongo_queries=0,
149
                expected_sql_queries=6 if with_storage_backing else 5,
150
            )
151 152

    @ddt.data(
153 154 155 156
        *product(
            ((ModuleStoreEnum.Type.mongo, 5), (ModuleStoreEnum.Type.split, 3)),
            (True, False),
        )
157 158
    )
    @ddt.unpack
159 160
    def test_query_counts_uncached(self, store_type_tuple, with_storage_backing):
        store_type, expected_mongo_queries = store_type_tuple
161
        with waffle().override(STORAGE_BACKING_FOR_CACHE, active=with_storage_backing):
162 163 164 165 166
            course = self._create_course(store_type)
            clear_course_from_cache(course.id)
            self._get_blocks(
                course,
                expected_mongo_queries,
167
                expected_sql_queries=14 if with_storage_backing else 6,
168
            )