blob: 2e7c591a3501d9c424ac2e147f3ed593acc1e70c [file] [log] [blame]
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
from datetime import datetime, timedelta
import mock
from tg import tmpl_context as c
from ming.orm.ormsession import ThreadLocalORMSession
import forgetracker
from forgetracker.model import Globals
from forgetracker.tests.unit import TrackerTestWithModel
from allura.lib import helpers as h
class TestGlobalsModel(TrackerTestWithModel):
def setup_method(self, method):
super().setup_method(method)
c.project.install_app('Tickets', 'doc-bugs')
ThreadLocalORMSession.flush_all()
def test_it_has_current_tracker_globals(self):
bugs_globals = Globals.query.get(app_config_id=c.app.config._id)
assert c.app.globals == bugs_globals
h.set_context('test', 'doc-bugs', neighborhood='Projects')
assert c.app.globals != bugs_globals
def test_next_ticket_number_increments(self):
gl = Globals()
assert gl.next_ticket_num() == 1
assert gl.next_ticket_num() == 2
def test_ticket_numbers_are_independent(self):
with h.push_context('test', 'doc-bugs', neighborhood='Projects'):
assert c.app.globals.next_ticket_num() == 1
with h.push_context('test', 'bugs', neighborhood='Projects'):
assert c.app.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.invalidate_bin_counts.reset_mock()
gbl._bin_counts_expire = now + timedelta(minutes=5)
bin = gbl.bin_count('bar')
assert bin['hits'] == 2
assert not gbl.invalidate_bin_counts.called
# expired, returns value for missing bin
gbl.invalidate_bin_counts.reset_mock()
gbl._bin_counts_expire = now - timedelta(minutes=5)
bin = gbl.bin_count('qux')
assert bin['hits'] == 0
assert gbl.invalidate_bin_counts.called
# config set to no expiration
gbl.invalidate_bin_counts.reset_mock()
with mock.patch.dict('forgetracker.model.ticket.tg_config', **{'forgetracker.bin_cache_expire': 0}):
gbl._bin_counts_expire = now - timedelta(minutes=5)
bin = gbl.bin_count('qux')
assert not gbl.invalidate_bin_counts.called
# no expire value (e.g. from previously having config set to no expirations)
gbl.invalidate_bin_counts.reset_mock()
gbl._bin_counts_expire = None
bin = gbl.bin_count('qux')
assert 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 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 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 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, fq=['-deleted_b:true'])
assert gbl._bin_counts_data == [{'summary': 'foo', 'hits': 5}]
assert gbl._bin_counts_expire == now + timedelta(minutes=60)
assert gbl._bin_counts_invalidated == None
def test_append_new_labels(self):
gbl = Globals()
assert gbl.append_new_labels([], ['tag1']) == ['tag1']
assert (
gbl.append_new_labels(['tag1', 'tag2'], ['tag2']) == ['tag1', 'tag2'])
assert gbl.append_new_labels(
['tag1', 'tag2'], ['tag3']) == ['tag1', 'tag2', 'tag3']
assert gbl.append_new_labels(
['tag1', 'tag2', 'tag3'], ['tag2']) == ['tag1', 'tag2', 'tag3']
class TestCustomFields(TrackerTestWithModel):
def test_it_has_sortable_custom_fields(self):
tracker_globals = globals_with_custom_fields(
[dict(label='Iteration Number',
name='_iteration_number',
show_in_search=False),
dict(label='Point Estimate',
name='_point_estimate',
show_in_search=True)])
expected = [dict(sortable_name='_point_estimate_s',
name='_point_estimate',
label='Point Estimate')]
assert tracker_globals.sortable_custom_fields_shown_in_search(
) == expected
def globals_with_custom_fields(custom_fields):
c.app.globals.custom_fields = custom_fields
ThreadLocalORMSession.flush_all()
return c.app.globals