From 21213ed8c6c873ef8e019419e3bad61836c51d76 Mon Sep 17 00:00:00 2001 From: Douglas Hall <dhall@edx.org> Date: Tue, 19 Jan 2016 16:29:59 -0500 Subject: [PATCH] Use django.utils.timezone.now() when determining if the due date of a component has passed to avoid tz-aware/naive datetime comparison bug --- lti_consumer/lti_consumer.py | 5 +++-- lti_consumer/tests/unit/test_lti_consumer.py | 21 +++++++++++++++++--- setup.py | 2 +- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/lti_consumer/lti_consumer.py b/lti_consumer/lti_consumer.py index f3e4e8a..84e8430 100644 --- a/lti_consumer/lti_consumer.py +++ b/lti_consumer/lti_consumer.py @@ -56,10 +56,11 @@ import re import json import urllib -from datetime import datetime from collections import namedtuple from webob import Response +from django.utils import timezone + from xblock.core import String, Scope, List, XBlock from xblock.fields import Boolean, Float, Integer from xblock.fragment import Fragment @@ -597,7 +598,7 @@ class LtiConsumerXBlock(StudioEditableXBlockMixin, XBlock): close_date = due_date + self.graceperiod # pylint: disable=no-member else: close_date = due_date - return close_date is not None and datetime.utcnow() > close_date + return close_date is not None and timezone.now() > close_date def student_view(self, context): """ diff --git a/lti_consumer/tests/unit/test_lti_consumer.py b/lti_consumer/tests/unit/test_lti_consumer.py index 8d8d4ad..652e59f 100644 --- a/lti_consumer/tests/unit/test_lti_consumer.py +++ b/lti_consumer/tests/unit/test_lti_consumer.py @@ -4,9 +4,11 @@ Unit tests for LtiConsumerXBlock import unittest -from datetime import datetime, timedelta +from datetime import timedelta from mock import Mock, PropertyMock, patch +from django.utils import timezone + from lti_consumer.tests.unit.test_utils import FAKE_USER_ID, make_xblock, make_request from lti_consumer.lti_consumer import LtiConsumerXBlock, parse_handler_suffix @@ -206,7 +208,7 @@ class TestProperties(TestLtiConsumerXBlock): """ Test `is_past_due` when a graceperiod has been defined """ - now = datetime.utcnow() + now = timezone.now() self.xblock.graceperiod = timedelta(days=1) self.xblock.due = now @@ -219,7 +221,7 @@ class TestProperties(TestLtiConsumerXBlock): """ Test `is_past_due` when no graceperiod has been defined """ - now = datetime.utcnow() + now = timezone.now() self.xblock.graceperiod = None self.xblock.due = now - timedelta(days=1) @@ -228,6 +230,19 @@ class TestProperties(TestLtiConsumerXBlock): self.xblock.due = now + timedelta(days=1) self.assertFalse(self.xblock.is_past_due) + @patch('lti_consumer.lti_consumer.timezone.now') + def test_is_past_due_timezone_now_called(self, mock_timezone_now): + """ + Test `is_past_due` calls django.utils.timezone.now to get current datetime + """ + now = timezone.now() + self.xblock.graceperiod = None + self.xblock.due = now + mock_timezone_now.return_value = now + + __ = self.xblock.is_past_due + self.assertTrue(mock_timezone_now.called) + class TestStudentView(TestLtiConsumerXBlock): """ diff --git a/setup.py b/setup.py index 5c4a756..3622d3d 100644 --- a/setup.py +++ b/setup.py @@ -22,7 +22,7 @@ def package_data(pkg, roots): setup( name='lti_consumer-xblock', - version='1.0.1', + version='1.0.2', description='This XBlock implements the consumer side of the LTI specification.', packages=[ 'lti_consumer', -- GitLab