from __future__ import absolute_import, print_function import collections try: from unittest import mock except ImportError: import mock import six import time import unittest import koji from koji_cli.commands import anon_handle_taskinfo, \ _printTaskInfo, _parseTaskParams from . import utils class TestParseTaskParams(utils.CliTestCase): # Show long diffs in error output... maxDiff = None def setUp(self): self.session = mock.MagicMock() self.build_templ = { 'package_name': 'bash', 'version': '4.4.12', 'release': '5.fc26', 'epoch': None, 'nvr': 'bash-4.4.12-5.fc26', 'build_id': 1, } def __run_parseTask_test(self, method, params, expect): self.session.getTaskRequest.return_value = params lines = _parseTaskParams(self.session, method, 1, '/mnt/koji') self.assertEqual(lines, expect) def test_error_with_param(self): params = [] expect = ['Unable to parse task parameters'] with mock.patch('koji_cli.commands.logging.getLogger', create=True) as get_logger_mock: h = get_logger_mock() h.isEnabledFor.return_value = True self.__run_parseTask_test('buildSRPMFromCVS', params, expect) logger = get_logger_mock() logger.isEnabledFor.assert_called_once() logger.debug.assert_called_once() def test_buildSRPMFrom(self): # from CVS case params = ['cvs.src.org'] expect = ["CVS URL: %s" % params[0]] self.__run_parseTask_test('buildSRPMFromCVS', params, expect) # from SCM case params = ['git.github.com'] expect = ["SCM URL: %s" % params[0]] self.__run_parseTask_test('buildSRPMFromSCM', params, expect) def test_buildArch(self): name = 'TEST' topdir = '/mnt/koji' self.session.getTag.return_value = {'name': name} params = ['path/to/bash-4.4.12-5.fc26.src.rpm', 2, 'x86_64', True, {'repo_id': 1}] expect = ["SRPM: %s/work/%s" % (topdir, params[0])] expect.append("Build Tag: %s" % name) expect.append("Build Arch: %s" % params[2]) expect.append("SRPM Kept: %r" % params[3]) expect.append("Options:") expect.append(" repo_id: 1") self.__run_parseTask_test('buildArch', params, expect) def test_tagBuild(self): params = [1, 1, False, None, True] self.session.getTag.return_value = {'name': 'fedora'} self.session.getBuild.return_value = self.build_templ expect = ["Destination Tag: fedora"] expect.append("Build: bash-4.4.12-5.fc26") self.__run_parseTask_test('tagBuild', params, expect) def test_buildNotification(self): params = [['r1', 'r2'], self.build_templ, {'name': 'fedora'}, 'fedoraproject.org'] expect = ["Recipients: %s" % (", ".join(params[0]))] expect.append("Build: %s" % self.build_templ['nvr']) expect.append("Build Target: %s" % params[2]['name']) expect.append("Web URL: %s" % params[3]) self.__run_parseTask_test('buildNotification', params, expect) def test_build(self): params = ['path/to/bash-4.4.12-5.fc26.src.rpm', 'fedora26-build', {'build-test': True}] expect = ["Source: %s" % params[0]] expect.append("Build Target: %s" % params[1]) expect.append("Options:") expect.append(" build-test: True") self.__run_parseTask_test('build', params, expect) def test_maven(self): params = ['scm.maven.org', 'maven-target', {'maven-test': True}] expect = ["SCM URL: %s" % params[0]] expect.append("Build Target: %s" % params[1]) expect.append("Options:") expect.append(" maven-test: True") self.__run_parseTask_test('maven', params, expect) def test_buildMaven(self): params = ['scm.maven.org', {'name': 'maven-tag'}, {'build-test': True}] expect = ["SCM URL: %s" % params[0]] expect.append("Build Tag: %s" % params[1]['name']) expect.append("Options:") expect.append(" build-test: True") self.__run_parseTask_test('buildMaven', params, expect) def test_wrapperRPM(self): target = 'test-target' params = [ 'http://path.to/pkg.spec', {'name': 'build-tag'}, self.build_templ, { 'id': 1, 'method': 'wrapperRPM', 'arch': 'x86_64', 'request': [1, {'name': target}, self.build_templ, 'task', 'opts'] }, {'wrapRPM-test': True}] expect = ["Spec File URL: %s" % params[0]] expect.append("Build Tag: %s" % params[1]['name']) expect.append("Build: %s" % self.build_templ['nvr']) task_info = "wrapperRPM (%s, %s)" % (target, self.build_templ['nvr']) expect.append("Task: %s %s" % (params[3]['id'], task_info)) expect.append("Options:") expect.append(" wrapRPM-test: True") self.__run_parseTask_test('wrapperRPM', params, expect) def test_chainmaven(self): params = [{ 'maven-pkg-1': {'build-opt': '--test'}, 'maven-pkg-2': {'build-opt': '-O2'}, }, 'build-target', {'chainmaven-test': True}] expect = ["Builds:"] for pkg, opt in params[0].items(): expect.append(" %s" % pkg) for k, v in opt.items(): expect.append(" %s: %s" % (k, v)) expect.append("Build Target: %s" % params[1]) expect.append("Options:") expect.append(" chainmaven-test: True") self.__run_parseTask_test('chainmaven', params, expect) def test_winbuild(self): params = ['vm-builder', 'github.com', 'target', {'winver': 10}] expect = ["VM: %s" % params[0]] expect.append("SCM URL: %s" % params[1]) expect.append("Build Target: %s" % params[2]) expect.append("Options:") expect.append(" winver: 10") self.__run_parseTask_test('winbuild', params, expect) def test_vmExec(self): params = ['vm-name', ['x86_64', {'cpu': 'GenuineIntel'}], {'optimize': '-O3'}] expect = ["VM: %s" % params[0]] expect.append("Exec Params:") expect.append(" x86_64") expect.append(" cpu: GenuineIntel") expect.append("Options:") expect.append(" optimize: -O3") self.__run_parseTask_test('vmExec', params, expect) def test_createXXX(self): params = ['name', '1.0', '1', 'x86_64', 'target_info', 'build-tag', 'Repo', 'kickstart.ks', {}] fields = ['Name', 'Version', 'Release', 'Arch', 'Target Info', 'Build Tag', 'Repo', 'Kickstart File'] template = list() for n, v in zip(fields, params): template.append("%s: %s" % (n, v)) for method in ('createLiveCD', 'createAppliance', 'createLiveMedia'): params[-1] = {"extra": "test-%s" % method} expect = list(template) expect.append("Options:") expect.append(" extra: test-%s" % method) self.__run_parseTask_test(method, params, expect) def test_appliance_livecd_livemedia(self): params = ['name', '1.0', 'x86_64, ppc64', 'target_info', 'kickstart.ks', {}] fields = ['Name', 'Version', 'Arches', 'Target', 'Kickstart'] template = list() for n, v in zip(fields, params): template.append("%s: %s" % (n, v)) for method in ('appliance', 'livecd', 'livemedia'): params[-1] = {"extra": "test-%s" % method} expect = list(template) expect.append("Options:") expect.append(" extra: test-%s" % method) self.__run_parseTask_test(method, params, expect) def test_newRepo(self): params = [0] self.session.getTag.return_value = {'name': 'f26'} expect = ['Tag: f26'] self.__run_parseTask_test('newRepo', params, expect) def test_prepRepo(self): params = [{'name': 'f26'}] expect = ['Tag: f26'] self.__run_parseTask_test('prepRepo', params, expect) def test_createRepo(self): params = [1, 'x86_64', {'id': 1, 'create_ts': 0}, [{'external_repo_name': 'fedoraproject.net'}, {'external_repo_name': 'centos.org'}]] expect = ["Repo ID: %i" % params[0]] expect.append("Arch: %s" % params[1]) expect.append("Old Repo ID: %i" % params[2]['id']) expect.append("Old Repo Creation: Thu, 01 Jan 1970") expect.append("External Repos: %s" % ', '.join( [ext['external_repo_name'] for ext in params[3]])) with mock.patch('koji.formatTimeLong', return_value='Thu, 01 Jan 1970'): self.__run_parseTask_test('createrepo', params, expect) def test_tagNotification(self): params = [['kojiadmin', 'user'], # recipients True, # successful 1, # dest tag id 2, # src tag id 3, # build id 0, # user id False, # Ignoresuccess 'no error'] # Failure message destTag, srcTag = {'name': 'dest-tag-1'}, {'name': 'src-tag-2'} user = {'name': 'kojiadmin'} self.session.getTag.side_effect = [destTag, srcTag] self.session.getBuild.return_value = self.build_templ self.session.getUser.return_value = user expect = ["Recipients: %s" % ", ".join(params[0])] expect.append("Successful?: %s" % (params[1] and 'yes' or 'no')) expect.append("Tagged Into: %s" % destTag['name']) expect.append("Moved From: %s" % srcTag['name']) expect.append("Build: %s" % self.build_templ['nvr']) expect.append("Tagged By: %s" % user['name']) expect.append("Ignore Success?: %s" % (params[6] and 'yes' or 'no')) expect.append("Failure Message: %s" % params[7]) self.__run_parseTask_test('tagNotification', params, expect) def test_dependantTask(self): params = [ [1, 2, 3, 4], # dependant task ids [ ['buildSRPMFromSCM', ['param1', 'param2'], {'scm': 'github.com'}], ['build', ['param1', 'param2'], {'arch': 'x86_64'}], ['tagBuild', ['tagname', 'param2'], {}] ] ] expect = ["Dependant Tasks: %s" % ", ".join([str(dep) for dep in params[0]])] expect.append("Subtasks:") for subtask in params[1]: expect.append(" Method: %s" % subtask[0]) expect.append(" Parameters: %s" % ", ".join( [str(subparam) for subparam in subtask[1]])) if subtask[2]: expect.append(' Options:') for k, v in subtask[2].items(): expect.append(' %s: %s' % (k, v)) expect.append('') self.__run_parseTask_test('dependantTask', params, expect) def test_chainbuild(self): params = [[ ['base-grp', 'desktop-grp'], ['base-grp', 'devel-grp'], ], 'f26', {'extra': 'f26-pre-release'}] expect = ["Build Groups:"] for i, grp in enumerate(params[0]): expect.append(' %i: %s' % (i + 1, ', '.join(grp))) expect.append("Build Target: %s" % params[1]) expect.append("Options:") expect.append(" extra: f26-pre-release") self.__run_parseTask_test('chainbuild', params, expect) def test_waitrepo(self): params = ['build-taget', True, ['bash-4.4.12-5.fc26']] expect = ["Build Target: %s" % params[0]] expect.append("Newer Than: %s" % params[1]) expect.append("NVRs: %s" % ', '.join(params[2])) self.__run_parseTask_test('waitrepo', params, expect) class TestPrintTaskInfo(utils.CliTestCase): # Show long diffs in error output... maxDiff = None def setUp(self): self.host_info = { "comment": None, "arches": "x86_64", "task_load": 0.0, "capacity": 2.0, "name": "kojibuilder", "ready": True, "user_id": 3, "enabled": True, "id": 1, "description": None } self.task_info_templ = { 'weight': 0.1, 'parent': None, 'create_ts': 1000, 'start_ts': 2000, 'completion_ts': 3000, 'state': 2, 'awaited': None, 'label': None, 'priority': 15, 'channel_id': 2, 'waiting': False, 'id': 1, 'owner': 1, 'host_id': 1, 'arch': 'noarch', 'method': 'newRepo' } self.tag_info = { 'maven_support': False, 'locked': False, 'name': 'fedora26-build', 'extra': {}, 'perm': None, 'id': 2, 'arches': 'x86_64', 'maven_include_all': False, 'perm_id': None } self.user_info = { 'status': 0, 'usertype': 0, 'id': 1, 'name': 'kojiadmin', 'krb_principal': None } @mock.patch('koji_cli.commands.list_task_output_all_volumes') def test_printTaskInfo_create_repo(self, list_task_output_mock): session = mock.MagicMock() parent = self.task_info_templ.copy() parent.update({ 'method': 'newRepo', 'host_id': None, }) children = self.task_info_templ.copy() children.update({ 'id': 2, 'parent': 1, 'request': [1, 'x86_64', None], 'label': 'x86_64', 'channel_id': 2, 'host_id': None, 'method': 'createrepo' }) session.getTaskInfo.side_effect = [parent, children] session.listBuildroots.return_value = {} session.listBuilds.return_value = {} session.getTag.return_value = self.tag_info session.getUser.return_value = self.user_info session.getTaskRequest.return_value = [1, 'x86_64', None] session.getTaskChildren.side_effect = [[children], []] task_output = { 'mergerepos.log': ['DEFAULT'], 'createrepo.log': ['DEFAULT'] } list_task_output_mock.side_effect = [ {}, task_output ] expected = """\ Task: 1 Type: newRepo Request Parameters: Tag: fedora26-build Owner: kojiadmin State: closed Created: Thu Jan 1 00:16:40 1970 Started: Thu Jan 1 00:33:20 1970 Finished: Thu Jan 1 00:50:00 1970 Log Files: No outputs reported [1] Output: No outputs reported [1] [1] Not all tasks produce outputs, and task outputs are not retained indefinitely. Task: 2 Type: createrepo Request Parameters: Repo ID: 1 Arch: x86_64 Owner: kojiadmin State: closed Created: Thu Jan 1 00:16:40 1970 Started: Thu Jan 1 00:33:20 1970 Finished: Thu Jan 1 00:50:00 1970 Log Files: %s %s Output: No outputs reported [1] [1] Not all tasks produce outputs, and task outputs are not retained indefinitely. """ % tuple('/mnt/koji/work/tasks/2/2/' + k for k in task_output.keys()) with mock.patch('sys.stdout', new_callable=six.StringIO) as stdout: with mock.patch('time.localtime', new=time.gmtime): _printTaskInfo(session, 1, '/mnt/koji') self.assert_console_message(stdout, expected) @mock.patch('koji_cli.commands.list_task_output_all_volumes') def test_printTaskInfo_build_srpm(self, list_task_output_mock): session = mock.MagicMock() parent = self.task_info_templ.copy() parent.update({ 'method': 'build', }) child_build = parent.copy() child_build.update({ 'id': 2, 'parent': 1, 'request': ['path/to/bash.src.rpm', 2, 'x86_64', True, {'repo_id': 1}], 'method': 'buildArch', }) child_tag = parent.copy() child_tag.update({ 'id': 3, 'parent': 1, 'request': [1, 1, False, None, True], 'arch': 'noarch', 'method': 'tagBuild' }) buildroot_info = [{ 'id': 1, 'repo_id': 1, 'tag_name': 'fedora26-build', 'host_name': 'kojibuilder', }] build_info = [{ 'package_name': 'bash', 'version': '4.4.12', 'release': '5.fc26', 'epoch': None, 'nvr': 'bash-4.4.12-5.fc26', 'build_id': 1, }] files = { 'bash-debuginfo-4.4.12-5.fc26.x86_64.rpm': ['DEFAULT'], 'hw_info.log': ['DEFAULT'], 'build.log': ['DEFAULT'], 'bash-4.4.12-5.fc26.src.rpm': ['DEFAULT'], 'root.log': ['DEFAULT'], 'state.log': ['DEFAULT'], 'mock_output.log': ['DEFAULT'], 'bash-4.4.12-5.fc26.x86_64.rpm': ['DEFAULT'], 'installed_pkgs.log': ['DEFAULT'], 'bash-doc-4.4.12-5.fc26.x86_64.rpm': ['DEFAULT'] } # need ordered dict to get same results files = collections.OrderedDict(sorted(list(files.items()), key=lambda t: t[0])) list_task_output_mock.side_effect = [[], files, {}] session.getTaskInfo.side_effect = [parent, child_build, child_tag] session.listBuildroots.side_effect = [[], buildroot_info, []] session.listBuilds.side_effect = [build_info, [], []] session.getTag.return_value = self.tag_info session.getUser.return_value = self.user_info session.getBuild.return_value = build_info[0] session.getHost.return_value = self.host_info session.getTaskRequest.side_effect = [ ['path/to/bash-4.4.12-5.fc26.src.rpm', 'fedora26-build', {}], ['path/to/bash-4.4.12-5.fc26.src.rpm', 2, 'x86_64', True, {'repo_id': 1}], [1, 1, False, None, True] ] session.getTaskChildren.side_effect = [[child_build, child_tag], [], []] expected = """\ Task: 1 Type: build Request Parameters: Source: path/to/bash-4.4.12-5.fc26.src.rpm Build Target: fedora26-build Owner: kojiadmin State: closed Created: Thu Jan 1 00:16:40 1970 Started: Thu Jan 1 00:33:20 1970 Finished: Thu Jan 1 00:50:00 1970 Host: kojibuilder Build: bash-4.4.12-5.fc26 (1) Log Files: No outputs reported [1] Output: No outputs reported [1] [1] Not all tasks produce outputs, and task outputs are not retained indefinitely. Task: 2 Type: buildArch Request Parameters: SRPM: /mnt/koji/work/path/to/bash-4.4.12-5.fc26.src.rpm Build Tag: fedora26-build Build Arch: x86_64 SRPM Kept: True Options: repo_id: 1 Owner: kojiadmin State: closed Created: Thu Jan 1 00:16:40 1970 Started: Thu Jan 1 00:33:20 1970 Finished: Thu Jan 1 00:50:00 1970 Host: kojibuilder Buildroots: /var/lib/mock/fedora26-build-1-1/ Log Files: /mnt/koji/work/tasks/2/2/build.log /mnt/koji/work/tasks/2/2/hw_info.log /mnt/koji/work/tasks/2/2/installed_pkgs.log /mnt/koji/work/tasks/2/2/mock_output.log /mnt/koji/work/tasks/2/2/root.log /mnt/koji/work/tasks/2/2/state.log Output: /mnt/koji/work/tasks/2/2/bash-4.4.12-5.fc26.src.rpm /mnt/koji/work/tasks/2/2/bash-4.4.12-5.fc26.x86_64.rpm /mnt/koji/work/tasks/2/2/bash-debuginfo-4.4.12-5.fc26.x86_64.rpm /mnt/koji/work/tasks/2/2/bash-doc-4.4.12-5.fc26.x86_64.rpm Task: 3 Type: tagBuild Request Parameters: Destination Tag: fedora26-build Build: bash-4.4.12-5.fc26 Owner: kojiadmin State: closed Created: Thu Jan 1 00:16:40 1970 Started: Thu Jan 1 00:33:20 1970 Finished: Thu Jan 1 00:50:00 1970 Host: kojibuilder Log Files: No outputs reported [1] Output: No outputs reported [1] [1] Not all tasks produce outputs, and task outputs are not retained indefinitely. """ with mock.patch('sys.stdout', new_callable=six.StringIO) as stdout: with mock.patch('time.localtime', new=time.gmtime): _printTaskInfo(session, 1, '/mnt/koji') self.assert_console_message(stdout, expected) def test_printTaskInfo_no_task(self): """Test _printTaskInfo with no task found""" session = mock.MagicMock() task_id = 1 session.getTaskInfo.return_value = None with self.assertRaises(koji.GenericError) as cm: _printTaskInfo(session, task_id, '/') self.assertEqual(str(cm.exception), "No such task: %d" % task_id) class TestTaskInfo(utils.CliTestCase): # Show long diffs in error output... maxDiff = None def setUp(self): self.error_format = """Usage: %s taskinfo [options] [ ...] (Specify the --help global option for a list of other help options) %s: error: {message} """ % (self.progname, self.progname) @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.commands.activate_session') @mock.patch('koji_cli.commands.ensure_connection') def test_anon_handle_taskinfo( self, ensure_connection_mock, activate_session_mock, stdout): """Test anon_handle_taskinfo function""" session = mock.MagicMock() options = mock.MagicMock() # Case 1. no task id error expected = self.format_error_message( "You must specify at least one task ID") self.assert_system_exit( anon_handle_taskinfo, options, session, [], stderr=expected, activate_session=None) activate_session_mock.assert_not_called() # Case 2. show task info task_output = """Task: 1 Type: newRepo Owner: kojiadmin State: closed Created: Thu Nov 16 17:34:29 2017 Started: Thu Nov 16 17:51:07 2017 Finished: Thu Nov 16 17:54:55 2017 Host: kojibuilder """ def print_task(*args, **kwargs): print(task_output, end='') with mock.patch('koji_cli.commands._printTaskInfo', new=print_task): anon_handle_taskinfo(options, session, ['1']) self.assert_console_message(stdout, task_output) def test_anon_handle_taskinfo_help(self): self.assert_help( anon_handle_taskinfo, """Usage: %s taskinfo [options] [ ...] (Specify the --help global option for a list of other help options) Options: -h, --help show this help message and exit -r, --recurse Show children of this task as well -v, --verbose Be verbose """ % self.progname) if __name__ == '__main__': unittest.main()