Imported Upstream version 4.8.10
This commit is contained in:
47
ipatests/test_ipalib/data/ipa.pot
Normal file
47
ipatests/test_ipalib/data/ipa.pot
Normal file
@@ -0,0 +1,47 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR Red Hat
|
||||
# This file is distributed under the same license as the ipa package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: ipa\n"
|
||||
"Report-Msgid-Bugs-To: https://fedorahosted.org/freeipa/newticket\n"
|
||||
"POT-Creation-Date: 2016-08-29 10:39+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"Language: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
|
||||
|
||||
#: ipaclient/frontend.py:28 ipaclient/frontend.py:85
|
||||
#: ipaserver/plugins/baseldap.py:52
|
||||
msgid "Failed members"
|
||||
msgstr ""
|
||||
|
||||
#: ipaclient/frontend.py:32 ipaserver/plugins/baseldap.py:169
|
||||
msgid "Failed source hosts/hostgroups"
|
||||
msgstr ""
|
||||
|
||||
#: ipaclient/frontend.py:36 ipaserver/plugins/baseldap.py:172
|
||||
msgid "Failed hosts/hostgroups"
|
||||
msgstr ""
|
||||
|
||||
#: ipaclient/frontend.py:40 ipaserver/plugins/baseldap.py:175
|
||||
msgid "Failed users/groups"
|
||||
msgstr ""
|
||||
|
||||
#: ipaclient/plugins/dns.py:249
|
||||
#, python-format
|
||||
msgid ""
|
||||
"%(count)d %(type)s record skipped. Only one value per DNS record type can be "
|
||||
"modified at one time."
|
||||
msgid_plural ""
|
||||
"%(count)d %(type)s records skipped. Only one value per DNS record type can "
|
||||
"be modified at one time."
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
@@ -21,13 +21,18 @@
|
||||
"""
|
||||
Test the `ipalib.aci` module.
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
from ipalib.aci import ACI
|
||||
|
||||
import pytest
|
||||
|
||||
pytestmark = pytest.mark.tier0
|
||||
|
||||
def check_aci_parsing(source, expected):
|
||||
a = ACI(source)
|
||||
print 'ACI was: ', a
|
||||
print 'Expected:', expected
|
||||
print('ACI was: ', a)
|
||||
print('Expected:', expected)
|
||||
assert str(ACI(source)) == expected
|
||||
|
||||
def test_aci_parsing_1():
|
||||
@@ -40,7 +45,7 @@ def test_aci_parsing_1_with_aci_keyword():
|
||||
|
||||
def test_aci_parsing_2():
|
||||
check_aci_parsing('(target="ldap:///uid=bjensen,dc=example,dc=com")(targetattr=*) (version 3.0;acl "aci1";allow (write) userdn="ldap:///self";)',
|
||||
'(targetattr = "*")(target = "ldap:///uid=bjensen,dc=example,dc=com")(version 3.0;acl "aci1";allow (write) userdn = "ldap:///self";)')
|
||||
'(target = "ldap:///uid=bjensen,dc=example,dc=com")(targetattr = "*")(version 3.0;acl "aci1";allow (write) userdn = "ldap:///self";)')
|
||||
|
||||
def test_aci_parsing_3():
|
||||
check_aci_parsing(' (targetattr = "givenName || sn || cn || displayName || title || initials || loginShell || gecos || homePhone || mobile || pager || facsimileTelephoneNumber || telephoneNumber || street || roomNumber || l || st || postalCode || manager || secretary || description || carLicense || labeledURI || inetUserHTTPURL || seeAlso || employeeType || businessCategory || ou")(version 3.0;acl "Self service";allow (write) userdn = "ldap:///self";)',
|
||||
@@ -52,11 +57,11 @@ def test_aci_parsing_4():
|
||||
|
||||
def test_aci_parsing_5():
|
||||
check_aci_parsing('(targetattr=member)(target="ldap:///cn=ipausers,cn=groups,cn=accounts,dc=example,dc=com")(version 3.0;acl "add_user_to_default_group";allow (write) groupdn="ldap:///cn=add_user_to_default_group,cn=taskgroups,dc=example,dc=com";)',
|
||||
'(targetattr = "member")(target = "ldap:///cn=ipausers,cn=groups,cn=accounts,dc=example,dc=com")(version 3.0;acl "add_user_to_default_group";allow (write) groupdn = "ldap:///cn=add_user_to_default_group,cn=taskgroups,dc=example,dc=com";)')
|
||||
'(target = "ldap:///cn=ipausers,cn=groups,cn=accounts,dc=example,dc=com")(targetattr = "member")(version 3.0;acl "add_user_to_default_group";allow (write) groupdn = "ldap:///cn=add_user_to_default_group,cn=taskgroups,dc=example,dc=com";)')
|
||||
|
||||
def test_aci_parsing_6():
|
||||
check_aci_parsing('(targetattr!=member)(targe="ldap:///cn=ipausers,cn=groups,cn=accounts,dc=example,dc=com")(version 3.0;acl "add_user_to_default_group";allow (write) groupdn="ldap:///cn=add_user_to_default_group,cn=taskgroups,dc=example,dc=com";)',
|
||||
'(targetattr != "member")(targe = "ldap:///cn=ipausers,cn=groups,cn=accounts,dc=example,dc=com")(version 3.0;acl "add_user_to_default_group";allow (write) groupdn = "ldap:///cn=add_user_to_default_group,cn=taskgroups,dc=example,dc=com";)')
|
||||
'(targe = "ldap:///cn=ipausers,cn=groups,cn=accounts,dc=example,dc=com")(targetattr != "member")(version 3.0;acl "add_user_to_default_group";allow (write) groupdn = "ldap:///cn=add_user_to_default_group,cn=taskgroups,dc=example,dc=com";)')
|
||||
|
||||
def test_aci_parsing_7():
|
||||
check_aci_parsing('(targetattr = "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory")(version 3.0; acl "change_password"; allow (write) groupdn = "ldap:///cn=change_password,cn=taskgroups,dc=example,dc=com";)',
|
||||
@@ -76,7 +81,7 @@ def make_test_aci():
|
||||
|
||||
def test_aci_equality():
|
||||
a = make_test_aci()
|
||||
print a
|
||||
print(a)
|
||||
|
||||
b = ACI()
|
||||
b.name ="foo"
|
||||
@@ -85,17 +90,17 @@ def test_aci_equality():
|
||||
b.set_bindrule_operator("=")
|
||||
b.set_bindrule_expression("\"ldap:///cn=foo,cn=groups,cn=accounts,dc=example,dc=com\"")
|
||||
b.permissions = ['add','read','write']
|
||||
print b
|
||||
print(b)
|
||||
|
||||
assert a.isequal(b)
|
||||
assert a == b
|
||||
assert not a != b
|
||||
assert not a != b # pylint: disable=unneeded-not
|
||||
|
||||
|
||||
def check_aci_inequality(b):
|
||||
a = make_test_aci()
|
||||
print a
|
||||
print b
|
||||
print(a)
|
||||
print(b)
|
||||
|
||||
assert not a.isequal(b)
|
||||
assert not a == b
|
||||
@@ -157,3 +162,15 @@ def test_aci_parsing_8():
|
||||
def test_aci_parsing_9():
|
||||
check_aci_parsing('(targetfilter = "(|(objectClass=person)(objectClass=krbPrincipalAux)(objectClass=posixAccount)(objectClass=groupOfNames)(objectClass=posixGroup))")(targetattr != "aci || userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory")(version 3.0; acl "Account Admins can manage Users and Groups"; allow (add, delete, read, write) groupdn = "ldap:///cn=admins,cn=groups,cn=accounts,dc=greyoak,dc=com";)',
|
||||
'(targetattr != "aci || userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory")(targetfilter = "(|(objectClass=person)(objectClass=krbPrincipalAux)(objectClass=posixAccount)(objectClass=groupOfNames)(objectClass=posixGroup))")(version 3.0;acl "Account Admins can manage Users and Groups";allow (add,delete,read,write) groupdn = "ldap:///cn=admins,cn=groups,cn=accounts,dc=greyoak,dc=com";)')
|
||||
|
||||
|
||||
def test_aci_parsing_10():
|
||||
"""test subtypes"""
|
||||
check_aci_parsing('(targetattr="ipaProtectedOperation;read_keys")'
|
||||
'(version 3.0; acl "Allow trust agents to retrieve '
|
||||
'keytab keys for cross realm principals"; allow(read) '
|
||||
'userattr="ipaAllowedToPerform;read_keys#GROUPDN";)',
|
||||
'(targetattr = "ipaProtectedOperation;read || keys")'
|
||||
'(version 3.0;acl "Allow trust agents to retrieve '
|
||||
'keytab keys for cross realm principals";allow (read) '
|
||||
'userattr = "ipaAllowedToPerform;read_keys#GROUPDN";)')
|
||||
|
||||
@@ -20,16 +20,19 @@
|
||||
"""
|
||||
Test the `ipalib.backend` module.
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
import threading
|
||||
from ipatests.util import ClassChecker, raises, create_test_api
|
||||
from ipatests.data import unicode_str
|
||||
from ipalib.request import context, Connection
|
||||
from ipalib.frontend import Command
|
||||
from ipalib import backend, plugable, errors, base
|
||||
from ipalib import backend, plugable, errors
|
||||
from ipapython.version import API_VERSION
|
||||
|
||||
import pytest
|
||||
|
||||
pytestmark = pytest.mark.tier0
|
||||
|
||||
class test_Backend(ClassChecker):
|
||||
"""
|
||||
@@ -42,7 +45,7 @@ class test_Backend(ClassChecker):
|
||||
assert self.cls.__bases__ == (plugable.Plugin,)
|
||||
|
||||
|
||||
class Disconnect(object):
|
||||
class Disconnect:
|
||||
called = False
|
||||
|
||||
def __init__(self, id=None):
|
||||
@@ -67,12 +70,13 @@ class test_Connectible(ClassChecker):
|
||||
Test the `ipalib.backend.Connectible.connect` method.
|
||||
"""
|
||||
# Test that connection is created:
|
||||
api = 'the api instance'
|
||||
class example(self.cls):
|
||||
def create_connection(self, *args, **kw):
|
||||
object.__setattr__(self, 'args', args)
|
||||
object.__setattr__(self, 'kw', kw)
|
||||
return 'The connection.'
|
||||
o = example()
|
||||
o = example(api, shared_instance=True)
|
||||
args = ('Arg1', 'Arg2', 'Arg3')
|
||||
kw = dict(key1='Val1', key2='Val2', key3='Val3')
|
||||
assert not hasattr(context, 'example')
|
||||
@@ -84,10 +88,11 @@ class test_Connectible(ClassChecker):
|
||||
assert conn.conn == 'The connection.'
|
||||
assert conn.disconnect == o.disconnect
|
||||
|
||||
# Test that StandardError is raised if already connected:
|
||||
m = "connect: 'context.%s' already exists in thread %r"
|
||||
e = raises(StandardError, o.connect, *args, **kw)
|
||||
assert str(e) == m % ('example', threading.currentThread().getName())
|
||||
# Test that Exception is raised if already connected:
|
||||
m = "{0} is already connected ({1} in {2})"
|
||||
e = raises(Exception, o.connect, *args, **kw)
|
||||
assert str(e) == m.format(
|
||||
'example', o.id, threading.currentThread().getName())
|
||||
|
||||
# Double check that it works after deleting context.example:
|
||||
del context.example
|
||||
@@ -97,10 +102,11 @@ class test_Connectible(ClassChecker):
|
||||
"""
|
||||
Test the `ipalib.backend.Connectible.create_connection` method.
|
||||
"""
|
||||
api = 'the api instance'
|
||||
class example(self.cls):
|
||||
pass
|
||||
for klass in (self.cls, example):
|
||||
o = klass()
|
||||
o = klass(api, shared_instance=True)
|
||||
e = raises(NotImplementedError, o.create_connection)
|
||||
assert str(e) == '%s.create_connection()' % klass.__name__
|
||||
|
||||
@@ -108,13 +114,15 @@ class test_Connectible(ClassChecker):
|
||||
"""
|
||||
Test the `ipalib.backend.Connectible.disconnect` method.
|
||||
"""
|
||||
api = 'the api instance'
|
||||
class example(self.cls):
|
||||
destroy_connection = Disconnect()
|
||||
o = example()
|
||||
o = example(api, shared_instance=True)
|
||||
|
||||
m = "disconnect: 'context.%s' does not exist in thread %r"
|
||||
e = raises(StandardError, o.disconnect)
|
||||
assert str(e) == m % ('example', threading.currentThread().getName())
|
||||
m = "{0} is not connected ({1} in {2})"
|
||||
e = raises(Exception, o.disconnect)
|
||||
assert str(e) == m.format(
|
||||
'example', o.id, threading.currentThread().getName())
|
||||
|
||||
context.example = 'The connection.'
|
||||
assert o.disconnect() is None
|
||||
@@ -124,10 +132,11 @@ class test_Connectible(ClassChecker):
|
||||
"""
|
||||
Test the `ipalib.backend.Connectible.destroy_connection` method.
|
||||
"""
|
||||
api = 'the api instance'
|
||||
class example(self.cls):
|
||||
pass
|
||||
for klass in (self.cls, example):
|
||||
o = klass()
|
||||
o = klass(api, shared_instance=True)
|
||||
e = raises(NotImplementedError, o.destroy_connection)
|
||||
assert str(e) == '%s.destroy_connection()' % klass.__name__
|
||||
|
||||
@@ -135,10 +144,11 @@ class test_Connectible(ClassChecker):
|
||||
"""
|
||||
Test the `ipalib.backend.Connectible.isconnected` method.
|
||||
"""
|
||||
api = 'the api instance'
|
||||
class example(self.cls):
|
||||
pass
|
||||
for klass in (self.cls, example):
|
||||
o = klass()
|
||||
o = klass(api, shared_instance=True)
|
||||
assert o.isconnected() is False
|
||||
conn = 'whatever'
|
||||
setattr(context, klass.__name__, conn)
|
||||
@@ -149,14 +159,15 @@ class test_Connectible(ClassChecker):
|
||||
"""
|
||||
Test the `ipalib.backend.Connectible.conn` property.
|
||||
"""
|
||||
msg = 'no context.%s in thread %r'
|
||||
api = 'the api instance'
|
||||
msg = '{0} is not connected ({1} in {2})'
|
||||
class example(self.cls):
|
||||
pass
|
||||
for klass in (self.cls, example):
|
||||
o = klass()
|
||||
o = klass(api, shared_instance=True)
|
||||
e = raises(AttributeError, getattr, o, 'conn')
|
||||
assert str(e) == msg % (
|
||||
klass.__name__, threading.currentThread().getName()
|
||||
assert str(e) == msg.format(
|
||||
klass.__name__, o.id, threading.currentThread().getName()
|
||||
)
|
||||
conn = Connection('The connection.', Disconnect())
|
||||
setattr(context, klass.__name__, conn)
|
||||
@@ -174,7 +185,7 @@ class test_Executioner(ClassChecker):
|
||||
"""
|
||||
Test the `ipalib.backend.Executioner.execute` method.
|
||||
"""
|
||||
(api, home) = create_test_api(in_server=True)
|
||||
api, _home = create_test_api(in_server=True)
|
||||
|
||||
class echo(Command):
|
||||
takes_args = ('arg1', 'arg2+')
|
||||
@@ -182,7 +193,7 @@ class test_Executioner(ClassChecker):
|
||||
def execute(self, *args, **options):
|
||||
assert type(args[1]) is tuple
|
||||
return dict(result=args + (options,))
|
||||
api.register(echo)
|
||||
api.add_plugin(echo)
|
||||
|
||||
class good(Command):
|
||||
def execute(self, **options):
|
||||
@@ -190,12 +201,12 @@ class test_Executioner(ClassChecker):
|
||||
name='nurse',
|
||||
error=u'Not naughty!',
|
||||
)
|
||||
api.register(good)
|
||||
api.add_plugin(good)
|
||||
|
||||
class bad(Command):
|
||||
def execute(self, **options):
|
||||
raise ValueError('This is private.')
|
||||
api.register(bad)
|
||||
api.add_plugin(bad)
|
||||
|
||||
class with_name(Command):
|
||||
"""
|
||||
@@ -204,22 +215,21 @@ class test_Executioner(ClassChecker):
|
||||
takes_options = 'name'
|
||||
def execute(self, **options):
|
||||
return dict(result=options['name'].upper())
|
||||
api.register(with_name)
|
||||
api.add_plugin(with_name)
|
||||
|
||||
api.finalize()
|
||||
o = self.cls()
|
||||
o.set_api(api)
|
||||
o = self.cls(api)
|
||||
o.finalize()
|
||||
|
||||
# Test that CommandError is raised:
|
||||
conn = Connection('The connection.', Disconnect('someconn'))
|
||||
context.someconn = conn
|
||||
print str(context.__dict__.keys())
|
||||
print(str(list(context.__dict__)))
|
||||
e = raises(errors.CommandError, o.execute, 'nope')
|
||||
assert e.name == 'nope'
|
||||
assert conn.disconnect.called is True # Make sure destroy_context() was called
|
||||
print str(context.__dict__.keys())
|
||||
assert context.__dict__.keys() == []
|
||||
print(str(list(context.__dict__)))
|
||||
assert list(context.__dict__) == []
|
||||
|
||||
# Test with echo command:
|
||||
arg1 = unicode_str
|
||||
@@ -230,15 +240,15 @@ class test_Executioner(ClassChecker):
|
||||
|
||||
conn = Connection('The connection.', Disconnect('someconn'))
|
||||
context.someconn = conn
|
||||
print o.execute('echo', arg1, arg2, **options)
|
||||
print dict(
|
||||
print(o.execute('echo', arg1, arg2, **options))
|
||||
print(dict(
|
||||
result=(arg1, arg2, options)
|
||||
)
|
||||
))
|
||||
assert o.execute('echo', arg1, arg2, **options) == dict(
|
||||
result=(arg1, arg2, options)
|
||||
)
|
||||
assert conn.disconnect.called is True # Make sure destroy_context() was called
|
||||
assert context.__dict__.keys() == []
|
||||
assert list(context.__dict__) == []
|
||||
|
||||
conn = Connection('The connection.', Disconnect('someconn'))
|
||||
context.someconn = conn
|
||||
@@ -246,7 +256,7 @@ class test_Executioner(ClassChecker):
|
||||
result=(arg1, arg2, options)
|
||||
)
|
||||
assert conn.disconnect.called is True # Make sure destroy_context() was called
|
||||
assert context.__dict__.keys() == []
|
||||
assert list(context.__dict__) == []
|
||||
|
||||
# Test with good command:
|
||||
conn = Connection('The connection.', Disconnect('someconn'))
|
||||
@@ -255,14 +265,14 @@ class test_Executioner(ClassChecker):
|
||||
assert e.name == 'nurse'
|
||||
assert e.error == u'Not naughty!'
|
||||
assert conn.disconnect.called is True # Make sure destroy_context() was called
|
||||
assert context.__dict__.keys() == []
|
||||
assert list(context.__dict__) == []
|
||||
|
||||
# Test with bad command:
|
||||
conn = Connection('The connection.', Disconnect('someconn'))
|
||||
context.someconn = conn
|
||||
e = raises(errors.InternalError, o.execute, 'bad')
|
||||
assert conn.disconnect.called is True # Make sure destroy_context() was called
|
||||
assert context.__dict__.keys() == []
|
||||
assert list(context.__dict__) == []
|
||||
|
||||
# Test with option 'name':
|
||||
conn = Connection('The connection.', Disconnect('someconn'))
|
||||
|
||||
@@ -21,11 +21,20 @@
|
||||
Test the `ipalib.base` module.
|
||||
"""
|
||||
|
||||
import six
|
||||
import pytest
|
||||
|
||||
from ipatests.util import ClassChecker, raises
|
||||
from ipalib.constants import NAME_REGEX, NAME_ERROR
|
||||
from ipalib.constants import TYPE_ERROR, SET_ERROR, DEL_ERROR, OVERRIDE_ERROR
|
||||
from ipalib import base
|
||||
|
||||
if six.PY3:
|
||||
unicode = str
|
||||
|
||||
|
||||
pytestmark = pytest.mark.tier0
|
||||
|
||||
|
||||
class test_ReadOnly(ClassChecker):
|
||||
"""
|
||||
@@ -99,7 +108,7 @@ def test_lock():
|
||||
assert str(e) == 'already locked: %r' % o
|
||||
|
||||
# Test with another class implemented locking protocol:
|
||||
class Lockable(object):
|
||||
class Lockable:
|
||||
__locked = False
|
||||
def __lock__(self):
|
||||
self.__locked = True
|
||||
@@ -113,7 +122,7 @@ def test_lock():
|
||||
assert str(e) == 'already locked: %r' % o
|
||||
|
||||
# Test with a class incorrectly implementing the locking protocol:
|
||||
class Broken(object):
|
||||
class Broken:
|
||||
def __lock__(self):
|
||||
pass
|
||||
def __islocked__(self):
|
||||
@@ -136,7 +145,7 @@ def test_islocked():
|
||||
assert f(o) is True
|
||||
|
||||
# Test with another class implemented locking protocol:
|
||||
class Lockable(object):
|
||||
class Lockable:
|
||||
__locked = False
|
||||
def __lock__(self):
|
||||
self.__locked = True
|
||||
@@ -148,7 +157,7 @@ def test_islocked():
|
||||
assert f(o) is True
|
||||
|
||||
# Test with a class incorrectly implementing the locking protocol:
|
||||
class Broken(object):
|
||||
class Broken:
|
||||
__lock__ = False
|
||||
def __islocked__(self):
|
||||
return False
|
||||
@@ -178,8 +187,14 @@ def test_check_name():
|
||||
]
|
||||
for name in okay:
|
||||
assert name is f(name)
|
||||
e = raises(TypeError, f, unicode(name))
|
||||
assert str(e) == TYPE_ERROR % ('name', str, unicode(name), unicode)
|
||||
if six.PY2:
|
||||
bad_type = unicode
|
||||
bad_value = unicode(name)
|
||||
else:
|
||||
bad_type = bytes
|
||||
bad_value = name.encode('ascii')
|
||||
e = raises(TypeError, f, bad_value)
|
||||
assert str(e) == TYPE_ERROR % ('name', str, bad_value, bad_type)
|
||||
for name in nope:
|
||||
e = raises(ValueError, f, name)
|
||||
assert str(e) == NAME_ERROR % (NAME_REGEX, name)
|
||||
@@ -192,7 +207,7 @@ def membername(i):
|
||||
return 'member%03d' % i
|
||||
|
||||
|
||||
class DummyMember(object):
|
||||
class DummyMember:
|
||||
def __init__(self, i):
|
||||
self.i = i
|
||||
self.name = self.__name__ = membername(i)
|
||||
@@ -209,7 +224,7 @@ class test_NameSpace(ClassChecker):
|
||||
_cls = base.NameSpace
|
||||
|
||||
def new(self, count, sort=True):
|
||||
members = tuple(DummyMember(i) for i in xrange(count, 0, -1))
|
||||
members = tuple(DummyMember(i) for i in range(count, 0, -1))
|
||||
assert len(members) == count
|
||||
o = self.cls(members, sort=sort)
|
||||
return (o, members)
|
||||
@@ -248,9 +263,9 @@ class test_NameSpace(ClassChecker):
|
||||
Test the `ipalib.base.NameSpace.__len__` method.
|
||||
"""
|
||||
for count in (5, 18, 127):
|
||||
(o, members) = self.new(count)
|
||||
o, _members = self.new(count)
|
||||
assert len(o) == count
|
||||
(o, members) = self.new(count, sort=False)
|
||||
o, _members = self.new(count, sort=False)
|
||||
assert len(o) == count
|
||||
|
||||
def test_iter(self):
|
||||
@@ -305,12 +320,12 @@ class test_NameSpace(ClassChecker):
|
||||
e = raises(KeyError, o.__getitem__, 'nope')
|
||||
|
||||
# Test int indexes:
|
||||
for i in xrange(cnt):
|
||||
for i in range(cnt):
|
||||
assert o[i] is members[i]
|
||||
e = raises(IndexError, o.__getitem__, cnt)
|
||||
|
||||
# Test negative int indexes:
|
||||
for i in xrange(1, cnt + 1):
|
||||
for i in range(1, cnt + 1):
|
||||
assert o[-i] is members[-i]
|
||||
e = raises(IndexError, o.__getitem__, -(cnt + 1))
|
||||
|
||||
@@ -338,7 +353,7 @@ class test_NameSpace(ClassChecker):
|
||||
"""
|
||||
for cnt in (0, 1, 2):
|
||||
for sort in (True, False):
|
||||
(o, members) = self.new(cnt, sort=sort)
|
||||
o, _members = self.new(cnt, sort=sort)
|
||||
if cnt == 1:
|
||||
assert repr(o) == \
|
||||
'NameSpace(<%d member>, sort=%r)' % (cnt, sort)
|
||||
|
||||
@@ -23,6 +23,9 @@ Test the `ipalib.errors` module.
|
||||
|
||||
from ipalib.capabilities import capabilities, client_has_capability
|
||||
|
||||
import pytest
|
||||
|
||||
pytestmark = pytest.mark.tier0
|
||||
|
||||
def test_client_has_capability():
|
||||
assert capabilities['messages'] == u'2.52'
|
||||
|
||||
@@ -21,9 +21,12 @@
|
||||
Test the `ipalib.cli` module.
|
||||
"""
|
||||
|
||||
from ipatests.util import raises, get_api, ClassChecker
|
||||
from ipalib import cli, plugable, frontend, backend
|
||||
from ipatests.util import raises, ClassChecker
|
||||
from ipalib import cli, plugable
|
||||
|
||||
import pytest
|
||||
|
||||
pytestmark = pytest.mark.tier0
|
||||
|
||||
class test_textui(ClassChecker):
|
||||
_cls = cli.textui
|
||||
@@ -32,15 +35,16 @@ class test_textui(ClassChecker):
|
||||
"""
|
||||
Test the `ipalib.cli.textui.max_col_width` method.
|
||||
"""
|
||||
o = self.cls()
|
||||
api = 'the api instance'
|
||||
o = self.cls(api)
|
||||
e = raises(TypeError, o.max_col_width, 'hello')
|
||||
assert str(e) == 'rows: need %r or %r; got %r' % (list, tuple, 'hello')
|
||||
rows = [
|
||||
'hello',
|
||||
'naughty',
|
||||
'empathetic',
|
||||
'nurse',
|
||||
]
|
||||
assert o.max_col_width(rows) == len('naughty')
|
||||
assert o.max_col_width(rows) == len('empathetic')
|
||||
rows = (
|
||||
( 'a', 'bbb', 'ccccc'),
|
||||
('aa', 'bbbb', 'cccccc'),
|
||||
@@ -72,7 +76,7 @@ def get_cmd_name(i):
|
||||
return 'cmd_%d' % i
|
||||
|
||||
|
||||
class DummyCommand(object):
|
||||
class DummyCommand:
|
||||
def __init__(self, name):
|
||||
self.__name = name
|
||||
|
||||
@@ -81,16 +85,16 @@ class DummyCommand(object):
|
||||
name = property(__get_name)
|
||||
|
||||
|
||||
class DummyAPI(object):
|
||||
class DummyAPI:
|
||||
def __init__(self, cnt):
|
||||
self.__cmd = plugable.NameSpace(self.__cmd_iter(cnt))
|
||||
self.__cmd = plugable.APINameSpace(self.__cmd_iter(cnt), DummyCommand)
|
||||
|
||||
def __get_cmd(self):
|
||||
return self.__cmd
|
||||
Command = property(__get_cmd)
|
||||
|
||||
def __cmd_iter(self, cnt):
|
||||
for i in xrange(cnt):
|
||||
for i in range(cnt):
|
||||
yield DummyCommand(get_cmd_name(i))
|
||||
|
||||
def finalize(self):
|
||||
|
||||
@@ -22,18 +22,20 @@
|
||||
Test the `ipalib.config` module.
|
||||
"""
|
||||
|
||||
import os
|
||||
from os import path
|
||||
import site
|
||||
import sys
|
||||
import socket
|
||||
from ipatests.util import raises, setitem, delitem, ClassChecker
|
||||
from ipatests.util import getitem, setitem, delitem
|
||||
|
||||
from ipatests.util import raises, delitem, ClassChecker
|
||||
from ipatests.util import getitem
|
||||
from ipatests.util import TempDir, TempHome
|
||||
from ipalib.constants import TYPE_ERROR, OVERRIDE_ERROR, SET_ERROR, DEL_ERROR
|
||||
from ipalib.constants import OVERRIDE_ERROR, SET_ERROR, DEL_ERROR
|
||||
from ipalib.constants import NAME_REGEX, NAME_ERROR
|
||||
from ipalib import config, constants, base
|
||||
from ipaplatform.paths import paths
|
||||
|
||||
import pytest
|
||||
|
||||
pytestmark = pytest.mark.tier0
|
||||
|
||||
# Valid environment variables in (key, raw, value) tuples:
|
||||
# key: the name of the environment variable
|
||||
@@ -166,7 +168,7 @@ class test_Env(ClassChecker):
|
||||
assert o.__islocked__() is False
|
||||
o.__lock__()
|
||||
assert o.__islocked__() is True
|
||||
e = raises(StandardError, o.__lock__)
|
||||
e = raises(Exception, o.__lock__)
|
||||
assert str(e) == 'Env.__lock__() already called'
|
||||
|
||||
# Also test with base.lock() function:
|
||||
@@ -298,7 +300,7 @@ class test_Env(ClassChecker):
|
||||
"""
|
||||
o = self.cls()
|
||||
assert len(o) == 0
|
||||
for i in xrange(1, 11):
|
||||
for i in range(1, 11):
|
||||
key = 'key%d' % i
|
||||
value = u'value %d' % i
|
||||
o[key] = value
|
||||
@@ -345,7 +347,7 @@ class test_Env(ClassChecker):
|
||||
expected.update(dict(group1))
|
||||
assert list(o) == sorted(expected)
|
||||
assert expected['key2'] == 'value 2' # And not 'Value 2'
|
||||
for (key, value) in expected.iteritems():
|
||||
for (key, value) in expected.items():
|
||||
assert getattr(o, key) is value
|
||||
assert o[key] is value
|
||||
assert o._merge(**expected) == (0, 6)
|
||||
@@ -390,7 +392,7 @@ class test_Env(ClassChecker):
|
||||
for (k, v) in orig.items():
|
||||
assert o[k] is v
|
||||
assert list(o) == sorted(keys + ('key0', 'key1', 'key2', 'key3', 'config_loaded'))
|
||||
for i in xrange(4):
|
||||
for i in range(4):
|
||||
assert o['key%d' % i] == ('var%d' % i)
|
||||
keys = tuple(o)
|
||||
|
||||
@@ -429,7 +431,7 @@ class test_Env(ClassChecker):
|
||||
assert o._isdone('_bootstrap') is False
|
||||
o._bootstrap(**overrides)
|
||||
assert o._isdone('_bootstrap') is True
|
||||
e = raises(StandardError, o._bootstrap)
|
||||
e = raises(Exception, o._bootstrap)
|
||||
assert str(e) == 'Env._bootstrap() already called'
|
||||
return (o, home)
|
||||
|
||||
@@ -447,26 +449,42 @@ class test_Env(ClassChecker):
|
||||
assert o.bin == path.dirname(path.abspath(sys.argv[0]))
|
||||
assert o.home == home.path
|
||||
assert o.dot_ipa == home.join('.ipa')
|
||||
assert o.in_tree is False
|
||||
assert o.context == 'default'
|
||||
assert o.confdir == paths.ETC_IPA
|
||||
assert o.conf == paths.IPA_DEFAULT_CONF
|
||||
assert o.conf_default == o.conf
|
||||
if (
|
||||
# venv site module doesn't have getsitepackages()
|
||||
not hasattr(site, "getsitepackages")
|
||||
or o.site_packages in site.getsitepackages()
|
||||
):
|
||||
assert o.in_tree is False
|
||||
assert o.confdir == '/etc/ipa'
|
||||
assert o.conf == '/etc/ipa/default.conf'
|
||||
assert o.conf_default == o.conf
|
||||
else:
|
||||
assert o.in_tree is True
|
||||
assert o.confdir == o.dot_ipa
|
||||
assert o.conf == home.join('.ipa/default.conf')
|
||||
assert o.conf_default == o.conf
|
||||
|
||||
# Test overriding values created by _bootstrap()
|
||||
(o, home) = self.bootstrap(in_tree='True', context='server')
|
||||
assert o.in_tree is True
|
||||
assert o.context == 'server'
|
||||
assert o.conf == home.join('.ipa', 'server.conf')
|
||||
(o, home) = self.bootstrap(conf='/my/wacky/whatever.conf')
|
||||
|
||||
o, home = self.bootstrap(
|
||||
conf='/my/wacky/whatever.conf', in_tree=False
|
||||
)
|
||||
assert o.in_tree is False
|
||||
assert o.context == 'default'
|
||||
assert o.conf == '/my/wacky/whatever.conf'
|
||||
assert o.conf_default == paths.IPA_DEFAULT_CONF
|
||||
(o, home) = self.bootstrap(conf_default='/my/wacky/default.conf')
|
||||
assert o.conf_default == '/etc/ipa/default.conf'
|
||||
|
||||
o, home = self.bootstrap(
|
||||
conf_default='/my/wacky/default.conf', in_tree=False
|
||||
)
|
||||
assert o.in_tree is False
|
||||
assert o.context == 'default'
|
||||
assert o.conf == paths.IPA_DEFAULT_CONF
|
||||
assert o.conf == '/etc/ipa/default.conf'
|
||||
assert o.conf_default == '/my/wacky/default.conf'
|
||||
|
||||
# Test various overrides and types conversion
|
||||
@@ -512,7 +530,7 @@ class test_Env(ClassChecker):
|
||||
assert key in o
|
||||
|
||||
# Check that it can't be called twice:
|
||||
e = raises(StandardError, o._finalize_core)
|
||||
e = raises(Exception, o._finalize_core)
|
||||
assert str(e) == 'Env._finalize_core() already called'
|
||||
|
||||
return (o, home)
|
||||
@@ -563,7 +581,8 @@ class test_Env(ClassChecker):
|
||||
# Test using DEFAULT_CONFIG:
|
||||
defaults = dict(constants.DEFAULT_CONFIG)
|
||||
(o, home) = self.finalize_core(None, **defaults)
|
||||
assert list(o) == sorted(defaults)
|
||||
list_o = [key for key in o if key != 'fips_mode']
|
||||
assert list_o == sorted(defaults)
|
||||
for (key, value) in defaults.items():
|
||||
if value is object:
|
||||
continue
|
||||
@@ -576,7 +595,7 @@ class test_Env(ClassChecker):
|
||||
Test the `ipalib.config.Env._finalize` method.
|
||||
"""
|
||||
# Check that calls cascade up the chain:
|
||||
(o, home) = self.new(in_tree=True)
|
||||
o, _home = self.new(in_tree=True)
|
||||
assert o._isdone('_bootstrap') is False
|
||||
assert o._isdone('_finalize_core') is False
|
||||
assert o._isdone('_finalize') is False
|
||||
@@ -586,19 +605,19 @@ class test_Env(ClassChecker):
|
||||
assert o._isdone('_finalize') is True
|
||||
|
||||
# Check that it can't be called twice:
|
||||
e = raises(StandardError, o._finalize)
|
||||
e = raises(Exception, o._finalize)
|
||||
assert str(e) == 'Env._finalize() already called'
|
||||
|
||||
# Check that _finalize() calls __lock__()
|
||||
(o, home) = self.new(in_tree=True)
|
||||
o, _home = self.new(in_tree=True)
|
||||
assert o.__islocked__() is False
|
||||
o._finalize()
|
||||
assert o.__islocked__() is True
|
||||
e = raises(StandardError, o.__lock__)
|
||||
e = raises(Exception, o.__lock__)
|
||||
assert str(e) == 'Env.__lock__() already called'
|
||||
|
||||
# Check that **lastchance works
|
||||
(o, home) = self.finalize_core(None)
|
||||
o, _home = self.finalize_core(None)
|
||||
key = 'just_one_more_key'
|
||||
value = u'with one more value'
|
||||
lastchance = {key: value}
|
||||
|
||||
@@ -21,10 +21,13 @@
|
||||
Test the `ipalib.crud` module.
|
||||
"""
|
||||
|
||||
from ipatests.util import read_only, raises, get_api, ClassChecker
|
||||
from ipalib import crud, frontend, plugable, config
|
||||
from ipatests.util import raises, get_api, ClassChecker
|
||||
from ipalib import crud, frontend
|
||||
from ipalib.parameters import Str
|
||||
|
||||
import pytest
|
||||
|
||||
pytestmark = pytest.mark.tier0
|
||||
|
||||
class CrudChecker(ClassChecker):
|
||||
"""
|
||||
@@ -35,7 +38,7 @@ class CrudChecker(ClassChecker):
|
||||
"""
|
||||
Return a finalized `ipalib.plugable.API` instance.
|
||||
"""
|
||||
(api, home) = get_api()
|
||||
api, _home = get_api()
|
||||
class user(frontend.Object):
|
||||
takes_params = (
|
||||
'givenname',
|
||||
@@ -47,8 +50,8 @@ class CrudChecker(ClassChecker):
|
||||
class user_verb(self.cls):
|
||||
takes_args = args
|
||||
takes_options = options
|
||||
api.register(user)
|
||||
api.register(user_verb)
|
||||
api.add_plugin(user)
|
||||
api.add_plugin(user_verb)
|
||||
api.finalize()
|
||||
return api
|
||||
|
||||
@@ -202,10 +205,11 @@ class test_CrudBackend(ClassChecker):
|
||||
return ldap
|
||||
|
||||
def check_method(self, name, *args):
|
||||
o = self.cls()
|
||||
api = 'the api instance'
|
||||
o = self.cls(api)
|
||||
e = raises(NotImplementedError, getattr(o, name), *args)
|
||||
assert str(e) == 'CrudBackend.%s()' % name
|
||||
sub = self.subcls()
|
||||
sub = self.subcls(api)
|
||||
e = raises(NotImplementedError, getattr(sub, name), *args)
|
||||
assert str(e) == 'ldap.%s()' % name
|
||||
|
||||
|
||||
@@ -21,40 +21,50 @@
|
||||
Test the `ipalib.errors` module.
|
||||
"""
|
||||
|
||||
# FIXME: Pylint errors
|
||||
# pylint: disable=no-member
|
||||
|
||||
import re
|
||||
import inspect
|
||||
import pytest
|
||||
|
||||
import six
|
||||
|
||||
from ipatests.util import assert_equal, raises
|
||||
from ipalib import errors, text
|
||||
from ipaplatform.paths import paths
|
||||
from ipalib import errors
|
||||
from ipalib.constants import TYPE_ERROR
|
||||
|
||||
if six.PY3:
|
||||
unicode = str
|
||||
|
||||
class PrivateExceptionTester(object):
|
||||
|
||||
pytestmark = pytest.mark.tier0
|
||||
|
||||
|
||||
class PrivateExceptionTester:
|
||||
_klass = None
|
||||
__klass = None
|
||||
|
||||
def __get_klass(self):
|
||||
if self.__klass is None:
|
||||
self.__klass = self._klass
|
||||
assert issubclass(self.__klass, StandardError)
|
||||
assert issubclass(self.__klass, Exception)
|
||||
assert issubclass(self.__klass, errors.PrivateError)
|
||||
assert not issubclass(self.__klass, errors.PublicError)
|
||||
return self.__klass
|
||||
klass = property(__get_klass)
|
||||
|
||||
def new(self, **kw):
|
||||
for (key, value) in kw.iteritems():
|
||||
for (key, value) in kw.items():
|
||||
assert not hasattr(self.klass, key), key
|
||||
inst = self.klass(**kw)
|
||||
assert isinstance(inst, StandardError)
|
||||
assert isinstance(inst, Exception)
|
||||
assert isinstance(inst, errors.PrivateError)
|
||||
assert isinstance(inst, self.klass)
|
||||
assert not isinstance(inst, errors.PublicError)
|
||||
for (key, value) in kw.iteritems():
|
||||
for (key, value) in kw.items():
|
||||
assert getattr(inst, key) is value
|
||||
assert str(inst) == self.klass.format % kw
|
||||
assert inst.message == str(inst)
|
||||
return inst
|
||||
|
||||
|
||||
@@ -103,11 +113,11 @@ class test_SubprocessError(PrivateExceptionTester):
|
||||
"""
|
||||
Test the `ipalib.errors.SubprocessError.__init__` method.
|
||||
"""
|
||||
inst = self.new(returncode=1, argv=(paths.BIN_FALSE,))
|
||||
bin_false = '/bin/false'
|
||||
inst = self.new(returncode=1, argv=(bin_false,))
|
||||
assert inst.returncode == 1
|
||||
assert inst.argv == (paths.BIN_FALSE,)
|
||||
assert str(inst) == "return code 1 from ('/bin/false',)"
|
||||
assert inst.message == str(inst)
|
||||
assert inst.argv == (bin_false,)
|
||||
assert str(inst) == "return code 1 from ('{}',)".format(bin_false)
|
||||
|
||||
|
||||
class test_PluginSubclassError(PrivateExceptionTester):
|
||||
@@ -126,7 +136,6 @@ class test_PluginSubclassError(PrivateExceptionTester):
|
||||
assert inst.bases == ('base1', 'base2')
|
||||
assert str(inst) == \
|
||||
"'bad' not subclass of any base in ('base1', 'base2')"
|
||||
assert inst.message == str(inst)
|
||||
|
||||
|
||||
class test_PluginDuplicateError(PrivateExceptionTester):
|
||||
@@ -143,7 +152,6 @@ class test_PluginDuplicateError(PrivateExceptionTester):
|
||||
inst = self.new(plugin='my_plugin')
|
||||
assert inst.plugin == 'my_plugin'
|
||||
assert str(inst) == "'my_plugin' was already registered"
|
||||
assert inst.message == str(inst)
|
||||
|
||||
|
||||
class test_PluginOverrideError(PrivateExceptionTester):
|
||||
@@ -162,7 +170,6 @@ class test_PluginOverrideError(PrivateExceptionTester):
|
||||
assert inst.name == 'cmd'
|
||||
assert inst.plugin == 'my_cmd'
|
||||
assert str(inst) == "unexpected override of Base.cmd with 'my_cmd'"
|
||||
assert inst.message == str(inst)
|
||||
|
||||
|
||||
class test_PluginMissingOverrideError(PrivateExceptionTester):
|
||||
@@ -181,21 +188,19 @@ class test_PluginMissingOverrideError(PrivateExceptionTester):
|
||||
assert inst.name == 'cmd'
|
||||
assert inst.plugin == 'my_cmd'
|
||||
assert str(inst) == "Base.cmd not registered, cannot override with 'my_cmd'"
|
||||
assert inst.message == str(inst)
|
||||
|
||||
|
||||
|
||||
##############################################################################
|
||||
# Unit tests for public errors:
|
||||
|
||||
class PublicExceptionTester(object):
|
||||
class PublicExceptionTester:
|
||||
_klass = None
|
||||
__klass = None
|
||||
|
||||
def __get_klass(self):
|
||||
if self.__klass is None:
|
||||
self.__klass = self._klass
|
||||
assert issubclass(self.__klass, StandardError)
|
||||
assert issubclass(self.__klass, Exception)
|
||||
assert issubclass(self.__klass, errors.PublicError)
|
||||
assert not issubclass(self.__klass, errors.PrivateError)
|
||||
assert type(self.__klass.errno) is int
|
||||
@@ -205,18 +210,18 @@ class PublicExceptionTester(object):
|
||||
|
||||
def new(self, format=None, message=None, **kw):
|
||||
# Test that TypeError is raised if message isn't unicode:
|
||||
e = raises(TypeError, self.klass, message='The message')
|
||||
assert str(e) == TYPE_ERROR % ('message', unicode, 'The message', str)
|
||||
e = raises(TypeError, self.klass, message=b'The message')
|
||||
assert str(e) == TYPE_ERROR % ('message', unicode, b'The message', bytes)
|
||||
|
||||
# Test the instance:
|
||||
for (key, value) in kw.iteritems():
|
||||
for (key, value) in kw.items():
|
||||
assert not hasattr(self.klass, key), key
|
||||
inst = self.klass(format=format, message=message, **kw)
|
||||
for required_class in self.required_classes:
|
||||
assert isinstance(inst, required_class)
|
||||
assert isinstance(inst, self.klass)
|
||||
assert not isinstance(inst, errors.PrivateError)
|
||||
for (key, value) in kw.iteritems():
|
||||
for (key, value) in kw.items():
|
||||
assert getattr(inst, key) is value
|
||||
return inst
|
||||
|
||||
@@ -226,20 +231,19 @@ class test_PublicError(PublicExceptionTester):
|
||||
Test the `ipalib.errors.PublicError` exception.
|
||||
"""
|
||||
_klass = errors.PublicError
|
||||
required_classes = StandardError, errors.PublicError
|
||||
required_classes = Exception, errors.PublicError
|
||||
|
||||
def test_init(self):
|
||||
message = u'The translated, interpolated message'
|
||||
format = 'key=%(key1)r and key2=%(key2)r'
|
||||
uformat = u'Translated key=%(key1)r and key2=%(key2)r'
|
||||
val1 = 'Value 1'
|
||||
val2 = 'Value 2'
|
||||
val1 = u'Value 1'
|
||||
val2 = u'Value 2'
|
||||
kw = dict(key1=val1, key2=val2)
|
||||
|
||||
# Test with format=str, message=None
|
||||
inst = self.klass(format, **kw)
|
||||
assert inst.format is format
|
||||
assert_equal(inst.message, format % kw)
|
||||
assert_equal(str(inst), format % kw)
|
||||
assert inst.forwarded is False
|
||||
assert inst.key1 is val1
|
||||
assert inst.key2 is val2
|
||||
@@ -247,15 +251,15 @@ class test_PublicError(PublicExceptionTester):
|
||||
# Test with format=None, message=unicode
|
||||
inst = self.klass(message=message, **kw)
|
||||
assert inst.format is None
|
||||
assert inst.message is message
|
||||
assert str(inst) == message
|
||||
assert inst.strerror is message
|
||||
assert inst.forwarded is True
|
||||
assert inst.key1 is val1
|
||||
assert inst.key2 is val2
|
||||
|
||||
# Test with format=None, message=str
|
||||
e = raises(TypeError, self.klass, message='the message', **kw)
|
||||
assert str(e) == TYPE_ERROR % ('message', unicode, 'the message', str)
|
||||
# Test with format=None, message=bytes
|
||||
e = raises(TypeError, self.klass, message=b'the message', **kw)
|
||||
assert str(e) == TYPE_ERROR % ('message', unicode, b'the message', bytes)
|
||||
|
||||
# Test with format=None, message=None
|
||||
e = raises(ValueError, self.klass, **kw)
|
||||
@@ -270,7 +274,7 @@ class test_PublicError(PublicExceptionTester):
|
||||
inst = self.new(format, **kw)
|
||||
assert isinstance(inst, self.klass)
|
||||
assert inst.format is format
|
||||
assert_equal(inst.message, format % kw)
|
||||
assert_equal(str(inst), format % kw)
|
||||
assert inst.forwarded is False
|
||||
assert inst.key1 is val1
|
||||
assert inst.key2 is val2
|
||||
@@ -279,7 +283,7 @@ class test_PublicError(PublicExceptionTester):
|
||||
inst = self.new(message=message, **kw)
|
||||
assert isinstance(inst, self.klass)
|
||||
assert inst.format is None
|
||||
assert inst.message is message
|
||||
assert str(inst) == message
|
||||
assert inst.strerror is message
|
||||
assert inst.forwarded is True
|
||||
assert inst.key1 is val1
|
||||
@@ -291,8 +295,7 @@ class test_PublicError(PublicExceptionTester):
|
||||
class subclass(self.klass):
|
||||
format = '%(true)r %(text)r %(number)r'
|
||||
|
||||
uformat = u'Translated %(true)r %(text)r %(number)r'
|
||||
kw = dict(true=True, text='Hello!', number=18)
|
||||
kw = dict(true=True, text=u'Hello!', number=18)
|
||||
|
||||
# Test with format=str, message=None
|
||||
e = raises(ValueError, subclass, format, **kw)
|
||||
@@ -302,7 +305,7 @@ class test_PublicError(PublicExceptionTester):
|
||||
# Test with format=None, message=None:
|
||||
inst = subclass(**kw)
|
||||
assert inst.format is subclass.format
|
||||
assert_equal(inst.message, subclass.format % kw)
|
||||
assert_equal(str(inst), subclass.format % kw)
|
||||
assert inst.forwarded is False
|
||||
assert inst.true is True
|
||||
assert inst.text is kw['text']
|
||||
@@ -311,7 +314,7 @@ class test_PublicError(PublicExceptionTester):
|
||||
# Test with format=None, message=unicode:
|
||||
inst = subclass(message=message, **kw)
|
||||
assert inst.format is subclass.format
|
||||
assert inst.message is message
|
||||
assert str(inst) == message
|
||||
assert inst.strerror is message
|
||||
assert inst.forwarded is True
|
||||
assert inst.true is True
|
||||
@@ -326,17 +329,16 @@ class test_PublicError(PublicExceptionTester):
|
||||
# this expression checks if each word of instructions
|
||||
# exists in a string as a separate line, with right order
|
||||
regexp = re.compile('(?ims).*' +
|
||||
''.join(map(lambda x: '(%s).*' % (x),
|
||||
instructions)) +
|
||||
''.join('(%s).*' % (x) for x in instructions) +
|
||||
'$')
|
||||
inst = subclass(instructions=instructions, **kw)
|
||||
assert inst.format is subclass.format
|
||||
assert_equal(inst.instructions, instructions)
|
||||
assert_equal(inst.instructions, unicode(instructions))
|
||||
inst_match = regexp.match(inst.strerror).groups()
|
||||
assert_equal(list(inst_match),list(instructions))
|
||||
|
||||
|
||||
class BaseMessagesTest(object):
|
||||
class BaseMessagesTest:
|
||||
"""Generic test for all of a module's errors or messages
|
||||
"""
|
||||
def test_public_messages(self):
|
||||
@@ -365,10 +367,10 @@ class BaseMessagesTest(object):
|
||||
pass
|
||||
|
||||
|
||||
class test_PublicErrors(object):
|
||||
class test_PublicErrors:
|
||||
message_list = errors.public_errors
|
||||
errno_range = xrange(900, 5999)
|
||||
required_classes = (StandardError, errors.PublicError)
|
||||
errno_range = list(range(900, 5999))
|
||||
required_classes = (Exception, errors.PublicError)
|
||||
texts = errors._texts
|
||||
|
||||
def extratest(self, cls):
|
||||
|
||||
@@ -21,8 +21,11 @@
|
||||
Test the `ipalib.frontend` module.
|
||||
"""
|
||||
|
||||
from ipatests.util import raises, getitem, no_set, no_del, read_only
|
||||
from ipatests.util import check_TypeError, ClassChecker, create_test_api
|
||||
import pytest
|
||||
import six
|
||||
|
||||
from ipatests.util import raises, read_only
|
||||
from ipatests.util import ClassChecker, create_test_api
|
||||
from ipatests.util import assert_equal
|
||||
from ipalib.constants import TYPE_ERROR
|
||||
from ipalib.base import NameSpace
|
||||
@@ -31,6 +34,13 @@ from ipalib import output, messages
|
||||
from ipalib.parameters import Str
|
||||
from ipapython.version import API_VERSION
|
||||
|
||||
if six.PY3:
|
||||
unicode = str
|
||||
|
||||
|
||||
pytestmark = pytest.mark.tier0
|
||||
|
||||
|
||||
def test_RULE_FLAG():
|
||||
assert frontend.RULE_FLAG == 'validation_rule'
|
||||
|
||||
@@ -59,7 +69,7 @@ def test_is_rule():
|
||||
is_rule = frontend.is_rule
|
||||
flag = frontend.RULE_FLAG
|
||||
|
||||
class no_call(object):
|
||||
class no_call:
|
||||
def __init__(self, value):
|
||||
if value is not None:
|
||||
assert value in (True, False)
|
||||
@@ -86,31 +96,32 @@ class test_HasParam(ClassChecker):
|
||||
"""
|
||||
Test the `ipalib.frontend.HasParam._get_param_iterable` method.
|
||||
"""
|
||||
api = 'the api instance'
|
||||
class WithTuple(self.cls):
|
||||
takes_stuff = ('one', 'two')
|
||||
o = WithTuple()
|
||||
o = WithTuple(api)
|
||||
assert o._get_param_iterable('stuff') is WithTuple.takes_stuff
|
||||
|
||||
junk = ('three', 'four')
|
||||
class WithCallable(self.cls):
|
||||
def takes_stuff(self):
|
||||
return junk
|
||||
o = WithCallable()
|
||||
o = WithCallable(api)
|
||||
assert o._get_param_iterable('stuff') is junk
|
||||
|
||||
class WithParam(self.cls):
|
||||
takes_stuff = parameters.Str('five')
|
||||
o = WithParam()
|
||||
o = WithParam(api)
|
||||
assert o._get_param_iterable('stuff') == (WithParam.takes_stuff,)
|
||||
|
||||
class WithStr(self.cls):
|
||||
takes_stuff = 'six'
|
||||
o = WithStr()
|
||||
o = WithStr(api)
|
||||
assert o._get_param_iterable('stuff') == ('six',)
|
||||
|
||||
class Wrong(self.cls):
|
||||
takes_stuff = ['seven', 'eight']
|
||||
o = Wrong()
|
||||
o = Wrong(api)
|
||||
e = raises(TypeError, o._get_param_iterable, 'stuff')
|
||||
assert str(e) == '%s.%s must be a tuple, callable, or spec; got %r' % (
|
||||
'Wrong', 'takes_stuff', Wrong.takes_stuff
|
||||
@@ -120,6 +131,7 @@ class test_HasParam(ClassChecker):
|
||||
"""
|
||||
Test the `ipalib.frontend.HasParam._filter_param_by_context` method.
|
||||
"""
|
||||
api = 'the api instance'
|
||||
class Example(self.cls):
|
||||
def get_stuff(self):
|
||||
return (
|
||||
@@ -129,7 +141,7 @@ class test_HasParam(ClassChecker):
|
||||
parameters.Str('four', exclude='server'),
|
||||
parameters.Str('five', exclude=['whatever', 'cli']),
|
||||
)
|
||||
o = Example()
|
||||
o = Example(api)
|
||||
|
||||
# Test when env is None:
|
||||
params = list(o._filter_param_by_context('stuff'))
|
||||
@@ -158,7 +170,7 @@ class test_HasParam(ClassChecker):
|
||||
# Test with no get_stuff:
|
||||
class Missing(self.cls):
|
||||
pass
|
||||
o = Missing()
|
||||
o = Missing(api)
|
||||
gen = o._filter_param_by_context('stuff')
|
||||
e = raises(NotImplementedError, list, gen)
|
||||
assert str(e) == 'Missing.get_stuff()'
|
||||
@@ -166,7 +178,7 @@ class test_HasParam(ClassChecker):
|
||||
# Test when get_stuff is not callable:
|
||||
class NotCallable(self.cls):
|
||||
get_stuff = ('one', 'two')
|
||||
o = NotCallable()
|
||||
o = NotCallable(api)
|
||||
gen = o._filter_param_by_context('stuff')
|
||||
e = raises(TypeError, list, gen)
|
||||
assert str(e) == '%s.%s must be a callable; got %r' % (
|
||||
@@ -185,13 +197,15 @@ class test_Command(ClassChecker):
|
||||
"""
|
||||
Return a standard subclass of `ipalib.frontend.Command`.
|
||||
"""
|
||||
class Rule(object):
|
||||
class Rule:
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
|
||||
def __call__(self, _, value):
|
||||
if value != self.name:
|
||||
return _('must equal %r') % self.name
|
||||
else:
|
||||
return None
|
||||
|
||||
default_from = parameters.DefaultFrom(
|
||||
lambda arg: arg,
|
||||
@@ -216,10 +230,14 @@ class test_Command(ClassChecker):
|
||||
"""
|
||||
Helper method used to test args and options.
|
||||
"""
|
||||
class api:
|
||||
@staticmethod
|
||||
def is_production_mode():
|
||||
return False
|
||||
class example(self.cls):
|
||||
takes_args = args
|
||||
takes_options = options
|
||||
o = example()
|
||||
o = example(api)
|
||||
o.finalize()
|
||||
return o
|
||||
|
||||
@@ -234,7 +252,8 @@ class test_Command(ClassChecker):
|
||||
"""
|
||||
Test the `ipalib.frontend.Command.get_args` method.
|
||||
"""
|
||||
assert list(self.cls().get_args()) == []
|
||||
api = 'the api instance'
|
||||
assert list(self.cls(api).get_args()) == []
|
||||
args = ('login', 'stuff')
|
||||
o = self.get_instance(args=args)
|
||||
assert tuple(o.get_args()) == args
|
||||
@@ -243,7 +262,8 @@ class test_Command(ClassChecker):
|
||||
"""
|
||||
Test the `ipalib.frontend.Command.get_options` method.
|
||||
"""
|
||||
options = list(self.cls().get_options())
|
||||
api = 'the api instance'
|
||||
options = list(self.cls(api).get_options())
|
||||
assert len(options) == 1
|
||||
assert options[0].name == 'version'
|
||||
options = ('verbose', 'debug')
|
||||
@@ -256,14 +276,17 @@ class test_Command(ClassChecker):
|
||||
"""
|
||||
Test the ``ipalib.frontend.Command.args`` instance attribute.
|
||||
"""
|
||||
assert self.cls().args is None
|
||||
o = self.cls()
|
||||
class api:
|
||||
@staticmethod
|
||||
def is_production_mode():
|
||||
return False
|
||||
o = self.cls(api)
|
||||
o.finalize()
|
||||
assert type(o.args) is plugable.NameSpace
|
||||
assert type(o.args) is NameSpace
|
||||
assert len(o.args) == 0
|
||||
args = ('destination', 'source?')
|
||||
ns = self.get_instance(args=args).args
|
||||
assert type(ns) is plugable.NameSpace
|
||||
assert type(ns) is NameSpace
|
||||
assert len(ns) == len(args)
|
||||
assert list(ns) == ['destination', 'source']
|
||||
assert type(ns.destination) is parameters.Str
|
||||
@@ -274,9 +297,14 @@ class test_Command(ClassChecker):
|
||||
assert ns.source.multivalue is False
|
||||
|
||||
# Test TypeError:
|
||||
e = raises(TypeError, self.get_instance, args=(u'whatever',))
|
||||
assert str(e) == TYPE_ERROR % (
|
||||
'spec', (str, parameters.Param), u'whatever', unicode)
|
||||
if six.PY2:
|
||||
e = raises(TypeError, self.get_instance, args=(u'whatever',))
|
||||
assert str(e) == TYPE_ERROR % (
|
||||
'spec', (str, parameters.Param), u'whatever', unicode)
|
||||
else:
|
||||
e = raises(TypeError, self.get_instance, args=(b'whatever',))
|
||||
assert str(e) == TYPE_ERROR % (
|
||||
'spec', (str, parameters.Param), b'whatever', bytes)
|
||||
|
||||
# Test ValueError, required after optional:
|
||||
e = raises(ValueError, self.get_instance, args=('arg1?', 'arg2'))
|
||||
@@ -305,14 +333,17 @@ class test_Command(ClassChecker):
|
||||
"""
|
||||
Test the ``ipalib.frontend.Command.options`` instance attribute.
|
||||
"""
|
||||
assert self.cls().options is None
|
||||
o = self.cls()
|
||||
class api:
|
||||
@staticmethod
|
||||
def is_production_mode():
|
||||
return False
|
||||
o = self.cls(api)
|
||||
o.finalize()
|
||||
assert type(o.options) is plugable.NameSpace
|
||||
assert type(o.options) is NameSpace
|
||||
assert len(o.options) == 1
|
||||
options = ('target', 'files*')
|
||||
ns = self.get_instance(options=options).options
|
||||
assert type(ns) is plugable.NameSpace
|
||||
assert type(ns) is NameSpace
|
||||
assert len(ns) == len(options) + 1
|
||||
assert list(ns) == ['target', 'files', 'version']
|
||||
assert type(ns.target) is parameters.Str
|
||||
@@ -326,10 +357,13 @@ class test_Command(ClassChecker):
|
||||
"""
|
||||
Test the ``ipalib.frontend.Command.output`` instance attribute.
|
||||
"""
|
||||
inst = self.cls()
|
||||
assert inst.output is None
|
||||
class api:
|
||||
@staticmethod
|
||||
def is_production_mode():
|
||||
return False
|
||||
inst = self.cls(api)
|
||||
inst.finalize()
|
||||
assert type(inst.output) is plugable.NameSpace
|
||||
assert type(inst.output) is NameSpace
|
||||
assert list(inst.output) == ['result']
|
||||
assert type(inst.output.result) is output.Output
|
||||
|
||||
@@ -337,9 +371,10 @@ class test_Command(ClassChecker):
|
||||
"""
|
||||
Test the ``ipalib.frontend.Command._iter_output`` instance attribute.
|
||||
"""
|
||||
api = 'the api instance'
|
||||
class Example(self.cls):
|
||||
pass
|
||||
inst = Example()
|
||||
inst = Example(api)
|
||||
|
||||
inst.has_output = tuple()
|
||||
assert list(inst._iter_output()) == []
|
||||
@@ -366,54 +401,37 @@ class test_Command(ClassChecker):
|
||||
for o in items:
|
||||
assert type(o) is output.Output
|
||||
|
||||
def test_soft_validate(self):
|
||||
"""
|
||||
Test the `ipalib.frontend.Command.soft_validate` method.
|
||||
"""
|
||||
class user_add(frontend.Command):
|
||||
takes_args = parameters.Str('uid',
|
||||
normalizer=lambda value: value.lower(),
|
||||
default_from=lambda givenname, sn: givenname[0] + sn,
|
||||
)
|
||||
|
||||
takes_options = ('givenname', 'sn')
|
||||
|
||||
cmd = user_add()
|
||||
cmd.env = config.Env(context='cli')
|
||||
cmd.finalize()
|
||||
assert list(cmd.params) == ['givenname', 'sn', 'uid', 'version']
|
||||
ret = cmd.soft_validate({})
|
||||
assert sorted(ret['values']) == ['version']
|
||||
assert sorted(ret['errors']) == ['givenname', 'sn', 'uid']
|
||||
assert cmd.soft_validate(dict(givenname=u'First', sn=u'Last')) == dict(
|
||||
values=dict(givenname=u'First', sn=u'Last', uid=u'flast',
|
||||
version=None),
|
||||
errors=dict(),
|
||||
)
|
||||
|
||||
def test_convert(self):
|
||||
"""
|
||||
Test the `ipalib.frontend.Command.convert` method.
|
||||
"""
|
||||
class api:
|
||||
@staticmethod
|
||||
def is_production_mode():
|
||||
return False
|
||||
kw = dict(
|
||||
option0=u'1.5',
|
||||
option1=u'7',
|
||||
)
|
||||
o = self.subcls()
|
||||
o = self.subcls(api)
|
||||
o.finalize()
|
||||
for (key, value) in o.convert(**kw).iteritems():
|
||||
for (key, value) in o.convert(**kw).items():
|
||||
assert_equal(unicode(kw[key]), value)
|
||||
|
||||
def test_normalize(self):
|
||||
"""
|
||||
Test the `ipalib.frontend.Command.normalize` method.
|
||||
"""
|
||||
class api:
|
||||
@staticmethod
|
||||
def is_production_mode():
|
||||
return False
|
||||
kw = dict(
|
||||
option0=u'OPTION0',
|
||||
option1=u'OPTION1',
|
||||
)
|
||||
norm = dict((k, v.lower()) for (k, v) in kw.items())
|
||||
sub = self.subcls()
|
||||
sub = self.subcls(api)
|
||||
sub.finalize()
|
||||
assert sub.normalize(**kw) == norm
|
||||
|
||||
@@ -439,24 +457,26 @@ class test_Command(ClassChecker):
|
||||
|
||||
kw = dict(option0=u'some value')
|
||||
|
||||
(api, home) = create_test_api()
|
||||
api, _home = create_test_api()
|
||||
api.finalize()
|
||||
o = my_cmd()
|
||||
o.set_api(api)
|
||||
o = my_cmd(api)
|
||||
o.finalize()
|
||||
e = o(**kw)
|
||||
e = o.get_default(**kw) # pylint: disable=not-callable
|
||||
assert type(e) is dict
|
||||
assert 'result' in e
|
||||
assert 'option2' in e['result']
|
||||
assert e['result']['option2'] == u'some value'
|
||||
assert 'option2' in e
|
||||
assert e['option2'] == u'some value'
|
||||
|
||||
def test_validate(self):
|
||||
"""
|
||||
Test the `ipalib.frontend.Command.validate` method.
|
||||
"""
|
||||
class api:
|
||||
env = config.Env(context='cli')
|
||||
@staticmethod
|
||||
def is_production_mode():
|
||||
return False
|
||||
|
||||
sub = self.subcls()
|
||||
sub.env = config.Env(context='cli')
|
||||
sub = self.subcls(api)
|
||||
sub.finalize()
|
||||
|
||||
# Check with valid values
|
||||
@@ -472,11 +492,8 @@ class test_Command(ClassChecker):
|
||||
fail = dict(okay)
|
||||
fail['option0'] = u'whatever'
|
||||
e = raises(errors.ValidationError, sub.validate, **fail)
|
||||
assert_equal(e.name, 'option0')
|
||||
assert_equal(e.value, u'whatever')
|
||||
assert_equal(e.name, u'option0')
|
||||
assert_equal(e.error, u"must equal 'option0'")
|
||||
assert e.rule.__class__.__name__ == 'Rule'
|
||||
assert e.index is None
|
||||
|
||||
# Check with a missing required arg
|
||||
fail = dict(okay)
|
||||
@@ -488,7 +505,8 @@ class test_Command(ClassChecker):
|
||||
"""
|
||||
Test the `ipalib.frontend.Command.execute` method.
|
||||
"""
|
||||
o = self.cls()
|
||||
api = 'the api instance'
|
||||
o = self.cls(api)
|
||||
e = raises(NotImplementedError, o.execute)
|
||||
assert str(e) == 'Command.execute()'
|
||||
|
||||
@@ -525,7 +543,7 @@ class test_Command(ClassChecker):
|
||||
o = self.get_instance(args=('one', 'two'), options=('three', 'four'))
|
||||
e = raises(errors.OverlapError, o.args_options_2_params,
|
||||
1, 2, three=3, two=2, four=4, one=1)
|
||||
assert e.names == ['one', 'two']
|
||||
assert e.names == "['one', 'two']"
|
||||
|
||||
# Test the permutations:
|
||||
o = self.get_instance(args=('one', 'two*'), options=('three', 'four'))
|
||||
@@ -563,10 +581,9 @@ class test_Command(ClassChecker):
|
||||
args = ('one', 'two')
|
||||
kw = dict(three=('three1', 'three2'), four='four')
|
||||
|
||||
(api, home) = create_test_api()
|
||||
api, _home = create_test_api()
|
||||
api.finalize()
|
||||
o = my_cmd()
|
||||
o.set_api(api)
|
||||
o = my_cmd(api)
|
||||
o.finalize()
|
||||
e = o.run(*args, **kw)
|
||||
assert type(e) is dict
|
||||
@@ -583,9 +600,9 @@ class test_Command(ClassChecker):
|
||||
Test the `ipalib.frontend.Command.params_2_args_options` method.
|
||||
"""
|
||||
o = self.get_instance(args='one', options='two')
|
||||
assert o.params_2_args_options() == ((None,), {})
|
||||
assert o.params_2_args_options() == ((), {})
|
||||
assert o.params_2_args_options(one=1) == ((1,), {})
|
||||
assert o.params_2_args_options(two=2) == ((None,), dict(two=2))
|
||||
assert o.params_2_args_options(two=2) == ((), dict(two=2))
|
||||
assert o.params_2_args_options(two=2, one=1) == ((1,), dict(two=2))
|
||||
|
||||
def test_run(self):
|
||||
@@ -603,20 +620,24 @@ class test_Command(ClassChecker):
|
||||
kw = dict(how_are='you', on_this='fine day?', version=API_VERSION)
|
||||
|
||||
# Test in server context:
|
||||
(api, home) = create_test_api(in_server=True)
|
||||
api, _home = create_test_api(in_server=True)
|
||||
api.finalize()
|
||||
o = my_cmd()
|
||||
o.set_api(api)
|
||||
assert o.run.im_func is self.cls.run.im_func
|
||||
o = my_cmd(api)
|
||||
if six.PY2:
|
||||
assert o.run.__func__ is self.cls.run.__func__
|
||||
else:
|
||||
assert o.run.__func__ is self.cls.run
|
||||
out = o.run(*args, **kw)
|
||||
assert ('execute', args, kw) == out
|
||||
|
||||
# Test in non-server context
|
||||
(api, home) = create_test_api(in_server=False)
|
||||
api, _home = create_test_api(in_server=False)
|
||||
api.finalize()
|
||||
o = my_cmd()
|
||||
o.set_api(api)
|
||||
assert o.run.im_func is self.cls.run.im_func
|
||||
o = my_cmd(api)
|
||||
if six.PY2:
|
||||
assert o.run.__func__ is self.cls.run.__func__
|
||||
else:
|
||||
assert o.run.__func__ is self.cls.run
|
||||
assert ('forward', args, kw) == o.run(*args, **kw)
|
||||
|
||||
def test_messages(self):
|
||||
@@ -645,29 +666,37 @@ class test_Command(ClassChecker):
|
||||
expected = [TestMessage().to_dict()]
|
||||
|
||||
# Test in server context:
|
||||
(api, home) = create_test_api(in_server=True)
|
||||
api, _home = create_test_api(in_server=True)
|
||||
api.finalize()
|
||||
o = my_cmd()
|
||||
o.set_api(api)
|
||||
assert o.run.im_func is self.cls.run.im_func
|
||||
o = my_cmd(api)
|
||||
if six.PY2:
|
||||
assert o.run.__func__ is self.cls.run.__func__
|
||||
else:
|
||||
assert o.run.__func__ is self.cls.run
|
||||
assert {'name': 'execute', 'messages': expected} == o.run(*args, **kw)
|
||||
|
||||
# Test in non-server context
|
||||
(api, home) = create_test_api(in_server=False)
|
||||
api, _home = create_test_api(in_server=False)
|
||||
api.finalize()
|
||||
o = my_cmd()
|
||||
o.set_api(api)
|
||||
assert o.run.im_func is self.cls.run.im_func
|
||||
o = my_cmd(api)
|
||||
if six.PY2:
|
||||
assert o.run.__func__ is self.cls.run.__func__
|
||||
else:
|
||||
assert o.run.__func__ is self.cls.run
|
||||
assert {'name': 'forward', 'messages': expected} == o.run(*args, **kw)
|
||||
|
||||
def test_validate_output_basic(self):
|
||||
"""
|
||||
Test the `ipalib.frontend.Command.validate_output` method.
|
||||
"""
|
||||
class api:
|
||||
@staticmethod
|
||||
def is_production_mode():
|
||||
return False
|
||||
class Example(self.cls):
|
||||
has_output = ('foo', 'bar', 'baz')
|
||||
|
||||
inst = Example()
|
||||
inst = Example(api)
|
||||
inst.finalize()
|
||||
|
||||
# Test with wrong type:
|
||||
@@ -702,24 +731,28 @@ class test_Command(ClassChecker):
|
||||
"""
|
||||
Test `ipalib.frontend.Command.validate_output` per-type validation.
|
||||
"""
|
||||
class api:
|
||||
@staticmethod
|
||||
def is_production_mode():
|
||||
return False
|
||||
|
||||
class Complex(self.cls):
|
||||
has_output = (
|
||||
output.Output('foo', int),
|
||||
output.Output('bar', list),
|
||||
)
|
||||
inst = Complex()
|
||||
inst = Complex(api)
|
||||
inst.finalize()
|
||||
|
||||
wrong = dict(foo=17.9, bar=[18])
|
||||
e = raises(TypeError, inst.validate_output, wrong)
|
||||
assert str(e) == '%s:\n output[%r]: need %r; got %r: %r' % (
|
||||
assert str(e) == '%s:\n output[%r]: need (%r,); got %r: %r' % (
|
||||
'Complex.validate_output()', 'foo', int, float, 17.9
|
||||
)
|
||||
|
||||
wrong = dict(foo=18, bar=17)
|
||||
e = raises(TypeError, inst.validate_output, wrong)
|
||||
assert str(e) == '%s:\n output[%r]: need %r; got %r: %r' % (
|
||||
assert str(e) == '%s:\n output[%r]: need (%r,); got %r: %r' % (
|
||||
'Complex.validate_output()', 'bar', list, int, 17
|
||||
)
|
||||
|
||||
@@ -727,6 +760,10 @@ class test_Command(ClassChecker):
|
||||
"""
|
||||
Test `ipalib.frontend.Command.validate_output` nested validation.
|
||||
"""
|
||||
class api:
|
||||
@staticmethod
|
||||
def is_production_mode():
|
||||
return False
|
||||
|
||||
class Subclass(output.ListOfEntries):
|
||||
pass
|
||||
@@ -737,7 +774,7 @@ class test_Command(ClassChecker):
|
||||
output.Output('hello', int),
|
||||
Subclass('world'),
|
||||
)
|
||||
inst = nested()
|
||||
inst = nested(api)
|
||||
inst.finalize()
|
||||
okay = dict(foo='bar')
|
||||
nope = ('aye', 'bee')
|
||||
@@ -758,6 +795,10 @@ class test_Command(ClassChecker):
|
||||
"""
|
||||
Test the `ipalib.frontend.Command.get_output_params` method.
|
||||
"""
|
||||
class api:
|
||||
@staticmethod
|
||||
def is_production_mode():
|
||||
return False
|
||||
class example(self.cls):
|
||||
has_output_params = (
|
||||
'one',
|
||||
@@ -768,17 +809,16 @@ class test_Command(ClassChecker):
|
||||
'foo',
|
||||
)
|
||||
takes_options = (
|
||||
Str('bar', flags='no_output'),
|
||||
Str('bar'),
|
||||
'baz',
|
||||
)
|
||||
|
||||
inst = example()
|
||||
assert list(inst.get_output_params()) == ['one', 'two', 'three']
|
||||
inst = example(api)
|
||||
inst.finalize()
|
||||
assert list(inst.get_output_params()) == [
|
||||
'one', 'two', 'three', inst.params.foo, inst.params.baz
|
||||
'one', 'two', 'three'
|
||||
]
|
||||
assert list(inst.output_params) == ['one', 'two', 'three', 'foo', 'baz']
|
||||
assert list(inst.output_params) == ['one', 'two', 'three']
|
||||
|
||||
|
||||
class test_LocalOrRemote(ClassChecker):
|
||||
@@ -791,7 +831,11 @@ class test_LocalOrRemote(ClassChecker):
|
||||
"""
|
||||
Test the `ipalib.frontend.LocalOrRemote.__init__` method.
|
||||
"""
|
||||
o = self.cls()
|
||||
class api:
|
||||
@staticmethod
|
||||
def is_production_mode():
|
||||
return False
|
||||
o = self.cls(api)
|
||||
o.finalize()
|
||||
assert list(o.args) == []
|
||||
assert list(o.options) == ['server', 'version']
|
||||
@@ -813,36 +857,36 @@ class test_LocalOrRemote(ClassChecker):
|
||||
return dict(result=('execute', args, options))
|
||||
|
||||
# Test when in_server=False:
|
||||
(api, home) = create_test_api(in_server=False)
|
||||
api.register(example)
|
||||
api, _home = create_test_api(in_server=False)
|
||||
api.add_plugin(example)
|
||||
api.finalize()
|
||||
cmd = api.Command.example
|
||||
assert cmd(version=u'2.47') == dict(
|
||||
result=('execute', (None,), dict(version=u'2.47', server=False))
|
||||
result=('execute', (), dict(version=u'2.47'))
|
||||
)
|
||||
assert cmd(u'var', version=u'2.47') == dict(
|
||||
result=('execute', (u'var',), dict(version=u'2.47', server=False))
|
||||
result=('execute', (u'var',), dict(version=u'2.47'))
|
||||
)
|
||||
assert cmd(server=True, version=u'2.47') == dict(
|
||||
result=('forward', (None,), dict(version=u'2.47', server=True))
|
||||
result=('forward', (), dict(version=u'2.47', server=True))
|
||||
)
|
||||
assert cmd(u'var', server=True, version=u'2.47') == dict(
|
||||
result=('forward', (u'var',), dict(version=u'2.47', server=True))
|
||||
)
|
||||
|
||||
# Test when in_server=True (should always call execute):
|
||||
(api, home) = create_test_api(in_server=True)
|
||||
api.register(example)
|
||||
api, _home = create_test_api(in_server=True)
|
||||
api.add_plugin(example)
|
||||
api.finalize()
|
||||
cmd = api.Command.example
|
||||
assert cmd(version=u'2.47') == dict(
|
||||
result=('execute', (None,), dict(version=u'2.47', server=False))
|
||||
result=('execute', (), dict(version=u'2.47', server=False))
|
||||
)
|
||||
assert cmd(u'var', version=u'2.47') == dict(
|
||||
result=('execute', (u'var',), dict(version=u'2.47', server=False))
|
||||
)
|
||||
assert cmd(server=True, version=u'2.47') == dict(
|
||||
result=('execute', (None,), dict(version=u'2.47', server=True))
|
||||
result=('execute', (), dict(version=u'2.47', server=True))
|
||||
)
|
||||
assert cmd(u'var', server=True, version=u'2.47') == dict(
|
||||
result=('execute', (u'var',), dict(version=u'2.47', server=True))
|
||||
@@ -869,18 +913,8 @@ class test_Object(ClassChecker):
|
||||
"""
|
||||
Test the `ipalib.frontend.Object.__init__` method.
|
||||
"""
|
||||
o = self.cls()
|
||||
assert o.backend is None
|
||||
assert o.methods is None
|
||||
assert o.params is None
|
||||
assert o.params_minus_pk is None
|
||||
|
||||
def test_set_api(self):
|
||||
"""
|
||||
Test the `ipalib.frontend.Object.set_api` method.
|
||||
"""
|
||||
# Setup for test:
|
||||
class DummyAttribute(object):
|
||||
class DummyAttribute:
|
||||
def __init__(self, obj_name, attr_name, name=None):
|
||||
self.obj_name = obj_name
|
||||
self.attr_name = attr_name
|
||||
@@ -888,6 +922,9 @@ class test_Object(ClassChecker):
|
||||
self.name = '%s_%s' % (obj_name, attr_name)
|
||||
else:
|
||||
self.name = name
|
||||
self.bases = (DummyAttribute,)
|
||||
self.version = '1'
|
||||
self.full_name = '{}/{}'.format(self.name, self.version)
|
||||
self.param = frontend.create_param(attr_name)
|
||||
|
||||
def __clone__(self, attr_name):
|
||||
@@ -899,33 +936,40 @@ class test_Object(ClassChecker):
|
||||
|
||||
def get_attributes(cnt, format):
|
||||
for name in ['other', 'user', 'another']:
|
||||
for i in xrange(cnt):
|
||||
for i in range(cnt):
|
||||
yield DummyAttribute(name, format % i)
|
||||
|
||||
cnt = 10
|
||||
methods_format = 'method_%d'
|
||||
|
||||
_d = dict(
|
||||
Method=plugable.NameSpace(
|
||||
get_attributes(cnt, methods_format)
|
||||
),
|
||||
)
|
||||
api = plugable.MagicDict(_d)
|
||||
class FakeAPI:
|
||||
def __init__(self):
|
||||
self._API__plugins = get_attributes(cnt, methods_format)
|
||||
self._API__default_map = {}
|
||||
self.Method = plugable.APINameSpace(self, DummyAttribute)
|
||||
def __contains__(self, key):
|
||||
return hasattr(self, key)
|
||||
def __getitem__(self, key):
|
||||
return getattr(self, key)
|
||||
def is_production_mode(self):
|
||||
return False
|
||||
def _get(self, plugin):
|
||||
return plugin
|
||||
api = FakeAPI()
|
||||
assert len(api.Method) == cnt * 3
|
||||
|
||||
class user(self.cls):
|
||||
pass
|
||||
|
||||
# Actually perform test:
|
||||
o = user()
|
||||
o.set_api(api)
|
||||
o = user(api)
|
||||
assert read_only(o, 'api') is api
|
||||
|
||||
namespace = o.methods
|
||||
assert isinstance(namespace, plugable.NameSpace)
|
||||
assert isinstance(namespace, NameSpace)
|
||||
assert len(namespace) == cnt
|
||||
f = methods_format
|
||||
for i in xrange(cnt):
|
||||
for i in range(cnt):
|
||||
attr_name = f % i
|
||||
attr = namespace[attr_name]
|
||||
assert isinstance(attr, DummyAttribute)
|
||||
@@ -935,17 +979,15 @@ class test_Object(ClassChecker):
|
||||
assert attr.name == '%s_%s' % ('user', attr_name)
|
||||
|
||||
# Test params instance attribute
|
||||
o = self.cls()
|
||||
o.set_api(api)
|
||||
o = self.cls(api)
|
||||
ns = o.params
|
||||
assert type(ns) is plugable.NameSpace
|
||||
assert type(ns) is NameSpace
|
||||
assert len(ns) == 0
|
||||
class example(self.cls):
|
||||
takes_params = ('banana', 'apple')
|
||||
o = example()
|
||||
o.set_api(api)
|
||||
o = example(api)
|
||||
ns = o.params
|
||||
assert type(ns) is plugable.NameSpace
|
||||
assert type(ns) is NameSpace
|
||||
assert len(ns) == 2, repr(ns)
|
||||
assert list(ns) == ['banana', 'apple']
|
||||
for p in ns():
|
||||
@@ -957,7 +999,7 @@ class test_Object(ClassChecker):
|
||||
"""
|
||||
Test the `ipalib.frontend.Object.primary_key` attribute.
|
||||
"""
|
||||
(api, home) = create_test_api()
|
||||
api, _home = create_test_api()
|
||||
api.finalize()
|
||||
|
||||
# Test with no primary keys:
|
||||
@@ -966,8 +1008,7 @@ class test_Object(ClassChecker):
|
||||
'one',
|
||||
'two',
|
||||
)
|
||||
o = example1()
|
||||
o.set_api(api)
|
||||
o = example1(api)
|
||||
assert o.primary_key is None
|
||||
|
||||
# Test with 1 primary key:
|
||||
@@ -978,14 +1019,13 @@ class test_Object(ClassChecker):
|
||||
parameters.Str('three', primary_key=True),
|
||||
'four',
|
||||
)
|
||||
o = example2()
|
||||
o.set_api(api)
|
||||
o = example2(api)
|
||||
pk = o.primary_key
|
||||
assert type(pk) is parameters.Str
|
||||
assert pk.name == 'three'
|
||||
assert pk.primary_key is True
|
||||
assert o.params[2] is o.primary_key
|
||||
assert isinstance(o.params_minus_pk, plugable.NameSpace)
|
||||
assert isinstance(o.params_minus_pk, NameSpace)
|
||||
assert list(o.params_minus_pk) == ['one', 'two', 'four']
|
||||
|
||||
# Test with multiple primary_key:
|
||||
@@ -996,8 +1036,7 @@ class test_Object(ClassChecker):
|
||||
'three',
|
||||
parameters.Str('four', primary_key=True),
|
||||
)
|
||||
o = example3()
|
||||
o.set_api(api)
|
||||
o = example3(api)
|
||||
e = raises(ValueError, o.finalize)
|
||||
assert str(e) == \
|
||||
'example3 (Object) has multiple primary keys: one, two, four'
|
||||
@@ -1006,13 +1045,13 @@ class test_Object(ClassChecker):
|
||||
"""
|
||||
Test the `ipalib.frontend.Object.backend` attribute.
|
||||
"""
|
||||
(api, home) = create_test_api()
|
||||
api, _home = create_test_api()
|
||||
class ldap(backend.Backend):
|
||||
whatever = 'It worked!'
|
||||
api.register(ldap)
|
||||
api.add_plugin(ldap)
|
||||
class user(frontend.Object):
|
||||
backend_name = 'ldap'
|
||||
api.register(user)
|
||||
api.add_plugin(user)
|
||||
api.finalize()
|
||||
b = api.Object.user.backend
|
||||
assert isinstance(b, ldap)
|
||||
@@ -1022,12 +1061,13 @@ class test_Object(ClassChecker):
|
||||
"""
|
||||
Test the `ipalib.frontend.Object.get_dn` method.
|
||||
"""
|
||||
o = self.cls()
|
||||
api = 'the api instance'
|
||||
o = self.cls(api)
|
||||
e = raises(NotImplementedError, o.get_dn, 'primary key')
|
||||
assert str(e) == 'Object.get_dn()'
|
||||
class user(self.cls):
|
||||
pass
|
||||
o = user()
|
||||
o = user(api)
|
||||
e = raises(NotImplementedError, o.get_dn, 'primary key')
|
||||
assert str(e) == 'user.get_dn()'
|
||||
|
||||
@@ -1037,9 +1077,9 @@ class test_Object(ClassChecker):
|
||||
"""
|
||||
class example(self.cls):
|
||||
takes_params = ('one', 'two', 'three', 'four')
|
||||
o = example()
|
||||
(api, home) = create_test_api()
|
||||
o.set_api(api)
|
||||
api, _home = create_test_api()
|
||||
api.finalize()
|
||||
o = example(api)
|
||||
p = o.params
|
||||
assert tuple(o.params_minus()) == tuple(p())
|
||||
assert tuple(o.params_minus([])) == tuple(p())
|
||||
@@ -1070,28 +1110,22 @@ class test_Attribute(ClassChecker):
|
||||
"""
|
||||
Test the `ipalib.frontend.Attribute.__init__` method.
|
||||
"""
|
||||
class user_add(self.cls):
|
||||
pass
|
||||
o = user_add()
|
||||
assert read_only(o, 'obj') is None
|
||||
assert read_only(o, 'obj_name') == 'user'
|
||||
assert read_only(o, 'attr_name') == 'add'
|
||||
|
||||
def test_set_api(self):
|
||||
"""
|
||||
Test the `ipalib.frontend.Attribute.set_api` method.
|
||||
"""
|
||||
user_obj = 'The user frontend.Object instance'
|
||||
class api(object):
|
||||
Object = dict(user=user_obj)
|
||||
|
||||
class api:
|
||||
Object = {("user", "1"): user_obj}
|
||||
@staticmethod
|
||||
def is_production_mode():
|
||||
return False
|
||||
|
||||
class user_add(self.cls):
|
||||
pass
|
||||
o = user_add()
|
||||
assert read_only(o, 'api') is None
|
||||
assert read_only(o, 'obj') is None
|
||||
o.set_api(api)
|
||||
|
||||
o = user_add(api)
|
||||
assert read_only(o, 'api') is api
|
||||
assert read_only(o, 'obj') is user_obj
|
||||
assert read_only(o, 'obj_name') == 'user'
|
||||
assert read_only(o, 'attr_name') == 'add'
|
||||
|
||||
|
||||
class test_Method(ClassChecker):
|
||||
@@ -1104,7 +1138,7 @@ class test_Method(ClassChecker):
|
||||
"""
|
||||
Return a finalized `ipalib.plugable.API` instance.
|
||||
"""
|
||||
(api, home) = create_test_api()
|
||||
api, _home = create_test_api()
|
||||
class user(frontend.Object):
|
||||
takes_params = (
|
||||
'givenname',
|
||||
@@ -1115,8 +1149,8 @@ class test_Method(ClassChecker):
|
||||
class user_verb(self.cls):
|
||||
takes_args = args
|
||||
takes_options = options
|
||||
api.register(user)
|
||||
api.register(user_verb)
|
||||
api.add_plugin(user)
|
||||
api.add_plugin(user_verb)
|
||||
api.finalize()
|
||||
return api
|
||||
|
||||
@@ -1130,9 +1164,10 @@ class test_Method(ClassChecker):
|
||||
"""
|
||||
Test the `ipalib.frontend.Method.__init__` method.
|
||||
"""
|
||||
api = 'the api instance'
|
||||
class user_add(self.cls):
|
||||
pass
|
||||
o = user_add()
|
||||
o = user_add(api)
|
||||
assert o.name == 'user_add'
|
||||
assert o.obj_name == 'user'
|
||||
assert o.attr_name == 'add'
|
||||
|
||||
@@ -25,6 +25,9 @@ from ipalib import messages
|
||||
from ipalib.capabilities import capabilities
|
||||
from ipatests.test_ipalib import test_errors
|
||||
|
||||
import pytest
|
||||
|
||||
pytestmark = pytest.mark.tier0
|
||||
|
||||
class HelloMessage(messages.PublicMessage):
|
||||
type = 'info'
|
||||
@@ -41,7 +44,7 @@ class test_PublicMessage(test_errors.test_PublicError):
|
||||
|
||||
class test_PublicMessages(test_errors.BaseMessagesTest):
|
||||
message_list = messages.public_messages
|
||||
errno_range = xrange(10000, 19999)
|
||||
errno_range = list(range(10000, 19999))
|
||||
required_classes = (UserWarning, messages.PublicMessage)
|
||||
texts = messages._texts
|
||||
|
||||
@@ -52,10 +55,11 @@ class test_PublicMessages(test_errors.BaseMessagesTest):
|
||||
|
||||
def test_to_dict():
|
||||
expected = dict(
|
||||
name='HelloMessage',
|
||||
type='info',
|
||||
message='Hello, world!',
|
||||
name=u'HelloMessage',
|
||||
type=u'info',
|
||||
message=u'Hello, world!',
|
||||
code=1234,
|
||||
data={'greeting': 'Hello', 'object': 'world'},
|
||||
)
|
||||
|
||||
assert HelloMessage(greeting='Hello', object='world').to_dict() == expected
|
||||
@@ -75,15 +79,17 @@ def test_add_message():
|
||||
|
||||
assert result == {'messages': [
|
||||
dict(
|
||||
name='HelloMessage',
|
||||
type='info',
|
||||
message='Hello, world!',
|
||||
name=u'HelloMessage',
|
||||
type=u'info',
|
||||
message=u'Hello, world!',
|
||||
code=1234,
|
||||
data={'greeting': 'Hello', 'object': 'world'},
|
||||
),
|
||||
dict(
|
||||
name='HelloMessage',
|
||||
type='info',
|
||||
message='Hi, version!',
|
||||
name=u'HelloMessage',
|
||||
type=u'info',
|
||||
message=u'Hi, version!',
|
||||
code=1234,
|
||||
data={'greeting': 'Hi', 'object': 'version'},
|
||||
)
|
||||
]}
|
||||
|
||||
@@ -24,9 +24,12 @@ Test the `ipalib.output` module.
|
||||
from ipatests.util import raises, ClassChecker
|
||||
from ipalib import output
|
||||
from ipalib.frontend import Command
|
||||
from ipalib import _
|
||||
from ipapython.version import API_VERSION
|
||||
|
||||
import pytest
|
||||
|
||||
pytestmark = pytest.mark.tier0
|
||||
|
||||
class test_Output(ClassChecker):
|
||||
"""
|
||||
Test the `ipalib.output.Output` class.
|
||||
@@ -48,16 +51,20 @@ class test_Output(ClassChecker):
|
||||
Test the `ipalib.output.Output.__repr__` method.
|
||||
"""
|
||||
o = self.cls('aye')
|
||||
assert repr(o) == "Output('aye', None, None)"
|
||||
assert repr(o) == "Output('aye')"
|
||||
o = self.cls('aye', type=int, doc='An A, aye?')
|
||||
assert repr(o) == "Output('aye', %r, 'An A, aye?')" % int
|
||||
assert repr(o) == (
|
||||
"Output('aye', type=[<type 'int'>], doc='An A, aye?')"
|
||||
)
|
||||
|
||||
class Entry(self.cls):
|
||||
pass
|
||||
o = Entry('aye')
|
||||
assert repr(o) == "Entry('aye', None, None)"
|
||||
assert repr(o) == "Entry('aye')"
|
||||
o = Entry('aye', type=int, doc='An A, aye?')
|
||||
assert repr(o) == "Entry('aye', %r, 'An A, aye?')" % int
|
||||
assert repr(o) == (
|
||||
"Entry('aye', type=[<type 'int'>], doc='An A, aye?')"
|
||||
)
|
||||
|
||||
|
||||
class test_ListOfEntries(ClassChecker):
|
||||
@@ -71,9 +78,10 @@ class test_ListOfEntries(ClassChecker):
|
||||
"""
|
||||
Test the `ipalib.output.ListOfEntries.validate` method.
|
||||
"""
|
||||
api = 'the api instance'
|
||||
class example(Command):
|
||||
pass
|
||||
cmd = example()
|
||||
cmd = example(api)
|
||||
inst = self.cls('stuff')
|
||||
|
||||
okay = dict(foo='bar')
|
||||
|
||||
@@ -22,22 +22,39 @@
|
||||
Test the `ipalib.parameters` module.
|
||||
"""
|
||||
|
||||
# FIXME: Pylint errors
|
||||
# pylint: disable=no-member
|
||||
|
||||
import base64
|
||||
import datetime
|
||||
import re
|
||||
import sys
|
||||
from types import NoneType
|
||||
from decimal import Decimal
|
||||
from inspect import isclass
|
||||
from xmlrpc.client import MAXINT, MININT
|
||||
|
||||
import pytest
|
||||
|
||||
import six
|
||||
from cryptography import x509 as crypto_x509
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
|
||||
from ipatests.util import raises, ClassChecker, read_only
|
||||
from ipatests.util import dummy_ugettext, assert_equal
|
||||
from ipatests.data import binary_bytes, utf8_bytes, unicode_str
|
||||
from ipalib import parameters, text, errors, config
|
||||
from ipalib import parameters, text, errors, config, x509
|
||||
from ipalib.constants import TYPE_ERROR, CALLABLE_ERROR
|
||||
from ipalib.errors import ValidationError, ConversionError
|
||||
from ipalib import _
|
||||
from xmlrpclib import MAXINT, MININT
|
||||
|
||||
NULLS = (None, '', u'', tuple(), [])
|
||||
if six.PY3:
|
||||
unicode = str
|
||||
long = int
|
||||
|
||||
NULLS = (None, b'', u'', tuple(), [])
|
||||
|
||||
pytestmark = pytest.mark.tier0
|
||||
|
||||
|
||||
class test_DefaultFrom(ClassChecker):
|
||||
"""
|
||||
@@ -85,18 +102,18 @@ class test_DefaultFrom(ClassChecker):
|
||||
pass
|
||||
|
||||
o = self.cls(stuff)
|
||||
assert repr(o) == "DefaultFrom(stuff, 'one', 'two')"
|
||||
assert repr(o) == "DefaultFrom('one', 'two')"
|
||||
|
||||
o = self.cls(stuff, 'aye', 'bee', 'see')
|
||||
assert repr(o) == "DefaultFrom(stuff, 'aye', 'bee', 'see')"
|
||||
assert repr(o) == "DefaultFrom('aye', 'bee', 'see')"
|
||||
|
||||
cb = lambda first, last: first[0] + last
|
||||
|
||||
o = self.cls(cb)
|
||||
assert repr(o) == "DefaultFrom(<lambda>, 'first', 'last')"
|
||||
assert repr(o) == "DefaultFrom('first', 'last')"
|
||||
|
||||
o = self.cls(cb, 'aye', 'bee', 'see')
|
||||
assert repr(o) == "DefaultFrom(<lambda>, 'aye', 'bee', 'see')"
|
||||
assert repr(o) == "DefaultFrom('aye', 'bee', 'see')"
|
||||
|
||||
def test_call(self):
|
||||
"""
|
||||
@@ -147,11 +164,15 @@ def test_parse_param_spec():
|
||||
assert f('name^') == ('name^', dict(required=True, multivalue=False))
|
||||
|
||||
# Test that TypeError is raised if spec isn't an str:
|
||||
e = raises(TypeError, f, u'name?')
|
||||
assert str(e) == TYPE_ERROR % ('spec', str, u'name?', unicode)
|
||||
if six.PY2:
|
||||
bad_value = u'name?'
|
||||
else:
|
||||
bad_value = b'name?'
|
||||
e = raises(TypeError, f, bad_value)
|
||||
assert str(e) == TYPE_ERROR % ('spec', str, bad_value, type(bad_value))
|
||||
|
||||
|
||||
class DummyRule(object):
|
||||
class DummyRule:
|
||||
def __init__(self, error=None):
|
||||
assert error is None or type(error) is unicode
|
||||
self.error = error
|
||||
@@ -205,7 +226,6 @@ class test_Param(ClassChecker):
|
||||
assert o.exclude is None
|
||||
assert o.flags == frozenset()
|
||||
assert o.sortorder == 2
|
||||
assert o.csv is False
|
||||
|
||||
# Test that doc defaults from label:
|
||||
o = self.cls('my_param', doc=_('Hello world'))
|
||||
@@ -219,12 +239,12 @@ class test_Param(ClassChecker):
|
||||
|
||||
# Test that ValueError is raised when a kwarg from a subclass
|
||||
# conflicts with an attribute:
|
||||
class Subclass(self.cls):
|
||||
class Subclass1(self.cls):
|
||||
kwargs = self.cls.kwargs + (
|
||||
('convert', callable, None),
|
||||
)
|
||||
e = raises(ValueError, Subclass, name)
|
||||
assert str(e) == "kwarg 'convert' conflicts with attribute on Subclass"
|
||||
e = raises(ValueError, Subclass1, name)
|
||||
assert str(e) == "kwarg 'convert' conflicts with attribute on Subclass1"
|
||||
|
||||
# Test type validation of keyword arguments:
|
||||
class Subclass(self.cls):
|
||||
@@ -235,7 +255,7 @@ class test_Param(ClassChecker):
|
||||
('extra4', callable, lambda whatever: whatever + 7),
|
||||
)
|
||||
o = Subclass('my_param') # Test with no **kw:
|
||||
for (key, kind, default) in o.kwargs:
|
||||
for key, kind, _default in o.kwargs:
|
||||
# Test with a type invalid for all:
|
||||
value = object()
|
||||
kw = {key: value}
|
||||
@@ -271,10 +291,6 @@ class test_Param(ClassChecker):
|
||||
'exclude', frozenset(['client', 'bar']),
|
||||
)
|
||||
|
||||
# Test that ValueError is raised if csv is set and multivalue is not set:
|
||||
e = raises(ValueError, self.cls, 'my_param', csv=True)
|
||||
assert str(e) == '%s: cannot have csv without multivalue' % "Param('my_param')"
|
||||
|
||||
# Test that default_from gets set:
|
||||
call = lambda first, last: first[0] + last
|
||||
o = self.cls('my_param', default_from=call)
|
||||
@@ -289,9 +305,9 @@ class test_Param(ClassChecker):
|
||||
o = self.cls(name)
|
||||
assert repr(o) == 'Param(%r)' % name
|
||||
o = self.cls('name', required=False)
|
||||
assert repr(o) == "Param('name', required=False)"
|
||||
assert repr(o) == "Param('name?')"
|
||||
o = self.cls('name', multivalue=True)
|
||||
assert repr(o) == "Param('name', multivalue=True)"
|
||||
assert repr(o) == "Param('name+')"
|
||||
|
||||
def test_use_in_context(self):
|
||||
"""
|
||||
@@ -339,18 +355,18 @@ class test_Param(ClassChecker):
|
||||
assert clone is not orig
|
||||
assert type(clone) is self.cls
|
||||
assert clone.name is orig.name
|
||||
for (key, kind, default) in self.cls.kwargs:
|
||||
assert getattr(clone, key) is getattr(orig, key)
|
||||
for key, _kind, _default in self.cls.kwargs:
|
||||
assert getattr(clone, key) == getattr(orig, key)
|
||||
|
||||
# Test with a param spec:
|
||||
orig = self.cls('my_param*')
|
||||
assert orig.param_spec == 'my_param*'
|
||||
clone = orig.clone()
|
||||
assert clone.param_spec == 'my_param'
|
||||
assert clone.param_spec == 'my_param*'
|
||||
assert clone is not orig
|
||||
assert type(clone) is self.cls
|
||||
for (key, kind, default) in self.cls.kwargs:
|
||||
assert getattr(clone, key) is getattr(orig, key)
|
||||
for key, _kind, _default in self.cls.kwargs:
|
||||
assert getattr(clone, key) == getattr(orig, key)
|
||||
|
||||
# Test with overrides:
|
||||
orig = self.cls('my_param*')
|
||||
@@ -361,7 +377,7 @@ class test_Param(ClassChecker):
|
||||
assert type(clone) is self.cls
|
||||
assert clone.required is True
|
||||
assert clone.multivalue is True
|
||||
assert clone.param_spec == 'my_param'
|
||||
assert clone.param_spec == 'my_param+'
|
||||
assert clone.name == 'my_param'
|
||||
|
||||
def test_clone_rename(self):
|
||||
@@ -376,7 +392,9 @@ class test_Param(ClassChecker):
|
||||
assert clone is not orig
|
||||
assert type(clone) is self.cls
|
||||
assert clone.name == new_name
|
||||
for (key, kind, default) in self.cls.kwargs:
|
||||
for key, _kind, _default in self.cls.kwargs:
|
||||
if key in ('cli_name', 'label', 'doc', 'cli_metavar'):
|
||||
continue
|
||||
assert getattr(clone, key) is getattr(orig, key)
|
||||
|
||||
# Test with overrides:
|
||||
@@ -388,7 +406,7 @@ class test_Param(ClassChecker):
|
||||
assert type(clone) is self.cls
|
||||
assert clone.required is True
|
||||
assert clone.multivalue is True
|
||||
assert clone.param_spec == new_name
|
||||
assert clone.param_spec == "{0}+".format(new_name)
|
||||
assert clone.name == new_name
|
||||
|
||||
|
||||
@@ -433,7 +451,7 @@ class test_Param(ClassChecker):
|
||||
assert o._convert_scalar(None) is None
|
||||
assert dummy.called() is False
|
||||
# Test with incorrect type
|
||||
e = raises(errors.ConversionError, o._convert_scalar, 'hello', index=17)
|
||||
raises(errors.ConversionError, o._convert_scalar, 'hello')
|
||||
|
||||
def test_validate(self):
|
||||
"""
|
||||
@@ -442,39 +460,33 @@ class test_Param(ClassChecker):
|
||||
|
||||
# Test in default state (with no rules, no kwarg):
|
||||
o = self.cls('my_param')
|
||||
e = raises(errors.RequirementError, o.validate, None, 'cli')
|
||||
e = raises(errors.RequirementError, o.validate, None)
|
||||
assert e.name == 'my_param'
|
||||
|
||||
# Test in default state that cli_name gets returned in the exception
|
||||
# when context == 'cli'
|
||||
o = self.cls('my_param', cli_name='short')
|
||||
e = raises(errors.RequirementError, o.validate, None, 'cli')
|
||||
assert e.name == 'short'
|
||||
|
||||
# Test with required=False
|
||||
o = self.cls('my_param', required=False)
|
||||
assert o.required is False
|
||||
assert o.validate(None, 'cli') is None
|
||||
assert o.validate(None) is None
|
||||
|
||||
# Test with query=True:
|
||||
o = self.cls('my_param', query=True)
|
||||
assert o.query is True
|
||||
e = raises(errors.RequirementError, o.validate, None, 'cli')
|
||||
assert_equal(e.name, 'my_param')
|
||||
e = raises(errors.RequirementError, o.validate, None)
|
||||
assert_equal(e.name, u'my_param')
|
||||
|
||||
# Test with multivalue=True:
|
||||
o = self.cls('my_param', multivalue=True)
|
||||
e = raises(TypeError, o.validate, [], 'cli')
|
||||
e = raises(TypeError, o.validate, [])
|
||||
assert str(e) == TYPE_ERROR % ('value', tuple, [], list)
|
||||
e = raises(ValueError, o.validate, tuple(), 'cli')
|
||||
e = raises(ValueError, o.validate, tuple())
|
||||
assert str(e) == 'value: empty tuple must be converted to None'
|
||||
|
||||
# Test with wrong (scalar) type:
|
||||
e = raises(TypeError, o.validate, (None, None, 42, None), 'cli')
|
||||
assert str(e) == TYPE_ERROR % ('my_param', NoneType, 42, int)
|
||||
e = raises(TypeError, o.validate, (None, None, 42, None))
|
||||
assert str(e) == TYPE_ERROR % ('my_param', type(None), 42, int)
|
||||
o = self.cls('my_param')
|
||||
e = raises(TypeError, o.validate, 'Hello', 'cli')
|
||||
assert str(e) == TYPE_ERROR % ('my_param', NoneType, 'Hello', str)
|
||||
e = raises(TypeError, o.validate, 'Hello')
|
||||
assert str(e) == TYPE_ERROR % ('my_param', type(None), 'Hello', str)
|
||||
|
||||
class Example(self.cls):
|
||||
type = int
|
||||
@@ -485,16 +497,15 @@ class test_Param(ClassChecker):
|
||||
fail = DummyRule(u'no good')
|
||||
o = Example('example', pass1, pass2)
|
||||
assert o.multivalue is False
|
||||
assert o.validate(11, 'cli') is None
|
||||
assert o.validate(11) is None
|
||||
assert pass1.calls == [(text.ugettext, 11)]
|
||||
assert pass2.calls == [(text.ugettext, 11)]
|
||||
pass1.reset()
|
||||
pass2.reset()
|
||||
o = Example('example', pass1, pass2, fail)
|
||||
e = raises(errors.ValidationError, o.validate, 42, 'cli')
|
||||
e = raises(errors.ValidationError, o.validate, 42)
|
||||
assert e.name == 'example'
|
||||
assert e.error == u'no good'
|
||||
assert e.index is None
|
||||
assert pass1.calls == [(text.ugettext, 42)]
|
||||
assert pass2.calls == [(text.ugettext, 42)]
|
||||
assert fail.calls == [(text.ugettext, 42)]
|
||||
@@ -505,7 +516,7 @@ class test_Param(ClassChecker):
|
||||
fail = DummyRule(u'this one is not good')
|
||||
o = Example('example', pass1, pass2, multivalue=True)
|
||||
assert o.multivalue is True
|
||||
assert o.validate((3, 9), 'cli') is None
|
||||
assert o.validate((3, 9)) is None
|
||||
assert pass1.calls == [
|
||||
(text.ugettext, 3),
|
||||
(text.ugettext, 9),
|
||||
@@ -518,10 +529,9 @@ class test_Param(ClassChecker):
|
||||
pass2.reset()
|
||||
o = Example('multi_example', pass1, pass2, fail, multivalue=True)
|
||||
assert o.multivalue is True
|
||||
e = raises(errors.ValidationError, o.validate, (3, 9), 'cli')
|
||||
e = raises(errors.ValidationError, o.validate, (3, 9))
|
||||
assert e.name == 'multi_example'
|
||||
assert e.error == u'this one is not good'
|
||||
assert e.index == 0
|
||||
assert pass1.calls == [(text.ugettext, 3)]
|
||||
assert pass2.calls == [(text.ugettext, 3)]
|
||||
assert fail.calls == [(text.ugettext, 3)]
|
||||
@@ -538,14 +548,10 @@ class test_Param(ClassChecker):
|
||||
# Test that TypeError is appropriately raised:
|
||||
e = raises(TypeError, o._validate_scalar, 0)
|
||||
assert str(e) == TYPE_ERROR % ('my_param', bool, 0, int)
|
||||
e = raises(TypeError, o._validate_scalar, 'Hi', index=4)
|
||||
assert str(e) == TYPE_ERROR % ('my_param', bool, 'Hi', str)
|
||||
e = raises(TypeError, o._validate_scalar, True, index=3.0)
|
||||
assert str(e) == TYPE_ERROR % ('index', int, 3.0, float)
|
||||
|
||||
# Test with passing rule:
|
||||
assert o._validate_scalar(True, index=None) is None
|
||||
assert o._validate_scalar(False, index=None) is None
|
||||
assert o._validate_scalar(True) is None
|
||||
assert o._validate_scalar(False) is None
|
||||
assert okay.calls == [
|
||||
(text.ugettext, True),
|
||||
(text.ugettext, False),
|
||||
@@ -558,11 +564,9 @@ class test_Param(ClassChecker):
|
||||
e = raises(errors.ValidationError, o._validate_scalar, True)
|
||||
assert e.name == 'my_param'
|
||||
assert e.error == u'this describes the error'
|
||||
assert e.index is None
|
||||
e = raises(errors.ValidationError, o._validate_scalar, False, index=2)
|
||||
e = raises(errors.ValidationError, o._validate_scalar, False)
|
||||
assert e.name == 'my_param'
|
||||
assert e.error == u'this describes the error'
|
||||
assert e.index == 2
|
||||
assert okay.calls == [
|
||||
(text.ugettext, True),
|
||||
(text.ugettext, False),
|
||||
@@ -576,7 +580,7 @@ class test_Param(ClassChecker):
|
||||
"""
|
||||
Test the `ipalib.parameters.Param.get_default` method.
|
||||
"""
|
||||
class PassThrough(object):
|
||||
class PassThrough:
|
||||
value = None
|
||||
|
||||
def __call__(self, value):
|
||||
@@ -593,6 +597,8 @@ class test_Param(ClassChecker):
|
||||
type = unicode
|
||||
|
||||
def __init__(self, name, **kw):
|
||||
# (Pylint complains because the superclass is unknowm)
|
||||
# pylint: disable=bad-super-call, super-on-old-class
|
||||
self._convert_scalar = PassThrough()
|
||||
super(Str, self).__init__(name, **kw)
|
||||
|
||||
@@ -639,7 +645,7 @@ class test_Flag(ClassChecker):
|
||||
|
||||
# Test that TypeError is raise if default is not a bool:
|
||||
e = raises(TypeError, self.cls, 'my_flag', default=None)
|
||||
assert str(e) == TYPE_ERROR % ('default', bool, None, NoneType)
|
||||
assert str(e) == TYPE_ERROR % ('default', bool, None, type(None))
|
||||
|
||||
# Test with autofill=False, default=True
|
||||
o = self.cls('my_flag', autofill=False, default=True)
|
||||
@@ -674,7 +680,7 @@ class test_Data(ClassChecker):
|
||||
Test the `ipalib.parameters.Data.__init__` method.
|
||||
"""
|
||||
o = self.cls('my_data')
|
||||
assert o.type is NoneType
|
||||
assert o.type is type(None) # noqa
|
||||
assert o.password is False
|
||||
assert o.rules == tuple()
|
||||
assert o.class_rules == tuple()
|
||||
@@ -682,7 +688,6 @@ class test_Data(ClassChecker):
|
||||
assert o.minlength is None
|
||||
assert o.maxlength is None
|
||||
assert o.length is None
|
||||
assert o.pattern is None
|
||||
|
||||
# Test mixing length with minlength or maxlength:
|
||||
o = self.cls('my_data', length=5)
|
||||
@@ -694,7 +699,7 @@ class test_Data(ClassChecker):
|
||||
]
|
||||
for kw in permutations:
|
||||
o = self.cls('my_data', **kw)
|
||||
for (key, value) in kw.iteritems():
|
||||
for (key, value) in kw.items():
|
||||
assert getattr(o, key) == value
|
||||
e = raises(ValueError, self.cls, 'my_data', length=5, **kw)
|
||||
assert str(e) == \
|
||||
@@ -728,7 +733,7 @@ class test_Bytes(ClassChecker):
|
||||
Test the `ipalib.parameters.Bytes.__init__` method.
|
||||
"""
|
||||
o = self.cls('my_bytes')
|
||||
assert o.type is str
|
||||
assert o.type is bytes
|
||||
assert o.password is False
|
||||
assert o.rules == tuple()
|
||||
assert o.class_rules == tuple()
|
||||
@@ -755,7 +760,7 @@ class test_Bytes(ClassChecker):
|
||||
assert len(o.class_rules) == len(kw)
|
||||
assert len(o.rules) == 0
|
||||
assert len(o.all_rules) == len(kw)
|
||||
for (key, value) in kw.iteritems():
|
||||
for (key, value) in kw.items():
|
||||
assert getattr(o, key) == value
|
||||
e = raises(ValueError, self.cls, 'my_bytes', length=5, **kw)
|
||||
assert str(e) == \
|
||||
@@ -789,12 +794,12 @@ class test_Bytes(ClassChecker):
|
||||
assert dummy.translation is translation
|
||||
|
||||
# Test with passing values:
|
||||
for value in ('abc', 'four', '12345'):
|
||||
for value in (b'abc', b'four', b'12345'):
|
||||
assert rule(dummy, value) is None
|
||||
assert dummy.called() is False
|
||||
|
||||
# Test with failing values:
|
||||
for value in ('', 'a', '12'):
|
||||
for value in (b'', b'a', b'12'):
|
||||
assert_equal(
|
||||
rule(dummy, value),
|
||||
translation % dict(minlength=3)
|
||||
@@ -815,12 +820,12 @@ class test_Bytes(ClassChecker):
|
||||
assert dummy.translation is translation
|
||||
|
||||
# Test with passing values:
|
||||
for value in ('ab', '123', 'four'):
|
||||
for value in (b'ab', b'123', b'four'):
|
||||
assert rule(dummy, value) is None
|
||||
assert dummy.called() is False
|
||||
|
||||
# Test with failing values:
|
||||
for value in ('12345', 'sixsix'):
|
||||
for value in (b'12345', b'sixsix'):
|
||||
assert_equal(
|
||||
rule(dummy, value),
|
||||
translation % dict(maxlength=4)
|
||||
@@ -841,12 +846,12 @@ class test_Bytes(ClassChecker):
|
||||
assert dummy.translation is translation
|
||||
|
||||
# Test with passing values:
|
||||
for value in ('1234', 'four'):
|
||||
for value in (b'1234', b'four'):
|
||||
assert rule(dummy, value) is None
|
||||
assert dummy.called() is False
|
||||
|
||||
# Test with failing values:
|
||||
for value in ('ab', '123', '12345', 'sixsix'):
|
||||
for value in (b'ab', b'123', b'12345', b'sixsix'):
|
||||
assert_equal(
|
||||
rule(dummy, value),
|
||||
translation % dict(length=4),
|
||||
@@ -860,9 +865,9 @@ class test_Bytes(ClassChecker):
|
||||
Test the `ipalib.parameters.Bytes._rule_pattern` method.
|
||||
"""
|
||||
# Test our assumptions about Python re module and Unicode:
|
||||
pat = '\w+$'
|
||||
pat = br'\w+$'
|
||||
r = re.compile(pat)
|
||||
assert r.match('Hello_World') is not None
|
||||
assert r.match(b'Hello_World') is not None
|
||||
assert r.match(utf8_bytes) is None
|
||||
assert r.match(binary_bytes) is None
|
||||
|
||||
@@ -874,12 +879,12 @@ class test_Bytes(ClassChecker):
|
||||
dummy = dummy_ugettext(translation)
|
||||
|
||||
# Test with passing values:
|
||||
for value in ('HELLO', 'hello', 'Hello_World'):
|
||||
for value in (b'HELLO', b'hello', b'Hello_World'):
|
||||
assert rule(dummy, value) is None
|
||||
assert dummy.called() is False
|
||||
|
||||
# Test with failing values:
|
||||
for value in ('Hello!', 'Hello World', utf8_bytes, binary_bytes):
|
||||
for value in (b'Hello!', b'Hello World', utf8_bytes, binary_bytes):
|
||||
assert_equal(
|
||||
rule(dummy, value),
|
||||
translation % dict(pattern=pat),
|
||||
@@ -915,21 +920,15 @@ class test_Str(ClassChecker):
|
||||
mthd = o._convert_scalar
|
||||
for value in (u'Hello', 42, 1.2, unicode_str):
|
||||
assert mthd(value) == unicode(value)
|
||||
bad = [True, 'Hello', dict(one=1), utf8_bytes]
|
||||
bad = [True, b'Hello', dict(one=1), utf8_bytes]
|
||||
for value in bad:
|
||||
e = raises(errors.ConversionError, mthd, value)
|
||||
assert e.name == 'my_str'
|
||||
assert e.index is None
|
||||
assert_equal(unicode(e.error), u'must be Unicode text')
|
||||
e = raises(errors.ConversionError, mthd, value, index=18)
|
||||
assert e.name == 'my_str'
|
||||
assert e.index == 18
|
||||
assert_equal(unicode(e.error), u'must be Unicode text')
|
||||
bad = [(u'Hello',), [42.3]]
|
||||
for value in bad:
|
||||
e = raises(errors.ConversionError, mthd, value)
|
||||
assert e.name == 'my_str'
|
||||
assert e.index is None
|
||||
assert_equal(unicode(e.error), u'Only one value is allowed')
|
||||
assert o.convert(None) is None
|
||||
|
||||
@@ -1016,10 +1015,13 @@ class test_Str(ClassChecker):
|
||||
Test the `ipalib.parameters.Str._rule_pattern` method.
|
||||
"""
|
||||
# Test our assumptions about Python re module and Unicode:
|
||||
pat = '\w{5}$'
|
||||
pat = r'\w{5}$'
|
||||
r1 = re.compile(pat)
|
||||
r2 = re.compile(pat, re.UNICODE)
|
||||
assert r1.match(unicode_str) is None
|
||||
if six.PY2:
|
||||
assert r1.match(unicode_str) is None
|
||||
else:
|
||||
assert r1.match(unicode_str) is not None
|
||||
assert r2.match(unicode_str) is not None
|
||||
|
||||
# Create instance:
|
||||
@@ -1070,7 +1072,6 @@ class test_Password(ClassChecker):
|
||||
o = self.cls('my_password')
|
||||
e = raises(errors.PasswordMismatch, o._convert_scalar, [u'one', u'two'])
|
||||
assert e.name == 'my_password'
|
||||
assert e.index is None
|
||||
assert o._convert_scalar([u'one', u'one']) == u'one'
|
||||
assert o._convert_scalar(u'one') == u'one'
|
||||
|
||||
@@ -1154,10 +1155,10 @@ class test_StrEnum(EnumChecker):
|
||||
_cls = parameters.StrEnum
|
||||
_name = 'my_strenum'
|
||||
_datatype = unicode
|
||||
_test_values = u'Hello', u'naughty', u'nurse!'
|
||||
_bad_type_values = u'Hello', 'naughty', u'nurse!'
|
||||
_bad_type = str
|
||||
_translation = u"values='Hello', 'naughty', 'nurse!'"
|
||||
_test_values = u'Hello', u'tall', u'nurse!'
|
||||
_bad_type_values = u'Hello', 1, u'nurse!'
|
||||
_bad_type = int
|
||||
_translation = u"values='Hello', 'tall', 'nurse!'"
|
||||
_bad_values = u'Howdy', u'quiet', u'library!'
|
||||
_single_value_translation = u"value='Hello'"
|
||||
|
||||
@@ -1173,11 +1174,10 @@ def check_int_scalar_conversions(o):
|
||||
for bad in ['hello', u'hello', True, None, u'', u'.', 8j, ()]:
|
||||
e = raises(errors.ConversionError, o._convert_scalar, bad)
|
||||
assert e.name == 'my_number'
|
||||
assert e.index is None
|
||||
# Assure large magnitude values are handled correctly
|
||||
assert type(o._convert_scalar(sys.maxint * 2)) == long
|
||||
assert o._convert_scalar(sys.maxint * 2) == sys.maxint * 2
|
||||
assert o._convert_scalar(unicode(sys.maxint * 2)) == sys.maxint * 2
|
||||
assert type(o._convert_scalar(sys.maxsize * 2)) == long
|
||||
assert o._convert_scalar(sys.maxsize * 2) == sys.maxsize * 2
|
||||
assert o._convert_scalar(unicode(sys.maxsize * 2)) == sys.maxsize * 2
|
||||
assert o._convert_scalar(long(16)) == 16
|
||||
# Assure normal conversions produce expected result
|
||||
assert o._convert_scalar(u'16.99') == 16
|
||||
@@ -1185,6 +1185,7 @@ def check_int_scalar_conversions(o):
|
||||
assert o._convert_scalar(u'16') == 16
|
||||
assert o._convert_scalar(u'0x10') == 16
|
||||
assert o._convert_scalar(u'020') == 16
|
||||
assert o._convert_scalar(u'0o20') == 16
|
||||
|
||||
|
||||
class test_IntEnum(EnumChecker):
|
||||
@@ -1220,7 +1221,7 @@ class test_Number(ClassChecker):
|
||||
Test the `ipalib.parameters.Number.__init__` method.
|
||||
"""
|
||||
o = self.cls('my_number')
|
||||
assert o.type is NoneType
|
||||
assert o.type is type(None) # noqa
|
||||
assert o.password is False
|
||||
assert o.rules == tuple()
|
||||
assert o.class_rules == tuple()
|
||||
@@ -1241,7 +1242,7 @@ class test_Int(ClassChecker):
|
||||
# Test with no kwargs:
|
||||
o = self.cls('my_number')
|
||||
assert o.type == int
|
||||
assert o.allowed_types == (int, long)
|
||||
assert o.allowed_types == (int,)
|
||||
assert isinstance(o, parameters.Int)
|
||||
assert o.minvalue == int(MININT)
|
||||
assert o.maxvalue == int(MAXINT)
|
||||
@@ -1419,8 +1420,7 @@ class test_Decimal(ClassChecker):
|
||||
param = self.cls('my_number', precision=1)
|
||||
e = raises(ConversionError, param, '123456789012345678901234567890')
|
||||
|
||||
assert str(e) == \
|
||||
"invalid 'my_number': quantize result has too many digits for current context"
|
||||
assert str(e).startswith("invalid 'my_number': ")
|
||||
|
||||
def test_exponential(self):
|
||||
"""
|
||||
@@ -1513,7 +1513,7 @@ class test_AccessTime(ClassChecker):
|
||||
u'periodical yearly month 4 day 1-31 0800-1400',
|
||||
u'periodic weekly day 8 0800-1400',
|
||||
):
|
||||
e = raises(ValidationError, o._rule_required, None, value)
|
||||
raises(ValidationError, o._rule_required, None, value)
|
||||
|
||||
def test_create_param():
|
||||
"""
|
||||
@@ -1535,13 +1535,17 @@ def test_create_param():
|
||||
for spec in ('one?', 'two+', 'three*', 'four'):
|
||||
(name, kw) = parameters.parse_param_spec(spec)
|
||||
p = f(spec)
|
||||
assert p.param_spec is spec
|
||||
assert p.param_spec == spec
|
||||
assert p.name == name
|
||||
assert p.required is kw['required']
|
||||
assert p.multivalue is kw['multivalue']
|
||||
|
||||
# Test that TypeError is raised when spec is neither a Param nor a str:
|
||||
for spec in (u'one', 42, parameters.Param, parameters.Str):
|
||||
if six.PY2:
|
||||
bad_value = u'one'
|
||||
else:
|
||||
bad_value = b'one'
|
||||
for spec in (bad_value, 42, parameters.Param, parameters.Str):
|
||||
e = raises(TypeError, f, spec)
|
||||
assert str(e) == \
|
||||
TYPE_ERROR % ('spec', (str, parameters.Param), spec, type(spec))
|
||||
@@ -1579,8 +1583,10 @@ class test_IA5Str(ClassChecker):
|
||||
for value in bad:
|
||||
e = raises(errors.ConversionError, mthd, value)
|
||||
assert e.name == 'my_str'
|
||||
assert e.index is None
|
||||
assert_equal(e.error, "The character '\\xc3' is not allowed.")
|
||||
if six.PY2:
|
||||
assert_equal(e.error, u"The character '\\xc3' is not allowed.")
|
||||
else:
|
||||
assert_equal(e.error, u"The character 'á' is not allowed.")
|
||||
|
||||
|
||||
class test_DateTime(ClassChecker):
|
||||
@@ -1625,4 +1631,122 @@ class test_DateTime(ClassChecker):
|
||||
u'1991-31-12Z',
|
||||
u'1991-12-07T25:30:05Z',
|
||||
):
|
||||
raises(ConversionError, o.convert, value)
|
||||
raises(ConversionError, o.convert, value)
|
||||
|
||||
|
||||
class test_CertificateSigningRequest(ClassChecker):
|
||||
"""
|
||||
Test the `ipalib.parameters.CertificateSigningRequest` class
|
||||
"""
|
||||
_cls = parameters.CertificateSigningRequest
|
||||
|
||||
sample_csr = (
|
||||
b'-----BEGIN CERTIFICATE REQUEST-----\n'
|
||||
b'MIIBjjCB+AIBADBPMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEQ\n'
|
||||
b'MA4GA1UEChMHRXhhbXBsZTEZMBcGA1UEAxMQdGVzdC5leGFtcGxlLmNvbTCBnzAN\n'
|
||||
b'BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAyxsN5dmvyKiw+5nyrcO3a61sivZRg+ja\n'
|
||||
b'kyNIyUo+tIUiYwTdpPESAHTWRlk0XhydauAkWfOIN7pR3a5Z+kQw8W7F+DuZze2M\n'
|
||||
b'6wRNmN+NTrTlqnKOiMHBXhIM0Qxrx68GDctYqtnKTVT94FvvLl9XYVdUEi2ePTc2\n'
|
||||
b'Nyfr1z66+W0CAwEAAaAAMA0GCSqGSIb3DQEBBQUAA4GBAIf3r+Y6WHrFnttUqDow\n'
|
||||
b'9/UCHtCeQlQoJqjjxi5wcjbkGwTgHbx/BPOd/8OVaHElboMXLGaZx+L/eFO6E9Yg\n'
|
||||
b'mDOYv3OsibDFGaEhJrU8EnfuFZKnbrGeSC9Hkqrq+3OjqacaPla5N7MHKbfLY377\n'
|
||||
b'ddbOHKzR0sURZ+ro4z3fATW2\n'
|
||||
b'-----END CERTIFICATE REQUEST-----\n'
|
||||
)
|
||||
# certmonger <= 0.79.5 (most probably in higher versions, too) will be
|
||||
# sending us just base64-encoded DER certs without the information it's
|
||||
# base64-encoded bytes (__base64__: in the JSON request), we need to
|
||||
# support that too, unfortunately
|
||||
sample_base64 = (
|
||||
"MIICETCCAXoCAQAwTzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWEx"
|
||||
"EDAOBgNVBAoTB0V4YW1wbGUxGTAXBgNVBAMTEHRlc3QuZXhhbXBsZS5jb20wgZ8w"
|
||||
"DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOXfP8LeiU7g6wLCclgkT1lVskK+Lxm1"
|
||||
"6ijE4LmEQBk5nn2P46im+E/UOgTddbDo5cdJlkoCnqXkO4RkqJckXYDxfI34KL3C"
|
||||
"CRFPvOa5Sg02m1x5Rg3boZfS6NciP62lRp0SI+0TCt3F16wYZxMahVIOXjbJ6Lu5"
|
||||
"mGjNn7XaWJhFAgMBAAGggYEwfwYJKoZIhvcNAQkOMXIwcDAeBgNVHREEFzAVghN0"
|
||||
"ZXN0bG93LmV4YW1wbGUuY29tME4GA1UdHwRHMEUwQ6BBoD+GHGh0dHA6Ly9jYS5l"
|
||||
"eGFtcGxlLmNvbS9teS5jcmyGH2h0dHA6Ly9vdGhlci5leGFtcGxlLmNvbS9teS5j"
|
||||
"cmwwDQYJKoZIhvcNAQEFBQADgYEAkv8pppcgGhX7erJmvg9r2UHrRriuKaOYgKZQ"
|
||||
"lf/eBt2N0L2mV4QvCY82H7HWuE+7T3mra9ikfvz0nYkPJQe2gntjZzECE0Jt5LWR"
|
||||
"UZOFwX8N6wrX11U2xu0NlvsbjU6siWd6OZjZ1p5/V330lzut/q3CNzaAcW1Fx3wL"
|
||||
"sV5SXSw="
|
||||
)
|
||||
sample_der_csr = (
|
||||
b'0\x82\x02\x110\x82\x01z\x02\x01\x000O1\x0b0\t\x06\x03U\x04\x06\x13'
|
||||
b'\x02US1\x130\x11\x06\x03U\x04\x08\x13\nCalifornia1\x100\x0e\x06\x03U'
|
||||
b'\x04\n\x13\x07Example1\x190\x17\x06\x03U\x04\x03\x13\x10test.example'
|
||||
b'.com0\x81\x9f0\r\x06\t*\x86H\x86\xf7\r\x01\x01\x01\x05\x00\x03\x81'
|
||||
b'\x8d\x000\x81\x89\x02\x81\x81\x00\xe5\xdf?\xc2\xde\x89N\xe0\xeb\x02'
|
||||
b'\xc2rX$OYU\xb2B\xbe/\x19\xb5\xea(\xc4\xe0\xb9\x84@\x199\x9e}\x8f\xe3'
|
||||
b'\xa8\xa6\xf8O\xd4:\x04\xddu\xb0\xe8\xe5\xc7I\x96J\x02\x9e\xa5\xe4;'
|
||||
b'\x84d\xa8\x97$]\x80\xf1|\x8d\xf8(\xbd\xc2\t\x11O\xbc\xe6\xb9J\r6\x9b'
|
||||
b'\\yF\r\xdb\xa1\x97\xd2\xe8\xd7"?\xad\xa5F\x9d\x12#\xed\x13\n\xdd\xc5'
|
||||
b'\xd7\xac\x18g\x13\x1a\x85R\x0e^6\xc9\xe8\xbb\xb9\x98h\xcd\x9f\xb5'
|
||||
b'\xdaX\x98E\x02\x03\x01\x00\x01\xa0\x81\x810\x7f\x06\t*\x86H\x86\xf7'
|
||||
b'\r\x01\t\x0e1r0p0\x1e\x06\x03U\x1d\x11\x04\x170\x15\x82\x13'
|
||||
b'testlow.example.com0N\x06\x03U\x1d\x1f\x04G0E0C\xa0A\xa0?\x86'
|
||||
b'\x1chttp://ca.example.com/my.crl\x86\x1fhttp://other.example.com/'
|
||||
b'my.crl0\r\x06\t*\x86H\x86\xf7\r\x01\x01\x05\x05\x00\x03\x81\x81\x00'
|
||||
b'\x92\xff)\xa6\x97 \x1a\x15\xfbz\xb2f\xbe\x0fk\xd9A\xebF\xb8\xae)\xa3'
|
||||
b'\x98\x80\xa6P\x95\xff\xde\x06\xdd\x8d\xd0\xbd\xa6W\x84/\t\x8f6\x1f'
|
||||
b'\xb1\xd6\xb8O\xbbOy\xabk\xd8\xa4~\xfc\xf4\x9d\x89\x0f%\x07\xb6\x82'
|
||||
b'{cg1\x02\x13Bm\xe4\xb5\x91Q\x93\x85\xc1\x7f\r\xeb\n\xd7\xd7U6\xc6'
|
||||
b'\xed\r\x96\xfb\x1b\x8dN\xac\x89gz9\x98\xd9\xd6\x9e\x7fW}\xf4\x97;'
|
||||
b'\xad\xfe\xad\xc276\x80qmE\xc7|\x0b\xb1^R],'
|
||||
)
|
||||
malformed_csr = (
|
||||
b'-----BEGIN CERTIFICATE REQUEST-----\n'
|
||||
b'VGhpcyBpcyBhbiBpbnZhbGlkIENTUg==\n'
|
||||
b'-----END CERTIFICATE REQUEST-----\n'
|
||||
)
|
||||
|
||||
def test_init(self):
|
||||
# create the parameter
|
||||
o = self.cls('csr')
|
||||
assert o.type is crypto_x509.CertificateSigningRequest
|
||||
assert isinstance(o, parameters.CertificateSigningRequest)
|
||||
assert o.multivalue is False
|
||||
|
||||
def test_convert(self):
|
||||
o = self.cls('csr')
|
||||
|
||||
# test that we're able to handle PEM CSR input equally as bytes, string
|
||||
# and cryptography x509._CertificateSigningRequest object
|
||||
for prep_input in (
|
||||
lambda x: x,
|
||||
lambda x: x.decode('utf-8'),
|
||||
lambda x: crypto_x509.load_pem_x509_csr(x, default_backend())
|
||||
):
|
||||
# test that input is correctly converted to python-crytography
|
||||
# object representation
|
||||
csr_object = o.convert(prep_input(self.sample_csr))
|
||||
assert isinstance(csr_object,
|
||||
crypto_x509.CertificateSigningRequest)
|
||||
assert (csr_object.public_bytes(x509.Encoding.PEM) ==
|
||||
self.sample_csr)
|
||||
|
||||
# test that we fail the same with malformed CSR as bytes or str
|
||||
for prep_input in (
|
||||
lambda x: x,
|
||||
lambda x: x.decode('utf-8'),
|
||||
):
|
||||
# test that malformed CSRs won't be accepted
|
||||
raises(errors.CertificateOperationError,
|
||||
o.convert,
|
||||
prep_input(self.malformed_csr))
|
||||
|
||||
# test DER as an input to the convert method
|
||||
csr_object = o.convert(self.sample_der_csr)
|
||||
assert isinstance(csr_object, crypto_x509.CertificateSigningRequest)
|
||||
assert (csr_object.public_bytes(x509.Encoding.DER) ==
|
||||
self.sample_der_csr)
|
||||
|
||||
# test base64-encoded DER as an input to the convert method
|
||||
csr_object = o.convert(self.sample_base64)
|
||||
assert isinstance(csr_object, crypto_x509.CertificateSigningRequest)
|
||||
assert (csr_object.public_bytes(x509.Encoding.DER) ==
|
||||
base64.b64decode(self.sample_base64))
|
||||
|
||||
# test that wrong type will not be accepted
|
||||
bad_value = datetime.date.today()
|
||||
raises(ConversionError, o.convert, bad_value)
|
||||
|
||||
@@ -21,182 +21,20 @@
|
||||
Test the `ipalib.plugable` module.
|
||||
"""
|
||||
|
||||
import inspect
|
||||
from ipatests.util import raises, no_set, no_del, read_only
|
||||
from ipatests.util import getitem, setitem, delitem
|
||||
from ipatests.util import ClassChecker, create_test_api
|
||||
from ipalib import plugable, errors, text
|
||||
from ipaplatform.paths import paths
|
||||
# FIXME: Pylint errors
|
||||
# pylint: disable=no-member
|
||||
|
||||
import os
|
||||
import sys
|
||||
import textwrap
|
||||
|
||||
class test_SetProxy(ClassChecker):
|
||||
"""
|
||||
Test the `ipalib.plugable.SetProxy` class.
|
||||
"""
|
||||
_cls = plugable.SetProxy
|
||||
from ipalib import plugable, errors, create_api
|
||||
from ipatests.util import raises, read_only
|
||||
from ipatests.util import ClassChecker, create_test_api, TempHome
|
||||
|
||||
def test_class(self):
|
||||
"""
|
||||
Test the `ipalib.plugable.SetProxy` class.
|
||||
"""
|
||||
assert self.cls.__bases__ == (plugable.ReadOnly,)
|
||||
import pytest
|
||||
|
||||
def test_init(self):
|
||||
"""
|
||||
Test the `ipalib.plugable.SetProxy.__init__` method.
|
||||
"""
|
||||
okay = (set, frozenset, dict)
|
||||
fail = (list, tuple)
|
||||
for t in okay:
|
||||
self.cls(t())
|
||||
raises(TypeError, self.cls, t)
|
||||
for t in fail:
|
||||
raises(TypeError, self.cls, t())
|
||||
raises(TypeError, self.cls, t)
|
||||
|
||||
def test_SetProxy(self):
|
||||
"""
|
||||
Test container emulation of `ipalib.plugable.SetProxy` class.
|
||||
"""
|
||||
def get_key(i):
|
||||
return 'key_%d' % i
|
||||
|
||||
cnt = 10
|
||||
target = set()
|
||||
proxy = self.cls(target)
|
||||
for i in xrange(cnt):
|
||||
key = get_key(i)
|
||||
|
||||
# Check initial state
|
||||
assert len(proxy) == len(target)
|
||||
assert list(proxy) == sorted(target)
|
||||
assert key not in proxy
|
||||
assert key not in target
|
||||
|
||||
# Add and test again
|
||||
target.add(key)
|
||||
assert len(proxy) == len(target)
|
||||
assert list(proxy) == sorted(target)
|
||||
assert key in proxy
|
||||
assert key in target
|
||||
|
||||
|
||||
class test_DictProxy(ClassChecker):
|
||||
"""
|
||||
Test the `ipalib.plugable.DictProxy` class.
|
||||
"""
|
||||
_cls = plugable.DictProxy
|
||||
|
||||
def test_class(self):
|
||||
"""
|
||||
Test the `ipalib.plugable.DictProxy` class.
|
||||
"""
|
||||
assert self.cls.__bases__ == (plugable.SetProxy,)
|
||||
|
||||
def test_init(self):
|
||||
"""
|
||||
Test the `ipalib.plugable.DictProxy.__init__` method.
|
||||
"""
|
||||
self.cls(dict())
|
||||
raises(TypeError, self.cls, dict)
|
||||
fail = (set, frozenset, list, tuple)
|
||||
for t in fail:
|
||||
raises(TypeError, self.cls, t())
|
||||
raises(TypeError, self.cls, t)
|
||||
|
||||
def test_DictProxy(self):
|
||||
"""
|
||||
Test container emulation of `ipalib.plugable.DictProxy` class.
|
||||
"""
|
||||
def get_kv(i):
|
||||
return (
|
||||
'key_%d' % i,
|
||||
'val_%d' % i,
|
||||
)
|
||||
cnt = 10
|
||||
target = dict()
|
||||
proxy = self.cls(target)
|
||||
for i in xrange(cnt):
|
||||
(key, val) = get_kv(i)
|
||||
|
||||
# Check initial state
|
||||
assert len(proxy) == len(target)
|
||||
assert list(proxy) == sorted(target)
|
||||
assert list(proxy()) == [target[k] for k in sorted(target)]
|
||||
assert key not in proxy
|
||||
raises(KeyError, getitem, proxy, key)
|
||||
|
||||
# Add and test again
|
||||
target[key] = val
|
||||
assert len(proxy) == len(target)
|
||||
assert list(proxy) == sorted(target)
|
||||
assert list(proxy()) == [target[k] for k in sorted(target)]
|
||||
|
||||
# Verify TypeError is raised trying to set/del via proxy
|
||||
raises(TypeError, setitem, proxy, key, val)
|
||||
raises(TypeError, delitem, proxy, key)
|
||||
|
||||
|
||||
class test_MagicDict(ClassChecker):
|
||||
"""
|
||||
Test the `ipalib.plugable.MagicDict` class.
|
||||
"""
|
||||
_cls = plugable.MagicDict
|
||||
|
||||
def test_class(self):
|
||||
"""
|
||||
Test the `ipalib.plugable.MagicDict` class.
|
||||
"""
|
||||
assert self.cls.__bases__ == (plugable.DictProxy,)
|
||||
for non_dict in ('hello', 69, object):
|
||||
raises(TypeError, self.cls, non_dict)
|
||||
|
||||
def test_MagicDict(self):
|
||||
"""
|
||||
Test container emulation of `ipalib.plugable.MagicDict` class.
|
||||
"""
|
||||
cnt = 10
|
||||
keys = []
|
||||
d = dict()
|
||||
dictproxy = self.cls(d)
|
||||
for i in xrange(cnt):
|
||||
key = 'key_%d' % i
|
||||
val = 'val_%d' % i
|
||||
keys.append(key)
|
||||
|
||||
# Test thet key does not yet exist
|
||||
assert len(dictproxy) == i
|
||||
assert key not in dictproxy
|
||||
assert not hasattr(dictproxy, key)
|
||||
raises(KeyError, getitem, dictproxy, key)
|
||||
raises(AttributeError, getattr, dictproxy, key)
|
||||
|
||||
# Test that items/attributes cannot be set on dictproxy:
|
||||
raises(TypeError, setitem, dictproxy, key, val)
|
||||
raises(AttributeError, setattr, dictproxy, key, val)
|
||||
|
||||
# Test that additions in d are reflected in dictproxy:
|
||||
d[key] = val
|
||||
assert len(dictproxy) == i + 1
|
||||
assert key in dictproxy
|
||||
assert hasattr(dictproxy, key)
|
||||
assert dictproxy[key] is val
|
||||
assert read_only(dictproxy, key) is val
|
||||
|
||||
# Test __iter__
|
||||
assert list(dictproxy) == keys
|
||||
|
||||
for key in keys:
|
||||
# Test that items cannot be deleted through dictproxy:
|
||||
raises(TypeError, delitem, dictproxy, key)
|
||||
raises(AttributeError, delattr, dictproxy, key)
|
||||
|
||||
# Test that deletions in d are reflected in dictproxy
|
||||
del d[key]
|
||||
assert len(dictproxy) == len(d)
|
||||
assert key not in dictproxy
|
||||
raises(KeyError, getitem, dictproxy, key)
|
||||
raises(AttributeError, getattr, dictproxy, key)
|
||||
pytestmark = pytest.mark.tier0
|
||||
|
||||
|
||||
class test_Plugin(ClassChecker):
|
||||
@@ -216,11 +54,10 @@ class test_Plugin(ClassChecker):
|
||||
"""
|
||||
Test the `ipalib.plugable.Plugin.__init__` method.
|
||||
"""
|
||||
o = self.cls()
|
||||
api = 'the api instance'
|
||||
o = self.cls(api)
|
||||
assert o.name == 'Plugin'
|
||||
assert o.module == 'ipalib.plugable'
|
||||
assert o.fullname == 'ipalib.plugable.Plugin'
|
||||
assert isinstance(o.doc, text.Gettext)
|
||||
assert isinstance(o.doc, str)
|
||||
class some_subclass(self.cls):
|
||||
"""
|
||||
Do sub-classy things.
|
||||
@@ -231,172 +68,89 @@ class test_Plugin(ClassChecker):
|
||||
|
||||
One more paragraph.
|
||||
"""
|
||||
o = some_subclass()
|
||||
o = some_subclass(api)
|
||||
assert o.name == 'some_subclass'
|
||||
assert o.module == __name__
|
||||
assert o.fullname == '%s.some_subclass' % __name__
|
||||
assert o.summary == 'Do sub-classy things.'
|
||||
assert isinstance(o.doc, text.Gettext)
|
||||
assert isinstance(o.doc, str)
|
||||
class another_subclass(self.cls):
|
||||
pass
|
||||
o = another_subclass()
|
||||
assert o.summary == '<%s>' % o.fullname
|
||||
|
||||
# Test that Plugin makes sure the subclass hasn't defined attributes
|
||||
# whose names conflict with the logger methods set in Plugin.__init__():
|
||||
class check(self.cls):
|
||||
info = 'whatever'
|
||||
e = raises(StandardError, check)
|
||||
assert str(e) == \
|
||||
"info is already bound to ipatests.test_ipalib.test_plugable.check()"
|
||||
|
||||
def test_set_api(self):
|
||||
"""
|
||||
Test the `ipalib.plugable.Plugin.set_api` method.
|
||||
"""
|
||||
api = 'the api instance'
|
||||
o = self.cls()
|
||||
assert o.api is None
|
||||
e = raises(AssertionError, o.set_api, None)
|
||||
assert str(e) == 'set_api() argument cannot be None'
|
||||
o.set_api(api)
|
||||
assert o.api is api
|
||||
e = raises(AssertionError, o.set_api, api)
|
||||
assert str(e) == 'set_api() can only be called once'
|
||||
o = another_subclass(api)
|
||||
assert o.summary == u'<%s.%s>' % (another_subclass.__module__,
|
||||
another_subclass.__name__)
|
||||
|
||||
def test_finalize(self):
|
||||
"""
|
||||
Test the `ipalib.plugable.Plugin.finalize` method.
|
||||
"""
|
||||
o = self.cls()
|
||||
class api:
|
||||
@staticmethod
|
||||
def is_production_mode():
|
||||
return False
|
||||
o = self.cls(api)
|
||||
assert not o.__islocked__()
|
||||
o.finalize()
|
||||
assert o.__islocked__()
|
||||
|
||||
def test_call(self):
|
||||
"""
|
||||
Test the `ipalib.plugable.Plugin.call` method.
|
||||
"""
|
||||
o = self.cls()
|
||||
o.call(paths.BIN_TRUE) is None
|
||||
e = raises(errors.SubprocessError, o.call, paths.BIN_FALSE)
|
||||
assert e.returncode == 1
|
||||
assert e.argv == (paths.BIN_FALSE,)
|
||||
|
||||
def test_Registry():
|
||||
"""
|
||||
Test the `ipalib.plugable.Registry` class
|
||||
"""
|
||||
class Base1:
|
||||
pass
|
||||
|
||||
def test_Registrar():
|
||||
"""
|
||||
Test the `ipalib.plugable.Registrar` class
|
||||
"""
|
||||
class Base1(object):
|
||||
pass
|
||||
class Base2(object):
|
||||
pass
|
||||
class Base3(object):
|
||||
class Base2:
|
||||
pass
|
||||
|
||||
class plugin1(Base1):
|
||||
pass
|
||||
|
||||
class plugin2(Base2):
|
||||
pass
|
||||
class plugin3(Base3):
|
||||
pass
|
||||
|
||||
# Test creation of Registrar:
|
||||
r = plugable.Registrar(Base1, Base2)
|
||||
|
||||
# Test __iter__:
|
||||
assert list(r) == ['Base1', 'Base2']
|
||||
|
||||
# Test __hasitem__, __getitem__:
|
||||
for base in [Base1, Base2]:
|
||||
name = base.__name__
|
||||
assert name in r
|
||||
assert r[name] is base
|
||||
magic = getattr(r, name)
|
||||
assert type(magic) is plugable.MagicDict
|
||||
assert len(magic) == 0
|
||||
# Test creation of Registry:
|
||||
r = plugable.Registry()
|
||||
|
||||
# Check that TypeError is raised trying to register something that isn't
|
||||
# a class:
|
||||
p = plugin1()
|
||||
e = raises(TypeError, r, p)
|
||||
assert str(e) == 'plugin must be a class; got %r' % p
|
||||
|
||||
# Check that SubclassError is raised trying to register a class that is
|
||||
# not a subclass of an allowed base:
|
||||
e = raises(errors.PluginSubclassError, r, plugin3)
|
||||
assert e.plugin is plugin3
|
||||
e = raises(TypeError, r(), p)
|
||||
assert str(e) == 'plugin must be callable; got %r' % p
|
||||
|
||||
# Check that registration works
|
||||
r(plugin1)
|
||||
assert len(r.Base1) == 1
|
||||
assert r.Base1['plugin1'] is plugin1
|
||||
assert r.Base1.plugin1 is plugin1
|
||||
r()(plugin1)
|
||||
|
||||
# Check that DuplicateError is raised trying to register exact class
|
||||
# again:
|
||||
e = raises(errors.PluginDuplicateError, r, plugin1)
|
||||
assert e.plugin is plugin1
|
||||
|
||||
# Check that OverrideError is raised trying to register class with same
|
||||
# name and same base:
|
||||
orig1 = plugin1
|
||||
class base1_extended(Base1):
|
||||
pass
|
||||
class plugin1(base1_extended):
|
||||
pass
|
||||
e = raises(errors.PluginOverrideError, r, plugin1)
|
||||
assert e.base == 'Base1'
|
||||
assert e.name == 'plugin1'
|
||||
e = raises(errors.PluginDuplicateError, r(), plugin1)
|
||||
assert e.plugin is plugin1
|
||||
|
||||
# Check that overriding works
|
||||
r(plugin1, override=True)
|
||||
assert len(r.Base1) == 1
|
||||
assert r.Base1.plugin1 is plugin1
|
||||
assert r.Base1.plugin1 is not orig1
|
||||
|
||||
# Check that MissingOverrideError is raised trying to override a name
|
||||
# not yet registerd:
|
||||
e = raises(errors.PluginMissingOverrideError, r, plugin2, override=True)
|
||||
assert e.base == 'Base2'
|
||||
assert e.name == 'plugin2'
|
||||
assert e.plugin is plugin2
|
||||
class base1_extended(Base1):
|
||||
pass
|
||||
class plugin1(base1_extended): # pylint: disable=function-redefined
|
||||
pass
|
||||
r(override=True)(plugin1)
|
||||
|
||||
# Test that another plugin can be registered:
|
||||
assert len(r.Base2) == 0
|
||||
r(plugin2)
|
||||
assert len(r.Base2) == 1
|
||||
assert r.Base2.plugin2 is plugin2
|
||||
r()(plugin2)
|
||||
|
||||
# Setup to test more registration:
|
||||
class plugin1a(Base1):
|
||||
pass
|
||||
r(plugin1a)
|
||||
r()(plugin1a)
|
||||
|
||||
class plugin1b(Base1):
|
||||
pass
|
||||
r(plugin1b)
|
||||
r()(plugin1b)
|
||||
|
||||
class plugin2a(Base2):
|
||||
pass
|
||||
r(plugin2a)
|
||||
r()(plugin2a)
|
||||
|
||||
class plugin2b(Base2):
|
||||
pass
|
||||
r(plugin2b)
|
||||
|
||||
# Again test __hasitem__, __getitem__:
|
||||
for base in [Base1, Base2]:
|
||||
name = base.__name__
|
||||
assert name in r
|
||||
assert r[name] is base
|
||||
magic = getattr(r, name)
|
||||
assert len(magic) == 3
|
||||
for key in magic:
|
||||
klass = magic[key]
|
||||
assert getattr(magic, key) is klass
|
||||
assert issubclass(klass, base)
|
||||
r()(plugin2b)
|
||||
|
||||
|
||||
class test_API(ClassChecker):
|
||||
@@ -421,12 +175,14 @@ class test_API(ClassChecker):
|
||||
def method(self, n):
|
||||
return n + 1
|
||||
|
||||
api = plugable.API(base0, base1)
|
||||
class API(plugable.API):
|
||||
bases = (base0, base1)
|
||||
modules = ()
|
||||
|
||||
api = API()
|
||||
api.env.mode = 'unit_test'
|
||||
api.env.in_tree = True
|
||||
r = api.register
|
||||
assert isinstance(r, plugable.Registrar)
|
||||
assert read_only(api, 'register') is r
|
||||
r = api.add_plugin
|
||||
|
||||
class base0_plugin0(base0):
|
||||
pass
|
||||
@@ -466,32 +222,31 @@ class test_API(ClassChecker):
|
||||
def get_plugin_name(b, p):
|
||||
return 'base%d_plugin%d' % (b, p)
|
||||
|
||||
for b in xrange(2):
|
||||
for b in range(2):
|
||||
base_name = get_base_name(b)
|
||||
base = locals()[base_name]
|
||||
ns = getattr(api, base_name)
|
||||
assert isinstance(ns, plugable.NameSpace)
|
||||
assert isinstance(ns, plugable.APINameSpace)
|
||||
assert read_only(api, base_name) is ns
|
||||
assert len(ns) == 3
|
||||
for p in xrange(3):
|
||||
for p in range(3):
|
||||
plugin_name = get_plugin_name(b, p)
|
||||
plugin = locals()[plugin_name]
|
||||
inst = ns[plugin_name]
|
||||
assert isinstance(inst, base)
|
||||
assert isinstance(inst, plugin)
|
||||
assert inst.name == plugin_name
|
||||
assert read_only(ns, plugin_name) is inst
|
||||
assert inst.method(7) == 7 + b
|
||||
|
||||
# Test that calling finilize again raises AssertionError:
|
||||
e = raises(StandardError, api.finalize)
|
||||
e = raises(Exception, api.finalize)
|
||||
assert str(e) == 'API.finalize() already called', str(e)
|
||||
|
||||
def test_bootstrap(self):
|
||||
"""
|
||||
Test the `ipalib.plugable.API.bootstrap` method.
|
||||
"""
|
||||
(o, home) = create_test_api()
|
||||
o, _home = create_test_api()
|
||||
assert o.env._isdone('_bootstrap') is False
|
||||
assert o.env._isdone('_finalize_core') is False
|
||||
assert o.isdone('bootstrap') is False
|
||||
@@ -500,18 +255,91 @@ class test_API(ClassChecker):
|
||||
assert o.env._isdone('_bootstrap') is True
|
||||
assert o.env._isdone('_finalize_core') is True
|
||||
assert o.env.my_test_override == 'Hello, world!'
|
||||
e = raises(StandardError, o.bootstrap)
|
||||
e = raises(Exception, o.bootstrap)
|
||||
assert str(e) == 'API.bootstrap() already called'
|
||||
|
||||
def test_load_plugins(self):
|
||||
"""
|
||||
Test the `ipalib.plugable.API.load_plugins` method.
|
||||
"""
|
||||
(o, home) = create_test_api()
|
||||
o, _home = create_test_api()
|
||||
assert o.isdone('bootstrap') is False
|
||||
assert o.isdone('load_plugins') is False
|
||||
o.load_plugins()
|
||||
assert o.isdone('bootstrap') is True
|
||||
assert o.isdone('load_plugins') is True
|
||||
e = raises(StandardError, o.load_plugins)
|
||||
e = raises(Exception, o.load_plugins)
|
||||
assert str(e) == 'API.load_plugins() already called'
|
||||
|
||||
def test_ipaconf_env(self):
|
||||
ipa_confdir = os.environ.get('IPA_CONFDIR', None)
|
||||
try:
|
||||
with TempHome() as home:
|
||||
defaultconf = home.join('default.conf')
|
||||
with open(defaultconf, 'w') as f:
|
||||
f.write(textwrap.dedent("""
|
||||
[global]
|
||||
basedn = dc=ipa,dc=test
|
||||
realm = IPA.TEST
|
||||
domain = ipa.test
|
||||
""")
|
||||
)
|
||||
os.environ['IPA_CONFDIR'] = home.path
|
||||
api = create_api(mode='unit_test')
|
||||
api.bootstrap()
|
||||
api.finalize()
|
||||
assert api.env.confdir == home.path
|
||||
assert api.env.conf_default == defaultconf
|
||||
assert api.env.realm == 'IPA.TEST'
|
||||
assert api.env.domain == 'ipa.test'
|
||||
|
||||
os.environ['IPA_CONFDIR'] = home.join('invalid')
|
||||
api = create_api(mode='unit_test')
|
||||
with pytest.raises(errors.EnvironmentError):
|
||||
api.bootstrap()
|
||||
finally:
|
||||
if ipa_confdir:
|
||||
os.environ['IPA_CONFDIR'] = ipa_confdir
|
||||
else:
|
||||
os.environ.pop('IPA_CONFDIR')
|
||||
|
||||
|
||||
class test_cli(ClassChecker):
|
||||
"""
|
||||
Test the `ipalib.plugable` global bootstrap.
|
||||
"""
|
||||
def test_no_args(self):
|
||||
sys.argv = ['/usr/bin/ipa']
|
||||
api = create_api(mode='unit_test')
|
||||
(_options, argv) = api.bootstrap_with_global_options(
|
||||
context='unit_test')
|
||||
assert len(argv) == 0
|
||||
assert _options.env is None
|
||||
assert _options.conf is None
|
||||
assert _options.debug is None
|
||||
assert _options.delegate is None
|
||||
assert _options.verbose is None
|
||||
|
||||
def test_one_arg(self):
|
||||
sys.argv = ['/usr/bin/ipa', 'user-show']
|
||||
api = create_api(mode='unit_test')
|
||||
(_options, argv) = api.bootstrap_with_global_options(
|
||||
context='unit_test')
|
||||
assert argv == ['user-show']
|
||||
assert _options.verbose is None
|
||||
|
||||
def test_args_valid_option(self):
|
||||
sys.argv = ['/usr/bin/ipa', '-v', 'user-show']
|
||||
api = create_api(mode='unit_test')
|
||||
(_options, argv) = api.bootstrap_with_global_options(
|
||||
context='unit_test')
|
||||
assert argv == ['user-show']
|
||||
assert _options.verbose == 1
|
||||
|
||||
def test_args_invalid_option(self):
|
||||
sys.argv = ['/usr/bin/ipa', '-verbose', 'user-show']
|
||||
api = create_api(mode='unit_test')
|
||||
try:
|
||||
api.bootstrap_with_global_options(context='unit_test')
|
||||
except errors.OptionError as e:
|
||||
assert e.msg == 'Unable to parse option rbose'
|
||||
|
||||
@@ -20,23 +20,31 @@
|
||||
"""
|
||||
Test the `ipalib.rpc` module.
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
from xmlrpclib import Binary, Fault, dumps, loads
|
||||
from xmlrpc.client import Binary, Fault, dumps, loads
|
||||
import urllib
|
||||
|
||||
import pytest
|
||||
import six
|
||||
|
||||
import nose
|
||||
from ipatests.util import raises, assert_equal, PluginTester, DummyClass
|
||||
from ipatests.util import Fuzzy
|
||||
from ipatests.data import binary_bytes, utf8_bytes, unicode_str
|
||||
from ipalib.frontend import Command
|
||||
from ipalib.request import context, Connection
|
||||
from ipalib import rpc, errors, api, request
|
||||
from ipalib import rpc, errors, api, request as ipa_request
|
||||
from ipapython.version import API_VERSION
|
||||
|
||||
if six.PY3:
|
||||
unicode = str
|
||||
|
||||
|
||||
std_compound = (binary_bytes, utf8_bytes, unicode_str)
|
||||
|
||||
|
||||
def dump_n_load(value):
|
||||
(param, method) = loads(
|
||||
param, _method = loads(
|
||||
dumps((value,), allow_none=True)
|
||||
)
|
||||
return param[0]
|
||||
@@ -52,32 +60,38 @@ def test_round_trip():
|
||||
"""
|
||||
Test `ipalib.rpc.xml_wrap` and `ipalib.rpc.xml_unwrap`.
|
||||
|
||||
This tests the two functions together with ``xmlrpclib.dumps()`` and
|
||||
``xmlrpclib.loads()`` in a full wrap/dumps/loads/unwrap round trip.
|
||||
This tests the two functions together with ``xmlrpc.client.dumps()`` and
|
||||
``xmlrpc.client.loads()`` in a full wrap/dumps/loads/unwrap round trip.
|
||||
"""
|
||||
# We first test that our assumptions about xmlrpclib module in the Python
|
||||
# We first test that our assumptions about xmlrpc.client module in the Python
|
||||
# standard library are correct:
|
||||
assert_equal(dump_n_load(utf8_bytes), unicode_str)
|
||||
if six.PY2:
|
||||
output_binary_type = bytes
|
||||
else:
|
||||
output_binary_type = Binary
|
||||
|
||||
if six.PY2:
|
||||
assert_equal(dump_n_load(utf8_bytes), unicode_str)
|
||||
assert_equal(dump_n_load(unicode_str), unicode_str)
|
||||
assert_equal(dump_n_load(Binary(binary_bytes)).data, binary_bytes)
|
||||
assert isinstance(dump_n_load(Binary(binary_bytes)), Binary)
|
||||
assert type(dump_n_load('hello')) is str
|
||||
assert type(dump_n_load(b'hello')) is output_binary_type
|
||||
assert type(dump_n_load(u'hello')) is str
|
||||
assert_equal(dump_n_load(''), '')
|
||||
assert_equal(dump_n_load(u''), '')
|
||||
assert_equal(dump_n_load(b''), output_binary_type(b''))
|
||||
assert_equal(dump_n_load(u''), str())
|
||||
assert dump_n_load(None) is None
|
||||
|
||||
# Now we test our wrap and unwrap methods in combination with dumps, loads:
|
||||
# All str should come back str (because they get wrapped in
|
||||
# xmlrpclib.Binary(). All unicode should come back unicode because str
|
||||
# All bytes should come back bytes (because they get wrapped in
|
||||
# xmlrpc.client.Binary(). All unicode should come back unicode because str
|
||||
# explicity get decoded by rpc.xml_unwrap() if they weren't already
|
||||
# decoded by xmlrpclib.loads().
|
||||
# decoded by xmlrpc.client.loads().
|
||||
assert_equal(round_trip(utf8_bytes), utf8_bytes)
|
||||
assert_equal(round_trip(unicode_str), unicode_str)
|
||||
assert_equal(round_trip(binary_bytes), binary_bytes)
|
||||
assert type(round_trip('hello')) is str
|
||||
assert type(round_trip(b'hello')) is bytes
|
||||
assert type(round_trip(u'hello')) is unicode
|
||||
assert_equal(round_trip(''), '')
|
||||
assert_equal(round_trip(b''), b'')
|
||||
assert_equal(round_trip(u''), u'')
|
||||
assert round_trip(None) is None
|
||||
compound = [utf8_bytes, None, binary_bytes, (None, unicode_str),
|
||||
@@ -93,13 +107,13 @@ def test_xml_wrap():
|
||||
f = rpc.xml_wrap
|
||||
assert f([], API_VERSION) == tuple()
|
||||
assert f({}, API_VERSION) == dict()
|
||||
b = f('hello', API_VERSION)
|
||||
b = f(b'hello', API_VERSION)
|
||||
assert isinstance(b, Binary)
|
||||
assert b.data == 'hello'
|
||||
assert b.data == b'hello'
|
||||
u = f(u'hello', API_VERSION)
|
||||
assert type(u) is unicode
|
||||
assert u == u'hello'
|
||||
value = f([dict(one=False, two=u'hello'), None, 'hello'], API_VERSION)
|
||||
f([dict(one=False, two=u'hello'), None, b'hello'], API_VERSION)
|
||||
|
||||
|
||||
def test_xml_unwrap():
|
||||
@@ -110,13 +124,13 @@ def test_xml_unwrap():
|
||||
assert f([]) == tuple()
|
||||
assert f({}) == dict()
|
||||
value = f(Binary(utf8_bytes))
|
||||
assert type(value) is str
|
||||
assert type(value) is bytes
|
||||
assert value == utf8_bytes
|
||||
assert f(utf8_bytes) == unicode_str
|
||||
assert f(unicode_str) == unicode_str
|
||||
value = f([True, Binary('hello'), dict(one=1, two=utf8_bytes, three=None)])
|
||||
assert value == (True, 'hello', dict(one=1, two=unicode_str, three=None))
|
||||
assert type(value[1]) is str
|
||||
value = f([True, Binary(b'hello'), dict(one=1, two=utf8_bytes, three=None)])
|
||||
assert value == (True, b'hello', dict(one=1, two=unicode_str, three=None))
|
||||
assert type(value[1]) is bytes
|
||||
assert type(value[2]['two']) is unicode
|
||||
|
||||
|
||||
@@ -195,15 +209,7 @@ class test_xmlclient(PluginTester):
|
||||
class user_add(Command):
|
||||
pass
|
||||
|
||||
# Test that ValueError is raised when forwarding a command that is not
|
||||
# in api.Command:
|
||||
(o, api, home) = self.instance('Backend', in_server=False)
|
||||
e = raises(ValueError, o.forward, 'user_add')
|
||||
assert str(e) == '%s.forward(): %r not in api.Command' % (
|
||||
'xmlclient', 'user_add'
|
||||
)
|
||||
|
||||
(o, api, home) = self.instance('Backend', user_add, in_server=False)
|
||||
o, _api, _home = self.instance('Backend', user_add, in_server=False)
|
||||
args = (binary_bytes, utf8_bytes, unicode_str)
|
||||
kw = dict(one=binary_bytes, two=utf8_bytes, three=unicode_str)
|
||||
params = [args, kw]
|
||||
@@ -229,6 +235,9 @@ class test_xmlclient(PluginTester):
|
||||
),
|
||||
|
||||
)
|
||||
|
||||
# Create connection for the current thread
|
||||
setattr(context, o.id, Connection(conn, lambda: None))
|
||||
context.xmlclient = Connection(conn, lambda: None)
|
||||
|
||||
# Test with a successful return value:
|
||||
@@ -246,18 +255,20 @@ class test_xmlclient(PluginTester):
|
||||
assert context.xmlclient.conn._calledall() is True
|
||||
|
||||
|
||||
class test_xml_introspection(object):
|
||||
@classmethod
|
||||
def setUpClass(self):
|
||||
@pytest.mark.skip_ipaclient_unittest
|
||||
@pytest.mark.needs_ipaapi
|
||||
class test_xml_introspection:
|
||||
@pytest.fixture(autouse=True, scope="class")
|
||||
def xml_introsp_setup(self, request):
|
||||
try:
|
||||
api.Backend.xmlclient.connect(fallback=False)
|
||||
api.Backend.xmlclient.connect()
|
||||
except (errors.NetworkError, IOError):
|
||||
raise nose.SkipTest('%r: Server not available: %r' %
|
||||
(__name__, api.env.xmlrpc_uri))
|
||||
pytest.skip('%r: Server not available: %r' %
|
||||
(__name__, api.env.xmlrpc_uri))
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(self):
|
||||
request.destroy_context()
|
||||
def fin():
|
||||
ipa_request.destroy_context()
|
||||
request.addfinalizer(fin)
|
||||
|
||||
def test_list_methods(self):
|
||||
result = api.Backend.xmlclient.conn.system.listMethods()
|
||||
@@ -270,9 +281,9 @@ class test_xml_introspection(object):
|
||||
|
||||
def test_list_methods_many_params(self):
|
||||
try:
|
||||
result = api.Backend.xmlclient.conn.system.listMethods('foo')
|
||||
except Fault, f:
|
||||
print f
|
||||
api.Backend.xmlclient.conn.system.listMethods('foo')
|
||||
except Fault as f:
|
||||
print(f)
|
||||
assert f.faultCode == 3003
|
||||
assert f.faultString == (
|
||||
"command 'system.listMethods' takes no arguments")
|
||||
@@ -290,9 +301,9 @@ class test_xml_introspection(object):
|
||||
|
||||
def test_signature_no_params(self):
|
||||
try:
|
||||
result = api.Backend.xmlclient.conn.system.methodSignature()
|
||||
except Fault, f:
|
||||
print f
|
||||
api.Backend.xmlclient.conn.system.methodSignature()
|
||||
except Fault as f:
|
||||
print(f)
|
||||
assert f.faultCode == 3007
|
||||
assert f.faultString == "'method name' is required"
|
||||
else:
|
||||
@@ -300,9 +311,9 @@ class test_xml_introspection(object):
|
||||
|
||||
def test_signature_many_params(self):
|
||||
try:
|
||||
result = api.Backend.xmlclient.conn.system.methodSignature('a', 'b')
|
||||
except Fault, f:
|
||||
print f
|
||||
api.Backend.xmlclient.conn.system.methodSignature('a', 'b')
|
||||
except Fault as f:
|
||||
print(f)
|
||||
assert f.faultCode == 3004
|
||||
assert f.faultString == (
|
||||
"command 'system.methodSignature' takes at most 1 argument")
|
||||
@@ -311,9 +322,9 @@ class test_xml_introspection(object):
|
||||
|
||||
def test_help_no_params(self):
|
||||
try:
|
||||
result = api.Backend.xmlclient.conn.system.methodHelp()
|
||||
except Fault, f:
|
||||
print f
|
||||
api.Backend.xmlclient.conn.system.methodHelp()
|
||||
except Fault as f:
|
||||
print(f)
|
||||
assert f.faultCode == 3007
|
||||
assert f.faultString == "'method name' is required"
|
||||
else:
|
||||
@@ -321,11 +332,65 @@ class test_xml_introspection(object):
|
||||
|
||||
def test_help_many_params(self):
|
||||
try:
|
||||
result = api.Backend.xmlclient.conn.system.methodHelp('a', 'b')
|
||||
except Fault, f:
|
||||
print f
|
||||
api.Backend.xmlclient.conn.system.methodHelp('a', 'b')
|
||||
except Fault as f:
|
||||
print(f)
|
||||
assert f.faultCode == 3004
|
||||
assert f.faultString == (
|
||||
"command 'system.methodHelp' takes at most 1 argument")
|
||||
else:
|
||||
raise AssertionError('did not raise')
|
||||
|
||||
|
||||
@pytest.mark.skip_ipaclient_unittest
|
||||
@pytest.mark.needs_ipaapi
|
||||
class test_rpcclient_context(PluginTester):
|
||||
"""
|
||||
Test the context in `ipalib.rpc.rpcclient` plugin.
|
||||
"""
|
||||
@pytest.fixture(autouse=True)
|
||||
def rpcclient_context_fsetup(self, request):
|
||||
try:
|
||||
api.Backend.rpcclient.connect(ca_certfile='foo')
|
||||
except (errors.NetworkError, IOError):
|
||||
pytest.skip('%r: Server not available: %r' %
|
||||
(__name__, api.env.xmlrpc_uri))
|
||||
|
||||
def fin():
|
||||
if api.Backend.rpcclient.isconnected():
|
||||
api.Backend.rpcclient.disconnect()
|
||||
request.addfinalizer(fin)
|
||||
|
||||
def test_context_cafile(self):
|
||||
"""
|
||||
Test that ca_certfile is set in `ipalib.rpc.rpcclient.connect`
|
||||
"""
|
||||
ca_certfile = getattr(context, 'ca_certfile', None)
|
||||
assert_equal(ca_certfile, 'foo')
|
||||
|
||||
def test_context_principal(self):
|
||||
"""
|
||||
Test that principal is set in `ipalib.rpc.rpcclient.connect`
|
||||
"""
|
||||
principal = getattr(context, 'principal', None)
|
||||
assert_equal(principal, 'admin@%s' % api.env.realm)
|
||||
|
||||
def test_context_request_url(self):
|
||||
"""
|
||||
Test that request_url is set in `ipalib.rpc.rpcclient.connect`
|
||||
"""
|
||||
request_url = getattr(context, 'request_url', None)
|
||||
assert_equal(request_url, 'https://%s/ipa/session/json' % api.env.host)
|
||||
|
||||
def test_context_session_cookie(self):
|
||||
"""
|
||||
Test that session_cookie is set in `ipalib.rpc.rpcclient.connect`
|
||||
"""
|
||||
fuzzy_cookie = Fuzzy(
|
||||
r'^ipa_session=MagBearerToken=[A-Za-z0-9+\/]+=*;$')
|
||||
|
||||
session_cookie = getattr(context, 'session_cookie', None)
|
||||
# pylint-2 is incorrectly spewing Too many positional arguments
|
||||
# pylint: disable=E1121
|
||||
unquoted = urllib.parse.unquote(session_cookie)
|
||||
assert(unquoted == fuzzy_cookie)
|
||||
|
||||
@@ -20,19 +20,23 @@
|
||||
"""
|
||||
Test the `ipalib.text` module.
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import tempfile
|
||||
import re
|
||||
import nose
|
||||
import locale
|
||||
from ipatests.util import raises, assert_equal
|
||||
|
||||
import six
|
||||
import pytest
|
||||
|
||||
from ipatests.i18n import create_po, po_file_iterate
|
||||
from ipalib.request import context
|
||||
from ipalib import request
|
||||
from ipalib import text
|
||||
from ipapython.ipautil import file_exists
|
||||
|
||||
if six.PY3:
|
||||
unicode = str
|
||||
|
||||
pytestmark = pytest.mark.tier0
|
||||
|
||||
singular = '%(count)d goose makes a %(dish)s'
|
||||
plural = '%(count)d geese make a %(dish)s'
|
||||
@@ -45,22 +49,45 @@ def test_create_translation():
|
||||
assert context.__dict__[key] is t
|
||||
|
||||
|
||||
class test_TestLang(object):
|
||||
def setUp(self):
|
||||
self.tmp_dir = None
|
||||
self.saved_lang = None
|
||||
class test_TestLang:
|
||||
lang_env_vars = {'LC_ALL', 'LC_MESSAGES', 'LANGUAGE', 'LANG'}
|
||||
|
||||
def setup_lang(self):
|
||||
"""
|
||||
Set all env variables used by gettext to localize translation files
|
||||
to xh_ZA
|
||||
"""
|
||||
self.lang = 'xh_ZA'
|
||||
self.domain = 'ipa'
|
||||
self.saved_locale = {
|
||||
k: v for k, v in os.environ.items() if k in self.lang_env_vars}
|
||||
|
||||
self.ipa_i18n_dir = os.path.join(os.path.dirname(__file__), '../../install/po')
|
||||
os.environ.update(
|
||||
{env_var: self.lang for env_var in self.lang_env_vars}
|
||||
)
|
||||
|
||||
def teardown_lang(self):
|
||||
"""
|
||||
Revert the locale settings to original values. If the original env
|
||||
variable was not set before, it will be popped off os.environ
|
||||
"""
|
||||
for env_var in self.lang_env_vars:
|
||||
if env_var not in self.saved_locale:
|
||||
os.environ.pop(env_var, None)
|
||||
|
||||
os.environ.update(self.saved_locale)
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def testlang_setup(self, request):
|
||||
self.tmp_dir = None
|
||||
self.setup_lang()
|
||||
|
||||
self.domain = 'ipa'
|
||||
|
||||
self.pot_basename = '%s.pot' % self.domain
|
||||
self.po_basename = '%s.po' % self.lang
|
||||
self.mo_basename = '%s.mo' % self.domain
|
||||
|
||||
self.tmp_dir = tempfile.mkdtemp()
|
||||
self.saved_lang = os.environ['LANG']
|
||||
|
||||
self.locale_dir = os.path.join(self.tmp_dir, 'test_locale')
|
||||
self.msg_dir = os.path.join(self.locale_dir, self.lang, 'LC_MESSAGES')
|
||||
@@ -68,39 +95,43 @@ class test_TestLang(object):
|
||||
if not os.path.exists(self.msg_dir):
|
||||
os.makedirs(self.msg_dir)
|
||||
|
||||
self.pot_file = os.path.join(self.ipa_i18n_dir, self.pot_basename)
|
||||
self.pot_file = os.path.join(
|
||||
os.path.dirname(__file__), 'data', self.pot_basename)
|
||||
self.mo_file = os.path.join(self.msg_dir, self.mo_basename)
|
||||
self.po_file = os.path.join(self.tmp_dir, self.po_basename)
|
||||
|
||||
result = create_po(self.pot_file, self.po_file, self.mo_file)
|
||||
if result:
|
||||
raise nose.SkipTest('Unable to create po file "%s" & mo file "%s" from pot file "%s"' %
|
||||
(self.po_file, self.mo_file, self.pot_file))
|
||||
pytest.skip(
|
||||
'Unable to create po file "%s" & mo file "%s" from pot '
|
||||
'file "%s"' % (self.po_file, self.mo_file, self.pot_file)
|
||||
)
|
||||
|
||||
if not file_exists(self.po_file):
|
||||
raise nose.SkipTest('Test po file unavailable, run "make test" in install/po')
|
||||
if not os.path.isfile(self.po_file):
|
||||
pytest.skip(
|
||||
'Test po file unavailable: {}'.format(self.po_file))
|
||||
|
||||
if not file_exists(self.mo_file):
|
||||
raise nose.SkipTest('Test mo file unavailable, run "make test" in install/po')
|
||||
if not os.path.isfile(self.mo_file):
|
||||
pytest.skip(
|
||||
'Test mo file unavailable: {}'.format(self.mo_file))
|
||||
|
||||
self.po_file_iterate = po_file_iterate
|
||||
|
||||
def tearDown(self):
|
||||
if self.saved_lang is not None:
|
||||
os.environ['LANG'] = self.saved_lang
|
||||
def fin():
|
||||
self.teardown_lang()
|
||||
|
||||
if self.tmp_dir is not None:
|
||||
shutil.rmtree(self.tmp_dir)
|
||||
if self.tmp_dir is not None:
|
||||
shutil.rmtree(self.tmp_dir)
|
||||
request.addfinalizer(fin)
|
||||
|
||||
def test_test_lang(self):
|
||||
print "test_test_lang"
|
||||
print("test_test_lang")
|
||||
# The test installs the test message catalog under the xh_ZA
|
||||
# (e.g. Zambia Xhosa) language by default. It would be nice to
|
||||
# use a dummy language not associated with any real language,
|
||||
# but the setlocale function demands the locale be a valid
|
||||
# known locale, Zambia Xhosa is a reasonable choice :)
|
||||
|
||||
os.environ['LANG'] = self.lang
|
||||
|
||||
# Create a gettext translation object specifying our domain as
|
||||
# 'ipa' and the locale_dir as 'test_locale' (i.e. where to
|
||||
@@ -118,7 +149,8 @@ class test_TestLang(object):
|
||||
result = self.po_file_iterate(self.po_file, get_msgstr, get_msgstr_plural)
|
||||
assert result == 0
|
||||
|
||||
class test_LazyText(object):
|
||||
|
||||
class test_LazyText:
|
||||
|
||||
klass = text.LazyText
|
||||
|
||||
@@ -129,7 +161,7 @@ class test_LazyText(object):
|
||||
assert inst.key == ('foo', 'bar')
|
||||
|
||||
|
||||
class test_FixMe(object):
|
||||
class test_FixMe:
|
||||
klass = text.FixMe
|
||||
|
||||
def test_init(self):
|
||||
@@ -148,7 +180,7 @@ class test_FixMe(object):
|
||||
assert type(unicode(inst)) is unicode
|
||||
|
||||
|
||||
class test_Gettext(object):
|
||||
class test_Gettext:
|
||||
|
||||
klass = text.Gettext
|
||||
|
||||
@@ -156,7 +188,7 @@ class test_Gettext(object):
|
||||
inst = self.klass('what up?', 'foo', 'bar')
|
||||
assert inst.domain == 'foo'
|
||||
assert inst.localedir == 'bar'
|
||||
assert inst.msg is 'what up?'
|
||||
assert inst.msg == 'what up?'
|
||||
assert inst.args == ('what up?', 'foo', 'bar')
|
||||
|
||||
def test_repr(self):
|
||||
@@ -169,7 +201,13 @@ class test_Gettext(object):
|
||||
|
||||
def test_mod(self):
|
||||
inst = self.klass('hello %(adj)s nurse', 'foo', 'bar')
|
||||
assert inst % dict(adj='naughty', stuff='junk') == 'hello naughty nurse'
|
||||
assert inst % dict(adj='tall', stuff='junk') == 'hello tall nurse'
|
||||
|
||||
def test_format(self):
|
||||
inst = self.klass('{0} {adj} nurse', 'foo', 'bar')
|
||||
posargs = ('hello', 'bye')
|
||||
knownargs = {'adj': 'caring', 'stuff': 'junk'}
|
||||
assert inst.format(*posargs, **knownargs) == 'hello caring nurse'
|
||||
|
||||
def test_eq(self):
|
||||
inst1 = self.klass('what up?', 'foo', 'bar')
|
||||
@@ -177,6 +215,7 @@ class test_Gettext(object):
|
||||
inst3 = self.klass('Hello world', 'foo', 'bar')
|
||||
inst4 = self.klass('what up?', 'foo', 'baz')
|
||||
|
||||
# pylint: disable=comparison-with-itself
|
||||
assert (inst1 == inst1) is True
|
||||
assert (inst1 == inst2) is True
|
||||
assert (inst1 == inst3) is False
|
||||
@@ -204,7 +243,7 @@ class test_Gettext(object):
|
||||
assert (inst4 != inst1) is True
|
||||
|
||||
|
||||
class test_NGettext(object):
|
||||
class test_NGettext:
|
||||
|
||||
klass = text.NGettext
|
||||
|
||||
@@ -234,12 +273,28 @@ class test_NGettext(object):
|
||||
assert inst % dict(count=1, dish='stew') == '1 goose makes a stew'
|
||||
assert inst % dict(count=2, dish='pie') == '2 geese make a pie'
|
||||
|
||||
def test_format(self):
|
||||
singular = '{count} goose makes a {0} {dish}'
|
||||
plural = '{count} geese make a {0} {dish}'
|
||||
inst = self.klass(singular, plural, 'foo', 'bar')
|
||||
posargs = ('tasty', 'disgusting')
|
||||
knownargs0 = {'count': 0, 'dish': 'frown', 'stuff': 'junk'}
|
||||
knownargs1 = {'count': 1, 'dish': 'stew', 'stuff': 'junk'}
|
||||
knownargs2 = {'count': 2, 'dish': 'pie', 'stuff': 'junk'}
|
||||
expected_str0 = '0 geese make a tasty frown'
|
||||
expected_str1 = '1 goose makes a tasty stew'
|
||||
expected_str2 = '2 geese make a tasty pie'
|
||||
assert inst.format(*posargs, **knownargs0) == expected_str0
|
||||
assert inst.format(*posargs, **knownargs1) == expected_str1
|
||||
assert inst.format(*posargs, **knownargs2) == expected_str2
|
||||
|
||||
def test_eq(self):
|
||||
inst1 = self.klass(singular, plural, 'foo', 'bar')
|
||||
inst2 = self.klass(singular, plural, 'foo', 'bar')
|
||||
inst3 = self.klass(singular, '%(count)d thingies', 'foo', 'bar')
|
||||
inst4 = self.klass(singular, plural, 'foo', 'baz')
|
||||
|
||||
# pylint: disable=comparison-with-itself
|
||||
assert (inst1 == inst1) is True
|
||||
assert (inst1 == inst2) is True
|
||||
assert (inst1 == inst3) is False
|
||||
@@ -267,7 +322,7 @@ class test_NGettext(object):
|
||||
assert (inst4 != inst1) is True
|
||||
|
||||
|
||||
class test_GettextFactory(object):
|
||||
class test_GettextFactory:
|
||||
|
||||
klass = text.GettextFactory
|
||||
|
||||
@@ -295,12 +350,12 @@ class test_GettextFactory(object):
|
||||
inst = self.klass('foo', 'bar')
|
||||
g = inst('what up?')
|
||||
assert type(g) is text.Gettext
|
||||
assert g.msg is 'what up?'
|
||||
assert g.msg == 'what up?'
|
||||
assert g.domain == 'foo'
|
||||
assert g.localedir == 'bar'
|
||||
|
||||
|
||||
class test_NGettextFactory(object):
|
||||
class test_NGettextFactory:
|
||||
|
||||
klass = text.NGettextFactory
|
||||
|
||||
@@ -334,7 +389,7 @@ class test_NGettextFactory(object):
|
||||
assert ng.localedir == 'bar'
|
||||
|
||||
|
||||
class test_ConcatenatedText(object):
|
||||
class test_ConcatenatedText:
|
||||
|
||||
klass = text.ConcatenatedLazyText
|
||||
|
||||
@@ -357,6 +412,12 @@ class test_ConcatenatedText(object):
|
||||
inst = self.klass('[', text.Gettext('%(color)s', 'foo', 'bar'), ']')
|
||||
assert inst % dict(color='red', stuff='junk') == '[red]'
|
||||
|
||||
def test_format(self):
|
||||
inst = self.klass('{0}', text.Gettext('{color}', 'foo', 'bar'), ']')
|
||||
posargs = ('[', '(')
|
||||
knownargs = {'color': 'red', 'stuff': 'junk'}
|
||||
assert inst.format(*posargs, **knownargs) == '[red]'
|
||||
|
||||
def test_add(self):
|
||||
inst = (text.Gettext('pale ', 'foo', 'bar') +
|
||||
text.Gettext('blue', 'foo', 'bar'))
|
||||
|
||||
@@ -1,26 +1,77 @@
|
||||
# Authors:
|
||||
# Jason Gerard DeRose <jderose@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2008 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
# Copyright (C) 2018 FreeIPA Contributors see COPYING for license
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""
|
||||
Test the `ipalib.util` module.
|
||||
"""Tests for ipalib.util module
|
||||
"""
|
||||
|
||||
from ipalib import util
|
||||
import os
|
||||
import ssl
|
||||
from unittest import mock
|
||||
|
||||
import pytest
|
||||
|
||||
from ipalib.util import (
|
||||
get_pager, create_https_connection, get_proper_tls_version_span
|
||||
)
|
||||
from ipaplatform.constants import constants
|
||||
|
||||
|
||||
@pytest.mark.parametrize('pager,expected_result', [
|
||||
# Valid values
|
||||
('cat', '/bin/cat'),
|
||||
('/bin/cat', '/bin/cat'),
|
||||
# Invalid values (wrong command, package is not installed, etc)
|
||||
('cat_', None),
|
||||
('', None)
|
||||
])
|
||||
def test_get_pager(pager, expected_result):
|
||||
with mock.patch.dict(os.environ, {'PAGER': pager}):
|
||||
pager = get_pager()
|
||||
assert(pager == expected_result or pager.endswith(expected_result))
|
||||
|
||||
|
||||
BASE_CTX = ssl.SSLContext(ssl.PROTOCOL_TLS)
|
||||
if constants.TLS_HIGH_CIPHERS is not None:
|
||||
BASE_CTX.set_ciphers(constants.TLS_HIGH_CIPHERS)
|
||||
else:
|
||||
BASE_CTX.set_ciphers("PROFILE=SYSTEM")
|
||||
|
||||
# options: IPA still supports Python 3.6 without min/max version setters
|
||||
BASE_OPT = BASE_CTX.options
|
||||
BASE_OPT |= (
|
||||
ssl.OP_ALL | ssl.OP_NO_COMPRESSION | ssl.OP_SINGLE_DH_USE |
|
||||
ssl.OP_SINGLE_ECDH_USE
|
||||
)
|
||||
TLS_OPT = (
|
||||
ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3 | ssl.OP_NO_TLSv1 |
|
||||
ssl.OP_NO_TLSv1_1
|
||||
)
|
||||
OP_NO_TLSv1_3 = getattr(ssl, "OP_NO_TLSv1_3", 0) # make pylint happy
|
||||
|
||||
|
||||
@pytest.mark.skip_if_platform(
|
||||
"debian", reason="Crypto policy is not supported on Debian"
|
||||
)
|
||||
@pytest.mark.parametrize('minver,maxver,opt,expected', [
|
||||
(None, None, BASE_OPT, None),
|
||||
(None, "tls1.3", BASE_OPT | TLS_OPT, ["tls1.2", "tls1.3"]),
|
||||
("tls1.2", "tls1.3", BASE_OPT | TLS_OPT, ["tls1.2", "tls1.3"]),
|
||||
("tls1.2", None, BASE_OPT | TLS_OPT, ["tls1.2", "tls1.3"]),
|
||||
("tls1.2", "tls1.2", BASE_OPT | TLS_OPT | OP_NO_TLSv1_3, ["tls1.2"]),
|
||||
(None, "tls1.2", BASE_OPT | TLS_OPT | OP_NO_TLSv1_3, ["tls1.2"]),
|
||||
("tls1.3", "tls1.3", BASE_OPT | TLS_OPT | ssl.OP_NO_TLSv1_2, ["tls1.3"]),
|
||||
("tls1.3", None, BASE_OPT | TLS_OPT | ssl.OP_NO_TLSv1_2, ["tls1.3"]),
|
||||
])
|
||||
def test_tls_version_span(minver, maxver, opt, expected):
|
||||
assert get_proper_tls_version_span(minver, maxver) == expected
|
||||
# file must exist and contain certs
|
||||
cafile = ssl.get_default_verify_paths().cafile
|
||||
conn = create_https_connection(
|
||||
"invalid.test",
|
||||
cafile=cafile,
|
||||
tls_version_min=minver,
|
||||
tls_version_max=maxver
|
||||
)
|
||||
ctx = getattr(conn, "_context")
|
||||
assert ctx.options == BASE_OPT | opt
|
||||
assert ctx.get_ciphers() == BASE_CTX.get_ciphers()
|
||||
|
||||
@@ -21,28 +21,151 @@
|
||||
Test the `ipalib.x509` module.
|
||||
"""
|
||||
|
||||
import os
|
||||
from os import path
|
||||
import sys
|
||||
from ipatests.util import raises, setitem, delitem, ClassChecker
|
||||
from ipatests.util import getitem, setitem, delitem
|
||||
from ipatests.util import TempDir, TempHome
|
||||
from ipalib.constants import TYPE_ERROR, OVERRIDE_ERROR, SET_ERROR, DEL_ERROR
|
||||
from ipalib.constants import NAME_REGEX, NAME_ERROR
|
||||
import base64
|
||||
from binascii import hexlify
|
||||
from configparser import RawConfigParser
|
||||
import datetime
|
||||
from io import StringIO
|
||||
import pickle
|
||||
|
||||
import pytest
|
||||
|
||||
from cryptography import x509 as crypto_x509
|
||||
from cryptography.x509.general_name import DNSName
|
||||
from ipalib import x509
|
||||
from nss.error import NSPRError
|
||||
from ipapython.dn import DN
|
||||
|
||||
pytestmark = pytest.mark.tier0
|
||||
|
||||
# certutil -
|
||||
|
||||
# certificate for CN=ipa.example.com,O=IPA
|
||||
goodcert = 'MIICAjCCAWugAwIBAgICBEUwDQYJKoZIhvcNAQEFBQAwKTEnMCUGA1UEAxMeSVBBIFRlc3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTEwMDYyNTEzMDA0MloXDTE1MDYyNTEzMDA0MlowKDEMMAoGA1UEChMDSVBBMRgwFgYDVQQDEw9pcGEuZXhhbXBsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAJcZ+H6+cQaN/BlzR8OYkVeJgaU5tCaV9FF1m7Ws/ftPtTJUaSL1ncp6603rjA4tH1aa/B8i8xdC46+ZbY2au8b9ryGcOsx2uaRpNLEQ2Fy//q1kQC8oM+iD8Nd6osF0a2wnugsgnJHPuJzhViaWxYgzk5DRdP81debokF3f3FX/AgMBAAGjOjA4MBEGCWCGSAGG+EIBAQQEAwIGQDATBgNVHSUEDDAKBggrBgEFBQcDATAOBgNVHQ8BAf8EBAMCBPAwDQYJKoZIhvcNAQEFBQADgYEALD6X9V9w381AzzQPcHsjIjiX3B/AF9RCGocKZUDXkdDhsD9NZ3PLPEf1AMjkraKG963HPB8scyiBbbSuSh6m7TCp0eDgRpo77zNuvd3U4Qpm0Qk+KEjtHQDjNNG6N4ZnCQPmjFPScElvc/GgW7XMbywJy2euF+3/Uip8cnPgSH4='
|
||||
goodcert = (
|
||||
b'MIICAjCCAWugAwIBAgICBEUwDQYJKoZIhvcNAQEFBQAwKTEnMCUGA1UEAxMeSVBB'
|
||||
b'IFRlc3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTEwMDYyNTEzMDA0MloXDTE1'
|
||||
b'MDYyNTEzMDA0MlowKDEMMAoGA1UEChMDSVBBMRgwFgYDVQQDEw9pcGEuZXhhbXBs'
|
||||
b'ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAJcZ+H6+cQaN/BlzR8OY'
|
||||
b'kVeJgaU5tCaV9FF1m7Ws/ftPtTJUaSL1ncp6603rjA4tH1aa/B8i8xdC46+ZbY2a'
|
||||
b'u8b9ryGcOsx2uaRpNLEQ2Fy//q1kQC8oM+iD8Nd6osF0a2wnugsgnJHPuJzhViaW'
|
||||
b'xYgzk5DRdP81debokF3f3FX/AgMBAAGjOjA4MBEGCWCGSAGG+EIBAQQEAwIGQDAT'
|
||||
b'BgNVHSUEDDAKBggrBgEFBQcDATAOBgNVHQ8BAf8EBAMCBPAwDQYJKoZIhvcNAQEF'
|
||||
b'BQADgYEALD6X9V9w381AzzQPcHsjIjiX3B/AF9RCGocKZUDXkdDhsD9NZ3PLPEf1'
|
||||
b'AMjkraKG963HPB8scyiBbbSuSh6m7TCp0eDgRpo77zNuvd3U4Qpm0Qk+KEjtHQDj'
|
||||
b'NNG6N4ZnCQPmjFPScElvc/GgW7XMbywJy2euF+3/Uip8cnPgSH4='
|
||||
)
|
||||
|
||||
goodcert_headers = (
|
||||
b'-----BEGIN CERTIFICATE-----\n' +
|
||||
goodcert +
|
||||
b'\n-----END CERTIFICATE-----'
|
||||
)
|
||||
# The base64-encoded string 'bad cert'
|
||||
badcert = 'YmFkIGNlcnQ='
|
||||
badcert = (
|
||||
b'-----BEGIN CERTIFICATE-----\n'
|
||||
b'YmFkIGNlcnQ=\r\n'
|
||||
b'-----END CERTIFICATE-----'
|
||||
)
|
||||
|
||||
class test_x509(object):
|
||||
good_pkcs7 = (
|
||||
b'-----BEGIN PKCS7-----\n'
|
||||
b'MIIDvAYJKoZIhvcNAQcCoIIDrTCCA6kCAQExADALBgkqhkiG9w0BBwGgggOPMIID\n'
|
||||
b'izCCAnOgAwIBAgIBATANBgkqhkiG9w0BAQsFADA2MRQwEgYDVQQKDAtFWEFNUExF\n'
|
||||
b'LkNPTTEeMBwGA1UEAwwVQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTE3MDkyMDIw\n'
|
||||
b'NDI1N1oXDTM3MDkyMDIwNDI1N1owNjEUMBIGA1UECgwLRVhBTVBMRS5DT00xHjAc\n'
|
||||
b'BgNVBAMMFUNlcnRpZmljYXRlIEF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQAD\n'
|
||||
b'ggEPADCCAQoCggEBAMNojX57UCCPTtEn9tQJBS4By5NixwodKm1UqOGsiecDrB0i\n'
|
||||
b'Pw7D6uGP6g4b6srYtbh+YsRJnfekB2L08q1dX3LVEItq2TS0WKqgZuRZkw7DvnGl\n'
|
||||
b'eANMwjHmE8k6/E0yI3GGxJLAfDZYw6CDspLkyN9anjQwVCz5N5z5bpeqi5BeVwin\n'
|
||||
b'O8WVF6FNn3iyL66uwOsTGEzCo3Y5HiwqYgaND73TtdsBHcIqOdRql3CC3IdoXXcW\n'
|
||||
b'044w4Lm2E95MuY729pPBHREtyzVkYtyuoKJ8KApghIY5oCklBkRDjyFK4tE7iF/h\n'
|
||||
b's+valeT9vcz2bHMIpvbjqAu/kqE8MjcNEFPjLhcCAwEAAaOBozCBoDAfBgNVHSME\n'
|
||||
b'GDAWgBTUB04/d1eLhbMtBi4AB65tsAt+2TAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud\n'
|
||||
b'DwEB/wQEAwIBxjAdBgNVHQ4EFgQU1AdOP3dXi4WzLQYuAAeubbALftkwPQYIKwYB\n'
|
||||
b'BQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwOi8vaXBhLWNhLmdyZXlvYWsuY29t\n'
|
||||
b'L2NhL29jc3AwDQYJKoZIhvcNAQELBQADggEBADQFwX1uh8tqLq8SqWZWtH95j33o\n'
|
||||
b'5Ze2dW7sVppb/wVnNauG0wDQW7uIx+Ynr7GgufXLNBMn1aP/mA2CdHk7NZz2IB1s\n'
|
||||
b'ZvbIfE8dVxzkA+Hh9d6cdgk4eU5rGf6Fw8ScEJ/48Mmncea3uGkHcOmt+BGLA8a1\n'
|
||||
b'wtruy+iQylOkbv36CbxKV7IsZDP106Zc+cVeOUQZnCLKmvQkotn6UJd8N1X0R2J3\n'
|
||||
b'4/qv0rUtcCnyEBNSgpTGCRlYM4kd98Dqc5W7wUpMcsQMFxQMSYY7pFQkdLPfJEx2\n'
|
||||
b'Mg63SPawxfAgUeukrdsF3wTIKkIBu1TVse+kvRvgmRRrfF2a4ZOv5qORe2uhADEA\n'
|
||||
b'-----END PKCS7-----'
|
||||
)
|
||||
|
||||
long_oid_cert = b'''
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFiTCCBHGgAwIBAgITSAAAAAd1bEC5lsOdnQAAAAAABzANBgkqhkiG9w0BAQsF
|
||||
ADBLMRUwEwYKCZImiZPyLGQBGRYFbG9jYWwxEjAQBgoJkiaJk/IsZAEZFgJhZDEe
|
||||
MBwGA1UEAxMVYWQtV0lOLVBQSzAxNUY5TURRLUNBMB4XDTE3MDUyNTIzNDg0NVoX
|
||||
DTE5MDUyNTIzNTg0NVowNDESMBAGA1UEChMJSVBBLkxPQ0FMMR4wHAYDVQQDExVD
|
||||
ZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
|
||||
AoIBAQDyyuty6irlL89hdaSW0UyAGLsOOMgAuJwBAeuRUorR159rsSnUXLcTHIsm
|
||||
EszKhwxp3NkkawRWx/s0UN1m2+RUwMl6gvlw+G80Mz0S77C77M+2lO8HRmZGm+Wu
|
||||
zBNcc9SANHuDQ1NISfZgLiscMS0+l0T3g6/Iqtg1kPWrq/tMevfh6tJEIedSBGo4
|
||||
3xKEMSDkrvaeTuSVrgn/QT0m+WNccZa0c7X35L/hgR22/l5sr057Ef8F9vL8zUH5
|
||||
TttFBIuiWJo8A8XX9I1zYIFhWjW3OVDZPBUnhGHH6yNyXGxXMRfcrrc74eTw8ivC
|
||||
080AQuRtgwvDErB/JPDJ5w5t/ielAgMBAAGjggJ7MIICdzA9BgkrBgEEAYI3FQcE
|
||||
MDAuBiYrBgEEAYI3FQiEoqJGhYq1PoGllQqGi+F4nacAgRODs5gfgozzAAIBZAIB
|
||||
BTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUnSrC
|
||||
yW3CR0e3ilJdN6kL06P3KHMwHwYDVR0jBBgwFoAUj69xtyUNwp8on+NWO+HlxKyg
|
||||
X7AwgdgGA1UdHwSB0DCBzTCByqCBx6CBxIaBwWxkYXA6Ly8vQ049YWQtV0lOLVBQ
|
||||
SzAxNUY5TURRLUNBLENOPVdJTi1QUEswMTVGOU1EUSxDTj1DRFAsQ049UHVibGlj
|
||||
JTIwS2V5JTIwU2VydmljZXMsQ049U2VydmljZXMsQ049Q29uZmlndXJhdGlvbixE
|
||||
Qz1hZCxEQz1sb2NhbD9jZXJ0aWZpY2F0ZVJldm9jYXRpb25MaXN0P2Jhc2U/b2Jq
|
||||
ZWN0Q2xhc3M9Y1JMRGlzdHJpYnV0aW9uUG9pbnQwgcQGCCsGAQUFBwEBBIG3MIG0
|
||||
MIGxBggrBgEFBQcwAoaBpGxkYXA6Ly8vQ049YWQtV0lOLVBQSzAxNUY5TURRLUNB
|
||||
LENOPUFJQSxDTj1QdWJsaWMlMjBLZXklMjBTZXJ2aWNlcyxDTj1TZXJ2aWNlcyxD
|
||||
Tj1Db25maWd1cmF0aW9uLERDPWFkLERDPWxvY2FsP2NBQ2VydGlmaWNhdGU/YmFz
|
||||
ZT9vYmplY3RDbGFzcz1jZXJ0aWZpY2F0aW9uQXV0aG9yaXR5MDMGA1UdIAQsMCow
|
||||
KAYmKwYBBAGCNxUIhKKiRoWKtT6BpZUKhovheJ2nAIEThrXzUYabpA4wDQYJKoZI
|
||||
hvcNAQELBQADggEBAIsFS+Qc/ufTrkuHbMmzksOpxq+OIi9rot8zy9/1Vmj6d+iP
|
||||
kB+vQ1u4/IhdQArJFNhsBzWSY9Pi8ZclovpepFeEZfXPUenyeRCU43HdMXcHXnlP
|
||||
YZfyLQWOugdo1WxK6S9qQSOSlC7BSGZWvKkiAPAwr4zNbbS+ROA2w0xaYMv0rr5W
|
||||
A4UAyzZAdqaGRJBRvCZ/uFHM5wMw0LzNCL4CqKW9jfZX0Fc2tdGx8zbTYxIdgr2D
|
||||
PL25as32r3S/m4uWqoQaK0lxK5Y97eusK2rrmidy32Jctzwl29UWq8kpjRAuD8iR
|
||||
CSc7sKqOf+fn3+fKITR2/DcSVvb0SGCr5fVVnjQ=
|
||||
-----END CERTIFICATE-----
|
||||
'''
|
||||
|
||||
ipa_demo_crt = b'''\
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIGFTCCBP2gAwIBAgISA61CoqWtpZoTEyfLCXliPLYFMA0GCSqGSIb3DQEBCwUA
|
||||
MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD
|
||||
ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xODA3MjUwNTM2NTlaFw0x
|
||||
ODEwMjMwNTM2NTlaMCAxHjAcBgNVBAMTFWlwYS5kZW1vMS5mcmVlaXBhLm9yZzCC
|
||||
ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKisvYUdarWE0CS9i+RcNf9Q
|
||||
41Euw36R4Myf/PUCDVUvGsVXQWSCanbtyxa8Ows4cAHrfqhiKAnSg0IhLqCMJVQ8
|
||||
8F699FHrP9EfPmZkG3RMLYPxKNrSmOVyNpIEQY9qfkDXZPLung6dk/c225Znoltq
|
||||
bVWLObXA7eP9C/djupg3gUD7vOAMHFmfZ3OKnx1uktL5p707o2/qlkSiEO4Z5ebD
|
||||
M8X0dTkN8V3LCCOjzCp88itGUWJM8Tjb86WkmYkJxmeZx6REd37rDXjqgYhwgXOB
|
||||
bSqDkYKRaihwvd5Up/vE1wApBS1k7b1oEW80teDUbzbaaqp7oBWbZD2Ac1yJF7UC
|
||||
AwEAAaOCAx0wggMZMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcD
|
||||
AQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUUmTMI1CB6qFMXc0+
|
||||
AGmqpfBAwhIwHwYDVR0jBBgwFoAUqEpqYwR93brm0Tm3pkVl7/Oo7KEwbwYIKwYB
|
||||
BQUHAQEEYzBhMC4GCCsGAQUFBzABhiJodHRwOi8vb2NzcC5pbnQteDMubGV0c2Vu
|
||||
Y3J5cHQub3JnMC8GCCsGAQUFBzAChiNodHRwOi8vY2VydC5pbnQteDMubGV0c2Vu
|
||||
Y3J5cHQub3JnLzAgBgNVHREEGTAXghVpcGEuZGVtbzEuZnJlZWlwYS5vcmcwgf4G
|
||||
A1UdIASB9jCB8zAIBgZngQwBAgEwgeYGCysGAQQBgt8TAQEBMIHWMCYGCCsGAQUF
|
||||
BwIBFhpodHRwOi8vY3BzLmxldHNlbmNyeXB0Lm9yZzCBqwYIKwYBBQUHAgIwgZ4M
|
||||
gZtUaGlzIENlcnRpZmljYXRlIG1heSBvbmx5IGJlIHJlbGllZCB1cG9uIGJ5IFJl
|
||||
bHlpbmcgUGFydGllcyBhbmQgb25seSBpbiBhY2NvcmRhbmNlIHdpdGggdGhlIENl
|
||||
cnRpZmljYXRlIFBvbGljeSBmb3VuZCBhdCBodHRwczovL2xldHNlbmNyeXB0Lm9y
|
||||
Zy9yZXBvc2l0b3J5LzCCAQQGCisGAQQB1nkCBAIEgfUEgfIA8AB2AMEWSuCnctLU
|
||||
OS3ICsEHcNTwxJvemRpIQMH6B1Fk9jNgAAABZNAnsSAAAAQDAEcwRQIgHkd/UkTZ
|
||||
w8iV1Ox8MPHLrpY33cX6i5FV6w9+7YH3H2kCIQCVcrhsr4fokDyE2ueUqSFxkBVH
|
||||
WND84/w5rFNAPjyO1QB2ACk8UZZUyDlluqpQ/FgH1Ldvv1h6KXLcpMMM9OVFR/R4
|
||||
AAABZNAnsyUAAAQDAEcwRQIhALDWY2k55abu7IPwnFvMr4Zqd1DYQXEKWZEQLXUP
|
||||
s4XGAiAabjpUwrLKVXpbp4WNLkTNlFjrSJafOzLG68H9AnoD4zANBgkqhkiG9w0B
|
||||
AQsFAAOCAQEAfBNuQn/A2olJHxoBGLfMcQCkkNOfvBpfQeKgni2VVM+r1ZY8YVXx
|
||||
OtVnV6XQ5M+l+6xlRpP1IwDdmJd/yaQgwbmYf4zl94W/s/qq4nlTd9G4ahmJOhlc
|
||||
mWeIQMoEtAmQlIOqWto+Knfakz6Xyo+HVCQEyeoBmYFGZcakeAm6tp/6qtpkej+4
|
||||
wBjShMPAdSYDPRaAqnZ3BAK2UmmlpAA5tkNvqOaHBCi760zYoxT6j1an7FotG0v9
|
||||
2+W0aL34eMWKz/g4qhwk+Jiz45LLQWhHGIgXIUoNSzHgLIVuVOQI8DPsguvT6GHW
|
||||
QUs1Hx1wL7mL4U8fKCFDKA+ds2B2xWgoZg==
|
||||
-----END CERTIFICATE-----
|
||||
'''
|
||||
|
||||
|
||||
class test_x509:
|
||||
"""
|
||||
Test `ipalib.x509`
|
||||
|
||||
@@ -58,24 +181,21 @@ class test_x509(object):
|
||||
"""
|
||||
|
||||
# Load a good cert
|
||||
cert = x509.load_certificate(goodcert)
|
||||
x509.load_pem_x509_certificate(goodcert_headers)
|
||||
|
||||
# Load a good cert with headers
|
||||
newcert = '-----BEGIN CERTIFICATE-----' + goodcert + '-----END CERTIFICATE-----'
|
||||
cert = x509.load_certificate(newcert)
|
||||
# Load a good cert with headers and leading text
|
||||
newcert = (
|
||||
b'leading text\n' + goodcert_headers)
|
||||
x509.load_pem_x509_certificate(newcert)
|
||||
|
||||
# Load a good cert with bad headers
|
||||
newcert = '-----BEGIN CERTIFICATE-----' + goodcert
|
||||
try:
|
||||
cert = x509.load_certificate(newcert)
|
||||
except TypeError:
|
||||
pass
|
||||
newcert = b'-----BEGIN CERTIFICATE-----' + goodcert_headers
|
||||
with pytest.raises((TypeError, ValueError)):
|
||||
x509.load_pem_x509_certificate(newcert)
|
||||
|
||||
# Load a bad cert
|
||||
try:
|
||||
cert = x509.load_certificate(badcert)
|
||||
except NSPRError:
|
||||
pass
|
||||
with pytest.raises(ValueError):
|
||||
x509.load_pem_x509_certificate(badcert)
|
||||
|
||||
def test_1_load_der_cert(self):
|
||||
"""
|
||||
@@ -85,55 +205,181 @@ class test_x509(object):
|
||||
der = base64.b64decode(goodcert)
|
||||
|
||||
# Load a good cert
|
||||
cert = x509.load_certificate(der, x509.DER)
|
||||
|
||||
def test_2_get_subject(self):
|
||||
"""
|
||||
Test retrieving the subject
|
||||
"""
|
||||
subject = x509.get_subject(goodcert)
|
||||
assert DN(str(subject)) == DN(('CN','ipa.example.com'),('O','IPA'))
|
||||
|
||||
der = base64.b64decode(goodcert)
|
||||
subject = x509.get_subject(der, x509.DER)
|
||||
assert DN(str(subject)) == DN(('CN','ipa.example.com'),('O','IPA'))
|
||||
|
||||
# We should be able to pass in a tuple/list of certs too
|
||||
subject = x509.get_subject((goodcert))
|
||||
assert DN(str(subject)) == DN(('CN','ipa.example.com'),('O','IPA'))
|
||||
|
||||
subject = x509.get_subject([goodcert])
|
||||
assert DN(str(subject)) == DN(('CN','ipa.example.com'),('O','IPA'))
|
||||
|
||||
def test_2_get_serial_number(self):
|
||||
"""
|
||||
Test retrieving the serial number
|
||||
"""
|
||||
serial = x509.get_serial_number(goodcert)
|
||||
assert serial == 1093
|
||||
|
||||
der = base64.b64decode(goodcert)
|
||||
serial = x509.get_serial_number(der, x509.DER)
|
||||
assert serial == 1093
|
||||
|
||||
# We should be able to pass in a tuple/list of certs too
|
||||
serial = x509.get_serial_number((goodcert))
|
||||
assert serial == 1093
|
||||
|
||||
serial = x509.get_serial_number([goodcert])
|
||||
assert serial == 1093
|
||||
x509.load_der_x509_certificate(der)
|
||||
|
||||
def test_3_cert_contents(self):
|
||||
"""
|
||||
Test the contents of a certificate
|
||||
"""
|
||||
# Verify certificate contents. This exercises python-nss more than
|
||||
# anything but confirms our usage of it.
|
||||
# Verify certificate contents. This exercises python-cryptography
|
||||
# more than anything but confirms our usage of it.
|
||||
|
||||
cert = x509.load_certificate(goodcert)
|
||||
not_before = datetime.datetime(2010, 6, 25, 13, 0, 42)
|
||||
not_after = datetime.datetime(2015, 6, 25, 13, 0, 42)
|
||||
cert = x509.load_pem_x509_certificate(goodcert_headers)
|
||||
|
||||
assert DN(str(cert.subject)) == DN(('CN','ipa.example.com'),('O','IPA'))
|
||||
assert DN(str(cert.issuer)) == DN(('CN','IPA Test Certificate Authority'))
|
||||
assert DN(cert.subject) == DN(('CN', 'ipa.example.com'), ('O', 'IPA'))
|
||||
assert DN(cert.issuer) == DN(('CN', 'IPA Test Certificate Authority'))
|
||||
assert cert.serial_number == 1093
|
||||
assert cert.valid_not_before_str == 'Fri Jun 25 13:00:42 2010 UTC'
|
||||
assert cert.valid_not_after_str == 'Thu Jun 25 13:00:42 2015 UTC'
|
||||
assert cert.not_valid_before == not_before
|
||||
assert cert.not_valid_after == not_after
|
||||
assert cert.san_general_names == []
|
||||
assert cert.san_a_label_dns_names == []
|
||||
assert cert.extended_key_usage == {'1.3.6.1.5.5.7.3.1'}
|
||||
assert cert.extended_key_usage_bytes == (
|
||||
b'0\x16\x06\x03U\x1d%\x01\x01\xff\x04\x0c0\n\x06\x08'
|
||||
b'+\x06\x01\x05\x05\x07\x03\x01'
|
||||
)
|
||||
|
||||
def test_load_pkcs7_pem(self):
|
||||
certlist = x509.pkcs7_to_certs(good_pkcs7, datatype=x509.PEM)
|
||||
assert len(certlist) == 1
|
||||
cert = certlist[0]
|
||||
assert DN(cert.subject) == DN('CN=Certificate Authority,O=EXAMPLE.COM')
|
||||
assert cert.serial_number == 1
|
||||
|
||||
def test_long_oid(self):
|
||||
"""
|
||||
Test cerificate with very long OID. In this case we are using a
|
||||
certificate from an opened case where one of X509v3 Certificate`s
|
||||
Policies OID is longer then 80 chars.
|
||||
"""
|
||||
cert = x509.load_pem_x509_certificate(long_oid_cert)
|
||||
ext = cert.extensions.get_extension_for_class(crypto_x509.
|
||||
CertificatePolicies)
|
||||
|
||||
assert len(ext.value) == 1
|
||||
assert ext.value[0].policy_identifier.dotted_string == (
|
||||
u'1.3.6.1.4.1.311.21.8.8950086.10656446.2706058.12775672.480128.'
|
||||
'147.13466065.13029902')
|
||||
|
||||
def test_ipa_demo_letsencrypt(self):
|
||||
cert = x509.load_pem_x509_certificate(ipa_demo_crt)
|
||||
assert DN(cert.subject) == DN('CN=ipa.demo1.freeipa.org')
|
||||
assert DN(cert.issuer) == DN(
|
||||
"CN=Let's Encrypt Authority X3,O=Let's Encrypt,C=US")
|
||||
assert cert.serial_number == 0x03ad42a2a5ada59a131327cb0979623cb605
|
||||
not_before = datetime.datetime(2018, 7, 25, 5, 36, 59)
|
||||
not_after = datetime.datetime(2018, 10, 23, 5, 36, 59)
|
||||
assert cert.not_valid_before == not_before
|
||||
assert cert.not_valid_after == not_after
|
||||
assert cert.san_general_names == [DNSName('ipa.demo1.freeipa.org')]
|
||||
assert cert.san_a_label_dns_names == ['ipa.demo1.freeipa.org']
|
||||
assert cert.extended_key_usage == {
|
||||
'1.3.6.1.5.5.7.3.1', '1.3.6.1.5.5.7.3.2'
|
||||
}
|
||||
assert cert.extended_key_usage_bytes == (
|
||||
b'0 \x06\x03U\x1d%\x01\x01\xff\x04\x160\x14\x06\x08+\x06\x01'
|
||||
b'\x05\x05\x07\x03\x01\x06\x08+\x06\x01\x05\x05\x07\x03\x02'
|
||||
)
|
||||
|
||||
|
||||
class test_ExternalCAProfile:
|
||||
def test_MSCSTemplateV1_good(self):
|
||||
o = x509.MSCSTemplateV1("MySubCA")
|
||||
assert hexlify(o.get_ext_data()) == b'1e0e004d007900530075006200430041'
|
||||
|
||||
def test_MSCSTemplateV1_bad(self):
|
||||
with pytest.raises(ValueError):
|
||||
x509.MSCSTemplateV1("MySubCA:1")
|
||||
|
||||
def test_MSCSTemplateV1_pickle_roundtrip(self):
|
||||
o = x509.MSCSTemplateV1("MySubCA")
|
||||
s = pickle.dumps(o)
|
||||
assert o.get_ext_data() == pickle.loads(s).get_ext_data()
|
||||
|
||||
def test_MSCSTemplateV2_too_few_parts(self):
|
||||
with pytest.raises(ValueError):
|
||||
x509.MSCSTemplateV2("1.2.3.4")
|
||||
|
||||
def test_MSCSTemplateV2_too_many_parts(self):
|
||||
with pytest.raises(ValueError):
|
||||
x509.MSCSTemplateV2("1.2.3.4:100:200:300")
|
||||
|
||||
def test_MSCSTemplateV2_bad_oid(self):
|
||||
with pytest.raises(ValueError):
|
||||
x509.MSCSTemplateV2("not_an_oid:1")
|
||||
|
||||
def test_MSCSTemplateV2_non_numeric_major_version(self):
|
||||
with pytest.raises(ValueError):
|
||||
x509.MSCSTemplateV2("1.2.3.4:major:200")
|
||||
|
||||
def test_MSCSTemplateV2_non_numeric_minor_version(self):
|
||||
with pytest.raises(ValueError):
|
||||
x509.MSCSTemplateV2("1.2.3.4:100:minor")
|
||||
|
||||
def test_MSCSTemplateV2_major_version_lt_zero(self):
|
||||
with pytest.raises(ValueError):
|
||||
x509.MSCSTemplateV2("1.2.3.4:-1:200")
|
||||
|
||||
def test_MSCSTemplateV2_minor_version_lt_zero(self):
|
||||
with pytest.raises(ValueError):
|
||||
x509.MSCSTemplateV2("1.2.3.4:100:-1")
|
||||
|
||||
def test_MSCSTemplateV2_major_version_gt_max(self):
|
||||
with pytest.raises(ValueError):
|
||||
x509.MSCSTemplateV2("1.2.3.4:4294967296:200")
|
||||
|
||||
def test_MSCSTemplateV2_minor_version_gt_max(self):
|
||||
with pytest.raises(ValueError):
|
||||
x509.MSCSTemplateV2("1.2.3.4:100:4294967296")
|
||||
|
||||
def test_MSCSTemplateV2_good_major(self):
|
||||
o = x509.MSCSTemplateV2("1.2.3.4:4294967295")
|
||||
assert hexlify(o.get_ext_data()) == b'300c06032a0304020500ffffffff'
|
||||
|
||||
def test_MSCSTemplateV2_good_major_minor(self):
|
||||
o = x509.MSCSTemplateV2("1.2.3.4:4294967295:0")
|
||||
assert hexlify(o.get_ext_data()) \
|
||||
== b'300f06032a0304020500ffffffff020100'
|
||||
|
||||
def test_MSCSTemplateV2_pickle_roundtrip(self):
|
||||
o = x509.MSCSTemplateV2("1.2.3.4:4294967295:0")
|
||||
s = pickle.dumps(o)
|
||||
assert o.get_ext_data() == pickle.loads(s).get_ext_data()
|
||||
|
||||
def test_ExternalCAProfile_dispatch(self):
|
||||
"""
|
||||
Test that constructing ExternalCAProfile actually returns an
|
||||
instance of the appropriate subclass.
|
||||
"""
|
||||
assert isinstance(
|
||||
x509.ExternalCAProfile("MySubCA"),
|
||||
x509.MSCSTemplateV1)
|
||||
assert isinstance(
|
||||
x509.ExternalCAProfile("1.2.3.4:100"),
|
||||
x509.MSCSTemplateV2)
|
||||
|
||||
def test_write_pkispawn_config_file_MSCSTemplateV1(self):
|
||||
template = x509.MSCSTemplateV1(u"SubCA")
|
||||
expected = (
|
||||
'[CA]\n'
|
||||
'pki_req_ext_oid = 1.3.6.1.4.1.311.20.2\n'
|
||||
'pki_req_ext_data = 1e0a00530075006200430041\n\n'
|
||||
)
|
||||
self._test_write_pkispawn_config_file(template, expected)
|
||||
|
||||
def test_write_pkispawn_config_file_MSCSTemplateV2(self):
|
||||
template = x509.MSCSTemplateV2(u"1.2.3.4:4294967295")
|
||||
expected = (
|
||||
'[CA]\n'
|
||||
'pki_req_ext_oid = 1.3.6.1.4.1.311.21.7\n'
|
||||
'pki_req_ext_data = 300c06032a0304020500ffffffff\n\n'
|
||||
)
|
||||
self._test_write_pkispawn_config_file(template, expected)
|
||||
|
||||
def _test_write_pkispawn_config_file(self, template, expected):
|
||||
"""
|
||||
Test that the values we read from an ExternalCAProfile
|
||||
object can be used to produce a reasonable-looking pkispawn
|
||||
configuration.
|
||||
"""
|
||||
config = RawConfigParser()
|
||||
config.optionxform = str
|
||||
config.add_section("CA")
|
||||
config.set("CA", "pki_req_ext_oid", template.ext_oid)
|
||||
config.set("CA", "pki_req_ext_data",
|
||||
hexlify(template.get_ext_data()).decode('ascii'))
|
||||
out = StringIO()
|
||||
config.write(out)
|
||||
assert out.getvalue() == expected
|
||||
|
||||
Reference in New Issue
Block a user