Files
edx-platform/lms/djangoapps/teams/tests/test_serializers.py
2015-08-19 10:52:50 -04:00

224 lines
8.8 KiB
Python

# -*- coding: utf-8 -*-
"""
Tests for custom Teams Serializers.
"""
from django.core.paginator import Paginator
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory
from lms.djangoapps.teams.tests.factories import CourseTeamFactory
from lms.djangoapps.teams.serializers import (
BaseTopicSerializer, PaginatedTopicSerializer, BulkTeamCountPaginatedTopicSerializer,
TopicSerializer, add_team_count
)
class TopicTestCase(ModuleStoreTestCase):
"""
Base test class to set up a course with topics
"""
def setUp(self):
"""
Set up a course with a teams configuration.
"""
super(TopicTestCase, self).setUp()
self.course = CourseFactory.create(
teams_configuration={
"max_team_size": 10,
"topics": [{u'name': u'Tøpic', u'description': u'The bést topic!', u'id': u'0'}]
}
)
class BaseTopicSerializerTestCase(TopicTestCase):
"""
Tests for the `BaseTopicSerializer`, which should not serialize team count
data.
"""
def test_team_count_not_included(self):
"""Verifies that the `BaseTopicSerializer` does not include team count"""
with self.assertNumQueries(0):
serializer = BaseTopicSerializer(self.course.teams_topics[0])
self.assertEqual(
serializer.data,
{u'name': u'Tøpic', u'description': u'The bést topic!', u'id': u'0'}
)
class TopicSerializerTestCase(TopicTestCase):
"""
Tests for the `TopicSerializer`, which should serialize team count data for
a single topic.
"""
def test_topic_with_no_team_count(self):
"""
Verifies that the `TopicSerializer` correctly displays a topic with a
team count of 0, and that it only takes one SQL query.
"""
with self.assertNumQueries(1):
serializer = TopicSerializer(self.course.teams_topics[0], context={'course_id': self.course.id})
self.assertEqual(
serializer.data,
{u'name': u'Tøpic', u'description': u'The bést topic!', u'id': u'0', u'team_count': 0}
)
def test_topic_with_team_count(self):
"""
Verifies that the `TopicSerializer` correctly displays a topic with a
positive team count, and that it only takes one SQL query.
"""
CourseTeamFactory.create(course_id=self.course.id, topic_id=self.course.teams_topics[0]['id'])
with self.assertNumQueries(1):
serializer = TopicSerializer(self.course.teams_topics[0], context={'course_id': self.course.id})
self.assertEqual(
serializer.data,
{u'name': u'Tøpic', u'description': u'The bést topic!', u'id': u'0', u'team_count': 1}
)
def test_scoped_within_course(self):
"""Verify that team count is scoped within a course."""
duplicate_topic = self.course.teams_topics[0]
second_course = CourseFactory.create(
teams_configuration={
"max_team_size": 10,
"topics": [duplicate_topic]
}
)
CourseTeamFactory.create(course_id=self.course.id, topic_id=duplicate_topic[u'id'])
CourseTeamFactory.create(course_id=second_course.id, topic_id=duplicate_topic[u'id'])
with self.assertNumQueries(1):
serializer = TopicSerializer(self.course.teams_topics[0], context={'course_id': self.course.id})
self.assertEqual(
serializer.data,
{u'name': u'Tøpic', u'description': u'The bést topic!', u'id': u'0', u'team_count': 1}
)
class BasePaginatedTopicSerializerTestCase(TopicTestCase):
"""
Base class for testing the two paginated topic serializers.
"""
__test__ = False
PAGE_SIZE = 5
# Extending test classes should specify their serializer class.
serializer = None
def _merge_dicts(self, first, second):
"""Convenience method to merge two dicts in a single expression"""
result = first.copy()
result.update(second)
return result
def setup_topics(self, num_topics=5, teams_per_topic=0):
"""
Helper method to set up topics on the course. Returns a list of
created topics.
"""
self.course.teams_configuration['topics'] = []
topics = [
{u'name': u'Tøpic {}'.format(i), u'description': u'The bést topic! {}'.format(i), u'id': unicode(i)}
for i in xrange(num_topics)
]
for i in xrange(num_topics):
topic_id = unicode(i)
self.course.teams_configuration['topics'].append(topics[i])
for _ in xrange(teams_per_topic):
CourseTeamFactory.create(course_id=self.course.id, topic_id=topic_id)
return topics
def assert_serializer_output(self, topics, num_teams_per_topic, num_queries):
"""
Verify that the serializer produced the expected topics.
"""
with self.assertNumQueries(num_queries):
page = Paginator(self.course.teams_topics, self.PAGE_SIZE).page(1)
# pylint: disable=not-callable
serializer = self.serializer(instance=page, context={'course_id': self.course.id})
self.assertEqual(
serializer.data['results'],
[self._merge_dicts(topic, {u'team_count': num_teams_per_topic}) for topic in topics]
)
def test_no_topics(self):
"""
Verify that we return no results and make no SQL queries for a page
with no topics.
"""
self.course.teams_configuration['topics'] = []
self.assert_serializer_output([], num_teams_per_topic=0, num_queries=0)
class BulkTeamCountPaginatedTopicSerializerTestCase(BasePaginatedTopicSerializerTestCase):
"""
Tests for the `BulkTeamCountPaginatedTopicSerializer`, which should serialize team_count
data for many topics with constant time SQL queries.
"""
__test__ = True
serializer = BulkTeamCountPaginatedTopicSerializer
def test_topics_with_no_team_counts(self):
"""
Verify that we serialize topics with no team count, making only one SQL
query.
"""
topics = self.setup_topics(teams_per_topic=0)
self.assert_serializer_output(topics, num_teams_per_topic=0, num_queries=1)
def test_topics_with_team_counts(self):
"""
Verify that we serialize topics with a positive team count, making only
one SQL query.
"""
teams_per_topic = 10
topics = self.setup_topics(teams_per_topic=teams_per_topic)
self.assert_serializer_output(topics, num_teams_per_topic=teams_per_topic, num_queries=1)
def test_subset_of_topics(self):
"""
Verify that we serialize a subset of the course's topics, making only
one SQL query.
"""
teams_per_topic = 10
topics = self.setup_topics(num_topics=self.PAGE_SIZE + 1, teams_per_topic=teams_per_topic)
self.assert_serializer_output(topics[:self.PAGE_SIZE], num_teams_per_topic=teams_per_topic, num_queries=1)
def test_scoped_within_course(self):
"""Verify that team counts are scoped within a course."""
teams_per_topic = 10
first_course_topics = self.setup_topics(num_topics=self.PAGE_SIZE, teams_per_topic=teams_per_topic)
duplicate_topic = first_course_topics[0]
second_course = CourseFactory.create(
teams_configuration={
"max_team_size": 10,
"topics": [duplicate_topic]
}
)
CourseTeamFactory.create(course_id=second_course.id, topic_id=duplicate_topic[u'id'])
self.assert_serializer_output(first_course_topics, num_teams_per_topic=teams_per_topic, num_queries=1)
class PaginatedTopicSerializerTestCase(BasePaginatedTopicSerializerTestCase):
"""
Tests for the `PaginatedTopicSerializer`, which will add team_count information per topic if not present.
"""
__test__ = True
serializer = PaginatedTopicSerializer
def test_topics_with_team_counts(self):
"""
Verify that we serialize topics with team_count, making one SQL query per topic.
"""
teams_per_topic = 2
topics = self.setup_topics(teams_per_topic=teams_per_topic)
self.assert_serializer_output(topics, num_teams_per_topic=teams_per_topic, num_queries=5)
def test_topics_with_team_counts_prepopulated(self):
"""
Verify that if team_count is pre-populated, there are no additional SQL queries.
"""
teams_per_topic = 8
topics = self.setup_topics(teams_per_topic=teams_per_topic)
add_team_count(topics, self.course.id)
self.assert_serializer_output(topics, num_teams_per_topic=teams_per_topic, num_queries=0)