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. ...@@ -4,67 +4,16 @@ Tools to create programs-related data for use in bok choy tests.
from collections import namedtuple from collections import namedtuple
import json import json
import factory
import requests import requests
from . import PROGRAMS_STUB_URL from . import PROGRAMS_STUB_URL
from .config import ConfigModelFixture from .config import ConfigModelFixture
from openedx.core.djangoapps.programs.tests import factories
FakeProgram = namedtuple('FakeProgram', ['name', 'status', 'org_key', 'course_id']) 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): class ProgramsFixture(object):
""" """
Interface to set up mock responses from the Programs stub server. Interface to set up mock responses from the Programs stub server.
...@@ -78,11 +27,11 @@ class ProgramsFixture(object): ...@@ -78,11 +27,11 @@ class ProgramsFixture(object):
""" """
programs = [] programs = []
for program in fake_programs: for program in fake_programs:
run_mode = RunMode(course_key=program.course_id) run_mode = factories.RunMode(course_key=program.course_id)
course_code = CourseCode(run_modes=[run_mode]) course_code = factories.CourseCode(run_modes=[run_mode])
org = Organization(key=program.org_key) org = factories.Organization(key=program.org_key)
program = Program( program = factories.Program(
name=program.name, name=program.name,
status=program.status, status=program.status,
organizations=[org], organizations=[org],
......
...@@ -8,7 +8,6 @@ from urlparse import urljoin ...@@ -8,7 +8,6 @@ from urlparse import urljoin
from django.conf import settings from django.conf import settings
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect
from django.test import override_settings from django.test import override_settings
from edx_oauth2_provider.tests.factories import ClientFactory from edx_oauth2_provider.tests.factories import ClientFactory
from opaque_keys.edx import locator from opaque_keys.edx import locator
...@@ -39,6 +38,7 @@ class TestProgramListing( ...@@ -39,6 +38,7 @@ class TestProgramListing(
Unit tests for getting the list of programs enrolled by a logged in user Unit tests for getting the list of programs enrolled by a logged in user
""" """
PASSWORD = 'test' PASSWORD = 'test'
url = reverse('program_listing_view')
def setUp(self): def setUp(self):
""" """
...@@ -81,10 +81,9 @@ class TestProgramListing( ...@@ -81,10 +81,9 @@ class TestProgramListing(
""" """
self.mock_programs_api() self.mock_programs_api()
self.client.login(username=self.student.username, password=self.PASSWORD) 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, 200)
x_series_url = urljoin(settings.MKTG_URLS.get('ROOT'), 'xseries') 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 return response
def _get_program_checklist(self, program_id): def _get_program_checklist(self, program_id):
...@@ -101,18 +100,18 @@ class TestProgramListing( ...@@ -101,18 +100,18 @@ class TestProgramListing(
def test_get_program_with_no_enrollment(self): def test_get_program_with_no_enrollment(self):
response = self._setup_and_get_program() response = self._setup_and_get_program()
for program_element in self._get_program_checklist(0): 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): for program_element in self._get_program_checklist(1):
self.assertNotIn(program_element, response.content) self.assertNotContains(response, program_element)
@httpretty.activate @httpretty.activate
def test_get_one_program(self): def test_get_one_program(self):
self._create_course_and_enroll(self.student, *self.COURSE_KEYS[0].split('/')) self._create_course_and_enroll(self.student, *self.COURSE_KEYS[0].split('/'))
response = self._setup_and_get_program() response = self._setup_and_get_program()
for program_element in self._get_program_checklist(0): 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): for program_element in self._get_program_checklist(1):
self.assertNotIn(program_element, response.content) self.assertNotContains(response, program_element)
@httpretty.activate @httpretty.activate
def test_get_both_program(self): def test_get_both_program(self):
...@@ -120,32 +119,34 @@ class TestProgramListing( ...@@ -120,32 +119,34 @@ class TestProgramListing(
self._create_course_and_enroll(self.student, *self.COURSE_KEYS[5].split('/')) self._create_course_and_enroll(self.student, *self.COURSE_KEYS[5].split('/'))
response = self._setup_and_get_program() response = self._setup_and_get_program()
for program_element in self._get_program_checklist(0): 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): 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): def test_get_programs_dashboard_not_enabled(self):
self.create_programs_config(program_listing_enabled=False) self.create_programs_config(program_listing_enabled=False)
self.client.login(username=self.student.username, password=self.PASSWORD) 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) self.assertEqual(response.status_code, 404)
def test_xseries_advertise_disabled(self): def test_xseries_advertise_disabled(self):
self.create_programs_config(program_listing_enabled=True, xseries_ad_enabled=False) self.create_programs_config(program_listing_enabled=True, xseries_ad_enabled=False)
self.client.login(username=self.student.username, password=self.PASSWORD) 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, 200)
x_series_url = urljoin(settings.MKTG_URLS.get('ROOT'), 'xseries') 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): def test_get_programs_not_logged_in(self):
self.create_programs_config() self.create_programs_config()
response = self.client.get(reverse("program_listing_view")) response = self.client.get(self.url)
self.assertEqual(response.status_code, 302)
self.assertIsInstance(response, HttpResponseRedirect)
self.assertIn('login', response.url) # pylint: disable=no-member
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.""" """ Dry method for getting expected credentials."""
return [ return [
...@@ -172,13 +173,11 @@ class TestProgramListing( ...@@ -172,13 +173,11 @@ class TestProgramListing(
self.mock_credentials_api(self.student, data=self.CREDENTIALS_API_RESPONSE, reset_url=False) self.mock_credentials_api(self.student, data=self.CREDENTIALS_API_RESPONSE, reset_url=False)
response = self.client.get(reverse("program_listing_view")) 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.assertContains(response, 'images/xseries-certificate-visual.png')
self.assertIn(certificate['display_name'], response.content)
self.assertIn(certificate['credential_url'], response.content)
self.assertIn('images/xseries-certificate-visual.png', response.content)
@httpretty.activate @httpretty.activate
def test_get_xseries_certificates_without_data(self): def test_get_xseries_certificates_without_data(self):
...@@ -193,8 +192,6 @@ class TestProgramListing( ...@@ -193,8 +192,6 @@ class TestProgramListing(
self.mock_credentials_api(self.student, data={"results": []}, reset_url=False) self.mock_credentials_api(self.student, data={"results": []}, reset_url=False)
response = self.client.get(reverse("program_listing_view")) response = self.client.get(reverse("program_listing_view"))
self.assertEqual(response.status_code, 200) for certificate in self._expected_credentials_data():
self.assertNotContains(response, certificate['display_name'])
for certificate in self._expected_credetials_data(): self.assertNotContains(response, certificate['credential_url'])
self.assertNotIn(certificate['display_name'], response.content)
self.assertNotIn(certificate['credential_url'], response.content)
"""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 ...@@ -4,6 +4,7 @@ import json
import httpretty import httpretty
from openedx.core.djangoapps.programs.models import ProgramsApiConfig from openedx.core.djangoapps.programs.models import ProgramsApiConfig
from openedx.core.djangoapps.programs.tests import factories
class ProgramsApiConfigMixin(object): class ProgramsApiConfigMixin(object):
...@@ -50,176 +51,48 @@ class ProgramsDataMixin(object): ...@@ -50,176 +51,48 @@ class ProgramsDataMixin(object):
'organization-b/course-d/winter', 'organization-b/course-d/winter',
] ]
# TODO: Use factory-boy.
PROGRAMS_API_RESPONSE = { PROGRAMS_API_RESPONSE = {
'results': [ 'results': [
{ factories.Program(
'id': 1, id=1,
'name': PROGRAM_NAMES[0], name=PROGRAM_NAMES[0],
'subtitle': 'A program used for testing purposes', organizations=[factories.Organization()],
'category': 'xseries', course_codes=[
'status': 'unpublished', factories.CourseCode(run_modes=[
'marketing_slug': '{}_test_url'.format(PROGRAM_NAMES[0].replace(' ', '_')), factories.RunMode(course_key=COURSE_KEYS[0]),
'organizations': [ factories.RunMode(course_key=COURSE_KEYS[1]),
{ ]),
'display_name': 'Test Organization A', factories.CourseCode(run_modes=[
'key': 'organization-a' factories.RunMode(course_key=COURSE_KEYS[2]),
} factories.RunMode(course_key=COURSE_KEYS[3]),
], ]),
'course_codes': [ ]
{ ),
'display_name': 'Test Course A', factories.Program(
'key': 'course-a', id=2,
'organization': { name=PROGRAM_NAMES[1],
'display_name': 'Test Organization A', organizations=[factories.Organization()],
'key': 'organization-a' course_codes=[
}, factories.CourseCode(run_modes=[
'run_modes': [ factories.RunMode(course_key=COURSE_KEYS[4]),
{ factories.RunMode(course_key=COURSE_KEYS[5]),
'course_key': COURSE_KEYS[0], ]),
'mode_slug': 'verified', factories.CourseCode(run_modes=[
'sku': '', factories.RunMode(course_key=COURSE_KEYS[6]),
'start_date': '2015-11-05T07:39:02.791741Z', factories.RunMode(course_key=COURSE_KEYS[7]),
'run_key': 'fall' ]),
}, ]
{ ),
'course_key': COURSE_KEYS[1], factories.Program(
'mode_slug': 'verified', id=3,
'sku': '', name=PROGRAM_NAMES[2],
'start_date': '2015-11-05T07:39:02.791741Z', organizations=[factories.Organization()],
'run_key': 'winter' course_codes=[
} factories.CourseCode(run_modes=[
] factories.RunMode(course_key=COURSE_KEYS[7]),
}, ]),
{ ]
'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'
}
] ]
} }
......
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