Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
C
course-discovery
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
course-discovery
Commits
6c6f49f0
Commit
6c6f49f0
authored
Apr 04, 2016
by
Bill DeRusha
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #55 from edx/bderusha/course-run-endpoint
Add course run endpoint
parents
3870cec7
11469da3
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
335 additions
and
32 deletions
+335
-32
course_discovery/apps/api/serializers.py
+46
-4
course_discovery/apps/api/tests/test_serializers.py
+78
-5
course_discovery/apps/api/v1/tests/test_views/test_course_runs.py
+36
-0
course_discovery/apps/api/v1/tests/test_views/test_courses.py
+5
-1
course_discovery/apps/api/v1/urls.py
+1
-0
course_discovery/apps/api/v1/views.py
+23
-3
course_discovery/apps/course_metadata/migrations/0002_auto_20160404_1626.py
+22
-0
course_discovery/apps/course_metadata/migrations/0003_auto_20160404_1734.py
+59
-0
course_discovery/apps/course_metadata/models.py
+26
-12
course_discovery/apps/course_metadata/tests/factories.py
+31
-2
course_discovery/apps/course_metadata/tests/test_models.py
+8
-5
No files found.
course_discovery/apps/api/serializers.py
View file @
6c6f49f0
...
...
@@ -3,7 +3,7 @@ from rest_framework import serializers
from
course_discovery.apps.catalogs.models
import
Catalog
from
course_discovery.apps.course_metadata.models
import
(
Course
,
Image
,
Organization
,
Prerequisite
,
Subject
,
Video
Course
,
CourseRun
,
Image
,
Organization
,
Person
,
Prerequisite
,
Seat
,
Subject
,
Video
)
...
...
@@ -50,11 +50,34 @@ class VideoSerializer(MediaSerializer):
fields
=
(
'src'
,
'description'
,
'image'
,
)
class
SeatSerializer
(
serializers
.
ModelSerializer
):
type
=
serializers
.
ChoiceField
(
choices
=
[
name
for
name
,
__
in
Seat
.
SEAT_TYPE_CHOICES
]
)
price
=
serializers
.
DecimalField
(
decimal_places
=
Seat
.
PRICE_FIELD_CONFIG
[
'decimal_places'
],
max_digits
=
Seat
.
PRICE_FIELD_CONFIG
[
'max_digits'
]
)
currency
=
serializers
.
SlugRelatedField
(
read_only
=
True
,
slug_field
=
'code'
)
upgrade_deadline
=
serializers
.
DateTimeField
()
credit_provider
=
serializers
.
CharField
()
credit_hours
=
serializers
.
IntegerField
()
class
Meta
(
object
):
model
=
Seat
fields
=
(
'type'
,
'price'
,
'currency'
,
'upgrade_deadline'
,
'credit_provider'
,
'credit_hours'
,
)
class
PersonSerializer
(
serializers
.
ModelSerializer
):
profile_image
=
ImageSerializer
()
class
Meta
(
object
):
model
=
Person
fields
=
(
'name'
,
'title'
,
'bio'
,
'profile_image'
,)
class
OrganizationSerializer
(
serializers
.
ModelSerializer
):
name
=
serializers
.
CharField
()
logo_image
=
ImageSerializer
()
description
=
serializers
.
CharField
()
homepage_url
=
serializers
.
CharField
()
class
Meta
(
object
):
model
=
Organization
...
...
@@ -86,6 +109,25 @@ class CourseSerializer(TimestampModelSerializer):
)
class
CourseRunSerializer
(
TimestampModelSerializer
):
content_language
=
serializers
.
SlugRelatedField
(
read_only
=
True
,
slug_field
=
'code'
,
source
=
'language'
)
transcript_languages
=
serializers
.
SlugRelatedField
(
many
=
True
,
read_only
=
True
,
slug_field
=
'code'
)
image
=
ImageSerializer
()
video
=
VideoSerializer
()
seats
=
SeatSerializer
(
many
=
True
)
instructors
=
PersonSerializer
(
many
=
True
)
staff
=
PersonSerializer
(
many
=
True
)
class
Meta
(
object
):
model
=
CourseRun
fields
=
(
'key'
,
'title'
,
'short_description'
,
'full_description'
,
'start'
,
'end'
,
'enrollment_start'
,
'enrollment_end'
,
'announcement'
,
'image'
,
'video'
,
'seats'
,
'content_language'
,
'transcript_languages'
,
'instructors'
,
'staff'
,
'pacing_type'
,
'min_effort'
,
'max_effort'
,
'modified'
,
)
class
ContainedCoursesSerializer
(
serializers
.
Serializer
):
# pylint: disable=abstract-method
courses
=
serializers
.
DictField
(
child
=
serializers
.
BooleanField
(),
...
...
course_discovery/apps/api/tests/test_serializers.py
View file @
6c6f49f0
...
...
@@ -4,15 +4,21 @@ import ddt
from
django.test
import
TestCase
from
course_discovery.apps.api.serializers
import
(
CatalogSerializer
,
CourseSerializer
,
ContainedCoursesSerializer
,
ImageSerializer
,
SubjectSerializer
,
PrerequisiteSerializer
,
VideoSerializer
,
OrganizationSerializer
CatalogSerializer
,
CourseSerializer
,
CourseRunSerializer
,
ContainedCoursesSerializer
,
ImageSerializer
,
SubjectSerializer
,
PrerequisiteSerializer
,
VideoSerializer
,
OrganizationSerializer
,
SeatSerializer
,
PersonSerializer
,
)
from
course_discovery.apps.catalogs.tests.factories
import
CatalogFactory
from
course_discovery.apps.course_metadata.tests.factories
import
(
CourseFactory
,
SubjectFactory
,
PrerequisiteFactory
,
ImageFactory
,
VideoFactory
,
OrganizationFactory
CourseFactory
,
CourseRunFactory
,
SubjectFactory
,
PrerequisiteFactory
,
ImageFactory
,
VideoFactory
,
OrganizationFactory
,
PersonFactory
,
SeatFactory
)
def
json_date_format
(
datetime_obj
):
return
datetime
.
strftime
(
datetime_obj
,
"
%
Y-
%
m-
%
dT
%
H:
%
M:
%
S.
%
fZ"
)
class
CatalogSerializerTests
(
TestCase
):
def
test_data
(
self
):
catalog
=
CatalogFactory
(
query
=
'*:*'
)
# We intentionally use a query for all Courses.
...
...
@@ -51,7 +57,40 @@ class CourseSerializerTests(TestCase):
'video'
:
VideoSerializer
(
video
)
.
data
,
'owners'
:
[],
'sponsors'
:
[],
'modified'
:
datetime
.
strftime
(
course
.
modified
,
"
%
Y-
%
m-
%
dT
%
H:
%
M:
%
S.
%
fZ"
)
# pylint: disable=no-member
'modified'
:
json_date_format
(
course
.
modified
)
# pylint: disable=no-member
}
self
.
assertDictEqual
(
serializer
.
data
,
expected
)
class
CourseRunSerializerTests
(
TestCase
):
def
test_data
(
self
):
course_run
=
CourseRunFactory
()
image
=
course_run
.
image
video
=
course_run
.
video
serializer
=
CourseRunSerializer
(
course_run
)
expected
=
{
'key'
:
course_run
.
key
,
'title'
:
course_run
.
title
,
# pylint: disable=no-member
'short_description'
:
course_run
.
short_description
,
# pylint: disable=no-member
'full_description'
:
course_run
.
full_description
,
# pylint: disable=no-member
'start'
:
json_date_format
(
course_run
.
start
),
'end'
:
json_date_format
(
course_run
.
end
),
'enrollment_start'
:
json_date_format
(
course_run
.
enrollment_start
),
'enrollment_end'
:
json_date_format
(
course_run
.
enrollment_end
),
'announcement'
:
json_date_format
(
course_run
.
announcement
),
'image'
:
ImageSerializer
(
image
)
.
data
,
'video'
:
VideoSerializer
(
video
)
.
data
,
'pacing_type'
:
course_run
.
pacing_type
,
'content_language'
:
course_run
.
language
.
code
,
'transcript_languages'
:
[],
'min_effort'
:
course_run
.
min_effort
,
'max_effort'
:
course_run
.
max_effort
,
'instructors'
:
[],
'staff'
:
[],
'seats'
:
[],
'modified'
:
json_date_format
(
course_run
.
modified
)
# pylint: disable=no-member
}
self
.
assertDictEqual
(
serializer
.
data
,
expected
)
...
...
@@ -70,7 +109,7 @@ class ContainedCoursesSerializerTests(TestCase):
@ddt.ddt
class
LinkObject
SerializerTests
(
TestCase
):
class
NamedModel
SerializerTests
(
TestCase
):
@ddt.data
(
(
SubjectFactory
,
SubjectSerializer
),
(
PrerequisiteFactory
,
PrerequisiteSerializer
),
...
...
@@ -136,3 +175,37 @@ class OrganizationSerializerTests(TestCase):
}
self
.
assertDictEqual
(
serializer
.
data
,
expected
)
class
SeatSerializerTests
(
TestCase
):
def
test_data
(
self
):
course_run
=
CourseRunFactory
()
seat
=
SeatFactory
(
course_run
=
course_run
)
serializer
=
SeatSerializer
(
seat
)
expected
=
{
'type'
:
seat
.
type
,
'price'
:
str
(
seat
.
price
),
'currency'
:
seat
.
currency
.
code
,
'upgrade_deadline'
:
json_date_format
(
seat
.
upgrade_deadline
),
'credit_provider'
:
seat
.
credit_provider
,
# pylint: disable=no-member
'credit_hours'
:
seat
.
credit_hours
# pylint: disable=no-member
}
self
.
assertDictEqual
(
serializer
.
data
,
expected
)
class
PersonSerializerTests
(
TestCase
):
def
test_data
(
self
):
person
=
PersonFactory
()
image
=
person
.
profile_image
serializer
=
PersonSerializer
(
person
)
expected
=
{
'name'
:
person
.
name
,
'title'
:
person
.
title
,
'bio'
:
person
.
bio
,
'profile_image'
:
ImageSerializer
(
image
)
.
data
}
self
.
assertDictEqual
(
serializer
.
data
,
expected
)
course_discovery/apps/api/v1/tests/test_views/test_course_runs.py
0 → 100644
View file @
6c6f49f0
# pylint: disable=no-member
from
django.db.models.functions
import
Lower
from
rest_framework.reverse
import
reverse
from
rest_framework.test
import
APITestCase
from
course_discovery.apps.api.serializers
import
CourseRunSerializer
from
course_discovery.apps.core.tests.factories
import
UserFactory
from
course_discovery.apps.course_metadata.tests.factories
import
CourseRunFactory
from
course_discovery.apps.course_metadata.models
import
CourseRun
class
CourseRunViewSetTests
(
APITestCase
):
def
setUp
(
self
):
super
(
CourseRunViewSetTests
,
self
)
.
setUp
()
self
.
user
=
UserFactory
(
is_staff
=
True
,
is_superuser
=
True
)
self
.
client
.
force_authenticate
(
self
.
user
)
self
.
course_run
=
CourseRunFactory
()
def
test_get
(
self
):
""" Verify the endpoint returns the details for a single course. """
url
=
reverse
(
'api:v1:course_run-detail'
,
kwargs
=
{
'key'
:
self
.
course_run
.
key
})
response
=
self
.
client
.
get
(
url
)
self
.
assertEqual
(
response
.
status_code
,
200
)
self
.
assertEqual
(
response
.
data
,
CourseRunSerializer
(
self
.
course_run
)
.
data
)
def
test_list
(
self
):
""" Verify the endpoint returns a list of all catalogs. """
url
=
reverse
(
'api:v1:course_run-list'
)
response
=
self
.
client
.
get
(
url
)
self
.
assertEqual
(
response
.
status_code
,
200
)
self
.
assertListEqual
(
response
.
data
[
'results'
],
CourseRunSerializer
(
CourseRun
.
objects
.
all
()
.
order_by
(
Lower
(
'key'
)),
many
=
True
)
.
data
)
course_discovery/apps/api/v1/tests/test_views/test_courses.py
View file @
6c6f49f0
from
django.db.models.functions
import
Lower
from
rest_framework.reverse
import
reverse
from
rest_framework.test
import
APITestCase
...
...
@@ -28,4 +29,7 @@ class CourseViewSetTests(SerializationMixin, APITestCase):
response
=
self
.
client
.
get
(
url
)
self
.
assertEqual
(
response
.
status_code
,
200
)
self
.
assertListEqual
(
response
.
data
[
'results'
],
self
.
serialize_course
(
Course
.
objects
.
all
(),
many
=
True
))
self
.
assertListEqual
(
response
.
data
[
'results'
],
self
.
serialize_course
(
Course
.
objects
.
all
()
.
order_by
(
Lower
(
'key'
)),
many
=
True
)
)
course_discovery/apps/api/v1/urls.py
View file @
6c6f49f0
...
...
@@ -8,5 +8,6 @@ urlpatterns = []
router
=
routers
.
SimpleRouter
()
router
.
register
(
r'catalogs'
,
views
.
CatalogViewSet
)
router
.
register
(
r'courses'
,
views
.
CourseViewSet
,
base_name
=
'course'
)
router
.
register
(
r'course_runs'
,
views
.
CourseRunViewSet
,
base_name
=
'course_run'
)
urlpatterns
+=
router
.
urls
course_discovery/apps/api/v1/views.py
View file @
6c6f49f0
...
...
@@ -8,10 +8,12 @@ from rest_framework.permissions import IsAuthenticated
from
rest_framework.response
import
Response
from
course_discovery.apps.api.filters
import
PermissionsFilter
from
course_discovery.apps.api.serializers
import
CatalogSerializer
,
CourseSerializer
,
ContainedCoursesSerializer
from
course_discovery.apps.api.serializers
import
(
CatalogSerializer
,
CourseSerializer
,
CourseRunSerializer
,
ContainedCoursesSerializer
)
from
course_discovery.apps.catalogs.models
import
Catalog
from
course_discovery.apps.course_metadata.constants
import
COURSE_ID_REGEX
from
course_discovery.apps.course_metadata.models
import
Course
from
course_discovery.apps.course_metadata.constants
import
COURSE_ID_REGEX
,
COURSE_RUN_ID_REGEX
from
course_discovery.apps.course_metadata.models
import
Course
,
CourseRun
logger
=
logging
.
getLogger
(
__name__
)
...
...
@@ -109,3 +111,21 @@ class CourseViewSet(viewsets.ReadOnlyModelViewSet):
def
retrieve
(
self
,
request
,
*
args
,
**
kwargs
):
""" Retrieve details for a course. """
return
super
(
CourseViewSet
,
self
)
.
retrieve
(
request
,
*
args
,
**
kwargs
)
class
CourseRunViewSet
(
viewsets
.
ReadOnlyModelViewSet
):
""" CourseRun resource. """
lookup_field
=
'key'
lookup_value_regex
=
COURSE_RUN_ID_REGEX
queryset
=
CourseRun
.
objects
.
all
()
.
order_by
(
Lower
(
'key'
))
permission_classes
=
(
IsAuthenticated
,)
serializer_class
=
CourseRunSerializer
# The boilerplate methods are required to be recognized by swagger
def
list
(
self
,
request
,
*
args
,
**
kwargs
):
""" List all course runs. """
return
super
(
CourseRunViewSet
,
self
)
.
list
(
request
,
*
args
,
**
kwargs
)
def
retrieve
(
self
,
request
,
*
args
,
**
kwargs
):
""" Retrieve details for a course run. """
return
super
(
CourseRunViewSet
,
self
)
.
retrieve
(
request
,
*
args
,
**
kwargs
)
course_discovery/apps/course_metadata/migrations/0002_auto_20160404_1626.py
0 → 100644
View file @
6c6f49f0
# -*- coding: utf-8 -*-
from
__future__
import
unicode_literals
from
django.db
import
migrations
,
models
class
Migration
(
migrations
.
Migration
):
dependencies
=
[
(
'course_metadata'
,
'0001_initial'
),
]
operations
=
[
migrations
.
AlterModelOptions
(
name
=
'expectedlearningitem'
,
options
=
{},
),
migrations
.
AlterModelOptions
(
name
=
'syllabusitem'
,
options
=
{},
),
]
course_discovery/apps/course_metadata/migrations/0003_auto_20160404_1734.py
0 → 100644
View file @
6c6f49f0
# -*- coding: utf-8 -*-
from
__future__
import
unicode_literals
from
django.db
import
migrations
,
models
class
Migration
(
migrations
.
Migration
):
dependencies
=
[
(
'course_metadata'
,
'0002_auto_20160404_1626'
),
]
operations
=
[
migrations
.
AlterField
(
model_name
=
'courserun'
,
name
=
'course'
,
field
=
models
.
ForeignKey
(
related_name
=
'course_runs'
,
to
=
'course_metadata.Course'
),
),
migrations
.
AlterField
(
model_name
=
'historicalseat'
,
name
=
'credit_hours'
,
field
=
models
.
IntegerField
(
null
=
True
,
blank
=
True
),
),
migrations
.
AlterField
(
model_name
=
'historicalseat'
,
name
=
'credit_provider'
,
field
=
models
.
CharField
(
max_length
=
255
,
null
=
True
,
blank
=
True
),
),
migrations
.
AlterField
(
model_name
=
'historicalseat'
,
name
=
'price'
,
field
=
models
.
DecimalField
(
decimal_places
=
2
,
default
=
0.0
,
max_digits
=
10
),
),
migrations
.
AlterField
(
model_name
=
'historicalseat'
,
name
=
'upgrade_deadline'
,
field
=
models
.
DateTimeField
(
null
=
True
,
blank
=
True
),
),
migrations
.
AlterField
(
model_name
=
'seat'
,
name
=
'credit_hours'
,
field
=
models
.
IntegerField
(
null
=
True
,
blank
=
True
),
),
migrations
.
AlterField
(
model_name
=
'seat'
,
name
=
'credit_provider'
,
field
=
models
.
CharField
(
max_length
=
255
,
null
=
True
,
blank
=
True
),
),
migrations
.
AlterField
(
model_name
=
'seat'
,
name
=
'price'
,
field
=
models
.
DecimalField
(
decimal_places
=
2
,
default
=
0.0
,
max_digits
=
10
),
),
migrations
.
AlterField
(
model_name
=
'seat'
,
name
=
'upgrade_deadline'
,
field
=
models
.
DateTimeField
(
null
=
True
,
blank
=
True
),
),
]
course_discovery/apps/course_metadata/models.py
View file @
6c6f49f0
...
...
@@ -23,6 +23,17 @@ class AbstractNamedModel(TimeStampedModel):
abstract
=
True
class
AbstractValueModel
(
TimeStampedModel
):
""" Abstract base class for models with only a value field. """
value
=
models
.
CharField
(
max_length
=
255
)
def
__str__
(
self
):
return
self
.
value
class
Meta
(
object
):
abstract
=
True
class
AbstractMediaModel
(
TimeStampedModel
):
""" Abstract base class for media-related (e.g. image, video) models. """
src
=
models
.
URLField
(
max_length
=
255
,
unique
=
True
)
...
...
@@ -58,18 +69,14 @@ class Prerequisite(AbstractNamedModel):
pass
class
ExpectedLearningItem
(
TimeStamped
Model
):
class
ExpectedLearningItem
(
AbstractValue
Model
):
""" ExpectedLearningItem model. """
value
=
models
.
CharField
(
max_length
=
255
)
def
__str__
(
self
):
return
self
.
value
pass
class
SyllabusItem
(
TimeStamped
Model
):
class
SyllabusItem
(
AbstractValue
Model
):
""" SyllabusItem model. """
parent
=
models
.
ForeignKey
(
'self'
,
blank
=
True
,
null
=
True
,
related_name
=
'children'
)
value
=
models
.
CharField
(
max_length
=
255
)
class
Organization
(
TimeStampedModel
):
...
...
@@ -146,7 +153,7 @@ class CourseRun(TimeStampedModel):
(
INSTRUCTOR_PACED
,
_
(
'Instructor-paced'
)),
)
course
=
models
.
ForeignKey
(
Course
)
course
=
models
.
ForeignKey
(
Course
,
related_name
=
'course_runs'
)
key
=
models
.
CharField
(
max_length
=
255
,
unique
=
True
)
title_override
=
models
.
CharField
(
max_length
=
255
,
default
=
None
,
null
=
True
,
blank
=
True
,
...
...
@@ -233,13 +240,20 @@ class Seat(TimeStampedModel):
(
PROFESSIONAL
,
_
(
'Professional'
)),
(
CREDIT
,
_
(
'Credit'
)),
)
PRICE_FIELD_CONFIG
=
{
'decimal_places'
:
2
,
'max_digits'
:
10
,
'null'
:
False
,
'default'
:
0.00
,
}
course_run
=
models
.
ForeignKey
(
CourseRun
,
related_name
=
'seats'
)
type
=
models
.
CharField
(
max_length
=
63
,
choices
=
SEAT_TYPE_CHOICES
)
price
=
models
.
DecimalField
(
decimal_places
=
2
,
max_digits
=
10
)
price
=
models
.
DecimalField
(
**
PRICE_FIELD_CONFIG
)
currency
=
models
.
ForeignKey
(
Currency
)
upgrade_deadline
=
models
.
DateTimeField
()
credit_provider
=
models
.
CharField
(
max_length
=
255
)
credit_hours
=
models
.
IntegerField
()
upgrade_deadline
=
models
.
DateTimeField
(
null
=
True
,
blank
=
True
)
credit_provider
=
models
.
CharField
(
max_length
=
255
,
null
=
True
,
blank
=
True
)
credit_hours
=
models
.
IntegerField
(
null
=
True
,
blank
=
True
)
history
=
HistoricalRecords
()
...
...
course_discovery/apps/course_metadata/tests/factories.py
View file @
6c6f49f0
from
datetime
import
datetime
import
factory
from
factory.fuzzy
import
BaseFuzzyAttribute
,
FuzzyText
,
FuzzyChoice
from
factory.fuzzy
import
(
BaseFuzzyAttribute
,
FuzzyText
,
FuzzyChoice
,
FuzzyDateTime
,
FuzzyInteger
,
FuzzyDecimal
)
from
pytz
import
UTC
from
course_discovery.apps.ietf_language_tags.models
import
LanguageTag
from
course_discovery.apps.core.models
import
Currency
from
course_discovery.apps.course_metadata.models
import
(
Course
,
CourseRun
,
Organization
,
Person
,
Image
,
Video
,
Subject
,
Prerequisite
,
LevelType
Course
,
CourseRun
,
Organization
,
Person
,
Image
,
Video
,
Subject
,
Seat
,
Prerequisite
,
LevelType
)
...
...
@@ -64,6 +71,16 @@ class PrerequisiteFactory(AbstractNamedModelFactory):
model
=
Prerequisite
class
SeatFactory
(
factory
.
DjangoModelFactory
):
type
=
FuzzyChoice
([
name
for
name
,
__
in
Seat
.
SEAT_TYPE_CHOICES
])
price
=
FuzzyDecimal
(
0.0
,
650.0
)
currency
=
factory
.
Iterator
(
Currency
.
objects
.
all
())
upgrade_deadline
=
FuzzyDateTime
(
datetime
(
2014
,
1
,
1
,
tzinfo
=
UTC
))
class
Meta
:
model
=
Seat
class
CourseFactory
(
factory
.
DjangoModelFactory
):
key
=
FuzzyText
(
prefix
=
'course-id/'
)
title
=
FuzzyText
(
prefix
=
"Test çօմɾʂҽ "
)
...
...
@@ -83,6 +100,17 @@ class CourseRunFactory(factory.DjangoModelFactory):
title_override
=
None
short_description_override
=
None
full_description_override
=
None
language
=
factory
.
Iterator
(
LanguageTag
.
objects
.
all
())
start
=
FuzzyDateTime
(
datetime
(
2014
,
1
,
1
,
tzinfo
=
UTC
))
end
=
FuzzyDateTime
(
datetime
(
2014
,
1
,
1
,
tzinfo
=
UTC
))
.
end_dt
enrollment_start
=
FuzzyDateTime
(
datetime
(
2014
,
1
,
1
,
tzinfo
=
UTC
))
enrollment_end
=
FuzzyDateTime
(
datetime
(
2014
,
1
,
1
,
tzinfo
=
UTC
))
.
end_dt
announcement
=
FuzzyDateTime
(
datetime
(
2014
,
1
,
1
,
tzinfo
=
UTC
))
image
=
factory
.
SubFactory
(
ImageFactory
)
video
=
factory
.
SubFactory
(
VideoFactory
)
min_effort
=
FuzzyInteger
(
1
,
10
)
max_effort
=
FuzzyInteger
(
10
,
20
)
pacing_type
=
FuzzyChoice
([
name
for
name
,
__
in
CourseRun
.
PACING_CHOICES
])
class
Meta
:
model
=
CourseRun
...
...
@@ -104,6 +132,7 @@ class PersonFactory(factory.DjangoModelFactory):
name
=
FuzzyText
()
title
=
FuzzyText
()
bio
=
FuzzyText
()
profile_image
=
factory
.
SubFactory
(
ImageFactory
)
class
Meta
:
model
=
Person
course_discovery/apps/course_metadata/tests/test_models.py
View file @
6c6f49f0
...
...
@@ -2,7 +2,7 @@ import ddt
from
django.test
import
TestCase
from
course_discovery.apps.course_metadata.models
import
(
AbstractNamedModel
,
AbstractMediaModel
,
CourseOrganization
,
ExpectedLearningItem
AbstractNamedModel
,
AbstractMediaModel
,
AbstractValueModel
,
CourseOrganization
)
from
course_discovery.apps.course_metadata.tests
import
factories
...
...
@@ -124,12 +124,15 @@ class AbstractMediaModelTests(TestCase):
self
.
assertEqual
(
str
(
instance
),
src
)
class
ExpectedLearningItem
Tests
(
TestCase
):
""" Tests for
ExpectedLearningItem
. """
class
AbstractValueModel
Tests
(
TestCase
):
""" Tests for
AbstractValueModel
. """
def
test_str
(
self
):
""" Verify casting an instance to a string returns a string containing the value. """
value
=
'Expected learnings'
instance
=
ExpectedLearningItem
(
value
=
value
)
class
TestAbstractValueModel
(
AbstractValueModel
):
pass
value
=
'abc'
instance
=
TestAbstractValueModel
(
value
=
value
)
self
.
assertEqual
(
str
(
instance
),
value
)
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment