Commit 6bfb801b authored by Tres Seaver's avatar Tres Seaver

Backported fix for timezone issues in date index tests from trunk.

parent b5ab9d1c
......@@ -18,6 +18,8 @@ Features Added
Bugs Fixed
++++++++++
- Backported fix for timezone issues in date index tests from trunk.
- LP #414757 (backported from Zope trunk): don't emit a IEndRequestEvent when
clearing a cloned request.
......
......@@ -16,18 +16,6 @@ $Id$
"""
import unittest
import Testing
import Zope2
Zope2.startup()
from datetime import date, datetime, tzinfo, timedelta
import time
from types import IntType, FloatType
from DateTime import DateTime
from Products.PluginIndexes.DateIndex.DateIndex import DateIndex, Local
class Dummy:
......@@ -48,21 +36,28 @@ class Dummy:
###############################################################################
# excerpted from the Python module docs
###############################################################################
ZERO = timedelta(0)
HOUR = timedelta(hours=1)
def first_sunday_on_or_after(dt):
def _getEastern():
from datetime import date
from datetime import datetime
from datetime import timedelta
from datetime import tzinfo
ZERO = timedelta(0)
HOUR = timedelta(hours=1)
def first_sunday_on_or_after(dt):
days_to_go = 6 - dt.weekday()
if days_to_go:
dt += timedelta(days_to_go)
return dt
# In the US, DST starts at 2am (standard time) on the first Sunday in April.
DSTSTART = datetime(1, 4, 1, 2)
# and ends at 2am (DST time; 1am standard time) on the last Sunday of Oct.
# which is the first Sunday on or after Oct 25.
DSTEND = datetime(1, 10, 25, 1)
# In the US, DST starts at 2am (standard time) on the first Sunday in
# April...
DSTSTART = datetime(1, 4, 1, 2)
# and ends at 2am (DST time; 1am standard time) on the last Sunday of
# October, which is the first Sunday on or after Oct 25.
DSTEND = datetime(1, 10, 25, 1)
class USTimeZone(tzinfo):
class USTimeZone(tzinfo):
def __init__(self, hours, reprname, stdname, dstname):
self.stdoffset = timedelta(hours=hours)
......@@ -102,13 +97,25 @@ class USTimeZone(tzinfo):
else:
return ZERO
Eastern = USTimeZone(-5, "Eastern", "EST", "EDT")
return USTimeZone(-5, "Eastern", "EST", "EDT")
###############################################################################
class DI_Tests(unittest.TestCase):
def setUp(self):
self._values = (
def _getTargetClass(self):
from Products.PluginIndexes.DateIndex.DateIndex import DateIndex
return DateIndex
def _makeOne(self, id='date'):
return self._getTargetClass()(id)
def _getValues(self):
from DateTime import DateTime
from datetime import date
from datetime import datetime
return [
(0, Dummy('a', None)), # None
(1, Dummy('b', DateTime(0))), # 1055335680
(2, Dummy('c', DateTime('2002-05-08 15:16:17'))), # 1072667236
......@@ -120,29 +127,15 @@ class DI_Tests(unittest.TestCase):
(8, Dummy('g', date(2034,2,5))), # 1073599200
(9, Dummy('h', datetime(2034,2,5,15,20,5))), # (varies)
(10, Dummy('i', datetime(2034,2,5,10,17,5,
tzinfo=Eastern))), # 1073600117
)
self._index = DateIndex('date')
self._noop_req = {'bar': 123}
self._request = {'date': DateTime(0)}
self._min_req = {'date': {'query': DateTime('2032-05-08 15:16:17'),
'range': 'min'}}
self._max_req = {'date': {'query': DateTime('2032-05-08 15:16:17'),
'range': 'max'}}
self._range_req = {'date': {'query':(DateTime('2002-05-08 15:16:17'),
DateTime('2062-05-08 15:16:17')),
'range': 'min:max'}}
self._zero_req = {'date': 0}
self._none_req = {'date': None}
self._float_req = {'date': 1072742620.0}
self._int_req = {'date': 1072742900}
def _populateIndex( self ):
for k, v in self._values:
self._index.index_object(k, v)
def _checkApply(self, req, expectedValues):
result, used = self._index._apply_index(req)
tzinfo=_getEastern()))), # 1073600117
]
def _populateIndex(self, index):
for k, v in self._getValues():
index.index_object(k, v)
def _checkApply(self, index, req, expectedValues):
result, used = index._apply_index(req)
if hasattr(result, 'keys'):
result = result.keys()
self.failUnlessEqual(used, ('date',))
......@@ -152,8 +145,12 @@ class DI_Tests(unittest.TestCase):
self.failUnless(k in result)
def _convert(self, dt):
if type(dt) in (FloatType, IntType):
yr, mo, dy, hr, mn = time.gmtime(dt)[:5]
from time import gmtime
from datetime import date
from datetime import datetime
from Products.PluginIndexes.DateIndex.DateIndex import Local
if isinstance(dt, (float, int)):
yr, mo, dy, hr, mn = gmtime(dt)[:5]
elif type(dt) is date:
yr, mo, dy, hr, mn = dt.timetuple()[:5]
elif type(dt) is datetime:
......@@ -171,37 +168,50 @@ class DI_Tests(unittest.TestCase):
from Products.PluginIndexes.interfaces import IUniqueValueIndex
from zope.interface.verify import verifyClass
verifyClass(IDateIndex, DateIndex)
verifyClass(IPluggableIndex, DateIndex)
verifyClass(ISortIndex, DateIndex)
verifyClass(IUniqueValueIndex, DateIndex)
verifyClass(IDateIndex, self._getTargetClass())
verifyClass(IPluggableIndex, self._getTargetClass())
verifyClass(ISortIndex, self._getTargetClass())
verifyClass(IUniqueValueIndex, self._getTargetClass())
def test_empty(self):
empty = self._index
from DateTime import DateTime
index = self._makeOne()
self.failUnlessEqual(len(empty), 0)
self.failUnlessEqual(len(empty.referencedObjects()), 0)
self.failUnlessEqual(len(index), 0)
self.failUnlessEqual(len(index.referencedObjects()), 0)
self.failUnless(empty.getEntryForObject(1234) is None)
self.failUnless(index.getEntryForObject(1234) is None)
marker = []
self.failUnless(empty.getEntryForObject(1234, marker) is marker)
empty.unindex_object(1234) # shouldn't throw
self.failUnless(empty.hasUniqueValuesFor('date'))
self.failIf(empty.hasUniqueValuesFor('foo'))
self.failUnlessEqual(len(empty.uniqueValues('date')), 0)
self.failUnless(empty._apply_index({'zed': 12345}) is None)
self.failUnless(index.getEntryForObject(1234, marker) is marker)
index.unindex_object(1234) # shouldn't throw
self._checkApply(self._request, [])
self._checkApply(self._min_req, [])
self._checkApply(self._max_req, [])
self._checkApply(self._range_req, [])
self.failUnless(index.hasUniqueValuesFor('date'))
self.failIf(index.hasUniqueValuesFor('foo'))
self.failUnlessEqual(len(index.uniqueValues('date')), 0)
self.failUnless(index._apply_index({'zed': 12345}) is None)
self._checkApply(index,
{'date': DateTime(0)}, [])
self._checkApply(index,
{'date': {'query': DateTime('2032-05-08 15:16:17'),
'range': 'min'}},
[])
self._checkApply(index,
{'date': {'query': DateTime('2032-05-08 15:16:17'),
'range': 'max'}},
[])
self._checkApply(index,
{'date': {'query':(DateTime('2002-05-08 15:16:17'),
DateTime('2062-05-08 15:16:17')),
'range': 'min:max'}},
[])
def test_retrieval( self ):
self._populateIndex()
values = self._values
index = self._index
from DateTime import DateTime
index = self._makeOne()
self._populateIndex(index)
values = self._getValues()
self.failUnlessEqual(len(index), len(values) - 2) # One dupe, one empty
self.failUnlessEqual(len(index.referencedObjects()), len(values) - 1)
......@@ -214,30 +224,43 @@ class DI_Tests(unittest.TestCase):
for k, v in values:
if v.date():
self.failUnlessEqual(self._index.getEntryForObject(k),
self.failUnlessEqual(index.getEntryForObject(k),
self._convert(v.date()))
self.failUnlessEqual(len(index.uniqueValues('date')), len(values) - 2)
self.failUnless(index._apply_index(self._noop_req) is None)
self._checkApply(self._request, values[1:2])
self._checkApply(self._min_req, values[3:6] + values[8:])
self._checkApply(self._max_req, values[1:4] + values[6:8])
self._checkApply(self._range_req, values[2:] )
self._checkApply(self._float_req, [values[6]] )
self._checkApply(self._int_req, [values[7]] )
self.failUnless(index._apply_index({'bar': 123}) is None)
self._checkApply(index,
{'date': DateTime(0)}, values[1:2])
self._checkApply(index,
{'date': {'query': DateTime('2032-05-08 15:16:17'),
'range': 'min'}},
values[3:6] + values[8:])
self._checkApply(index,
{'date': {'query': DateTime('2032-05-08 15:16:17'),
'range': 'max'}},
values[1:4] + values[6:8])
self._checkApply(index,
{'date': {'query':(DateTime('2002-05-08 15:16:17'),
DateTime('2062-05-08 15:16:17')),
'range': 'min:max'}},
values[2:] )
self._checkApply(index,
{'date': 1072742620.0}, [values[6]])
self._checkApply(index,
{'date': 1072742900}, [values[7]])
def test_naive_convert_to_utc(self):
values = self._values
index = self._index
index = self._makeOne()
values = self._getValues()
index.index_naive_time_as_local = False
self._populateIndex()
self._populateIndex(index)
for k, v in values[9:]:
# assert that the timezone is effectively UTC for item 9,
# and still correct for item 10
yr, mo, dy, hr, mn = v.date().utctimetuple()[:5]
val = (((yr * 12 + mo) * 31 + dy) * 24 + hr) * 60 + mn
self.failUnlessEqual(self._index.getEntryForObject(k), val)
self.failUnlessEqual(index.getEntryForObject(k), val)
def test_removal(self):
""" DateIndex would hand back spurious entries when used as a
......@@ -246,10 +269,11 @@ class DI_Tests(unittest.TestCase):
None. The catalog consults a sort_index's
documentToKeyMap() to build the brains.
"""
values = self._values
index = self._index
self._populateIndex()
self._checkApply(self._int_req, [values[7]])
values = self._getValues()
index = self._makeOne()
self._populateIndex(index)
self._checkApply(index,
{'date': 1072742900}, [values[7]])
index.index_object(7, None)
self.failIf(7 in index.documentToKeyMap().keys())
......
......@@ -16,14 +16,6 @@ $Id$
"""
import unittest
import Testing
import Zope2
Zope2.startup()
import sys
from Products.PluginIndexes.DateRangeIndex.DateRangeIndex import DateRangeIndex
class Dummy:
......@@ -74,11 +66,22 @@ def matchingDummies( value ):
class DRI_Tests( unittest.TestCase ):
def setUp( self ):
pass
def tearDown( self ):
pass
def _getTargetClass(self):
from Products.PluginIndexes.DateRangeIndex.DateRangeIndex \
import DateRangeIndex
return DateRangeIndex
def _makeOne(self,
id,
since_field=None,
until_field=None,
caller=None,
extra=None,
):
klass = self._getTargetClass()
return klass(id, since_field, until_field, caller, extra)
def test_z3interfaces(self):
from Products.PluginIndexes.interfaces import IDateRangeIndex
......@@ -87,14 +90,14 @@ class DRI_Tests( unittest.TestCase ):
from Products.PluginIndexes.interfaces import IUniqueValueIndex
from zope.interface.verify import verifyClass
verifyClass(IDateRangeIndex, DateRangeIndex)
verifyClass(IPluggableIndex, DateRangeIndex)
verifyClass(ISortIndex, DateRangeIndex)
verifyClass(IUniqueValueIndex, DateRangeIndex)
verifyClass(IDateRangeIndex, self._getTargetClass())
verifyClass(IPluggableIndex, self._getTargetClass())
verifyClass(ISortIndex, self._getTargetClass())
verifyClass(IUniqueValueIndex, self._getTargetClass())
def test_empty( self ):
empty = DateRangeIndex( 'empty' )
empty = self._makeOne( 'empty' )
assert empty.getEntryForObject( 1234 ) is None
empty.unindex_object( 1234 ) # shouldn't throw
......@@ -111,18 +114,18 @@ class DRI_Tests( unittest.TestCase ):
def test_retrieval( self ):
work = DateRangeIndex( 'work', 'start', 'stop' )
index = self._makeOne( 'work', 'start', 'stop' )
for i in range( len( dummies ) ):
work.index_object( i, dummies[i] )
index.index_object( i, dummies[i] )
for i in range( len( dummies ) ):
assert work.getEntryForObject( i ) == dummies[i].datum()
self.assertEqual(index.getEntryForObject( i ), dummies[i].datum())
for value in range( -1, 15 ):
matches = matchingDummies( value )
results, used = work._apply_index( { 'work' : value } )
results, used = index._apply_index( { 'work' : value } )
assert used == ( 'start', 'stop' )
assert len( matches ) == len( results ), ( '%s: %s == %s'
......@@ -131,44 +134,85 @@ class DRI_Tests( unittest.TestCase ):
matches.sort( lambda x, y: cmp( x.name(), y.name() ) )
for result, match in map( None, results, matches ):
assert work.getEntryForObject( result ) == match.datum()
self.assertEqual(index.getEntryForObject(result), match.datum())
def test_longdates( self ):
self.assertRaises(OverflowError, self._badlong )
def _badlong(self):
work = DateRangeIndex ('work', 'start', 'stop' )
import sys
index = self._makeOne ('work', 'start', 'stop' )
bad = Dummy( 'bad', long(sys.maxint) + 1, long(sys.maxint) + 1 )
work.index_object( 0, bad )
index.index_object( 0, bad )
def test_datetime(self):
from datetime import datetime
from DateTime.DateTime import DateTime
from Products.PluginIndexes.DateIndex.tests.test_DateIndex \
import _getEastern
before = datetime(2009, 7, 11, 0, 0, tzinfo=_getEastern())
start = datetime(2009, 7, 13, 5, 15, tzinfo=_getEastern())
between = datetime(2009, 7, 13, 5, 45, tzinfo=_getEastern())
stop = datetime(2009, 7, 13, 6, 30, tzinfo=_getEastern())
after = datetime(2009, 7, 14, 0, 0, tzinfo=_getEastern())
dummy = Dummy('test', start, stop)
index = self._makeOne( 'work', 'start', 'stop' )
index.index_object(0, dummy)
self.assertEqual(index.getEntryForObject(0),
(DateTime(start).millis() / 60000,
DateTime(stop).millis() / 60000))
results, used = index._apply_index( { 'work' : before } )
self.assertEqual(len(results), 0)
results, used = index._apply_index( { 'work' : start } )
self.assertEqual(len(results), 1)
results, used = index._apply_index( { 'work' : between } )
self.assertEqual(len(results), 1)
results, used = index._apply_index( { 'work' : stop } )
self.assertEqual(len(results), 1)
results, used = index._apply_index( { 'work' : after } )
self.assertEqual(len(results), 0)
def test_datetime_naive_timezone(self):
from datetime import datetime
from DateTime.DateTime import DateTime
from Products.PluginIndexes.DateIndex.DateIndex import Local
before = datetime(2009, 7, 11, 0, 0)
start = datetime(2009, 7, 13, 5, 15)
start_local = datetime(2009, 7, 13, 5, 15, tzinfo=Local)
between = datetime(2009, 7, 13, 5, 45)
stop = datetime(2009, 7, 13, 6, 30)
stop_local = datetime(2009, 7, 13, 6, 30, tzinfo=Local)
after = datetime(2009, 7, 14, 0, 0)
dummy = Dummy('test', start, stop)
work = DateRangeIndex( 'work', 'start', 'stop' )
work.index_object(0, dummy)
index = self._makeOne( 'work', 'start', 'stop' )
index.index_object(0, dummy)
assert work.getEntryForObject(0) == (20790915, 20790990)
self.assertEqual(index.getEntryForObject(0),
(DateTime(start_local).millis() / 60000,
DateTime(stop_local).millis() / 60000))
results, used = work._apply_index( { 'work' : before } )
assert len(results) == 0
results, used = index._apply_index( { 'work' : before } )
self.assertEqual(len(results), 0)
results, used = work._apply_index( { 'work' : start } )
assert len(results) == 1
results, used = index._apply_index( { 'work' : start } )
self.assertEqual(len(results), 1)
results, used = work._apply_index( { 'work' : between } )
assert len(results) == 1
results, used = index._apply_index( { 'work' : between } )
self.assertEqual(len(results), 1)
results, used = work._apply_index( { 'work' : stop } )
assert len(results) == 1
results, used = index._apply_index( { 'work' : stop } )
self.assertEqual(len(results), 1)
results, used = work._apply_index( { 'work' : after } )
assert len(results) == 0
results, used = index._apply_index( { 'work' : after } )
self.assertEqual(len(results), 0)
def test_suite():
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment