summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mailman/database/autorespond.py6
-rw-r--r--src/mailman/docs/autorespond.txt10
-rw-r--r--src/mailman/testing/layers.py21
-rw-r--r--src/mailman/utilities/datetime.py69
4 files changed, 102 insertions, 4 deletions
diff --git a/src/mailman/database/autorespond.py b/src/mailman/database/autorespond.py
index 9561e804c..0a22dfa14 100644
--- a/src/mailman/database/autorespond.py
+++ b/src/mailman/database/autorespond.py
@@ -27,7 +27,6 @@ __all__ = [
]
-from datetime import date
from storm.locals import And, Date, Int, Reference
from zope.interface import implements
@@ -37,6 +36,7 @@ from mailman.database.types import Enum
from mailman.interfaces.autorespond import (
IAutoResponseRecord, IAutoResponseSet, Response)
from mailman.interfaces.mailinglist import IMailingList
+from mailman.utilities.datetime import today
@@ -58,7 +58,7 @@ class AutoResponseRecord(Model):
self.mailing_list = mailing_list
self.address = address
self.response_type = response_type
- self.date_sent = date.today()
+ self.date_sent = today()
@@ -75,7 +75,7 @@ class AutoResponseSet:
And(AutoResponseRecord.address == address,
AutoResponseRecord.mailing_list == self._mailing_list,
AutoResponseRecord.response_type == response_type,
- AutoResponseRecord.date_sent == date.today())).count()
+ AutoResponseRecord.date_sent == today())).count()
def response_sent(self, address, response_type):
"""See `IAutoResponseSet`."""
diff --git a/src/mailman/docs/autorespond.txt b/src/mailman/docs/autorespond.txt
index 29af740ec..d2e4797f7 100644
--- a/src/mailman/docs/autorespond.txt
+++ b/src/mailman/docs/autorespond.txt
@@ -60,3 +60,13 @@ Let's send one more.
1
>>> response_set.todays_count(address, Response.command)
2
+
+Now the day flips over and all the counts reset.
+
+ >>> from mailman.utilities.datetime import factory
+ >>> factory.fast_forward()
+
+ >>> response_set.todays_count(address, Response.hold)
+ 0
+ >>> response_set.todays_count(address, Response.command)
+ 0
diff --git a/src/mailman/testing/layers.py b/src/mailman/testing/layers.py
index 19300ba1e..3f7e63406 100644
--- a/src/mailman/testing/layers.py
+++ b/src/mailman/testing/layers.py
@@ -22,6 +22,7 @@ from __future__ import absolute_import, unicode_literals
__metaclass__ = type
__all__ = [
'ConfigLayer',
+ 'MockAndMonkeyLayer',
'SMTPLayer',
]
@@ -40,6 +41,7 @@ from mailman.core import initialize
from mailman.core.logging import get_handler
from mailman.i18n import _
from mailman.testing.helpers import SMTPServer
+from mailman.utilities.datetime import factory
from mailman.utilities.string import expand
@@ -47,7 +49,24 @@ NL = '\n'
-class ConfigLayer:
+class MockAndMonkeyLayer:
+ """Layer for mocking and monkey patching for testing."""
+
+ @classmethod
+ def setUp(cls):
+ factory.testing_mode = True
+
+ @classmethod
+ def tearDown(cls):
+ factory.testing_mode = False
+
+ @classmethod
+ def testTearDown(cls):
+ factory.reset()
+
+
+
+class ConfigLayer(MockAndMonkeyLayer):
"""Layer for pushing and popping test configurations."""
var_dir = None
diff --git a/src/mailman/utilities/datetime.py b/src/mailman/utilities/datetime.py
new file mode 100644
index 000000000..764b2eecd
--- /dev/null
+++ b/src/mailman/utilities/datetime.py
@@ -0,0 +1,69 @@
+# Copyright (C) 2009 by the Free Software Foundation, Inc.
+#
+# This file is part of GNU Mailman.
+#
+# GNU Mailman is free software: you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free
+# Software Foundation, either version 3 of the License, or (at your option)
+# any later version.
+#
+# GNU Mailman is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+# more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# GNU Mailman. If not, see <http://www.gnu.org/licenses/>.
+
+"""Datetime utilities.
+
+Use these functions to produce variable times rather than the built-in
+datetime.datetime.now() and datetime.date.today(). These are better
+instrumented for testing purposes.
+"""
+
+
+from __future__ import absolute_import, unicode_literals
+
+__metaclass__ = type
+__all__ = [
+ ]
+
+
+import datetime
+
+
+
+class DateFactory:
+ """A factory for today() and now() that works with testing."""
+
+ # Set to True to produce predictable dates and times.
+ testing_mode = False
+ # The predictable time.
+ predictable_now = None
+ predictable_today = None
+
+ def now(self, tz=None):
+ return (self.predictable_now
+ if self.testing_mode
+ else datetime.datetime.now(tz))
+
+ def today(self):
+ return (self.predictable_today
+ if self.testing_mode
+ else datetime.date.today())
+
+ @classmethod
+ def reset(cls):
+ cls.predictable_now = datetime.datetime(2005, 8, 1, 7, 49, 23)
+ cls.predictable_today = cls.predictable_now.today()
+
+ @classmethod
+ def fast_forward(cls, days=1):
+ cls.predictable_today += datetime.timedelta(days=days)
+
+
+factory = DateFactory()
+factory.reset()
+today = factory.today
+now = factory.now