Imported Upstream version 4.6.2
This commit is contained in:
22
ipatests/test_ipapython/__init__.py
Normal file
22
ipatests/test_ipapython/__init__.py
Normal file
@@ -0,0 +1,22 @@
|
||||
# Authors:
|
||||
# Jan Cholasta <jcholast@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2011 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# 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/>.
|
||||
|
||||
"""
|
||||
Sub-package containing unit tests for `ipapython` package.
|
||||
"""
|
||||
497
ipatests/test_ipapython/test_cookie.py
Normal file
497
ipatests/test_ipapython/test_cookie.py
Normal file
@@ -0,0 +1,497 @@
|
||||
# Authors:
|
||||
# John Dennis <jdennis@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2012 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# 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/>.
|
||||
|
||||
import unittest
|
||||
import datetime
|
||||
import email.utils
|
||||
import calendar
|
||||
from ipapython.cookie import Cookie
|
||||
|
||||
import pytest
|
||||
|
||||
pytestmark = pytest.mark.tier0
|
||||
|
||||
class TestParse(unittest.TestCase):
|
||||
|
||||
def test_parse(self):
|
||||
# Empty string
|
||||
s = ''
|
||||
cookies = Cookie.parse(s)
|
||||
self.assertEqual(len(cookies), 0)
|
||||
|
||||
# Invalid single token
|
||||
s = 'color'
|
||||
with self.assertRaises(ValueError):
|
||||
cookies = Cookie.parse(s)
|
||||
|
||||
# Invalid single token that's keyword
|
||||
s = 'HttpOnly'
|
||||
with self.assertRaises(ValueError):
|
||||
cookies = Cookie.parse(s)
|
||||
|
||||
# Invalid key/value pair whose key is a keyword
|
||||
s = 'domain=example.com'
|
||||
with self.assertRaises(ValueError):
|
||||
cookies = Cookie.parse(s)
|
||||
|
||||
# 1 cookie with empty value
|
||||
s = 'color='
|
||||
cookies = Cookie.parse(s)
|
||||
self.assertEqual(len(cookies), 1)
|
||||
cookie = cookies[0]
|
||||
self.assertEqual(cookie.key, 'color')
|
||||
self.assertEqual(cookie.value, '')
|
||||
self.assertEqual(cookie.domain, None)
|
||||
self.assertEqual(cookie.path, None)
|
||||
self.assertEqual(cookie.max_age, None)
|
||||
self.assertEqual(cookie.expires, None)
|
||||
self.assertEqual(cookie.secure, None)
|
||||
self.assertEqual(cookie.httponly, None)
|
||||
self.assertEqual(str(cookie), "color=")
|
||||
self.assertEqual(cookie.http_cookie(), "color=;")
|
||||
|
||||
# 1 cookie with name/value
|
||||
s = 'color=blue'
|
||||
cookies = Cookie.parse(s)
|
||||
self.assertEqual(len(cookies), 1)
|
||||
cookie = cookies[0]
|
||||
self.assertEqual(cookie.key, 'color')
|
||||
self.assertEqual(cookie.value, 'blue')
|
||||
self.assertEqual(cookie.domain, None)
|
||||
self.assertEqual(cookie.path, None)
|
||||
self.assertEqual(cookie.max_age, None)
|
||||
self.assertEqual(cookie.expires, None)
|
||||
self.assertEqual(cookie.secure, None)
|
||||
self.assertEqual(cookie.httponly, None)
|
||||
self.assertEqual(str(cookie), "color=blue")
|
||||
self.assertEqual(cookie.http_cookie(), "color=blue;")
|
||||
|
||||
# 1 cookie with whose value is quoted
|
||||
# Use "get by name" utility to extract specific cookie
|
||||
s = 'color="blue"'
|
||||
cookie = Cookie.get_named_cookie_from_string(s, 'color')
|
||||
self.assertIsNotNone(cookie)
|
||||
self.assertIsNotNone(cookie, Cookie)
|
||||
self.assertEqual(cookie.key, 'color')
|
||||
self.assertEqual(cookie.value, 'blue')
|
||||
self.assertEqual(cookie.domain, None)
|
||||
self.assertEqual(cookie.path, None)
|
||||
self.assertEqual(cookie.max_age, None)
|
||||
self.assertEqual(cookie.expires, None)
|
||||
self.assertEqual(cookie.secure, None)
|
||||
self.assertEqual(cookie.httponly, None)
|
||||
self.assertEqual(str(cookie), "color=blue")
|
||||
self.assertEqual(cookie.http_cookie(), "color=blue;")
|
||||
|
||||
# 1 cookie with name/value and domain, path attributes.
|
||||
# Change up the whitespace a bit.
|
||||
s = 'color =blue; domain= example.com ; path = /toplevel '
|
||||
cookies = Cookie.parse(s)
|
||||
self.assertEqual(len(cookies), 1)
|
||||
cookie = cookies[0]
|
||||
self.assertEqual(cookie.key, 'color')
|
||||
self.assertEqual(cookie.value, 'blue')
|
||||
self.assertEqual(cookie.domain, 'example.com')
|
||||
self.assertEqual(cookie.path, '/toplevel')
|
||||
self.assertEqual(cookie.max_age, None)
|
||||
self.assertEqual(cookie.expires, None)
|
||||
self.assertEqual(cookie.secure, None)
|
||||
self.assertEqual(cookie.httponly, None)
|
||||
self.assertEqual(str(cookie), "color=blue; Domain=example.com; Path=/toplevel")
|
||||
self.assertEqual(cookie.http_cookie(), "color=blue;")
|
||||
|
||||
# 2 cookies, various attributes
|
||||
s = 'color=blue; Max-Age=3600; temperature=hot; HttpOnly'
|
||||
cookies = Cookie.parse(s)
|
||||
self.assertEqual(len(cookies), 2)
|
||||
cookie = cookies[0]
|
||||
self.assertEqual(cookie.key, 'color')
|
||||
self.assertEqual(cookie.value, 'blue')
|
||||
self.assertEqual(cookie.domain, None)
|
||||
self.assertEqual(cookie.path, None)
|
||||
self.assertEqual(cookie.max_age, 3600)
|
||||
self.assertEqual(cookie.expires, None)
|
||||
self.assertEqual(cookie.secure, None)
|
||||
self.assertEqual(cookie.httponly, None)
|
||||
self.assertEqual(str(cookie), "color=blue; Max-Age=3600")
|
||||
self.assertEqual(cookie.http_cookie(), "color=blue;")
|
||||
cookie = cookies[1]
|
||||
self.assertEqual(cookie.key, 'temperature')
|
||||
self.assertEqual(cookie.value, 'hot')
|
||||
self.assertEqual(cookie.domain, None)
|
||||
self.assertEqual(cookie.path, None)
|
||||
self.assertEqual(cookie.max_age, None)
|
||||
self.assertEqual(cookie.expires, None)
|
||||
self.assertEqual(cookie.secure, None)
|
||||
self.assertEqual(cookie.httponly, True)
|
||||
self.assertEqual(str(cookie), "temperature=hot; HttpOnly")
|
||||
self.assertEqual(cookie.http_cookie(), "temperature=hot;")
|
||||
|
||||
class TestExpires(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
# Force microseconds to zero because cookie timestamps only have second resolution
|
||||
self.now = datetime.datetime.utcnow().replace(microsecond=0)
|
||||
self.now_timestamp = calendar.timegm(self.now.utctimetuple())
|
||||
self.now_string = email.utils.formatdate(self.now_timestamp, usegmt=True)
|
||||
|
||||
self.max_age = 3600 # 1 hour
|
||||
self.age_expiration = self.now + datetime.timedelta(seconds=self.max_age)
|
||||
self.age_timestamp = calendar.timegm(self.age_expiration.utctimetuple())
|
||||
self.age_string = email.utils.formatdate(self.age_timestamp, usegmt=True)
|
||||
|
||||
self.expires = self.now + datetime.timedelta(days=1) # 1 day
|
||||
self.expires_timestamp = calendar.timegm(self.expires.utctimetuple())
|
||||
self.expires_string = email.utils.formatdate(self.expires_timestamp, usegmt=True)
|
||||
|
||||
def test_expires(self):
|
||||
# 1 cookie with name/value and no Max-Age and no Expires
|
||||
s = 'color=blue;'
|
||||
cookies = Cookie.parse(s)
|
||||
self.assertEqual(len(cookies), 1)
|
||||
cookie = cookies[0]
|
||||
# Force timestamp to known value
|
||||
cookie.timestamp = self.now
|
||||
self.assertEqual(cookie.key, 'color')
|
||||
self.assertEqual(cookie.value, 'blue')
|
||||
self.assertEqual(cookie.domain, None)
|
||||
self.assertEqual(cookie.path, None)
|
||||
self.assertEqual(cookie.max_age, None)
|
||||
self.assertEqual(cookie.expires, None)
|
||||
self.assertEqual(cookie.secure, None)
|
||||
self.assertEqual(cookie.httponly, None)
|
||||
self.assertEqual(str(cookie), "color=blue")
|
||||
self.assertEqual(cookie.get_expiration(), None)
|
||||
# Normalize
|
||||
self.assertEqual(cookie.normalize_expiration(), None)
|
||||
self.assertEqual(cookie.max_age, None)
|
||||
self.assertEqual(cookie.expires, None)
|
||||
self.assertEqual(str(cookie), "color=blue")
|
||||
|
||||
# 1 cookie with name/value and Max-Age
|
||||
s = 'color=blue; max-age=%d' % (self.max_age)
|
||||
cookies = Cookie.parse(s)
|
||||
self.assertEqual(len(cookies), 1)
|
||||
cookie = cookies[0]
|
||||
# Force timestamp to known value
|
||||
cookie.timestamp = self.now
|
||||
self.assertEqual(cookie.key, 'color')
|
||||
self.assertEqual(cookie.value, 'blue')
|
||||
self.assertEqual(cookie.domain, None)
|
||||
self.assertEqual(cookie.path, None)
|
||||
self.assertEqual(cookie.max_age, self.max_age)
|
||||
self.assertEqual(cookie.expires, None)
|
||||
self.assertEqual(cookie.secure, None)
|
||||
self.assertEqual(cookie.httponly, None)
|
||||
self.assertEqual(str(cookie), "color=blue; Max-Age=%d" % (self.max_age))
|
||||
self.assertEqual(cookie.get_expiration(), self.age_expiration)
|
||||
# Normalize
|
||||
self.assertEqual(cookie.normalize_expiration(), self.age_expiration)
|
||||
self.assertEqual(cookie.max_age, None)
|
||||
self.assertEqual(cookie.expires, self.age_expiration)
|
||||
self.assertEqual(str(cookie), "color=blue; Expires=%s" % (self.age_string))
|
||||
|
||||
|
||||
# 1 cookie with name/value and Expires
|
||||
s = 'color=blue; Expires=%s' % (self.expires_string)
|
||||
cookies = Cookie.parse(s)
|
||||
self.assertEqual(len(cookies), 1)
|
||||
cookie = cookies[0]
|
||||
# Force timestamp to known value
|
||||
cookie.timestamp = self.now
|
||||
self.assertEqual(cookie.key, 'color')
|
||||
self.assertEqual(cookie.value, 'blue')
|
||||
self.assertEqual(cookie.domain, None)
|
||||
self.assertEqual(cookie.path, None)
|
||||
self.assertEqual(cookie.max_age, None)
|
||||
self.assertEqual(cookie.expires, self.expires)
|
||||
self.assertEqual(cookie.secure, None)
|
||||
self.assertEqual(cookie.httponly, None)
|
||||
self.assertEqual(str(cookie), "color=blue; Expires=%s" % (self.expires_string))
|
||||
self.assertEqual(cookie.get_expiration(), self.expires)
|
||||
# Normalize
|
||||
self.assertEqual(cookie.normalize_expiration(), self.expires)
|
||||
self.assertEqual(cookie.max_age, None)
|
||||
self.assertEqual(cookie.expires, self.expires)
|
||||
self.assertEqual(str(cookie), "color=blue; Expires=%s" % (self.expires_string))
|
||||
|
||||
# 1 cookie with name/value witht both Max-Age and Expires, Max-Age takes precedence
|
||||
s = 'color=blue; Expires=%s; max-age=%d' % (self.expires_string, self.max_age)
|
||||
cookies = Cookie.parse(s)
|
||||
self.assertEqual(len(cookies), 1)
|
||||
cookie = cookies[0]
|
||||
# Force timestamp to known value
|
||||
cookie.timestamp = self.now
|
||||
self.assertEqual(cookie.key, 'color')
|
||||
self.assertEqual(cookie.value, 'blue')
|
||||
self.assertEqual(cookie.domain, None)
|
||||
self.assertEqual(cookie.path, None)
|
||||
self.assertEqual(cookie.max_age, self.max_age)
|
||||
self.assertEqual(cookie.expires, self.expires)
|
||||
self.assertEqual(cookie.secure, None)
|
||||
self.assertEqual(cookie.httponly, None)
|
||||
self.assertEqual(str(cookie), "color=blue; Max-Age=%d; Expires=%s" % (self.max_age, self.expires_string))
|
||||
self.assertEqual(cookie.get_expiration(), self.age_expiration)
|
||||
# Normalize
|
||||
self.assertEqual(cookie.normalize_expiration(), self.age_expiration)
|
||||
self.assertEqual(cookie.max_age, None)
|
||||
self.assertEqual(cookie.expires, self.age_expiration)
|
||||
self.assertEqual(str(cookie), "color=blue; Expires=%s" % (self.age_string))
|
||||
|
||||
# Verify different types can be assigned to the timestamp and
|
||||
# expires attribute.
|
||||
|
||||
cookie = Cookie('color', 'blue')
|
||||
cookie.timestamp = self.now
|
||||
self.assertEqual(cookie.timestamp, self.now)
|
||||
cookie.timestamp = self.now_timestamp
|
||||
self.assertEqual(cookie.timestamp, self.now)
|
||||
cookie.timestamp = self.now_string
|
||||
self.assertEqual(cookie.timestamp, self.now)
|
||||
|
||||
self.assertEqual(cookie.expires, None)
|
||||
|
||||
cookie.expires = self.expires
|
||||
self.assertEqual(cookie.expires, self.expires)
|
||||
cookie.expires = self.expires_timestamp
|
||||
self.assertEqual(cookie.expires, self.expires)
|
||||
cookie.expires = self.expires_string
|
||||
self.assertEqual(cookie.expires, self.expires)
|
||||
|
||||
class TestInvalidAttributes(unittest.TestCase):
|
||||
def test_invalid(self):
|
||||
# Invalid Max-Age
|
||||
s = 'color=blue; Max-Age=over-the-hill'
|
||||
with self.assertRaises(ValueError):
|
||||
Cookie.parse(s)
|
||||
|
||||
cookie = Cookie('color', 'blue')
|
||||
with self.assertRaises(ValueError):
|
||||
cookie.max_age = 'over-the-hill'
|
||||
|
||||
# Invalid Expires
|
||||
s = 'color=blue; Expires=Sun, 06 Xxx 1994 08:49:37 GMT'
|
||||
with self.assertRaises(ValueError):
|
||||
Cookie.parse(s)
|
||||
|
||||
cookie = Cookie('color', 'blue')
|
||||
with self.assertRaises(ValueError):
|
||||
cookie.expires = 'Sun, 06 Xxx 1994 08:49:37 GMT'
|
||||
|
||||
|
||||
class TestAttributes(unittest.TestCase):
|
||||
def test_attributes(self):
|
||||
cookie = Cookie('color', 'blue')
|
||||
self.assertEqual(cookie.key, 'color')
|
||||
self.assertEqual(cookie.value, 'blue')
|
||||
self.assertEqual(cookie.domain, None)
|
||||
self.assertEqual(cookie.path, None)
|
||||
self.assertEqual(cookie.max_age, None)
|
||||
self.assertEqual(cookie.expires, None)
|
||||
self.assertEqual(cookie.secure, None)
|
||||
self.assertEqual(cookie.httponly, None)
|
||||
|
||||
cookie.domain = 'example.com'
|
||||
self.assertEqual(cookie.domain, 'example.com')
|
||||
cookie.domain = None
|
||||
self.assertEqual(cookie.domain, None)
|
||||
|
||||
cookie.path = '/toplevel'
|
||||
self.assertEqual(cookie.path, '/toplevel')
|
||||
cookie.path = None
|
||||
self.assertEqual(cookie.path, None)
|
||||
|
||||
cookie.max_age = 400
|
||||
self.assertEqual(cookie.max_age, 400)
|
||||
cookie.max_age = None
|
||||
self.assertEqual(cookie.max_age, None)
|
||||
|
||||
cookie.expires = 'Sun, 06 Nov 1994 08:49:37 GMT'
|
||||
self.assertEqual(cookie.expires, datetime.datetime(1994, 11, 6, 8, 49, 37))
|
||||
cookie.expires = None
|
||||
self.assertEqual(cookie.expires, None)
|
||||
|
||||
cookie.secure = True
|
||||
self.assertEqual(cookie.secure, True)
|
||||
self.assertEqual(str(cookie), "color=blue; Secure")
|
||||
cookie.secure = False
|
||||
self.assertEqual(cookie.secure, False)
|
||||
self.assertEqual(str(cookie), "color=blue")
|
||||
cookie.secure = None
|
||||
self.assertEqual(cookie.secure, None)
|
||||
self.assertEqual(str(cookie), "color=blue")
|
||||
|
||||
cookie.httponly = True
|
||||
self.assertEqual(cookie.httponly, True)
|
||||
self.assertEqual(str(cookie), "color=blue; HttpOnly")
|
||||
cookie.httponly = False
|
||||
self.assertEqual(cookie.httponly, False)
|
||||
self.assertEqual(str(cookie), "color=blue")
|
||||
cookie.httponly = None
|
||||
self.assertEqual(cookie.httponly, None)
|
||||
self.assertEqual(str(cookie), "color=blue")
|
||||
|
||||
|
||||
class TestHTTPReturn(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.url = 'http://www.foo.bar.com/one/two'
|
||||
|
||||
def test_no_attributes(self):
|
||||
cookie = Cookie('color', 'blue')
|
||||
self.assertTrue(cookie.http_return_ok(self.url))
|
||||
|
||||
def test_domain(self):
|
||||
cookie = Cookie('color', 'blue', domain='www.foo.bar.com')
|
||||
self.assertTrue(cookie.http_return_ok(self.url))
|
||||
|
||||
cookie = Cookie('color', 'blue', domain='.foo.bar.com')
|
||||
self.assertTrue(cookie.http_return_ok(self.url))
|
||||
|
||||
cookie = Cookie('color', 'blue', domain='.bar.com')
|
||||
self.assertTrue(cookie.http_return_ok(self.url))
|
||||
|
||||
cookie = Cookie('color', 'blue', domain='bar.com')
|
||||
with self.assertRaises(Cookie.URLMismatch):
|
||||
self.assertTrue(cookie.http_return_ok(self.url))
|
||||
|
||||
cookie = Cookie('color', 'blue', domain='bogus.com')
|
||||
with self.assertRaises(Cookie.URLMismatch):
|
||||
self.assertTrue(cookie.http_return_ok(self.url))
|
||||
|
||||
cookie = Cookie('color', 'blue', domain='www.foo.bar.com')
|
||||
with self.assertRaises(Cookie.URLMismatch):
|
||||
self.assertTrue(cookie.http_return_ok('http://192.168.1.1/one/two'))
|
||||
|
||||
def test_path(self):
|
||||
cookie = Cookie('color', 'blue')
|
||||
self.assertTrue(cookie.http_return_ok(self.url))
|
||||
|
||||
cookie = Cookie('color', 'blue', path='/')
|
||||
self.assertTrue(cookie.http_return_ok(self.url))
|
||||
|
||||
cookie = Cookie('color', 'blue', path='/one')
|
||||
self.assertTrue(cookie.http_return_ok(self.url))
|
||||
|
||||
cookie = Cookie('color', 'blue', path='/oneX')
|
||||
with self.assertRaises(Cookie.URLMismatch):
|
||||
self.assertTrue(cookie.http_return_ok(self.url))
|
||||
|
||||
def test_expires(self):
|
||||
now = datetime.datetime.utcnow().replace(microsecond=0)
|
||||
|
||||
# expires 1 day from now
|
||||
expires = now + datetime.timedelta(days=1)
|
||||
|
||||
cookie = Cookie('color', 'blue', expires=expires)
|
||||
self.assertTrue(cookie.http_return_ok(self.url))
|
||||
|
||||
# expired 1 day ago
|
||||
expires = now + datetime.timedelta(days=-1)
|
||||
cookie = Cookie('color', 'blue', expires=expires)
|
||||
with self.assertRaises(Cookie.Expired):
|
||||
self.assertTrue(cookie.http_return_ok(self.url))
|
||||
|
||||
|
||||
def test_httponly(self):
|
||||
cookie = Cookie('color', 'blue', httponly=True)
|
||||
self.assertTrue(cookie.http_return_ok('http://example.com'))
|
||||
self.assertTrue(cookie.http_return_ok('https://example.com'))
|
||||
|
||||
with self.assertRaises(Cookie.URLMismatch):
|
||||
self.assertTrue(cookie.http_return_ok('ftp://example.com'))
|
||||
|
||||
def test_secure(self):
|
||||
cookie = Cookie('color', 'blue', secure=True)
|
||||
self.assertTrue(cookie.http_return_ok('https://Xexample.com'))
|
||||
|
||||
with self.assertRaises(Cookie.URLMismatch):
|
||||
self.assertTrue(cookie.http_return_ok('http://Xexample.com'))
|
||||
|
||||
class TestNormalization(unittest.TestCase):
|
||||
def setUp(self):
|
||||
# Force microseconds to zero because cookie timestamps only have second resolution
|
||||
self.now = datetime.datetime.utcnow().replace(microsecond=0)
|
||||
self.now_timestamp = calendar.timegm(self.now.utctimetuple())
|
||||
self.now_string = email.utils.formatdate(self.now_timestamp, usegmt=True)
|
||||
|
||||
self.max_age = 3600 # 1 hour
|
||||
self.age_expiration = self.now + datetime.timedelta(seconds=self.max_age)
|
||||
self.age_timestamp = calendar.timegm(self.age_expiration.utctimetuple())
|
||||
self.age_string = email.utils.formatdate(self.age_timestamp, usegmt=True)
|
||||
|
||||
self.expires = self.now + datetime.timedelta(days=1) # 1 day
|
||||
self.expires_timestamp = calendar.timegm(self.expires.utctimetuple())
|
||||
self.expires_string = email.utils.formatdate(self.expires_timestamp, usegmt=True)
|
||||
|
||||
def test_path_normalization(self):
|
||||
self.assertEqual(Cookie.normalize_url_path(''), '/')
|
||||
self.assertEqual(Cookie.normalize_url_path('foo'), '/')
|
||||
self.assertEqual(Cookie.normalize_url_path('foo/'), '/')
|
||||
self.assertEqual(Cookie.normalize_url_path('/foo'), '/')
|
||||
self.assertEqual(Cookie.normalize_url_path('/foo/'), '/foo')
|
||||
self.assertEqual(Cookie.normalize_url_path('/Foo/bar'), '/foo')
|
||||
self.assertEqual(Cookie.normalize_url_path('/foo/baR/'), '/foo/bar')
|
||||
|
||||
def test_normalization(self):
|
||||
cookie = Cookie('color', 'blue', expires=self.expires)
|
||||
cookie.timestamp = self.now_timestamp
|
||||
|
||||
self.assertEqual(cookie.domain, None)
|
||||
self.assertEqual(cookie.path, None)
|
||||
|
||||
url = 'http://example.COM/foo'
|
||||
cookie.normalize(url)
|
||||
self.assertEqual(cookie.domain, 'example.com')
|
||||
self.assertEqual(cookie.path, '/')
|
||||
self.assertEqual(cookie.expires, self.expires)
|
||||
|
||||
cookie = Cookie('color', 'blue', max_age=self.max_age)
|
||||
cookie.timestamp = self.now_timestamp
|
||||
|
||||
self.assertEqual(cookie.domain, None)
|
||||
self.assertEqual(cookie.path, None)
|
||||
|
||||
url = 'http://example.com/foo/'
|
||||
cookie.normalize(url)
|
||||
self.assertEqual(cookie.domain, 'example.com')
|
||||
self.assertEqual(cookie.path, '/foo')
|
||||
self.assertEqual(cookie.expires, self.age_expiration)
|
||||
|
||||
cookie = Cookie('color', 'blue')
|
||||
url = 'http://example.com/foo'
|
||||
cookie.normalize(url)
|
||||
self.assertEqual(cookie.domain, 'example.com')
|
||||
self.assertEqual(cookie.path, '/')
|
||||
|
||||
cookie = Cookie('color', 'blue')
|
||||
url = 'http://example.com/foo/bar'
|
||||
cookie.normalize(url)
|
||||
self.assertEqual(cookie.domain, 'example.com')
|
||||
self.assertEqual(cookie.path, '/foo')
|
||||
|
||||
cookie = Cookie('color', 'blue')
|
||||
url = 'http://example.com/foo/bar/'
|
||||
cookie.normalize(url)
|
||||
self.assertEqual(cookie.domain, 'example.com')
|
||||
self.assertEqual(cookie.path, '/foo/bar')
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
1348
ipatests/test_ipapython/test_dn.py
Normal file
1348
ipatests/test_ipapython/test_dn.py
Normal file
File diff suppressed because it is too large
Load Diff
479
ipatests/test_ipapython/test_ipautil.py
Normal file
479
ipatests/test_ipapython/test_ipautil.py
Normal file
@@ -0,0 +1,479 @@
|
||||
# encoding: utf-8
|
||||
|
||||
# Authors:
|
||||
# Jan Cholasta <jcholast@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2011 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# 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 `ipapython/ipautil.py` module.
|
||||
"""
|
||||
|
||||
import nose
|
||||
import pytest
|
||||
import six
|
||||
import tempfile
|
||||
|
||||
from ipapython import ipautil
|
||||
|
||||
pytestmark = pytest.mark.tier0
|
||||
|
||||
|
||||
@pytest.mark.parametrize("addr,words,prefixlen", [
|
||||
('0.0.0.0/0', None, None),
|
||||
('10.11.12.13', (10, 11, 12, 13), 8),
|
||||
('10.11.12.13/14', (10, 11, 12, 13), 14),
|
||||
('10.11.12.13%zoneid', None, None),
|
||||
('10.11.12.13%zoneid/14', None, None),
|
||||
('10.11.12.1337', None, None),
|
||||
('10.11.12.13/33', None, None),
|
||||
('127.0.0.1', None, None),
|
||||
('241.1.2.3', None, None),
|
||||
('169.254.1.2', None, None),
|
||||
('10.11.12.0/24', (10, 11, 12, 0), 24),
|
||||
('10.0.0.255', (10, 0, 0, 255), 8),
|
||||
('224.5.6.7', None, None),
|
||||
('10.11.12.255/24', (10, 11, 12, 255), 24),
|
||||
('255.255.255.255', None, None),
|
||||
('::/0', None, None),
|
||||
('2001::1', (0x2001, 0, 0, 0, 0, 0, 0, 1), 64),
|
||||
('2001::1/72', (0x2001, 0, 0, 0, 0, 0, 0, 1), 72),
|
||||
('2001::1%zoneid', (0x2001, 0, 0, 0, 0, 0, 0, 1), 64),
|
||||
('2001::1%zoneid/72', None, None),
|
||||
('2001::1beef', None, None),
|
||||
('2001::1/129', None, None),
|
||||
('::1', None, None),
|
||||
('6789::1', None, None),
|
||||
('fe89::1', None, None),
|
||||
('2001::/64', (0x2001, 0, 0, 0, 0, 0, 0, 0), 64),
|
||||
('ff01::1', None, None),
|
||||
('junk', None, None)
|
||||
])
|
||||
def test_ip_address(addr, words, prefixlen):
|
||||
if words is None:
|
||||
pytest.raises(
|
||||
ValueError, ipautil.CheckedIPAddress, addr)
|
||||
else:
|
||||
ip = ipautil.CheckedIPAddress(addr)
|
||||
assert ip.words == words
|
||||
assert ip.prefixlen == prefixlen
|
||||
|
||||
|
||||
class TestCIDict(object):
|
||||
def setup(self):
|
||||
self.cidict = ipautil.CIDict()
|
||||
self.cidict["Key1"] = "val1"
|
||||
self.cidict["key2"] = "val2"
|
||||
self.cidict["KEY3"] = "VAL3"
|
||||
|
||||
def test_init(self):
|
||||
cidict = ipautil.CIDict()
|
||||
assert dict(cidict.items()) == {}
|
||||
cidict = ipautil.CIDict([('a', 2), ('b', 3), ('C', 4)])
|
||||
assert dict(cidict.items()) == {'a': 2, 'b': 3, 'C': 4}
|
||||
cidict = ipautil.CIDict([('a', 2), ('b', None)], b=3, C=4)
|
||||
assert dict(cidict.items()) == {'a': 2, 'b': 3, 'C': 4}
|
||||
cidict = ipautil.CIDict({'a': 2, 'b': None}, b=3, C=4)
|
||||
assert dict(cidict.items()) == {'a': 2, 'b': 3, 'C': 4}
|
||||
cidict = ipautil.CIDict(a=2, b=3, C=4)
|
||||
assert dict(cidict.items()) == {'a': 2, 'b': 3, 'C': 4}
|
||||
|
||||
def test_len(self):
|
||||
nose.tools.assert_equal(3, len(self.cidict))
|
||||
|
||||
def test_getitem(self):
|
||||
nose.tools.assert_equal("val1", self.cidict["Key1"])
|
||||
nose.tools.assert_equal("val1", self.cidict["key1"])
|
||||
nose.tools.assert_equal("val2", self.cidict["KEY2"])
|
||||
nose.tools.assert_equal("VAL3", self.cidict["key3"])
|
||||
nose.tools.assert_equal("VAL3", self.cidict["KEY3"])
|
||||
with nose.tools.assert_raises(KeyError):
|
||||
self.cidict["key4"] # pylint: disable=pointless-statement
|
||||
|
||||
def test_get(self):
|
||||
nose.tools.assert_equal("val1", self.cidict.get("Key1"))
|
||||
nose.tools.assert_equal("val1", self.cidict.get("key1"))
|
||||
nose.tools.assert_equal("val2", self.cidict.get("KEY2"))
|
||||
nose.tools.assert_equal("VAL3", self.cidict.get("key3"))
|
||||
nose.tools.assert_equal("VAL3", self.cidict.get("KEY3"))
|
||||
nose.tools.assert_equal("default", self.cidict.get("key4", "default"))
|
||||
|
||||
def test_setitem(self):
|
||||
self.cidict["key4"] = "val4"
|
||||
nose.tools.assert_equal("val4", self.cidict["key4"])
|
||||
self.cidict["KEY4"] = "newval4"
|
||||
nose.tools.assert_equal("newval4", self.cidict["key4"])
|
||||
|
||||
def test_del(self):
|
||||
assert "Key1" in self.cidict
|
||||
del(self.cidict["Key1"])
|
||||
assert "Key1" not in self.cidict
|
||||
|
||||
assert "key2" in self.cidict
|
||||
del(self.cidict["KEY2"])
|
||||
assert "key2" not in self.cidict
|
||||
|
||||
def test_clear(self):
|
||||
nose.tools.assert_equal(3, len(self.cidict))
|
||||
self.cidict.clear()
|
||||
nose.tools.assert_equal(0, len(self.cidict))
|
||||
assert self.cidict == {}
|
||||
assert list(self.cidict) == []
|
||||
assert list(self.cidict.values()) == []
|
||||
assert list(self.cidict.items()) == []
|
||||
if six.PY2:
|
||||
assert self.cidict.keys() == []
|
||||
assert self.cidict.values() == []
|
||||
assert self.cidict.items() == []
|
||||
assert self.cidict._keys == {}
|
||||
|
||||
def test_copy(self):
|
||||
copy = self.cidict.copy()
|
||||
assert copy == self.cidict
|
||||
nose.tools.assert_equal(3, len(copy))
|
||||
assert "Key1" in copy
|
||||
assert "key1" in copy
|
||||
nose.tools.assert_equal("val1", copy["Key1"])
|
||||
|
||||
@pytest.mark.skipif(not six.PY2, reason="Python 2 only")
|
||||
def test_haskey(self):
|
||||
assert self.cidict.has_key("KEY1")
|
||||
assert self.cidict.has_key("key2")
|
||||
assert self.cidict.has_key("key3")
|
||||
|
||||
assert not self.cidict.has_key("Key4")
|
||||
|
||||
def test_contains(self):
|
||||
assert "KEY1" in self.cidict
|
||||
assert "key2" in self.cidict
|
||||
assert "key3" in self.cidict
|
||||
|
||||
assert "Key4" not in self.cidict
|
||||
|
||||
def test_items(self):
|
||||
items = list(self.cidict.items())
|
||||
nose.tools.assert_equal(3, len(items))
|
||||
items_set = set(items)
|
||||
assert ("Key1", "val1") in items_set
|
||||
assert ("key2", "val2") in items_set
|
||||
assert ("KEY3", "VAL3") in items_set
|
||||
|
||||
assert list(self.cidict.items()) == list(self.cidict.iteritems()) == list(zip(
|
||||
self.cidict.keys(), self.cidict.values()))
|
||||
|
||||
def test_iter(self):
|
||||
assert list(self.cidict) == list(self.cidict.keys())
|
||||
assert sorted(self.cidict) == sorted(['Key1', 'key2', 'KEY3'])
|
||||
|
||||
def test_iteritems(self):
|
||||
items = []
|
||||
for (k,v) in self.cidict.iteritems():
|
||||
items.append((k,v))
|
||||
nose.tools.assert_equal(3, len(items))
|
||||
items_set = set(items)
|
||||
assert ("Key1", "val1") in items_set
|
||||
assert ("key2", "val2") in items_set
|
||||
assert ("KEY3", "VAL3") in items_set
|
||||
|
||||
def test_iterkeys(self):
|
||||
keys = []
|
||||
for k in self.cidict.iterkeys():
|
||||
keys.append(k)
|
||||
nose.tools.assert_equal(3, len(keys))
|
||||
keys_set = set(keys)
|
||||
assert "Key1" in keys_set
|
||||
assert "key2" in keys_set
|
||||
assert "KEY3" in keys_set
|
||||
|
||||
def test_itervalues(self):
|
||||
values = []
|
||||
for k in self.cidict.itervalues():
|
||||
values.append(k)
|
||||
nose.tools.assert_equal(3, len(values))
|
||||
values_set = set(values)
|
||||
assert "val1" in values_set
|
||||
assert "val2" in values_set
|
||||
assert "VAL3" in values_set
|
||||
|
||||
def test_keys(self):
|
||||
keys = list(self.cidict.keys())
|
||||
nose.tools.assert_equal(3, len(keys))
|
||||
keys_set = set(keys)
|
||||
assert "Key1" in keys_set
|
||||
assert "key2" in keys_set
|
||||
assert "KEY3" in keys_set
|
||||
|
||||
assert list(self.cidict.keys()) == list(self.cidict.iterkeys())
|
||||
|
||||
def test_values(self):
|
||||
values = list(self.cidict.values())
|
||||
nose.tools.assert_equal(3, len(values))
|
||||
values_set = set(values)
|
||||
assert "val1" in values_set
|
||||
assert "val2" in values_set
|
||||
assert "VAL3" in values_set
|
||||
|
||||
assert list(self.cidict.values()) == list(self.cidict.itervalues())
|
||||
|
||||
def test_update(self):
|
||||
newdict = { "KEY2": "newval2",
|
||||
"key4": "val4" }
|
||||
self.cidict.update(newdict)
|
||||
nose.tools.assert_equal(4, len(self.cidict))
|
||||
|
||||
items = list(self.cidict.items())
|
||||
nose.tools.assert_equal(4, len(items))
|
||||
items_set = set(items)
|
||||
assert ("Key1", "val1") in items_set
|
||||
# note the update "overwrites" the case of the key2
|
||||
assert ("KEY2", "newval2") in items_set
|
||||
assert ("KEY3", "VAL3") in items_set
|
||||
assert ("key4", "val4") in items_set
|
||||
|
||||
def test_update_dict_and_kwargs(self):
|
||||
self.cidict.update({'a': 'va', 'b': None}, b='vb', key2='v2')
|
||||
assert dict(self.cidict.items()) == {
|
||||
'a': 'va', 'b': 'vb',
|
||||
'Key1': 'val1', 'key2': 'v2', 'KEY3': 'VAL3'}
|
||||
|
||||
def test_update_list_and_kwargs(self):
|
||||
self.cidict.update([('a', 'va'), ('b', None)], b='vb', key2='val2')
|
||||
assert dict(self.cidict.items()) == {
|
||||
'a': 'va', 'b': 'vb',
|
||||
'Key1': 'val1', 'key2': 'val2', 'KEY3': 'VAL3'}
|
||||
|
||||
def test_update_duplicate_values_dict(self):
|
||||
with nose.tools.assert_raises(ValueError):
|
||||
self.cidict.update({'a': 'va', 'A': None, 'b': 3})
|
||||
|
||||
def test_update_duplicate_values_list(self):
|
||||
with nose.tools.assert_raises(ValueError):
|
||||
self.cidict.update([('a', 'va'), ('A', None), ('b', 3)])
|
||||
|
||||
def test_update_duplicate_values_kwargs(self):
|
||||
with nose.tools.assert_raises(ValueError):
|
||||
self.cidict.update(a='va', A=None, b=3)
|
||||
|
||||
def test_update_kwargs(self):
|
||||
self.cidict.update(b='vb', key2='val2')
|
||||
assert dict(self.cidict.items()) == {
|
||||
'b': 'vb', 'Key1': 'val1', 'key2': 'val2', 'KEY3': 'VAL3'}
|
||||
|
||||
def test_setdefault(self):
|
||||
nose.tools.assert_equal("val1", self.cidict.setdefault("KEY1", "default"))
|
||||
|
||||
assert "KEY4" not in self.cidict
|
||||
nose.tools.assert_equal("default", self.cidict.setdefault("KEY4", "default"))
|
||||
assert "KEY4" in self.cidict
|
||||
nose.tools.assert_equal("default", self.cidict["key4"])
|
||||
|
||||
assert "KEY5" not in self.cidict
|
||||
nose.tools.assert_equal(None, self.cidict.setdefault("KEY5"))
|
||||
assert "KEY5" in self.cidict
|
||||
nose.tools.assert_equal(None, self.cidict["key5"])
|
||||
|
||||
def test_pop(self):
|
||||
nose.tools.assert_equal("val1", self.cidict.pop("KEY1", "default"))
|
||||
assert "key1" not in self.cidict
|
||||
|
||||
nose.tools.assert_equal("val2", self.cidict.pop("KEY2"))
|
||||
assert "key2" not in self.cidict
|
||||
|
||||
nose.tools.assert_equal("default", self.cidict.pop("key4", "default"))
|
||||
with nose.tools.assert_raises(KeyError):
|
||||
self.cidict.pop("key4")
|
||||
|
||||
def test_popitem(self):
|
||||
items = set(self.cidict.items())
|
||||
nose.tools.assert_equal(3, len(self.cidict))
|
||||
|
||||
item = self.cidict.popitem()
|
||||
nose.tools.assert_equal(2, len(self.cidict))
|
||||
assert item in items
|
||||
items.discard(item)
|
||||
|
||||
item = self.cidict.popitem()
|
||||
nose.tools.assert_equal(1, len(self.cidict))
|
||||
assert item in items
|
||||
items.discard(item)
|
||||
|
||||
item = self.cidict.popitem()
|
||||
nose.tools.assert_equal(0, len(self.cidict))
|
||||
assert item in items
|
||||
items.discard(item)
|
||||
|
||||
def test_fromkeys(self):
|
||||
dct = ipautil.CIDict.fromkeys(('A', 'b', 'C'))
|
||||
assert sorted(dct.keys()) == sorted(['A', 'b', 'C'])
|
||||
assert list(dct.values()) == [None] * 3
|
||||
|
||||
|
||||
class TestTimeParser(object):
|
||||
def test_simple(self):
|
||||
timestr = "20070803"
|
||||
|
||||
time = ipautil.parse_generalized_time(timestr)
|
||||
nose.tools.assert_equal(2007, time.year)
|
||||
nose.tools.assert_equal(8, time.month)
|
||||
nose.tools.assert_equal(3, time.day)
|
||||
nose.tools.assert_equal(0, time.hour)
|
||||
nose.tools.assert_equal(0, time.minute)
|
||||
nose.tools.assert_equal(0, time.second)
|
||||
|
||||
def test_hour_min_sec(self):
|
||||
timestr = "20051213141205"
|
||||
|
||||
time = ipautil.parse_generalized_time(timestr)
|
||||
nose.tools.assert_equal(2005, time.year)
|
||||
nose.tools.assert_equal(12, time.month)
|
||||
nose.tools.assert_equal(13, time.day)
|
||||
nose.tools.assert_equal(14, time.hour)
|
||||
nose.tools.assert_equal(12, time.minute)
|
||||
nose.tools.assert_equal(5, time.second)
|
||||
|
||||
def test_fractions(self):
|
||||
timestr = "2003092208.5"
|
||||
|
||||
time = ipautil.parse_generalized_time(timestr)
|
||||
nose.tools.assert_equal(2003, time.year)
|
||||
nose.tools.assert_equal(9, time.month)
|
||||
nose.tools.assert_equal(22, time.day)
|
||||
nose.tools.assert_equal(8, time.hour)
|
||||
nose.tools.assert_equal(30, time.minute)
|
||||
nose.tools.assert_equal(0, time.second)
|
||||
|
||||
timestr = "199203301544,25"
|
||||
|
||||
time = ipautil.parse_generalized_time(timestr)
|
||||
nose.tools.assert_equal(1992, time.year)
|
||||
nose.tools.assert_equal(3, time.month)
|
||||
nose.tools.assert_equal(30, time.day)
|
||||
nose.tools.assert_equal(15, time.hour)
|
||||
nose.tools.assert_equal(44, time.minute)
|
||||
nose.tools.assert_equal(15, time.second)
|
||||
|
||||
timestr = "20060401185912,8"
|
||||
|
||||
time = ipautil.parse_generalized_time(timestr)
|
||||
nose.tools.assert_equal(2006, time.year)
|
||||
nose.tools.assert_equal(4, time.month)
|
||||
nose.tools.assert_equal(1, time.day)
|
||||
nose.tools.assert_equal(18, time.hour)
|
||||
nose.tools.assert_equal(59, time.minute)
|
||||
nose.tools.assert_equal(12, time.second)
|
||||
nose.tools.assert_equal(800000, time.microsecond)
|
||||
|
||||
def test_time_zones(self):
|
||||
# pylint: disable=no-member
|
||||
|
||||
timestr = "20051213141205Z"
|
||||
|
||||
time = ipautil.parse_generalized_time(timestr)
|
||||
nose.tools.assert_equal(0, time.tzinfo.houroffset)
|
||||
nose.tools.assert_equal(0, time.tzinfo.minoffset)
|
||||
offset = time.tzinfo.utcoffset(time.tzinfo.dst())
|
||||
nose.tools.assert_equal(0, offset.seconds)
|
||||
|
||||
timestr = "20051213141205+0500"
|
||||
|
||||
time = ipautil.parse_generalized_time(timestr)
|
||||
nose.tools.assert_equal(5, time.tzinfo.houroffset)
|
||||
nose.tools.assert_equal(0, time.tzinfo.minoffset)
|
||||
offset = time.tzinfo.utcoffset(time.tzinfo.dst())
|
||||
nose.tools.assert_equal(5 * 60 * 60, offset.seconds)
|
||||
|
||||
timestr = "20051213141205-0500"
|
||||
|
||||
time = ipautil.parse_generalized_time(timestr)
|
||||
nose.tools.assert_equal(-5, time.tzinfo.houroffset)
|
||||
nose.tools.assert_equal(0, time.tzinfo.minoffset)
|
||||
# NOTE - the offset is always positive - it's minutes
|
||||
# _east_ of UTC
|
||||
offset = time.tzinfo.utcoffset(time.tzinfo.dst())
|
||||
nose.tools.assert_equal((24 - 5) * 60 * 60, offset.seconds)
|
||||
|
||||
timestr = "20051213141205-0930"
|
||||
|
||||
time = ipautil.parse_generalized_time(timestr)
|
||||
nose.tools.assert_equal(-9, time.tzinfo.houroffset)
|
||||
nose.tools.assert_equal(-30, time.tzinfo.minoffset)
|
||||
offset = time.tzinfo.utcoffset(time.tzinfo.dst())
|
||||
nose.tools.assert_equal(((24 - 9) * 60 * 60) - (30 * 60), offset.seconds)
|
||||
|
||||
|
||||
def test_run():
|
||||
result = ipautil.run(['echo', 'foo\x02bar'],
|
||||
capture_output=True,
|
||||
capture_error=True)
|
||||
assert result.returncode == 0
|
||||
assert result.output == 'foo\x02bar\n'
|
||||
assert result.raw_output == b'foo\x02bar\n'
|
||||
assert result.error_output == ''
|
||||
assert result.raw_error_output == b''
|
||||
|
||||
|
||||
def test_run_no_capture_output():
|
||||
result = ipautil.run(['echo', 'foo\x02bar'])
|
||||
assert result.returncode == 0
|
||||
assert result.output is None
|
||||
assert result.raw_output == b'foo\x02bar\n'
|
||||
assert result.error_output is None
|
||||
assert result.raw_error_output == b''
|
||||
|
||||
|
||||
def test_run_bytes():
|
||||
result = ipautil.run(['echo', b'\x01\x02'], capture_output=True)
|
||||
assert result.returncode == 0
|
||||
assert result.raw_output == b'\x01\x02\n'
|
||||
|
||||
|
||||
def test_run_decode():
|
||||
result = ipautil.run(['echo', u'á'.encode('utf-8')],
|
||||
encoding='utf-8', capture_output=True)
|
||||
assert result.returncode == 0
|
||||
if six.PY3:
|
||||
assert result.output == 'á\n'
|
||||
else:
|
||||
assert result.output == 'á\n'.encode('utf-8')
|
||||
|
||||
|
||||
def test_run_decode_bad():
|
||||
if six.PY3:
|
||||
with pytest.raises(UnicodeDecodeError):
|
||||
ipautil.run(['echo', b'\xa0\xa1'],
|
||||
capture_output=True,
|
||||
encoding='utf-8')
|
||||
else:
|
||||
result = ipautil.run(['echo', '\xa0\xa1'],
|
||||
capture_output=True,
|
||||
encoding='utf-8')
|
||||
assert result.returncode == 0
|
||||
assert result.output == '\xa0\xa1\n'
|
||||
|
||||
|
||||
def test_backcompat():
|
||||
result = out, err, rc = ipautil.run(['echo', 'foo\x02bar'],
|
||||
capture_output=True,
|
||||
capture_error=True)
|
||||
assert rc is result.returncode
|
||||
assert out is result.output
|
||||
assert err is result.error_output
|
||||
|
||||
|
||||
def test_flush_sync():
|
||||
with tempfile.NamedTemporaryFile('wb+') as f:
|
||||
f.write(b'data')
|
||||
ipautil.flush_sync(f)
|
||||
94
ipatests/test_ipapython/test_ipavalidate.py
Normal file
94
ipatests/test_ipapython/test_ipavalidate.py
Normal file
@@ -0,0 +1,94 @@
|
||||
#! /usr/bin/python2 -E
|
||||
#
|
||||
# Copyright (C) 2007 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# 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/>.
|
||||
#
|
||||
|
||||
import sys
|
||||
sys.path.insert(0, ".")
|
||||
|
||||
import unittest
|
||||
import pytest
|
||||
|
||||
from ipapython import ipavalidate
|
||||
|
||||
pytestmark = pytest.mark.tier0
|
||||
|
||||
class TestValidate(unittest.TestCase):
|
||||
def test_validEmail(self):
|
||||
self.assertEqual(True, ipavalidate.Email("test@freeipa.org"))
|
||||
self.assertEqual(True, ipavalidate.Email("", notEmpty=False))
|
||||
|
||||
def test_invalidEmail(self):
|
||||
self.assertEqual(False, ipavalidate.Email("test"))
|
||||
self.assertEqual(False, ipavalidate.Email("test@freeipa"))
|
||||
self.assertEqual(False, ipavalidate.Email("test@.com"))
|
||||
self.assertEqual(False, ipavalidate.Email(""))
|
||||
self.assertEqual(False, ipavalidate.Email(None))
|
||||
|
||||
def test_validPlain(self):
|
||||
self.assertEqual(True, ipavalidate.Plain("Joe User"))
|
||||
self.assertEqual(True, ipavalidate.Plain("Joe O'Malley"))
|
||||
self.assertEqual(True, ipavalidate.Plain("", notEmpty=False))
|
||||
self.assertEqual(True, ipavalidate.Plain(None, notEmpty=False))
|
||||
self.assertEqual(True, ipavalidate.Plain("JoeUser", allowSpaces=False))
|
||||
self.assertEqual(True, ipavalidate.Plain("JoeUser", allowSpaces=True))
|
||||
|
||||
def test_invalidPlain(self):
|
||||
self.assertEqual(False, ipavalidate.Plain("Joe (User)"))
|
||||
self.assertEqual(False, ipavalidate.Plain("Joe C. User"))
|
||||
self.assertEqual(False, ipavalidate.Plain("", notEmpty=True))
|
||||
self.assertEqual(False, ipavalidate.Plain(None, notEmpty=True))
|
||||
self.assertEqual(False, ipavalidate.Plain("Joe User", allowSpaces=False))
|
||||
self.assertEqual(False, ipavalidate.Plain("Joe C. User"))
|
||||
|
||||
def test_validString(self):
|
||||
self.assertEqual(True, ipavalidate.String("Joe User"))
|
||||
self.assertEqual(True, ipavalidate.String("Joe O'Malley"))
|
||||
self.assertEqual(True, ipavalidate.String("", notEmpty=False))
|
||||
self.assertEqual(True, ipavalidate.String(None, notEmpty=False))
|
||||
self.assertEqual(True, ipavalidate.String("Joe C. User"))
|
||||
|
||||
def test_invalidString(self):
|
||||
self.assertEqual(False, ipavalidate.String("", notEmpty=True))
|
||||
self.assertEqual(False, ipavalidate.String(None, notEmpty=True))
|
||||
|
||||
def test_validPath(self):
|
||||
self.assertEqual(True, ipavalidate.Path("/"))
|
||||
self.assertEqual(True, ipavalidate.Path("/home/user"))
|
||||
self.assertEqual(True, ipavalidate.Path("../home/user"))
|
||||
self.assertEqual(True, ipavalidate.Path("", notEmpty=False))
|
||||
self.assertEqual(True, ipavalidate.Path(None, notEmpty=False))
|
||||
|
||||
def test_invalidPath(self):
|
||||
self.assertEqual(False, ipavalidate.Path("(foo)"))
|
||||
self.assertEqual(False, ipavalidate.Path("", notEmpty=True))
|
||||
self.assertEqual(False, ipavalidate.Path(None, notEmpty=True))
|
||||
|
||||
def test_validName(self):
|
||||
self.assertEqual(True, ipavalidate.GoodName("foo"))
|
||||
self.assertEqual(True, ipavalidate.GoodName("1foo"))
|
||||
self.assertEqual(True, ipavalidate.GoodName("foo.bar"))
|
||||
self.assertEqual(True, ipavalidate.GoodName("foo.bar$"))
|
||||
|
||||
def test_invalidName(self):
|
||||
self.assertEqual(False, ipavalidate.GoodName("foo bar"))
|
||||
self.assertEqual(False, ipavalidate.GoodName("foo%bar"))
|
||||
self.assertEqual(False, ipavalidate.GoodName("*foo"))
|
||||
self.assertEqual(False, ipavalidate.GoodName("$foo.bar$"))
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
139
ipatests/test_ipapython/test_kerberos.py
Normal file
139
ipatests/test_ipapython/test_kerberos.py
Normal file
@@ -0,0 +1,139 @@
|
||||
#
|
||||
# Copyright (C) 2016 FreeIPA Project Contributors - see LICENSE file
|
||||
#
|
||||
|
||||
import pytest
|
||||
import six
|
||||
|
||||
from ipapython.kerberos import Principal
|
||||
|
||||
if six.PY3:
|
||||
unicode = str
|
||||
|
||||
valid_principals = {
|
||||
u'tuser@REALM.TEST': {
|
||||
'components': (u'tuser',),
|
||||
'realm': u'REALM.TEST',
|
||||
'username': u'tuser'
|
||||
},
|
||||
u'tuser\@tupn.test@REALM.TEST': {
|
||||
'components': (u'tuser@tupn.test',),
|
||||
'realm': u'REALM.TEST',
|
||||
'username': u'tuser@tupn.test',
|
||||
'upn_suffix': u'tupn.test'
|
||||
},
|
||||
u'test/host.ipa.test@REALM.TEST': {
|
||||
'components': (u'test', u'host.ipa.test'),
|
||||
'realm': u'REALM.TEST',
|
||||
'hostname': u'host.ipa.test'
|
||||
},
|
||||
u'test/service/host.ipa.test@REALM.TEST': {
|
||||
'components': (u'test', u'service', u'host.ipa.test'),
|
||||
'realm': u'REALM.TEST',
|
||||
'service_name': u'test/service'
|
||||
|
||||
},
|
||||
u'tuser': {
|
||||
'components': (u'tuser',),
|
||||
'realm': None,
|
||||
'username': u'tuser'
|
||||
},
|
||||
u'$%user@REALM.TEST': {
|
||||
'components': (u'$%user',),
|
||||
'realm': u'REALM.TEST',
|
||||
'username': u'$%user'
|
||||
},
|
||||
u'host/host.ipa.test': {
|
||||
'components': (u'host', u'host.ipa.test'),
|
||||
'realm': None,
|
||||
'hostname': u'host.ipa.test'
|
||||
},
|
||||
u's$c/$%^.ipa.t%$t': {
|
||||
'components': (u's$c', u'$%^.ipa.t%$t'),
|
||||
'realm': None,
|
||||
'hostname': u'$%^.ipa.t%$t',
|
||||
'service_name': u's$c'
|
||||
},
|
||||
u'test\/service/test\/host@REALM\@TEST': {
|
||||
'components': (u'test/service', u'test/host'),
|
||||
'realm': u'REALM@TEST',
|
||||
'hostname': u'test/host',
|
||||
'service_name': u'test\/service'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def valid_principal_iter(principals):
|
||||
for princ, data in principals.items():
|
||||
yield princ, data
|
||||
|
||||
|
||||
@pytest.fixture(params=list(valid_principal_iter(valid_principals)))
|
||||
def valid_principal(request):
|
||||
return request.param
|
||||
|
||||
|
||||
def test_principals(valid_principal):
|
||||
principal_name, data = valid_principal
|
||||
|
||||
princ = Principal(principal_name)
|
||||
|
||||
for name, value in data.items():
|
||||
assert getattr(princ, name) == value
|
||||
|
||||
assert unicode(princ) == principal_name
|
||||
assert repr(princ) == "ipapython.kerberos.Principal('{}')".format(
|
||||
principal_name)
|
||||
|
||||
|
||||
def test_multiple_unescaped_ats_raise_error():
|
||||
pytest.raises(ValueError, Principal, u'too@many@realms')
|
||||
|
||||
|
||||
principals_properties = {
|
||||
u'user@REALM': {
|
||||
'property_true': ('is_user',),
|
||||
'property_raises': ('upn_suffix', 'hostname', 'service_name')
|
||||
},
|
||||
u'host/m1.ipa.test@REALM': {
|
||||
'property_true': ('is_host', 'is_service'),
|
||||
'property_raises': ('username', 'upn_suffix')
|
||||
},
|
||||
u'service/m1.ipa.test@REALM': {
|
||||
'property_true': ('is_service'),
|
||||
'property_raises': ('username', 'upn_suffix')
|
||||
},
|
||||
u'user\@domain@REALM': {
|
||||
'property_true': ('is_user', 'is_enterprise'),
|
||||
'property_raises': ('hostname', 'service_name')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def principal_properties_iter(principals_properties):
|
||||
for p, data in principals_properties.items():
|
||||
yield p, data
|
||||
|
||||
|
||||
@pytest.fixture(params=list(principal_properties_iter(principals_properties)))
|
||||
def principal_properties(request):
|
||||
return request.param
|
||||
|
||||
|
||||
def test_principal_properties(principal_properties):
|
||||
principal, data = principal_properties
|
||||
|
||||
princ = Principal(principal)
|
||||
|
||||
boolean_propertes = [prop for prop in dir(princ) if
|
||||
prop.startswith('is_')]
|
||||
|
||||
for b in boolean_propertes:
|
||||
if b in data['property_true']:
|
||||
assert getattr(princ, b)
|
||||
else:
|
||||
assert not getattr(princ, b)
|
||||
|
||||
for property_raises in data['property_raises']:
|
||||
with pytest.raises(ValueError):
|
||||
getattr(princ, property_raises)
|
||||
167
ipatests/test_ipapython/test_keyring.py
Normal file
167
ipatests/test_ipapython/test_keyring.py
Normal file
@@ -0,0 +1,167 @@
|
||||
# Authors:
|
||||
# Rob Crittenden <rcritten@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2012 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# 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 `kernel_keyring.py` module.
|
||||
"""
|
||||
|
||||
from nose.tools import raises # pylint: disable=E0611
|
||||
from ipapython import kernel_keyring
|
||||
|
||||
import pytest
|
||||
|
||||
pytestmark = pytest.mark.tier0
|
||||
|
||||
TEST_KEY = 'ipa_test'
|
||||
TEST_UNICODEKEY = u'ipa_unicode'
|
||||
TEST_VALUE = b'abc123'
|
||||
UPDATE_VALUE = b'123abc'
|
||||
|
||||
SIZE_256 = 'abcdefgh' * 32
|
||||
SIZE_512 = 'abcdefgh' * 64
|
||||
SIZE_1024 = 'abcdefgh' * 128
|
||||
|
||||
class test_keyring(object):
|
||||
"""
|
||||
Test the kernel keyring interface
|
||||
"""
|
||||
|
||||
def setup(self):
|
||||
try:
|
||||
kernel_keyring.del_key(TEST_KEY)
|
||||
except ValueError:
|
||||
pass
|
||||
try:
|
||||
kernel_keyring.del_key(SIZE_256)
|
||||
except ValueError:
|
||||
pass
|
||||
try:
|
||||
kernel_keyring.del_key(TEST_UNICODEKEY)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
def test_01(self):
|
||||
"""
|
||||
Add a new key and value, then remove it
|
||||
"""
|
||||
kernel_keyring.add_key(TEST_KEY, TEST_VALUE)
|
||||
result = kernel_keyring.read_key(TEST_KEY)
|
||||
assert(result == TEST_VALUE)
|
||||
|
||||
kernel_keyring.del_key(TEST_KEY)
|
||||
|
||||
# Make sure it is gone
|
||||
try:
|
||||
result = kernel_keyring.read_key(TEST_KEY)
|
||||
except ValueError as e:
|
||||
assert str(e) == 'key %s not found' % TEST_KEY
|
||||
|
||||
def test_02(self):
|
||||
"""
|
||||
Delete a non_existent key
|
||||
"""
|
||||
try:
|
||||
kernel_keyring.del_key(TEST_KEY)
|
||||
raise AssertionError('key should not have been deleted')
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
@raises(ValueError)
|
||||
def test_03(self):
|
||||
"""
|
||||
Add a duplicate key
|
||||
"""
|
||||
kernel_keyring.add_key(TEST_KEY, TEST_VALUE)
|
||||
kernel_keyring.add_key(TEST_KEY, TEST_VALUE)
|
||||
|
||||
def test_04(self):
|
||||
"""
|
||||
Update the value in a key
|
||||
"""
|
||||
kernel_keyring.update_key(TEST_KEY, UPDATE_VALUE)
|
||||
result = kernel_keyring.read_key(TEST_KEY)
|
||||
assert(result == UPDATE_VALUE)
|
||||
|
||||
# Now update it 10 times
|
||||
for i in range(10):
|
||||
value = ('test %d' % i).encode('ascii')
|
||||
kernel_keyring.update_key(TEST_KEY, value)
|
||||
result = kernel_keyring.read_key(TEST_KEY)
|
||||
assert(result == value)
|
||||
|
||||
kernel_keyring.del_key(TEST_KEY)
|
||||
|
||||
@raises(ValueError)
|
||||
def test_05(self):
|
||||
"""
|
||||
Read a non-existent key
|
||||
"""
|
||||
kernel_keyring.read_key(TEST_KEY)
|
||||
|
||||
def test_06(self):
|
||||
"""
|
||||
See if a key is available
|
||||
"""
|
||||
kernel_keyring.add_key(TEST_KEY, TEST_VALUE)
|
||||
|
||||
result = kernel_keyring.has_key(TEST_KEY)
|
||||
assert(result == True)
|
||||
kernel_keyring.del_key(TEST_KEY)
|
||||
|
||||
result = kernel_keyring.has_key(TEST_KEY)
|
||||
assert(result == False)
|
||||
|
||||
def test_07(self):
|
||||
"""
|
||||
Test a 256-byte key
|
||||
"""
|
||||
kernel_keyring.add_key(SIZE_256, TEST_VALUE)
|
||||
result = kernel_keyring.read_key(SIZE_256)
|
||||
assert(result == TEST_VALUE)
|
||||
|
||||
kernel_keyring.del_key(SIZE_256)
|
||||
|
||||
def test_08(self):
|
||||
"""
|
||||
Test 512-bytes of data
|
||||
"""
|
||||
kernel_keyring.add_key(TEST_KEY, SIZE_512.encode('ascii'))
|
||||
result = kernel_keyring.read_key(TEST_KEY)
|
||||
assert(result == SIZE_512.encode('ascii'))
|
||||
|
||||
kernel_keyring.del_key(TEST_KEY)
|
||||
|
||||
def test_09(self):
|
||||
"""
|
||||
Test 1k bytes of data
|
||||
"""
|
||||
kernel_keyring.add_key(TEST_KEY, SIZE_1024.encode('ascii'))
|
||||
result = kernel_keyring.read_key(TEST_KEY)
|
||||
assert(result == SIZE_1024.encode('ascii'))
|
||||
|
||||
kernel_keyring.del_key(TEST_KEY)
|
||||
|
||||
def test_10(self):
|
||||
"""
|
||||
Test a unicode key
|
||||
"""
|
||||
kernel_keyring.add_key(TEST_UNICODEKEY, TEST_VALUE)
|
||||
result = kernel_keyring.read_key(TEST_UNICODEKEY)
|
||||
assert(result == TEST_VALUE)
|
||||
|
||||
kernel_keyring.del_key(TEST_UNICODEKEY)
|
||||
40
ipatests/test_ipapython/test_session_storage.py
Normal file
40
ipatests/test_ipapython/test_session_storage.py
Normal file
@@ -0,0 +1,40 @@
|
||||
#
|
||||
# Copyright (C) 2017 FreeIPA Contributors see COPYING for license
|
||||
#
|
||||
|
||||
"""
|
||||
Test the `session_storage.py` module.
|
||||
"""
|
||||
import pytest
|
||||
|
||||
from ipapython import session_storage
|
||||
|
||||
|
||||
@pytest.mark.skip_ipaclient_unittest
|
||||
@pytest.mark.needs_ipaapi
|
||||
class test_session_storage(object):
|
||||
"""
|
||||
Test the session storage interface
|
||||
"""
|
||||
|
||||
def setup(self):
|
||||
# TODO: set up test user and kinit to it
|
||||
# tmpdir = tempfile.mkdtemp(prefix = "tmp-")
|
||||
# os.environ['KRB5CCNAME'] = 'FILE:%s/ccache' % tmpdir
|
||||
self.principal = 'admin'
|
||||
self.key = 'X-IPA-test-session-storage'
|
||||
self.data = b'Test Data'
|
||||
|
||||
def test_01(self):
|
||||
session_storage.store_data(self.principal, self.key, self.data)
|
||||
|
||||
def test_02(self):
|
||||
data = session_storage.get_data(self.principal, self.key)
|
||||
assert(data == self.data)
|
||||
|
||||
def test_03(self):
|
||||
session_storage.remove_data(self.principal, self.key)
|
||||
try:
|
||||
session_storage.get_data(self.principal, self.key)
|
||||
except session_storage.KRB5Error:
|
||||
pass
|
||||
87
ipatests/test_ipapython/test_ssh.py
Normal file
87
ipatests/test_ipapython/test_ssh.py
Normal file
@@ -0,0 +1,87 @@
|
||||
# Authors:
|
||||
# Jan Cholasta <jcholast@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2011 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# 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 `ipapython/ssh.py` module.
|
||||
"""
|
||||
|
||||
import base64
|
||||
|
||||
import six
|
||||
import pytest
|
||||
|
||||
from ipapython import ssh
|
||||
|
||||
if six.PY3:
|
||||
unicode = str
|
||||
|
||||
pytestmark = pytest.mark.tier0
|
||||
|
||||
b64 = 'AAAAB3NzaC1yc2EAAAADAQABAAABAQDGAX3xAeLeaJggwTqMjxNwa6XHBUAikXPGMzEpVrlLDCZtv00djsFTBi38PkgxBJVkgRWMrcBsr/35lq7P6w8KGIwA8GI48Z0qBS2NBMJ2u9WQ2hjLN6GdMlo77O0uJY3251p12pCVIS/bHRSq8kHO2No8g7KA9fGGcagPfQH+ee3t7HUkpbQkFTmbPPN++r3V8oVUk5LxbryB3UIIVzNmcSIn3JrXynlvui4MixvrtX6zx+O/bBo68o8/eZD26QrahVbA09fivrn/4h3TM019Eu/c2jOdckfU3cHUV/3Tno5d6JicibyaoDDK7S/yjdn5jhaz8MSEayQvFkZkiF0L'
|
||||
raw = base64.b64decode(b64)
|
||||
openssh = 'ssh-rsa %s' % b64
|
||||
|
||||
|
||||
@pytest.mark.parametrize("pk,out", [
|
||||
(b'\xff', UnicodeDecodeError),
|
||||
(u'\xff', ValueError),
|
||||
|
||||
(raw, openssh),
|
||||
(b'\0\0\0\x04none', u'none AAAABG5vbmU='),
|
||||
(b'\0\0\0', ValueError),
|
||||
(b'\0\0\0\0', ValueError),
|
||||
(b'\0\0\0\x01', ValueError),
|
||||
(b'\0\0\0\x01\xff', ValueError),
|
||||
|
||||
(u'\0\0\0\x04none', ValueError),
|
||||
(u'\0\0\0', ValueError),
|
||||
(u'\0\0\0\0', ValueError),
|
||||
(u'\0\0\0\x01', ValueError),
|
||||
(u'\0\0\0\x01\xff', ValueError),
|
||||
|
||||
(b64, openssh),
|
||||
(unicode(b64), openssh),
|
||||
(b64.encode('ascii'), openssh),
|
||||
(u'\n%s\n\n' % b64, openssh),
|
||||
(u'AAAABG5vbmU=', u'none AAAABG5vbmU='),
|
||||
(u'AAAAB', ValueError),
|
||||
|
||||
(openssh, openssh),
|
||||
(unicode(openssh), openssh),
|
||||
(openssh.encode('ascii'), openssh),
|
||||
(u'none AAAABG5vbmU=', u'none AAAABG5vbmU='),
|
||||
(u'\t \t ssh-rsa \t \t%s\t \tthis is a comment\t \t ' % b64,
|
||||
u'%s this is a comment' % openssh),
|
||||
(u'opt3,opt2="\tx ",opt1,opt2="\\"x " %s comment ' % openssh,
|
||||
u'opt1,opt2="\\"x ",opt3 %s comment' % openssh),
|
||||
(u'ssh-rsa\n%s' % b64, ValueError),
|
||||
(u'ssh-rsa\t%s' % b64, ValueError),
|
||||
(u'vanitas %s' % b64, ValueError),
|
||||
(u'@opt %s' % openssh, ValueError),
|
||||
(u'opt=val %s' % openssh, ValueError),
|
||||
(u'opt, %s' % openssh, ValueError)],
|
||||
# ids=repr is workaround for pytest issue with NULL bytes,
|
||||
# see https://github.com/pytest-dev/pytest/issues/2644
|
||||
ids=repr
|
||||
)
|
||||
def test_public_key_parsing(pk, out):
|
||||
if isinstance(out, type) and issubclass(out, Exception):
|
||||
pytest.raises(out, ssh.SSHPublicKey, pk)
|
||||
else:
|
||||
parsed = ssh.SSHPublicKey(pk)
|
||||
assert parsed.openssh() == out
|
||||
Reference in New Issue
Block a user