PLAT-1881 Fix datetimes lacking timezone information

This commit is contained in:
Jeremy Bowman
2018-01-10 14:33:01 -05:00
parent 4026c25f7a
commit 1a7753d775
13 changed files with 71 additions and 65 deletions

View File

@@ -454,9 +454,9 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase, Ente
# enforced at the data layer, so we need to handle the case
# in which no dates are specified.
(None, None, None, None),
(datetime.datetime(2015, 1, 2, 3, 4, 5), None, "2015-01-02T03:04:05Z", None),
(None, datetime.datetime(2015, 1, 2, 3, 4, 5), None, "2015-01-02T03:04:05Z"),
(datetime.datetime(2014, 6, 7, 8, 9, 10), datetime.datetime(2015, 1, 2, 3, 4, 5), "2014-06-07T08:09:10Z", "2015-01-02T03:04:05Z"),
(datetime.datetime(2015, 1, 2, 3, 4, 5, tzinfo=pytz.UTC), None, "2015-01-02T03:04:05Z", None),
(None, datetime.datetime(2015, 1, 2, 3, 4, 5, tzinfo=pytz.UTC), None, "2015-01-02T03:04:05Z"),
(datetime.datetime(2014, 6, 7, 8, 9, 10, tzinfo=pytz.UTC), datetime.datetime(2015, 1, 2, 3, 4, 5, tzinfo=pytz.UTC), "2014-06-07T08:09:10Z", "2015-01-02T03:04:05Z"),
)
@ddt.unpack
def test_get_course_details_course_dates(self, start_datetime, end_datetime, expected_start, expected_end):
@@ -579,7 +579,7 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase, Ente
course_id=self.course.id,
mode_slug=CourseMode.VERIFIED,
mode_display_name=CourseMode.VERIFIED,
expiration_datetime='1970-01-01 05:00:00'
expiration_datetime='1970-01-01 05:00:00Z'
)
# Passes the include_expired parameter to the API call

View File

@@ -2,11 +2,11 @@ import json
import logging
import unittest
import uuid
from datetime import datetime, timedelta
from datetime import timedelta
import pytz
from django.conf import settings
from django.core.urlresolvers import reverse
from django.utils.timezone import now
from course_modes.models import CourseMode
from course_modes.tests.factories import CourseModeFactory
@@ -41,7 +41,7 @@ class EntitlementViewSetTest(ModuleStoreTestCase):
course_id=self.course.id,
mode_slug=CourseMode.VERIFIED,
# This must be in the future to ensure it is returned by downstream code.
expiration_datetime=datetime.now(pytz.UTC) + timedelta(days=1)
expiration_datetime=now() + timedelta(days=1)
)
self.entitlements_list_url = reverse('entitlements_api:v1:entitlements-list')
@@ -216,11 +216,11 @@ class EntitlementViewSetTest(ModuleStoreTestCase):
assert results == CourseEntitlementSerializer([entitlement], many=True).data
def test_staff_get_expired_entitlements(self):
past_datetime = datetime.utcnow().replace(tzinfo=pytz.UTC) - timedelta(days=365 * 2)
past_datetime = now() - timedelta(days=365 * 2)
entitlements = CourseEntitlementFactory.create_batch(2, created=past_datetime, user=self.user)
# Set the first entitlement to be at a time that it isn't expired
entitlements[0].created = datetime.utcnow()
entitlements[0].created = now()
entitlements[0].save()
response = self.client.get(
@@ -233,7 +233,7 @@ class EntitlementViewSetTest(ModuleStoreTestCase):
assert results[0].get('expired_at') is None and results[1].get('expired_at') is None
def test_get_user_expired_entitlements(self):
past_datetime = datetime.utcnow().replace(tzinfo=pytz.UTC) - timedelta(days=365 * 2)
past_datetime = now() - timedelta(days=365 * 2)
not_staff_user = UserFactory()
self.client.login(username=not_staff_user.username, password=TEST_PASSWORD)
entitlement_user2 = CourseEntitlementFactory.create_batch(2, user=not_staff_user, created=past_datetime)
@@ -241,7 +241,7 @@ class EntitlementViewSetTest(ModuleStoreTestCase):
url += '?user={username}'.format(username=not_staff_user.username)
# Set the first entitlement to be at a time that it isn't expired
entitlement_user2[0].created = datetime.utcnow()
entitlement_user2[0].created = now()
entitlement_user2[0].save()
response = self.client.get(
@@ -284,7 +284,7 @@ class EntitlementViewSetTest(ModuleStoreTestCase):
assert results == CourseEntitlementSerializer(entitlement).data and results.get('expired_at') is None
def test_get_expired_entitlement_by_uuid(self):
past_datetime = datetime.utcnow().replace(tzinfo=pytz.UTC) - timedelta(days=365 * 2)
past_datetime = now() - timedelta(days=365 * 2)
entitlement = CourseEntitlementFactory(created=past_datetime)
CourseEntitlementFactory.create_batch(2)

View File

@@ -1,11 +1,11 @@
import uuid as uuid_tools
from datetime import datetime, timedelta
from datetime import timedelta
from util.date_utils import strftime_localized
import pytz
from django.conf import settings
from django.contrib.sites.models import Site
from django.db import models
from django.utils.timezone import now
from certificates.models import GeneratedCertificate
from model_utils.models import TimeStampedModel
@@ -45,16 +45,16 @@ class CourseEntitlementPolicy(models.Model):
Returns an integer of number of days until the entitlement expires.
Includes the logic for regaining an entitlement.
"""
now = datetime.now(tz=pytz.UTC)
now_timestamp = now()
expiry_date = entitlement.created + self.expiration_period
days_until_expiry = (expiry_date - now).days
days_until_expiry = (expiry_date - now_timestamp).days
if not entitlement.enrollment_course_run:
return days_until_expiry
course_overview = CourseOverview.get_from_id(entitlement.enrollment_course_run.course_id)
# Compute the days left for the regain
days_since_course_start = (now - course_overview.start).days
days_since_enrollment = (now - entitlement.enrollment_course_run.created).days
days_since_entitlement_created = (now - entitlement.created).days
days_since_course_start = (now_timestamp - course_overview.start).days
days_since_enrollment = (now_timestamp - entitlement.enrollment_course_run.created).days
days_since_entitlement_created = (now_timestamp - entitlement.created).days
# We want to return whichever days value is less since it is then the more recent one
days_until_regain_ends = (self.regain_period.days - # pylint: disable=no-member
@@ -184,8 +184,7 @@ class CourseEntitlement(TimeStampedModel):
"""
Returns an integer of number of days since the entitlement has been created
"""
utc = pytz.UTC
return (datetime.now(tz=utc) - self.created).days
return (now() - self.created).days
def update_expired_at(self):
"""
@@ -195,7 +194,7 @@ class CourseEntitlement(TimeStampedModel):
if not self.expired_at:
if (self.policy.get_days_until_expiration(self) < 0 or
(self.enrollment_course_run and not self.is_entitlement_regainable())):
self.expired_at = datetime.utcnow()
self.expired_at = now()
self.save()
def get_days_until_expiration(self):
@@ -235,7 +234,7 @@ class CourseEntitlement(TimeStampedModel):
expiration_date = None
if self.get_days_until_expiration() < settings.ENTITLEMENT_EXPIRED_ALERT_PERIOD:
expiration_date = strftime_localized(
datetime.now(tz=pytz.UTC) + timedelta(days=self.get_days_until_expiration()),
now() + timedelta(days=self.get_days_until_expiration()),
'SHORT_DATE'
)
expired_at = strftime_localized(self.expired_at_datetime, 'SHORT_DATE') if self.expired_at_datetime else None

View File

@@ -1,11 +1,11 @@
"""Test Entitlements models"""
import unittest
from datetime import datetime, timedelta
from datetime import timedelta
import pytz
from django.conf import settings
from django.test import TestCase
from django.utils.timezone import now
from certificates.models import CertificateStatuses # pylint: disable=import-error
from lms.djangoapps.certificates.api import MODES
@@ -25,7 +25,7 @@ class TestModels(TestCase):
def setUp(self):
super(TestModels, self).setUp()
self.course = CourseOverviewFactory.create(
start=datetime.utcnow()
start=now()
)
self.enrollment = CourseEnrollmentFactory.create(course_id=self.course.id)
@@ -40,13 +40,13 @@ class TestModels(TestCase):
assert entitlement.is_entitlement_redeemable() is True
# Create a date 2 years in the past (greater than the policy expire period of 450 days)
past_datetime = datetime.utcnow().replace(tzinfo=pytz.UTC) - timedelta(days=365 * 2)
past_datetime = now() - timedelta(days=365 * 2)
entitlement.created = past_datetime
entitlement.save()
assert entitlement.is_entitlement_redeemable() is False
entitlement = CourseEntitlementFactory.create(expired_at=datetime.now())
entitlement = CourseEntitlementFactory.create(expired_at=now())
assert entitlement.is_entitlement_refundable() is False
@@ -64,7 +64,7 @@ class TestModels(TestCase):
assert entitlement.is_entitlement_refundable() is False
# Create a date 70 days in the past (greater than the policy refund expire period of 60 days)
past_datetime = datetime.utcnow().replace(tzinfo=pytz.UTC) - timedelta(days=70)
past_datetime = now() - timedelta(days=70)
entitlement = CourseEntitlementFactory.create(created=past_datetime)
assert entitlement.is_entitlement_refundable() is False
@@ -72,7 +72,7 @@ class TestModels(TestCase):
entitlement = CourseEntitlementFactory.create(enrollment_course_run=self.enrollment)
# Create a date 20 days in the past (less than the policy refund expire period of 60 days)
# but more than the policy regain period of 14 days and also the course start
past_datetime = datetime.utcnow().replace(tzinfo=pytz.UTC) - timedelta(days=20)
past_datetime = now() - timedelta(days=20)
entitlement.created = past_datetime
self.enrollment.created = past_datetime
self.course.start = past_datetime
@@ -87,7 +87,7 @@ class TestModels(TestCase):
assert entitlement.is_entitlement_refundable() is True
entitlement = CourseEntitlementFactory.create(expired_at=datetime.now())
entitlement = CourseEntitlementFactory.create(expired_at=now())
assert entitlement.is_entitlement_refundable() is False
@@ -111,7 +111,7 @@ class TestModels(TestCase):
# Create a date 20 days in the past (greater than the policy expire period of 14 days)
# and apply it to both the entitlement and the course
past_datetime = datetime.utcnow().replace(tzinfo=pytz.UTC) - timedelta(days=20)
past_datetime = now() - timedelta(days=20)
entitlement = CourseEntitlementFactory.create(enrollment_course_run=self.enrollment, created=past_datetime)
self.enrollment.created = past_datetime
self.course.start = past_datetime
@@ -121,7 +121,7 @@ class TestModels(TestCase):
assert entitlement.is_entitlement_regainable() is False
entitlement = CourseEntitlementFactory.create(expired_at=datetime.now())
entitlement = CourseEntitlementFactory.create(expired_at=now())
assert entitlement.is_entitlement_regainable
@@ -147,7 +147,7 @@ class TestModels(TestCase):
assert entitlement.expired_at is None
# Verify an entitlement from two years ago is expired and the db row is updated
past_datetime = datetime.utcnow().replace(tzinfo=pytz.UTC) - timedelta(days=365 * 2)
past_datetime = now() - timedelta(days=365 * 2)
entitlement.created = past_datetime
entitlement.save()
expired_at_datetime = entitlement.expired_at_datetime
@@ -163,7 +163,7 @@ class TestModels(TestCase):
# Verify that an entitlement that has been redeemed but not within 14 days
# and the course started more than two weeks ago is expired
past_datetime = datetime.utcnow().replace(tzinfo=pytz.UTC) - timedelta(days=20)
past_datetime = now() - timedelta(days=20)
entitlement.created = past_datetime
self.enrollment.created = past_datetime
self.course.start = past_datetime
@@ -178,8 +178,8 @@ class TestModels(TestCase):
# Verify that an entitlement that has just been created, but the user has been enrolled in the course for
# greater than 14 days, and the course started more than 14 days ago is not expired
entitlement = CourseEntitlementFactory.create(enrollment_course_run=self.enrollment)
past_datetime = datetime.utcnow().replace(tzinfo=pytz.UTC) - timedelta(days=20)
entitlement.created = datetime.utcnow().replace(tzinfo=pytz.UTC)
past_datetime = now() - timedelta(days=20)
entitlement.created = now()
self.enrollment.created = past_datetime
self.course.start = past_datetime
entitlement.save()
@@ -193,11 +193,11 @@ class TestModels(TestCase):
# Verify a date 451 days in the past (1 days after the policy expiration)
# That is enrolled and started in within the regain period is still expired
entitlement = CourseEntitlementFactory.create(enrollment_course_run=self.enrollment)
expired_datetime = datetime.utcnow().replace(tzinfo=pytz.UTC) - timedelta(days=451)
expired_datetime = now() - timedelta(days=451)
entitlement.created = expired_datetime
now = datetime.now(tz=pytz.UTC)
self.enrollment.created = now
self.course.start = now
start = now()
self.enrollment.created = start
self.course.start = start
entitlement.save()
self.course.save()
self.enrollment.save()

View File

@@ -4,6 +4,7 @@ import datetime
from django.test import TestCase
from django.test.utils import override_settings
from django.utils.timezone import now
from student.models import UserProfile
from student.tests.factories import UserFactory
@@ -40,20 +41,20 @@ class ProfileParentalControlsTest(TestCase):
self.assertFalse(self.profile.requires_parental_consent(default_requires_consent=False))
# Verify that even a child does not require parental consent
current_year = datetime.datetime.now().year
current_year = now().year
self.set_year_of_birth(current_year - 10)
self.assertFalse(self.profile.requires_parental_consent())
def test_adult_user(self):
"""Verify the behavior for an adult."""
current_year = datetime.datetime.now().year
current_year = now().year
self.set_year_of_birth(current_year - 20)
self.assertFalse(self.profile.requires_parental_consent())
self.assertTrue(self.profile.requires_parental_consent(age_limit=21))
def test_child_user(self):
"""Verify the behavior for a child."""
current_year = datetime.datetime.now().year
current_year = now().year
# Verify for a child born 13 years agp
self.set_year_of_birth(current_year - 13)
@@ -70,14 +71,14 @@ class ProfileParentalControlsTest(TestCase):
"""Verify that a profile's image obeys parental controls."""
# Verify that an image cannot be set for a user with no year of birth set
self.profile.profile_image_uploaded_at = datetime.datetime.now()
self.profile.profile_image_uploaded_at = now()
self.profile.save()
self.assertFalse(self.profile.has_profile_image)
# Verify that an image can be set for an adult user
current_year = datetime.datetime.now().year
current_year = now().year
self.set_year_of_birth(current_year - 20)
self.profile.profile_image_uploaded_at = datetime.datetime.now()
self.profile.profile_image_uploaded_at = now()
self.profile.save()
self.assertTrue(self.profile.has_profile_image)

View File

@@ -7,6 +7,7 @@ import unittest
import ddt
from django.conf import settings
from django.core.urlresolvers import reverse
from django.utils.timezone import now
from nose.plugins.attrib import attr
from opaque_keys.edx import locator
from pytz import UTC
@@ -43,7 +44,7 @@ class TestRecentEnrollments(ModuleStoreTestCase, XssTestMixin):
# Old Course
old_course_location = locator.CourseLocator('Org0', 'Course0', 'Run0')
__, enrollment = self._create_course_and_enrollment(old_course_location)
enrollment.created = datetime.datetime(1900, 12, 31, 0, 0, 0, 0)
enrollment.created = datetime.datetime(1900, 12, 31, 0, 0, 0, 0, tzinfo=UTC)
enrollment.save()
# New Course
@@ -107,7 +108,7 @@ class TestRecentEnrollments(ModuleStoreTestCase, XssTestMixin):
'Run{num}'.format(num=idx)
)
course, enrollment = self._create_course_and_enrollment(course_location)
enrollment.created = datetime.datetime.now(UTC) - datetime.timedelta(seconds=seconds_past)
enrollment.created = now() - datetime.timedelta(seconds=seconds_past)
enrollment.save()
courses.append(course)

View File

@@ -1,17 +1,17 @@
"""
Test the student dashboard view.
"""
import datetime
import itertools
import json
import unittest
from datetime import timedelta
import ddt
import pytz
from django.conf import settings
from django.core.urlresolvers import reverse
from django.test import RequestFactory, TestCase
from django.test.utils import override_settings
from django.utils.timezone import now
from edx_oauth2_provider.constants import AUTHORIZED_CLIENTS_SESSION_KEY
from edx_oauth2_provider.tests.factories import ClientFactory, TrustedClientFactory
from milestones.tests.utils import MilestonesTestCaseMixin
@@ -241,9 +241,9 @@ class StudentDashboardTests(SharedModuleStoreTestCase, MilestonesTestCaseMixin):
EMAIL_SETTINGS_ELEMENT_ID = "#actions-item-email-settings-0"
ENABLED_SIGNALS = ['course_published']
TOMORROW = datetime.datetime.now(pytz.utc) + datetime.timedelta(days=1)
THREE_YEARS_FROM_NOW = datetime.datetime.now(pytz.utc) + datetime.timedelta(days=(365 * 3))
THREE_YEARS_AGO = datetime.datetime.now(pytz.utc) - datetime.timedelta(days=(365 * 3))
TOMORROW = now() + timedelta(days=1)
THREE_YEARS_FROM_NOW = now() + timedelta(days=(365 * 3))
THREE_YEARS_AGO = now() - timedelta(days=(365 * 3))
MOCK_SETTINGS = {
'FEATURES': {
'DISABLE_START_DATES': False,
@@ -391,7 +391,7 @@ class StudentDashboardTests(SharedModuleStoreTestCase, MilestonesTestCaseMixin):
CourseEntitlementFactory(
user=self.user,
created=self.THREE_YEARS_AGO,
expired_at=datetime.datetime.now()
expired_at=now()
)
mock_course_overview.return_value = CourseOverviewFactory(start=self.TOMORROW)
mock_course_runs.return_value = [

View File

@@ -10,6 +10,7 @@ import dateutil.parser
import pytz
import requests
from celery.task import task
from django.utils.timezone import now
from lxml import etree
from onelogin.saml2.utils import OneLogin_Saml2_Utils
from requests import exceptions
@@ -188,7 +189,7 @@ def _update_data(entity_id, public_key, sso_url, expires_at):
True if a new record was created. (Either this is a new provider or something changed.)
"""
data_obj = SAMLProviderData.current(entity_id)
fetched_at = datetime.datetime.now()
fetched_at = now()
if data_obj and (data_obj.public_key == public_key and data_obj.sso_url == sso_url):
data_obj.expires_at = expires_at
data_obj.fetched_at = fetched_at

View File

@@ -205,7 +205,7 @@ class PersistentSubsectionGradeTest(GradesModelTestCase):
"user_id": 12345,
"usage_key": self.usage_key,
"course_version": "deadbeef",
"subtree_edited_timestamp": "2016-08-01 18:53:24.354741",
"subtree_edited_timestamp": "2016-08-01 18:53:24.354741Z",
"earned_all": 6.0,
"possible_all": 12.0,
"earned_graded": 6.0,
@@ -338,6 +338,7 @@ class PersistentCourseGradesTest(GradesModelTestCase):
minute=53,
second=24,
microsecond=354741,
tzinfo=pytz.UTC,
),
"percent_grade": 77.7,
"letter_grade": "Great job",

View File

@@ -4,6 +4,7 @@ Utilities for grades related tests
from contextlib import contextmanager
from datetime import datetime
import pytz
from mock import patch, MagicMock
from courseware.model_data import FieldDataCache
@@ -30,7 +31,7 @@ def mock_passing_grade(letter_grade='Pass', percent=0.75, ):
@contextmanager
def mock_get_score(earned=0, possible=1, first_attempted=datetime(2000, 1, 1, 0, 0, 0)):
def mock_get_score(earned=0, possible=1, first_attempted=datetime(2000, 1, 1, 0, 0, 0, tzinfo=pytz.UTC)):
"""
Mocks the get_score function to return a valid grade.
"""
@@ -48,7 +49,7 @@ def mock_get_score(earned=0, possible=1, first_attempted=datetime(2000, 1, 1, 0,
@contextmanager
def mock_get_submissions_score(earned=0, possible=1, first_attempted=datetime(2000, 1, 1, 0, 0, 0)):
def mock_get_submissions_score(earned=0, possible=1, first_attempted=datetime(2000, 1, 1, 0, 0, 0, tzinfo=pytz.UTC)):
"""
Mocks the _get_submissions_score function to return the specified values
"""

View File

@@ -1,6 +1,7 @@
from datetime import datetime
import ddt
import pytz
from celery.states import FAILURE
from django.core.management import call_command
from django.core.management.base import CommandError
@@ -45,7 +46,7 @@ class TestFailOldQueueingTasksCommand(InstructorTaskTestCase):
Override each task's "created" date
"""
for task in self.tasks:
task.created = datetime.strptime(created_date, "%Y-%m-%d")
task.created = datetime.strptime(created_date, "%Y-%m-%d").replace(tzinfo=pytz.UTC)
task.save()
def get_tasks(self):

View File

@@ -67,7 +67,7 @@ class RefundTests(ModuleStoreTestCase):
self.order = Order.get_cart_for_user(self.student)
CertificateItem.add_to_order(self.order, self.course_id, 1, self.course_mode.mode_slug)
self.order.purchase()
self.course_mode.expiration_datetime = datetime.datetime(1983, 4, 6)
self.course_mode.expiration_datetime = datetime.datetime(1983, 4, 6, tzinfo=pytz.UTC)
self.course_mode.save()
def test_support_access(self):
@@ -96,7 +96,7 @@ class RefundTests(ModuleStoreTestCase):
@patch('student.models.CourseEnrollment.refund_cutoff_date')
def test_not_refundable(self, cutoff_date):
self._enroll()
self.course_mode.expiration_datetime = datetime.datetime(2033, 4, 6)
self.course_mode.expiration_datetime = datetime.datetime(2033, 4, 6, tzinfo=pytz.UTC)
self.course_mode.save()
cutoff_date.return_value = datetime.datetime.now(pytz.UTC) + datetime.timedelta(days=1)
response = self.client.post('/support/refund/', self.form_pars)

View File

@@ -9,7 +9,7 @@ import itertools
import json
import unittest
from collections import namedtuple
from datetime import datetime, timedelta
from datetime import timedelta
import ddt
import pytest
@@ -20,6 +20,7 @@ from django.http import HttpResponse
from django.test import TestCase
from django.test.utils import override_settings
from django.utils.http import urlencode
from django.utils.timezone import now
from nose.plugins.attrib import attr
from oauth2_provider import models as dot_models
from rest_framework import status
@@ -123,7 +124,7 @@ class OAuth2Tests(TestCase):
user=self.user,
token='dot-access-token',
application=self.dot_oauth2_client,
expires=datetime.now() + timedelta(days=30),
expires=now() + timedelta(days=30),
)
# This is the a change we've made from the django-rest-framework-oauth version
@@ -253,7 +254,7 @@ class OAuth2Tests(TestCase):
@unittest.skipUnless(oauth2_provider, 'django-oauth2-provider not installed')
def test_post_form_with_expired_access_token_failing_auth(self):
"""Ensure POSTing with expired access token fails with a 'token_expired' error"""
self.access_token.expires = datetime.now() - timedelta(seconds=10) # 10 seconds late
self.access_token.expires = now() - timedelta(seconds=10) # 10 seconds late
self.access_token.save()
response = self.post_with_bearer_token('/oauth2-test/')
self.check_error_codes(