From bbd841c0d45adf60fad36be32d023ee22dc5a4b0 Mon Sep 17 00:00:00 2001 From: Jana Cupova Date: Mar 29 2023 11:49:32 +0000 Subject: Increase hub unit tests 03-02 --- diff --git a/tests/test_hub/test_create_external_repo.py b/tests/test_hub/test_create_external_repo.py index 9b21504..53388c7 100644 --- a/tests/test_hub/test_create_external_repo.py +++ b/tests/test_hub/test_create_external_repo.py @@ -6,12 +6,15 @@ import mock import koji import kojihub +IP = kojihub.InsertProcessor + class TestCreateExternalRepo(unittest.TestCase): def setUp(self): self.get_external_repos = mock.patch('kojihub.kojihub.get_external_repos').start() self.verify_name_internal = mock.patch('kojihub.kojihub.verify_name_internal').start() + self.get_external_repo_id = mock.patch('kojihub.kojihub.get_external_repo_id').start() self.context = mock.patch('kojihub.kojihub.context').start() # It seems MagicMock will not automatically handle attributes that # start with "assert" @@ -20,6 +23,17 @@ class TestCreateExternalRepo(unittest.TestCase): self.repo_url = 'http://path_to_ext_repo.com' self.repo_name = 'test-repo' self.repo_info = {'id': 1, 'name': self.repo_name, 'url': self.repo_url} + self.InsertProcessor = mock.patch('kojihub.kojihub.InsertProcessor', + side_effect=self.getInsert).start() + self.inserts = [] + self.context_db = mock.patch('kojihub.db.context').start() + self.context_db.session.assertLogin = mock.MagicMock() + + def getInsert(self, *args, **kwargs): + insert = IP(*args, **kwargs) + insert.execute = mock.MagicMock() + self.inserts.append(insert) + return insert def tearDown(self): mock.patch.stopall() @@ -45,3 +59,24 @@ class TestCreateExternalRepo(unittest.TestCase): with self.assertRaises(koji.GenericError) as cm: kojihub.create_external_repo(self.repo_name, self.repo_url) self.assertEqual(expected, str(cm.exception)) + + def test_valid(self): + self.verify_name_internal.return_value = None + self.get_external_repos.return_value = None + self.context_db.event_id = 42 + self.context_db.session.user_id = 23 + self.get_external_repo_id.return_value = self.repo_info['id'] + repo_url = self.repo_url + '/' + result = kojihub.create_external_repo(self.repo_name, self.repo_url) + self.assertEqual(result, + {'id': self.repo_info['id'], 'name': self.repo_name, 'url': repo_url}) + self.assertEqual(len(self.inserts), 1) + insert = self.inserts[0] + self.assertEqual(insert.table, 'external_repo_config') + self.assertEqual(insert.data, { + 'create_event': 42, + 'creator_id': 23, + 'external_repo_id': self.repo_info['id'], + 'url': repo_url + }) + self.assertEqual(insert.rawdata, {}) diff --git a/tests/test_hub/test_delete_build_target.py b/tests/test_hub/test_delete_build_target.py index 1d684bc..c90a68b 100644 --- a/tests/test_hub/test_delete_build_target.py +++ b/tests/test_hub/test_delete_build_target.py @@ -6,15 +6,46 @@ import koji import kojihub +UP = kojihub.UpdateProcessor + + class TestDeleteBuildTarget(unittest.TestCase): + def getUpdate(self, *args, **kwargs): + update = UP(*args, **kwargs) + update.execute = mock.MagicMock() + self.updates.append(update) + return update + def setUp(self): - self.lookup_name = mock.patch('kojihub.kojihub.lookup_name').start() + self.lookup_build_target = mock.patch('kojihub.kojihub.lookup_build_target').start() self.exports = kojihub.RootExports() + self.UpdateProcessor = mock.patch('kojihub.kojihub.UpdateProcessor', + side_effect=self.getUpdate).start() + self.updates = [] + self.context_db = mock.patch('kojihub.db.context').start() + # It seems MagicMock will not automatically handle attributes that + # start with "assert" + self.context_db.session.assertLogin = mock.MagicMock() def test_non_exist_target(self): build_target = 'build-target' - self.lookup_name.return_value = None + self.lookup_build_target.return_value = None with self.assertRaises(koji.GenericError) as cm: self.exports.deleteBuildTarget(build_target) self.assertEqual("No such build target: %s" % build_target, str(cm.exception)) + self.assertEqual(len(self.updates), 0) + + def test_valid(self): + build_target = 'build-target' + self.context_db.event_id = 42 + self.context_db.session.user_id = 23 + self.lookup_build_target.return_value = {'id': 123} + self.exports.deleteBuildTarget(build_target) + + self.assertEqual(len(self.updates), 1) + update = self.updates[0] + self.assertEqual(update.table, 'build_target_config') + self.assertEqual(update.clauses, ["build_target_id = %(targetID)i", 'active = TRUE']) + self.assertEqual(update.data, {'revoke_event': 42, 'revoker_id': 23}) + self.assertEqual(update.rawdata, {'active': 'NULL'}) diff --git a/tests/test_hub/test_delete_external_repo.py b/tests/test_hub/test_delete_external_repo.py new file mode 100644 index 0000000..d079ca4 --- /dev/null +++ b/tests/test_hub/test_delete_external_repo.py @@ -0,0 +1,55 @@ +import unittest + +import mock + +import kojihub + +UP = kojihub.UpdateProcessor + + +class TestDeleteExternalRepo(unittest.TestCase): + def getUpdate(self, *args, **kwargs): + update = UP(*args, **kwargs) + update.execute = mock.MagicMock() + self.updates.append(update) + return update + + def setUp(self): + self.context = mock.patch('kojihub.kojihub.context').start() + self.context.session.assertPerm = mock.MagicMock() + self.context_db = mock.patch('kojihub.db.context').start() + self.context_db.session.assertLogin = mock.MagicMock() + self.UpdateProcessor = mock.patch('kojihub.kojihub.UpdateProcessor', + side_effect=self.getUpdate).start() + self.updates = [] + self.get_external_repo = mock.patch('kojihub.kojihub.get_external_repo').start() + self.get_tag_external_repos = mock.patch('kojihub.kojihub.get_tag_external_repos').start() + self.remove_external_repo_from_tag = mock.patch( + 'kojihub.kojihub.remove_external_repo_from_tag').start() + + def tearDown(self): + mock.patch.stopall() + + def test_valid(self): + tag_ids = [23, 25] + repo_id = 123 + self.context_db.event_id = 42 + self.context_db.session.user_id = 23 + self.get_external_repo.return_value = {'id': repo_id} + self.get_tag_external_repos.return_value = [{'id': repo_id, 'tag_id': tag_ids[0]}, + {'id': repo_id, 'tag_id': tag_ids[0]}] + self.remove_external_repo_from_tag.side_effect = [None, None] + kojihub.delete_external_repo(repo_id) + + self.assertEqual(len(self.updates), 1) + update = self.updates[0] + self.assertEqual(update.table, 'external_repo_config') + self.assertEqual(update.clauses, ['external_repo_id = %(repo_id)i', 'active = TRUE']) + self.assertEqual(update.data, {'revoke_event': 42, 'revoker_id': 23}) + self.assertEqual(update.rawdata, {'active': 'NULL'}) + + self.get_external_repo.assert_called_once_with(123, strict=True) + self.get_tag_external_repos.assert_called_once_with(repo_info=123) + self.remove_external_repo_from_tag.has_calls( + [mock.call(tag_info=tag_ids[0], repo_info=repo_id), + mock.call(tag_info=tag_ids[1], repo_info=repo_id)]) diff --git a/tests/test_hub/test_edit_external_repo.py b/tests/test_hub/test_edit_external_repo.py index 82e85eb..28fcc03 100644 --- a/tests/test_hub/test_edit_external_repo.py +++ b/tests/test_hub/test_edit_external_repo.py @@ -6,9 +6,33 @@ import mock import koji import kojihub +IP = kojihub.InsertProcessor +QP = kojihub.QueryProcessor +UP = kojihub.UpdateProcessor + class TestEditExternalRepo(unittest.TestCase): + def getQuery(self, *args, **kwargs): + query = QP(*args, **kwargs) + query.execute = mock.MagicMock() + query.executeOne = mock.MagicMock() + 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 + def setUp(self): self.get_external_repo = mock.patch('kojihub.kojihub.get_external_repo').start() self.verify_name_internal = mock.patch('kojihub.kojihub.verify_name_internal').start() @@ -20,6 +44,20 @@ class TestEditExternalRepo(unittest.TestCase): self.repo_url = 'http://path_to_ext_repo.com' self.repo_name = 'test-repo' self.repo_info = {'id': 1, 'name': self.repo_name, 'url': self.repo_url} + self.context_db = mock.patch('kojihub.db.context').start() + # It seems MagicMock will not automatically handle attributes that + # start with "assert" + self.context_db.session.assertLogin = mock.MagicMock() + self.InsertProcessor = mock.patch('kojihub.kojihub.InsertProcessor', + side_effect=self.getInsert).start() + self.inserts = [] + self.QueryProcessor = mock.patch('kojihub.kojihub.QueryProcessor', + side_effect=self.getQuery).start() + self.queries = [] + self.query_singleValue = mock.MagicMock() + self.UpdateProcessor = mock.patch('kojihub.kojihub.UpdateProcessor', + side_effect=self.getUpdate).start() + self.updates = [] def tearDown(self): mock.patch.stopall() @@ -37,3 +75,67 @@ class TestEditExternalRepo(unittest.TestCase): self.verify_name_internal.side_effect = koji.GenericError with self.assertRaises(koji.GenericError): kojihub.edit_external_repo(self.repo_name, repo_name_new, self.repo_url) + + def test_edit_external_repo_existing_name(self): + repo_name_new = 'test-repo+' + self.get_external_repo.return_value = self.repo_info + self.verify_name_internal.side_effect = None + self.query_singleValue.return_value = 111 + with self.assertRaises(koji.GenericError) as ex: + kojihub.edit_external_repo(self.repo_name, repo_name_new, self.repo_url) + self.assertEqual(f'name "{repo_name_new}" is already taken by external repo {111}', + str(ex.exception)) + self.assertEqual(len(self.queries), 1) + self.assertEqual(len(self.inserts), 0) + self.assertEqual(len(self.updates), 0) + + query = self.queries[0] + self.assertEqual(query.tables, ['external_repo']) + self.assertEqual(query.joins, None) + self.assertEqual(query.clauses, ['name = %(name)s']) + self.assertEqual(query.columns, ['id']) + self.assertEqual(query.values, {'name': repo_name_new}) + + def test_edit_valid(self): + path_to_new_repo = 'http://path_to_new_ext_repo.com' + repo_name_new = 'test-repo+' + self.get_external_repo.return_value = self.repo_info + self.verify_name_internal.side_effect = None + self.query_singleValue.return_value = None + self.context_db.event_id = 42 + self.context_db.session.user_id = 23 + kojihub.edit_external_repo(self.repo_name, repo_name_new, path_to_new_repo) + + self.assertEqual(len(self.queries), 1) + self.assertEqual(len(self.inserts), 1) + self.assertEqual(len(self.updates), 2) + + query = self.queries[0] + self.assertEqual(query.tables, ['external_repo']) + self.assertEqual(query.joins, None) + self.assertEqual(query.clauses, ['name = %(name)s']) + self.assertEqual(query.columns, ['id']) + self.assertEqual(query.values, {'name': repo_name_new}) + + insert = self.inserts[0] + self.assertEqual(insert.table, 'external_repo_config') + self.assertEqual(insert.data, { + 'create_event': 42, + 'creator_id': 23, + 'external_repo_id': self.repo_info['id'], + 'url': path_to_new_repo + '/' + }) + self.assertEqual(insert.rawdata, {}) + + update = self.updates[0] + self.assertEqual(update.table, 'external_repo') + self.assertEqual(update.values, {'repo_id': self.repo_info['id']}) + self.assertEqual(update.clauses, ['id = %(repo_id)i']) + self.assertEqual(update.data, {'name': repo_name_new}) + self.assertEqual(update.rawdata, {}) + + update = self.updates[1] + self.assertEqual(update.table, 'external_repo_config') + self.assertEqual(update.clauses, ['external_repo_id = %(repo_id)i', 'active = TRUE']) + self.assertEqual(update.data, {'revoke_event': 42, 'revoker_id': 23}) + self.assertEqual(update.rawdata, {'active': 'NULL'}) diff --git a/tests/test_hub/test_getPackageID.py b/tests/test_hub/test_getPackageID.py index 000284c..a926087 100644 --- a/tests/test_hub/test_getPackageID.py +++ b/tests/test_hub/test_getPackageID.py @@ -10,7 +10,7 @@ class TestGetPackageID(DBQueryTestCase): maxDiff = None def test_getPackageID(self): - self.qp_execute_return_value = [{'id': 1}] + self.qp_execute_one_return_value = {'id': 1} rv = kojihub.RootExports().getPackageID('koji') self.assertEqual(len(self.queries), 1) self.assertLastQueryEqual(tables=['package'], @@ -30,8 +30,7 @@ class TestGetPackageID(DBQueryTestCase): values={'name': 'invalidpkg', 'strict': True, 'self': mock.ANY}) - self.assertEqual(cm.exception.args[0], - 'No such package name: invalidpkg') + self.assertEqual(cm.exception.args[0], 'No such package name: invalidpkg') def test_getPackageID_None(self): rv = kojihub.RootExports().getPackageID('invalidpkg') diff --git a/tests/test_hub/test_getRPM.py b/tests/test_hub/test_getRPM.py index 4cf1ef9..984c4e0 100644 --- a/tests/test_hub/test_getRPM.py +++ b/tests/test_hub/test_getRPM.py @@ -1,33 +1,21 @@ import os.path import shutil import tempfile -import unittest import mock +import unittest import koji import kojihub - -QP = kojihub.QueryProcessor +from .utils import DBQueryTestCase -class TestGetRPM(unittest.TestCase): +class TestGetRPM(DBQueryTestCase): def setUp(self): + super(TestGetRPM, self).setUp() self.exports = kojihub.RootExports() self.context = mock.patch('kojihub.kojihub.context').start() self.get_external_repo_id = mock.patch('kojihub.kojihub.get_external_repo_id').start() - self.QueryProcessor = mock.patch('kojihub.kojihub.QueryProcessor', - side_effect=self.getQuery).start() - self.queries = [] - - def getQuery(self, *args, **kwargs): - query = QP(*args, **kwargs) - query.execute = mock.MagicMock() - self.queries.append(query) - return query - - def tearDown(self): - mock.patch.stopall() def test_wrong_type_rpminfo(self): rpminfo = ['test-user'] @@ -37,7 +25,9 @@ class TestGetRPM(unittest.TestCase): def test_rpm_info_int(self): rpminfo = 123 - kojihub.get_rpm(rpminfo) + self.qp_execute_one_return_value = {'rpminfo.id': 123} + result = kojihub.get_rpm(rpminfo) + self.assertEqual(result, {'rpminfo.id': 123}) self.assertEqual(len(self.queries), 1) query = self.queries[0] @@ -52,6 +42,45 @@ class TestGetRPM(unittest.TestCase): ['external_repo ON rpminfo.external_repo_id = external_repo.id']) self.assertEqual(query.values, {'id': rpminfo}) + def test_rpm_info_empty_query_result_without_strict(self): + rpminfo = 123 + self.qp_execute_one_return_value = {} + result = kojihub.get_rpm(rpminfo) + self.assertEqual(result, None) + + self.assertEqual(len(self.queries), 1) + query = self.queries[0] + str(query) + self.assertEqual(query.tables, ['rpminfo']) + columns = ['rpminfo.id', 'build_id', 'buildroot_id', 'rpminfo.name', 'version', 'release', + 'epoch', 'arch', 'external_repo_id', 'external_repo.name', 'payloadhash', + 'size', 'buildtime', 'metadata_only', 'extra'] + self.assertEqual(set(query.columns), set(columns)) + self.assertEqual(query.clauses, ["rpminfo.id=%(id)s"]) + self.assertEqual(query.joins, + ['external_repo ON rpminfo.external_repo_id = external_repo.id']) + self.assertEqual(query.values, {'id': rpminfo}) + + def test_rpm_info_empty_query_result_with_strict(self): + rpminfo = 123 + self.qp_execute_one_return_value = {} + with self.assertRaises(koji.GenericError) as ex: + kojihub.get_rpm(rpminfo, strict=True) + self.assertEqual("No such rpm: {'id': 123}", str(ex.exception)) + + self.assertEqual(len(self.queries), 1) + query = self.queries[0] + str(query) + self.assertEqual(query.tables, ['rpminfo']) + columns = ['rpminfo.id', 'build_id', 'buildroot_id', 'rpminfo.name', 'version', 'release', + 'epoch', 'arch', 'external_repo_id', 'external_repo.name', 'payloadhash', + 'size', 'buildtime', 'metadata_only', 'extra'] + self.assertEqual(set(query.columns), set(columns)) + self.assertEqual(query.clauses, ["rpminfo.id=%(id)s"]) + self.assertEqual(query.joins, + ['external_repo ON rpminfo.external_repo_id = external_repo.id']) + self.assertEqual(query.values, {'id': rpminfo}) + def test_rpm_info_str(self): rpminfo = 'testrpm-1.23-4.x86_64.rpm' kojihub.get_rpm(rpminfo, multi=True) diff --git a/tests/test_hub/test_getRPMDeps.py b/tests/test_hub/test_getRPMDeps.py index 46cf4b0..ca1f317 100644 --- a/tests/test_hub/test_getRPMDeps.py +++ b/tests/test_hub/test_getRPMDeps.py @@ -6,49 +6,50 @@ import kojihub class TestGetRPMDeps(unittest.TestCase): + def setUp(self): + self.exports = kojihub.RootExports() + self.get_rpm = mock.patch('kojihub.kojihub.get_rpm').start() + self.get_build = mock.patch('kojihub.kojihub.get_build').start() - @mock.patch('kojihub.kojihub.get_rpm') - def test_getRPMDeps_no_rpminfo(self, get_rpm): + def test_getRPMDeps_no_rpminfo(self): def mock_get_rpm(rpmID, strict=False): if strict: raise koji.GenericError('msg') else: return None - get_rpm.side_effect = mock_get_rpm - re = kojihub.RootExports().getRPMDeps(1) + self.get_rpm.side_effect = mock_get_rpm + re = self.exports.getRPMDeps(1) self.assertEqual(re, []) with self.assertRaises(koji.GenericError) as cm: - kojihub.RootExports().getRPMDeps(1, strict=True) + self.exports.getRPMDeps(1, strict=True) self.assertEqual(cm.exception.args[0], 'msg') - @mock.patch('kojihub.kojihub.get_rpm', return_value={'id': 1, 'build_id': None}) - def test_getRPMDeps_external_rpm(self, get_rpm): - re = kojihub.RootExports().getRPMDeps(1) + def test_getRPMDeps_external_rpm(self): + self.get_rpm.return_value = {'id': 1, 'build_id': None} + re = self.exports.getRPMDeps(1) self.assertEqual(re, []) with self.assertRaises(koji.GenericError) as cm: - kojihub.RootExports().getRPMDeps(1, strict=True) + self.exports.getRPMDeps(1, strict=True) self.assertEqual(cm.exception.args[0], 'Can not get dependencies, because RPM: 1 is not internal') - @mock.patch('kojihub.kojihub.get_rpm', return_value={'id': 1, 'build_id': 1}) - @mock.patch('kojihub.kojihub.get_build', return_value={'id': 1}) @mock.patch('koji.pathinfo.build', return_value='fakebuildpath') @mock.patch('koji.pathinfo.rpm', return_value='fakerpmrelpath') @mock.patch('os.path.exists', return_value=False) - def test_getRPMDeps_no_rpmfile(self, ope, pr, pb, get_build, get_rpm): - re = kojihub.RootExports().getRPMDeps(1) + def test_getRPMDeps_no_rpmfile(self, ope, pr, pb): + self.get_rpm.return_value = {'id': 1, 'build_id': 1} + self.get_build.return_value = {'id': 1} + re = self.exports.getRPMDeps(1) self.assertEqual(re, []) with self.assertRaises(koji.GenericError) as cm: - kojihub.RootExports().getRPMDeps(1, strict=True) + self.exports.getRPMDeps(1, strict=True) self.assertEqual(cm.exception.args[0], "RPM file of 1 doesn't exist") - @mock.patch('kojihub.kojihub.get_rpm') - @mock.patch('kojihub.kojihub.get_build') @mock.patch('koji.pathinfo') - def test_getRPMDeps(self, pi, build, rpm): + def test_getRPMDeps(self, pi): pi.build.return_value = os.path.join(os.path.dirname(__file__), '../test_lib/data/rpms') pi.rpm.return_value = 'test-deps-1-1.fc24.x86_64.rpm' - getRPMDeps = kojihub.RootExports().getRPMDeps + getRPMDeps = self.exports.getRPMDeps res = getRPMDeps('') # limit test for rpm < 4.12 if any(koji.SUPPORTED_OPT_DEP_HDRS.values()): diff --git a/tests/test_hub/test_get_active_repos.py b/tests/test_hub/test_get_active_repos.py index f1a0632..3dcea0d 100644 --- a/tests/test_hub/test_get_active_repos.py +++ b/tests/test_hub/test_get_active_repos.py @@ -25,7 +25,7 @@ class TestGetActiveRepos(unittest.TestCase): def test_get_active_repos(self): # currently not really a lot of parameters to test - result = kojihub.get_active_repos() + kojihub.get_active_repos() self.assertEqual(len(self.queries), 1) query = self.queries[0] # make sure the following does not error diff --git a/tests/test_hub/test_get_archive_type.py b/tests/test_hub/test_get_archive_type.py index fa68c63..5318a68 100644 --- a/tests/test_hub/test_get_archive_type.py +++ b/tests/test_hub/test_get_archive_type.py @@ -1,20 +1,190 @@ -import unittest - import koji import kojihub +import mock +from .utils import DBQueryTestCase -class TestGetArchiveType(unittest.TestCase): +class TestGetArchiveType(DBQueryTestCase): + def setUp(self): + super(TestGetArchiveType, self).setUp() + self.maxDiff = None + self.archive_info = {'id': 1, 'name': 'archive-type-1', + 'description': 'archive-desc', 'extensions': 'ext', + 'compression_type': 'cmptype'} - def test_get_archive_wrong_type_filename(self): + @mock.patch('kojihub.kojihub._get_archive_type_by_name') + @mock.patch('kojihub.kojihub._get_archive_type_by_id') + def test_get_archive_wrong_type_filename( + self, get_archive_type_by_id, get_archive_type_by_name): filename = ['test-filename'] - with self.assertRaises(koji.ParameterError) as cm: + with self.assertRaises(koji.ParameterError) as ex: kojihub.get_archive_type(filename=filename) self.assertEqual(f"Invalid type for value '{filename}': {type(filename)}, " - f"expected type ", str(cm.exception)) + f"expected type ", str(ex.exception)) + self.assertEqual(len(self.queries), 0) + get_archive_type_by_name.assert_not_called() + get_archive_type_by_id.assert_not_called() - def test_get_archive_without_opt(self): - with self.assertRaises(koji.GenericError) as cm: + @mock.patch('kojihub.kojihub._get_archive_type_by_name') + @mock.patch('kojihub.kojihub._get_archive_type_by_id') + def test_get_archive_without_opt(self, get_archive_type_by_id, get_archive_type_by_name): + with self.assertRaises(koji.GenericError) as ex: kojihub.get_archive_type() self.assertEqual("one of filename, type_name, or type_id must be specified", - str(cm.exception)) + str(ex.exception)) + self.assertEqual(len(self.queries), 0) + get_archive_type_by_name.assert_not_called() + get_archive_type_by_id.assert_not_called() + + @mock.patch('kojihub.kojihub._get_archive_type_by_name') + @mock.patch('kojihub.kojihub._get_archive_type_by_id') + def test_get_archive_type_id(self, get_archive_type_by_id, get_archive_type_by_name): + get_archive_type_by_id.return_value = self.archive_info + kojihub.get_archive_type(type_id=1) + self.assertEqual(len(self.queries), 0) + get_archive_type_by_name.assert_not_called() + get_archive_type_by_id.assert_called_once_with(1, False) + + @mock.patch('kojihub.kojihub._get_archive_type_by_name') + @mock.patch('kojihub.kojihub._get_archive_type_by_id') + def test_get_archive_type_name(self, get_archive_type_by_id, get_archive_type_by_name): + get_archive_type_by_name.return_value = self.archive_info + kojihub.get_archive_type(type_name='archive-type-1') + self.assertEqual(len(self.queries), 0) + get_archive_type_by_name.assert_called_once_with('archive-type-1', False) + get_archive_type_by_id.assert_not_called() + + @mock.patch('kojihub.kojihub._get_archive_type_by_name') + @mock.patch('kojihub.kojihub._get_archive_type_by_id') + def test_get_archive_more_files_extension( + self, get_archive_type_by_id, get_archive_type_by_name): + archive_info = [{'id': 1, 'name': 'archive-type-1', 'extensions': 'ext'}, + {'id': 2, 'name': 'archive-type-2', 'extensions': 'ext'}] + filename = 'test-filename.ext' + self.qp_execute_return_value = archive_info + with self.assertRaises(koji.GenericError) as ex: + kojihub.get_archive_type(filename=filename) + self.assertEqual("multiple matches for file extension: ext", str(ex.exception)) + + self.assertEqual(len(self.queries), 1) + query = self.queries[0] + self.assertEqual(query.tables, ['archivetypes']) + self.assertEqual(query.joins, None) + self.assertEqual(query.clauses, ['extensions ~* %(pattern)s']) + self.assertEqual(query.columns, + ['compression_type', 'description', 'extensions', 'id', 'name']) + get_archive_type_by_name.assert_not_called() + get_archive_type_by_id.assert_not_called() + + @mock.patch('kojihub.kojihub._get_archive_type_by_name') + @mock.patch('kojihub.kojihub._get_archive_type_by_id') + def test_get_archive_no_extensions_with_strict( + self, get_archive_type_by_id, get_archive_type_by_name): + archive_info = [] + filename = 'test-filename.ext' + self.qp_execute_return_value = archive_info + with self.assertRaises(koji.GenericError) as ex: + kojihub.get_archive_type(filename=filename, strict=True) + self.assertEqual(f'unsupported file extension: {filename}', str(ex.exception)) + + self.assertEqual(len(self.queries), 1) + query = self.queries[0] + self.assertEqual(query.tables, ['archivetypes']) + self.assertEqual(query.joins, None) + self.assertEqual(query.clauses, ['extensions ~* %(pattern)s']) + self.assertEqual(query.columns, + ['compression_type', 'description', 'extensions', 'id', 'name']) + get_archive_type_by_name.assert_not_called() + get_archive_type_by_id.assert_not_called() + + @mock.patch('kojihub.kojihub._get_archive_type_by_name') + @mock.patch('kojihub.kojihub._get_archive_type_by_id') + def test_get_archive_no_extensions_without_strict( + self, get_archive_type_by_id, get_archive_type_by_name): + archive_info = [] + filename = 'test-filename.ext' + self.qp_execute_return_value = archive_info + result = kojihub.get_archive_type(filename=filename, strict=False) + self.assertEqual(result, None) + + self.assertEqual(len(self.queries), 1) + query = self.queries[0] + self.assertEqual(query.tables, ['archivetypes']) + self.assertEqual(query.joins, None) + self.assertEqual(query.clauses, ['extensions ~* %(pattern)s']) + self.assertEqual(query.columns, + ['compression_type', 'description', 'extensions', 'id', 'name']) + get_archive_type_by_name.assert_not_called() + get_archive_type_by_id.assert_not_called() + + @mock.patch('kojihub.kojihub._get_archive_type_by_name') + @mock.patch('kojihub.kojihub._get_archive_type_by_id') + def test_get_archive_valid(self, get_archive_type_by_id, get_archive_type_by_name): + filename = 'test-filename.ext' + self.qp_execute_return_value = [self.archive_info] + result = kojihub.get_archive_type(filename=filename) + self.assertEqual(result, self.archive_info) + + self.assertEqual(len(self.queries), 1) + query = self.queries[0] + self.assertEqual(query.tables, ['archivetypes']) + self.assertEqual(query.joins, None) + self.assertEqual(query.clauses, ['extensions ~* %(pattern)s']) + self.assertEqual(query.columns, + ['compression_type', 'description', 'extensions', 'id', 'name']) + get_archive_type_by_name.assert_not_called() + get_archive_type_by_id.assert_not_called() + + def test_get_archive_type_by_id_empty_without_strict(self): + self.qp_execute_one_return_value = None + result = kojihub._get_archive_type_by_id(1, False) + self.assertEqual(result, None) + self.assertEqual(len(self.queries), 1) + query = self.queries[0] + self.assertEqual(query.tables, ['archivetypes']) + self.assertEqual(query.joins, None) + self.assertEqual(query.clauses, ['id = %(type_id)i']) + self.assertEqual(query.columns, + ['compression_type', 'description', 'extensions', 'id', 'name']) + self.assertEqual(query.values, {'type_id': 1}) + + def test_get_archive_type_by_id_empty_with_strict(self): + self.qp_execute_one_side_effect = koji.GenericError('query returned no rows') + with self.assertRaises(koji.GenericError) as ex: + kojihub._get_archive_type_by_id(1, True) + self.assertEqual('query returned no rows', str(ex.exception)) + self.assertEqual(len(self.queries), 1) + query = self.queries[0] + self.assertEqual(query.tables, ['archivetypes']) + self.assertEqual(query.joins, None) + self.assertEqual(query.clauses, ['id = %(type_id)i']) + self.assertEqual(query.columns, + ['compression_type', 'description', 'extensions', 'id', 'name']) + self.assertEqual(query.values, {'type_id': 1}) + + def test_get_archive_type_by_name_without_strict(self): + self.qp_execute_one_return_value = None + result = kojihub._get_archive_type_by_name('archive-type', False) + self.assertEqual(result, None) + self.assertEqual(len(self.queries), 1) + query = self.queries[0] + self.assertEqual(query.tables, ['archivetypes']) + self.assertEqual(query.joins, None) + self.assertEqual(query.clauses, ['name = %(name)s']) + self.assertEqual(query.columns, + ['compression_type', 'description', 'extensions', 'id', 'name']) + self.assertEqual(query.values, {'name': 'archive-type'}) + + def test_get_archive_type_by_name_with_strict(self): + self.qp_execute_one_side_effect = koji.GenericError('query returned no rows') + with self.assertRaises(koji.GenericError) as ex: + kojihub._get_archive_type_by_name('archive-type', True) + self.assertEqual('query returned no rows', str(ex.exception)) + self.assertEqual(len(self.queries), 1) + query = self.queries[0] + self.assertEqual(query.tables, ['archivetypes']) + self.assertEqual(query.joins, None) + self.assertEqual(query.clauses, ['name = %(name)s']) + self.assertEqual(query.columns, + ['compression_type', 'description', 'extensions', 'id', 'name']) + self.assertEqual(query.values, {'name': 'archive-type'}) diff --git a/tests/test_hub/test_get_build.py b/tests/test_hub/test_get_build.py index d260715..78c4ef5 100644 --- a/tests/test_hub/test_get_build.py +++ b/tests/test_hub/test_get_build.py @@ -10,22 +10,69 @@ class TestGetBuild(DBQueryTestCase): def setUp(self): super(TestGetBuild, self).setUp() self.find_build_id = mock.patch('kojihub.kojihub.find_build_id').start() + self.lookup_name = mock.patch('kojihub.kojihub.lookup_name').start() - def test_non_exist_build_string(self): + def test_non_exist_build_string_with_strict(self): build = 'build-1-23' self.find_build_id.side_effect = koji.GenericError('No such build: %s' % build) with self.assertRaises(koji.GenericError) as cm: kojihub.get_build(build, strict=True) self.assertEqual('No such build: %s' % build, str(cm.exception)) + self.find_build_id.assert_called_once_with(build, strict=True) + self.assertEqual(len(self.queries), 0) - def test_non_exist_build_int(self): + def test_non_exist_build_int_without_result_with_strict(self): build = 11 self.find_build_id.return_value = build with self.assertRaises(koji.GenericError) as cm: kojihub.get_build(build, strict=True) self.assertEqual('No such build: %s' % build, str(cm.exception)) + self.find_build_id.assert_called_once_with(build, strict=True) + self.assertEqual(len(self.queries), 1) + query = self.queries[0] + self.assertEqual(query.tables, ['build']) + self.assertEqual(query.joins, ['events ON build.create_event = events.id', + 'package on build.pkg_id = package.id', + 'volume on build.volume_id = volume.id', + 'users on build.owner = users.id']) + self.assertEqual(query.clauses, ['build.id = %(buildID)i']) + self.assertEqual(query.columns, + ['build.id', 'build.cg_id', 'build.completion_time', + "date_part('epoch', build.completion_time)", 'events.id', 'events.time', + "date_part('epoch', events.time)", 'build.epoch', 'build.extra', + 'build.id', 'package.name', + "package.name || '-' || build.version || '-' || build.release", + 'users.id', 'users.name', 'package.id', 'package.name', 'build.release', + 'build.source', 'build.start_time', + "date_part('epoch', build.start_time)", 'build.state', 'build.task_id', + 'build.version', 'volume.id', 'volume.name']) - def test_non_exist_build_dict(self): + def test_non_exist_build_int_without_result_without_strict(self): + build = 11 + self.find_build_id.return_value = build + result = kojihub.get_build(build, strict=False) + self.assertEqual(result, None) + self.find_build_id.assert_called_once_with(build, strict=False) + self.assertEqual(len(self.queries), 1) + query = self.queries[0] + self.assertEqual(query.tables, ['build']) + self.assertEqual(query.joins, ['events ON build.create_event = events.id', + 'package on build.pkg_id = package.id', + 'volume on build.volume_id = volume.id', + 'users on build.owner = users.id']) + self.assertEqual(query.clauses, ['build.id = %(buildID)i']) + self.assertEqual(query.columns, + ['build.id', 'build.cg_id', 'build.completion_time', + "date_part('epoch', build.completion_time)", 'events.id', 'events.time', + "date_part('epoch', events.time)", 'build.epoch', 'build.extra', + 'build.id', 'package.name', + "package.name || '-' || build.version || '-' || build.release", + 'users.id', 'users.name', 'package.id', 'package.name', 'build.release', + 'build.source', 'build.start_time', + "date_part('epoch', build.start_time)", 'build.state', 'build.task_id', + 'build.version', 'volume.id', 'volume.name']) + + def test_non_exist_build_dict_with_strict(self): build = { 'name': 'test_name', 'version': 'test_version', @@ -35,3 +82,66 @@ class TestGetBuild(DBQueryTestCase): with self.assertRaises(koji.GenericError) as cm: kojihub.get_build(build, strict=True) self.assertEqual('No such build: %s' % build['name'], str(cm.exception)) + self.find_build_id.assert_called_once_with(build, strict=True) + self.assertEqual(len(self.queries), 0) + + def test_build_none_exist_without_strict(self): + build = 'build-1-23' + self.find_build_id.return_value = None + result = kojihub.get_build(build, strict=False) + self.assertEqual(result, None) + self.find_build_id.assert_called_once_with(build, strict=False) + self.assertEqual(len(self.queries), 0) + + def test_result_with_cg_id_none(self): + build = 11 + self.find_build_id.return_value = build + self.qp_execute_one_return_value = {'cg_id': None} + result = kojihub.get_build(build, strict=True) + self.assertEqual(result, {'cg_id': None, 'cg_name': None}) + self.find_build_id.assert_called_once_with(build, strict=True) + self.assertEqual(len(self.queries), 1) + query = self.queries[0] + self.assertEqual(query.tables, ['build']) + self.assertEqual(query.joins, ['events ON build.create_event = events.id', + 'package on build.pkg_id = package.id', + 'volume on build.volume_id = volume.id', + 'users on build.owner = users.id']) + self.assertEqual(query.clauses, ['build.id = %(buildID)i']) + self.assertEqual(query.columns, + ['build.id', 'build.cg_id', 'build.completion_time', + "date_part('epoch', build.completion_time)", 'events.id', 'events.time', + "date_part('epoch', events.time)", 'build.epoch', 'build.extra', + 'build.id', 'package.name', + "package.name || '-' || build.version || '-' || build.release", + 'users.id', 'users.name', 'package.id', 'package.name', 'build.release', + 'build.source', 'build.start_time', + "date_part('epoch', build.start_time)", 'build.state', 'build.task_id', + 'build.version', 'volume.id', 'volume.name']) + + def test_result_with_cg_id(self): + build = 11 + self.find_build_id.return_value = build + self.lookup_name.return_value = {'name': 'cg_name'} + self.qp_execute_one_return_value = {'cg_id': 1} + result = kojihub.get_build(build, strict=True) + self.assertEqual(result, {'cg_id': 1, 'cg_name': 'cg_name'}) + self.find_build_id.assert_called_once_with(build, strict=True) + self.assertEqual(len(self.queries), 1) + query = self.queries[0] + self.assertEqual(query.tables, ['build']) + self.assertEqual(query.joins, ['events ON build.create_event = events.id', + 'package on build.pkg_id = package.id', + 'volume on build.volume_id = volume.id', + 'users on build.owner = users.id']) + self.assertEqual(query.clauses, ['build.id = %(buildID)i']) + self.assertEqual(query.columns, + ['build.id', 'build.cg_id', 'build.completion_time', + "date_part('epoch', build.completion_time)", 'events.id', 'events.time', + "date_part('epoch', events.time)", 'build.epoch', 'build.extra', + 'build.id', 'package.name', + "package.name || '-' || build.version || '-' || build.release", + 'users.id', 'users.name', 'package.id', 'package.name', 'build.release', + 'build.source', 'build.start_time', + "date_part('epoch', build.start_time)", 'build.state', 'build.task_id', + 'build.version', 'volume.id', 'volume.name']) diff --git a/tests/test_hub/test_get_build_notification.py b/tests/test_hub/test_get_build_notification.py index a93ea0f..c2e0f36 100644 --- a/tests/test_hub/test_get_build_notification.py +++ b/tests/test_hub/test_get_build_notification.py @@ -1,22 +1,52 @@ -import mock -import unittest import koji import kojihub +from .utils import DBQueryTestCase -class TestGetBuildNotification(unittest.TestCase): +class TestGetBuildNotification(DBQueryTestCase): def setUp(self): - self.QueryProcessor = mock.patch('kojihub.kojihub.QueryProcessor').start() - self.query = self.QueryProcessor.return_value + super(TestGetBuildNotification, self).setUp() self.exports = kojihub.RootExports() - def tearDown(self): - mock.patch.stopall() - def test_empty_result_with_strict(self): notif_id = 1 - self.query.executeOne.return_value = None + self.qp_execute_one_return_value = None with self.assertRaises(koji.GenericError) as cm: self.exports.getBuildNotification(notif_id, strict=True) self.assertEqual(f"No notification with ID {notif_id} found", str(cm.exception)) + self.assertEqual(len(self.queries), 1) + query = self.queries[0] + self.assertEqual(query.tables, ['build_notifications']) + self.assertEqual(query.joins, None) + self.assertEqual(query.clauses, ['id = %(id)i']) + self.assertEqual(query.columns, + ['email', 'id', 'package_id', 'success_only', 'tag_id', 'user_id']) + + def test_empty_result_without_strict(self): + notif_id = 1 + self.qp_execute_one_return_value = None + result = self.exports.getBuildNotification(notif_id, strict=False) + self.assertEqual(result, None) + self.assertEqual(len(self.queries), 1) + query = self.queries[0] + self.assertEqual(query.tables, ['build_notifications']) + self.assertEqual(query.joins, None) + self.assertEqual(query.clauses, ['id = %(id)i']) + self.assertEqual(query.columns, + ['email', 'id', 'package_id', 'success_only', 'tag_id', 'user_id']) + + def test_valid_result(self): + qp_result = {'id': 1, 'user_id': 2, 'package_id': 3, 'tag_id': 4, 'success_only': True, + 'email': 'test-mail'} + notif_id = 1 + self.qp_execute_one_return_value = qp_result + result = self.exports.getBuildNotification(notif_id, strict=True) + self.assertEqual(result, qp_result) + self.assertEqual(len(self.queries), 1) + query = self.queries[0] + self.assertEqual(query.tables, ['build_notifications']) + self.assertEqual(query.joins, None) + self.assertEqual(query.clauses, ['id = %(id)i']) + self.assertEqual(query.columns, + ['email', 'id', 'package_id', 'success_only', 'tag_id', 'user_id']) diff --git a/tests/test_hub/test_get_build_notification_block.py b/tests/test_hub/test_get_build_notification_block.py index b2d7c94..362bd9c 100644 --- a/tests/test_hub/test_get_build_notification_block.py +++ b/tests/test_hub/test_get_build_notification_block.py @@ -1,14 +1,13 @@ import mock -import unittest import koji import kojihub +from .utils import DBQueryTestCase -class TestGetBuildNotificationBlock(unittest.TestCase): +class TestGetBuildNotificationBlock(DBQueryTestCase): def setUp(self): - self.QueryProcessor = mock.patch('kojihub.kojihub.QueryProcessor').start() - self.query = self.QueryProcessor.return_value + super(TestGetBuildNotificationBlock, self).setUp() self.exports = kojihub.RootExports() def tearDown(self): @@ -16,7 +15,27 @@ class TestGetBuildNotificationBlock(unittest.TestCase): def test_empty_result_with_strict(self): notif_id = 1 - self.query.executeOne.return_value = None + self.qp_execute_one_return_value = None with self.assertRaises(koji.GenericError) as cm: self.exports.getBuildNotificationBlock(notif_id, strict=True) self.assertEqual(f"No notification block with ID {notif_id} found", str(cm.exception)) + + def test_empty_result_without_strict(self): + notif_id = 1 + self.qp_execute_one_return_value = None + result = self.exports.getBuildNotificationBlock(notif_id, strict=False) + self.assertEqual(result, None) + + def test_valid_result(self): + qp_result = {'id': 1, 'user_id': 2, 'package_id': 3, 'tag_id': 4} + notif_id = 1 + self.qp_execute_one_return_value = qp_result + result = self.exports.getBuildNotificationBlock(notif_id, strict=True) + self.assertEqual(result, qp_result) + self.assertEqual(len(self.queries), 1) + query = self.queries[0] + self.assertEqual(query.tables, ['build_notifications_block']) + self.assertEqual(query.joins, None) + self.assertEqual(query.values, {'id': 1}) + self.assertEqual(query.clauses, ['id = %(id)i']) + self.assertEqual(query.columns, ['id', 'package_id', 'tag_id', 'user_id']) diff --git a/tests/test_hub/test_get_build_targets.py b/tests/test_hub/test_get_build_targets.py index 1785b0a..fad921d 100644 --- a/tests/test_hub/test_get_build_targets.py +++ b/tests/test_hub/test_get_build_targets.py @@ -1,40 +1,25 @@ -import unittest - import mock import kojihub - -QP = kojihub.QueryProcessor +from .utils import DBQueryTestCase -class TestGetBuildTargets(unittest.TestCase): +class TestGetBuildTargets(DBQueryTestCase): def setUp(self): + super(TestGetBuildTargets, self).setUp() self.maxDiff = None self.name_or_id_clause = mock.patch('kojihub.kojihub.name_or_id_clause').start() self.get_tag_id = mock.patch('kojihub.kojihub.get_tag_id').start() self.exports = kojihub.RootExports() self.context = mock.patch('kojihub.kojihub.context').start() self.cursor = mock.MagicMock() - self.QueryProcessor = mock.patch('kojihub.kojihub.QueryProcessor', - side_effect=self.getQuery).start() - self.queries = [] self.build_target = 'build-target' self.build_tag_name = 'tag' self.dest_tag_name = 'dest-tag' self.build_tag_id = 1 self.dest_tag_id = 2 - def tearDown(self): - mock.patch.stopall() - - def getQuery(self, *args, **kwargs): - query = QP(*args, **kwargs) - query.execute = mock.MagicMock() - query.executeOne = mock.MagicMock() - self.queries.append(query) - return query - def test_get_build_targets_strings(self): self.name_or_id_clause.return_value = '(build_target.name = %(build_target_name)s)', \ {'build_target_name': 'build-target-url'} diff --git a/tests/test_hub/test_get_build_type.py b/tests/test_hub/test_get_build_type.py index b00719d..14afc03 100644 --- a/tests/test_hub/test_get_build_type.py +++ b/tests/test_hub/test_get_build_type.py @@ -1,33 +1,19 @@ import mock -import unittest import kojihub +from .utils import DBQueryTestCase -QP = kojihub.QueryProcessor - -class TestGetBuildType(unittest.TestCase): +class TestGetBuildType(DBQueryTestCase): def setUp(self): + super(TestGetBuildType, self).setUp() self.maxDiff = None - self.QueryProcessor = mock.patch('kojihub.kojihub.QueryProcessor', - side_effect=self.getQuery).start() - self.queries = [] - self.query_execute = mock.MagicMock() self.get_build = mock.patch('kojihub.kojihub.get_build').start() self.get_maven_build = mock.patch('kojihub.kojihub.get_maven_build').start() self.get_win_build = mock.patch('kojihub.kojihub.get_win_build').start() self.get_image_build = mock.patch('kojihub.kojihub.get_image_build').start() - def tearDown(self): - mock.patch.stopall() - - def getQuery(self, *args, **kwargs): - query = QP(*args, **kwargs) - query.execute = self.query_execute - self.queries.append(query) - return query - def test_no_build(self): self.get_build.return_value = None @@ -47,7 +33,7 @@ class TestGetBuildType(unittest.TestCase): self.get_win_build.return_value = typeinfo['win'] self.get_image_build.return_value = typeinfo['image'] - self.query_execute.return_value = [['new_type']] + self.qp_execute_return_value = [['new_type']] ret = kojihub.get_build_type('mytestbuild-1-1', strict=True) assert ret == typeinfo diff --git a/tests/test_hub/test_get_channel.py b/tests/test_hub/test_get_channel.py index 30dd769..50778e4 100644 --- a/tests/test_hub/test_get_channel.py +++ b/tests/test_hub/test_get_channel.py @@ -1,33 +1,17 @@ -import unittest - import mock import koji import kojihub +from .utils import DBQueryTestCase -QP = kojihub.QueryProcessor - - -class TestGetChannel(unittest.TestCase): - - def getQuery(self, *args, **kwargs): - query = QP(*args, **kwargs) - query.execute = mock.MagicMock() - query.executeOne = mock.MagicMock() - self.queries.append(query) - return query +class TestGetChannel(DBQueryTestCase): def setUp(self): - self.QueryProcessor = mock.patch('kojihub.kojihub.QueryProcessor', - side_effect=self.getQuery).start() - self.queries = [] + super(TestGetChannel, self).setUp() self.context = mock.patch('kojihub.kojihub.context').start() self.exports = kojihub.RootExports() - def tearDown(self): - mock.patch.stopall() - def test_wrong_type_channelInfo(self): # dict channel_info = {'channel': 'val'} @@ -54,7 +38,6 @@ class TestGetChannel(unittest.TestCase): self.assertEqual(set(query.clauses), set(clauses)) self.assertEqual(query.values, values) - def test_query_by_id(self): self.exports.getChannel(12345) self.assertEqual(len(self.queries), 1) @@ -67,7 +50,7 @@ class TestGetChannel(unittest.TestCase): self.assertEqual(query.values, values) def test_query_by_dict(self): - self.exports.getChannel({'id':12345, 'name': 'whatever'}) + self.exports.getChannel({'id': 12345, 'name': 'whatever'}) self.assertEqual(len(self.queries), 1) query = self.queries[0] clauses = ['(channels.id = %(channels_id)s)'] diff --git a/tests/test_hub/test_get_external_repo_list.py b/tests/test_hub/test_get_external_repo_list.py new file mode 100644 index 0000000..ab54114 --- /dev/null +++ b/tests/test_hub/test_get_external_repo_list.py @@ -0,0 +1,34 @@ +import unittest + +import mock + +import kojihub + + +class TestGetExternalRepo(unittest.TestCase): + + def setUp(self): + self.get_tag = mock.patch('kojihub.kojihub.get_tag').start() + self.read_full_inheritance = mock.patch('kojihub.kojihub.readFullInheritance').start() + self.get_tag_external_repos = mock.patch('kojihub.kojihub.get_tag_external_repos').start() + + def tearDown(self): + mock.patch.stopall() + + def test_valid(self): + self.get_tag.return_value = {'id': 123} + self.read_full_inheritance.return_value = [{'parent_id': 111}, {'parent_id': 112}] + self.get_tag_external_repos.side_effect = [ + [{'external_repo_id': 10, 'tag_id': 123}], + [{'external_repo_id': 11, 'tag_id': 111}, {'external_repo_id': 12, 'tag_id': 111}], + [{'external_repo_id': 13, 'tag_id': 112}]] + result = kojihub.get_external_repo_list('test-tag') + self.assertEqual(result, [ + {'external_repo_id': 10, 'tag_id': 123}, + {'external_repo_id': 11, 'tag_id': 111}, {'external_repo_id': 12, 'tag_id': 111}, + {'external_repo_id': 13, 'tag_id': 112}]) + self.get_tag.assert_called_once_with('test-tag', strict=True, event=None) + self.read_full_inheritance.assert_called_once_with(123, None) + self.get_tag_external_repos.assert_has_calls( + [mock.call(tag_info=123, event=None), mock.call(tag_info=111, event=None), + mock.call(tag_info=112, event=None)]) diff --git a/tests/test_hub/test_get_group_members.py b/tests/test_hub/test_get_group_members.py index 79c7f25..e9ae267 100644 --- a/tests/test_hub/test_get_group_members.py +++ b/tests/test_hub/test_get_group_members.py @@ -1,16 +1,14 @@ -import unittest - import mock import koji import kojihub +from .utils import DBQueryTestCase -class TestGetGroupMembers(unittest.TestCase): +class TestGetGroupMembers(DBQueryTestCase): def setUp(self): - self.context = mock.patch('kojihub.kojihub.context').start() - self.context.session.assertPerm = mock.MagicMock() + super(TestGetGroupMembers, self).setUp() self.get_user = mock.patch('kojihub.kojihub.get_user').start() self.exports = kojihub.RootExports() @@ -20,3 +18,18 @@ class TestGetGroupMembers(unittest.TestCase): with self.assertRaises(koji.GenericError) as cm: self.exports.getGroupMembers(group) self.assertEqual("No such group: %s" % group, str(cm.exception)) + self.assertEqual(len(self.queries), 0) + + def test_valid(self): + group = 'test-group' + self.get_user.return_value = {'id': 23, 'usertype': 2} + self.exports.getGroupMembers(group) + self.assertEqual(len(self.queries), 1) + query = self.queries[0] + self.assertEqual(query.tables, ['user_groups']) + self.assertEqual(query.joins, ['JOIN users ON user_groups.user_id = users.id', + 'LEFT JOIN user_krb_principals' + ' ON users.id = user_krb_principals.user_id']) + self.assertEqual(query.clauses, ['(active = TRUE)', 'group_id = %(group_id)i']) + self.assertEqual(query.values, {'group_id': 23}) + self.assertEqual(query.columns, ['id', 'array_agg(krb_principal)', 'name', 'usertype']) diff --git a/tests/test_hub/test_get_image_archive.py b/tests/test_hub/test_get_image_archive.py new file mode 100644 index 0000000..73b707a --- /dev/null +++ b/tests/test_hub/test_get_image_archive.py @@ -0,0 +1,41 @@ +import kojihub +from .utils import DBQueryTestCase + + +class TestGetImageArchive(DBQueryTestCase): + + def setUp(self): + super(TestGetImageArchive, self).setUp() + self.maxDiff = None + + def test_not_exist_image_archive(self): + self.qp_execute_one_return_value = {} + result = kojihub.get_image_archive(123) + self.assertEqual(result, None) + self.assertEqual(len(self.queries), 1) + query = self.queries[0] + self.assertEqual(query.tables, ['image_archives']) + self.assertEqual(query.joins, None) + self.assertEqual(query.clauses, ['archive_id = %(archive_id)i']) + self.assertEqual(query.values, {'archive_id': 123}) + self.assertEqual(query.columns, ['arch', 'archive_id']) + + def test_valid(self): + self.qp_execute_one_side_effect = [{'archive_id': 123, 'arch': 'arch'}, + {'rpm_id': 1}] + result = kojihub.get_image_archive(123) + self.assertEqual(result, {'archive_id': 123, 'arch': 'arch', 'rootid': True}) + self.assertEqual(len(self.queries), 2) + query = self.queries[0] + self.assertEqual(query.tables, ['image_archives']) + self.assertEqual(query.joins, None) + self.assertEqual(query.clauses, ['archive_id = %(archive_id)i']) + self.assertEqual(query.values, {'archive_id': 123}) + self.assertEqual(query.columns, ['arch', 'archive_id']) + + query = self.queries[1] + self.assertEqual(query.tables, ['archive_rpm_components']) + self.assertEqual(query.joins, None) + self.assertEqual(query.clauses, ['archive_id = %(archive_id)i']) + self.assertEqual(query.values, {'archive_id': 123}) + self.assertEqual(query.columns, ['rpm_id']) diff --git a/tests/test_hub/test_get_image_build.py b/tests/test_hub/test_get_image_build.py new file mode 100644 index 0000000..e81c8b1 --- /dev/null +++ b/tests/test_hub/test_get_image_build.py @@ -0,0 +1,64 @@ +import mock +import koji +import kojihub +from .utils import DBQueryTestCase + + +class TestGetImageBuild(DBQueryTestCase): + + def setUp(self): + super(TestGetImageBuild, self).setUp() + self.maxDiff = None + self.find_build_id = mock.patch('kojihub.kojihub.find_build_id').start() + + def test_build_id_not_found(self): + self.find_build_id.return_value = None + result = kojihub.get_image_build('test-build.1-23.1') + self.assertEqual(result, None) + self.assertEqual(len(self.queries), 0) + self.find_build_id.assert_called_once_with('test-build.1-23.1', strict=False) + + def test_valid(self): + self.find_build_id.return_value = 123 + self.qp_execute_one_return_value = {'build_id': 123} + kojihub.get_image_build('test-build.1-23.1') + self.assertEqual(len(self.queries), 1) + query = self.queries[0] + self.assertEqual(query.tables, ['image_builds']) + self.assertEqual(query.joins, None) + self.assertEqual(query.clauses, ['build_id = %(build_id)i']) + self.assertEqual(query.values, {'build_id': 123}) + self.assertEqual(query.columns, ['build_id']) + + self.find_build_id.assert_called_once_with('test-build.1-23.1', strict=False) + + def test_without_result_without_strict(self): + self.find_build_id.return_value = 123 + self.qp_execute_one_return_value = {} + result = kojihub.get_image_build('test-build.1-23.1') + self.assertEqual(result, {}) + self.assertEqual(len(self.queries), 1) + query = self.queries[0] + self.assertEqual(query.tables, ['image_builds']) + self.assertEqual(query.joins, None) + self.assertEqual(query.clauses, ['build_id = %(build_id)i']) + self.assertEqual(query.values, {'build_id': 123}) + self.assertEqual(query.columns, ['build_id']) + + self.find_build_id.assert_called_once_with('test-build.1-23.1', strict=False) + + def test_without_result_with_strict(self): + self.find_build_id.return_value = 123 + self.qp_execute_one_return_value = {} + with self.assertRaises(koji.GenericError) as ex: + kojihub.get_image_build('test-build.1-23.1', strict=True) + self.assertEqual('no such image build: test-build.1-23.1', str(ex.exception)) + self.assertEqual(len(self.queries), 1) + query = self.queries[0] + self.assertEqual(query.tables, ['image_builds']) + self.assertEqual(query.joins, None) + self.assertEqual(query.clauses, ['build_id = %(build_id)i']) + self.assertEqual(query.values, {'build_id': 123}) + self.assertEqual(query.columns, ['build_id']) + + self.find_build_id.assert_called_once_with('test-build.1-23.1', strict=True) diff --git a/tests/test_hub/test_get_last_event.py b/tests/test_hub/test_get_last_event.py index 5a06cd6..b803365 100644 --- a/tests/test_hub/test_get_last_event.py +++ b/tests/test_hub/test_get_last_event.py @@ -1,12 +1,12 @@ -import unittest - import koji import kojihub +from .utils import DBQueryTestCase -class TestGetLastEvent(unittest.TestCase): +class TestGetLastEvent(DBQueryTestCase): def setUp(self): + super(TestGetLastEvent, self).setUp() self.exports = kojihub.RootExports() def test_wrong_type_before(self): @@ -14,3 +14,14 @@ class TestGetLastEvent(unittest.TestCase): with self.assertRaises(koji.GenericError) as cm: self.exports.getLastEvent(before) self.assertEqual("Invalid type for before: %s" % type(before), str(cm.exception)) + + def test_valid(self): + before = 123 + self.exports.getLastEvent(before) + self.assertEqual(len(self.queries), 1) + query = self.queries[0] + self.assertEqual(query.tables, ['events']) + self.assertEqual(query.joins, None) + self.assertEqual(query.clauses, ["date_part('epoch', time) < %(before)r"]) + self.assertEqual(query.values, {'before': 123}) + self.assertEqual(query.columns, ['id', "date_part('epoch', time)"]) diff --git a/tests/test_hub/test_get_last_host_update.py b/tests/test_hub/test_get_last_host_update.py index aa14ed4..b304f5d 100644 --- a/tests/test_hub/test_get_last_host_update.py +++ b/tests/test_hub/test_get_last_host_update.py @@ -1,26 +1,15 @@ -import unittest -import mock import datetime import sys import kojihub +from .utils import DBQueryTestCase -QP = kojihub.QueryProcessor - -class TestGetLastHostUpdate(unittest.TestCase): - def getQuery(self, *args, **kwargs): - query = QP(*args, **kwargs) - query.singleValue = self.query_singleValue - self.queries.append(query) - return query +class TestGetLastHostUpdate(DBQueryTestCase): def setUp(self): + super(TestGetLastHostUpdate, self).setUp() self.exports = kojihub.RootExports() - self.QueryProcessor = mock.patch('kojihub.kojihub.QueryProcessor', - side_effect=self.getQuery).start() - self.queries = [] - self.query_singleValue = mock.MagicMock() def test_valid_ts(self): expected = 1615875554.862938 @@ -30,9 +19,16 @@ class TestGetLastHostUpdate(unittest.TestCase): else: dt = datetime.datetime.strptime( "2021-03-16T06:19:14.862938+00:00", "%Y-%m-%dT%H:%M:%S.%f%z") - self.query_singleValue.return_value = dt + self.qp_single_value_return_value = dt rv = self.exports.getLastHostUpdate(1, ts=True) self.assertEqual(rv, expected) + self.assertEqual(len(self.queries), 1) + query = self.queries[0] + self.assertEqual(query.tables, ['sessions']) + self.assertEqual(query.joins, ['host ON sessions.user_id = host.user_id']) + self.assertEqual(query.clauses, ['host.id = %(hostID)i']) + self.assertEqual(query.values, {'hostID': 1}) + self.assertEqual(query.columns, ['update_time']) def test_valid_datetime(self): if sys.version_info[1] <= 6: @@ -41,6 +37,6 @@ class TestGetLastHostUpdate(unittest.TestCase): else: dt = datetime.datetime.strptime( "2021-03-16T06:19:14.862938+00:00", "%Y-%m-%dT%H:%M:%S.%f%z") - self.query_singleValue.return_value = dt + self.qp_single_value_return_value = dt rv = self.exports.getLastHostUpdate(1) self.assertEqual(rv, dt) diff --git a/tests/test_hub/test_get_maven_archive.py b/tests/test_hub/test_get_maven_archive.py new file mode 100644 index 0000000..c43a978 --- /dev/null +++ b/tests/test_hub/test_get_maven_archive.py @@ -0,0 +1,19 @@ +import kojihub +from .utils import DBQueryTestCase + + +class TestGetMavenArchive(DBQueryTestCase): + + def setUp(self): + super(TestGetMavenArchive, self).setUp() + self.maxDiff = None + + def test_valid(self): + kojihub.get_maven_archive(123) + self.assertEqual(len(self.queries), 1) + query = self.queries[0] + self.assertEqual(query.tables, ['maven_archives']) + self.assertEqual(query.joins, None) + self.assertEqual(query.clauses, ['archive_id = %(archive_id)i']) + self.assertEqual(query.values, {'archive_id': 123}) + self.assertEqual(query.columns, ['archive_id', 'artifact_id', 'group_id', 'version']) diff --git a/tests/test_hub/test_get_next_release.py b/tests/test_hub/test_get_next_release.py index 49cc24e..1ca0962 100644 --- a/tests/test_hub/test_get_next_release.py +++ b/tests/test_hub/test_get_next_release.py @@ -1,31 +1,37 @@ import mock -import unittest import koji import kojihub +from .utils import DBQueryTestCase -class TestGetNextRelease(unittest.TestCase): +class TestGetNextRelease(DBQueryTestCase): def setUp(self): + super(TestGetNextRelease, self).setUp() self.maxDiff = None - self.QueryProcessor = mock.patch('kojihub.kojihub.QueryProcessor').start() self.get_build = mock.patch('kojihub.kojihub.get_build').start() - self._dml = mock.patch('kojihub.kojihub._dml').start() - self.query = self.QueryProcessor.return_value self.binfo = {'name': 'name', 'version': 'version'} - def tearDown(self): - mock.patch.stopall() - def test_get_next_release_new(self): # no previous build - self.query.executeOne.return_value = None + self.qp_execute_one_return_value = None result = kojihub.get_next_release(self.binfo) self.assertEqual(result, '1') + self.assertEqual(len(self.queries), 1) + query = self.queries[0] + self.assertEqual(query.tables, ['build']) + self.assertEqual(query.joins, ['package ON build.pkg_id = package.id']) + self.assertEqual(query.clauses, + ['name = %(name)s', 'state in %(states)s', 'version = %(version)s']) + self.assertEqual(query.values, {'name': self.binfo['name'], + 'version': self.binfo['version'], + 'states': (1, 2, 0) + }) + self.assertEqual(query.columns, ['build.id', 'release']) def test_get_next_release_int(self): for n in [1, 2, 3, 5, 8, 13, 21, 34, 55]: - self.query.executeOne.return_value = {'release': str(n)} + self.qp_execute_one_return_value = {'release': str(n)} result = kojihub.get_next_release(self.binfo) self.assertEqual(result, str(n + 1)) @@ -38,7 +44,7 @@ class TestGetNextRelease(unittest.TestCase): ['20211105.nightly.7', '20211105.nightly.8'], ] for a, b in data: - self.query.executeOne.return_value = {'release': a} + self.qp_execute_one_return_value = {'release': a} result = kojihub.get_next_release(self.binfo) self.assertEqual(result, b) @@ -52,9 +58,10 @@ class TestGetNextRelease(unittest.TestCase): "1.2.fc23", ] for val in data: - self.query.executeOne.return_value = {'release': val} - with self.assertRaises(koji.BuildError): + self.qp_execute_one_return_value = {'release': val} + with self.assertRaises(koji.BuildError) as ex: kojihub.get_next_release(self.binfo) + self.assertEqual(f'Unable to increment release value: {val}', str(ex.exception)) def test_get_next_release_bad_incr(self): data = [ diff --git a/tests/test_hub/test_get_notification_recipients.py b/tests/test_hub/test_get_notification_recipients.py index 542d286..c725a5a 100644 --- a/tests/test_hub/test_get_notification_recipients.py +++ b/tests/test_hub/test_get_notification_recipients.py @@ -5,16 +5,9 @@ import koji import kojihub QP = kojihub.QueryProcessor -IP = kojihub.InsertProcessor -UP = kojihub.UpdateProcessor class TestGetNotificationRecipients(unittest.TestCase): - def getInsert(self, *args, **kwargs): - insert = IP(*args, **kwargs) - insert.execute = mock.MagicMock() - self.inserts.append(insert) - return insert def getQuery(self, *args, **kwargs): query = QP(*args, **kwargs) @@ -22,12 +15,6 @@ class TestGetNotificationRecipients(unittest.TestCase): self.queries.append(query) return query - def getUpdate(self, *args, **kwargs): - update = UP(*args, **kwargs) - update.execute = mock.MagicMock() - self.updates.append(update) - return update - def setUp(self): self.context = mock.patch('kojihub.kojihub.context').start() self.context.opts = { @@ -38,12 +25,6 @@ class TestGetNotificationRecipients(unittest.TestCase): self.QueryProcessor = mock.patch('kojihub.kojihub.QueryProcessor', side_effect=self.getQuery).start() self.queries = [] - self.InsertProcessor = mock.patch('kojihub.kojihub.InsertProcessor', - side_effect=self.getInsert).start() - self.inserts = [] - self.UpdateProcessor = mock.patch('kojihub.kojihub.UpdateProcessor', - side_effect=self.getUpdate).start() - self.updates = [] self.readPackageList = mock.patch('kojihub.kojihub.readPackageList').start() self.get_user = mock.patch('kojihub.kojihub.get_user').start() @@ -75,15 +56,6 @@ class TestGetNotificationRecipients(unittest.TestCase): self.assertEqual(q.values['state'], state) self.assertEqual(q.values['build'], build) self.assertEqual(q.values['tag_id'], tag_id) - - ''' - q = self.queries[1] - self.assertEqual(q.columns, ['user_id']) - self.assertEqual(q.tables, ['build_notifications_block']) - self.assertEqual(q.clauses, ['user_id IN %(user_ids)s']) - self.assertEqual(q.joins, []) - self.assertEqual(q.values['user_ids'], None) - ''' self.readPackageList.assert_not_called() def test_get_notification_recipients_build_without_tag(self): @@ -128,6 +100,34 @@ class TestGetNotificationRecipients(unittest.TestCase): self.readPackageList.assert_not_called() + def test_get_notification_not_recipients(self): + ### without build, without tag, result not recipients + tag_id = None + state = koji.BUILD_STATES['CANCELED'] + build = None + self.queries = [] + self.set_queries([[]]) + + result = kojihub.get_notification_recipients(build, tag_id, state) + self.assertEqual(result, []) + + # there should be only query to watchers + self.assertEqual(len(self.queries), 1) + q = self.queries[0] + self.assertEqual(q.columns, ['email', 'user_id']) + self.assertEqual(q.tables, ['build_notifications']) + self.assertEqual(q.clauses, ['package_id IS NULL', + 'status = %(users_status)i', + 'success_only = FALSE', + 'tag_id IS NULL', + 'usertype IN %(users_usertypes)s']) + self.assertEqual(q.joins, ['JOIN users ON build_notifications.user_id = users.id']) + self.assertEqual(q.values['state'], state) + self.assertEqual(q.values['build'], build) + self.assertEqual(q.values['tag_id'], tag_id) + + self.readPackageList.assert_not_called() + def test_get_notification_recipients_tag_without_build(self): ### with tag without build makes no sense build = None @@ -135,8 +135,9 @@ class TestGetNotificationRecipients(unittest.TestCase): state = koji.BUILD_STATES['CANCELED'] self.queries = [] - with self.assertRaises(koji.GenericError): + with self.assertRaises(koji.GenericError) as ex: kojihub.get_notification_recipients(build, tag_id, state) + self.assertEqual('Invalid call', str(ex.exception)) self.assertEqual(self.queries, []) self.readPackageList.assert_not_called() @@ -256,3 +257,44 @@ class TestGetNotificationRecipients(unittest.TestCase): ]) emails = kojihub.get_notification_recipients(build, tag_id, state) self.assertEqual(emails, ['owner_name@test.domain.com']) + + def test_get_notification_recipients_without_build(self): + ### without build, without tag, result not recipients + tag_id = None + state = koji.BUILD_STATES['CANCELED'] + build = None + self.queries = [] + self.set_queries([ + [{'user_id': 5, 'email': 'owner_name@%s' % self.context.opts['EmailDomain']}], + [] + ]) + + result = kojihub.get_notification_recipients(build, tag_id, state) + self.assertEqual(result, ['owner_name@test.domain.com']) + + # there should be only query to watchers + self.assertEqual(len(self.queries), 2) + q = self.queries[0] + self.assertEqual(q.columns, ['email', 'user_id']) + self.assertEqual(q.tables, ['build_notifications']) + self.assertEqual(q.clauses, ['package_id IS NULL', + 'status = %(users_status)i', + 'success_only = FALSE', + 'tag_id IS NULL', + 'usertype IN %(users_usertypes)s']) + self.assertEqual(q.joins, ['JOIN users ON build_notifications.user_id = users.id']) + self.assertEqual(q.values['state'], state) + self.assertEqual(q.values['build'], build) + self.assertEqual(q.values['tag_id'], tag_id) + + q = self.queries[1] + self.assertEqual(q.columns, ['user_id']) + self.assertEqual(q.tables, ['build_notifications_block']) + self.assertEqual(q.clauses, ['package_id IS NULL', + 'tag_id IS NULL', + 'user_id IN %(user_ids)s', + ]) + self.assertEqual(q.joins, None) + self.assertEqual(q.values['user_ids'], [5]) + + self.readPackageList.assert_not_called() diff --git a/tests/test_hub/test_get_ready_hosts.py b/tests/test_hub/test_get_ready_hosts.py new file mode 100644 index 0000000..8c1447a --- /dev/null +++ b/tests/test_hub/test_get_ready_hosts.py @@ -0,0 +1,64 @@ +import kojihub +import mock +import unittest + +QP = kojihub.QueryProcessor + + +class TestGetReadyHosts(unittest.TestCase): + + def setUp(self): + self.maxDiff = None + self.QueryProcessor = mock.patch('kojihub.kojihub.QueryProcessor', + side_effect=self.getQuery).start() + self.queries = [] + self.query_execute = mock.MagicMock() + + def tearDown(self): + mock.patch.stopall() + + def getQuery(self, *args, **kwargs): + query = QP(*args, **kwargs) + query.execute = self.query_execute + self.queries.append(query) + return query + + def test_valid(self): + hosts = [{'host.id': 1, 'name': 'hostname', 'arches': 'arch123', 'task_load': 0, + 'capacity': 3}, + {'host.id': 2, 'name': 'hostname-2', 'arches': 'arch123', 'task_load': 0, + 'capacity': 3}] + expected_res = [{'host.id': 1, 'name': 'hostname', 'arches': 'arch123', 'task_load': 0, + 'capacity': 3, 'channels': [1]}, + {'host.id': 2, 'name': 'hostname-2', 'arches': 'arch123', 'task_load': 0, + 'capacity': 3, 'channels': [2, 3]} + ] + self.query_execute.side_effect = [hosts, [{'channel_id': 1}], + [{'channel_id': 2}, {'channel_id': 3}]] + result = kojihub.get_ready_hosts() + self.assertEqual(result, expected_res) + self.assertEqual(len(self.queries), 3) + + query = self.queries[0] + self.assertEqual(query.tables, ['host']) + self.assertEqual(query.joins, ['sessions USING (user_id)', + 'host_config ON host.id = host_config.host_id']) + self.assertEqual(query.clauses, ['active IS TRUE', 'enabled IS TRUE', 'expired IS FALSE', + 'master IS NULL', 'ready IS TRUE', + "update_time > NOW() - '5 minutes'::interval"]) + self.assertEqual(query.values, {}) + self.assertEqual(query.columns, ['arches', 'capacity', 'host.id', 'name', 'task_load']) + + query = self.queries[1] + self.assertEqual(query.tables, ['host_channels']) + self.assertEqual(query.joins, ['channels ON host_channels.channel_id = channels.id']) + self.assertEqual(query.clauses, ['active IS TRUE', 'enabled IS TRUE', 'host_id=%(id)s']) + self.assertEqual(query.values, hosts[0]) + self.assertEqual(query.columns, ['channel_id']) + + query = self.queries[2] + self.assertEqual(query.tables, ['host_channels']) + self.assertEqual(query.joins, ['channels ON host_channels.channel_id = channels.id']) + self.assertEqual(query.clauses, ['active IS TRUE', 'enabled IS TRUE', 'host_id=%(id)s']) + self.assertEqual(query.values, hosts[1]) + self.assertEqual(query.columns, ['channel_id']) diff --git a/tests/test_hub/test_get_session_info.py b/tests/test_hub/test_get_session_info.py index a97f8c4..9777421 100644 --- a/tests/test_hub/test_get_session_info.py +++ b/tests/test_hub/test_get_session_info.py @@ -1,34 +1,19 @@ -import mock -import unittest - import koji import kojihub +import mock +from .utils import DBQueryTestCase -QP = kojihub.QueryProcessor - - -class TestGetSessionInfo(unittest.TestCase): - def getQuery(self, *args, **kwargs): - query = QP(*args, **kwargs) - query.execute = mock.MagicMock() - self.queries.append(query) - return query +class TestGetSessionInfo(DBQueryTestCase): def setUp(self): + super(TestGetSessionInfo, self).setUp() self.context = mock.patch('kojihub.kojihub.context').start() self.exports = kojihub.RootExports() - - self.QueryProcessor = mock.patch('kojihub.kojihub.QueryProcessor', - side_effect=self.getQuery).start() - self.queries = [] self.context.session.hasPerm = mock.MagicMock() self.get_user = mock.patch('kojihub.kojihub.get_user').start() self.userinfo = {'id': 123, 'name': 'testuser'} self.exports.getLoggedInUser = mock.MagicMock() - def tearDown(self): - mock.patch.stopall() - def test_get_session_info_not_logged(self): self.context.session.logged_in = False result = self.exports.getSessionInfo() @@ -94,6 +79,7 @@ class TestGetSessionInfo(unittest.TestCase): def test_get_session_info_details(self): self.context.session.logged_in = True self.context.session.hasPerm.return_value = True + self.qp_execute_one_return_value = {'hostip': '10.0.0.0', 'id': 123} self.exports.getSessionInfo(details=True) self.assertEqual(len(self.queries), 1) query = self.queries[0] diff --git a/tests/test_hub/test_get_tag_external_repos.py b/tests/test_hub/test_get_tag_external_repos.py index ff0fc67..688017a 100644 --- a/tests/test_hub/test_get_tag_external_repos.py +++ b/tests/test_hub/test_get_tag_external_repos.py @@ -1,39 +1,24 @@ -import unittest - import mock import kojihub - -QP = kojihub.QueryProcessor +from .utils import DBQueryTestCase -class TestGetTagExternalRepos(unittest.TestCase): +class TestGetTagExternalRepos(DBQueryTestCase): def setUp(self): + super(TestGetTagExternalRepos, self).setUp() self.maxDiff = None self.get_tag = mock.patch('kojihub.kojihub.get_tag').start() self.get_external_repo = mock.patch('kojihub.kojihub.get_external_repo').start() self.exports = kojihub.RootExports() self.context = mock.patch('kojihub.kojihub.context').start() self.cursor = mock.MagicMock() - self.QueryProcessor = mock.patch('kojihub.kojihub.QueryProcessor', - side_effect=self.getQuery).start() - self.queries = [] self.build_tag = 'tag' self.repo = 'repo_name' self.build_tag_info = {'id': 111, 'name': self.build_tag} self.repo_info = {'id': 123, 'name': self.repo} - def tearDown(self): - mock.patch.stopall() - - def getQuery(self, *args, **kwargs): - query = QP(*args, **kwargs) - query.execute = mock.MagicMock() - query.executeOne = mock.MagicMock() - self.queries.append(query) - return query - def test_valid(self): self.get_tag.return_value = self.build_tag_info self.get_external_repo.return_value = self.repo_info diff --git a/tests/test_hub/test_get_task_children.py b/tests/test_hub/test_get_task_children.py index 495963e..2c01db8 100644 --- a/tests/test_hub/test_get_task_children.py +++ b/tests/test_hub/test_get_task_children.py @@ -1,34 +1,22 @@ import mock -import unittest import koji import kojihub +from .utils import DBQueryTestCase QP = kojihub.QueryProcessor -class TestGetTaskChildren(unittest.TestCase): +class TestGetTaskChildren(DBQueryTestCase): def setUp(self): + super(TestGetTaskChildren, self).setUp() self.exports = kojihub.RootExports() - self.QueryProcessor = mock.patch('kojihub.kojihub.QueryProcessor', - side_effect=self.getQuery).start() - self.queries = [] - - def getQuery(self, *args, **kwargs): - query = QP(*args, **kwargs) - query.execute = mock.MagicMock() - query.executeOne = mock.MagicMock() - query.singleValue = mock.MagicMock() - self.queries.append(query) - return query def tearDown(self): mock.patch.stopall() def test_get_task_children_non_existing(self): - q = self.getQuery() - q.execute.return_value = [] - self.QueryProcessor.side_effect = [q] + self.qp_execute_return_value = [] r = self.exports.getTaskChildren(1000) @@ -36,18 +24,14 @@ class TestGetTaskChildren(unittest.TestCase): def test_get_task_children_non_existing_strict(self): # get task info - q = self.getQuery() - q.executeOne.side_effect = koji.GenericError - self.QueryProcessor.side_effect = [q] + self.qp_execute_one_side_effect = koji.GenericError with self.assertRaises(koji.GenericError): self.exports.getTaskChildren(1000, strict=True) def test_get_task_children(self): children = [{'id': 1}] - q = self.getQuery() - q.execute.return_value = children - self.QueryProcessor.side_effect = [q] + self.qp_execute_return_value = children r = self.exports.getTaskChildren(1000) diff --git a/tests/test_hub/test_get_user.py b/tests/test_hub/test_get_user.py index 725c5b0..8365427 100644 --- a/tests/test_hub/test_get_user.py +++ b/tests/test_hub/test_get_user.py @@ -1,30 +1,19 @@ -import unittest - import mock +import unittest import koji import kojihub +from .utils import DBQueryTestCase -QP = kojihub.QueryProcessor - -class TestGetUser(unittest.TestCase): +class TestGetUser(DBQueryTestCase): def setUp(self): + super(TestGetUser, self).setUp() self.exports = kojihub.RootExports() self.context = mock.patch('kojihub.kojihub.context').start() - self.QueryProcessor = mock.patch('kojihub.kojihub.QueryProcessor', - side_effect=self.getQuery).start() - self.queries = [] - - def getQuery(self, *args, **kwargs): - query = QP(*args, **kwargs) - query.execute = mock.MagicMock() - self.queries.append(query) - return query - - def tearDown(self): - mock.patch.stopall() + self.list_user_krb_principals = mock.patch( + 'kojihub.kojihub.list_user_krb_principals').start() def test_wrong_format_user_info(self): userinfo = ['test-user'] @@ -71,9 +60,14 @@ class TestGetUser(unittest.TestCase): 'users.id = user_krb_principals.user_id']) self.assertEqual(query.values, {'info': userinfo}) - def test_userinfo_dict(self): + def test_userinfo_dict_with_krbs(self): userinfo = {'id': 123456, 'name': 'test-user', 'krb_principal': 'test-krb@krb.com'} - kojihub.get_user(userinfo, krb_princs=False) + self.qp_execute_one_return_value = {'id': 123456, 'name': 'test-user', + 'status': 1, 'usertype': 1} + self.list_user_krb_principals.return_value = 'test-krb@krb.com' + result = kojihub.get_user(userinfo, krb_princs=True) + self.assertEqual(result, {'id': 123456, 'krb_principals': 'test-krb@krb.com', + 'name': 'test-user', 'status': 1, 'usertype': 1}) self.assertEqual(len(self.queries), 1) query = self.queries[0] str(query) @@ -86,6 +80,23 @@ class TestGetUser(unittest.TestCase): 'users.id = user_krb_principals.user_id']) self.assertEqual(query.values, userinfo) + def test_userinfo_int_user_not_exist_and_strict(self): + userinfo = {'id': 123456} + self.qp_execute_one_return_value = {} + with self.assertRaises(koji.GenericError) as cm: + kojihub.get_user(userinfo['id'], strict=True, krb_princs=False) + self.assertEqual(f"No such user: {userinfo['id']}", str(cm.exception)) + self.assertEqual(len(self.queries), 1) + query = self.queries[0] + str(query) + self.assertEqual(query.tables, ['users']) + columns = ['id', 'name', 'status', 'usertype'] + self.assertEqual(set(query.columns), set(columns)) + self.assertEqual(query.clauses, ['users.id = %(id)i']) + self.assertEqual(query.joins, ['LEFT JOIN user_krb_principals ON ' + 'users.id = user_krb_principals.user_id']) + self.assertEqual(query.values, userinfo) + class TestGetUserByKrbPrincipal(unittest.TestCase): def setUp(self): diff --git a/tests/test_hub/test_get_verify_class.py b/tests/test_hub/test_get_verify_class.py index 918d3e2..077dfa7 100644 --- a/tests/test_hub/test_get_verify_class.py +++ b/tests/test_hub/test_get_verify_class.py @@ -9,8 +9,9 @@ from koji.util import adler32_constructor class TestGetVerifyClass(unittest.TestCase): def test_get_verify_class_generic_error(self): - with self.assertRaises(GenericError): + with self.assertRaises(GenericError) as ex: kojihub.get_verify_class('not_a_real_value') + self.assertEqual('Unsupported verify type: not_a_real_value', str(ex.exception)) def test_get_verify_class_is_none(self): kojihub.get_verify_class(None) is None @@ -23,4 +24,3 @@ class TestGetVerifyClass(unittest.TestCase): def test_get_verify_class_is_sha256(self): kojihub.get_verify_class('sha256') is hashlib.sha256 - diff --git a/tests/test_hub/test_get_volume.py b/tests/test_hub/test_get_volume.py index 2606116..3c17b1e 100644 --- a/tests/test_hub/test_get_volume.py +++ b/tests/test_hub/test_get_volume.py @@ -18,7 +18,7 @@ class TestGetVolume(unittest.TestCase): self.exports.getVolume(volume, strict=True) self.assertEqual("No such volume: %s" % volume, str(cm.exception)) - def test_non_exist_volume_with_strict(self): + def test_non_exist_volume_without_strict(self): volume = ['test-volume'] self.lookup_name.return_value = None result = self.exports.getVolume(volume) diff --git a/tests/test_hub/test_get_win_archive.py b/tests/test_hub/test_get_win_archive.py new file mode 100644 index 0000000..a3e14e9 --- /dev/null +++ b/tests/test_hub/test_get_win_archive.py @@ -0,0 +1,19 @@ +import kojihub +from .utils import DBQueryTestCase + + +class TestGetWinArchive(DBQueryTestCase): + + def setUp(self): + super(TestGetWinArchive, self).setUp() + self.maxDiff = None + + def test_valid(self): + kojihub.get_win_archive(123) + self.assertEqual(len(self.queries), 1) + query = self.queries[0] + self.assertEqual(query.tables, ['win_archives']) + self.assertEqual(query.joins, None) + self.assertEqual(query.clauses, ['archive_id = %(archive_id)i']) + self.assertEqual(query.values, {'archive_id': 123}) + self.assertEqual(query.columns, ['archive_id', 'flags', 'platforms', 'relpath']) diff --git a/tests/test_hub/test_get_win_build.py b/tests/test_hub/test_get_win_build.py new file mode 100644 index 0000000..c71e929 --- /dev/null +++ b/tests/test_hub/test_get_win_build.py @@ -0,0 +1,64 @@ +import mock +import koji +import kojihub +from .utils import DBQueryTestCase + + +class TestGetWinBuild(DBQueryTestCase): + + def setUp(self): + super(TestGetWinBuild, self).setUp() + self.maxDiff = None + self.find_build_id = mock.patch('kojihub.kojihub.find_build_id').start() + + def test_build_id_not_found(self): + self.find_build_id.return_value = None + result = kojihub.get_win_build('test-build.1-23.1') + self.assertEqual(result, None) + self.assertEqual(len(self.queries), 0) + self.find_build_id.assert_called_once_with('test-build.1-23.1', strict=False) + + def test_valid(self): + self.find_build_id.return_value = 123 + self.qp_execute_one_return_value = {'build_id': 123} + kojihub.get_win_build('test-build.1-23.1') + self.assertEqual(len(self.queries), 1) + query = self.queries[0] + self.assertEqual(query.tables, ['win_builds']) + self.assertEqual(query.joins, None) + self.assertEqual(query.clauses, ['build_id = %(build_id)i']) + self.assertEqual(query.values, {'build_id': 123}) + self.assertEqual(query.columns, ['build_id', 'platform']) + + self.find_build_id.assert_called_once_with('test-build.1-23.1', strict=False) + + def test_without_result_without_strict(self): + self.find_build_id.return_value = 123 + self.qp_execute_one_return_value = {} + result = kojihub.get_win_build('test-build.1-23.1') + self.assertEqual(result, {}) + self.assertEqual(len(self.queries), 1) + query = self.queries[0] + self.assertEqual(query.tables, ['win_builds']) + self.assertEqual(query.joins, None) + self.assertEqual(query.clauses, ['build_id = %(build_id)i']) + self.assertEqual(query.values, {'build_id': 123}) + self.assertEqual(query.columns, ['build_id', 'platform']) + + self.find_build_id.assert_called_once_with('test-build.1-23.1', strict=False) + + def test_without_result_with_strict(self): + self.find_build_id.return_value = 123 + self.qp_execute_one_return_value = {} + with self.assertRaises(koji.GenericError) as ex: + kojihub.get_win_build('test-build.1-23.1', strict=True) + self.assertEqual('no such Windows build: test-build.1-23.1', str(ex.exception)) + self.assertEqual(len(self.queries), 1) + query = self.queries[0] + self.assertEqual(query.tables, ['win_builds']) + self.assertEqual(query.joins, None) + self.assertEqual(query.clauses, ['build_id = %(build_id)i']) + self.assertEqual(query.values, {'build_id': 123}) + self.assertEqual(query.columns, ['build_id', 'platform']) + + self.find_build_id.assert_called_once_with('test-build.1-23.1', strict=True) diff --git a/tests/test_hub/test_recycle_build.py b/tests/test_hub/test_recycle_build.py index 237c2d7..24d3704 100644 --- a/tests/test_hub/test_recycle_build.py +++ b/tests/test_hub/test_recycle_build.py @@ -6,18 +6,26 @@ import kojihub QP = kojihub.QueryProcessor UP = kojihub.UpdateProcessor +DP = kojihub.DeleteProcessor class TestRecycleBuild(unittest.TestCase): def setUp(self): - self.QueryProcessor = mock.patch('kojihub.kojihub.QueryProcessor').start() + self.maxDiff = None + self.QueryProcessor = mock.patch('kojihub.kojihub.QueryProcessor', + side_effect=self.getQuery).start() + self.queries = [] + self.query_execute = mock.MagicMock() self.UpdateProcessor = mock.patch('kojihub.kojihub.UpdateProcessor', side_effect=self.getUpdate).start() - self._dml = mock.patch('kojihub.kojihub._dml').start() self.run_callbacks = mock.patch('koji.plugin.run_callbacks').start() self.rmtree = mock.patch('koji.util.rmtree').start() self.exists = mock.patch('os.path.exists').start() self.updates = [] + self.DeleteProcessor = mock.patch('kojihub.kojihub.DeleteProcessor', + side_effect=self.getDelete).start() + self.deletes = [] + self.get_build = mock.patch('kojihub.kojihub.get_build').start() def tearDown(self): mock.patch.stopall() @@ -28,9 +36,21 @@ class TestRecycleBuild(unittest.TestCase): self.updates.append(update) return update + def getQuery(self, *args, **kwargs): + query = QP(*args, **kwargs) + query.execute = self.query_execute + self.queries.append(query) + return query + + def getDelete(self, *args, **kwargs): + delete = DP(*args, **kwargs) + delete.execute = mock.MagicMock() + self.deletes.append(delete) + return delete + # Basic old and new build infos old = {'id': 2, - 'state': 0, + 'state': 3, 'task_id': None, 'epoch': None, 'name': 'GConf2', @@ -44,7 +64,7 @@ class TestRecycleBuild(unittest.TestCase): 'cg_id': None, 'volume_id': 0, 'volume_name': 'DEFAULT'} - new = {'state': 0, + new = {'state': 3, 'name': 'GConf2', 'version': '3.2.6', 'release': '15.fc23', @@ -58,97 +78,201 @@ class TestRecycleBuild(unittest.TestCase): 'cg_id': None, 'volume_id': 0} - def test_recycle_building(self): + def test_build_already_in_progress(self): new = self.new.copy() old = self.old.copy() old['state'] = new['state'] = koji.BUILD_STATES['BUILDING'] - old['task_id'] = new['task_id'] = 137 - kojihub.recycle_build(old, new) - self.UpdateProcessor.assert_not_called() - self.QueryProcessor.assert_not_called() - self._dml.assert_not_called() - self.run_callbacks.assert_not_called() - - def run_fail(self, old, new): - try: + old['task_id'] = 137 + with self.assertRaises(koji.GenericError) as ex: kojihub.recycle_build(old, new) - except koji.GenericError: - pass - else: - raise Exception("expected koji.GenericError") - self.UpdateProcessor.assert_not_called() - self._dml.assert_not_called() + self.assertEqual(f"Build already in progress (task {old['task_id']})", str(ex.exception)) + self.assertEqual(len(self.queries), 0) + self.assertEqual(len(self.updates), 0) + self.assertEqual(len(self.deletes), 0) + + self.get_build.assert_not_called() self.run_callbacks.assert_not_called() - def test_recycle_building_bad(self): + def test_build_already_in_progress_same_task_id(self): new = self.new.copy() old = self.old.copy() old['state'] = new['state'] = koji.BUILD_STATES['BUILDING'] + old['task_id'] = new['task_id'] = 137 + result = kojihub.recycle_build(old, new) + self.assertEqual(result, None) + self.assertEqual(len(self.queries), 0) + self.assertEqual(len(self.updates), 0) + self.assertEqual(len(self.deletes), 0) + + self.get_build.assert_not_called() + self.run_callbacks.assert_not_called() + + def test_not_in_failed_or_canceled_state(self): + old = self.old.copy() + old['state'] = koji.BUILD_STATES['COMPLETE'] + with self.assertRaises(koji.GenericError) as ex: + kojihub.recycle_build(old, self.new) + self.assertEqual(f"Build already exists (id={old['id']}, state=COMPLETE): {self.new}", + str(ex.exception)) + self.assertEqual(len(self.queries), 0) + self.assertEqual(len(self.updates), 0) + self.assertEqual(len(self.deletes), 0) + + self.get_build.assert_not_called() + self.run_callbacks.assert_not_called() + + def test_tag_activity_already_exists(self): + old = self.old.copy() old['task_id'] = 137 - new['task_id'] = 200 - self.run_fail(old, new) - self.QueryProcessor.assert_not_called() + self.query_execute.return_value = [{'tag_id': 123}] + with self.assertRaises(koji.GenericError) as ex: + kojihub.recycle_build(old, self.new) + self.assertEqual("Build already exists. Unable to recycle, has tag history", + str(ex.exception)) + self.assertEqual(len(self.queries), 1) + self.assertEqual(len(self.updates), 0) + self.assertEqual(len(self.deletes), 0) - def test_recycle_states_good(self): - for state in 'FAILED', 'CANCELED': - self.check_recycle_states_good, koji.BUILD_STATES[state] + query = self.queries[0] + self.assertEqual(query.tables, ['tag_listing']) + self.assertEqual(query.joins, None) + self.assertEqual(query.clauses, ['build_id = %(id)s']) + self.assertEqual(query.values, old) + self.assertEqual(query.columns, ['tag_id']) - def check_recycle_states_good(self, state): - new = self.new.copy() + self.get_build.assert_not_called() + self.run_callbacks.assert_not_called() + + def test_rpm_activity_already_exists(self): + old = self.old.copy() + old['task_id'] = 137 + self.query_execute.side_effect = [[], [{'id': 1}]] + with self.assertRaises(koji.GenericError) as ex: + kojihub.recycle_build(old, self.new) + self.assertEqual("Build already exists. Unable to recycle, has rpm data", + str(ex.exception)) + + self.assertEqual(len(self.queries), 2) + self.assertEqual(len(self.updates), 0) + self.assertEqual(len(self.deletes), 0) + + query = self.queries[0] + self.assertEqual(query.tables, ['tag_listing']) + self.assertEqual(query.joins, None) + self.assertEqual(query.clauses, ['build_id = %(id)s']) + self.assertEqual(query.values, old) + self.assertEqual(query.columns, ['tag_id']) + + query = self.queries[1] + self.assertEqual(query.tables, ['rpminfo']) + self.assertEqual(query.joins, None) + self.assertEqual(query.clauses, ['build_id = %(id)s']) + self.assertEqual(query.values, old) + self.assertEqual(query.columns, ['id']) + + self.get_build.assert_not_called() + self.run_callbacks.assert_not_called() + + def test_archive_activity_already_exists(self): + old = self.old.copy() + old['task_id'] = 137 + self.query_execute.side_effect = [[], [], [{'id': 11}]] + with self.assertRaises(koji.GenericError) as ex: + kojihub.recycle_build(old, self.new) + self.assertEqual("Build already exists. Unable to recycle, has archive data", + str(ex.exception)) + + self.assertEqual(len(self.queries), 3) + self.assertEqual(len(self.updates), 0) + self.assertEqual(len(self.deletes), 0) + + query = self.queries[0] + self.assertEqual(query.tables, ['tag_listing']) + self.assertEqual(query.joins, None) + self.assertEqual(query.clauses, ['build_id = %(id)s']) + self.assertEqual(query.values, old) + self.assertEqual(query.columns, ['tag_id']) + + query = self.queries[1] + self.assertEqual(query.tables, ['rpminfo']) + self.assertEqual(query.joins, None) + self.assertEqual(query.clauses, ['build_id = %(id)s']) + self.assertEqual(query.values, old) + self.assertEqual(query.columns, ['id']) + + query = self.queries[2] + self.assertEqual(query.tables, ['archiveinfo']) + self.assertEqual(query.joins, None) + self.assertEqual(query.clauses, ['build_id = %(id)s']) + self.assertEqual(query.values, old) + self.assertEqual(query.columns, ['id']) + + self.get_build.assert_not_called() + self.run_callbacks.assert_not_called() + + def test_valid(self): old = self.old.copy() - old['state'] = state - new['state'] = koji.BUILD_STATES['BUILDING'] - old['task_id'] = 99 - new['task_id'] = 137 - query = self.QueryProcessor.return_value - # for all checks - query.execute.return_value = [] - # for getBuild - query.executeOne.return_value = old - self.run_pass(old, new) - - def run_pass(self, old, new): + new = self.new.copy() + old['task_id'] = new['task_id'] = 137 + self.query_execute.side_effect = [[], [], []] + self.get_build.return_value = {'build_id': 2, 'name': 'GConf2', 'version': '3.2.6', + 'release': '15.fc23'} + kojihub.recycle_build(old, new) - self.UpdateProcessor.assert_called_once() + + self.assertEqual(len(self.queries), 3) + self.assertEqual(len(self.updates), 1) + self.assertEqual(len(self.deletes), 4) + + query = self.queries[0] + self.assertEqual(query.tables, ['tag_listing']) + self.assertEqual(query.joins, None) + self.assertEqual(query.clauses, ['build_id = %(id)s']) + self.assertEqual(query.values, old) + self.assertEqual(query.columns, ['tag_id']) + + query = self.queries[1] + self.assertEqual(query.tables, ['rpminfo']) + self.assertEqual(query.joins, None) + self.assertEqual(query.clauses, ['build_id = %(id)s']) + self.assertEqual(query.values, old) + self.assertEqual(query.columns, ['id']) + + query = self.queries[2] + self.assertEqual(query.tables, ['archiveinfo']) + self.assertEqual(query.joins, None) + self.assertEqual(query.clauses, ['build_id = %(id)s']) + self.assertEqual(query.values, old) + self.assertEqual(query.columns, ['id']) + + delete = self.deletes[0] + self.assertEqual(delete.table, 'maven_builds') + self.assertEqual(delete.clauses, ['build_id = %(id)i']) + self.assertEqual(delete.values, old) + + delete = self.deletes[1] + self.assertEqual(delete.table, 'win_builds') + self.assertEqual(delete.clauses, ['build_id = %(id)i']) + self.assertEqual(delete.values, old) + + delete = self.deletes[2] + self.assertEqual(delete.table, 'image_builds') + self.assertEqual(delete.clauses, ['build_id = %(id)i']) + self.assertEqual(delete.values, old) + + delete = self.deletes[3] + self.assertEqual(delete.table, 'build_types') + self.assertEqual(delete.clauses, ['build_id = %(id)i']) + self.assertEqual(delete.values, old) + update = self.updates[0] - assert update.table == 'build' + self.assertEqual(update.table, 'build') + self.assertEqual(update.values, new) for key in ['state', 'task_id', 'owner', 'start_time', 'completion_time', 'epoch']: assert update.data[key] == new[key] - assert update.rawdata == {'create_event': 'get_event()'} - assert update.clauses == ['id=%(id)s'] - assert update.values['id'] == old['id'] - - def test_recycle_states_bad(self): - for state in 'BUILDING', 'COMPLETE', 'DELETED': - self.check_recycle_states_bad, koji.BUILD_STATES[state] + self.assertEqual(update.rawdata, {'create_event': 'get_event()'}) + self.assertEqual(update.clauses, ['id=%(id)s']) - def check_recycle_states_bad(self, state): - new = self.new.copy() - old = self.old.copy() - old['state'] = state - new['state'] = koji.BUILD_STATES['BUILDING'] - old['task_id'] = 99 - new['task_id'] = 137 - self.run_fail(old, new) - self.QueryProcessor.assert_not_called() - - def test_recycle_query_bad(self): - vlists = [ - [[], [], True], - [True, [], []], - [[], True, []], - ] - for values in vlists: - self.check_recycle_query_bad, values - - def check_recycle_query_bad(self, values): - new = self.new.copy() - old = self.old.copy() - old['state'] = koji.BUILD_STATES['FAILED'] - new['state'] = koji.BUILD_STATES['BUILDING'] - old['task_id'] = 99 - new['task_id'] = 137 - query = self.QueryProcessor.return_value - query.execute.side_effect = values - self.run_fail(old, new) + self.get_build.assert_called_once_with(new['id'], strict=True) + self.assertEqual(self.run_callbacks.call_count, 2) diff --git a/tests/test_hub/test_remove_external_repo_from_tag.py b/tests/test_hub/test_remove_external_repo_from_tag.py new file mode 100644 index 0000000..19337e6 --- /dev/null +++ b/tests/test_hub/test_remove_external_repo_from_tag.py @@ -0,0 +1,72 @@ +import unittest +import mock + +import koji +import kojihub + +UP = kojihub.UpdateProcessor + + +class TestRemoveExternalRepoFromTag(unittest.TestCase): + def getUpdate(self, *args, **kwargs): + update = UP(*args, **kwargs) + update.execute = mock.MagicMock() + self.updates.append(update) + return update + + def setUp(self): + self.context = mock.patch('kojihub.kojihub.context').start() + self.context.session.assertPerm = mock.MagicMock() + self.context_db = mock.patch('kojihub.db.context').start() + self.context_db.session.assertLogin = mock.MagicMock() + self.UpdateProcessor = mock.patch('kojihub.kojihub.UpdateProcessor', + side_effect=self.getUpdate).start() + self.updates = [] + self.get_tag = mock.patch('kojihub.kojihub.get_tag').start() + self.get_tag_external_repos = mock.patch('kojihub.kojihub.get_tag_external_repos').start() + self.get_external_repo = mock.patch('kojihub.kojihub.get_external_repo').start() + + def tearDown(self): + mock.patch.stopall() + + def test_not_exist_tag_external_repo(self): + tag_info = {'id': 22, 'name': 'test-tag'} + repo_info = {'id': 1, 'name': 'test-repo'} + self.get_tag.return_value = tag_info + self.get_external_repo.return_value = repo_info + self.get_tag_external_repos.return_value = None + with self.assertRaises(koji.GenericError) as ex: + kojihub.remove_external_repo_from_tag(tag_info['name'], repo_info['name']) + self.assertEqual( + f'external repo {repo_info["name"]} not associated with tag {tag_info["name"]}', + str(ex.exception)) + + self.assertEqual(len(self.updates), 0) + self.get_tag.assert_called_once_with(tag_info['name'], strict=True) + self.get_external_repo.assert_called_once_with(repo_info['name'], strict=True) + self.get_tag_external_repos.assert_called_once_with( + tag_info=tag_info['id'], repo_info=repo_info['id']) + + def test_valid(self): + tag_info = {'id': 22, 'name': 'test-tag'} + repo_info = {'id': 1, 'name': 'test-repo'} + self.context_db.event_id = 42 + self.context_db.session.user_id = 23 + self.get_tag.return_value = tag_info + self.get_external_repo.return_value = repo_info + self.get_tag_external_repos.return_value = [{'id': repo_info['id'], + 'tag_id': tag_info['id']}] + kojihub.remove_external_repo_from_tag(tag_info['name'], repo_info['name']) + + self.assertEqual(len(self.updates), 1) + update = self.updates[0] + self.assertEqual(update.table, 'tag_external_repos') + self.assertEqual(update.clauses, ["tag_id = %(tag_id)i", "external_repo_id = %(repo_id)i", + 'active = TRUE']) + self.assertEqual(update.data, {'revoke_event': 42, 'revoker_id': 23}) + self.assertEqual(update.rawdata, {'active': 'NULL'}) + + self.get_tag.assert_called_once_with(tag_info['name'], strict=True) + self.get_external_repo.assert_called_once_with(repo_info['name'], strict=True) + self.get_tag_external_repos.assert_called_once_with( + tag_info=tag_info['id'], repo_info=repo_info['id']) diff --git a/tests/test_hub/utils.py b/tests/test_hub/utils.py index 4e069ae..4923cb3 100644 --- a/tests/test_hub/utils.py +++ b/tests/test_hub/utils.py @@ -12,8 +12,11 @@ class DBQueryTestCase(unittest.TestCase): mock.patch.stopall() self.qp_execute_return_value = [] self.qp_execute_side_effect = None + self.qp_execute_one_return_value = [] + self.qp_execute_one_side_effect = None + self.qp_single_value_return_value = None self.QueryProcessor = mock.patch('kojihub.kojihub.QueryProcessor', - side_effect=self.get_query).start() + side_effect=self.get_query).start() self.queries = [] def tearDown(self): @@ -28,6 +31,11 @@ class DBQueryTestCase(unittest.TestCase): query.execute = mock.MagicMock() query.execute.return_value = self.qp_execute_return_value query.execute.side_effect = self.qp_execute_side_effect + query.executeOne = mock.MagicMock() + query.executeOne.return_value = self.qp_execute_one_return_value + query.executeOne.side_effect = self.qp_execute_one_side_effect + query.singleValue = mock.MagicMock() + query.singleValue.return_value = self.qp_single_value_return_value self.queries.append(query) return query @@ -42,4 +50,3 @@ class DBQueryTestCase(unittest.TestCase): def assertQueriesEqual(self, arglist): for i, query in enumerate(self.queries): self.assertQueryEqual(query, **arglist[i]) -