You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@allura.apache.org by br...@apache.org on 2013/02/05 22:03:15 UTC
[1/2] git commit: [#5705] Added comments and tests for bin_count
changes
[#5705] Added comments and tests for bin_count changes
Signed-off-by: Cory Johns <jo...@geek.net>
Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/bb34f6a3
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/bb34f6a3
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/bb34f6a3
Branch: refs/heads/master
Commit: bb34f6a3c148d93cfa713b4c1e79f48018049a53
Parents: 3c7c8f6
Author: Cory Johns <jo...@geek.net>
Authored: Mon Feb 4 23:26:26 2013 +0000
Committer: Dave Brondsema <db...@geek.net>
Committed: Tue Feb 5 21:01:10 2013 +0000
----------------------------------------------------------------------
ForgeTracker/forgetracker/model/ticket.py | 7 ++
.../forgetracker/tests/unit/test_globals_model.py | 69 +++++++++++++++
2 files changed, 76 insertions(+), 0 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/bb34f6a3/ForgeTracker/forgetracker/model/ticket.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/model/ticket.py b/ForgeTracker/forgetracker/model/ticket.py
index 82a52c1..96f3f7e 100644
--- a/ForgeTracker/forgetracker/model/ticket.py
+++ b/ForgeTracker/forgetracker/model/ticket.py
@@ -127,6 +127,8 @@ class Globals(MappedClass):
self._bin_counts_invalidated = None
def bin_count(self, name):
+ # not sure why we expire bin counts after an hour even if unchanged
+ # I guess a catch-all in case invalidate_bin_counts is missed
if self._bin_counts_expire < datetime.utcnow():
self.invalidate_bin_counts()
for d in self._bin_counts_data:
@@ -149,6 +151,11 @@ class Globals(MappedClass):
def invalidate_bin_counts(self):
'''Force expiry of bin counts and queue them to be updated.'''
+ # To prevent multiple calls to this method from piling on redundant
+ # tasks, we set _bin_counts_invalidated when we post the task, and
+ # the task clears it when it's done. However, in the off chance
+ # that the task fails or is interrupted, we ignore the flag if it's
+ # older than 5 minutes.
invalidation_expiry = datetime.utcnow() - timedelta(minutes=5)
if self._bin_counts_invalidated is not None and \
self._bin_counts_invalidated > invalidation_expiry:
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/bb34f6a3/ForgeTracker/forgetracker/tests/unit/test_globals_model.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/tests/unit/test_globals_model.py b/ForgeTracker/forgetracker/tests/unit/test_globals_model.py
index aaa88c2..b713265 100644
--- a/ForgeTracker/forgetracker/tests/unit/test_globals_model.py
+++ b/ForgeTracker/forgetracker/tests/unit/test_globals_model.py
@@ -1,3 +1,8 @@
+import mock
+from nose.tools import assert_equal
+from datetime import datetime, timedelta
+
+import forgetracker
from forgetracker.model import Globals
from forgetracker.tests.unit import TrackerTestWithModel
from pylons import c
@@ -27,6 +32,70 @@ class TestGlobalsModel(TrackerTestWithModel):
h.set_context('test', 'doc-bugs', neighborhood='Projects')
assert Globals.next_ticket_num() == 1
+ @mock.patch('forgetracker.model.ticket.datetime')
+ def test_bin_count(self, mock_dt):
+ now = datetime.utcnow()
+ mock_dt.utcnow.return_value = now
+ gbl = Globals()
+ gbl._bin_counts_data = [{'summary': 'foo', 'hits': 1}, {'summary': 'bar', 'hits': 2}]
+ gbl.invalidate_bin_counts = mock.Mock()
+
+ # not expired, finds bin
+ gbl._bin_counts_expire = now + timedelta(minutes=5)
+ bin = gbl.bin_count('bar')
+ assert_equal(bin['hits'], 2)
+ assert not gbl.invalidate_bin_counts.called
+
+ # expired, returns value for missing bin
+ gbl._bin_counts_expire = now - timedelta(minutes=5)
+ bin = gbl.bin_count('qux')
+ assert_equal(bin['hits'], 0)
+ assert gbl.invalidate_bin_counts.called
+
+ @mock.patch('forgetracker.tasks.update_bin_counts')
+ @mock.patch('forgetracker.model.ticket.datetime')
+ def test_invalidate_bin_counts(self, mock_dt, mock_task):
+ now = datetime.utcnow().replace(microsecond=0)
+ mock_dt.utcnow.return_value = now
+ gbl = Globals()
+
+ # invalidated recently, don't dog-pile
+ gbl._bin_counts_invalidated = now - timedelta(minutes=1)
+ gbl.invalidate_bin_counts()
+ assert not mock_task.post.called
+
+ # invalidated too long ago, call again
+ gbl._bin_counts_invalidated = now - timedelta(minutes=6)
+ gbl.invalidate_bin_counts()
+ assert mock_task.post.called
+ assert_equal(gbl._bin_counts_invalidated, now)
+
+ # never invalidated
+ mock_task.reset_mock()
+ gbl._bin_counts_invalidated = None
+ gbl.invalidate_bin_counts()
+ assert mock_task.post.called
+ assert_equal(gbl._bin_counts_invalidated, now)
+
+ @mock.patch('forgetracker.model.ticket.Bin')
+ @mock.patch('forgetracker.model.ticket.search_artifact')
+ @mock.patch('forgetracker.model.ticket.datetime')
+ def test_update_bin_counts(self, mock_dt, mock_search, mock_bin):
+ now = datetime.utcnow().replace(microsecond=0)
+ mock_dt.utcnow.return_value = now
+ gbl = Globals()
+ gbl._bin_counts_invalidated = now - timedelta(minutes=1)
+ mock_bin.query.find.return_value = [mock.Mock(summary='foo', terms='bar')]
+ mock_search().hits = 5
+
+ assert_equal(gbl._bin_counts_data, []) # sanity pre-check
+ gbl.update_bin_counts()
+ assert mock_bin.query.find.called
+ mock_search.assert_called_with(forgetracker.model.Ticket, 'bar', rows=0, short_timeout=False)
+ assert_equal(gbl._bin_counts_data, [{'summary': 'foo', 'hits': 5}])
+ assert_equal(gbl._bin_counts_expire, now + timedelta(minutes=60))
+ assert_equal(gbl._bin_counts_invalidated, None)
+
class TestCustomFields(TrackerTestWithModel):
def test_it_has_sortable_custom_fields(self):