mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-09-03 07:25:18 +00:00
Merge branch 'work/authtsig'
This commit is contained in:
@@ -686,6 +686,7 @@ AC_CONFIG_FILES([Makefile
|
|||||||
src/bin/bindctl/tests/Makefile
|
src/bin/bindctl/tests/Makefile
|
||||||
src/bin/cfgmgr/Makefile
|
src/bin/cfgmgr/Makefile
|
||||||
src/bin/cfgmgr/plugins/Makefile
|
src/bin/cfgmgr/plugins/Makefile
|
||||||
|
src/bin/cfgmgr/plugins/tests/Makefile
|
||||||
src/bin/cfgmgr/tests/Makefile
|
src/bin/cfgmgr/tests/Makefile
|
||||||
src/bin/host/Makefile
|
src/bin/host/Makefile
|
||||||
src/bin/loadzone/Makefile
|
src/bin/loadzone/Makefile
|
||||||
|
@@ -18,6 +18,7 @@
|
|||||||
import sys; sys.path.append ('@@PYTHONPATH@@')
|
import sys; sys.path.append ('@@PYTHONPATH@@')
|
||||||
|
|
||||||
from isc.config.cfgmgr import ConfigManager, ConfigManagerDataReadError
|
from isc.config.cfgmgr import ConfigManager, ConfigManagerDataReadError
|
||||||
|
import bind10_config
|
||||||
from isc.cc import SessionError
|
from isc.cc import SessionError
|
||||||
import isc.util.process
|
import isc.util.process
|
||||||
import signal
|
import signal
|
||||||
@@ -28,24 +29,10 @@ import os.path
|
|||||||
|
|
||||||
isc.util.process.rename()
|
isc.util.process.rename()
|
||||||
|
|
||||||
# If B10_FROM_SOURCE is set in the environment, we use data files
|
# Import some paths from our configuration
|
||||||
# from a directory relative to the value of that variable, or, if defined,
|
DATA_PATH = bind10_config.DATA_PATH
|
||||||
# relative to the value of B10_FROM_SOURCE_LOCALSTATEDIR. Otherwise
|
PLUGIN_PATHS = bind10_config.PLUGIN_PATHS
|
||||||
# we use the ones installed on the system.
|
PREFIX = bind10_config.PREFIX
|
||||||
# B10_FROM_SOURCE_LOCALSTATEDIR is specifically intended to be used for
|
|
||||||
# tests where we want to use variuos types of configuration within the test
|
|
||||||
# environment. (We may want to make it even more generic so that the path is
|
|
||||||
# passed from the boss process)
|
|
||||||
if "B10_FROM_SOURCE" in os.environ:
|
|
||||||
if "B10_FROM_SOURCE_LOCALSTATEDIR" in os.environ:
|
|
||||||
DATA_PATH = os.environ["B10_FROM_SOURCE_LOCALSTATEDIR"]
|
|
||||||
else:
|
|
||||||
DATA_PATH = os.environ["B10_FROM_SOURCE"]
|
|
||||||
PLUGIN_PATHS = [DATA_PATH + '/src/bin/cfgmgr/plugins']
|
|
||||||
else:
|
|
||||||
PREFIX = "@prefix@"
|
|
||||||
DATA_PATH = "@localstatedir@/@PACKAGE@".replace("${prefix}", PREFIX)
|
|
||||||
PLUGIN_PATHS = ["@prefix@/share/@PACKAGE@/config_plugins"]
|
|
||||||
DEFAULT_CONFIG_FILE = "b10-config.db"
|
DEFAULT_CONFIG_FILE = "b10-config.db"
|
||||||
|
|
||||||
cm = None
|
cm = None
|
||||||
|
@@ -1 +1,5 @@
|
|||||||
EXTRA_DIST = README
|
SUBDIRS = tests
|
||||||
|
EXTRA_DIST = README tsig_keys.py tsig_keys.spec
|
||||||
|
|
||||||
|
config_plugindir = @prefix@/share/@PACKAGE@/config_plugins
|
||||||
|
config_plugin_DATA = tsig_keys.py tsig_keys.spec
|
||||||
|
19
src/bin/cfgmgr/plugins/tests/Makefile.am
Normal file
19
src/bin/cfgmgr/plugins/tests/Makefile.am
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
PYCOVERAGE_RUN = @PYCOVERAGE_RUN@
|
||||||
|
PYTESTS = tsig_keys_test.py
|
||||||
|
|
||||||
|
EXTRA_DIST = $(PYTESTS)
|
||||||
|
|
||||||
|
# test using command-line arguments, so use check-local target instead of TESTS
|
||||||
|
check-local:
|
||||||
|
if ENABLE_PYTHON_COVERAGE
|
||||||
|
touch $(abs_top_srcdir)/.coverage
|
||||||
|
rm -f .coverage
|
||||||
|
${LN_S} $(abs_top_srcdir)/.coverage .coverage
|
||||||
|
endif
|
||||||
|
for pytest in $(PYTESTS) ; do \
|
||||||
|
echo Running test: $$pytest ; \
|
||||||
|
env B10_TEST_PLUGIN_DIR=$(abs_srcdir)/..:$(abs_builddir)/.. \
|
||||||
|
env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/bin/cfgmgr:$(abs_top_builddir)/src/lib/dns/python/.libs \
|
||||||
|
$(PYCOVERAGE_RUN) $(abs_srcdir)/$$pytest || exit ; \
|
||||||
|
done
|
||||||
|
|
103
src/bin/cfgmgr/plugins/tests/tsig_keys_test.py
Normal file
103
src/bin/cfgmgr/plugins/tests/tsig_keys_test.py
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
# Copyright (C) 2011 Internet Systems Consortium.
|
||||||
|
#
|
||||||
|
# Permission to use, copy, modify, and distribute this software for any
|
||||||
|
# purpose with or without fee is hereby granted, provided that the above
|
||||||
|
# copyright notice and this permission notice appear in all copies.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
|
||||||
|
# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
|
||||||
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
|
||||||
|
# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||||
|
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
|
||||||
|
# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
|
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
|
||||||
|
# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
# Make sure we can load the module, put it into path
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
sys.path.extend(os.environ["B10_TEST_PLUGIN_DIR"].split(':'))
|
||||||
|
|
||||||
|
import tsig_keys
|
||||||
|
import unittest
|
||||||
|
import isc.config.module_spec
|
||||||
|
|
||||||
|
class TSigKeysTest(unittest.TestCase):
|
||||||
|
def test_load(self):
|
||||||
|
"""
|
||||||
|
Checks the entry point returns the correct values.
|
||||||
|
"""
|
||||||
|
(spec, check) = tsig_keys.load()
|
||||||
|
# It returns the checking function
|
||||||
|
self.assertEqual(check, tsig_keys.check)
|
||||||
|
# The plugin stores it's spec
|
||||||
|
self.assertEqual(spec, tsig_keys.spec)
|
||||||
|
|
||||||
|
def test_spec(self):
|
||||||
|
"""
|
||||||
|
Checks the spec is looking sane (doesn't do really deep check here).
|
||||||
|
"""
|
||||||
|
spec = tsig_keys.spec
|
||||||
|
# In python, we don't generally check the type of something, because
|
||||||
|
# of the duck typing.
|
||||||
|
# But this is unittest, so we check it does what we intend and
|
||||||
|
# supplying that's behaving the same but is different is not our
|
||||||
|
# intention
|
||||||
|
self.assertTrue(isinstance(spec, isc.config.module_spec.ModuleSpec))
|
||||||
|
# Correct name
|
||||||
|
self.assertEqual("tsig_keys", spec.get_module_name())
|
||||||
|
# There are no commands, nobody would handle them anyway
|
||||||
|
self.assertEqual([], spec.get_commands_spec())
|
||||||
|
# There's some nonempty configuration
|
||||||
|
self.assertNotEqual({}, spec.get_config_spec())
|
||||||
|
|
||||||
|
def test_missing_keys(self):
|
||||||
|
"""
|
||||||
|
Test that missing keys doesn't kill us. There are just no keys there.
|
||||||
|
"""
|
||||||
|
self.assertEqual(None, tsig_keys.check({}))
|
||||||
|
|
||||||
|
def test_data_empty(self):
|
||||||
|
"""Check we accept valid config with empty set of tsig keys."""
|
||||||
|
self.assertEqual(None, tsig_keys.check({'keys': []}))
|
||||||
|
|
||||||
|
def test_keys_valid(self):
|
||||||
|
"""
|
||||||
|
Check we accept some valid keys (we don't check all the algorithms,
|
||||||
|
that's the job of isc.dns.TSIGKey).
|
||||||
|
"""
|
||||||
|
self.assertEqual(None, tsig_keys.check({'keys':
|
||||||
|
['testkey:QklORCAxMCBpcyBjb29sCg==',
|
||||||
|
'test.key:QklORCAxMCBpcyBjb29sCg==:hmac-sha1']}))
|
||||||
|
|
||||||
|
def test_keys_same_name(self):
|
||||||
|
"""
|
||||||
|
Test we reject when we have multiple keys with the same name.
|
||||||
|
"""
|
||||||
|
self.assertEqual("Multiple TSIG keys with name 'test.key.'",
|
||||||
|
tsig_keys.check({'keys':
|
||||||
|
['test.key:QklORCAxMCBpcyBjb29sCg==',
|
||||||
|
'test.key:b3RoZXIK']}))
|
||||||
|
|
||||||
|
def test_invalid_key(self):
|
||||||
|
"""
|
||||||
|
Test we reject invalid key.
|
||||||
|
"""
|
||||||
|
self.assertEqual("TSIG: Invalid TSIG key string: invalid.key",
|
||||||
|
tsig_keys.check({'keys': ['invalid.key']}))
|
||||||
|
self.assertEqual(
|
||||||
|
"TSIG: attempt to decode a value not in base64 char set",
|
||||||
|
tsig_keys.check({'keys': ['invalid.key:123']}))
|
||||||
|
|
||||||
|
def test_bad_format(self):
|
||||||
|
"""
|
||||||
|
Test we fail on bad format. We don't really care much how here, though,
|
||||||
|
as this should not get in trough config manager anyway.
|
||||||
|
"""
|
||||||
|
self.assertNotEqual(None, tsig_keys.check({'bad_name': {}}))
|
||||||
|
self.assertNotEqual(None, tsig_keys.check({'keys': 'not_list'}))
|
||||||
|
self.assertNotEqual(None, tsig_keys.check({'keys': 42}))
|
||||||
|
self.assertNotEqual(None, tsig_keys.check({'keys': {}}))
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
50
src/bin/cfgmgr/plugins/tsig_keys.py
Normal file
50
src/bin/cfgmgr/plugins/tsig_keys.py
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
# Copyright (C) 2011 Internet Systems Consortium.
|
||||||
|
#
|
||||||
|
# Permission to use, copy, modify, and distribute this software for any
|
||||||
|
# purpose with or without fee is hereby granted, provided that the above
|
||||||
|
# copyright notice and this permission notice appear in all copies.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
|
||||||
|
# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
|
||||||
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
|
||||||
|
# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||||
|
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
|
||||||
|
# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
|
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
|
||||||
|
# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
# This is the plugin for tsig_keys configuration section. The TSIG keyring
|
||||||
|
# lives there (eg. all the shared secrets, with some exceptions where there
|
||||||
|
# are some TSIG keys elsewhere, but these should be removed soon). We do
|
||||||
|
# sanity checking of user configuration here, simply by trying to construct
|
||||||
|
# all the keys here.
|
||||||
|
|
||||||
|
from isc.config.module_spec import module_spec_from_file
|
||||||
|
from isc.util.file import path_search
|
||||||
|
from pydnspp import TSIGKey, InvalidParameter
|
||||||
|
from bind10_config import PLUGIN_PATHS
|
||||||
|
spec = module_spec_from_file(path_search('tsig_keys.spec', PLUGIN_PATHS))
|
||||||
|
|
||||||
|
def check(config):
|
||||||
|
# Check the data layout first
|
||||||
|
errors=[]
|
||||||
|
if not spec.validate_config(False, config, errors):
|
||||||
|
return ' '.join(errors)
|
||||||
|
# Get the list of keys, if any
|
||||||
|
keys = config.get('keys', [])
|
||||||
|
# Run through them, check they can be constructed and there are no
|
||||||
|
# duplicates
|
||||||
|
keyNames = set()
|
||||||
|
for key in keys:
|
||||||
|
try:
|
||||||
|
name = str(TSIGKey(key).get_key_name())
|
||||||
|
except InvalidParameter as e:
|
||||||
|
return "TSIG: " + str(e)
|
||||||
|
if name in keyNames:
|
||||||
|
return "Multiple TSIG keys with name '" + name + "'"
|
||||||
|
keyNames.add(name)
|
||||||
|
# No error found, so let's assume it's OK
|
||||||
|
return None
|
||||||
|
|
||||||
|
def load():
|
||||||
|
return (spec, check)
|
21
src/bin/cfgmgr/plugins/tsig_keys.spec
Normal file
21
src/bin/cfgmgr/plugins/tsig_keys.spec
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"module_spec": {
|
||||||
|
"module_name": "tsig_keys",
|
||||||
|
"module_description": "The TSIG keyring is stored here",
|
||||||
|
"config_data": [
|
||||||
|
{
|
||||||
|
"item_name": "keys",
|
||||||
|
"item_type": "list",
|
||||||
|
"item_optional": false,
|
||||||
|
"item_default": [],
|
||||||
|
"list_item_spec": {
|
||||||
|
"item_name": "key",
|
||||||
|
"item_type": "string",
|
||||||
|
"item_optional": false,
|
||||||
|
"item_default": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"commands": []
|
||||||
|
}
|
||||||
|
}
|
@@ -20,6 +20,7 @@
|
|||||||
import unittest
|
import unittest
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
import bind10_config
|
||||||
from isc.testutils.parse_args import OptsError, TestOptParser
|
from isc.testutils.parse_args import OptsError, TestOptParser
|
||||||
|
|
||||||
class MyConfigManager:
|
class MyConfigManager:
|
||||||
@@ -110,6 +111,7 @@ class TestConfigManagerStartup(unittest.TestCase):
|
|||||||
env_var = os.environ["B10_FROM_SOURCE"]
|
env_var = os.environ["B10_FROM_SOURCE"]
|
||||||
|
|
||||||
os.environ["B10_FROM_SOURCE"] = tmp_env_var
|
os.environ["B10_FROM_SOURCE"] = tmp_env_var
|
||||||
|
bind10_config.reload()
|
||||||
b = __import__("b10-cfgmgr", globals(), locals())
|
b = __import__("b10-cfgmgr", globals(), locals())
|
||||||
b.PLUGIN_PATH = [] # It's enough to test plugins in one test
|
b.PLUGIN_PATH = [] # It's enough to test plugins in one test
|
||||||
b.ConfigManager = MyConfigManager
|
b.ConfigManager = MyConfigManager
|
||||||
@@ -117,6 +119,7 @@ class TestConfigManagerStartup(unittest.TestCase):
|
|||||||
|
|
||||||
if env_var != None:
|
if env_var != None:
|
||||||
os.environ["B10_FROM_SOURCE"] = env_var
|
os.environ["B10_FROM_SOURCE"] = env_var
|
||||||
|
bind10_config.reload()
|
||||||
|
|
||||||
sys.modules.pop("b10-cfgmgr")
|
sys.modules.pop("b10-cfgmgr")
|
||||||
|
|
||||||
|
@@ -17,7 +17,37 @@
|
|||||||
# variables to python scripts and libraries.
|
# variables to python scripts and libraries.
|
||||||
import os
|
import os
|
||||||
|
|
||||||
BIND10_MSGQ_SOCKET_FILE = os.path.join("@localstatedir@",
|
def reload():
|
||||||
"@PACKAGE_NAME@",
|
# In a function, for testing purposes
|
||||||
"msgq_socket").replace("${prefix}",
|
global BIND10_MSGQ_SOCKET_FILE
|
||||||
"@prefix@")
|
global DATA_PATH
|
||||||
|
global PLUGIN_PATHS
|
||||||
|
global PREFIX
|
||||||
|
BIND10_MSGQ_SOCKET_FILE = os.path.join("@localstatedir@",
|
||||||
|
"@PACKAGE_NAME@",
|
||||||
|
"msgq_socket").replace("${prefix}",
|
||||||
|
"@prefix@")
|
||||||
|
|
||||||
|
# If B10_FROM_SOURCE is set in the environment, we use data files
|
||||||
|
# from a directory relative to the value of that variable, or, if defined,
|
||||||
|
# relative to the value of B10_FROM_SOURCE_LOCALSTATEDIR. Otherwise
|
||||||
|
# we use the ones installed on the system.
|
||||||
|
# B10_FROM_SOURCE_LOCALSTATEDIR is specifically intended to be used for
|
||||||
|
# tests where we want to use variuos types of configuration within the test
|
||||||
|
# environment. (We may want to make it even more generic so that the path is
|
||||||
|
# passed from the boss process)
|
||||||
|
if "B10_FROM_SOURCE" in os.environ:
|
||||||
|
if "B10_FROM_SOURCE_LOCALSTATEDIR" in os.environ:
|
||||||
|
DATA_PATH = os.environ["B10_FROM_SOURCE_LOCALSTATEDIR"]
|
||||||
|
else:
|
||||||
|
DATA_PATH = os.environ["B10_FROM_SOURCE"]
|
||||||
|
PLUGIN_PATHS = [DATA_PATH + '/src/bin/cfgmgr/plugins']
|
||||||
|
else:
|
||||||
|
PREFIX = "@prefix@"
|
||||||
|
DATA_PATH = "@localstatedir@/@PACKAGE@".replace("${prefix}", PREFIX)
|
||||||
|
PLUGIN_PATHS = ["@prefix@/share/@PACKAGE@/config_plugins"]
|
||||||
|
# For testing the plugins so they can find their own spec files
|
||||||
|
if "B10_TEST_PLUGIN_DIR" in os.environ:
|
||||||
|
PLUGIN_PATHS = os.environ["B10_TEST_PLUGIN_DIR"].split(':')
|
||||||
|
|
||||||
|
reload()
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
SUBDIRS = . tests
|
SUBDIRS = . tests
|
||||||
|
|
||||||
python_PYTHON = __init__.py process.py socketserver_mixin.py
|
python_PYTHON = __init__.py process.py socketserver_mixin.py file.py
|
||||||
|
|
||||||
pythondir = $(pyexecdir)/isc/util
|
pythondir = $(pyexecdir)/isc/util
|
||||||
|
29
src/lib/python/isc/util/file.py
Normal file
29
src/lib/python/isc/util/file.py
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
# Copyright (C) 2011 Internet Systems Consortium.
|
||||||
|
#
|
||||||
|
# Permission to use, copy, modify, and distribute this software for any
|
||||||
|
# purpose with or without fee is hereby granted, provided that the above
|
||||||
|
# copyright notice and this permission notice appear in all copies.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
|
||||||
|
# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
|
||||||
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
|
||||||
|
# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||||
|
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
|
||||||
|
# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
|
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
|
||||||
|
# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
"""Various functions for working with files and directories."""
|
||||||
|
|
||||||
|
from os.path import exists, join
|
||||||
|
|
||||||
|
def path_search(filename, paths):
|
||||||
|
"""
|
||||||
|
Searches list of paths to find filename in one of them. The found one will
|
||||||
|
be returned or IOError will be returned if it isn't found.
|
||||||
|
"""
|
||||||
|
for p in paths:
|
||||||
|
f = join(p, filename)
|
||||||
|
if exists(f):
|
||||||
|
return f
|
||||||
|
raise IOError("'" + filename + "' not found in " + str(paths))
|
@@ -1,5 +1,5 @@
|
|||||||
PYCOVERAGE_RUN = @PYCOVERAGE_RUN@
|
PYCOVERAGE_RUN = @PYCOVERAGE_RUN@
|
||||||
PYTESTS = process_test.py socketserver_mixin_test.py
|
PYTESTS = process_test.py socketserver_mixin_test.py file_test.py
|
||||||
EXTRA_DIST = $(PYTESTS)
|
EXTRA_DIST = $(PYTESTS)
|
||||||
|
|
||||||
# test using command-line arguments, so use check-local target instead of TESTS
|
# test using command-line arguments, so use check-local target instead of TESTS
|
||||||
|
32
src/lib/python/isc/util/tests/file_test.py
Normal file
32
src/lib/python/isc/util/tests/file_test.py
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
# Copyright (C) 2011 Internet Systems Consortium.
|
||||||
|
#
|
||||||
|
# Permission to use, copy, modify, and distribute this software for any
|
||||||
|
# purpose with or without fee is hereby granted, provided that the above
|
||||||
|
# copyright notice and this permission notice appear in all copies.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
|
||||||
|
# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
|
||||||
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
|
||||||
|
# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||||
|
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
|
||||||
|
# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
|
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
|
||||||
|
# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
import isc.util.file
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
class FileTest(unittest.TestCase):
|
||||||
|
def test_search_path_find(self):
|
||||||
|
"""Test it returns the first occurence of the file"""
|
||||||
|
self.assertEqual('./Makefile',
|
||||||
|
isc.util.file.path_search('Makefile',
|
||||||
|
['/no/such/directory/', '.',
|
||||||
|
'../tests/']))
|
||||||
|
|
||||||
|
def test_search_path_notfound(self):
|
||||||
|
"""Test it throws an exception when the file can't be found"""
|
||||||
|
self.assertRaises(IOError, isc.util.file.path_search, 'no file', ['/no/such/directory'])
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
Reference in New Issue
Block a user