move lib tests into subdir
This commit is contained in:
parent
efa92224ad
commit
c4a48efd83
24 changed files with 1 additions and 1 deletions
0
tests/test_lib/data/maven/bad_empty_config.ini
Normal file
0
tests/test_lib/data/maven/bad_empty_config.ini
Normal file
16
tests/test_lib/data/maven/bad_scmurl_config.ini
Normal file
16
tests/test_lib/data/maven/bad_scmurl_config.ini
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
[pkg]
|
||||
type=maven
|
||||
patches=patchurl
|
||||
specfile=specfile
|
||||
goals=goal1 goal2
|
||||
profiles=profile1 profile2
|
||||
packages=pkg1 pkg2
|
||||
jvm_options=--opt1 --opt2=val
|
||||
maven_options=--opt1 --opt2=val
|
||||
properties: p1=1
|
||||
p2
|
||||
p3=ppp3
|
||||
envs:e1=1
|
||||
e2=2
|
||||
buildrequires=r1 r2
|
||||
otheropts=others
|
||||
17
tests/test_lib/data/maven/bad_type_config.ini
Normal file
17
tests/test_lib/data/maven/bad_type_config.ini
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
[pkg]
|
||||
type=other
|
||||
scmurl=scmurl
|
||||
patches=patchurl
|
||||
specfile=specfile
|
||||
goals=goal1 goal2
|
||||
profiles=profile1 profile2
|
||||
packages=pkg1 pkg2
|
||||
jvm_options=--opt1 --opt2=val
|
||||
maven_options=--opt1 --opt2=val
|
||||
properties: p1=1
|
||||
p2
|
||||
p3=ppp3
|
||||
envs:e1=1
|
||||
e2=2
|
||||
buildrequires=r1 r2
|
||||
otheropts=others
|
||||
17
tests/test_lib/data/maven/bad_wrapper_config.ini
Normal file
17
tests/test_lib/data/maven/bad_wrapper_config.ini
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
[pkg]
|
||||
type=wrapper
|
||||
scmurl=scmurl
|
||||
patches=patchurl
|
||||
specfile=specfile
|
||||
goals=goal1 goal2
|
||||
profiles=profile1 profile2
|
||||
packages=pkg1 pkg2
|
||||
jvm_options=--opt1 --opt2=val
|
||||
maven_options=--opt1 --opt2=val
|
||||
properties: p1=1
|
||||
p2
|
||||
p3=ppp3
|
||||
envs:e1=1
|
||||
e2=2
|
||||
buildrequires=r1 r2
|
||||
otheropts=others
|
||||
52
tests/test_lib/data/maven/config.ini
Normal file
52
tests/test_lib/data/maven/config.ini
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
[pkg1]
|
||||
scmurl=scmurl
|
||||
patches=patchurl
|
||||
specfile=specfile
|
||||
goals=goal1 goal2
|
||||
profiles=profile1 profile2
|
||||
packages=pkg1 pkg2
|
||||
jvm_options=--opt1 --opt2=val
|
||||
maven_options=--opt1 --opt2=val
|
||||
properties: p1=1
|
||||
p2
|
||||
p3=ppp3
|
||||
envs:e1=1
|
||||
e2=2
|
||||
buildrequires=r1 r2
|
||||
otheropts=others
|
||||
|
||||
[pkg2]
|
||||
type=maven
|
||||
scmurl=scmurl
|
||||
patches=patchurl
|
||||
specfile=specfile
|
||||
goals=goal1 goal2
|
||||
profiles=profile1 profile2
|
||||
packages=pkg1 pkg2
|
||||
jvm_options=--opt1 --opt2=val
|
||||
maven_options=--opt1 --opt2=val
|
||||
properties: p1=1
|
||||
p2
|
||||
p3=ppp3
|
||||
envs:e1=1
|
||||
e2=2
|
||||
buildrequires=r1 r2
|
||||
otheropts=others
|
||||
|
||||
[pkg3]
|
||||
type=wrapper
|
||||
scmurl=scmurl
|
||||
patches=patchurl
|
||||
specfile=specfile
|
||||
goals=goal1 goal2
|
||||
profiles=profile1 profile2
|
||||
packages=pkg1 pkg2
|
||||
jvm_options=--opt1 --opt2=val
|
||||
maven_options=--opt1 --opt2=val
|
||||
properties: p1=1
|
||||
p2
|
||||
p3=ppp3
|
||||
envs:e1=1
|
||||
e2=2
|
||||
buildrequires=r1
|
||||
otheropts=others
|
||||
16
tests/test_lib/data/maven/good_config.ini
Normal file
16
tests/test_lib/data/maven/good_config.ini
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
[pkg4]
|
||||
scmurl=scmurl
|
||||
patches=patchurl
|
||||
specfile=specfile
|
||||
goals=goal1 goal2
|
||||
profiles=profile1 profile2
|
||||
packages=pkg1 pkg2
|
||||
jvm_options=--opt1 --opt2=val
|
||||
maven_options=--opt1 --opt2=val
|
||||
properties: p1=1
|
||||
p2
|
||||
p3=ppp3
|
||||
envs:e1=1
|
||||
e2=2
|
||||
buildrequires=r1 r2
|
||||
otheropts=others
|
||||
BIN
tests/test_lib/data/rpms/test-deps-1-1.fc24.x86_64.rpm
Normal file
BIN
tests/test_lib/data/rpms/test-deps-1-1.fc24.x86_64.rpm
Normal file
Binary file not shown.
BIN
tests/test_lib/data/rpms/test-nopatch-1-1.fc24.nosrc.rpm
Normal file
BIN
tests/test_lib/data/rpms/test-nopatch-1-1.fc24.nosrc.rpm
Normal file
Binary file not shown.
BIN
tests/test_lib/data/rpms/test-nosrc-1-1.fc24.nosrc.rpm
Normal file
BIN
tests/test_lib/data/rpms/test-nosrc-1-1.fc24.nosrc.rpm
Normal file
Binary file not shown.
BIN
tests/test_lib/data/rpms/test-src-1-1.fc24.src.rpm
Normal file
BIN
tests/test_lib/data/rpms/test-src-1-1.fc24.src.rpm
Normal file
Binary file not shown.
28
tests/test_lib/data/specs/test-deps._spec
Normal file
28
tests/test_lib/data/specs/test-deps._spec
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
Name: test-deps
|
||||
Version: 1
|
||||
Release: 1%{?dist}
|
||||
Summary: Testing dependency header fields
|
||||
|
||||
License: none
|
||||
|
||||
Requires: require1
|
||||
Requires: require2
|
||||
Provides: provide1
|
||||
Provides: provide2
|
||||
Obsoletes: obsoletes1
|
||||
Obsoletes: obsoletes2
|
||||
Conflicts: conflicts1
|
||||
Conflicts: conflicts2
|
||||
Suggests: suggests1
|
||||
Suggests: suggests2
|
||||
Enhances: enhances1
|
||||
Enhances: enhances2
|
||||
Supplements: supplements1
|
||||
Supplements: supplements2
|
||||
Recommends: recommends1
|
||||
Recommends: recommends2
|
||||
|
||||
%description
|
||||
Testing dependency header fields
|
||||
|
||||
%files
|
||||
13
tests/test_lib/data/specs/test-nopatch._spec
Normal file
13
tests/test_lib/data/specs/test-nopatch._spec
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
Name: test-nopatch
|
||||
Version: 1
|
||||
Release: 1%{?dist}
|
||||
Summary: Testing source arch header fields
|
||||
|
||||
License: none
|
||||
Patch0: secret.patch
|
||||
Nopatch: 0
|
||||
|
||||
%description
|
||||
...
|
||||
|
||||
%files
|
||||
13
tests/test_lib/data/specs/test-nosrc._spec
Normal file
13
tests/test_lib/data/specs/test-nosrc._spec
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
Name: test-nosrc
|
||||
Version: 1
|
||||
Release: 1%{?dist}
|
||||
Summary: Testing source arch header fields
|
||||
|
||||
License: none
|
||||
Source0: secret.key
|
||||
Nosource: 0
|
||||
|
||||
%description
|
||||
...
|
||||
|
||||
%files
|
||||
11
tests/test_lib/data/specs/test-src._spec
Normal file
11
tests/test_lib/data/specs/test-src._spec
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
Name: test-src
|
||||
Version: 1
|
||||
Release: 1%{?dist}
|
||||
Summary: Testing source arch header fields
|
||||
|
||||
License: none
|
||||
|
||||
%description
|
||||
...
|
||||
|
||||
%files
|
||||
182
tests/test_lib/test_client_session.py
Normal file
182
tests/test_lib/test_client_session.py
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
from __future__ import absolute_import
|
||||
import mock
|
||||
import unittest
|
||||
import six
|
||||
|
||||
import koji
|
||||
|
||||
|
||||
class TestClientSession(unittest.TestCase):
|
||||
|
||||
@mock.patch('socket.getfqdn')
|
||||
def test_server_principal_rdns(self, getfqdn):
|
||||
opts = {'krb_rdns': True}
|
||||
session = koji.ClientSession('http://koji.example.com:30/kojihub', opts)
|
||||
cprinc = mock.MagicMock()
|
||||
cprinc.realm = "REALM"
|
||||
getfqdn.return_value = 'koji02.example.com'
|
||||
|
||||
princ = session._serverPrincipal(cprinc)
|
||||
self.assertEqual(princ, 'host/koji02.example.com@REALM')
|
||||
getfqdn.assert_called_with('koji.example.com')
|
||||
|
||||
@mock.patch('socket.getfqdn')
|
||||
def test_server_principal_no_rdns(self, getfqdn):
|
||||
opts = {'krb_rdns': False}
|
||||
session = koji.ClientSession('http://koji.example.com/kojihub', opts)
|
||||
cprinc = mock.MagicMock()
|
||||
cprinc.realm = "REALM"
|
||||
getfqdn.return_value = 'koji02.example.com'
|
||||
|
||||
princ = session._serverPrincipal(cprinc)
|
||||
self.assertEqual(princ, 'host/koji.example.com@REALM')
|
||||
getfqdn.assert_not_called()
|
||||
|
||||
@mock.patch('requests.Session')
|
||||
def test_new_session(self, rsession):
|
||||
opts = {'use_old_ssl': False}
|
||||
ksession = koji.ClientSession('http://koji.example.com/kojihub', opts)
|
||||
|
||||
# init should have called new_session for us
|
||||
|
||||
rsession.assert_called_once()
|
||||
|
||||
@mock.patch('requests.Session')
|
||||
def test_new_session_old(self, rsession):
|
||||
if six.PY3:
|
||||
return
|
||||
opts = {'use_old_ssl': True}
|
||||
ksession = koji.ClientSession('http://koji.example.com/kojihub', opts)
|
||||
|
||||
# init should have called new_session for us
|
||||
|
||||
rsession.assert_not_called()
|
||||
|
||||
@mock.patch('requests.Session')
|
||||
def test_new_session_close(self, rsession):
|
||||
if six.PY3:
|
||||
return
|
||||
opts = {'use_old_ssl': True}
|
||||
ksession = koji.ClientSession('http://koji.example.com/kojihub', opts)
|
||||
my_rsession = mock.MagicMock()
|
||||
ksession.rsession = my_rsession
|
||||
|
||||
ksession.new_session()
|
||||
my_rsession.close.assert_called()
|
||||
self.assertNotEqual(ksession.rsession, my_rsession)
|
||||
|
||||
|
||||
class TestFastUpload(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.ksession = koji.ClientSession('http://koji.example.com/kojihub', {})
|
||||
self.do_fake_login()
|
||||
# mocks
|
||||
self.ksession._callMethod = mock.MagicMock()
|
||||
self.ksession.retries = 1
|
||||
self.rsession = mock.patch('requests.Session').start()
|
||||
if six.PY2:
|
||||
self.file_mock = mock.patch('__builtin__.open').start()
|
||||
else:
|
||||
self.file_mock = mock.patch('builtins.open').start()
|
||||
self.getsize_mock = mock.patch('os.path.getsize').start()
|
||||
|
||||
def tearDown(self):
|
||||
del self.ksession
|
||||
mock.patch.stopall()
|
||||
|
||||
def do_fake_login(self):
|
||||
self.ksession.logged_in = True
|
||||
self.ksession.sinfo = {}
|
||||
self.ksession.callnum = 1
|
||||
|
||||
def test_fastUpload_nologin(self):
|
||||
# without login (ActionNotAllowed)
|
||||
self.ksession.logged_in = False
|
||||
with self.assertRaises(koji.ActionNotAllowed):
|
||||
self.ksession.fastUpload('nonexistent_file', 'target')
|
||||
|
||||
def test_fastUpload_nofile(self):
|
||||
|
||||
# fail with nonexistent file (IOError)
|
||||
self.file_mock.side_effect = IOError('mocked exception')
|
||||
with self.assertRaises(IOError):
|
||||
self.ksession.fastUpload('file', 'target')
|
||||
|
||||
def test_fastUpload_empty_file(self):
|
||||
# upload empty file (success)
|
||||
fileobj = mock.MagicMock()
|
||||
fileobj.read.return_value = ''
|
||||
self.file_mock.return_value = fileobj
|
||||
self.ksession._callMethod.return_value = {
|
||||
'size': 0,
|
||||
'hexdigest': koji.util.adler32_constructor().hexdigest()
|
||||
}
|
||||
self.ksession.fastUpload('file', 'target')
|
||||
|
||||
def test_fastUpload_regular_file(self):
|
||||
# upload regular file (success)
|
||||
fileobj = mock.MagicMock()
|
||||
fileobj.read.side_effect = ['123123', '']
|
||||
self.file_mock.return_value = fileobj
|
||||
self.ksession._callMethod.side_effect = [
|
||||
{'size': 6, 'hexdigest': '041c012d'}, # rawUpload
|
||||
{'size': 6, 'hexdigest': '041c012d'}, # checkUpload
|
||||
]
|
||||
self.ksession.fastUpload('file', 'target', blocksize=1024)
|
||||
|
||||
def test_fastUpload_size_change(self):
|
||||
# change file size during upload (success)
|
||||
fileobj = mock.MagicMock()
|
||||
fileobj.read.side_effect = ['123123', '']
|
||||
self.file_mock.return_value = fileobj
|
||||
self.getsize_mock.return_value = 123456
|
||||
self.ksession._callMethod.side_effect = [
|
||||
{'size': 6, 'hexdigest': '041c012d'}, # rawUpload
|
||||
{'size': 6, 'hexdigest': '041c012d'}, # checkUpload
|
||||
]
|
||||
self.ksession.fastUpload('file', 'target', blocksize=1024)
|
||||
|
||||
def test_fastUpload_wrong_length(self):
|
||||
# uploaded file is corrupted (length) (GenericError)
|
||||
fileobj = mock.MagicMock()
|
||||
fileobj.read.side_effect = ['123123', '']
|
||||
self.file_mock.return_value = fileobj
|
||||
self.getsize_mock.return_value = 123456
|
||||
self.ksession._callMethod.side_effect = [
|
||||
{'size': 6, 'hexdigest': '041c012d'}, # rawUpload
|
||||
{'size': 3, 'hexdigest': '041c012d'}, # checkUpload
|
||||
]
|
||||
with self.assertRaises(koji.GenericError):
|
||||
self.ksession.fastUpload('file', 'target', blocksize=1024)
|
||||
|
||||
def test_fastUpload_wrong_checksum(self):
|
||||
# uploaded file is corrupted (checksum) (GenericError)
|
||||
fileobj = mock.MagicMock()
|
||||
fileobj.read.side_effect = ['123123', '']
|
||||
self.file_mock.return_value = fileobj
|
||||
self.getsize_mock.return_value = 123456
|
||||
self.ksession._callMethod.side_effect = [
|
||||
{'size': 6, 'hexdigest': '041c012d'}, # rawUpload
|
||||
{'size': 3, 'hexdigest': 'deadbeef'}, # checkUpload
|
||||
]
|
||||
with self.assertRaises(koji.GenericError):
|
||||
self.ksession.fastUpload('file', 'target', blocksize=1024)
|
||||
|
||||
def test_fastUpload_nondefault_volume(self):
|
||||
# upload regular file (success)
|
||||
fileobj = mock.MagicMock()
|
||||
fileobj.read.side_effect = ['123123', '']
|
||||
self.file_mock.return_value = fileobj
|
||||
self.ksession._callMethod.side_effect = [
|
||||
{'size': 6, 'hexdigest': '041c012d'}, # rawUpload
|
||||
{'size': 6, 'hexdigest': '041c012d'}, # checkUpload
|
||||
]
|
||||
self.ksession.fastUpload('file', 'target', blocksize=1024, volume='foobar')
|
||||
for call in self.ksession._callMethod.call_args_list:
|
||||
# both calls should pass volume as a named arg to the method
|
||||
# (note: not literally a named arg to _callMethod)
|
||||
# _callMethod args are: method, method_args, method_kwargs
|
||||
kwargs = call[0][2]
|
||||
self.assertTrue('volume' in kwargs)
|
||||
self.assertEqual(kwargs['volume'], 'foobar')
|
||||
268
tests/test_lib/test_compatrequests.py
Normal file
268
tests/test_lib/test_compatrequests.py
Normal file
|
|
@ -0,0 +1,268 @@
|
|||
from __future__ import absolute_import
|
||||
import six.moves.http_client
|
||||
import mock
|
||||
import unittest
|
||||
import six.moves.urllib
|
||||
|
||||
import koji.compatrequests
|
||||
|
||||
|
||||
class TestResponse(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
session = mock.MagicMock()
|
||||
response = mock.MagicMock()
|
||||
self.response = koji.compatrequests.Response(session, response)
|
||||
|
||||
def tearDown(self):
|
||||
del self.response
|
||||
|
||||
def test_read(self):
|
||||
self.response.response.status = 200
|
||||
data = [
|
||||
"Here's some data",
|
||||
"Here's some mooore data",
|
||||
"And look!",
|
||||
"Here's a nice block of lorem text",
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do "
|
||||
"eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
|
||||
"enim ad minim veniam, quis nostrud exercitation ullamco laboris "
|
||||
"nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor "
|
||||
"in reprehenderit in voluptate velit esse cillum dolore eu fugiat "
|
||||
"nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
|
||||
"sunt in culpa qui officia deserunt mollit anim id est laborum.",
|
||||
"", #eof
|
||||
]
|
||||
self.response.response.read.side_effect = data
|
||||
|
||||
result = list(self.response.iter_content(blocksize=10240))
|
||||
|
||||
self.assertEqual(result, data[:-1])
|
||||
rcalls = [mock.call(10240) for s in data]
|
||||
self.response.response.read.assert_has_calls(rcalls)
|
||||
|
||||
self.response.close()
|
||||
self.response.response.close.assert_called_once()
|
||||
|
||||
def test_error(self):
|
||||
self.response.response.status = 404
|
||||
self.response.response.getheader.return_value = 0
|
||||
with self.assertRaises(Exception):
|
||||
list(self.response.iter_content(8192))
|
||||
self.response.response.read.assert_not_called()
|
||||
|
||||
self.response.response.status = 404
|
||||
self.response.response.getheader.return_value = 42
|
||||
with self.assertRaises(Exception):
|
||||
list(self.response.iter_content(8192))
|
||||
self.response.response.read.assert_called_once()
|
||||
|
||||
self.response.response.status = 404
|
||||
self.response.response.reason = 'Not Found'
|
||||
self.response.response.getheader.return_value = 42
|
||||
with self.assertRaises(six.moves.http_client.HTTPException):
|
||||
self.response.raise_for_status()
|
||||
|
||||
|
||||
|
||||
class TestSessionPost(unittest.TestCase):
|
||||
|
||||
def test_simple(self):
|
||||
session = koji.compatrequests.Session()
|
||||
url = 'https://www.fakedomain.org/KOJIHUB'
|
||||
cnx = mock.MagicMock()
|
||||
session.get_connection = mock.MagicMock()
|
||||
session.get_connection.return_value = cnx
|
||||
response = mock.MagicMock()
|
||||
cnx.getresponse.return_value = response
|
||||
|
||||
ret = session.post(url, data="data", headers={"foo": "bar"})
|
||||
cnx.putrequest.assert_called_once_with('POST', '/KOJIHUB')
|
||||
cnx.putheader.assert_called_once_with('foo', 'bar')
|
||||
cnx.send.assert_called_once_with("data")
|
||||
self.assertEqual(ret.response, response)
|
||||
|
||||
def test_less_simple(self):
|
||||
session = koji.compatrequests.Session()
|
||||
url = 'https://www.fakedomain.org/KOJIHUB?a=1&b=2'
|
||||
cnx = mock.MagicMock()
|
||||
session.get_connection = mock.MagicMock()
|
||||
session.get_connection.return_value = cnx
|
||||
response = mock.MagicMock()
|
||||
cnx.getresponse.return_value = response
|
||||
|
||||
ret = session.post(url, data="data", headers={"foo": "bar"},
|
||||
cert="cert", verify="verify", stream=True, timeout=1701)
|
||||
cnx.putrequest.assert_called_once_with('POST', '/KOJIHUB?a=1&b=2')
|
||||
cnx.putheader.assert_called_once_with('foo', 'bar')
|
||||
cnx.send.assert_called_once_with("data")
|
||||
self.assertEqual(ret.response, response)
|
||||
|
||||
|
||||
class TestSessionConnection(unittest.TestCase):
|
||||
|
||||
@mock.patch('httplib.HTTPConnection')
|
||||
def test_http(self, HTTPConnection):
|
||||
# no cert, no verify, no timeout
|
||||
session = koji.compatrequests.Session()
|
||||
url = 'http://www.fakedomain234234.org/KOJIHUB?a=1&b=2'
|
||||
uri = six.moves.urllib.parse.urlsplit(url)
|
||||
|
||||
cnx = session.get_connection(uri, None, None, None)
|
||||
HTTPConnection.assert_called_once_with('www.fakedomain234234.org', 80)
|
||||
key = ('http', 'www.fakedomain234234.org', None, None, None)
|
||||
self.assertEqual(session.connection, (key, cnx))
|
||||
|
||||
# and close it
|
||||
session.close()
|
||||
self.assertEqual(session.connection, None)
|
||||
cnx.close.assert_called_with()
|
||||
|
||||
# double close should not error
|
||||
session.close()
|
||||
|
||||
def test_cached(self):
|
||||
session = koji.compatrequests.Session()
|
||||
url = 'http://www.fakedomain234234.org/KOJIHUB?a=1&b=2'
|
||||
uri = six.moves.urllib.parse.urlsplit(url)
|
||||
key = ('http', 'www.fakedomain234234.org', None, None, None)
|
||||
cnx = mock.MagicMock()
|
||||
session.connection = (key, cnx)
|
||||
|
||||
ret = session.get_connection(uri, None, None, None)
|
||||
self.assertEqual(ret, cnx)
|
||||
|
||||
def test_badproto(self):
|
||||
session = koji.compatrequests.Session()
|
||||
url = 'nosuchproto://www.fakedomain234234.org/KOJIHUB?a=1&b=2'
|
||||
uri = six.moves.urllib.parse.urlsplit(url)
|
||||
|
||||
with self.assertRaises(IOError):
|
||||
session.get_connection(uri, None, None, None)
|
||||
|
||||
@mock.patch('httplib.HTTPConnection')
|
||||
@mock.patch('sys.version_info', new=(2, 7, 12, 'final', 0))
|
||||
def test_timeout(self, HTTPConnection):
|
||||
# no cert, no verify
|
||||
session = koji.compatrequests.Session()
|
||||
url = 'http://www.fakedomain234234.org/KOJIHUB?a=1&b=2'
|
||||
uri = six.moves.urllib.parse.urlsplit(url)
|
||||
timeout = 1701
|
||||
|
||||
cnx = session.get_connection(uri, None, None, timeout)
|
||||
HTTPConnection.assert_called_once_with('www.fakedomain234234.org', 80, timeout=timeout)
|
||||
key = ('http', 'www.fakedomain234234.org', None, None, timeout)
|
||||
self.assertEqual(session.connection, (key, cnx))
|
||||
|
||||
@mock.patch('httplib.HTTPConnection')
|
||||
@mock.patch('sys.version_info', new=(2, 4, 3, 'final', 0))
|
||||
def test_timeout_compat(self, HTTPConnection):
|
||||
# no cert, no verify
|
||||
session = koji.compatrequests.Session()
|
||||
url = 'http://www.fakedomain234234.org/KOJIHUB?a=1&b=2'
|
||||
uri = six.moves.urllib.parse.urlsplit(url)
|
||||
timeout = 1701
|
||||
|
||||
cnx = session.get_connection(uri, None, None, timeout)
|
||||
HTTPConnection.assert_called_once_with('www.fakedomain234234.org', 80)
|
||||
key = ('http', 'www.fakedomain234234.org', None, None, timeout)
|
||||
self.assertEqual(session.connection, (key, cnx))
|
||||
cnx.connect.assert_called_once()
|
||||
cnx.sock.settimeout.assert_called_with(timeout)
|
||||
|
||||
@mock.patch('httplib.HTTPSConnection')
|
||||
def test_https(self, HTTPSConnection):
|
||||
# no cert, no verify, no timeout
|
||||
session = koji.compatrequests.Session()
|
||||
url = 'https://www.fakedomain234234.org/KOJIHUB?a=1&b=2'
|
||||
uri = six.moves.urllib.parse.urlsplit(url)
|
||||
|
||||
cnx = session.get_connection(uri, None, None, None)
|
||||
HTTPSConnection.assert_called_once_with('www.fakedomain234234.org', 443)
|
||||
key = ('https', 'www.fakedomain234234.org', None, None, None)
|
||||
self.assertEqual(session.connection, (key, cnx))
|
||||
|
||||
@mock.patch('koji.ssl.SSLCommon.CreateSSLContext')
|
||||
@mock.patch('koji.ssl.SSLCommon.PlgHTTPSConnection')
|
||||
def test_cert(self, PlgHTTPSConnection, CreateSSLContext):
|
||||
# no verify, no timeout
|
||||
session = koji.compatrequests.Session()
|
||||
url = 'https://www.fakedomain234234.org/KOJIHUB?a=1&b=2'
|
||||
uri = six.moves.urllib.parse.urlsplit(url)
|
||||
cert = '/path/to/cert/file'
|
||||
context = mock.MagicMock()
|
||||
CreateSSLContext.return_value = context
|
||||
|
||||
cnx = session.get_connection(uri, cert, None, None)
|
||||
PlgHTTPSConnection.assert_called_once_with('www.fakedomain234234.org', 443, ssl_context=context)
|
||||
key = ('https', 'www.fakedomain234234.org', cert, None, None)
|
||||
self.assertEqual(session.connection, (key, cnx))
|
||||
|
||||
@mock.patch('ssl._create_unverified_context')
|
||||
@mock.patch('httplib.HTTPSConnection')
|
||||
@mock.patch('sys.version_info', new=(2, 7, 12, 'final', 0))
|
||||
def test_unverified(self, HTTPSConnection, create_unverified_context):
|
||||
# no cert, verify=False, no timeout
|
||||
session = koji.compatrequests.Session()
|
||||
url = 'https://www.fakedomain234234.org/KOJIHUB?a=1&b=2'
|
||||
uri = six.moves.urllib.parse.urlsplit(url)
|
||||
context = mock.MagicMock()
|
||||
create_unverified_context.return_value = context
|
||||
|
||||
cnx = session.get_connection(uri, None, False, None)
|
||||
create_unverified_context.assert_called_once()
|
||||
HTTPSConnection.assert_called_once_with('www.fakedomain234234.org', 443, context=context)
|
||||
key = ('https', 'www.fakedomain234234.org', None, False, None)
|
||||
self.assertEqual(session.connection, (key, cnx))
|
||||
|
||||
@mock.patch('httplib.HTTPSConnection')
|
||||
@mock.patch('sys.version_info', new=(2, 4, 3, 'final', 0))
|
||||
def test_unverified_compat(self, HTTPSConnection):
|
||||
# no cert, verify=False, no timeout
|
||||
session = koji.compatrequests.Session()
|
||||
url = 'https://www.fakedomain234234.org/KOJIHUB?a=1&b=2'
|
||||
uri = six.moves.urllib.parse.urlsplit(url)
|
||||
|
||||
cnx = session.get_connection(uri, None, False, None)
|
||||
HTTPSConnection.assert_called_once_with('www.fakedomain234234.org', 443)
|
||||
key = ('https', 'www.fakedomain234234.org', None, False, None)
|
||||
self.assertEqual(session.connection, (key, cnx))
|
||||
|
||||
@mock.patch('ssl._create_unverified_context')
|
||||
@mock.patch('ssl.SSLContext')
|
||||
@mock.patch('httplib.HTTPSConnection')
|
||||
@mock.patch('sys.version_info', new=(2, 7, 12, 'final', 0))
|
||||
def test_verify(self, HTTPSConnection, SSLContext, create_unverified_context):
|
||||
# no cert, no timeout
|
||||
session = koji.compatrequests.Session()
|
||||
url = 'https://www.fakedomain234234.org/KOJIHUB?a=1&b=2'
|
||||
uri = six.moves.urllib.parse.urlsplit(url)
|
||||
context = mock.MagicMock()
|
||||
SSLContext.return_value = context
|
||||
verify = '/path/to/verify/cert'
|
||||
|
||||
cnx = session.get_connection(uri, None, verify, None)
|
||||
create_unverified_context.assert_not_called()
|
||||
SSLContext.assert_called_once()
|
||||
context.load_verify_locations.called_once_with(cafile=verify)
|
||||
HTTPSConnection.assert_called_once_with('www.fakedomain234234.org', 443, context=context)
|
||||
key = ('https', 'www.fakedomain234234.org', None, verify, None)
|
||||
self.assertEqual(session.connection, (key, cnx))
|
||||
|
||||
@mock.patch('ssl._create_unverified_context')
|
||||
@mock.patch('ssl.SSLContext')
|
||||
@mock.patch('httplib.HTTPSConnection')
|
||||
@mock.patch('sys.version_info', new=(2, 4, 3, 'final', 0))
|
||||
def test_verify_compat(self, HTTPSConnection, SSLContext, create_unverified_context):
|
||||
# no cert, no timeout
|
||||
session = koji.compatrequests.Session()
|
||||
url = 'https://www.fakedomain234234.org/KOJIHUB?a=1&b=2'
|
||||
uri = six.moves.urllib.parse.urlsplit(url)
|
||||
verify = '/path/to/verify/cert'
|
||||
|
||||
cnx = session.get_connection(uri, None, verify, None)
|
||||
create_unverified_context.assert_not_called()
|
||||
SSLContext.assert_not_called()
|
||||
HTTPSConnection.assert_called_once_with('www.fakedomain234234.org', 443, cert_file=verify)
|
||||
key = ('https', 'www.fakedomain234234.org', None, verify, None)
|
||||
self.assertEqual(session.connection, (key, cnx))
|
||||
77
tests/test_lib/test_fixEncoding.py
Normal file
77
tests/test_lib/test_fixEncoding.py
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
#!/usr/bin/python
|
||||
# coding=utf-8
|
||||
|
||||
"""Test the __init__.py module"""
|
||||
|
||||
from __future__ import absolute_import
|
||||
import koji
|
||||
import unittest
|
||||
|
||||
class FixEncodingTestCase(unittest.TestCase):
|
||||
"""Main test case container"""
|
||||
|
||||
simple_values = [
|
||||
# [ value, fixed ]
|
||||
['', ''],
|
||||
[u'', ''],
|
||||
[u'góðan daginn', 'g\xc3\xb3\xc3\xb0an daginn'],
|
||||
[u'hej', 'hej'],
|
||||
[u'zdravstvuite', 'zdravstvuite'],
|
||||
[u'céad míle fáilte', 'c\xc3\xa9ad m\xc3\xadle f\xc3\xa1ilte'],
|
||||
[u'dobrý den', 'dobr\xc3\xbd den'],
|
||||
[u'hylô', 'hyl\xc3\xb4'],
|
||||
[u'jó napot', 'j\xc3\xb3 napot'],
|
||||
[u'tervehdys', 'tervehdys'],
|
||||
[u'olá', 'ol\xc3\xa1'],
|
||||
[u'grüezi', 'gr\xc3\xbcezi'],
|
||||
[u'dobre dan', 'dobre dan'],
|
||||
[u'hello', 'hello'],
|
||||
[u'bună ziua', 'bun\xc4\x83 ziua'],
|
||||
[u'こんにちは', '\xe3\x81\x93\xe3\x82\x93\xe3\x81\xab\xe3\x81\xa1\xe3\x81\xaf'],
|
||||
[u'你好', '\xe4\xbd\xa0\xe5\xa5\xbd'],
|
||||
[u'नमस्कार', '\xe0\xa4\xa8\xe0\xa4\xae\xe0\xa4\xb8\xe0\xa5\x8d\xe0\xa4\x95\xe0\xa4\xbe\xe0\xa4\xb0'],
|
||||
[u'안녕하세요', '\xec\x95\x88\xeb\x85\x95\xed\x95\x98\xec\x84\xb8\xec\x9a\x94'],
|
||||
]
|
||||
|
||||
def test_fixEncoding(self):
|
||||
"""Test the fixEncoding function"""
|
||||
for a, b in self.simple_values:
|
||||
self.assertEqual(koji.fixEncoding(a), b)
|
||||
self.assertEqual(koji.fixEncoding(b), b)
|
||||
c = a.encode('utf16')
|
||||
self.assertEqual(koji.fixEncoding(c, fallback='utf16'), b)
|
||||
d = a[:-3] + u'\x00\x01' + a[-3:]
|
||||
self.assertEqual(koji.fixEncoding(d, remove_nonprintable=True), b)
|
||||
|
||||
complex_values = [
|
||||
# [ value, fixed ]
|
||||
[{}, {}],
|
||||
[(), ()],
|
||||
[None, None],
|
||||
[[], []],
|
||||
[{u'a': 'a' , 'b' : {'c': u'c\x00'}},
|
||||
{ 'a': 'a' , 'b' : {'c': 'c\x00'}}],
|
||||
# iso8859-15 fallback
|
||||
['g\xf3\xf0an daginn', 'g\xc3\xb3\xc3\xb0an daginn'],
|
||||
]
|
||||
|
||||
nonprint = [
|
||||
['hello\0world\0', 'helloworld'],
|
||||
[u'hello\0world\0', 'helloworld'],
|
||||
[[u'hello\0world\0'], ['helloworld']],
|
||||
[{0: u'hello\0world\0'}, {0: 'helloworld'}],
|
||||
[[{0: u'hello\0world\0'}], [{0: 'helloworld'}]],
|
||||
]
|
||||
|
||||
def test_fixEncodingRecurse(self):
|
||||
"""Test the fixEncodingRecurse function"""
|
||||
for a, b in self.simple_values:
|
||||
self.assertEqual(koji.fixEncoding(a), b)
|
||||
for a, b in self.complex_values:
|
||||
self.assertEqual(koji.fixEncodingRecurse(a), b)
|
||||
for a, b in self.nonprint:
|
||||
self.assertEqual(koji.fixEncodingRecurse(a, remove_nonprintable=True), b)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
18
tests/test_lib/test_krbv.py
Normal file
18
tests/test_lib/test_krbv.py
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
from __future__ import absolute_import
|
||||
import unittest
|
||||
|
||||
# This is python-mock, not the rpm mock tool we know and love
|
||||
import mock
|
||||
|
||||
import koji
|
||||
|
||||
|
||||
class KrbVTestCase(unittest.TestCase):
|
||||
|
||||
@mock.patch('koji.krbV', new=None)
|
||||
def test_krbv_disabled(self):
|
||||
""" Test that when krbV is absent, we behave rationally. """
|
||||
self.assertEquals(koji.krbV, None)
|
||||
session = koji.ClientSession('whatever')
|
||||
with self.assertRaises(ImportError):
|
||||
session.krb_login()
|
||||
191
tests/test_lib/test_parsers.py
Normal file
191
tests/test_lib/test_parsers.py
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
"""Test the __init__.py module"""
|
||||
|
||||
from __future__ import absolute_import
|
||||
import mock
|
||||
import os
|
||||
import rpm
|
||||
import unittest
|
||||
|
||||
import koji
|
||||
|
||||
class INITTestCase(unittest.TestCase):
|
||||
"""Main test case container"""
|
||||
|
||||
def test_parse_NVR(self):
|
||||
"""Test the parse_NVR method"""
|
||||
|
||||
self.assertRaises(AttributeError, koji.parse_NVR, None)
|
||||
self.assertRaises(AttributeError, koji.parse_NVR, 1)
|
||||
self.assertRaises(AttributeError, koji.parse_NVR, {})
|
||||
self.assertRaises(AttributeError, koji.parse_NVR, [])
|
||||
self.assertRaises(koji.GenericError, koji.parse_NVR, "")
|
||||
self.assertRaises(koji.GenericError, koji.parse_NVR, "foo")
|
||||
self.assertRaises(koji.GenericError, koji.parse_NVR, "foo-1")
|
||||
self.assertRaises(koji.GenericError, koji.parse_NVR, "foo-1-")
|
||||
self.assertRaises(koji.GenericError, koji.parse_NVR, "foo--1")
|
||||
self.assertRaises(koji.GenericError, koji.parse_NVR, "--1")
|
||||
ret = koji.parse_NVR("foo-1-2")
|
||||
self.assertEqual(ret['name'], "foo")
|
||||
self.assertEqual(ret['version'], "1")
|
||||
self.assertEqual(ret['release'], "2")
|
||||
self.assertEqual(ret['epoch'], "")
|
||||
ret = koji.parse_NVR("12:foo-1-2")
|
||||
self.assertEqual(ret['name'], "foo")
|
||||
self.assertEqual(ret['version'], "1")
|
||||
self.assertEqual(ret['release'], "2")
|
||||
self.assertEqual(ret['epoch'], "12")
|
||||
|
||||
def test_parse_NVRA(self):
|
||||
"""Test the parse_NVRA method"""
|
||||
|
||||
self.assertRaises(AttributeError, koji.parse_NVRA, None)
|
||||
self.assertRaises(AttributeError, koji.parse_NVRA, 1)
|
||||
self.assertRaises(AttributeError, koji.parse_NVRA, {})
|
||||
self.assertRaises(AttributeError, koji.parse_NVRA, [])
|
||||
self.assertRaises(koji.GenericError, koji.parse_NVRA, "")
|
||||
self.assertRaises(koji.GenericError, koji.parse_NVRA, "foo")
|
||||
self.assertRaises(koji.GenericError, koji.parse_NVRA, "foo-1")
|
||||
self.assertRaises(koji.GenericError, koji.parse_NVRA, "foo-1-")
|
||||
self.assertRaises(koji.GenericError, koji.parse_NVRA, "foo--1")
|
||||
self.assertRaises(koji.GenericError, koji.parse_NVRA, "--1")
|
||||
self.assertRaises(koji.GenericError, koji.parse_NVRA, "foo-1-1")
|
||||
self.assertRaises(koji.GenericError, koji.parse_NVRA, "foo-1-1.")
|
||||
self.assertRaises(koji.GenericError, koji.parse_NVRA, "foo-1.-1")
|
||||
ret = koji.parse_NVRA("foo-1-2.i386")
|
||||
self.assertEqual(ret['name'], "foo")
|
||||
self.assertEqual(ret['version'], "1")
|
||||
self.assertEqual(ret['release'], "2")
|
||||
self.assertEqual(ret['epoch'], "")
|
||||
self.assertEqual(ret['arch'], "i386")
|
||||
self.assertEqual(ret['src'], False)
|
||||
ret = koji.parse_NVRA("12:foo-1-2.src")
|
||||
self.assertEqual(ret['name'], "foo")
|
||||
self.assertEqual(ret['version'], "1")
|
||||
self.assertEqual(ret['release'], "2")
|
||||
self.assertEqual(ret['epoch'], "12")
|
||||
self.assertEqual(ret['arch'], "src")
|
||||
self.assertEqual(ret['src'], True)
|
||||
|
||||
def test_check_NVR(self):
|
||||
"""Test the check_NVR function"""
|
||||
good = [
|
||||
"name-version-release",
|
||||
"fnord-5.23-17",
|
||||
{'name': 'foo', 'version': '2.2.2', 'release': '1.1'},
|
||||
]
|
||||
bad = [
|
||||
"this is not an NVR",
|
||||
{'name': 'foo', 'version': '2.2.2-a', 'release': '1.1'},
|
||||
{'name': 'foo', 'version': '2.2.2', 'release': '1.1-b'},
|
||||
]
|
||||
for value in good:
|
||||
self.assertEqual(koji.check_NVR(value), True)
|
||||
for value in bad:
|
||||
self.assertEqual(koji.check_NVR(value), False)
|
||||
self.assertRaises(koji.GenericError,
|
||||
koji.check_NVR, value, strict=True)
|
||||
|
||||
def test_check_NVRA(self):
|
||||
"""Test the check_NVRA function"""
|
||||
good = [
|
||||
"name-version-release.arch",
|
||||
"fnord-5.23-17.x86_64",
|
||||
{'name': 'foo', 'version': '2.2.2', 'release': '1.1',
|
||||
'arch': 'i686'},
|
||||
]
|
||||
bad = [
|
||||
"this is not an NVRA",
|
||||
"fnord-5.23-17",
|
||||
{'name': 'foo', 'version': '2.2.2-a', 'release': '1.1',
|
||||
'arch': 'ppc64'},
|
||||
{'name': 'foo', 'version': '2.2.2', 'release': '1.1-b',
|
||||
'arch': 'x86_64'},
|
||||
{'name': 'foo', 'version': '2.2.2', 'release': '1.1',
|
||||
'arch': 'x.86.64'},
|
||||
]
|
||||
for value in good:
|
||||
self.assertEqual(koji.check_NVRA(value), True)
|
||||
for value in bad:
|
||||
self.assertEqual(koji.check_NVRA(value), False)
|
||||
self.assertRaises(koji.GenericError,
|
||||
koji.check_NVRA, value, strict=True)
|
||||
|
||||
|
||||
class HeaderTestCase(unittest.TestCase):
|
||||
rpm_path = os.path.join(os.path.dirname(__file__), 'data/rpms/test-deps-1-1.fc24.x86_64.rpm')
|
||||
rpmdir = os.path.join(os.path.dirname(__file__), 'data/rpms')
|
||||
|
||||
def setUp(self):
|
||||
self.fd = open(self.rpm_path)
|
||||
|
||||
def tearDown(self):
|
||||
self.fd.close()
|
||||
|
||||
def test_get_rpm_header(self):
|
||||
self.assertRaises(IOError, koji.get_rpm_header, 'nonexistent_path')
|
||||
self.assertRaises(AttributeError, koji.get_rpm_header, None)
|
||||
self.assertIsInstance(koji.get_rpm_header(self.rpm_path), rpm.hdr)
|
||||
self.assertIsInstance(koji.get_rpm_header(self.fd), rpm.hdr)
|
||||
# TODO:
|
||||
# test ts
|
||||
|
||||
def test_get_header_fields(self):
|
||||
# incorrect
|
||||
self.assertRaises(IOError, koji.get_header_fields, 'nonexistent_path', [])
|
||||
self.assertRaises(koji.GenericError, koji.get_header_fields, self.rpm_path, 'nonexistent_header')
|
||||
self.assertEqual(koji.get_header_fields(self.rpm_path, []), {})
|
||||
|
||||
# correct
|
||||
self.assertEqual(['REQUIRES'], list(koji.get_header_fields(self.rpm_path, ['REQUIRES']).keys()))
|
||||
self.assertEqual(['PROVIDES', 'REQUIRES'], sorted(koji.get_header_fields(self.rpm_path, ['REQUIRES', 'PROVIDES'])))
|
||||
hdr = koji.get_rpm_header(self.rpm_path)
|
||||
self.assertEqual(['REQUIRES'], list(koji.get_header_fields(hdr, ['REQUIRES']).keys()))
|
||||
|
||||
|
||||
def test_get_header_field_src(self):
|
||||
srpm = os.path.join(self.rpmdir, 'test-src-1-1.fc24.src.rpm')
|
||||
|
||||
# without src_arch, should return the build arch (x86_64)
|
||||
data = koji.get_header_fields(srpm, ['arch'])
|
||||
self.assertEqual(data['arch'], 'x86_64')
|
||||
|
||||
# with src_arch, should return src
|
||||
data = koji.get_header_fields(srpm, ['arch'], src_arch=True)
|
||||
self.assertEqual(data['arch'], 'src')
|
||||
|
||||
|
||||
def test_get_header_field_nosrc(self):
|
||||
srpm1 = os.path.join(self.rpmdir, 'test-nosrc-1-1.fc24.nosrc.rpm')
|
||||
srpm2 = os.path.join(self.rpmdir, 'test-nopatch-1-1.fc24.nosrc.rpm')
|
||||
|
||||
# without src_arch, should return the build arch (x86_64)
|
||||
for srpm in srpm1, srpm2:
|
||||
data = koji.get_header_fields(srpm, ['arch'])
|
||||
self.assertEqual(data['arch'], 'x86_64')
|
||||
|
||||
# with src_arch, should return nosrc
|
||||
for srpm in srpm1, srpm2:
|
||||
data = koji.get_header_fields(srpm, ['arch'], src_arch=True)
|
||||
self.assertEqual(data['arch'], 'nosrc')
|
||||
|
||||
|
||||
@mock.patch('rpm.RPMTAG_NOSOURCE', new=None)
|
||||
@mock.patch('rpm.RPMTAG_NOPATCH', new=None)
|
||||
@mock.patch('koji.RPM_SUPPORTS_OPTIONAL_DEPS', new=False)
|
||||
def test_get_header_field_workarounds(self):
|
||||
srpm0 = os.path.join(self.rpmdir, 'test-src-1-1.fc24.src.rpm')
|
||||
srpm1 = os.path.join(self.rpmdir, 'test-nosrc-1-1.fc24.nosrc.rpm')
|
||||
srpm2 = os.path.join(self.rpmdir, 'test-nopatch-1-1.fc24.nosrc.rpm')
|
||||
|
||||
# should still work even with rpm constants set to None
|
||||
self.assertEqual([0], koji.get_header_fields(srpm1, ['nosource'])['nosource'])
|
||||
self.assertEqual([0], koji.get_header_fields(srpm2, ['nopatch'])['nopatch'])
|
||||
|
||||
# should return [] with optional dep support off
|
||||
self.assertEqual([], koji.get_header_fields(srpm0, ['suggestname'])['suggestname'])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
299
tests/test_lib/test_policy.py
Normal file
299
tests/test_lib/test_policy.py
Normal file
|
|
@ -0,0 +1,299 @@
|
|||
from __future__ import absolute_import
|
||||
import unittest
|
||||
|
||||
from nose.tools import raises
|
||||
|
||||
import koji.policy
|
||||
|
||||
|
||||
class MyBoolTest(koji.policy.BoolTest):
|
||||
name = 'bool_check'
|
||||
field = 'bool_field'
|
||||
|
||||
|
||||
class MyMatchTest(koji.policy.MatchTest):
|
||||
name = 'match_check'
|
||||
field = 'match_field'
|
||||
|
||||
|
||||
class myvarTest(koji.policy.CompareTest):
|
||||
name = None
|
||||
field = 'myvar'
|
||||
allow_float = False
|
||||
|
||||
|
||||
class TestBasicTests(unittest.TestCase):
|
||||
|
||||
@raises(NotImplementedError)
|
||||
def test_base_test(self):
|
||||
obj = koji.policy.BaseSimpleTest('something')
|
||||
obj.run({})
|
||||
|
||||
def test_true_test(self):
|
||||
obj = koji.policy.TrueTest('something')
|
||||
self.assertTrue(obj.run({}))
|
||||
|
||||
def test_false_test(self):
|
||||
obj = koji.policy.FalseTest('something')
|
||||
self.assertFalse(obj.run({}))
|
||||
|
||||
def test_all_test(self):
|
||||
obj = koji.policy.AllTest('something')
|
||||
self.assertTrue(obj.run({}))
|
||||
|
||||
def test_none_test(self):
|
||||
obj = koji.policy.NoneTest('something')
|
||||
self.assertFalse(obj.run({}))
|
||||
|
||||
def test_has_test(self):
|
||||
obj = koji.policy.HasTest('some thing')
|
||||
self.assertFalse(obj.run({}))
|
||||
self.assertFalse(obj.run({'blah': 'blah'}))
|
||||
self.assertTrue(obj.run({'thing': 'blah'}))
|
||||
self.assertRaises(koji.GenericError, koji.policy.HasTest, 'something')
|
||||
|
||||
def test_bool_test(self):
|
||||
obj = koji.policy.BoolTest('some thing')
|
||||
self.assertFalse(obj.run({'thing': None}))
|
||||
self.assertFalse(obj.run({'thing': []}))
|
||||
self.assertTrue(obj.run({'thing': 'yes'}))
|
||||
|
||||
def test_match_test(self):
|
||||
obj = koji.policy.MatchTest('some thing else')
|
||||
self.assertFalse(obj.run({'thing': 'elseplus'}))
|
||||
obj = koji.policy.MatchTest('some thing else*')
|
||||
self.assertTrue(obj.run({'thing': 'elseplus'}))
|
||||
|
||||
def test_compare_test(self):
|
||||
obj = koji.policy.CompareTest('compare thing > 2')
|
||||
self.assertFalse(obj.run({'thing': 1}))
|
||||
self.assertFalse(obj.run({'thing': 2}))
|
||||
self.assertTrue(obj.run({'thing': 3}))
|
||||
|
||||
obj = koji.policy.CompareTest('compare thing < 1.5')
|
||||
self.assertFalse(obj.run({'thing': 3.2}))
|
||||
self.assertTrue(obj.run({'thing': 1.0}))
|
||||
|
||||
obj = koji.policy.CompareTest('compare thing = 42')
|
||||
self.assertFalse(obj.run({'thing': 54}))
|
||||
self.assertTrue(obj.run({'thing': 42}))
|
||||
|
||||
obj = koji.policy.CompareTest('compare thing != 99')
|
||||
self.assertFalse(obj.run({'thing': 99}))
|
||||
self.assertTrue(obj.run({'thing': 100}))
|
||||
|
||||
obj = koji.policy.CompareTest('compare thing >= 2')
|
||||
self.assertFalse(obj.run({'thing': 1}))
|
||||
self.assertTrue(obj.run({'thing': 2}))
|
||||
self.assertTrue(obj.run({'thing': 3}))
|
||||
|
||||
obj = koji.policy.CompareTest('compare thing <= 5')
|
||||
self.assertFalse(obj.run({'thing': 23}))
|
||||
self.assertTrue(obj.run({'thing': 5}))
|
||||
self.assertTrue(obj.run({'thing': 0}))
|
||||
|
||||
@raises(koji.GenericError)
|
||||
def test_invalid_compare_test(self):
|
||||
koji.policy.CompareTest('some thing LOL 2')
|
||||
|
||||
|
||||
class TestDiscovery(unittest.TestCase):
|
||||
|
||||
def test_find_simple_tests(self):
|
||||
actual = koji.policy.findSimpleTests(koji.policy.__dict__)
|
||||
expected = {
|
||||
'all': koji.policy.AllTest,
|
||||
'bool': koji.policy.BoolTest,
|
||||
'compare': koji.policy.CompareTest,
|
||||
'false': koji.policy.FalseTest,
|
||||
'has': koji.policy.HasTest,
|
||||
'match': koji.policy.MatchTest,
|
||||
'none': koji.policy.NoneTest,
|
||||
'true': koji.policy.TrueTest,
|
||||
}
|
||||
self.assertDictEqual(expected, actual)
|
||||
|
||||
|
||||
class TestRuleHandling(unittest.TestCase):
|
||||
|
||||
def test_simple_rule_set_instantiation(self):
|
||||
tests = koji.policy.findSimpleTests(koji.policy.__dict__)
|
||||
rules = ['true :: allow']
|
||||
koji.policy.SimpleRuleSet(rules, tests)
|
||||
|
||||
def test_simple_rule_set_all_actions(self):
|
||||
tests = koji.policy.findSimpleTests(koji.policy.__dict__)
|
||||
rules = ['true :: allow']
|
||||
obj = koji.policy.SimpleRuleSet(rules, tests)
|
||||
result = obj.all_actions()
|
||||
self.assertEquals(result, ['allow'])
|
||||
|
||||
def test_simple_rule_set_apply(self):
|
||||
tests = koji.policy.findSimpleTests(koji.policy.__dict__)
|
||||
data = {}
|
||||
|
||||
rules = ['true :: allow']
|
||||
obj = koji.policy.SimpleRuleSet(rules, tests)
|
||||
action = obj.apply(data)
|
||||
self.assertEqual(action, 'allow')
|
||||
|
||||
rules = ['false :: allow']
|
||||
obj = koji.policy.SimpleRuleSet(rules, tests)
|
||||
action = obj.apply(data)
|
||||
self.assertEqual(action, None)
|
||||
|
||||
def test_custom_rules(self):
|
||||
tests = koji.policy.findSimpleTests([globals(), koji.policy.__dict__])
|
||||
|
||||
rules = ['bool_check :: True', 'all :: False']
|
||||
for val in True, False:
|
||||
data = {'bool_field' : val}
|
||||
obj = koji.policy.SimpleRuleSet(rules, tests)
|
||||
action = obj.apply(data)
|
||||
self.assertEqual(action, str(val))
|
||||
|
||||
rules = ['match_check foo* :: foo', 'match_check * :: bar']
|
||||
data = {'match_field' : 'foo1234'}
|
||||
obj = koji.policy.SimpleRuleSet(rules, tests)
|
||||
action = obj.apply(data)
|
||||
self.assertEqual(action, 'foo')
|
||||
|
||||
data = {'match_field' : 'not foo'}
|
||||
obj = koji.policy.SimpleRuleSet(rules, tests)
|
||||
action = obj.apply(data)
|
||||
self.assertEqual(action, 'bar')
|
||||
|
||||
data = {'myvar': 37}
|
||||
rules = ['myvar = 37 :: get back here']
|
||||
obj = koji.policy.SimpleRuleSet(rules, tests)
|
||||
action = obj.apply(data)
|
||||
self.assertEqual(action, 'get back here')
|
||||
|
||||
rules = ['myvar = 2.718281828 :: euler']
|
||||
with self.assertRaises(ValueError):
|
||||
obj = koji.policy.SimpleRuleSet(rules, tests)
|
||||
|
||||
def test_last_rule(self):
|
||||
tests = koji.policy.findSimpleTests(koji.policy.__dict__)
|
||||
data = {}
|
||||
|
||||
# no match
|
||||
rules = ['none :: allow']
|
||||
obj = koji.policy.SimpleRuleSet(rules, tests)
|
||||
self.assertEquals(obj.last_rule(), None)
|
||||
action = obj.apply(data)
|
||||
self.assertEquals(obj.last_rule(), '(no match)')
|
||||
|
||||
# simple rule
|
||||
rules = ['all :: allow']
|
||||
obj = koji.policy.SimpleRuleSet(rules, tests)
|
||||
action = obj.apply(data)
|
||||
self.assertEquals(obj.last_rule(), rules[0])
|
||||
|
||||
# negate rule
|
||||
rules = ['none !! allow']
|
||||
obj = koji.policy.SimpleRuleSet(rules, tests)
|
||||
action = obj.apply(data)
|
||||
self.assertEquals(obj.last_rule(), rules[0])
|
||||
|
||||
# nested rule
|
||||
policy = '''
|
||||
all :: {
|
||||
all :: {
|
||||
all :: allow
|
||||
}
|
||||
}
|
||||
'''
|
||||
rules = policy.splitlines()
|
||||
obj = koji.policy.SimpleRuleSet(rules, tests)
|
||||
action = obj.apply(data)
|
||||
expected = 'all :: ... all :: ... all :: allow'
|
||||
self.assertEquals(obj.last_rule(), expected)
|
||||
|
||||
def test_unclosed_brace(self):
|
||||
tests = koji.policy.findSimpleTests(koji.policy.__dict__)
|
||||
data = {}
|
||||
|
||||
lines = ['true :: {']
|
||||
with self.assertRaises(koji.GenericError):
|
||||
obj = koji.policy.SimpleRuleSet(lines, tests)
|
||||
|
||||
def test_unmatched_brace(self):
|
||||
tests = koji.policy.findSimpleTests(koji.policy.__dict__)
|
||||
data = {}
|
||||
|
||||
lines = ['true :: }']
|
||||
with self.assertRaises(koji.GenericError):
|
||||
obj = koji.policy.SimpleRuleSet(lines, tests)
|
||||
|
||||
def test_no_action(self):
|
||||
tests = koji.policy.findSimpleTests(koji.policy.__dict__)
|
||||
data = {}
|
||||
|
||||
lines = ['true && true']
|
||||
with self.assertRaises(Exception):
|
||||
obj = koji.policy.SimpleRuleSet(lines, tests)
|
||||
|
||||
def test_missing_handler(self):
|
||||
tests = koji.policy.findSimpleTests(koji.policy.__dict__)
|
||||
data = {}
|
||||
|
||||
lines = ['NOSUCHHANDLER && true :: allow']
|
||||
with self.assertRaises(koji.GenericError):
|
||||
obj = koji.policy.SimpleRuleSet(lines, tests)
|
||||
|
||||
def test_complex_policy(self):
|
||||
tests = koji.policy.findSimpleTests(koji.policy.__dict__)
|
||||
data = {}
|
||||
|
||||
policy = '''
|
||||
# This is a comment in the test policy
|
||||
|
||||
#^blank line
|
||||
# commented test && true :: some result
|
||||
|
||||
# First some rules that should never match
|
||||
false :: ERROR
|
||||
none :: ERROR
|
||||
|
||||
true !! ERROR
|
||||
all !! ERROR
|
||||
|
||||
false && true && true :: ERROR
|
||||
none && true && true :: ERROR
|
||||
|
||||
has NOSUCHFIELD :: ERROR
|
||||
|
||||
# nesting
|
||||
has DEPTH :: {
|
||||
match DEPTH 1 :: 1
|
||||
all :: {
|
||||
match DEPTH 2 :: 2
|
||||
all :: {
|
||||
match DEPTH 3 :: 3
|
||||
all :: {
|
||||
match DEPTH 4 :: 4
|
||||
all :: END
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
'''
|
||||
|
||||
lines = policy.splitlines()
|
||||
|
||||
for depth in ['1', '2', '3', '4']:
|
||||
data = {'DEPTH': depth}
|
||||
obj = koji.policy.SimpleRuleSet(lines, tests)
|
||||
action = obj.apply(data)
|
||||
self.assertEqual(action, depth)
|
||||
|
||||
data = {'DEPTH': '99'}
|
||||
obj = koji.policy.SimpleRuleSet(lines, tests)
|
||||
action = obj.apply(data)
|
||||
self.assertEqual(action, 'END')
|
||||
|
||||
actions = set(obj.all_actions())
|
||||
self.assertEquals(actions, set(['1', '2', '3', '4', 'ERROR', 'END']))
|
||||
|
||||
|
||||
43
tests/test_lib/test_profiles.py
Normal file
43
tests/test_lib/test_profiles.py
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
from __future__ import absolute_import
|
||||
import unittest
|
||||
|
||||
import koji
|
||||
import sys
|
||||
import threading
|
||||
import traceback
|
||||
from six.moves import range
|
||||
|
||||
|
||||
class ProfilesTestCase(unittest.TestCase):
|
||||
|
||||
def test_profile_threading(self):
|
||||
""" Test that profiles thread safe"""
|
||||
# see: https://pagure.io/koji/issue/58 and https://pagure.io/pungi/issue/253
|
||||
# loop a few times to increase chances of hitting race conditions
|
||||
for i in range(20):
|
||||
errors = {}
|
||||
threads = [threading.Thread(target=stress, args=(errors, _)) for _ in range(100)]
|
||||
for t in threads:
|
||||
t.start()
|
||||
for t in threads:
|
||||
t.join(30)
|
||||
for n in errors:
|
||||
err = errors[n]
|
||||
if err is not None:
|
||||
print(err)
|
||||
assert False
|
||||
|
||||
|
||||
def stress(errors, n):
|
||||
errors[n] = "Failed to start"
|
||||
try:
|
||||
koji.get_profile_module('koji')
|
||||
except Exception:
|
||||
# if we don't catch this, nose seems to ignore the test
|
||||
errors[n] = ''.join(traceback.format_exception(*sys.exc_info()))
|
||||
return
|
||||
else:
|
||||
errors[n] = None
|
||||
|
||||
|
||||
|
||||
715
tests/test_lib/test_tasks.py
Normal file
715
tests/test_lib/test_tasks.py
Normal file
|
|
@ -0,0 +1,715 @@
|
|||
from __future__ import absolute_import
|
||||
import random
|
||||
from os import path, makedirs
|
||||
from shutil import rmtree
|
||||
from tempfile import gettempdir
|
||||
from unittest import TestCase
|
||||
from mock import patch, Mock, call
|
||||
|
||||
import koji
|
||||
from koji.tasks import BaseTaskHandler, FakeTask, ForkTask, SleepTask, \
|
||||
WaitTestTask, scan_mounts, umount_all, \
|
||||
safe_rmtree
|
||||
import six
|
||||
|
||||
|
||||
def get_fake_mounts_file():
|
||||
""" Returns contents of /prc/mounts in a file-like object
|
||||
"""
|
||||
return six.StringIO(six.text_type((
|
||||
'sysfs /sys sysfs rw,seclabel,nosuid,nodev,noexec,relatime 0 0\n'
|
||||
'proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0\n'
|
||||
'devtmpfs /dev devtmpfs rw,seclabel,nosuid,size=238836k,nr_inodes=59709,mode=755 0 0\n'
|
||||
'securityfs /sys/kernel/security securityfs rw,nosuid,nodev,noexec,relatime 0 0\n'
|
||||
'tmpfs /dev/shm\040(deleted) tmpfs rw,seclabel,nosuid,nodev 0 0\n'
|
||||
'devpts /dev/pts devpts rw,seclabel,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=000 0 0\n'
|
||||
'tmpfs /run tmpfs rw,seclabel,nosuid,nodev,mode=755 0 0\n'
|
||||
'tmpfs /sys/fs/cgroup tmpfs ro,seclabel,nosuid,nodev,noexec,mode=755 0 0\n'
|
||||
'pstore /sys/fs/pstore pstore rw,seclabel,nosuid,nodev,noexec,relatime 0 0\n'
|
||||
'cgroup /sys/fs/cgroup/devices cgroup rw,nosuid,nodev,noexec,relatime,devices 0 0\n'
|
||||
'cgroup /sys/fs/cgroup/perf_event cgroup rw,nosuid,nodev,noexec,relatime,perf_event 0 0\n'
|
||||
'cgroup /sys/fs/cgroup/net_cls,net_prio cgroup rw,nosuid,nodev,noexec,relatime,net_cls,net_prio 0 0\n'
|
||||
'cgroup /sys/fs/cgroup/cpu,cpuacct cgroup rw,nosuid,nodev,noexec,relatime,cpu,cpuacct 0 0\n'
|
||||
'cgroup /sys/fs/cgroup/blkio cgroup rw,nosuid,nodev,noexec,relatime,blkio 0 0\n'
|
||||
'cgroup /sys/fs/cgroup/cpuset cgroup rw,nosuid,nodev,noexec,relatime,cpuset 0 0\n'
|
||||
'cgroup /sys/fs/cgroup/freezer cgroup rw,nosuid,nodev,noexec,relatime,freezer 0 0\n'
|
||||
'cgroup /sys/fs/cgroup/memory cgroup rw,nosuid,nodev,noexec,relatime,memory 0 0\n'
|
||||
'cgroup /sys/fs/cgroup/hugetlb cgroup rw,nosuid,nodev,noexec,relatime,hugetlb 0 0\n'
|
||||
'configfs /sys/kernel/config configfs rw,relatime 0 0\n'
|
||||
)))
|
||||
|
||||
|
||||
def get_temp_dir_root():
|
||||
return path.join(gettempdir(), 'koji_tests')
|
||||
|
||||
|
||||
def get_tmp_dir_path(folder_starts_with):
|
||||
return path.join(get_temp_dir_root(), ('{0}{1}'.format(folder_starts_with, random.randint(1, 999999999999))))
|
||||
|
||||
|
||||
class TestTask(BaseTaskHandler):
|
||||
Methods = ['some_method']
|
||||
_taskWeight = 5.2
|
||||
|
||||
def handler(self, *args):
|
||||
return 42
|
||||
|
||||
|
||||
class TestTaskNoWeight(BaseTaskHandler):
|
||||
Methods = ['some_method']
|
||||
|
||||
def handler(self, *args):
|
||||
return 42
|
||||
|
||||
|
||||
class BadTask(BaseTaskHandler):
|
||||
Methods = ['some_method']
|
||||
|
||||
|
||||
class TasksTestCase(TestCase):
|
||||
|
||||
def tearDown(self):
|
||||
temp_dir_root = get_temp_dir_root()
|
||||
|
||||
if path.isdir(temp_dir_root):
|
||||
rmtree(get_temp_dir_root())
|
||||
|
||||
def test_scan_mounts_results(self):
|
||||
""" Tests the scan_mounts function with a mocked /proc/mounts file. A list containing mount points
|
||||
starting with /dev are expected to be returned from the function based on the function input of /dev.
|
||||
"""
|
||||
fake_mounts_file_contents = get_fake_mounts_file()
|
||||
|
||||
with patch('{0}.open'.format(__name__), return_value=fake_mounts_file_contents, create=True):
|
||||
self.assertIn(scan_mounts('/dev'), [['/dev/shm', '/dev/pts', '/dev/mqueue', '/dev/hugepages', '/dev'],
|
||||
['/dev/shm', '/dev/pts', '/dev/mqueue', '/dev/console', '/dev']])
|
||||
|
||||
def test_scan_mounts_no_results(self):
|
||||
""" Tests the scan_mounts function with a mocked /proc/mounts file. An argument of /nonexistent/path
|
||||
to the function should return an empty list.
|
||||
"""
|
||||
fake_mounts_file_contents = get_fake_mounts_file()
|
||||
|
||||
with patch('{0}.open'.format(__name__), return_value=fake_mounts_file_contents, create=True):
|
||||
self.assertEquals(scan_mounts('/nonexistent/path'), [])
|
||||
|
||||
# Patching the scan_mounts function instead of the built-in open function because this is only testing umount_all
|
||||
@patch('koji.tasks.scan_mounts', side_effect=[['/dev/shm', '/dev/pts', '/dev/mqueue'], []])
|
||||
@patch('os.spawnvp', return_value=0)
|
||||
def test_umount_all(self, mocked_spawnvp, mocked_scan_mounts):
|
||||
""" Tests that umount_all returns nothing when successful.
|
||||
"""
|
||||
self.assertEquals(umount_all('/test'), None)
|
||||
|
||||
# Patching the scan_mounts function instead of the built-in open function because this is only testing umount_all
|
||||
@patch('koji.tasks.scan_mounts', return_value=['/dev/shm', '/dev/pts', '/dev/mqueue'])
|
||||
@patch('os.spawnvp', return_value=1)
|
||||
def test_umount_all_failure(self, mocked_spawnvp, mocked_scan_mounts):
|
||||
""" Tests that umount_all raises an exception when a mount point can't be unmounted.
|
||||
"""
|
||||
try:
|
||||
umount_all('/dev')
|
||||
raise Exception('A GenericError was not raised during the test')
|
||||
except koji.GenericError as e:
|
||||
self.assertEquals(e.args[0],
|
||||
'umount failed (exit code 1) for /dev/shm')
|
||||
|
||||
# Patching the scan_mounts function instead of the built-in open function because this is only testing umount_all
|
||||
@patch('koji.tasks.scan_mounts', side_effect=[['/dev/shm', '/dev/pts', '/dev/mqueue'], ['/dev/shm', '/dev/mqueue']])
|
||||
@patch('os.spawnvp', return_value=0)
|
||||
def test_umount_all_unexpected_failure(self, mocked_spawnvp, mocked_scan_mounts):
|
||||
""" Tests that umount_all will fail if the command to unmount the mount points was successful
|
||||
but a second run of scan_mounts still shows some of the unmount mount points still mounted.
|
||||
"""
|
||||
try:
|
||||
umount_all('/dev')
|
||||
raise Exception('A GenericError was not raised during the test')
|
||||
except koji.GenericError as e:
|
||||
self.assertEquals(e.args[0], 'Unmounting incomplete: [\'/dev/shm\', \'/dev/mqueue\']')
|
||||
|
||||
@patch('os.path.isfile', return_value=True)
|
||||
@patch('os.remove')
|
||||
def test_safe_rmtree_file(self, mock_remove, mock_isfile):
|
||||
""" Tests that the safe_rmtree function returns nothing when the path parameter is a file.
|
||||
"""
|
||||
self.assertEquals(safe_rmtree('/mnt/folder/some_file', False, True), None)
|
||||
|
||||
@patch('os.path.isfile', return_value=False)
|
||||
@patch('os.path.islink', return_value=True)
|
||||
@patch('os.remove')
|
||||
def test_safe_rmtree_link(self, mock_remove, mock_islink, mock_isfile):
|
||||
""" Tests that the safe_rmtree function returns nothing when the path parameter is a link.
|
||||
"""
|
||||
self.assertEquals(safe_rmtree('/mnt/folder/some_link', False, True), None)
|
||||
|
||||
@patch('os.path.isfile', return_value=False)
|
||||
@patch('os.path.islink', return_value=False)
|
||||
@patch('os.path.exists', return_value=False)
|
||||
def test_safe_rmtree_does_not_exist(self, mock_exists, mock_islink, mock_isfile):
|
||||
""" Tests that the safe_rmtree function returns nothing if the path does not exist.
|
||||
"""
|
||||
self.assertEquals(safe_rmtree('/mnt/folder/some_file', False, True), None)
|
||||
|
||||
@patch('os.path.isfile', return_value=False)
|
||||
@patch('os.path.islink', return_value=False)
|
||||
@patch('os.path.exists', return_value=True)
|
||||
@patch('os.system', side_effect=[0, 0])
|
||||
def test_safe_rmtree_directory(self, mock_os_system, mock_exists, mock_islink, mock_isfile):
|
||||
""" Tests that the safe_rmtree function returns nothing when the path is a directory.
|
||||
"""
|
||||
self.assertEquals(safe_rmtree('/mnt/folder', False, True), 0)
|
||||
|
||||
@patch('os.path.isfile', return_value=False)
|
||||
@patch('os.path.islink', return_value=False)
|
||||
@patch('os.path.exists', return_value=True)
|
||||
@patch('os.system', side_effect=[1, 0])
|
||||
def test_safe_rmtree_directory_scrub_file_failure(self, mock_os_system, mock_exists, mock_islink, mock_isfile):
|
||||
""" Tests that the safe_rmtree function returns a GeneralException when the path parameter is a directory
|
||||
and the scrub of the files in the directory fails.
|
||||
"""
|
||||
try:
|
||||
safe_rmtree('/mnt/folder', False, True)
|
||||
raise Exception('A GenericError was not raised during the test')
|
||||
except koji.GenericError as e:
|
||||
self.assertEquals(e.args[0], 'file removal failed (code 1) for /mnt/folder')
|
||||
|
||||
@patch('os.path.isfile', return_value=False)
|
||||
@patch('os.path.islink', return_value=False)
|
||||
@patch('os.path.exists', return_value=True)
|
||||
@patch('os.system', side_effect=[0, 1])
|
||||
def test_safe_rmtree_directory_scrub_directory_failure(self, mock_os_system, mock_exists, mock_islink, mock_isfile):
|
||||
""" Tests that the safe_rmtree function returns a GeneralException when the path parameter is a directory
|
||||
and the scrub of the directories in the directory fails.
|
||||
"""
|
||||
try:
|
||||
safe_rmtree('/mnt/folder', False, True)
|
||||
raise Exception('A GenericError was not raised during the test')
|
||||
except koji.GenericError as e:
|
||||
self.assertEquals(e.args[0], 'dir removal failed (code 1) for /mnt/folder')
|
||||
|
||||
def test_BaseTaskHandler_handler_not_set(self):
|
||||
""" Tests that an exception is thrown when the handler function is not overwritten by the child class.
|
||||
"""
|
||||
obj = BadTask(123, 'some_method', ['random_arg'], None, None, (get_tmp_dir_path('BadTask')))
|
||||
try:
|
||||
obj.handler()
|
||||
raise Exception('The NotImplementedError exception was not raised')
|
||||
except NotImplementedError as e:
|
||||
self.assertEquals(e.__class__.__name__, 'NotImplementedError')
|
||||
|
||||
def test_BaseTaskHandler_weight_default(self):
|
||||
""" Tests that the weight function returns 1.0 when _taskWeight is not set in the child class' definition.
|
||||
"""
|
||||
obj = TestTaskNoWeight(123, 'some_method', ['random_arg'], None, None, (get_tmp_dir_path('TestTaskNoWeight')))
|
||||
self.assertEquals(obj.weight(), 1.0)
|
||||
|
||||
def test_BaseTaskHandler_weight_set(self):
|
||||
""" Tests that the weight function returns the value of _taskWeight when it is set in the
|
||||
child class' definition.
|
||||
"""
|
||||
obj = TestTask(123, 'some_method', ['random_arg'], None, None, (get_tmp_dir_path('TestTask')))
|
||||
self.assertEquals(obj.weight(), 5.2)
|
||||
|
||||
def test_BaseTaskHandler_createWorkdir_workdir_not_defined(self):
|
||||
""" Tests that the createWorkdir function does nothing when the workdir member variable is set to None.
|
||||
"""
|
||||
temp_path = get_tmp_dir_path('TestTask')
|
||||
obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path)
|
||||
obj.workdir = None
|
||||
obj.createWorkdir()
|
||||
self.assertEquals(path.isdir(temp_path), False)
|
||||
|
||||
# This patch removes the dependence on removeWorkdir functioning
|
||||
@patch('{0}.TestTask.removeWorkdir'.format(__name__))
|
||||
def test_BaseTaskHandler_createWorkdir(self, mock_removeWorkDir):
|
||||
""" Tests that the createWorkdir function creates a folder based on the path given to the
|
||||
workdir member variable.
|
||||
"""
|
||||
temp_path = get_tmp_dir_path('TestTask')
|
||||
obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path)
|
||||
obj.createWorkdir()
|
||||
self.assertEquals(path.isdir(temp_path), True)
|
||||
rmtree(get_temp_dir_root())
|
||||
|
||||
def test_BaseTaskHandler_removeWorkdir(self):
|
||||
""" Tests that the removeWOrkdir function deletes a folder based on the path given to the
|
||||
workdir member variable.
|
||||
"""
|
||||
temp_path = get_tmp_dir_path('TestTask')
|
||||
obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path)
|
||||
makedirs(temp_path)
|
||||
self.assertEquals(path.isdir(temp_path), True)
|
||||
obj.removeWorkdir()
|
||||
self.assertEquals(path.isdir(temp_path), False)
|
||||
|
||||
def test_BaseTaskHandler_wait_all_done(self):
|
||||
""" Tests that the wait function returns the subtask results of when the taskWait function returns only
|
||||
two finished tasks
|
||||
"""
|
||||
temp_path = get_tmp_dir_path('TestTask')
|
||||
obj = TestTask(12345678, 'some_method', ['random_arg'], None, None, temp_path)
|
||||
makedirs(temp_path)
|
||||
obj.session = Mock()
|
||||
obj.session.host.taskSetWait.return_value = None
|
||||
obj.session.host.taskWait.return_value = [[1551234, 1591234], []]
|
||||
taskWaitResults = [
|
||||
['1551234', {
|
||||
'brootid': 2342345,
|
||||
'logs': ['tasks/5678/12345678/root.log',
|
||||
'tasks/5678/12345678/state.log',
|
||||
'tasks/5678/12345678/build.log'],
|
||||
'srpm': 'tasks/5678/12345678/some_package-1.2.3p5-25.src.rpm'
|
||||
}],
|
||||
|
||||
['1591234', {
|
||||
'brootid': 1231234,
|
||||
'logs': ['tasks/6789/2345678/root.log',
|
||||
'tasks/6789/2345678/state.log',
|
||||
'tasks/6789/2345678/build.log'],
|
||||
'rpms': ['tasks/6789/2345678/some_other_package-doc-1.2.3p5-25.el7.noarch.rpm'],
|
||||
'srpms': ['tasks/6789/2345678/some_other_package-1.2.3p5-25.el7.src.rpm']
|
||||
}]
|
||||
]
|
||||
|
||||
obj.session.host.taskWaitResults.return_value = taskWaitResults
|
||||
self.assertEquals(obj.wait([1551234, 1591234]), dict(taskWaitResults))
|
||||
obj.session.host.taskSetWait.assert_called_once_with(12345678, [1551234, 1591234])
|
||||
obj.session.host.taskWaitResults.assert_called_once_with(12345678, [1551234, 1591234], canfail=[])
|
||||
|
||||
def test_BaseTaskHandler_wait_some_not_done(self):
|
||||
""" Tests that the wait function returns the one finished subtask results of
|
||||
when the taskWait function returns one finished task and one unfinished
|
||||
"""
|
||||
temp_path = get_tmp_dir_path('TestTask')
|
||||
obj = TestTask(12345678, 'some_method', ['random_arg'], None, None, temp_path)
|
||||
makedirs(temp_path)
|
||||
obj.session = Mock()
|
||||
obj.session.host.taskSetWait.return_value = None
|
||||
obj.session.host.taskWait.return_value = [[1551234], [1591234]]
|
||||
taskWaitResults = [
|
||||
['1551234', {
|
||||
'brootid': 2342345,
|
||||
'logs': ['tasks/5678/12345678/root.log',
|
||||
'tasks/5678/12345678/state.log',
|
||||
'tasks/5678/12345678/build.log'],
|
||||
'srpm': 'tasks/5678/12345678/some_package-1.2.3p5-25.src.rpm'
|
||||
}]
|
||||
]
|
||||
|
||||
obj.session.host.taskWaitResults.return_value = taskWaitResults
|
||||
self.assertEquals(obj.wait([1551234, 1591234]), dict(taskWaitResults))
|
||||
obj.session.host.taskSetWait.assert_called_once_with(12345678, [1551234, 1591234])
|
||||
obj.session.host.taskWaitResults.assert_called_once_with(12345678, [1551234], canfail=[])
|
||||
|
||||
@patch('signal.pause', return_value=None)
|
||||
def test_BaseTaskHandler_wait_some_not_done_all_set(self, mock_signal_pause):
|
||||
""" Tests that the wait function returns the two subtask results since the all kwarg is set to True.
|
||||
The taskWait function should first return one finished and one unfinished task, then the second time it should
|
||||
return two finished tasks.
|
||||
"""
|
||||
temp_path = get_tmp_dir_path('TestTask')
|
||||
obj = TestTask(12345678, 'some_method', ['random_arg'], None, None, temp_path)
|
||||
makedirs(temp_path)
|
||||
obj.session = Mock()
|
||||
obj.session.host.taskSetWait.return_value = None
|
||||
obj.session.host.taskWait.side_effect = [[[1551234], [1591234]], [[1551234, 1591234], []]]
|
||||
taskWaitResults = [
|
||||
['1551234', {
|
||||
'brootid': 2342345,
|
||||
'logs': ['tasks/5678/12345678/root.log',
|
||||
'tasks/5678/12345678/state.log',
|
||||
'tasks/5678/12345678/build.log'],
|
||||
'srpm': 'tasks/5678/12345678/some_package-1.2.3p5-25.src.rpm'
|
||||
}],
|
||||
|
||||
['1591234', {
|
||||
'brootid': 1231234,
|
||||
'logs': ['tasks/6789/2345678/root.log',
|
||||
'tasks/6789/2345678/state.log',
|
||||
'tasks/6789/2345678/build.log'],
|
||||
'rpms': ['tasks/6789/2345678/some_other_package-doc-1.2.3p5-25.el7.noarch.rpm'],
|
||||
'srpms': ['tasks/6789/2345678/some_other_package-1.2.3p5-25.el7.src.rpm']
|
||||
}]
|
||||
]
|
||||
|
||||
obj.session.getTaskResult.side_effect
|
||||
|
||||
obj.session.host.taskWaitResults.return_value = taskWaitResults
|
||||
self.assertEquals(obj.wait([1551234, 1591234], all=True), dict(taskWaitResults))
|
||||
obj.session.host.taskSetWait.assert_called_once_with(12345678, [1551234, 1591234])
|
||||
obj.session.host.taskWait.assert_has_calls([call(12345678), call(12345678)])
|
||||
mock_signal_pause.assert_called_once_with()
|
||||
obj.session.host.taskWaitResults.assert_called_once_with(12345678, [1551234, 1591234], canfail=[])
|
||||
|
||||
def test_BaseTaskHandler_wait_some_not_done_all_set_failany_set_failed_task(self):
|
||||
""" Tests that the wait function raises an exception when one of the subtask fails when the failany flag is set
|
||||
to True.
|
||||
"""
|
||||
temp_path = get_tmp_dir_path('TestTask')
|
||||
obj = TestTask(12345678, 'some_method', ['random_arg'], None, None, temp_path)
|
||||
makedirs(temp_path)
|
||||
obj.session = Mock()
|
||||
obj.session.host.taskSetWait.return_value = None
|
||||
obj.session.host.taskWait.side_effect = [[[1551234], [1591234]], [[1551234, 1591234], []]]
|
||||
obj.session.getTaskResult.side_effect = koji.GenericError('Uh oh, we\'ve got a problem here!')
|
||||
try:
|
||||
obj.wait([1551234, 1591234], all=True, failany=True)
|
||||
raise Exception('A GeneralError was not raised.')
|
||||
except koji.GenericError as e:
|
||||
self.assertEquals(e.args[0], 'Uh oh, we\'ve got a problem here!')
|
||||
obj.session.host.taskSetWait.assert_called_once_with(12345678, [1551234, 1591234])
|
||||
|
||||
def test_BaseTaskHandler_getUploadDir(self):
|
||||
""" Tests that the getUploadDir function returns the appropriate path based on the id of the handler.
|
||||
"""
|
||||
temp_path = get_tmp_dir_path('TestTask')
|
||||
obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path)
|
||||
self.assertEquals(obj.getUploadDir(), 'tasks/123/123')
|
||||
|
||||
# This patch removes the dependence on getUploadDir functioning
|
||||
@patch('{0}.TestTask.getUploadDir'.format(__name__), return_value='tasks/123/123')
|
||||
def test_BaseTaskHandler_uploadFile(self, mock_getUploadDir):
|
||||
""" Tests that the uploadFile function calls the uploadWrapper function on the session member variable
|
||||
with the correct input
|
||||
"""
|
||||
temp_path = get_tmp_dir_path('TestTask')
|
||||
makedirs(temp_path)
|
||||
temp_file = path.join(temp_path, 'test.txt')
|
||||
with open(temp_file, 'w') as temp_file_handler:
|
||||
temp_file_handler.write('Test')
|
||||
|
||||
obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path)
|
||||
obj.session = Mock()
|
||||
self.assertEquals(obj.uploadFile(temp_file), None)
|
||||
obj.session.uploadWrapper.assert_called_once_with(temp_file, 'tasks/123/123', None, volume=None)
|
||||
|
||||
# This patch removes the dependence on getUploadDir functioning
|
||||
@patch('{0}.TestTask.getUploadDir'.format(__name__), return_value='tasks/123/123')
|
||||
def test_BaseTaskHandler_uploadFile_no_content(self, mock_getUploadDir):
|
||||
""" Tests that the uploadFile function calls the uploadWrapper function on the session member variable
|
||||
without including empty files.
|
||||
"""
|
||||
temp_path = get_tmp_dir_path('TestTask')
|
||||
makedirs(temp_path)
|
||||
|
||||
temp_file = path.join(temp_path, 'test.txt')
|
||||
temp_file_handler = open(temp_file, 'w')
|
||||
temp_file_handler.close()
|
||||
|
||||
obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path)
|
||||
obj.session = Mock()
|
||||
self.assertEquals(obj.uploadFile(temp_file), None)
|
||||
self.assertEquals(obj.session.uploadWrapper.called, False)
|
||||
|
||||
def test_BaseTaskHandler_uploadTree(self):
|
||||
""" Tests that the uploadTree function calls the uploadFile function with the correct parameters.
|
||||
"""
|
||||
temp_path = get_tmp_dir_path('TestTask')
|
||||
makedirs(temp_path)
|
||||
|
||||
dummy_dir = path.join(temp_path, 'some_directory')
|
||||
makedirs(dummy_dir)
|
||||
|
||||
dummy_file = path.join(temp_path, 'test.txt')
|
||||
with open(dummy_file, 'w') as temp_file_handler:
|
||||
temp_file_handler.write('Test')
|
||||
|
||||
dummy_file2 = path.join(dummy_dir, 'test2.txt')
|
||||
with open(dummy_file2, 'w') as temp_file_handler2:
|
||||
temp_file_handler2.write('Test2')
|
||||
|
||||
obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path)
|
||||
obj.uploadFile = Mock()
|
||||
obj.uploadFile.return_value = None
|
||||
self.assertEquals(obj.uploadTree(temp_path), None)
|
||||
obj.uploadFile.assert_has_calls([call(dummy_file, '', volume=None), call(dummy_file2, 'some_directory', volume=None)])
|
||||
|
||||
@patch('os.lchown', return_value=None)
|
||||
def test_BaseTaskHandler_chownTree(self, mock_lchown):
|
||||
""" Tests that the chownTree functions as expected on dummy files created in a temp directory
|
||||
"""
|
||||
temp_path = get_tmp_dir_path('TestTask')
|
||||
makedirs(temp_path)
|
||||
|
||||
dummy_file = path.join(temp_path, 'test.txt')
|
||||
dummy_file_handler = open(dummy_file, 'w')
|
||||
dummy_file_handler.close()
|
||||
|
||||
dummy_file2 = path.join(temp_path, 'test2.txt')
|
||||
dummy_file_handler2 = open(dummy_file2, 'w')
|
||||
dummy_file_handler2.close()
|
||||
|
||||
obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path)
|
||||
self.assertEquals(obj.chownTree(temp_path, 2, 0), None)
|
||||
mock_lchown.assert_has_calls([call(temp_path, 2, 0), call(dummy_file2, 2, 0), call(dummy_file, 2, 0)], any_order=True)
|
||||
|
||||
def test_BaseTaskHandler_localPath_file_exists(self):
|
||||
""" Tests the localPath function to ensure that when a file exists, it returns that path without
|
||||
trying to download it.
|
||||
"""
|
||||
temp_path = get_tmp_dir_path('TestTask')
|
||||
makedirs(temp_path)
|
||||
|
||||
local_folder = path.join(temp_path, 'local')
|
||||
makedirs(local_folder)
|
||||
|
||||
dummy_file = path.join(local_folder, 'test.txt')
|
||||
dummy_file_handler = open(dummy_file, 'w')
|
||||
dummy_file_handler.close()
|
||||
options = Mock()
|
||||
options.topurl = 'https://www.domain.local'
|
||||
obj = TestTask(123, 'some_method', ['random_arg'], None, options, temp_path)
|
||||
self.assertEquals(obj.localPath('test.txt'), dummy_file)
|
||||
|
||||
@patch('six.moves.urllib.request.urlopen', return_value=six.StringIO(six.text_type('Important things\nSome more important things\n')))
|
||||
def test_BaseTaskHandler_localPath_no_file(self, mock_urlopen):
|
||||
"""
|
||||
"""
|
||||
temp_path = get_tmp_dir_path('TestTask')
|
||||
makedirs(temp_path)
|
||||
|
||||
local_folder = path.join(temp_path, 'local')
|
||||
makedirs(local_folder)
|
||||
|
||||
target_file_path = path.join(local_folder, 'test.txt')
|
||||
|
||||
options = Mock()
|
||||
options.topurl = 'https://www.domain.local'
|
||||
obj = TestTask(123, 'some_method', ['random_arg'], None, options, temp_path)
|
||||
|
||||
self.assertEquals(obj.localPath('test.txt'), target_file_path)
|
||||
mock_urlopen.assert_called_once_with('https://www.domain.local/test.txt')
|
||||
|
||||
def test_BaseTaskHandler_localPath_no_topurl(self):
|
||||
""" Tests that the localPath function returns a path when options.topurl is not defined.
|
||||
"""
|
||||
temp_path = get_tmp_dir_path('TestTask')
|
||||
makedirs(temp_path)
|
||||
|
||||
options = Mock()
|
||||
options.topurl = None
|
||||
options.topdir = get_temp_dir_root()
|
||||
obj = TestTask(123, 'some_method', ['random_arg'], None, options, temp_path)
|
||||
|
||||
self.assertEquals(obj.localPath('test.txt'), path.join(get_temp_dir_root(), 'test.txt'))
|
||||
|
||||
def test_BaseTaskHandler_find_arch(self):
|
||||
""" Tests that the find_arch function returns the input for arch when the input is not "noarch".
|
||||
"""
|
||||
temp_path = get_tmp_dir_path('TestTask')
|
||||
makedirs(temp_path)
|
||||
obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path)
|
||||
self.assertEquals(obj.find_arch('x86_64', None, None), 'x86_64')
|
||||
|
||||
def test_BaseTaskHandler_find_arch_noarch_bad_host(self):
|
||||
""" Tests that the find_arch function raises an exception when the host parameter doesn't contain a
|
||||
value for the arches key.
|
||||
"""
|
||||
temp_path = get_tmp_dir_path('TestTask')
|
||||
makedirs(temp_path)
|
||||
host = {'arches': None, 'name': 'test.domain.local'}
|
||||
obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path)
|
||||
try:
|
||||
obj.find_arch('noarch', host, None)
|
||||
raise Exception('The BuildError Exception was not raised')
|
||||
except koji.BuildError as e:
|
||||
self.assertEquals(e.args[0], 'No arch list for this host: test.domain.local')
|
||||
|
||||
def test_BaseTaskHandler_find_arch_noarch_bad_tag(self):
|
||||
""" Tests that the find_arch function raises an exception when the tag parameter doesn't contain a
|
||||
value for the arches key.
|
||||
"""
|
||||
temp_path = get_tmp_dir_path('TestTask')
|
||||
makedirs(temp_path)
|
||||
host = {'arches': 'x86_64', 'name': 'test.domain.local'}
|
||||
tag = {'arches': None, 'name': 'some_package-1.2-build'}
|
||||
obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path)
|
||||
try:
|
||||
obj.find_arch('noarch', host, tag)
|
||||
raise Exception('The BuildError Exception was not raised')
|
||||
except koji.BuildError as e:
|
||||
self.assertEquals(e.args[0], 'No arch list for tag: some_package-1.2-build')
|
||||
|
||||
def test_BaseTaskHandler_find_arch_noarch(self):
|
||||
""" Tests that the find_arch function finds a match of x86_64 when the host only supports x86_64
|
||||
and the tag supports x86_64 and aarch64.
|
||||
"""
|
||||
temp_path = get_tmp_dir_path('TestTask')
|
||||
makedirs(temp_path)
|
||||
host = {'arches': 'x86_64', 'name': 'test.domain.local'}
|
||||
tag = {'arches': 'x86_64 aarch64', 'name': 'some_package-1.2-build'}
|
||||
obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path)
|
||||
self.assertEquals(obj.find_arch('noarch', host, tag), 'x86_64')
|
||||
|
||||
def test_BaseTaskHandler_find_arch__noarch_no_match(self):
|
||||
""" Tests that the find_arch function raises an exception when there isn't a common arch supported between
|
||||
the host and the tag.
|
||||
"""
|
||||
temp_path = get_tmp_dir_path('TestTask')
|
||||
makedirs(temp_path)
|
||||
host = {'arches': 'i386', 'name': 'test.domain.local'}
|
||||
tag = {'arches': 'x86_64 aarch64', 'name': 'some_package-1.2-build'}
|
||||
obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path)
|
||||
try:
|
||||
obj.find_arch('noarch', host, tag)
|
||||
raise Exception('The BuildError Exception was not raised')
|
||||
except koji.BuildError as e:
|
||||
self.assertEquals(e.args[0], ('host test.domain.local (i386) does not support '
|
||||
'any arches of tag some_package-1.2-build (aarch64, x86_64)'))
|
||||
|
||||
def test_getRepo_tied_to_session(self):
|
||||
""" Tests that the getRepo function calls session.getRepo(), and returns the result when successful
|
||||
"""
|
||||
temp_path = get_tmp_dir_path('TestTask')
|
||||
makedirs(temp_path)
|
||||
|
||||
repo_dict = {
|
||||
'create_event': 13635166,
|
||||
'create_ts': 1469039671.5743899,
|
||||
'creation_time': '2016-07-20 18:34:31.574386',
|
||||
'id': 1630631,
|
||||
'state': 1
|
||||
}
|
||||
|
||||
obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path)
|
||||
obj.session = Mock()
|
||||
obj.session.getRepo.return_value = repo_dict
|
||||
|
||||
self.assertEquals(obj.getRepo(8472), repo_dict)
|
||||
|
||||
@patch('{0}.TestTask.wait'.format(__name__))
|
||||
def test_getRepo_not_tied_to_session(self, mock_wait):
|
||||
""" Tests that the getRepo function waits until the results are available for session.getRepo, when it is
|
||||
not available at the start of the function call.
|
||||
"""
|
||||
temp_path = get_tmp_dir_path('TestTask')
|
||||
makedirs(temp_path)
|
||||
|
||||
repo_dict = {
|
||||
'create_event': 13413120,
|
||||
'create_ts': 1466140834.9119599,
|
||||
'creation_time': '2016-06-17 05:20:34.911962',
|
||||
'id': 1592850,
|
||||
'state': 1
|
||||
}
|
||||
|
||||
obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path)
|
||||
obj.session = Mock()
|
||||
obj.session.getRepo.return_value = None
|
||||
obj.session.getTag.return_value = {
|
||||
'arches': 'i386 ia64 x86_64 ppc s390 s390x ppc64',
|
||||
'extra': {},
|
||||
'id': 851,
|
||||
'locked': True,
|
||||
'maven_include_all': False,
|
||||
'maven_support': False,
|
||||
'name': 'dist-3.0E-build',
|
||||
'perm': None,
|
||||
'perm_id': None
|
||||
}
|
||||
obj.session.getBuildTargets.return_value = [{
|
||||
'build_tag': 3093,
|
||||
'build_tag_name': 'dist-6E-dsrv-9-build',
|
||||
'dest_tag': 3092,
|
||||
'dest_tag_name': 'dist-6E-dsrv-9-qu-candidate',
|
||||
'id': 851,
|
||||
'name': 'dist-6E-dsrv-9-qu-candidate'
|
||||
}]
|
||||
|
||||
obj.session.host.subtask.return_value = 123
|
||||
mock_wait.return_value = {123: repo_dict}
|
||||
|
||||
self.assertEquals(obj.getRepo(851), repo_dict)
|
||||
obj.session.getRepo.assert_called_once_with(851)
|
||||
obj.session.getTag.assert_called_once_with(851, strict=True)
|
||||
|
||||
@patch('{0}.TestTask.wait'.format(__name__))
|
||||
def test_getRepo_not_tied_to_session_no_build_targets(self, mock_wait):
|
||||
""" Tests that the getRepo function raises an exception when session.getBuildTargets returns an empty list
|
||||
"""
|
||||
temp_path = get_tmp_dir_path('TestTask')
|
||||
makedirs(temp_path)
|
||||
|
||||
obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path)
|
||||
obj.session = Mock()
|
||||
obj.session.getRepo.return_value = None
|
||||
obj.session.getTag.return_value = {
|
||||
'arches': 'i686 x86_64 ppc ppc64 ppc64le s390 s390x aarch64',
|
||||
'extra': {},
|
||||
'id': 8472,
|
||||
'locked': False,
|
||||
'maven_include_all': False,
|
||||
'maven_support': False,
|
||||
'name': 'rhel-7.3-build',
|
||||
'perm': 'admin',
|
||||
'perm_id': 1
|
||||
}
|
||||
obj.session.getBuildTargets.return_value = []
|
||||
|
||||
try:
|
||||
obj.getRepo(8472)
|
||||
raise Exception('The BuildError Exception was not raised')
|
||||
except koji.BuildError as e:
|
||||
obj.session.getRepo.assert_called_once_with(8472)
|
||||
self.assertEquals(e.args[0], 'no repo (and no target) for tag rhel-7.3-build')
|
||||
|
||||
def test_FakeTask_handler(self):
|
||||
""" Tests that the FakeTest handler can be instantiated and returns 42 when run
|
||||
"""
|
||||
obj = FakeTask(123, 'someMethod', ['random_arg'], None, None, (get_tmp_dir_path('FakeTask')))
|
||||
self.assertEquals(obj.run(), 42)
|
||||
|
||||
@patch('time.sleep')
|
||||
def test_SleepTask_handler(self, mock_sleep):
|
||||
""" Tests that the SleepTask handler can be instantiated and runs appropriately based on the input
|
||||
"""
|
||||
obj = SleepTask(123, 'sleep', [5], None, None, (get_tmp_dir_path('SleepTask')))
|
||||
obj.run()
|
||||
mock_sleep.assert_called_once_with(5)
|
||||
|
||||
@patch('os.spawnvp')
|
||||
def test_ForkTask_handler(self, mock_spawnvp):
|
||||
""" Tests that the ForkTask handler can be instantiated and runs appropriately based on the input
|
||||
"""
|
||||
obj = ForkTask(123, 'fork', [1, 20], None, None, (get_tmp_dir_path('ForkTask')))
|
||||
obj.run()
|
||||
mock_spawnvp.assert_called_once_with(1, 'sleep', ['sleep', '20'])
|
||||
|
||||
@patch('signal.pause', return_value=None)
|
||||
@patch('time.sleep')
|
||||
def test_WaitTestTask_handler(self, mock_sleep, mock_signal_pause):
|
||||
""" Tests that the WaitTestTask handler can be instantiated and runs appropriately based on the input
|
||||
Specifically, that forking works and canfail behaves correctly.
|
||||
"""
|
||||
self.mock_subtask_id = 1
|
||||
def mock_subtask(method, arglist, id, **opts):
|
||||
self.assertEqual(method, 'sleep')
|
||||
task_id = self.mock_subtask_id
|
||||
self.mock_subtask_id += 1
|
||||
obj = SleepTask(task_id, 'sleep', arglist, None, None, (get_tmp_dir_path('SleepTask')))
|
||||
obj.run()
|
||||
return task_id
|
||||
|
||||
mock_taskWait = [
|
||||
[[], [1, 2, 3, 4]],
|
||||
[[3, 4], [1, 2]],
|
||||
[[1, 2, 3, 4], []],
|
||||
]
|
||||
def mock_getTaskResult(task_id):
|
||||
if task_id == 4:
|
||||
raise koji.GenericError()
|
||||
|
||||
|
||||
obj = WaitTestTask(123, 'waittest', [3], None, None, (get_tmp_dir_path('WaitTestTask')))
|
||||
obj.session = Mock()
|
||||
obj.session.host.subtask.side_effect = mock_subtask
|
||||
obj.session.getTaskResult.side_effect = mock_getTaskResult
|
||||
obj.session.host.taskWait.side_effect = mock_taskWait
|
||||
obj.session.host.taskWaitResults.return_value = [ ['1', {}], ['2', {}], ['3', {}], ['4', {}], ]
|
||||
obj.run()
|
||||
#self.assertEqual(mock_sleep.call_count, 4)
|
||||
obj.session.host.taskSetWait.assert_called_once()
|
||||
obj.session.host.taskWait.assert_has_calls([call(123), call(123), call(123)])
|
||||
# getTaskResult should be called in 2nd round only for task 3, as 4
|
||||
# will be skipped as 'canfail'
|
||||
obj.session.getTaskResult.assert_has_calls([call(3)])
|
||||
493
tests/test_lib/test_utils.py
Normal file
493
tests/test_lib/test_utils.py
Normal file
|
|
@ -0,0 +1,493 @@
|
|||
from __future__ import absolute_import
|
||||
import mock
|
||||
import unittest
|
||||
from mock import call
|
||||
|
||||
import os
|
||||
import optparse
|
||||
import six.moves.configparser
|
||||
import koji
|
||||
import koji.util
|
||||
|
||||
|
||||
class EnumTestCase(unittest.TestCase):
|
||||
|
||||
def test_enum_create_alpha(self):
|
||||
""" Test that we can create an Enum with alphabet names """
|
||||
koji.Enum(('one', 'two', 'three'))
|
||||
|
||||
def test_enum_bracket_access(self):
|
||||
""" Test bracket access. """
|
||||
test = koji.Enum(('one', 'two', 'three'))
|
||||
self.assertEquals(test['one'], 0)
|
||||
self.assertEquals(test['two'], 1)
|
||||
self.assertEquals(test['three'], 2)
|
||||
|
||||
with self.assertRaises(KeyError):
|
||||
test['does not exist']
|
||||
|
||||
def test_enum_getter_access(self):
|
||||
""" Test getter access. """
|
||||
test = koji.Enum(('one', 'two', 'three'))
|
||||
self.assertEquals(test.get('one'), 0)
|
||||
self.assertEquals(test.get('two'), 1)
|
||||
self.assertEquals(test.get('three'), 2)
|
||||
self.assertEquals(test.get('does not exist'), None)
|
||||
|
||||
def test_enum_slice_access(self):
|
||||
""" Test slice access. """
|
||||
test = koji.Enum(('one', 'two', 'three'))
|
||||
self.assertEquals(test[1:], ('two', 'three'))
|
||||
|
||||
|
||||
def mock_open():
|
||||
"""Return the right patch decorator for open"""
|
||||
if six.PY2:
|
||||
return mock.patch('__builtin__.open')
|
||||
else:
|
||||
return mock.patch('builtins.open')
|
||||
|
||||
|
||||
class MiscFunctionTestCase(unittest.TestCase):
|
||||
|
||||
@mock.patch('os.path.exists')
|
||||
@mock.patch('os.path.islink')
|
||||
@mock.patch('shutil.move')
|
||||
def test_safer_move(self, move, islink, exists):
|
||||
"""Test safer_move function"""
|
||||
src = '/FAKEPATH/SRC'
|
||||
dst = '/FAKEPATH/DST'
|
||||
|
||||
# good args
|
||||
exists.return_value = False
|
||||
islink.return_value = False
|
||||
koji.util.safer_move(src, dst)
|
||||
exists.assert_called_once_with(dst)
|
||||
islink.assert_called_once_with(dst)
|
||||
move.assert_called_once_with(src, dst)
|
||||
|
||||
move.reset_mock()
|
||||
islink.reset_mock()
|
||||
exists.reset_mock()
|
||||
|
||||
# existing dst
|
||||
exists.return_value = True
|
||||
with self.assertRaises(koji.GenericError):
|
||||
koji.util.safer_move(src, dst)
|
||||
exists.assert_called_once_with(dst)
|
||||
move.assert_not_called()
|
||||
|
||||
move.reset_mock()
|
||||
islink.reset_mock()
|
||||
exists.reset_mock()
|
||||
|
||||
# symlink dst
|
||||
exists.return_value = False
|
||||
islink.return_value = True
|
||||
with self.assertRaises(koji.GenericError):
|
||||
koji.util.safer_move(src, dst)
|
||||
exists.assert_called_once_with(dst)
|
||||
islink.assert_called_once_with(dst)
|
||||
move.assert_not_called()
|
||||
|
||||
@mock_open()
|
||||
@mock.patch('six.moves.urllib.request.urlopen')
|
||||
@mock.patch('tempfile.TemporaryFile')
|
||||
@mock.patch('shutil.copyfileobj')
|
||||
def test_openRemoteFile(self, m_copyfileobj, m_TemporaryFile,
|
||||
m_urlopen, m_open):
|
||||
"""Test openRemoteFile function"""
|
||||
|
||||
mocks = [m_open, m_copyfileobj, m_TemporaryFile, m_urlopen]
|
||||
|
||||
topurl = 'http://example.com/koji'
|
||||
path = 'relative/file/path'
|
||||
url = 'http://example.com/koji/relative/file/path'
|
||||
|
||||
# using topurl, no tempfile
|
||||
fo = koji.openRemoteFile(path, topurl)
|
||||
m_urlopen.assert_called_once_with(url)
|
||||
m_urlopen.return_value.close.assert_called_once()
|
||||
m_TemporaryFile.assert_called_once_with(dir=None)
|
||||
m_copyfileobj.assert_called_once()
|
||||
m_open.assert_not_called()
|
||||
assert fo is m_TemporaryFile.return_value
|
||||
|
||||
for m in mocks:
|
||||
m.reset_mock()
|
||||
|
||||
# using topurl + tempfile
|
||||
tempdir = '/tmp/koji/1234'
|
||||
fo = koji.openRemoteFile(path, topurl, tempdir=tempdir)
|
||||
m_urlopen.assert_called_once_with(url)
|
||||
m_urlopen.return_value.close.assert_called_once()
|
||||
m_TemporaryFile.assert_called_once_with(dir=tempdir)
|
||||
m_copyfileobj.assert_called_once()
|
||||
m_open.assert_not_called()
|
||||
assert fo is m_TemporaryFile.return_value
|
||||
|
||||
for m in mocks:
|
||||
m.reset_mock()
|
||||
|
||||
# using topdir
|
||||
topdir = '/mnt/mykojidir'
|
||||
filename = '/mnt/mykojidir/relative/file/path'
|
||||
fo = koji.openRemoteFile(path, topdir=topdir)
|
||||
m_urlopen.assert_not_called()
|
||||
m_TemporaryFile.assert_not_called()
|
||||
m_copyfileobj.assert_not_called()
|
||||
m_open.assert_called_once_with(filename)
|
||||
assert fo is m_open.return_value
|
||||
|
||||
for m in mocks:
|
||||
m.reset_mock()
|
||||
|
||||
# using neither
|
||||
with self.assertRaises(koji.GenericError):
|
||||
koji.openRemoteFile(path)
|
||||
for m in mocks:
|
||||
m.assert_not_called()
|
||||
|
||||
|
||||
class MavenUtilTestCase(unittest.TestCase):
|
||||
"""Test maven relative functions"""
|
||||
maxDiff = None
|
||||
|
||||
def test_maven_config_opt_adapter(self):
|
||||
"""Test class MavenConfigOptAdapter"""
|
||||
conf = mock.MagicMock()
|
||||
section = 'section'
|
||||
adapter = koji.util.MavenConfigOptAdapter(conf, section)
|
||||
self.assertIs(adapter._conf, conf)
|
||||
self.assertIs(adapter._section, section)
|
||||
conf.has_option.return_value = True
|
||||
adapter.goals
|
||||
adapter.properties
|
||||
adapter.someattr
|
||||
conf.has_option.return_value = False
|
||||
with self.assertRaises(AttributeError) as cm:
|
||||
adapter.noexistsattr
|
||||
self.assertEquals(cm.exception.args[0], 'noexistsattr')
|
||||
self.assertEquals(conf.mock_calls, [call.has_option(section, 'goals'),
|
||||
call.get(section, 'goals'),
|
||||
call.get().split(),
|
||||
call.has_option(section, 'properties'),
|
||||
call.get(section, 'properties'),
|
||||
call.get().splitlines(),
|
||||
call.has_option(section, 'someattr'),
|
||||
call.get('section', 'someattr'),
|
||||
call.has_option(section, 'noexistsattr')])
|
||||
|
||||
def test_maven_opts(self):
|
||||
"""Test maven_opts function"""
|
||||
values = optparse.Values({
|
||||
'scmurl': 'scmurl',
|
||||
'patches': 'patchurl',
|
||||
'specfile': 'specfile',
|
||||
'goals': ['goal1', 'goal2'],
|
||||
'profiles': ['profile1', 'profile2'],
|
||||
'packages': ['pkg1', 'pkg2'],
|
||||
'jvm_options': ['--opt1', '--opt2=val'],
|
||||
'maven_options': ['--opt1', '--opt2=val'],
|
||||
'properties': ['p1=1', 'p2', 'p3=ppp3'],
|
||||
'envs': ['e1=1', 'e2=2'],
|
||||
'buildrequires': ['r1', 'r2'],
|
||||
'otheropts': 'others'})
|
||||
self.assertEqual(koji.util.maven_opts(values), {
|
||||
'scmurl': 'scmurl',
|
||||
'patches': 'patchurl',
|
||||
'specfile': 'specfile',
|
||||
'goals': ['goal1', 'goal2'],
|
||||
'profiles': ['profile1', 'profile2'],
|
||||
'packages': ['pkg1', 'pkg2'],
|
||||
'jvm_options': ['--opt1', '--opt2=val'],
|
||||
'maven_options': ['--opt1', '--opt2=val'],
|
||||
'properties': {'p2': None, 'p3': 'ppp3', 'p1': '1'},
|
||||
'envs': {'e1': '1', 'e2': '2'}})
|
||||
self.assertEqual(koji.util.maven_opts(values, chain=True, scratch=True), {
|
||||
'scmurl': 'scmurl',
|
||||
'patches': 'patchurl',
|
||||
'specfile': 'specfile',
|
||||
'goals': ['goal1', 'goal2'],
|
||||
'profiles': ['profile1', 'profile2'],
|
||||
'packages': ['pkg1', 'pkg2'],
|
||||
'jvm_options': ['--opt1', '--opt2=val'],
|
||||
'maven_options': ['--opt1', '--opt2=val'],
|
||||
'properties': {'p2': None, 'p3': 'ppp3', 'p1': '1'},
|
||||
'envs': {'e1': '1', 'e2': '2'},
|
||||
'buildrequires': ['r1', 'r2']})
|
||||
self.assertEqual(koji.util.maven_opts(values, chain=False, scratch=True), {
|
||||
'scmurl': 'scmurl',
|
||||
'patches': 'patchurl',
|
||||
'specfile': 'specfile',
|
||||
'goals': ['goal1', 'goal2'],
|
||||
'profiles': ['profile1', 'profile2'],
|
||||
'packages': ['pkg1', 'pkg2'],
|
||||
'jvm_options': ['--opt1', '--opt2=val'],
|
||||
'maven_options': ['--opt1', '--opt2=val'],
|
||||
'properties': {'p2': None, 'p3': 'ppp3', 'p1': '1'},
|
||||
'envs': {'e1': '1', 'e2': '2'},
|
||||
'scratch': True})
|
||||
values = optparse.Values({'envs': ['e1']})
|
||||
with self.assertRaises(ValueError) as cm:
|
||||
koji.util.maven_opts(values)
|
||||
self.assertEqual(
|
||||
cm.exception.args[0],
|
||||
"Environment variables must be in NAME=VALUE format")
|
||||
|
||||
def test_maven_params(self):
|
||||
"""Test maven_params function"""
|
||||
config = self._read_conf('/data/maven/config.ini')
|
||||
self.assertEqual(koji.util.maven_params(config, 'pkg1'), {
|
||||
'scmurl': 'scmurl',
|
||||
'patches': 'patchurl',
|
||||
'specfile': 'specfile',
|
||||
'goals': ['goal1', 'goal2'],
|
||||
'profiles': ['profile1', 'profile2'],
|
||||
'packages': ['pkg1', 'pkg2'],
|
||||
'jvm_options': ['--opt1', '--opt2=val'],
|
||||
'maven_options': ['--opt1', '--opt2=val'],
|
||||
'properties': {'p2': None, 'p3': 'ppp3', 'p1': '1'},
|
||||
'envs': {'e1': '1', 'e2': '2'}})
|
||||
|
||||
def test_wrapper_params(self):
|
||||
"""Test wrapper_params function"""
|
||||
config = self._read_conf('/data/maven/config.ini')
|
||||
self.assertEqual(koji.util.wrapper_params(config, 'pkg2'), {
|
||||
'type': 'maven',
|
||||
'scmurl': 'scmurl',
|
||||
'buildrequires': ['r1', 'r2'],
|
||||
'create_build': True})
|
||||
self.assertEqual(koji.util.wrapper_params(config, 'pkg2', scratch=True), {
|
||||
'type': 'maven',
|
||||
'scmurl': 'scmurl',
|
||||
'buildrequires': ['r1', 'r2']})
|
||||
|
||||
def test_parse_maven_params(self):
|
||||
"""Test parse_maven_params function"""
|
||||
path = os.path.dirname(__file__)
|
||||
# single conf file, and chain=False, scratch=False
|
||||
confs = path + '/data/maven/config.ini'
|
||||
self.assertEqual(koji.util.parse_maven_params(confs), {
|
||||
'pkg1': {
|
||||
'scmurl': 'scmurl',
|
||||
'patches': 'patchurl',
|
||||
'specfile': 'specfile',
|
||||
'goals': ['goal1', 'goal2'],
|
||||
'profiles': ['profile1', 'profile2'],
|
||||
'packages': ['pkg1', 'pkg2'],
|
||||
'jvm_options': ['--opt1', '--opt2=val'],
|
||||
'maven_options': ['--opt1', '--opt2=val'],
|
||||
'properties': {'p2': None, 'p3': 'ppp3', 'p1': '1'},
|
||||
'envs': {'e1': '1', 'e2': '2'}},
|
||||
'pkg2': {
|
||||
'scmurl': 'scmurl',
|
||||
'patches': 'patchurl',
|
||||
'specfile': 'specfile',
|
||||
'goals': ['goal1', 'goal2'],
|
||||
'profiles': ['profile1', 'profile2'],
|
||||
'packages': ['pkg1', 'pkg2'],
|
||||
'jvm_options': ['--opt1', '--opt2=val'],
|
||||
'maven_options': ['--opt1', '--opt2=val'],
|
||||
'properties': {'p2': None, 'p3': 'ppp3', 'p1': '1'},
|
||||
'envs': {'e1': '1', 'e2': '2'}},
|
||||
'pkg3': {
|
||||
'type': 'wrapper',
|
||||
'scmurl': 'scmurl',
|
||||
'buildrequires': ['r1'],
|
||||
'create_build': True}})
|
||||
|
||||
# multiple conf file, and chain=True, scratch=False
|
||||
confs = [confs, path + '/data/maven/good_config.ini']
|
||||
self.assertEqual(koji.util.parse_maven_params(confs, chain=True), {
|
||||
'pkg1': {
|
||||
'scmurl': 'scmurl',
|
||||
'patches': 'patchurl',
|
||||
'specfile': 'specfile',
|
||||
'goals': ['goal1', 'goal2'],
|
||||
'profiles': ['profile1', 'profile2'],
|
||||
'packages': ['pkg1', 'pkg2'],
|
||||
'jvm_options': ['--opt1', '--opt2=val'],
|
||||
'maven_options': ['--opt1', '--opt2=val'],
|
||||
'properties': {'p2': None, 'p3': 'ppp3', 'p1': '1'},
|
||||
'envs': {'e1': '1', 'e2': '2'},
|
||||
'buildrequires': ['r1', 'r2']},
|
||||
'pkg2': {
|
||||
'scmurl': 'scmurl',
|
||||
'patches': 'patchurl',
|
||||
'specfile': 'specfile',
|
||||
'goals': ['goal1', 'goal2'],
|
||||
'profiles': ['profile1', 'profile2'],
|
||||
'packages': ['pkg1', 'pkg2'],
|
||||
'jvm_options': ['--opt1', '--opt2=val'],
|
||||
'maven_options': ['--opt1', '--opt2=val'],
|
||||
'properties': {'p2': None, 'p3': 'ppp3', 'p1': '1'},
|
||||
'envs': {'e1': '1', 'e2': '2'},
|
||||
'buildrequires': ['r1', 'r2']},
|
||||
'pkg3': {
|
||||
'type': 'wrapper',
|
||||
'scmurl': 'scmurl',
|
||||
'buildrequires': ['r1'],
|
||||
'create_build': True},
|
||||
'pkg4': {
|
||||
'scmurl': 'scmurl',
|
||||
'patches': 'patchurl',
|
||||
'specfile': 'specfile',
|
||||
'goals': ['goal1', 'goal2'],
|
||||
'profiles': ['profile1', 'profile2'],
|
||||
'packages': ['pkg1', 'pkg2'],
|
||||
'jvm_options': ['--opt1', '--opt2=val'],
|
||||
'maven_options': ['--opt1', '--opt2=val'],
|
||||
'properties': {'p2': None, 'p3': 'ppp3', 'p1': '1'},
|
||||
'envs': {'e1': '1', 'e2': '2'},
|
||||
'buildrequires': ['r1', 'r2']},
|
||||
})
|
||||
|
||||
# bad conf file - type=wrapper and len(params.get('buildrequires')!=1)
|
||||
confs = path + '/data/maven/bad_wrapper_config.ini'
|
||||
with self.assertRaises(ValueError) as cm:
|
||||
koji.util.parse_maven_params(confs)
|
||||
self.assertEqual(
|
||||
cm.exception.args[0],
|
||||
'A wrapper-rpm must depend on exactly one package')
|
||||
|
||||
# bad conf file - type is neither 'maven' nor 'wrapper')
|
||||
confs = path + '/data/maven/bad_type_config.ini'
|
||||
with self.assertRaises(ValueError) as cm:
|
||||
koji.util.parse_maven_params(confs)
|
||||
self.assertEqual(cm.exception.args[0], 'Unsupported build type: other')
|
||||
|
||||
# bad conf file - no scmurl param
|
||||
confs = path + '/data/maven/bad_scmurl_config.ini'
|
||||
with self.assertRaises(ValueError) as cm:
|
||||
koji.util.parse_maven_params(confs)
|
||||
self.assertEqual(
|
||||
cm.exception.args[0],
|
||||
'pkg is missing the scmurl parameter')
|
||||
|
||||
# bad conf file - empty dict returned
|
||||
confs = path + '/data/maven/bad_empty_config.ini'
|
||||
with self.assertRaises(ValueError) as cm:
|
||||
koji.util.parse_maven_params(confs)
|
||||
self.assertEqual(
|
||||
cm.exception.args[0],
|
||||
'No sections found in: %s' %
|
||||
confs)
|
||||
|
||||
def test_parse_maven_param(self):
|
||||
"""Test parse_maven_param function"""
|
||||
path = os.path.dirname(__file__)
|
||||
# single conf file, and chain=False, scratch=False
|
||||
confs = path + '/data/maven/config.ini'
|
||||
with mock.patch('koji.util.parse_maven_params',
|
||||
return_value={
|
||||
'pkg1': {'sth': 'pkg1'},
|
||||
'pkg2': {'sth': 'pkg2'},
|
||||
'pkg3': {'sth': 'pkg3'}}):
|
||||
self.assertEqual(
|
||||
koji.util.parse_maven_param(
|
||||
confs, section='pkg1'), {
|
||||
'pkg1': {
|
||||
'sth': 'pkg1'}})
|
||||
with self.assertRaises(ValueError) as cm:
|
||||
koji.util.parse_maven_param(confs, section='pkg4')
|
||||
self.assertEqual(
|
||||
cm.exception.args[0],
|
||||
'Section pkg4 does not exist in: %s' %
|
||||
confs)
|
||||
with self.assertRaises(ValueError) as cm:
|
||||
koji.util.parse_maven_param(confs)
|
||||
self.assertEqual(
|
||||
cm.exception.args[0],
|
||||
'Multiple sections in: %s, you must specify the section' %
|
||||
confs)
|
||||
with mock.patch('koji.util.parse_maven_params', return_value={
|
||||
'pkg': {'sth': 'pkg'}}):
|
||||
self.assertEqual(koji.util.parse_maven_param(confs),
|
||||
{'pkg': {'sth': 'pkg'}})
|
||||
|
||||
def test_parse_maven_chain(self):
|
||||
"""Test parse_maven_chain function"""
|
||||
path = os.path.dirname(__file__)
|
||||
confs = path + '/data/maven/config.ini'
|
||||
with mock.patch('koji.util.parse_maven_params',
|
||||
return_value={
|
||||
'pkg1': {'buildrequires': ['pkg2', 'pkg3']},
|
||||
'pkg2': {'buildrequires': ['pkg3']},
|
||||
'pkg3': {'sth': 'sth'}}):
|
||||
self.assertEqual(koji.util.parse_maven_chain(confs),
|
||||
{'pkg1': {'buildrequires': ['pkg2', 'pkg3']},
|
||||
'pkg2': {'buildrequires': ['pkg3']},
|
||||
'pkg3': {'sth': 'sth'}})
|
||||
# circular deps
|
||||
with mock.patch('koji.util.parse_maven_params',
|
||||
return_value={
|
||||
'pkg1': {'buildrequires': ['pkg2', 'pkg3']},
|
||||
'pkg2': {'buildrequires': ['pkg3']},
|
||||
'pkg3': {'buildrequires': ['pkg1']}}):
|
||||
with self.assertRaises(ValueError) as cm:
|
||||
koji.util.parse_maven_chain(confs)
|
||||
self.assertEqual(
|
||||
cm.exception.args[0],
|
||||
'No possible build order, missing/circular dependencies')
|
||||
# missing deps
|
||||
with mock.patch('koji.util.parse_maven_params',
|
||||
return_value={
|
||||
'pkg1': {'buildrequires': ['pkg2', 'pkg3']},
|
||||
'pkg2': {'buildrequires': ['pkg3']},
|
||||
'pkg3': {'buildrequires': ['pkg4']}}):
|
||||
with self.assertRaises(ValueError) as cm:
|
||||
koji.util.parse_maven_chain(confs)
|
||||
self.assertEqual(
|
||||
cm.exception.args[0],
|
||||
'No possible build order, missing/circular dependencies')
|
||||
|
||||
def test_tsort(self):
|
||||
# success, one path
|
||||
parts = {
|
||||
'p1': {'p2', 'p3'},
|
||||
'p2': {'p3'},
|
||||
'p3': set()
|
||||
}
|
||||
self.assertEqual(koji.util.tsort(parts),
|
||||
[{'p3'}, {'p2'}, {'p1'}])
|
||||
# success, multi-path
|
||||
parts = {
|
||||
'p1': {'p2'},
|
||||
'p2': {'p4'},
|
||||
'p3': {'p4'},
|
||||
'p4': set(),
|
||||
'p5': set()
|
||||
}
|
||||
self.assertEqual(koji.util.tsort(parts),
|
||||
[{'p4', 'p5'}, {'p2', 'p3'}, {'p1'}])
|
||||
# failed, missing child 'p4'
|
||||
parts = {
|
||||
'p1': {'p2'},
|
||||
'p2': {'p3'},
|
||||
'p3': {'p4'}
|
||||
}
|
||||
with self.assertRaises(ValueError) as cm:
|
||||
koji.util.tsort(parts)
|
||||
self.assertEqual(cm.exception.args[0], 'total ordering not possible')
|
||||
|
||||
# failed, circular
|
||||
parts = {
|
||||
'p1': {'p2'},
|
||||
'p2': {'p3'},
|
||||
'p3': {'p1'}
|
||||
}
|
||||
with self.assertRaises(ValueError) as cm:
|
||||
koji.util.tsort(parts)
|
||||
self.assertEqual(cm.exception.args[0], 'total ordering not possible')
|
||||
|
||||
def _read_conf(self, cfile):
|
||||
config = six.moves.configparser.ConfigParser()
|
||||
path = os.path.dirname(__file__)
|
||||
with open(path + cfile, 'r') as conf_file:
|
||||
config.readfp(conf_file)
|
||||
return config
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
Loading…
Add table
Add a link
Reference in a new issue