Commit 0d27b5ed by Renzo Lucioni

Merge pull request #12215 from edx/renzo/program-factory

Retrofit programs data mixin with factories
parents f8f5e703 1ffa81f7
......@@ -4,67 +4,16 @@ Tools to create programs-related data for use in bok choy tests.
from collections import namedtuple
import json
import factory
import requests
from . import PROGRAMS_STUB_URL
from .config import ConfigModelFixture
from openedx.core.djangoapps.programs.tests import factories
FakeProgram = namedtuple('FakeProgram', ['name', 'status', 'org_key', 'course_id'])
class Program(factory.Factory):
"""
Factory for stubbing program resources from the Programs API (v1).
"""
class Meta(object):
model = dict
id = factory.Sequence(lambda n: n) # pylint: disable=invalid-name
name = 'dummy-program-name'
subtitle = 'dummy-program-subtitle'
category = 'xseries'
status = 'unpublished'
marketing_slug = factory.Sequence(lambda n: 'slug-{}'.format(n)) # pylint: disable=unnecessary-lambda
organizations = []
course_codes = []
banner_image_urls = {}
class Organization(factory.Factory):
"""
Factory for stubbing nested organization resources from the Programs API (v1).
"""
class Meta(object):
model = dict
key = 'dummyX'
display_name = 'dummy-org-display-name'
class CourseCode(factory.Factory):
"""
Factory for stubbing nested course code resources from the Programs API (v1).
"""
class Meta(object):
model = dict
display_name = 'dummy-org-display-name'
run_modes = []
class RunMode(factory.Factory):
"""
Factory for stubbing nested run mode resources from the Programs API (v1).
"""
class Meta(object):
model = dict
course_key = 'org/course/run'
mode_slug = 'verified'
class ProgramsFixture(object):
"""
Interface to set up mock responses from the Programs stub server.
......@@ -78,11 +27,11 @@ class ProgramsFixture(object):
"""
programs = []
for program in fake_programs:
run_mode = RunMode(course_key=program.course_id)
course_code = CourseCode(run_modes=[run_mode])
org = Organization(key=program.org_key)
run_mode = factories.RunMode(course_key=program.course_id)
course_code = factories.CourseCode(run_modes=[run_mode])
org = factories.Organization(key=program.org_key)
program = Program(
program = factories.Program(
name=program.name,
status=program.status,
organizations=[org],
......
......@@ -8,7 +8,6 @@ from urlparse import urljoin
from django.conf import settings
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect
from django.test import override_settings
from edx_oauth2_provider.tests.factories import ClientFactory
from opaque_keys.edx import locator
......@@ -39,6 +38,7 @@ class TestProgramListing(
Unit tests for getting the list of programs enrolled by a logged in user
"""
PASSWORD = 'test'
url = reverse('program_listing_view')
def setUp(self):
"""
......@@ -81,10 +81,9 @@ class TestProgramListing(
"""
self.mock_programs_api()
self.client.login(username=self.student.username, password=self.PASSWORD)
response = self.client.get(reverse("program_listing_view"))
self.assertEqual(response.status_code, 200)
response = self.client.get(self.url)
x_series_url = urljoin(settings.MKTG_URLS.get('ROOT'), 'xseries')
self.assertIn(x_series_url, response.content)
self.assertContains(response, x_series_url)
return response
def _get_program_checklist(self, program_id):
......@@ -101,18 +100,18 @@ class TestProgramListing(
def test_get_program_with_no_enrollment(self):
response = self._setup_and_get_program()
for program_element in self._get_program_checklist(0):
self.assertNotIn(program_element, response.content)
self.assertNotContains(response, program_element)
for program_element in self._get_program_checklist(1):
self.assertNotIn(program_element, response.content)
self.assertNotContains(response, program_element)
@httpretty.activate
def test_get_one_program(self):
self._create_course_and_enroll(self.student, *self.COURSE_KEYS[0].split('/'))
response = self._setup_and_get_program()
for program_element in self._get_program_checklist(0):
self.assertIn(program_element, response.content)
self.assertContains(response, program_element)
for program_element in self._get_program_checklist(1):
self.assertNotIn(program_element, response.content)
self.assertNotContains(response, program_element)
@httpretty.activate
def test_get_both_program(self):
......@@ -120,32 +119,34 @@ class TestProgramListing(
self._create_course_and_enroll(self.student, *self.COURSE_KEYS[5].split('/'))
response = self._setup_and_get_program()
for program_element in self._get_program_checklist(0):
self.assertIn(program_element, response.content)
self.assertContains(response, program_element)
for program_element in self._get_program_checklist(1):
self.assertIn(program_element, response.content)
self.assertContains(response, program_element)
def test_get_programs_dashboard_not_enabled(self):
self.create_programs_config(program_listing_enabled=False)
self.client.login(username=self.student.username, password=self.PASSWORD)
response = self.client.get(reverse("program_listing_view"))
response = self.client.get(self.url)
self.assertEqual(response.status_code, 404)
def test_xseries_advertise_disabled(self):
self.create_programs_config(program_listing_enabled=True, xseries_ad_enabled=False)
self.client.login(username=self.student.username, password=self.PASSWORD)
response = self.client.get(reverse("program_listing_view"))
self.assertEqual(response.status_code, 200)
response = self.client.get(self.url)
x_series_url = urljoin(settings.MKTG_URLS.get('ROOT'), 'xseries')
self.assertNotIn(x_series_url, response.content)
self.assertNotContains(response, x_series_url)
def test_get_programs_not_logged_in(self):
self.create_programs_config()
response = self.client.get(reverse("program_listing_view"))
self.assertEqual(response.status_code, 302)
self.assertIsInstance(response, HttpResponseRedirect)
self.assertIn('login', response.url) # pylint: disable=no-member
response = self.client.get(self.url)
def _expected_credetials_data(self):
self.assertRedirects(
response,
'{}?next={}'.format(reverse('signin_user'), self.url)
)
# TODO: Use a factory to generate this data.
def _expected_credentials_data(self):
""" Dry method for getting expected credentials."""
return [
......@@ -172,13 +173,11 @@ class TestProgramListing(
self.mock_credentials_api(self.student, data=self.CREDENTIALS_API_RESPONSE, reset_url=False)
response = self.client.get(reverse("program_listing_view"))
self.assertEqual(response.status_code, 200)
for certificate in self._expected_credentials_data():
self.assertContains(response, certificate['display_name'])
self.assertContains(response, certificate['credential_url'])
for certificate in self._expected_credetials_data():
self.assertIn(certificate['display_name'], response.content)
self.assertIn(certificate['credential_url'], response.content)
self.assertIn('images/xseries-certificate-visual.png', response.content)
self.assertContains(response, 'images/xseries-certificate-visual.png')
@httpretty.activate
def test_get_xseries_certificates_without_data(self):
......@@ -193,8 +192,6 @@ class TestProgramListing(
self.mock_credentials_api(self.student, data={"results": []}, reset_url=False)
response = self.client.get(reverse("program_listing_view"))
self.assertEqual(response.status_code, 200)
for certificate in self._expected_credetials_data():
self.assertNotIn(certificate['display_name'], response.content)
self.assertNotIn(certificate['credential_url'], response.content)
for certificate in self._expected_credentials_data():
self.assertNotContains(response, certificate['display_name'])
self.assertNotContains(response, certificate['credential_url'])
"""Factories for generating fake program-related data."""
import factory
from factory.fuzzy import FuzzyText
class Program(factory.Factory):
"""
Factory for stubbing program resources from the Programs API (v1).
"""
class Meta(object):
model = dict
id = factory.Sequence(lambda n: n) # pylint: disable=invalid-name
name = FuzzyText(prefix='Program ')
subtitle = FuzzyText(prefix='Subtitle ')
category = 'xseries'
status = 'unpublished'
marketing_slug = FuzzyText(prefix='slug_')
organizations = []
course_codes = []
banner_image_urls = {}
class Organization(factory.Factory):
"""
Factory for stubbing nested organization resources from the Programs API (v1).
"""
class Meta(object):
model = dict
key = FuzzyText(prefix='org_')
display_name = FuzzyText(prefix='Display Name ')
class CourseCode(factory.Factory):
"""
Factory for stubbing nested course code resources from the Programs API (v1).
"""
class Meta(object):
model = dict
display_name = FuzzyText(prefix='Display Name ')
run_modes = []
class RunMode(factory.Factory):
"""
Factory for stubbing nested run mode resources from the Programs API (v1).
"""
class Meta(object):
model = dict
course_key = FuzzyText(prefix='org/', suffix='/run')
mode_slug = 'verified'
......@@ -4,6 +4,7 @@ import json
import httpretty
from openedx.core.djangoapps.programs.models import ProgramsApiConfig
from openedx.core.djangoapps.programs.tests import factories
class ProgramsApiConfigMixin(object):
......@@ -50,176 +51,48 @@ class ProgramsDataMixin(object):
'organization-b/course-d/winter',
]
# TODO: Use factory-boy.
PROGRAMS_API_RESPONSE = {
'results': [
{
'id': 1,
'name': PROGRAM_NAMES[0],
'subtitle': 'A program used for testing purposes',
'category': 'xseries',
'status': 'unpublished',
'marketing_slug': '{}_test_url'.format(PROGRAM_NAMES[0].replace(' ', '_')),
'organizations': [
{
'display_name': 'Test Organization A',
'key': 'organization-a'
}
],
'course_codes': [
{
'display_name': 'Test Course A',
'key': 'course-a',
'organization': {
'display_name': 'Test Organization A',
'key': 'organization-a'
},
'run_modes': [
{
'course_key': COURSE_KEYS[0],
'mode_slug': 'verified',
'sku': '',
'start_date': '2015-11-05T07:39:02.791741Z',
'run_key': 'fall'
},
{
'course_key': COURSE_KEYS[1],
'mode_slug': 'verified',
'sku': '',
'start_date': '2015-11-05T07:39:02.791741Z',
'run_key': 'winter'
}
]
},
{
'display_name': 'Test Course B',
'key': 'course-b',
'organization': {
'display_name': 'Test Organization A',
'key': 'organization-a'
},
'run_modes': [
{
'course_key': COURSE_KEYS[2],
'mode_slug': 'verified',
'sku': '',
'start_date': '2015-11-05T07:39:02.791741Z',
'run_key': 'fall'
},
{
'course_key': COURSE_KEYS[3],
'mode_slug': 'verified',
'sku': '',
'start_date': '2015-11-05T07:39:02.791741Z',
'run_key': 'winter'
}
]
}
],
'created': '2015-10-26T17:52:32.861000Z',
'modified': '2015-11-18T22:21:30.826365Z'
},
{
'id': 2,
'name': PROGRAM_NAMES[1],
'subtitle': 'Another program used for testing purposes',
'category': 'xseries',
'status': 'unpublished',
'marketing_slug': '{}_test_url'.format(PROGRAM_NAMES[1].replace(' ', '_')),
'organizations': [
{
'display_name': 'Test Organization B',
'key': 'organization-b'
}
],
'course_codes': [
{
'display_name': 'Test Course C',
'key': 'course-c',
'organization': {
'display_name': 'Test Organization B',
'key': 'organization-b'
},
'run_modes': [
{
'course_key': COURSE_KEYS[4],
'mode_slug': 'verified',
'sku': '',
'start_date': '2015-11-05T07:39:02.791741Z',
'run_key': 'fall'
},
{
'course_key': COURSE_KEYS[5],
'mode_slug': 'verified',
'sku': '',
'start_date': '2015-11-05T07:39:02.791741Z',
'run_key': 'winter'
}
]
},
{
'display_name': 'Test Course D',
'key': 'course-d',
'organization': {
'display_name': 'Test Organization B',
'key': 'organization-b'
},
'run_modes': [
{
'course_key': COURSE_KEYS[6],
'mode_slug': 'verified',
'sku': '',
'start_date': '2015-11-05T07:39:02.791741Z',
'run_key': 'fall'
},
{
'course_key': COURSE_KEYS[7],
'mode_slug': 'verified',
'sku': '',
'start_date': '2015-11-05T07:39:02.791741Z',
'run_key': 'winter'
}
]
}
],
'created': '2015-10-26T19:59:03.064000Z',
'modified': '2015-10-26T19:59:18.536000Z'
},
{
'id': 3,
'name': PROGRAM_NAMES[2],
'subtitle': 'A third program used for testing purposes',
'category': 'xseries',
'status': 'unpublished',
'marketing_slug': '{}_test_url'.format(PROGRAM_NAMES[2].replace(' ', '_')),
'organizations': [
{
'display_name': 'Test Organization B',
'key': 'organization-b'
}
],
'course_codes': [
{
'display_name': 'Test Course D',
'key': 'course-d',
'organization': {
'display_name': 'Test Organization B',
'key': 'organization-b'
},
'run_modes': [
{
'course_key': COURSE_KEYS[7],
'mode_slug': 'verified',
'sku': '',
'start_date': '2015-11-05T07:39:02.791741Z',
'run_key': 'winter'
}
]
}
],
'created': '2015-10-26T19:59:03.064000Z',
'modified': '2015-10-26T19:59:18.536000Z'
}
factories.Program(
id=1,
name=PROGRAM_NAMES[0],
organizations=[factories.Organization()],
course_codes=[
factories.CourseCode(run_modes=[
factories.RunMode(course_key=COURSE_KEYS[0]),
factories.RunMode(course_key=COURSE_KEYS[1]),
]),
factories.CourseCode(run_modes=[
factories.RunMode(course_key=COURSE_KEYS[2]),
factories.RunMode(course_key=COURSE_KEYS[3]),
]),
]
),
factories.Program(
id=2,
name=PROGRAM_NAMES[1],
organizations=[factories.Organization()],
course_codes=[
factories.CourseCode(run_modes=[
factories.RunMode(course_key=COURSE_KEYS[4]),
factories.RunMode(course_key=COURSE_KEYS[5]),
]),
factories.CourseCode(run_modes=[
factories.RunMode(course_key=COURSE_KEYS[6]),
factories.RunMode(course_key=COURSE_KEYS[7]),
]),
]
),
factories.Program(
id=3,
name=PROGRAM_NAMES[2],
organizations=[factories.Organization()],
course_codes=[
factories.CourseCode(run_modes=[
factories.RunMode(course_key=COURSE_KEYS[7]),
]),
]
),
]
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment