From 8ba75e6966e12acfd3aec959f09d9918ba5c995b Mon Sep 17 00:00:00 2001 From: Yuming Zhu Date: Dec 08 2017 05:33:48 +0000 Subject: hub: make list_archives to accept strict argument fixes: #721 --- diff --git a/hub/kojihub.py b/hub/kojihub.py index d823f30..5eb0882 100644 --- a/hub/kojihub.py +++ b/hub/kojihub.py @@ -3949,7 +3949,7 @@ def add_btype(name): def list_archives(buildID=None, buildrootID=None, componentBuildrootID=None, hostID=None, type=None, filename=None, size=None, checksum=None, typeInfo=None, queryOpts=None, imageID=None, - archiveID=None): + archiveID=None, strict=False): """ Retrieve information about archives. If buildID is not null it will restrict the list to archives built by the build with that ID. @@ -4007,8 +4007,8 @@ def list_archives(buildID=None, buildrootID=None, componentBuildrootID=None, hos For the 'maven' type, this dict may contain one or more of group_id, artifact_id, or version, and the output will be restricted to archives with matching attributes. - If there are no archives matching the selection criteria, - an empty list is returned. + If there are no archives matching the selection criteria, if strict is False, + an empty list is returned, otherwise GenericError is raised. """ values = {} @@ -4106,6 +4106,7 @@ def list_archives(buildID=None, buildrootID=None, componentBuildrootID=None, hos joins.append('image_archives ON archiveinfo.id = image_archives.archive_id') fields.append(['image_archives.arch', 'arch']) if typeInfo and typeInfo.get('arch'): + key = 'arch' clauses.append('image_archives.%s = %%(%s)s' % (key, key)) values[key] = typeInfo[key] else: @@ -4122,6 +4123,8 @@ def list_archives(buildID=None, buildrootID=None, componentBuildrootID=None, hos ret = QueryProcessor(tables=tables, columns=columns, aliases=aliases, joins=joins, transform=_fix_archive_row, clauses=clauses, values=values, opts=queryOpts).execute() + if strict and not ret: + raise koji.GenericError('No archives found.') return ret diff --git a/tests/test_hub/test_list_archives.py b/tests/test_hub/test_list_archives.py new file mode 100644 index 0000000..677755d --- /dev/null +++ b/tests/test_hub/test_list_archives.py @@ -0,0 +1,259 @@ +import mock +from utils import DBQueryTestCase + +import koji +import kojihub + + +class TestListArchives(DBQueryTestCase): + maxDiff = None + + def test_list_archives_simple(self): + rv = kojihub.list_archives() + + self.assertEqual(len(self.queries), 1) + self.assertLastQueryEqual(tables=['archiveinfo'], + joins=['archivetypes on archiveinfo.type_id = archivetypes.id', + 'btype ON archiveinfo.btype_id = btype.id'], + clauses=[], + values={}) + self.assertEqual(rv, []) + + def test_list_archives_strict(self): + with self.assertRaises(koji.GenericError) as cm: + kojihub.list_archives(strict=True) + self.assertEqual(cm.exception.args[0], 'No archives found.') + + def test_list_archives_buildid(self): + kojihub.list_archives(buildID=1) + self.assertLastQueryEqual(tables=['archiveinfo'], + joins=['archivetypes on archiveinfo.type_id = archivetypes.id', + 'btype ON archiveinfo.btype_id = btype.id'], + clauses=['build_id = %(build_id)i'], + values={'build_id': 1}) + + def test_list_archives_buildrootid(self): + kojihub.list_archives(buildrootID=1) + self.assertLastQueryEqual(tables=['archiveinfo'], + joins=['archivetypes on archiveinfo.type_id = archivetypes.id', + 'btype ON archiveinfo.btype_id = btype.id'], + clauses=['buildroot_id = %(buildroot_id)i'], + values={'buildroot_id': 1}) + + def test_list_archives_componentbuildrootid(self): + kojihub.list_archives(componentBuildrootID=1) + self.assertLastQueryEqual(tables=['archiveinfo'], + joins=['archivetypes on archiveinfo.type_id = archivetypes.id', + 'btype ON archiveinfo.btype_id = btype.id', + 'buildroot_archives on archiveinfo.id = buildroot_archives.archive_id'], + clauses=['buildroot_archives.buildroot_id = %(component_buildroot_id)i'], + values={'component_buildroot_id': 1}, + colsByAlias={'build_id': 'archiveinfo.build_id', + 'type_name': 'archivetypes.name', + 'component_buildroot_id': 'buildroot_archives.buildroot_id', + 'type_id': 'archiveinfo.type_id', + 'checksum': 'archiveinfo.checksum', + 'extra': 'archiveinfo.extra', + 'filename': 'archiveinfo.filename', + 'project': 'buildroot_archives.project_dep', + 'type_description': 'archivetypes.description', + 'metadata_only': 'archiveinfo.metadata_only', + 'type_extensions': 'archivetypes.extensions', + 'btype': 'btype.name', + 'checksum_type': 'archiveinfo.checksum_type', + 'btype_id': 'archiveinfo.btype_id', + 'buildroot_id': 'archiveinfo.buildroot_id', + 'id': 'archiveinfo.id', + 'size': 'archiveinfo.size'}) + + def test_list_archives_imageid(self): + kojihub.list_archives(imageID=1) + self.assertLastQueryEqual(tables=['archiveinfo'], + joins=['archivetypes on archiveinfo.type_id = archivetypes.id', + 'btype ON archiveinfo.btype_id = btype.id', + 'archive_components ON archiveinfo.id = archive_components.component_id'], + clauses=['archive_components.archive_id = %(imageID)i'], + values={'imageID': 1}) + + def test_list_archives_hostid(self): + kojihub.list_archives(hostID=1) + self.assertLastQueryEqual(tables=['archiveinfo'], + joins=['archivetypes on archiveinfo.type_id = archivetypes.id', + 'btype ON archiveinfo.btype_id = btype.id', + 'standard_buildroot on archiveinfo.buildroot_id = standard_buildroot.buildroot_id'], + clauses=['standard_buildroot.host_id = %(host_id)i'], + values={'host_id': 1}, + colsByAlias={'host_id': 'standard_buildroot.host_id', + 'build_id': 'archiveinfo.build_id', + 'type_name': 'archivetypes.name', + 'type_id': 'archiveinfo.type_id', + 'checksum': 'archiveinfo.checksum', + 'extra': 'archiveinfo.extra', + 'filename': 'archiveinfo.filename', + 'type_description': 'archivetypes.description', + 'metadata_only': 'archiveinfo.metadata_only', + 'type_extensions': 'archivetypes.extensions', + 'btype': 'btype.name', + 'checksum_type': 'archiveinfo.checksum_type', + 'btype_id': 'archiveinfo.btype_id', + 'buildroot_id': 'archiveinfo.buildroot_id', + 'id': 'archiveinfo.id', + 'size': 'archiveinfo.size'}) + + def test_list_archives_filename(self): + kojihub.list_archives(filename='somefile.txt') + self.assertLastQueryEqual(tables=['archiveinfo'], + joins=['archivetypes on archiveinfo.type_id = archivetypes.id', + 'btype ON archiveinfo.btype_id = btype.id'], + clauses=['filename = %(filename)s'], + values={'filename': 'somefile.txt'}) + + def test_list_archives_size(self): + kojihub.list_archives(size=1231831) + self.assertLastQueryEqual(tables=['archiveinfo'], + joins=['archivetypes on archiveinfo.type_id = archivetypes.id', + 'btype ON archiveinfo.btype_id = btype.id'], + clauses=['size = %(size)i'], + values={'size': 1231831}) + + def test_list_archives_checksum(self): + kojihub.list_archives(checksum='7873f0a6dbf3abc07724e000ac9b3941') + self.assertLastQueryEqual(tables=['archiveinfo'], + joins=['archivetypes on archiveinfo.type_id = archivetypes.id', + 'btype ON archiveinfo.btype_id = btype.id'], + clauses=['checksum = %(checksum)s'], + values={'checksum': '7873f0a6dbf3abc07724e000ac9b3941'}) + + def test_list_archives_archiveid(self): + kojihub.list_archives(archiveID=1) + self.assertLastQueryEqual(tables=['archiveinfo'], + joins=['archivetypes on archiveinfo.type_id = archivetypes.id', + 'btype ON archiveinfo.btype_id = btype.id'], + clauses=['archiveinfo.id = %(archive_id)s'], + values={'archive_id': 1}) + + def test_list_archives_type_maven(self): + kojihub.list_archives(type='maven', typeInfo={'group_id': 'gid', + 'artifact_id': 'aid', + 'version': '1.0.1'}) + self.assertLastQueryEqual(tables=['archiveinfo'], + joins=['archivetypes on archiveinfo.type_id = archivetypes.id', + 'btype ON archiveinfo.btype_id = btype.id', + 'maven_archives ON archiveinfo.id = maven_archives.archive_id'], + clauses=['maven_archives.group_id = %(group_id)s', + 'maven_archives.artifact_id = %(artifact_id)s', + 'maven_archives.version = %(version)s'], + values={'group_id': 'gid', + 'artifact_id': 'aid', + 'version': '1.0.1'}, + colsByAlias={'group_id': 'maven_archives.group_id', + 'artifact_id': 'maven_archives.artifact_id', + 'version': 'maven_archives.version', + 'build_id': 'archiveinfo.build_id', + 'type_name': 'archivetypes.name', + 'type_id': 'archiveinfo.type_id', + 'checksum': 'archiveinfo.checksum', + 'extra': 'archiveinfo.extra', + 'filename': 'archiveinfo.filename', + 'type_description': 'archivetypes.description', + 'metadata_only': 'archiveinfo.metadata_only', + 'type_extensions': 'archivetypes.extensions', + 'btype': 'btype.name', + 'checksum_type': 'archiveinfo.checksum_type', + 'btype_id': 'archiveinfo.btype_id', + 'buildroot_id': 'archiveinfo.buildroot_id', + 'id': 'archiveinfo.id', + 'size': 'archiveinfo.size'}) + + def test_list_archives_type_win(self): + kojihub.list_archives(type='win', typeInfo={'relpath': 'somerelpath', + 'platforms': 'all', + 'flags': ['A', 'B']}) + self.assertLastQueryEqual(tables=['archiveinfo'], + joins=['archivetypes on archiveinfo.type_id = archivetypes.id', + 'btype ON archiveinfo.btype_id = btype.id', + 'win_archives ON archiveinfo.id = win_archives.archive_id'], + clauses=['win_archives.relpath = %(relpath)s', + r"platforms ~ E'\\mall\\M'", + r"flags ~ E'\\mA\\M'", + r"flags ~ E'\\mB\\M'"], + values={'relpath': 'somerelpath'}, + colsByAlias={'relpath': 'win_archives.relpath', + 'platforms': 'win_archives.platforms', + 'flags': 'win_archives.flags', + 'build_id': 'archiveinfo.build_id', + 'type_name': 'archivetypes.name', + 'type_id': 'archiveinfo.type_id', + 'checksum': 'archiveinfo.checksum', + 'extra': 'archiveinfo.extra', + 'filename': 'archiveinfo.filename', + 'type_description': 'archivetypes.description', + 'metadata_only': 'archiveinfo.metadata_only', + 'type_extensions': 'archivetypes.extensions', + 'btype': 'btype.name', + 'checksum_type': 'archiveinfo.checksum_type', + 'btype_id': 'archiveinfo.btype_id', + 'buildroot_id': 'archiveinfo.buildroot_id', + 'id': 'archiveinfo.id', + 'size': 'archiveinfo.size'}) + + def test_list_archives_type_image(self): + kojihub.list_archives(type='image', typeInfo={'arch': 'i386'}) + self.assertLastQueryEqual(tables=['archiveinfo'], + joins=['archivetypes on archiveinfo.type_id = archivetypes.id', + 'btype ON archiveinfo.btype_id = btype.id', + 'image_archives ON archiveinfo.id = image_archives.archive_id'], + clauses=['image_archives.arch = %(arch)s'], + values={'arch': 'i386'}, + colsByAlias={'arch': 'image_archives.arch', + 'build_id': 'archiveinfo.build_id', + 'type_name': 'archivetypes.name', + 'type_id': 'archiveinfo.type_id', + 'checksum': 'archiveinfo.checksum', + 'extra': 'archiveinfo.extra', + 'filename': 'archiveinfo.filename', + 'type_description': 'archivetypes.description', + 'metadata_only': 'archiveinfo.metadata_only', + 'type_extensions': 'archivetypes.extensions', + 'btype': 'btype.name', + 'checksum_type': 'archiveinfo.checksum_type', + 'btype_id': 'archiveinfo.btype_id', + 'buildroot_id': 'archiveinfo.buildroot_id', + 'id': 'archiveinfo.id', + 'size': 'archiveinfo.size'}) + + @mock.patch('kojihub.lookup_name', return_value={'id': 111, 'name': 'other'}) + def test_list_archives_type_others(self, lookup_name): + kojihub.list_archives(type='other') + self.assertLastQueryEqual(tables=['archiveinfo'], + joins=['archivetypes on archiveinfo.type_id = archivetypes.id', + 'btype ON archiveinfo.btype_id = btype.id'], + clauses=['archiveinfo.btype_id = %(btype_id)s'], + values={'btype_id': 111}, + colsByAlias={'build_id': 'archiveinfo.build_id', + 'type_name': 'archivetypes.name', + 'type_id': 'archiveinfo.type_id', + 'checksum': 'archiveinfo.checksum', + 'extra': 'archiveinfo.extra', + 'filename': 'archiveinfo.filename', + 'type_description': 'archivetypes.description', + 'metadata_only': 'archiveinfo.metadata_only', + 'type_extensions': 'archivetypes.extensions', + 'btype': 'btype.name', + 'checksum_type': 'archiveinfo.checksum_type', + 'btype_id': 'archiveinfo.btype_id', + 'buildroot_id': 'archiveinfo.buildroot_id', + 'id': 'archiveinfo.id', + 'size': 'archiveinfo.size'}) + + @mock.patch('kojihub.lookup_name', return_value=None) + def test_list_archives_type_not_found(self, lookup_name): + with self.assertRaises(koji.GenericError) as cm: + kojihub.list_archives(type='other') + self.assertEqual(cm.exception.args[0], 'unsupported archive type: other') + + @mock.patch('kojihub.lookup_name', return_value={'id': 111, 'name': 'other'}) + def test_list_archives_type_other_with_typeinfo(self, lookup_name): + with self.assertRaises(koji.GenericError) as cm: + kojihub.list_archives(type='other', typeInfo={'somekey': 'somevalue'}) + self.assertEqual(cm.exception.args[0], 'typeInfo queries not supported for type other') diff --git a/tests/test_hub/utils.py b/tests/test_hub/utils.py new file mode 100644 index 0000000..1e14b6e --- /dev/null +++ b/tests/test_hub/utils.py @@ -0,0 +1,45 @@ +import unittest +import mock +import six + +import kojihub + +QP = kojihub.QueryProcessor + + +class DBQueryTestCase(unittest.TestCase): + + def setUp(self): + self.qp_execute_return_value = [] + self.qp_execute_side_effect = None + self.QueryProcessor = mock.patch('kojihub.QueryProcessor', + side_effect=self.get_query).start() + self.queries = [] + + def tearDown(self): + mock.patch.stopall() + self.reset_query() + + def reset_query(self): + del self.queries[:] + + def get_query(self, *args, **kwargs): + query = QP(*args, **kwargs) + query.execute = mock.MagicMock() + query.execute.return_value = self.qp_execute_return_value + query.execute.side_effect = self.qp_execute_side_effect + self.queries.append(query) + return query + + def assertQueryEqual(self, query, **kwargs): + for k, v in six.iteritems(kwargs): + self.assertEqual(getattr(query, k, None), v) + + def assertLastQueryEqual(self, **kwargs): + query = self.queries[-1] + self.assertQueryEqual(query, **kwargs) + + def assertQueriesEqual(self, arglist): + for i, query in enumerate(self.queries): + self.assertQueryEqual(query, **arglist[i]) +