debian-koji/tests/test_cli/test_import.py
2024-01-05 10:00:29 +00:00

941 lines
36 KiB
Python

from __future__ import absolute_import
import mock
import os
import six
import unittest
import koji
from koji_cli.commands import handle_import
from . import utils
def md5_to_bytes(s):
if six.PY2:
return bytearray.fromhex(unicode(s))
else:
return bytearray.fromhex(s)
class TestImport(utils.CliTestCase):
def setUp(self):
self.maxDiff = None
self.huburl = "https://%s.local/%shub" % (self.progname, self.progname)
self.md5 = '00112233445566778899aabbccddeeff'
self.fake_srv_dir = '/path/to/server/import'
#
# RPM header example (bash-4.4.12-5.fc26.x86_64.rpm):
# {
# 'sourcepackage': None,
# 'name': 'bash',
# 'sigmd5': 'J\x15\xca\x94\xb1\xacY\xd5\xef\x9f\xc6\xd5\n\xd7?>',
# 'epoch': None,
# 'version': '4.4.12',
# 'release': '5.fc26',
# 'sourcerpm': 'bash-4.4.12-5.fc26.src.rpm',
# 'arch': 'x86_64'
# }
#
# SRPM header example (bash-4.4.12-5.fc26.src.rpm):
# {
# 'sourcepackage': 1,
# 'name': 'bash',
# 'sigmd5': '\x8a\x17\x05\xe8k\xef\x15\x16V[\x02\x9cs\xab\x7f\xdd',
# 'epoch': None,
# 'version': '4.4.12',
# 'release': '5.fc26',
# 'sourcerpm': None,
# 'arch': 'x86_64'
# }
self.srpm_header = {
'sourcepackage': 1,
'name': 'bash',
'sigmd5': md5_to_bytes(self.md5),
'epoch': None,
'version': '4.4.12',
'release': '5.fc26',
'sourcerpm': None,
'arch': 'x86_64'
}
self.rpm_header = {
'sourcepackage': None,
'name': 'bash',
'sigmd5': md5_to_bytes(self.md5),
'epoch': None,
'version': '4.4.12',
'release': '5.fc26',
'sourcerpm': 'bash-4.4.12-5.fc26.src.rpm',
'arch': 'x86_64'
}
# koji.BUILD_STATES
self.bstate = {
'BUILDING': 0,
'COMPLETE': 1,
'DELETED': 2,
'FAILED': 3,
'CANCELED': 4,
}
self.error_format = """Usage: %s import [options] <package> [<package> ...]
(Specify the --help global option for a list of other help options)
%s: error: {message}
""" % (self.progname, self.progname)
def __do_import_test(self, options, session, arguments, **kwargs):
expected = kwargs.get('expected', None)
rpm_header = kwargs.get('rpm_header', {})
rpm_headers = kwargs.get('rpm_headers', [])
if not rpm_headers:
rpm_headers = [rpm_header]
fake_srv_path = kwargs.get('srv_path', '/path/to/server/import')
upload_rpm_mock = kwargs.get('upload_rpm_mock', session.uploadWrapper)
getrpm_called = kwargs.get('getrpm_called', True)
getrpm_calls = kwargs.get('getrpm_calls', [])
import_opts = kwargs.get('import_opts', {})
import_rpm_calls = kwargs.get('import_rpm_calls', None)
with mock.patch('koji.get_header_fields') as get_header_fields_mock:
with mock.patch('koji_cli.commands.unique_path') as unique_path_mock:
with mock.patch('koji_cli.commands.activate_session') as activate_session_mock:
with mock.patch('sys.stdout', new_callable=six.StringIO) as stdout:
with upload_rpm_mock:
get_header_fields_mock.side_effect = rpm_headers
unique_path_mock.return_value = fake_srv_path
handle_import(options, session, arguments)
# check output message
self.assert_console_message(stdout, expected)
# check mock calls
activate_session_mock.assert_called_with(session, options)
get_header_fields_calls = [
mock.call(arguments[i],
('name', 'version', 'release', 'epoch',
'arch', 'sigmd5', 'sourcepackage', 'sourcerpm')
) for i in range(len(rpm_headers) - 1)
]
get_header_fields_mock.assert_has_calls(get_header_fields_calls)
if getrpm_calls:
session.getRPM.assert_has_calls(getrpm_calls)
elif getrpm_called:
session.getRPM.assert_called_with(
dict((k, rpm_header.get(k, ''))
for k in ['release', 'version', 'arch', 'name'])
)
else:
session.getRPM.assert_not_called()
unique_path_mock.assert_called_with('cli-import')
upload_rpm_mock.assert_called_with(arguments[0], self.fake_srv_dir)
if import_rpm_calls:
session.importRPM.assert_has_calls(import_rpm_calls)
else:
session.importRPM.assert_called_with(
self.fake_srv_dir, os.path.basename(arguments[0]), **import_opts)
# reset for next test
activate_session_mock.reset_mock()
get_header_fields_mock.reset_mock()
unique_path_mock.reset_mock()
upload_rpm_mock.reset_mock()
session.getRPM.reset_mock()
session.importRPM.reset_mock()
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('sys.stderr', new_callable=six.StringIO)
@mock.patch('koji_cli.commands.activate_session')
def __skip_import_test(self, options, session, arguments, activate_session_mock,
stderr, stdout, **kwargs):
expected = kwargs.get('expected', None)
expected_warn = kwargs.get('expected_warn', None)
rpm_header = kwargs.get('rpm_header', {})
getrpm_called = kwargs.get('getrpm_called', True)
with mock.patch('koji.get_header_fields') as get_header_fields_mock:
get_header_fields_mock.return_value = rpm_header
handle_import(options, session, arguments)
# check output message
self.assert_console_message(stdout, expected)
self.assert_console_message(stderr, expected_warn)
# check mock calls
activate_session_mock.assert_called_with(session, options)
get_header_fields_mock.assert_called_with(
arguments[0],
('name', 'version', 'release', 'epoch',
'arch', 'sigmd5', 'sourcepackage', 'sourcerpm')
)
if getrpm_called:
session.getRPM.assert_called_with(
dict((k, rpm_header.get(k, ''))
for k in ['release', 'version', 'arch', 'name'])
)
else:
session.getRPM.assert_not_called()
session.uploadWrapper.assert_not_called()
session.importRPM.assert_not_called()
def test_handle_import_src_rpm_import_with_no_exist_build(self):
"""Test handle_import source RPM import.
No build is on the server case,
this tests are focusing on do_import() function coverage.
"""
arguments = ['/path/to/bash-4.4.12-5.fc26.src.rpm', '--src-epoch', 'None']
options = mock.MagicMock()
session = mock.MagicMock()
# No exist build test case
# import general case
session.getBuild.return_value = None
session.getRPM.return_value = None
expected = "uploading %s... done\n" % arguments[0]
expected += "importing %s... done\n" % arguments[0]
self.__do_import_test(
options, session, arguments,
rpm_header=self.srpm_header, expected=expected)
# import error case
session.importRPM.side_effect = koji.GenericError('fake-import-error')
expected = "uploading %s... done\n" % arguments[0]
expected += "importing %s... \n" % arguments[0]
expected += "Error importing: fake-import-error\n"
self.__do_import_test(
options, session, arguments,
rpm_header=self.srpm_header, expected=expected)
# import with --link (hardlink) option
session.importRPM.side_effect = None
expected = "importing %s... done\n" % arguments[0]
self.__do_import_test(
options, session, arguments + ['--link'],
upload_rpm_mock=mock.patch('koji_cli.commands.linked_upload').start(),
rpm_header=self.srpm_header, expected=expected)
session.uploadWrapper.assert_not_called()
def test_handle_import_src_rpm_import_with_exist_build(self):
"""Test handle_import source RPM import with exist build case."""
arguments = ['/path/to/bash-4.4.12-5.fc26.src.rpm']
options = mock.MagicMock()
session = mock.MagicMock()
false_md5 = 'ffeeddccbbaa99887766554433221100'
#
# getBuild return example (bash-4.4.12-5.fc26.src.rpm)
# {
# 'package_name': 'bash',
# 'extra': None,
# 'creation_time': '2017-11-08 18:56:31.359440',
# 'completion_time': '2017-11-08 18:56:31.359440',
# 'package_id': 1,
# 'id': 1,
# 'build_id': 1,
# 'state': 1,
# 'source': None,
# 'epoch': None,
# 'version': '4.4.12',
# 'completion_ts': 1510167391.35944,
# 'owner_id': 1,
# 'owner_name': 'kojiadmin',
# 'nvr': 'bash-4.4.12-5.fc26',
# 'start_time': '2017-11-08 18:56:31.359440',
# 'creation_event_id': 81,
# 'start_ts': 1510167391.35944,
# 'volume_id': 0,
# 'creation_ts': 1510167391.35944,
# 'name': 'bash',
# 'task_id': None,
# 'volume_name': 'DEFAULT',
# 'release': '5.fc26'
# }
#
#
# getRPM return example:
# {
# 'build_id': 1,
# 'name': 'bash',
# 'extra': None,
# 'external_repo_id': 0,
# 'buildtime': 1496119944,
# 'id': 1,
# 'epoch': None,
# 'version': '4.4.12',
# 'buildroot_id': None,
# 'metadata_only': False,
# 'release': '5.fc26',
# 'arch': 'src',
# 'payloadhash': '8a1705e86bef1516565b029c73ab7fdd',
# 'external_repo_name': 'INTERNAL',
# 'size': 9462614
# }
#
# Case 1: build exists and status is 'COMPLETE', md5 matched
# reseult: import skipped
session.getBuild.return_value = {'state': self.bstate['COMPLETE']}
session.getRPM.return_value = {
'external_repo_id': 0,
'external_repo_name': 'INTERNAL',
'payloadhash': self.md5
}
expected = "RPM already imported: %s\n" % arguments[0]
expected += "Skipping import\n"
self.__skip_import_test(
options, session, arguments,
rpm_header=self.srpm_header,
expected=expected)
# Case 2: build exists and status is 'COMPLETE', md5 mismatched
# reseult: import skipped
session.getRPM.return_value['payloadhash'] = false_md5
expected_warn = "md5sum mismatch for %s\n" % arguments[0]
expected_warn += " A different rpm with the same name has already been imported\n"
expected_warn += " Existing sigmd5 is %r, your import has %r\n" % (false_md5, self.md5)
expected = "Skipping import\n"
self.__skip_import_test(
options, session, arguments,
rpm_header=self.srpm_header,
expected=expected, expected_warn=expected_warn)
# Case 3: build exists and status is 'COMPLETE', has external_repo_id
# reseult: import will be performed
session.getRPM.return_value['external_repo_id'] = 1
expected = "uploading %s... done\n" % arguments[0]
expected += "importing %s... done\n" % arguments[0]
self.__do_import_test(
options, session, arguments,
rpm_header=self.srpm_header,
expected=expected)
nvr = '%(name)s-%(version)s-%(release)s' % self.srpm_header
# Case 4: build exists and the status is FAILED or CANCELED
# without --create-build option.
# result: import skipped
session.getBuild.return_value = {
'name': 'bash',
'version': '4.4.12',
'release': '5.fc26',
'state': self.bstate['FAILED']}
session.getRPM.return_value = {
'external_repo_name': 'INTERNAL',
'payloadhash': self.md5
}
expected = "Build %s state is %s. Skipping import\n" % (nvr, 'FAILED')
with mock.patch('koji.get_header_fields') as get_header_fields_mock:
with mock.patch('koji_cli.commands.activate_session') as activate_session_mock:
with mock.patch('sys.stdout', new_callable=six.StringIO) as stdout:
get_header_fields_mock.return_value = self.srpm_header
handle_import(options, session, arguments)
activate_session_mock.assert_called_with(session, options)
self.assert_console_message(stdout, expected)
# Case 5: build exists and the status is FAILED or CANCELED
# with --create-build option.
# result: empty build will be created,
# import will be performed.
expected = "Creating empty build: %s\n" % nvr
expected += "uploading %s... done\n" % arguments[0]
expected += "importing %s... done\n" % arguments[0]
session.getBuild.side_effect = [
# simulate build fail case
{'name': 'bash',
'version': '4.4.12',
'release': '5.fc26',
'state': self.bstate['FAILED']},
# after calling createEmptyBuild, getBuild should return:
{'name': 'bash',
'version': '4.4.12',
'release': '5.fc26',
'state': self.bstate['COMPLETE']},
]
# no RPM info is returned
session.getRPM.return_value = {}
self.__do_import_test(
options, session, arguments + ['--create-build'],
rpm_header=self.srpm_header,
expected=expected)
kwarg = dict((k, self.rpm_header.get(k, None))
for k in ['name', 'version', 'release', 'epoch'])
session.createEmptyBuild.assert_called_with(**kwarg)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('sys.stderr', new_callable=six.StringIO)
@mock.patch('koji.get_header_fields')
@mock.patch('koji_cli.commands.activate_session')
def test_handle_import_binary_rpm_import_with_no_build_exist(
self,
activate_session_mock,
get_header_fields_mock,
stderr,
stdout):
"""Test handle_import binary RPM import with no exist build case."""
arguments = ['/path/to/bash-4.4.12-5.fc26.rpm']
options = mock.MagicMock()
session = mock.MagicMock()
get_header_fields_mock.return_value = self.rpm_header
nvr = '%(name)s-%(version)s-%(release)s' % get_header_fields_mock.return_value
# Case 1. without exist build on server
# result: abort
session.getBuild.return_value = None
handle_import(options, session, arguments)
expected = "Missing build or srpm: %s\n" % nvr
expected += "Aborting import\n"
self.assert_console_message(stdout, expected)
# Case 2. without exist build on server,
# with --create-build option
# result: import will be performed
session.getBuild.return_value = None
session.getRPM.return_value = None
expected = "Missing build or srpm: %s\n" % nvr
expected += "Creating empty build: %s\n" % nvr
expected += "uploading %s... done\n" % arguments[0]
expected += "importing %s... done\n" % arguments[0]
self.__do_import_test(
options, session, arguments + ['--create-build'],
rpm_header=self.rpm_header,
expected=expected)
kwarg = dict((k, self.rpm_header.get(k, None))
for k in ['name', 'version', 'release', 'epoch'])
session.createEmptyBuild.assert_called_with(**kwarg)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('sys.stderr', new_callable=six.StringIO)
@mock.patch('koji_cli.commands.activate_session')
def test_handle_import_binary_rpm_with_exist_build(
self,
activate_session_mock,
stderr,
stdout):
"""Test handle_import binary RPM import with exist build case."""
arguments = ['/path/to/bash-4.4.12-5.fc26.rpm']
options = mock.MagicMock()
session = mock.MagicMock()
nvr = '%(name)s-%(version)s-%(release)s' % self.rpm_header
# Case 1. have exist build on server, build status is COMPLETE case.
# result: skip import
session.getBuild.return_value = {'state': self.bstate['COMPLETE']}
session.getRPM.return_value = {
'external_repo_name': 'INTERNAL',
'payloadhash': self.md5,
}
expected = "RPM already imported: %s\n" % arguments[0]
expected += "Skipping import\n"
self.__skip_import_test(
options, session, arguments,
rpm_header=self.rpm_header,
expected=expected)
# Case 2. have exist build on server, build status is failed,
# without --create-build case.
# result: import will be skipped
session.getBuild.return_value = {'state': self.bstate['FAILED']}
expected = "Build %s state is %s. Skipping import\n" % (nvr, 'FAILED')
self.__skip_import_test(
options, session, arguments,
rpm_header=self.rpm_header,
expected=expected)
# Case 3. have exist build on server, build status is failed,
# with --create-build,
# result:
# empty build will be created,
# import will be performed.
expected = "Creating empty build: %s\n" % nvr
expected += "uploading %s... done\n" % arguments[0]
expected += "importing %s... done\n" % arguments[0]
session.getBuild.side_effect = [
# binary rpm case,
# getBuild is called to check build.
{'state': self.bstate['FAILED']},
# simulate build fail case
{'name': 'bash',
'version': '4.4.12',
'release': '5.fc26',
'state': self.bstate['FAILED']},
# after calling createEmptyBuild, getBuild should return:
{'name': 'bash',
'version': '4.4.12',
'release': '5.fc26',
'state': self.bstate['COMPLETE']},
]
# no RPM info is returned
session.getRPM.return_value = {}
self.__do_import_test(
options, session, arguments + ['--create-build'],
rpm_header=self.rpm_header,
expected=expected)
kwarg = dict((k, self.rpm_header.get(k, None))
for k in ['name', 'version', 'release', 'epoch'])
session.createEmptyBuild.assert_called_with(**kwarg)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji.get_header_fields')
@mock.patch('koji_cli.commands.unique_path')
@mock.patch('koji_cli.commands.activate_session')
def test_handle_import_with_test_option(
self,
activate_session_mock,
unique_path_mock,
get_header_fields_mock,
stdout):
"""Test handle_import RPM with --test option"""
options = mock.MagicMock()
session = mock.MagicMock()
nvr = lambda: '%(name)s-%(version)s-%(release)s' % get_header_fields_mock.return_value
# Case 1. SRPM case
# result: skip because of --test
get_header_fields_mock.return_value = self.srpm_header
session.getBuild.return_value = {}
session.getRPM.return_value = {}
arguments = ['/path/to/bash-4.4.12-5.fc26.src.rpm', '--test']
expected = "Test mode -- skipping import for %s\n" % arguments[0]
handle_import(options, session, arguments)
self.assert_console_message(stdout, expected)
unique_path_mock.assert_not_called()
session.importRPM.assert_not_called()
# Case 2. Binary RPM case (need --create-build option)
# result: skip because of --test
session.getBuild.side_effect = [
# binary rpm case,
# getBuild is called to check build.
{'state': self.bstate['FAILED']},
# simulate build fail case
{'name': 'bash',
'version': '4.4.12',
'release': '5.fc26',
'state': self.bstate['FAILED']},
]
get_header_fields_mock.return_value = self.rpm_header
arguments = ['/path/to/bash-4.4.12-5.fc26.rpm', '--test', '--create-build']
expected = "Test mode -- would have created empty build: %s\n" % nvr()
expected += "Test mode -- skipping import for %s\n" % arguments[0]
with mock.patch('koji_cli.commands.unique_path') as unique_path_mock:
handle_import(options, session, arguments)
self.assert_console_message(stdout, expected)
unique_path_mock.assert_not_called()
session.createEmptyBuild.assert_not_called()
session.importRPM.assert_not_called()
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji.get_header_fields')
@mock.patch('koji_cli.commands.unique_path')
@mock.patch('koji_cli.commands.activate_session')
def test_handle_import_with_epoch_option(
self,
activate_session_mock,
unique_path_mock,
get_header_fields_mock,
stdout):
"""Test handle_import RPM with --src-epoch option"""
options = mock.MagicMock()
session = mock.MagicMock()
epoch = "1"
nvr = '%(name)s-%(version)s-%(release)s' % self.rpm_header
# Binary RPM case (need --create-build option)
# result: skip because of --test
arguments = ['/path/to/bash-4.4.12-5.fc26.rpm',
'--create-build',
'--src-epoch', epoch]
expected = "Creating empty build: %s\n" % nvr
expected += "uploading %s... done\n" % arguments[0]
expected += "importing %s... done\n" % arguments[0]
session.getBuild.side_effect = [
# binary rpm case,
# getBuild is called to check build.
{'state': self.bstate['FAILED']},
# simulate build fail case
{'name': 'bash',
'version': '4.4.12',
'release': '5.fc26',
'state': self.bstate['FAILED']},
# after calling createEmptyBuild, getBuild should return:
{'name': 'bash',
'version': '4.4.12',
'release': '5.fc26',
'state': self.bstate['COMPLETE']},
]
# no RPM info is returned
session.getRPM.return_value = {}
self.__do_import_test(
options, session, arguments + ['--create-build'],
rpm_header=self.rpm_header,
expected=expected)
kwarg = dict((k, self.rpm_header.get(k, None))
for k in ['name', 'version', 'release', 'epoch'])
kwarg['epoch'] = int(epoch)
session.createEmptyBuild.assert_called_with(**kwarg)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('sys.stderr', new_callable=six.StringIO)
@mock.patch('koji.get_header_fields')
@mock.patch('koji_cli.commands.activate_session')
def test_handle_import_has_build_states_test(
self,
activate_session_mock,
get_header_fields_mock,
stderr,
stdout):
"""Test handle_import RPM with existing build but status not COMPLETE case"""
arguments = ['/path/to/bash-4.4.12-5.fc26.src.rpm']
options = mock.MagicMock()
session = mock.MagicMock()
get_header_fields_mock.return_value = self.srpm_header
test_cases = [
{
'state': 'FAILED',
'msg': "Build %s state is %s. Skipping import"
},
{
'state': 'CANCELED',
'msg': "Build %s state is %s. Skipping import"
},
{
'state': 'DELETED',
'msg': 'Build %s exists with state=%s. Skipping import'
},
{
'state': 'BUILDING',
'msg': 'Build %s exists with state=%s. Skipping import'
}
]
nvr = '%(name)s-%(version)s-%(release)s' % \
get_header_fields_mock.return_value
# build failed cases
for case in test_cases:
session.getBuild.return_value = {
'state': self.bstate[case['state']]}
handle_import(options, session, arguments)
expected = case['msg'] % (nvr, case['state']) + "\n"
self.assert_console_message(stdout, expected)
get_header_fields_mock.assert_called_with(
arguments[0],
('name', 'version', 'release', 'epoch',
'arch', 'sigmd5', 'sourcepackage', 'sourcerpm')
)
activate_session_mock.assert_called_with(session, options)
session.getRPM.assert_not_called()
session.importRPM.assert_not_called()
@mock.patch('sys.stderr', new_callable=six.StringIO)
@mock.patch('koji_cli.commands.activate_session')
def test_handle_import_argument_error(
self,
activate_session_mock,
stderr):
"""Test handle_import function with error arguments"""
options = mock.MagicMock()
session = mock.MagicMock()
epoch = 'zzz'
test_cases = [
# empty argument error
{
'arguments': [],
'error': "At least one package must be specified"
},
# invalid epoch number test (epoch must be integer)
{
'arguments': ['pkg', '--src-epoch', epoch],
'error': "Invalid value for epoch: %s" % epoch
}
]
for case in test_cases:
expect = self.format_error_message(case['error'])
self.assert_system_exit(
handle_import,
options,
session,
case['arguments'],
stderr=expect,
activate_session=None)
activate_session_mock.assert_not_called()
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('sys.stderr', new_callable=six.StringIO)
@mock.patch('koji_cli.commands.activate_session')
def test_handle_import_src_rpm_with_create_draft(
self,
activate_session_mock,
stderr,
stdout):
"""Test handle_import SRPM import with creating draft build case."""
arguments = ['/path/to/bash-4.4.12-5.fc26.rpm', '--create-draft']
options = mock.MagicMock()
session = mock.MagicMock()
session.importRPM.return_value = {'build': {'nvr': 'a-draft-build', 'draft': True}}
nvr = '%(name)s-%(version)s-%(release)s' % self.srpm_header
# Case 1. import src rpm with --create-draft
# result: success
expected = "Will create draft build instead if desired nvr doesn't exist\n"
expected += "Will create draft build with target nvr: %s while importing\n" % nvr
expected += "uploading %s... done\n" % arguments[0]
expected += "importing %s... done\n" % arguments[0]
expected += "Draft build: a-draft-build created\n"
self.__do_import_test(
options, session, arguments,
rpm_header=self.srpm_header,
expected=expected,
getrpm_called=False,
import_opts={'draft': True})
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('sys.stderr', new_callable=six.StringIO)
@mock.patch('koji_cli.commands.activate_session')
def test_handle_import_binary_rpm_with_create_draft(
self,
activate_session_mock,
stderr,
stdout):
"""Test handle_import binary RPM import with creating draft build case."""
arguments = ['/path/to/bash-4.4.12-5.fc26.rpm', '--create-draft']
options = mock.MagicMock()
session = mock.MagicMock()
nvr = '%(name)s-%(version)s-%(release)s' % self.rpm_header
# Case 1. import bin rpm with --create-draft
# result: Aborting import
expected = "Will create draft build instead if desired nvr doesn't exist\n"
expected += "Missing srpm for draft build creating with target nvr: %s\n" % nvr
expected += "Aborting import\n"
self.__skip_import_test(
options, session, arguments,
rpm_header=self.rpm_header,
expected=expected,
getrpm_called=False)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('sys.stderr', new_callable=six.StringIO)
@mock.patch('koji_cli.commands.activate_session')
def test_handle_import_src_bin_rpm_with_create_draft(
self,
activate_session_mock,
stderr,
stdout):
"""Test handle_import SRPM & RPM import with creating draft build case."""
arguments = ['/path/to/bash-4.4.12-5.fc26.rpm', '/path/to/bash-4.4.12-5.fc26.src.rpm',
'--create-draft']
options = mock.MagicMock()
session = mock.MagicMock()
session.getRPM.return_value = None
session.importRPM.return_value = {'build': {'nvr': 'a-draft-build', 'draft': True}}
nvr = '%(name)s-%(version)s-%(release)s' % self.srpm_header
# Case 1. import src & bin rpm with --create-draft
# result: success
expected = "Will create draft build instead if desired nvr doesn't exist\n"
expected += "Will create draft build with target nvr: %s while importing\n" % nvr
expected += "uploading %s... done\n" % arguments[1]
expected += "importing %s... done\n" % arguments[1]
expected += "Draft build: a-draft-build created\n"
expected += "uploading %s... done\n" % arguments[0]
expected += "importing %s... done\n" % arguments[0]
self.__do_import_test(
options, session, arguments,
rpm_headers=[self.rpm_header, self.srpm_header],
expected=expected,
getrpm_calls=[
mock.call(
{'name': 'bash', 'version': '4.4.12', 'release': '5.fc26', 'arch': 'x86_64'},
build=session.importRPM.return_value['build']
)
],
import_rpm_calls=[
mock.call(
self.fake_srv_dir, os.path.basename(arguments[1]), draft=True
),
mock.call(
self.fake_srv_dir, os.path.basename(arguments[0]),
build=session.importRPM.return_value['build'], draft=True
)
])
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('sys.stderr', new_callable=six.StringIO)
@mock.patch('koji_cli.commands.activate_session')
def test_handle_import_src_rpm_with_specified_draft_build(
self,
activate_session_mock,
stderr,
stdout):
"""Test handle_import SRPM import with --draft-build case."""
arguments = ['/path/to/bash-4.4.12-5.fc26.rpm', '--draft-build', 'a-draft-build']
options = mock.MagicMock()
session = mock.MagicMock()
build = {
'name': 'bash',
'version': '4.4.12',
'release': '5.fc26#draft_123',
'nvr': 'bash-4.4.12-5.fc26',
'draft': True,
'extra': {
'draft': {
'target_release': '5.fc26'
}
},
'state': self.bstate['COMPLETE']
}
session.getBuild.return_value = build
# Case 1. import src rpm with --draft-build
# result: success
expected = "uploading %s... done\n" % arguments[0]
expected += "importing %s... done\n" % arguments[0]
self.__do_import_test(
options, session, arguments,
rpm_header=self.srpm_header,
expected=expected,
getrpm_calls=[mock.call(
{'name': 'bash', 'version': '4.4.12', 'release': '5.fc26', 'arch': 'src'},
build=build)],
import_opts={'build': build, 'draft': True})
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('sys.stderr', new_callable=six.StringIO)
@mock.patch('koji_cli.commands.activate_session')
def test_handle_import_binary_rpm_with_specified_draft_build(
self,
activate_session_mock,
stderr,
stdout):
"""Test handle_import RPM import with --draft-build case."""
arguments = ['/path/to/bash-4.4.12-5.fc26.rpm', '--draft-build', 'a-draft-build']
options = mock.MagicMock()
session = mock.MagicMock()
session.getRPM.return_value = None
build = {
'name': 'bash',
'version': '4.4.12',
'release': '5.fc26#draft_123',
'nvr': 'bash-4.4.12-5.fc26',
'draft': True,
'extra': {
'draft': {
'target_release': '5.fc26'
}
},
'state': self.bstate['COMPLETE']
}
session.getBuild.return_value = build
# Case 1. import bin rpm with --draft-build
# result: success
expected = "uploading %s... done\n" % arguments[0]
expected += "importing %s... done\n" % arguments[0]
self.__do_import_test(
options, session, arguments,
rpm_header=self.rpm_header,
expected=expected,
getrpm_calls=[mock.call(
{'name': 'bash', 'version': '4.4.12', 'release': '5.fc26', 'arch': 'x86_64'},
build=build)],
import_opts={'build': build, 'draft': True})
def test_handle_import_specified_draft_build_invalid(self):
"""Test handle_import RPM import with --draft-build case."""
arguments = ['/path/to/bash-4.4.12-5.fc26.rpm', '--draft-build', '286']
options = mock.MagicMock()
session = mock.MagicMock()
cases = [
# build, stderr
(None, "No such build: 286"),
({'draft': False, 'nvr': 'a-bad-draft'}, "a-bad-draft is not a draft build"),
({'draft': True, 'nvr': 'a-bad-draft', 'state': koji.BUILD_STATES['DELETED']},
"draft build a-bad-draft is expected as COMPLETE, got DELETED"),
({'draft': True, 'nvr': 'a-bad-draft', 'state': koji.BUILD_STATES['COMPLETE'],
'extra': {'draft': {'no_target_release': 'omg'}}},
"Invalid draft build: a-bad-draft, no draft.target_release found in extra")
]
for build, expected in cases:
session.getBuild.return_value = build
# result: error
expected += "\n"
self.assert_system_exit(
handle_import,
options,
session,
arguments,
stderr=expected,
activate_session=None,
exit_code=1)
options.reset_mock()
session.reset_mock()
def test_handle_import_help(self):
"""Test handle_import function help message"""
self.assert_help(
handle_import,
"""Usage: %s import [options] <package> [<package> ...]
(Specify the --help global option for a list of other help options)
Options:
-h, --help show this help message and exit
--link Attempt to hardlink instead of uploading
--test Don't actually import
--create-build Auto-create builds as needed
--src-epoch=SRC_EPOCH
When auto-creating builds, use this epoch
--create-draft Auto-create draft builds instead as needed
--draft-build=NVR|ID The target draft build to import to
""" % self.progname)
if __name__ == '__main__':
unittest.main()