Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Figures bug fixes #213

Merged
merged 5 commits into from
May 16, 2020
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 13 additions & 5 deletions figures/migrations/0010_site_monthly_metrics.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,27 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.15 on 2020-04-08 21:46
# Manually updated to support Django 1.8 as well as 1.11

from __future__ import unicode_literals

from django import VERSION as DJANGO_VERSION
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
import model_utils.fields


class Migration(migrations.Migration):

dependencies = [
('sites', '0002_alter_domain_unique'),
('figures', '0009_mau_metrics'),
]
if DJANGO_VERSION[0:2] == (1,8):
dependencies = [
('sites', '0001_initial'),
('figures', '0009_mau_metrics'),
]
else: # Assuming 1.11+
dependencies = [
('sites', '0002_alter_domain_unique'),
('figures', '0009_mau_metrics'),
]

operations = [
migrations.CreateModel(
Expand Down
19 changes: 10 additions & 9 deletions figures/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -611,17 +611,21 @@ def get_progress_data(self, course_enrollment):
else:
course_completed = False

# Default values if we can't retrieve progress data
progress_percent = 0.0
course_progress_details = None

try:
obj = LearnerCourseGradeMetrics.objects.most_recent_for_learner_course(
user=course_enrollment.user,
course_id=str(course_enrollment.course_id))
course_progress = dict(
progress_percent=obj.progress_percent,
course_progress_details=obj.progress_details)
if obj:
progress_percent = obj.progress_percent
course_progress_details = obj.progress_details
except Exception as e: # pylint: disable=broad-except
# TODO: Use more specific database-related exception
error_data = dict(
msg='Unable to get learner course metrics',
msg='Exception trying to get learner course metrics',
username=course_enrollment.user.username,
course_id=str(course_enrollment.course_id),
exception=str(e)
Expand All @@ -630,18 +634,15 @@ def get_progress_data(self, course_enrollment):
error_data=error_data,
error_type=PipelineError.UNSPECIFIED_DATA,
)
course_progress = dict(
progress_percent=0.0,
course_progress_details=None)

# Empty list initially, then will fill after we implement capturing
# learner specific progress
course_progress_history = []

data = dict(
course_completed=course_completed,
course_progress=course_progress['progress_percent'],
course_progress_details=course_progress['course_progress_details'],
course_progress=progress_percent,
course_progress_details=course_progress_details,
course_progress_history=course_progress_history,
)
return data
Expand Down
49 changes: 47 additions & 2 deletions tests/models/test_learner_course_grade_metrics_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,55 @@
import pytest

from django.contrib.sites.models import Site
from django.utils.timezone import utc

from figures.helpers import as_date
from figures.models import LearnerCourseGradeMetrics

from tests.factories import CourseEnrollmentFactory
from tests.factories import (
CourseEnrollmentFactory,
CourseOverviewFactory,
LearnerCourseGradeMetricsFactory,
UserFactory
)


@pytest.mark.django_db
def test_most_recent_with_data(db):
"""Make sure the query works with a couple of existing models

We create two LearnerCourseGradeMetrics models and test that the function
retrieves the newer one
"""
user = UserFactory()
first_date = as_date('2020-02-02')
second_date = as_date('2020-04-01')
course_overview = CourseOverviewFactory()
older_lcgm = LearnerCourseGradeMetricsFactory(user=user,
course_id=str(course_overview.id),
date_for=first_date)
newer_lcgm = LearnerCourseGradeMetricsFactory(user=user,
course_id=str(course_overview.id),
date_for=second_date)

obj = LearnerCourseGradeMetrics.objects.most_recent_for_learner_course(
user=user, course_id=course_overview.id)
assert obj == newer_lcgm


@pytest.mark.django_db
def test_most_recent_with_empty_table(db):
"""Make sure the query works when there are no models to find

Tests that the function returns None and does not fail when it cannot find
any LearnerCourseGradeMetrics model instances
"""
assert not LearnerCourseGradeMetrics.objects.count()
user = UserFactory()
course_overview = CourseOverviewFactory()
obj = LearnerCourseGradeMetrics.objects.most_recent_for_learner_course(
user=user, course_id=course_overview.id)
assert not obj


@pytest.mark.django_db
Expand Down Expand Up @@ -69,7 +114,7 @@ def test_most_recent_for_learner_course_multiple_dates(self):

def test_progress_percent(self):
expected = (self.grade_data['sections_worked'] /
self.grade_data['sections_possible'])
self.grade_data['sections_possible'])
obj = LearnerCourseGradeMetrics(**self.create_rec)
assert obj.progress_percent == expected

Expand Down
12 changes: 12 additions & 0 deletions tests/pipeline/test_site_monthly_metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

from courseware.models import StudentModule

from figures.compat import RELEASE_LINE
from figures.models import SiteMonthlyMetrics
from figures.pipeline.site_monthly_metrics import fill_month, fill_last_month

Expand Down Expand Up @@ -70,13 +71,24 @@ def mock_get_student_modules_for_site(site):
assert obj.month_for == smm_test_data['month_before'].date()


@pytest.mark.skipif(RELEASE_LINE=='ginkgo',
reason='Freezegun breaks the StudentModule query')
def test_fill_last_month_wo_overwrite(monkeypatch, smm_test_data):
"""
This test breaks when run in the Ginkgo environment. The problem is that
after `freezer.start()`, StudentModule queries on `modified` fields return
empty results when there are data for the modified fields set for the filter
values. See tests/test_ginkgo.py
"""
assert SiteMonthlyMetrics.objects.count() == 0
mock_today = smm_test_data['mock_today']
freezer = freeze_time(mock_today)
year_check = smm_test_data['last_month_sm'][0].modified.year
assert StudentModule.objects.filter(modified__year=year_check), \
'before freezegun start'
freezer.start()
assert StudentModule.objects.filter(modified__year=year_check), \
'after freezegun start'

site = smm_test_data['site']

Expand Down
58 changes: 50 additions & 8 deletions tests/test_serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from figures.models import (
CourseDailyMetrics,
CourseMauMetrics,
LearnerCourseGradeMetrics,
SiteDailyMetrics,
SiteMauMetrics,
)
Expand Down Expand Up @@ -45,6 +46,7 @@
CourseMauMetricsFactory,
CourseOverviewFactory,
GeneratedCertificateFactory,
LearnerCourseGradeMetricsFactory,
SiteDailyMetricsFactory,
SiteMauMetricsFactory,
UserFactory,
Expand Down Expand Up @@ -395,7 +397,7 @@ def test_has_fields(self):
data = self.serializer.data

assert set(data.keys()) == set(self.expected_fields)

# This is to make sure that the serializer retrieves the correct nested
# model (UserProfile) data
assert data['username'] == 'alpha_one'
Expand All @@ -413,13 +415,6 @@ class TestLearnerCourseDetailsSerializer(object):
'''
@pytest.fixture(autouse=True)
def setup(self, db):
# self.model = CourseEnrollment
# self.user_attributes = {
# 'username': 'alpha_one',
# 'profile__name': 'Alpha One',
# 'profile__country': 'CA',
# }
#self.user = UserFactory(**self.user_attributes)
self.site = Site.objects.first()
self.certificate_date = datetime.datetime(2018, 4, 1, tzinfo=utc)
self.course_enrollment = CourseEnrollmentFactory(
Expand All @@ -442,6 +437,53 @@ def test_has_fields(self):
data = self.serializer.data
assert set(data.keys()) == expected_fields

def test_get_progress_data(self):
"""
Method should return data of the form:
{'course_progress_history': [],
'course_progress_details': {
'sections_worked': 5,
'points_possible': 30.0,
'sections_possible': 10,
'points_earned': 15.0
},
'course_progress': (0.5,),
'course_completed': datetime.datetime(2018, 4, 1, 0, 0, tzinfo=<UTC>)
}
"""
metrics_data = dict(
points_possible=1,
points_earned=2,
sections_worked=3,
sections_possible=4)
lcgm = LearnerCourseGradeMetricsFactory(
user=self.course_enrollment.user,
course_id=str(self.course_enrollment.course_id),
**metrics_data
)

data = self.serializer.get_progress_data(self.course_enrollment)
details = data['course_progress_details']
for key, val in metrics_data.items():
assert details[key] == val
assert data['course_progress'] == lcgm.progress_percent
assert data['course_completed'] == self.generated_certificate.created_date

def test_get_progress_data_with_no_data(self):
"""Tests that the serializer method succeeds when no learner course
grade metrics records
"""
expected_data = {
'course_progress_history': [],
'course_progress_details': None,
'course_progress': 0.0,
'course_completed': False
}
assert not LearnerCourseGradeMetrics.objects.count()
course_enrollment = CourseEnrollmentFactory()
data = self.serializer.get_progress_data(course_enrollment)
assert data == expected_data


@pytest.mark.django_db
class TestLearnerDetailsSerializer(object):
Expand Down