debian-koji/tests/test_hub/test_repo_requests.py
2025-05-19 09:48:20 +02:00

1471 lines
55 KiB
Python

import json
import shutil
import tempfile
import unittest
from unittest import mock
import koji
import kojihub
import kojihub.db
from kojihub import repos
QP = repos.QueryProcessor
IP = repos.InsertProcessor
UP = repos.UpdateProcessor
TASK = kojihub.Task
class MyError(Exception):
pass
class BaseTest(unittest.TestCase):
def setUp(self):
self.context = mock.MagicMock()
self.context.session.assertLogin = mock.MagicMock()
self.getLastEvent = mock.MagicMock()
self.getEvent = mock.MagicMock()
self.context.handlers = {
'getLastEvent': self.getLastEvent,
'getEvent': self.getEvent,
}
mock.patch('kojihub.repos.context', new=self.context).start()
mock.patch('kojihub.db.context', new=self.context).start()
mock.patch('kojihub.kojihub.context', new=self.context).start()
self.context.opts = {
# duplicating hub defaults
'MaxRepoTasks': 10,
'MaxRepoTasksMaven': 2,
'RepoRetries': 3,
'RequestCleanTime': 60 * 24,
'RepoLag': 3600,
'RepoAutoLag': 7200,
'RepoLagWindow': 600,
'RepoQueueUser': 'kojira',
'DebuginfoTags': '',
'SourceTags': '',
'SeparateSourceTags': '',
'EnableMaven': False,
}
self.QueryProcessor = mock.patch('kojihub.repos.QueryProcessor',
side_effect=self.getQuery).start()
self.queries = []
self.InsertProcessor = mock.patch('kojihub.repos.InsertProcessor',
side_effect=self.getInsert).start()
self.inserts = []
self.UpdateProcessor = mock.patch('kojihub.repos.UpdateProcessor',
side_effect=self.getUpdate).start()
self.updates = []
self._dml = mock.patch('kojihub.db._dml').start()
self.exports = kojihub.RootExports()
self.get_tag = mock.patch('kojihub.kojihub.get_tag').start()
self.get_id = mock.patch('kojihub.kojihub.get_id').start()
self.make_task = mock.patch('kojihub.kojihub.make_task').start()
self.tag_last_change_event = mock.patch('kojihub.kojihub.tag_last_change_event').start()
self.tag_first_change_event = mock.patch('kojihub.kojihub.tag_first_change_event').start()
self.query_execute = mock.MagicMock()
self.query_executeOne = mock.MagicMock()
self.query_singleValue = mock.MagicMock()
self.RepoQueueQuery = mock.patch('kojihub.repos.RepoQueueQuery').start()
self.RepoQuery = mock.patch('kojihub.repos.RepoQuery').start()
self.nextval = mock.patch('kojihub.repos.nextval').start()
def tearDown(self):
mock.patch.stopall()
def getQuery(self, *args, **kwargs):
query = QP(*args, **kwargs)
query.execute = self.query_execute
query.executeOne = self.query_executeOne
query.singleValue = self.query_singleValue
self.queries.append(query)
return query
def getInsert(self, *args, **kwargs):
insert = IP(*args, **kwargs)
insert.execute = mock.MagicMock()
self.inserts.append(insert)
return insert
def getUpdate(self, *args, **kwargs):
update = UP(*args, **kwargs)
update.execute = mock.MagicMock()
self.updates.append(update)
return update
class TestRepoQueue(BaseTest):
def setUp(self):
super(TestRepoQueue, self).setUp()
self.clean_repo_queue = mock.patch('kojihub.repos.clean_repo_queue').start()
self.repo_queue_task = mock.patch('kojihub.repos.repo_queue_task').start()
self.get_repo_from_task = mock.patch('kojihub.repos.get_repo_from_task').start()
self.valid_repo = mock.patch('kojihub.repos.valid_repo').start()
self.db_lock = mock.patch('kojihub.repos.db_lock').start()
self.db_lock.return_value = True
def test_nolock(self):
self.db_lock.return_value = False
repos.check_repo_queue()
self.db_lock.assert_called_once()
self.RepoQueueQuery.assert_not_called()
def test_check_queue_full(self):
self.context.opts['MaxRepoTasks'] = 10
basereq = {'task_state': koji.TASK_STATES['FREE'], 'opts': {}, 'tries': 1}
# 10 reqs with free tasks
reqs = [dict({'id': n, 'task_id': 100 + n}, **basereq) for n in range(10)]
# plus one with no task
reqs.append({'id': 99, 'task_id': None, 'task_state': None, 'opts': {}, 'tries': 1})
self.RepoQueueQuery.return_value.execute.return_value = reqs
repos.check_repo_queue()
self.repo_queue_task.assert_not_called()
self.UpdateProcessor.assert_not_called()
self.clean_repo_queue.assert_not_called()
def test_check_maven_full(self):
self.context.opts['MaxRepoTasksMaven'] = 2
basereq = {'task_state': koji.TASK_STATES['FREE'], 'opts': {'maven': True}, 'tries': 1}
# 2 maven reqs with free tasks
reqs = [dict({'id': n, 'task_id': 100 + n}, **basereq) for n in range(2)]
# plus two more, one maven, one not
req_a = {'id': 98, 'task_id': None, 'task_state': None, 'opts': {'maven': True},
'tries': 1}
req_b = {'id': 99, 'task_id': None, 'task_state': None, 'opts': {}, 'tries': 1}
reqs.extend([req_a, req_b])
self.RepoQueueQuery.return_value.execute.return_value = reqs
repos.check_repo_queue()
# only the non-maven should get a task
self.repo_queue_task.assert_called_once_with(req_b)
self.UpdateProcessor.assert_called_once()
self.clean_repo_queue.assert_called_once()
def test_check_queue_filled(self):
# fill up the queue
self.context.opts['MaxRepoTasks'] = 10
basereq = {'task_state': koji.TASK_STATES['FREE'], 'opts': {}, 'tries': 1}
# 9 reqs with free tasks
reqs = [dict({'id': n, 'task_id': 100 + n}, **basereq) for n in range(9)]
# plus two more
req_a = {'id': 98, 'task_id': None, 'task_state': None, 'opts': {}, 'tries': 1}
req_b = {'id': 99, 'task_id': None, 'task_state': None, 'opts': {}, 'tries': 1}
reqs.extend([req_a, req_b])
self.RepoQueueQuery.return_value.execute.return_value = reqs
repos.check_repo_queue()
# req_a should be fulfilled, but not req_b
self.repo_queue_task.assert_called_once_with(req_a)
self.UpdateProcessor.assert_called_once()
self.clean_repo_queue.assert_called_once()
def test_check_queue_filled_maven(self):
# fill up the queue
self.context.opts['MaxRepoTasks'] = 10
self.context.opts['MaxRepoTasksMaven'] = 2
base1 = {'task_state': koji.TASK_STATES['FREE'], 'opts': {}, 'tries': 1}
base2 = {'task_state': koji.TASK_STATES['FREE'], 'opts': {'maven': True}, 'tries': 1}
# 7 reqs with free tasks
reqs = [dict({'id': n, 'task_id': 100 + n}, **base1) for n in range(7)]
# 1 maven req with free tasks
reqs.append(dict({'id': 7, 'task_id': 107}, **base2))
# plus 4 more, two maven, two not
req_a = {'id': 96, 'task_id': None, 'task_state': None, 'opts': {'maven': True},
'tries': 1}
req_b = {'id': 97, 'task_id': None, 'task_state': None, 'opts': {'maven': True},
'tries': 1}
req_c = {'id': 98, 'task_id': None, 'task_state': None, 'opts': {}, 'tries': 1}
req_d = {'id': 99, 'task_id': None, 'task_state': None, 'opts': {}, 'tries': 1}
reqs.extend([req_a, req_b, req_c, req_d])
self.RepoQueueQuery.return_value.execute.return_value = reqs
repos.check_repo_queue()
# req_a and req_c should be fulfilled, but not b or d
expected = [mock.call(req_a), mock.call(req_c)]
self.assertEqual(self.repo_queue_task.call_args_list, expected)
self.clean_repo_queue.assert_called_once()
def test_check_queue_retry(self):
self.context.opts['MaxRepoTasks'] = 10
self.context.opts['MaxRepoTasksMaven'] = 2
self.context.opts['RepoRetries'] = 3
base = {'id': 100, 'task_id': 200, 'task_state': koji.TASK_STATES['FREE'], 'opts': {},
'tries': 1}
# these should get retries
reqs1 = [
dict(base, task_state=koji.TASK_STATES['CANCELED']),
dict(base, task_state=koji.TASK_STATES['CANCELED'], tries=3),
dict(base, task_state=koji.TASK_STATES['FAILED']),
dict(base, task_state=koji.TASK_STATES['FAILED'], tries=3),
]
# these should not
reqs2 = [
dict(base, task_state=koji.TASK_STATES['OPEN']),
dict(base, task_state=koji.TASK_STATES['FREE']),
dict(base, task_state=koji.TASK_STATES['CANCELED'], tries=4),
dict(base, task_state=koji.TASK_STATES['FAILED'], tries=4),
]
self.RepoQueueQuery.return_value.execute.return_value = reqs1 + reqs2
repos.check_repo_queue()
expected = [mock.call(r) for r in reqs1]
self.assertEqual(self.repo_queue_task.call_args_list, expected)
self.assertEqual(len(self.UpdateProcessor.mock_calls), 8)
self.clean_repo_queue.assert_called_once()
def test_check_queue_badrepo1(self):
req = {'id': 100, 'task_id': 200, 'task_state': koji.TASK_STATES['CLOSED'], 'opts': {},
'tries': 1}
self.RepoQueueQuery.return_value.execute.return_value = [req]
self.get_repo_from_task.return_value = None
# should retry
repos.check_repo_queue()
self.repo_queue_task.assert_called_once_with(req)
self.UpdateProcessor.assert_called_once()
self.clean_repo_queue.assert_called_once()
def test_check_queue_badrepo2(self):
req = {'id': 100, 'task_id': 200, 'task_state': koji.TASK_STATES['CLOSED'], 'opts': {},
'tries': 1}
self.RepoQueueQuery.return_value.execute.return_value = [req]
self.get_repo_from_task.return_value = 'REPO'
self.valid_repo.return_value = False
# should retry
repos.check_repo_queue()
self.repo_queue_task.assert_called_once_with(req)
self.UpdateProcessor.assert_called_once()
self.clean_repo_queue.assert_called_once()
def test_check_queue_goodrepo(self):
req = {'id': 100, 'task_id': 200, 'task_state': koji.TASK_STATES['CLOSED'], 'opts': {},
'tries': 1}
self.RepoQueueQuery.return_value.execute.return_value = [req]
repo = {'id': 123, 'sentinel': 'hello 123dfs'}
self.get_repo_from_task.return_value = repo
self.valid_repo.return_value = True
# should update, not retry
repos.check_repo_queue()
self.repo_queue_task.assert_not_called()
self.UpdateProcessor.assert_called_once()
self.clean_repo_queue.assert_called_once()
class TestRepoFromTask(BaseTest):
def setUp(self):
super(TestRepoFromTask, self).setUp()
self.Task = mock.patch('kojihub.kojihub.Task').start()
def test_valid(self):
result = [1234, "ignored event id"]
self.Task.return_value.getResult.return_value = result
self.RepoQuery.return_value.execute.return_value = ["REPO"]
repo = repos.get_repo_from_task("TASK_ID")
self.assertEqual(repo, "REPO")
self.Task.assert_called_once_with("TASK_ID")
self.RepoQuery.assert_called_once_with([['id', '=', 1234]])
def test_missing(self):
result = [1234, "ignored event id"]
self.Task.return_value.getResult.return_value = result
self.RepoQuery.return_value.execute.return_value = []
repo = repos.get_repo_from_task("TASK_ID")
self.assertEqual(repo, None)
self.Task.assert_called_once_with("TASK_ID")
self.RepoQuery.assert_called_once_with([['id', '=', 1234]])
def test_invalid(self):
result = ["invalid: not an int", "ignored event id"]
self.Task.return_value.getResult.return_value = result
self.RepoQuery.return_value.execute.return_value = []
repo = repos.get_repo_from_task("TASK_ID")
self.assertEqual(repo, None)
self.Task.assert_called_once_with("TASK_ID")
self.RepoQuery.assert_not_called()
class TestRepoRequests(BaseTest):
def test_clean_queue(self):
repos.clean_repo_queue()
def test_valid_repo(self):
# match
req = {'id': 101,
'at_event': None,
'min_event': 101010,
'opts': {},
'tag_id': 42,
'tag_name': 'TAG'}
repo = {'id': 999,
'tag_id': 42,
'begin_event': 497440,
'create_event': 101020,
'custom_opts': {},
'dist': False,
'opts': {'debuginfo': False, 'separate_src': False, 'src': False},
'state': 1}
check = repos.valid_repo(req, repo)
self.assertTrue(check)
# wrong tag
bad = repo.copy()
bad['tag_id'] = 99
check = repos.valid_repo(req, bad)
self.assertFalse(check)
# wrong state
bad = repo.copy()
bad['state'] = 2
check = repos.valid_repo(req, bad)
self.assertFalse(check)
# wrong event
bad = repo.copy()
bad['create_event'] = 101000
check = repos.valid_repo(req, bad)
self.assertFalse(check)
# wrong at_event
req2 = req.copy()
req2.update(min_event=None, at_event=10000)
bad = repo.copy()
bad['create_event'] = 101000
check = repos.valid_repo(req2, bad)
self.assertFalse(check)
# different opt value
bad = repo.copy()
bad['opts'] = {'debuginfo': True, 'separate_src': False, 'src': False}
bad['custom_opts'] = {'debuginfo': True}
check = repos.valid_repo(req, bad)
self.assertFalse(check)
# missing opt value
req2 = req.copy()
req2.update(opts={'debuginfo': True})
bad = repo.copy()
bad['opts'] = {'separate_src': False, 'src': False}
bad['custom_opts'] = {'debuginfo': True}
check = repos.valid_repo(req2, bad)
self.assertFalse(check)
# wrong custom opts
req2 = req.copy()
req2.update(opts={'src': True})
bad = repo.copy()
bad['opts'] = {'debuginfo': True, 'separate_src': False, 'src': False}
bad['custom_opts'] = {'debuginfo': True}
check = repos.valid_repo(req2, bad)
self.assertFalse(check)
# invalid opts
req2 = req.copy()
req2.update(opts={'src': True})
bad = repo.copy()
bad['opts'] = {}
# opts field should never be blank
bad['custom_opts'] = {}
check = repos.valid_repo(req2, bad)
self.assertFalse(check)
class TestDoneHook(BaseTest):
def setUp(self):
super(TestDoneHook, self).setUp()
self.Savepoint = mock.patch('kojihub.repos.Savepoint').start()
def test_simple(self):
repos.repo_done_hook(100)
def test_no_repo(self):
self.RepoQuery.return_value.executeOne.return_value = None
# should return without error
repos.repo_done_hook(100)
# should not query further or update
self.RepoQueueQuery.assert_not_called()
self.UpdateProcessor.assert_not_called()
# no exception
self.Savepoint.return_value.rollback.assert_not_called()
def test_dist_repo(self):
self.RepoQuery.return_value.executeOne.return_value = {'dist': True}
# hook should not process dist repos
repos.repo_done_hook(100)
# should not query further or update
self.RepoQueueQuery.assert_not_called()
self.UpdateProcessor.assert_not_called()
# no exception
self.Savepoint.return_value.rollback.assert_not_called()
def test_invalid_repo(self):
# hook should not process invalid repos
self.RepoQuery.return_value.executeOne.return_value = {'dist': False, 'opts': None,
'custom_opts': {}}
repos.repo_done_hook(100)
# should not query further or update
self.RepoQueueQuery.assert_not_called()
self.UpdateProcessor.assert_not_called()
# no exception
self.Savepoint.return_value.rollback.assert_not_called()
def test_no_match(self):
repo = {'dist': False, 'opts': {}, 'custom_opts': {}, 'tag_id': 'TAGID',
'create_event': 101010}
self.RepoQuery.return_value.executeOne.return_value = repo
self.RepoQueueQuery.return_value.execute.return_value = []
repos.repo_done_hook(100)
self.assertEqual(len(self.RepoQueueQuery.call_args_list), 2)
# should not update
self.UpdateProcessor.assert_not_called()
# no exception
self.Savepoint.return_value.rollback.assert_not_called()
def test_match(self):
repo = {'id': 55, 'dist': False, 'opts': {}, 'custom_opts': {}, 'tag_id': 'TAGID',
'create_event': 101010}
self.RepoQuery.return_value.executeOne.return_value = repo
req = {'id': 'REQ_ID'}
self.RepoQueueQuery.return_value.execute.side_effect = [[req], []]
repos.repo_done_hook(100)
self.assertEqual(len(self.RepoQueueQuery.call_args_list), 2)
# should not update
self.UpdateProcessor.assert_called_once()
update = self.updates[0]
self.assertEqual(update.table, 'repo_queue')
self.assertEqual(update.values, {'ids': ['REQ_ID']})
self.assertEqual(update.data, {'repo_id': 55, 'active': False})
# no exception
self.Savepoint.return_value.rollback.assert_not_called()
def test_exception(self):
self.RepoQuery.side_effect = MyError()
# should return without error
repos.repo_done_hook(100)
# should not query further or update
self.RepoQueueQuery.assert_not_called()
self.UpdateProcessor.assert_not_called()
# rollback should be called
self.Savepoint.return_value.rollback.assert_called_once()
class TestSymlink(BaseTest):
def setUp(self):
super(TestSymlink, self).setUp()
self.tempdir = tempfile.mkdtemp()
self.pathinfo = koji.PathInfo(self.tempdir)
mock.patch('koji.pathinfo', new=self.pathinfo).start()
self.symlink = mock.patch('os.symlink').start()
self.lexists = mock.patch('os.path.lexists').start()
self.unlink = mock.patch('os.unlink').start()
self.lexists.return_value = False
def tearDown(self):
super(TestSymlink, self).tearDown()
shutil.rmtree(self.tempdir)
def test_skip_custom(self):
repo = {'dist': False, 'custom_opts': {'src': True}}
result = repos.symlink_if_latest(repo)
self.assertFalse(result)
self.RepoQuery.assert_not_called()
self.symlink.assert_not_called()
def test_skip_old(self):
repo = {'dist': False, 'custom_opts': {}, 'tag_id': 'TAGID', 'create_event': 101010}
self.RepoQuery.return_value.execute.return_value = ['REPO']
result = repos.symlink_if_latest(repo)
self.assertFalse(result)
self.symlink.assert_not_called()
# and same for a dist repo
repo['dist'] = True
result = repos.symlink_if_latest(repo)
self.assertFalse(result)
self.symlink.assert_not_called()
def test_symlink(self):
repo = {'id': 99, 'dist': False, 'custom_opts': {}, 'tag_id': 'TAGID',
'create_event': 101010, 'tag_name': 'MYTAG'}
self.RepoQuery.return_value.execute.return_value = []
self.lexists.return_value = False
result = repos.symlink_if_latest(repo)
self.assertTrue(result)
expect = self.tempdir + '/repos/MYTAG/latest'
self.symlink.assert_called_with('99', expect)
self.unlink.assert_not_called()
def test_symlink_dist(self):
repo = {'id': 99, 'dist': True, 'custom_opts': {}, 'tag_id': 'TAGID',
'create_event': 101010, 'tag_name': 'MYTAG'}
self.RepoQuery.return_value.execute.return_value = []
result = repos.symlink_if_latest(repo)
self.assertTrue(result)
expect = self.tempdir + '/repos-dist/MYTAG/latest'
self.symlink.assert_called_with('99', expect)
def test_symlink_replace(self):
repo = {'id': 99, 'dist': False, 'custom_opts': {}, 'tag_id': 'TAGID',
'create_event': 101010, 'tag_name': 'MYTAG'}
self.RepoQuery.return_value.execute.return_value = []
self.lexists.return_value = True
result = repos.symlink_if_latest(repo)
self.assertTrue(result)
expect = self.tempdir + '/repos/MYTAG/latest'
self.unlink.assert_called_once_with(expect)
self.symlink.assert_called_with('99', expect)
def test_symlink_fail(self):
repo = {'id': 99, 'dist': False, 'custom_opts': {}, 'tag_id': 'TAGID',
'create_event': 101010, 'tag_name': 'MYTAG'}
self.RepoQuery.return_value.execute.return_value = []
self.symlink.side_effect = OSError('failed')
result = repos.symlink_if_latest(repo)
self.assertFalse(result)
self.symlink.assert_called_once()
class TestQueueTask(BaseTest):
def setUp(self):
super(TestQueueTask, self).setUp()
self.ensuredir = mock.patch('koji.ensuredir').start()
def test_queue_task(self):
req = {'id': 100, 'tag_id': 42, 'tag_name': 'tag 100',
'min_event': None, 'at_event': None, 'opts': None}
req['opts'] = {}
repos.repo_queue_task(req)
self.make_task.assert_called_once()
def test_queue_task_event(self):
req = {'id': 100, 'tag_id': 42, 'tag_name': 'tag 100',
'min_event': None, 'at_event': 101010, 'opts': None}
req['opts'] = {}
repos.repo_queue_task(req)
self.make_task.assert_called_once()
method, args = self.make_task.call_args.args
taskopts = self.make_task.call_args.kwargs
self.assertEqual(method, 'newRepo')
self.assertEqual(taskopts['channel'], 'createrepo')
params = koji.tasks.parse_task_params('newRepo', args)
self.assertEqual(params['event'], 101010)
class TestUpdateEndEvents(BaseTest):
def setUp(self):
super(TestUpdateEndEvents, self).setUp()
self.BulkUpdateProcessor = mock.patch('kojihub.repos.BulkUpdateProcessor').start()
def test_no_update(self):
repo = {'id': 1, 'tag_id': 99, 'create_event': 1000}
self.RepoQuery.return_value.execute.return_value = [repo]
self.tag_first_change_event.return_value = None
self.tag_last_change_event.return_value = 1000
repos.update_end_events()
self.BulkUpdateProcessor.assert_not_called()
def test_update(self):
repo = {'id': 1, 'tag_id': 99, 'create_event': 1000}
self.RepoQuery.return_value.execute.return_value = [repo]
self.tag_first_change_event.return_value = 1001
repos.update_end_events()
self.tag_last_change_event.assert_not_called()
expect = [{'id': 1, 'end_event': 1001}]
self.BulkUpdateProcessor.assert_called_once()
updates = self.BulkUpdateProcessor.call_args.kwargs['data']
self.assertEqual(updates, expect)
def test_event_cache(self):
# two current and one obsolete. all same tag
repolist = [
{'id': 1, 'tag_id': 99, 'create_event': 1000},
# first is current, populates tag_last cache
{'id': 2, 'tag_id': 99, 'create_event': 1000},
{'id': 3, 'tag_id': 99, 'create_event': 1000},
# 2 and 3 avoid checking tag due to cache
{'id': 4, 'tag_id': 99, 'create_event': 999},
# 4 is obsolete
]
self.tag_last_change_event.return_value = 1000
self.RepoQuery.return_value.execute.return_value = repolist
self.tag_first_change_event.side_effect = [None, 1000]
# the latter should only be called twice due to cache
repos.update_end_events()
self.tag_last_change_event.assert_called_once_with(99)
expect_calls = [
mock.call(99, after=1000),
mock.call(99, after=999),
]
self.assertEqual(self.tag_first_change_event.mock_calls, expect_calls)
expect_updates = [{'id': 4, 'end_event': 1000}]
self.BulkUpdateProcessor.assert_called_once()
updates = self.BulkUpdateProcessor.call_args.kwargs['data']
self.assertEqual(updates, expect_updates)
class TestExternalRepo(BaseTest):
def setUp(self):
super(TestExternalRepo, self).setUp()
self.get_external_repo_id = mock.patch('kojihub.kojihub.get_external_repo_id').start()
def test_get_external(self):
self.get_external_repo_id.return_value = 42
self.query_singleValue.return_value = 'DATA'
data = repos.get_external_repo_data('my_ext_repo')
self.assertEqual(data, 'DATA')
self.QueryProcessor.assert_called_once()
query = self.queries[0]
self.assertEqual(query.tables, ['external_repo_data'])
self.assertEqual(query.values, {'id': 42})
def test_set_external(self):
self.get_external_repo_id.return_value = 42
self.query_singleValue.return_value = 'DATA'
data = {'max_ts': 1717171717}
repos.set_external_repo_data('my_ext_repo', data)
self.UpdateProcessor.assert_called_once()
self.InsertProcessor.assert_called_once()
insert = self.inserts[0]
self.assertEqual(insert.data['external_repo_id'], 42)
self.assertEqual(json.loads(insert.data['data']), data)
class TestAutoRequests(BaseTest):
def setUp(self):
super(TestAutoRequests, self).setUp()
self.request_repo = mock.patch('kojihub.repos.request_repo').start()
self.tag_last_change_event = mock.patch('kojihub.kojihub.tag_last_change_event').start()
self.time = mock.patch('time.time').start()
def test_auto_requests(self):
autokeys = [
{'tag_id': 99, 'key': 'repo.auto', 'value': 'true'},
]
self.query_execute.return_value = autokeys
self.getLastEvent.return_value = {'id': 1050}
self.tag_last_change_event.return_value = 1000
self.request_repo.return_value = {'repo': None, 'request': 'REQ', 'duplicate': False}
repos.do_auto_requests()
self.request_repo.assert_called_once_with(99, min_event=1000, priority=5)
def test_no_tags(self):
autokeys = []
self.query_execute.return_value = autokeys
self.request_repo.assert_not_called()
self.tag_last_change_event.assert_not_called()
def test_bad_row(self):
autokeys = [
{'tag_id': 99, 'key': 'repo.auto', 'value': 'true'},
{'tag_id': 98, 'key': 'repo.auto', 'value': 'not+valid+json'},
{'tag_id': 98, 'key': 'repo.lag', 'value': '"valid json, but not valid int"'},
]
# the bad rows should be ignored without blocking other auto requests
self.query_execute.return_value = autokeys
self.getLastEvent.return_value = {'id': 1050}
self.tag_last_change_event.return_value = 1000
self.request_repo.return_value = {'repo': None, 'request': 'REQ', 'duplicate': False}
repos.do_auto_requests()
self.request_repo.assert_called_once_with(99, min_event=1000, priority=5)
def test_blocked_row(self):
autokeys = [
{'tag_id': 99, 'key': 'repo.auto', 'value': 'true'},
{'tag_id': 98, 'key': 'repo.auto', 'value': None},
]
# the blocked row should be ignored without blocking other auto requests
self.query_execute.return_value = autokeys
self.getLastEvent.return_value = {'id': 1050}
self.tag_last_change_event.return_value = 1000
self.request_repo.return_value = {'repo': None, 'request': 'REQ', 'duplicate': False}
repos.do_auto_requests()
self.request_repo.assert_called_once_with(99, min_event=1000, priority=5)
def test_auto_lag(self):
# use a trivial window to simplify the lag calculation
self.context.opts['RepoLagWindow'] = 1
autokeys = [
{'tag_id': 99, 'key': 'repo.auto', 'value': 'true'},
{'tag_id': 99, 'key': 'repo.lag', 'value': '0'},
]
now = 1717171717
self.time.return_value = now
self.query_execute.return_value = autokeys
self.getLastEvent.return_value = {'id': 1050}
self.tag_last_change_event.return_value = 1000
self.request_repo.return_value = {'repo': None, 'request': 'REQ', 'duplicate': True}
repos.do_auto_requests()
self.request_repo.assert_called_once_with(99, min_event=1000, priority=5)
# with zero lag, getLastEvent should be called with current time
self.getLastEvent.assert_called_once_with(before=now, strict=False)
def test_auto_lag_window(self):
self.context.opts['RepoLagWindow'] = 600
autokeys = [
{'tag_id': 99, 'key': 'repo.auto', 'value': 'true'},
{'tag_id': 99, 'key': 'repo.lag', 'value': '0'},
]
now = 1717171717
self.time.return_value = now
self.query_execute.return_value = autokeys
self.getLastEvent.return_value = {'id': 1050}
self.tag_last_change_event.return_value = 1000
self.request_repo.return_value = {'repo': None, 'request': 'REQ', 'duplicate': False}
repos.do_auto_requests()
self.request_repo.assert_called_once_with(99, min_event=1000, priority=5)
# with zero lag, getLastEvent should be called with current time
self.getLastEvent.assert_called_once()
before = self.getLastEvent.call_args.kwargs['before']
# should be earlier than current time, but within lag window
if before > now or before < now - 600:
raise Exception('Invalid lag calculation')
def test_no_last_tag_event(self):
# corner case that should not happen
autokeys = [
{'tag_id': 99, 'key': 'repo.auto', 'value': 'true'},
]
self.query_execute.return_value = autokeys
self.tag_last_change_event.return_value = None
repos.do_auto_requests()
self.request_repo.assert_not_called()
self.tag_last_change_event.assert_called_once()
def test_no_last_event(self):
# corner case that can happen with very new instances
autokeys = [
{'tag_id': 99, 'key': 'repo.auto', 'value': 'true'},
]
self.getLastEvent.return_value = None
self.query_execute.return_value = autokeys
self.tag_last_change_event.return_value = 1000
self.tag_first_change_event.return_value = 990
self.request_repo.return_value = {'repo': None, 'request': 'REQ', 'duplicate': False}
repos.do_auto_requests()
self.request_repo.assert_called_once_with(99, min_event=990, priority=5)
self.tag_last_change_event.assert_called_once()
self.tag_first_change_event.assert_called_once()
repos.do_auto_requests()
class TestGetRepo(BaseTest):
def test_get_repo_simple(self):
self.RepoQuery.return_value.executeOne.return_value = 'REPO'
repo = repos.get_repo('TAGID')
self.assertEqual(repo, 'REPO')
self.RepoQuery.assert_called_once()
def test_get_repo_at_event(self):
repos.get_repo('TAGID', at_event=101010)
self.RepoQuery.assert_called_once()
clauses, fields, qopts = self.RepoQuery.call_args.args
self.assertIn(['create_event', '=', 101010], clauses)
def test_get_repo_min_event(self):
repos.get_repo('TAGID', min_event=101010)
self.RepoQuery.assert_called_once()
clauses, fields, qopts = self.RepoQuery.call_args.args
self.assertIn(['create_event', '>=', 101010], clauses)
class TestGetRepoOpts(BaseTest):
def test_basic(self):
taginfo = {'extra': {}}
opts, custom = repos.get_repo_opts(taginfo)
expect = {'src': False, 'debuginfo': False, 'separate_src': False, 'maven': False}
self.assertEqual(opts, expect)
self.assertEqual(custom, {})
def test_override(self):
taginfo = {'extra': {}}
override = {'src': True}
opts, custom = repos.get_repo_opts(taginfo, override)
expect = {'src': True, 'debuginfo': False, 'separate_src': False, 'maven': False}
self.assertEqual(opts, expect)
self.assertEqual(custom, override)
def test_override_redundant(self):
taginfo = {'extra': {}}
override = {'src': False} # default setting, shouldn't be reported as custom
opts, custom = repos.get_repo_opts(taginfo, override)
expect = {'src': False, 'debuginfo': False, 'separate_src': False, 'maven': False}
self.assertEqual(opts, expect)
self.assertEqual(custom, {})
def test_pattern_debug(self):
self.context.opts['DebuginfoTags'] = 'TAG*'
taginfo = {'name': 'TAG123', 'extra': {}}
opts, custom = repos.get_repo_opts(taginfo)
expect = {'src': False, 'debuginfo': True, 'separate_src': False, 'maven': False}
self.assertEqual(opts, expect)
self.assertEqual(custom, {})
def test_pattern_source(self):
self.context.opts['SourceTags'] = 'TAG*'
taginfo = {'name': 'TAG123', 'extra': {}}
opts, custom = repos.get_repo_opts(taginfo)
expect = {'src': True, 'debuginfo': False, 'separate_src': False, 'maven': False}
self.assertEqual(opts, expect)
self.assertEqual(custom, {})
def test_pattern_separate_src(self):
self.context.opts['SeparateSourceTags'] = 'TAG*'
taginfo = {'name': 'TAG123', 'extra': {}}
opts, custom = repos.get_repo_opts(taginfo)
expect = {'src': False, 'debuginfo': False, 'separate_src': True, 'maven': False}
self.assertEqual(opts, expect)
self.assertEqual(custom, {})
def test_pattern_nomatch(self):
self.context.opts['DebuginfoTags'] = 'FOO*'
self.context.opts['SourceTags'] = 'FOO*'
self.context.opts['SeparateSourceTags'] = 'FOO*'
# this one shouldn't match
taginfo = {'name': 'bar123', 'extra': {}}
opts, custom = repos.get_repo_opts(taginfo)
expect = {'src': False, 'debuginfo': False, 'separate_src': False, 'maven': False}
self.assertEqual(opts, expect)
self.assertEqual(custom, {})
def test_tag_config(self):
taginfo = {'extra': {'repo.opts': {'debuginfo': True}}}
opts, custom = repos.get_repo_opts(taginfo)
expect = {'src': False, 'debuginfo': True, 'separate_src': False, 'maven': False}
self.assertEqual(opts, expect)
self.assertEqual(custom, {})
# old debuginfo should still work
taginfo = {'extra': {'with_debuginfo': True}}
opts, custom = repos.get_repo_opts(taginfo)
expect = {'src': False, 'debuginfo': True, 'separate_src': False, 'maven': False}
self.assertEqual(opts, expect)
self.assertEqual(custom, {})
# but repo.opts should win
taginfo = {'extra': {'repo.opts': {}, 'with_debuginfo': True}}
opts, custom = repos.get_repo_opts(taginfo)
expect = {'src': False, 'debuginfo': False, 'separate_src': False, 'maven': False}
self.assertEqual(opts, expect)
self.assertEqual(custom, {})
def test_old_maven(self):
self.context.opts['EnableMaven'] = True
taginfo = {'extra': {}, 'maven_support': True}
opts, custom = repos.get_repo_opts(taginfo)
expect = {'src': False, 'debuginfo': False, 'separate_src': False, 'maven': True}
self.assertEqual(opts, expect)
self.assertEqual(custom, {})
def test_maven_disabled(self):
self.context.opts['EnableMaven'] = False
taginfo = {'extra': {}, 'maven_support': True}
taginfo = {'extra': {'repo.opts': {'maven': True}, 'maven_support': True}}
# should report maven=false regardless of other settings
opts, custom = repos.get_repo_opts(taginfo)
expect = {'src': False, 'debuginfo': False, 'separate_src': False, 'maven': False}
self.assertEqual(opts, expect)
self.assertEqual(custom, {})
def test_maven_disabled_override(self):
self.context.opts['EnableMaven'] = False
taginfo = {'extra': {}}
override = {'maven': True}
opts, custom = repos.get_repo_opts(taginfo, override)
# should report the override anyway
expect = {'src': False, 'debuginfo': False, 'separate_src': False, 'maven': True}
self.assertEqual(opts, expect)
self.assertEqual(custom, override)
class TestConvertRepoOpts(BaseTest):
def test_basic(self):
value = {'debuginfo': False, 'src': True}
# correctly formatted opts should not change
opts = repos.convert_repo_opts(value)
self.assertEqual(opts, value)
def test_wrong_type(self):
opts = repos.convert_repo_opts('STRING')
self.assertEqual(opts, {})
with self.assertRaises(koji.ParameterError):
repos.convert_repo_opts('STRING', strict=True)
def test_bad_key(self):
bad = {'XYZ': True, 'src': True}
opts = repos.convert_repo_opts(bad)
self.assertEqual(opts, {'src': True})
with self.assertRaises(koji.ParameterError):
repos.convert_repo_opts(bad, strict=True)
def test_null_value(self):
value = {'debuginfo': None, 'src': True}
opts = repos.convert_repo_opts(value)
self.assertEqual(opts, {'src': True})
class TestRequestRepo(BaseTest):
def setUp(self):
super(TestRequestRepo, self).setUp()
self.get_repo = mock.patch('kojihub.repos.get_repo').start()
self.set_request_priority = mock.patch('kojihub.repos.set_request_priority').start()
def test_basic_request(self):
self.get_tag.return_value = {'id': 100, 'name': 'TAG', 'extra': {}}
self.getLastEvent.return_value = {'id': 101010}
self.tag_last_change_event.return_value = 100000
repos.request_repo('TAGID')
def test_request_last(self):
self.get_tag.return_value = {'id': 100, 'name': 'TAG', 'extra': {}}
self.getLastEvent.return_value = {'id': 101010}
last = 100001
self.tag_last_change_event.return_value = last
self.get_repo.return_value = None
self.RepoQueueQuery.return_value.execute.return_value = []
repos.request_repo('TAGID', min_event="last")
# check all the calls made with the value
self.get_repo.assert_called_once()
ev = self.get_repo.call_args.kwargs['min_event']
self.assertEqual(ev, last)
clauses = self.RepoQueueQuery.call_args_list[0].args[0]
self.assertIn(['min_event', '>=', last], clauses)
self.InsertProcessor.assert_called_once()
data = self.InsertProcessor.call_args.kwargs['data']
self.assertEqual(data['min_event'], last)
def test_request_priority(self):
self.get_tag.return_value = {'id': 100, 'name': 'TAG', 'extra': {}}
ev = 100001
self.get_repo.return_value = None
self.RepoQueueQuery.return_value.execute.return_value = []
repos.request_repo('TAGID', min_event=ev, priority=5)
# check all the calls made with the value
self.InsertProcessor.assert_called_once()
data = self.InsertProcessor.call_args.kwargs['data']
self.assertEqual(data['min_event'], ev)
self.assertEqual(data['priority'], 25) # default + 5
def test_request_priority_lower_than_existing(self):
self.get_tag.return_value = {'id': 100, 'name': 'TAG', 'extra': {}}
ev = 100001
self.get_repo.return_value = None
oldreq = {'priority': 20, 'id': 424242} # default
self.RepoQueueQuery.return_value.execute.return_value = [oldreq]
ret = repos.request_repo('TAGID', min_event=ev, priority=5)
# we should return the existing entry
# we should not update the priority since it is higher
self.assertEqual(ret['request']['id'], 424242)
self.assertEqual(ret['request']['priority'], 20)
self.assertEqual(ret['duplicate'], True)
self.InsertProcessor.assert_not_called()
self.set_request_priority.assert_not_called()
def test_request_priority_higher_not_allowed(self):
self.context.session.hasPerm.return_value = False
with self.assertRaises(koji.ActionNotAllowed):
repos.request_repo('TAGID', min_event=101010, priority=-5)
self.get_repo.assert_not_called()
self.InsertProcessor.assert_not_called()
self.set_request_priority.assert_not_called()
def test_request_priority_higher_than_existing(self):
self.get_tag.return_value = {'id': 100, 'name': 'TAG', 'extra': {}}
ev = 100001
self.get_repo.return_value = None
oldreq = {'priority': 20, 'id': 424242} # default
self.RepoQueueQuery.return_value.execute.return_value = [oldreq]
ret = repos.request_repo('TAGID', min_event=ev, priority=-5)
# we should return the existing entry
# we should update the priority
self.assertEqual(ret['request']['id'], 424242)
self.assertEqual(ret['request']['priority'], 15)
self.assertEqual(ret['duplicate'], True)
self.InsertProcessor.assert_not_called()
self.set_request_priority.assert_called_once_with(424242, 15)
def test_maven_disabled(self):
self.context.opts['EnableMaven'] = False
self.get_tag.return_value = {'id': 100, 'name': 'TAG', 'extra': {}}
with self.assertRaises(koji.GenericError):
repos.request_repo('TAGID', opts={'maven': True})
self.InsertProcessor.assert_not_called()
self.get_repo.assert_not_called()
def test_event_conflict(self):
self.get_tag.return_value = {'id': 100, 'name': 'TAG', 'extra': {}}
with self.assertRaises(koji.ParameterError):
repos.request_repo('TAGID', min_event=100, at_event=101)
self.InsertProcessor.assert_not_called()
self.get_repo.assert_not_called()
def test_bad_at_event(self):
self.get_tag.return_value = {'id': 100, 'name': 'TAG', 'extra': {}}
self.getEvent.return_value = None
with self.assertRaises(koji.ParameterError):
repos.request_repo('TAGID', at_event=101)
self.InsertProcessor.assert_not_called()
self.get_repo.assert_not_called()
self.getEvent.assert_called_once_with(101, strict=False)
def test_bad_min_event(self):
self.get_tag.return_value = {'id': 100, 'name': 'TAG', 'extra': {}}
self.getEvent.return_value = None
with self.assertRaises(koji.ParameterError):
repos.request_repo('TAGID', min_event=101)
self.InsertProcessor.assert_not_called()
self.get_repo.assert_not_called()
self.getEvent.assert_called_once_with(101, strict=False)
def test_request_existing_repo(self):
# if a matching repo exists, we should return it
self.get_repo.return_value = 'MY-REPO'
self.get_tag.return_value = {'id': 100, 'name': 'TAG', 'extra': {}}
result = repos.request_repo('TAGID', min_event=101010)
self.assertEqual(result['repo'], 'MY-REPO')
self.get_repo.assert_called_with(100, min_event=101010, at_event=None, opts={})
self.RepoQueueQuery.assert_not_called()
self.nextval.assert_not_called()
self.assertEqual(self.inserts, [])
def test_request_existing_req(self):
# if a matching request exists, we should return it
self.get_tag.return_value = {'id': 100, 'name': 'TAG', 'extra': {}}
self.get_repo.return_value = None
req = {'repo_id': None, 'priority': 20, 'sentinel': 'hello'}
self.RepoQueueQuery.return_value.execute.return_value = [req]
result = repos.request_repo('TAG', min_event=101010)
self.assertEqual(result['request'], req)
self.get_repo.assert_called_with(100, min_event=101010, at_event=None, opts={})
self.RepoQueueQuery.assert_called_once()
expect = [['tag_id', '=', 100],
['active', 'IS', True],
['opts', '=', '{}'],
['min_event', '>=', 101010]]
clauses = self.RepoQueueQuery.mock_calls[0][1][0]
self.assertEqual(clauses, expect)
self.nextval.assert_not_called()
self.assertEqual(self.inserts, [])
def test_request_new_req(self):
# if a matching request exists, we should return it
self.get_tag.return_value = {'id': 100, 'name': 'TAG', 'extra': {}}
self.get_repo.return_value = None
self.RepoQueueQuery.return_value.execute.return_value = []
self.RepoQueueQuery.return_value.executeOne.return_value = 'NEW-REQ'
self.nextval.return_value = 'NEW-ID'
self.context.session.user_id = 'USER'
result = repos.request_repo('TAG', min_event=101010)
self.get_repo.assert_called_with(100, min_event=101010, at_event=None, opts={})
self.assertEqual(len(self.inserts), 1)
expect = {
'id': 'NEW-ID',
'owner': 'USER',
'priority': 20,
'tag_id': 100,
'at_event': None,
'min_event': 101010,
'opts': '{}',
}
self.assertEqual(self.inserts[0].data, expect)
self.assertEqual(self.RepoQueueQuery.call_count, 2)
# clauses for final query
clauses = self.RepoQueueQuery.call_args[1]['clauses']
self.assertEqual(clauses, [['id', '=', 'NEW-ID']])
self.assertEqual(result['request'], 'NEW-REQ')
def test_request_at_event(self):
# similate an at_event request that finds an existing matching request to return
self.get_tag.return_value = {'id': 100, 'name': 'TAG', 'extra': {}}
self.get_repo.return_value = None
req = {'repo_id': None, 'priority': 20, 'sentinel': 'hello'}
self.RepoQueueQuery.return_value.execute.return_value = [req]
result = repos.request_repo('TAG', at_event=101010)
self.assertEqual(result['request'], req)
self.get_repo.assert_called_with(100, min_event=None, at_event=101010, opts={})
self.RepoQueueQuery.assert_called_once()
expect = [['tag_id', '=', 100],
['active', 'IS', True],
['opts', '=', '{}'],
['at_event', '=', 101010]]
clauses = self.RepoQueueQuery.mock_calls[0][1][0]
self.assertEqual(clauses, expect)
self.nextval.assert_not_called()
self.assertEqual(self.inserts, [])
class TestDefaultMinEvent(BaseTest):
def setUp(self):
super(TestDefaultMinEvent, self).setUp()
self.time = mock.patch('time.time').start()
def test_simple_lag(self):
now = 1717171717
self.time.return_value = now
self.context.opts['RepoLag'] = 3600
self.context.opts['RepoLagWindow'] = 1
taginfo = {'id': 55, 'name': 'MYTAG', 'extra': {}} # no lag override
self.tag_last_change_event.return_value = 10000
self.getLastEvent.return_value = {'id': 9999}
ev = repos.default_min_event(taginfo)
# we should report the ts from the last event, minus lag
self.assertEqual(ev, 9999)
self.getLastEvent.assert_called_once()
base_ts = self.getLastEvent.call_args.kwargs['before']
self.assertEqual(base_ts, now - 3600)
def test_tag_older(self):
now = 1717171717
self.time.return_value = now
self.context.opts['RepoLag'] = 3600
self.context.opts['RepoLagWindow'] = 1
taginfo = {'id': 55, 'name': 'MYTAG', 'extra': {}} # no lag override
self.tag_last_change_event.return_value = 9900
self.getLastEvent.return_value = {'id': 9999}
ev = repos.default_min_event(taginfo)
# we should report the ts for the tag, since it is older
self.assertEqual(ev, 9900)
self.getLastEvent.assert_called_once()
base_ts = self.getLastEvent.call_args.kwargs['before']
self.assertEqual(base_ts, now - 3600)
def test_window(self):
now = 1717171717
self.time.return_value = now
self.context.opts['RepoLag'] = 3600
self.context.opts['RepoLagWindow'] = 300
taginfo = {'id': 55, 'name': 'MYTAG', 'extra': {}} # no lag override
self.tag_last_change_event.return_value = 9900
self.getLastEvent.return_value = {'id': 9999}
ev = repos.default_min_event(taginfo)
# we should report the ts for the tag, since it is older
self.assertEqual(ev, 9900)
self.getLastEvent.assert_called_once()
base_ts = self.getLastEvent.call_args.kwargs['before']
# should be earlier than target time, but within lag window
lag_ts = now - 3600
if base_ts > lag_ts or base_ts < lag_ts - 600:
raise Exception('Invalid lag window calculation')
def test_lag_override(self):
now = 1717171717
self.time.return_value = now
self.context.opts['RepoLag'] = 3600
self.context.opts['RepoLagWindow'] = 1
taginfo = {'id': 55, 'name': 'MYTAG', 'extra': {'repo.lag': 1800}}
self.tag_last_change_event.return_value = 10000
self.getLastEvent.return_value = {'id': 9999}
ev = repos.default_min_event(taginfo)
# we should report the ts from the last event, minus lag
self.assertEqual(ev, 9999)
self.getLastEvent.assert_called_once()
base_ts = self.getLastEvent.call_args.kwargs['before']
self.assertEqual(base_ts, now - 1800)
def test_lag_override_invalid(self):
now = 1717171717
self.time.return_value = now
self.context.opts['RepoLag'] = 3600
self.context.opts['RepoLagWindow'] = 1
taginfo = {'id': 55, 'name': 'MYTAG', 'extra': {'repo.lag': 'not an int'}}
self.tag_last_change_event.return_value = 10000
self.getLastEvent.return_value = {'id': 9999}
ev = repos.default_min_event(taginfo)
# we should report the ts from the last event, minus lag
self.assertEqual(ev, 9999)
self.getLastEvent.assert_called_once()
base_ts = self.getLastEvent.call_args.kwargs['before']
self.assertEqual(base_ts, now - 3600)
def test_no_last_event(self):
# corner case that can happen with very new instances
now = 1717171717
self.time.return_value = now
taginfo = {'id': 55, 'name': 'MYTAG', 'extra': {}}
self.tag_last_change_event.return_value = 10000
self.getLastEvent.return_value = None
self.tag_first_change_event.return_value = 9990
ev = repos.default_min_event(taginfo)
# in this corner case we should use the first event for the tag
self.assertEqual(ev, 9990)
self.getLastEvent.assert_called_once()
self.tag_first_change_event.assert_called_once_with(55)
class TestCheckRequest(BaseTest):
def setUp(self):
super(TestCheckRequest, self).setUp()
self.repo_info = mock.patch('kojihub.kojihub.repo_info').start()
self.Task = mock.patch('kojihub.kojihub.Task').start()
def test_have_repo(self):
req = {'repo_id': 'REPOID', 'task_id': 'TASKID'}
self.RepoQueueQuery.return_value.executeOne.return_value = req
self.repo_info.return_value = 'REPO'
ret = repos.check_repo_request(99)
self.RepoQueueQuery.assert_called_once()
self.repo_info.assert_called_once_with('REPOID')
expect = {'request': req, 'repo': 'REPO'}
self.assertEqual(ret, expect)
def test_have_task(self):
req = {'repo_id': None, 'task_id': 'TASKID'}
self.RepoQueueQuery.return_value.executeOne.return_value = req
self.Task.return_value.getInfo.return_value = 'TASK'
ret = repos.check_repo_request(99)
self.RepoQueueQuery.assert_called_once()
self.repo_info.assert_not_called()
self.Task.assert_called_once_with('TASKID')
expect = {'repo': None, 'request': req, 'task': 'TASK'}
self.assertEqual(ret, expect)
def test_no_match(self):
self.RepoQueueQuery.return_value.executeOne.return_value = None
with self.assertRaises(koji.GenericError):
repos.check_repo_request(99)
self.RepoQueueQuery.assert_called_once()
self.repo_info.assert_not_called()
self.Task.assert_not_called()
class TestSetPriority(BaseTest):
def test_set_request_priority(self):
repos.set_request_priority(99, 15)
self.UpdateProcessor.assert_called_once()
update = self.updates[0]
self.assertEqual(update.data, {'priority': 15})
self.assertEqual(update.values, {'id': 99})
class TestExports(BaseTest):
def setUp(self):
super(TestExports, self).setUp()
self.set_request_priority = mock.patch('kojihub.repos.set_request_priority').start()
self.RepoQuery = mock.patch('kojihub.repos.RepoQuery').start()
self.set_external_repo_data = mock.patch('kojihub.repos.set_external_repo_data').start()
self.do_auto_requests = mock.patch('kojihub.repos.do_auto_requests').start()
self.check_repo_queue = mock.patch('kojihub.repos.check_repo_queue').start()
self.RepoQueueQuery = mock.patch('kojihub.repos.RepoQueueQuery').start()
self.update_end_events = mock.patch('kojihub.repos.update_end_events').start()
self.repo_references = mock.patch('kojihub.kojihub.repo_references').start()
self.repo_set_state = mock.patch('kojihub.kojihub.repo_set_state').start()
self.exports = repos.RepoExports()
self.assertPerm = mock.MagicMock()
self.context.session.assertPerm = self.assertPerm
def test_no_perm(self):
self.assertPerm.side_effect = koji.ActionNotAllowed('...')
self.exports.references('REPO')
self.exports.query('CLAUSES')
self.exports.queryQueue('CLAUSES')
def test_require_perm(self):
self.assertPerm.side_effect = koji.ActionNotAllowed('...')
with self.assertRaises(koji.ActionNotAllowed):
self.exports.setRequestPriority(99, 1)
self.set_request_priority.assert_not_called()
self.assertEqual(self.assertPerm.call_args.args, ('admin',))
with self.assertRaises(koji.ActionNotAllowed):
self.exports.setState(99, 1)
self.repo_set_state.assert_not_called()
self.assertEqual(self.assertPerm.call_args.args, ('repo',))
with self.assertRaises(koji.ActionNotAllowed):
self.exports.setExternalRepoData(99, 1)
self.set_external_repo_data.assert_not_called()
self.assertEqual(self.assertPerm.call_args.args, ('repo',))
with self.assertRaises(koji.ActionNotAllowed):
self.exports.autoRequests()
self.do_auto_requests.assert_not_called()
self.assertEqual(self.assertPerm.call_args.args, ('repo',))
with self.assertRaises(koji.ActionNotAllowed):
self.exports.checkQueue()
self.check_repo_queue.assert_not_called()
self.assertEqual(self.assertPerm.call_args.args, ('repo',))
with self.assertRaises(koji.ActionNotAllowed):
self.exports.updateEndEvents()
self.update_end_events.assert_not_called()
self.assertEqual(self.assertPerm.call_args.args, ('repo',))
def test_with_perm(self):
# assertPerm does not raise
self.exports.setRequestPriority(99, 1)
self.exports.setState(99, 1)
self.exports.setExternalRepoData(99, 1)
self.exports.autoRequests()
self.exports.checkQueue()
self.exports.updateEndEvents()
# the end