BIND 10 trac1704, updated. a90425936c557c3c0fce2c6e82e7d649ccb05a8b [1704] Delete lock files when BIND 10 shuts down
BIND 10 source code commits
bind10-changes at lists.isc.org
Mon May 21 06:01:23 UTC 2012
The branch, trac1704 has been updated
via a90425936c557c3c0fce2c6e82e7d649ccb05a8b (commit)
via ec9aa508ff60e250beddad2b2d6920879c2caecf (commit)
via a206e3181aa79f6ddd2be622b69b884cec289855 (commit)
via 7f43b9842c5ac72d927ef34da7ff577d1b127583 (commit)
via 23d2eee456b5be38e2c40d39eaad23e46d038ee7 (commit)
via 674e8b54ce09f983549a76700dbfde5d88766a1a (commit)
from 4507aa61c9e802dadb0293a51e5f92760f916764 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit a90425936c557c3c0fce2c6e82e7d649ccb05a8b
Author: Mukund Sivaraman <muks at isc.org>
Date: Mon May 21 11:30:18 2012 +0530
[1704] Delete lock files when BIND 10 shuts down
commit ec9aa508ff60e250beddad2b2d6920879c2caecf
Author: Mukund Sivaraman <muks at isc.org>
Date: Mon May 21 11:07:32 2012 +0530
[1704] Set B10_FROM_SOURCE in the Makefile, not in the python test script
commit a206e3181aa79f6ddd2be622b69b884cec289855
Author: Mukund Sivaraman <muks at isc.org>
Date: Mon May 21 10:42:01 2012 +0530
[1704] Log messages even if we're unable to open the lock file
commit 7f43b9842c5ac72d927ef34da7ff577d1b127583
Author: Mukund Sivaraman <muks at isc.org>
Date: Mon May 21 10:40:24 2012 +0530
[1704] Log "Unable to use logger lockfile" only once, not per log message
commit 23d2eee456b5be38e2c40d39eaad23e46d038ee7
Author: Mukund Sivaraman <muks at isc.org>
Date: Mon May 21 10:37:52 2012 +0530
[1704] Use mode 0666 for lock file
commit 674e8b54ce09f983549a76700dbfde5d88766a1a
Author: Mukund Sivaraman <muks at isc.org>
Date: Mon May 21 09:46:07 2012 +0530
[1704] Move locking code to LoggerImpl
-----------------------------------------------------------------------
Summary of changes:
configure.ac | 1 -
src/bin/bind10/bind10_src.py.in | 20 +++++
src/lib/log/logger.cc | 80 +-------------------
src/lib/log/logger.h | 12 ++-
src/lib/log/logger_impl.cc | 70 +++++++++++++++++
src/lib/log/logger_impl.h | 2 +
src/lib/python/isc/log/tests/Makefile.am | 1 +
src/lib/python/isc/log/tests/log_console.py.in | 3 -
.../isc/log/tests/{log_test.py.in => log_test.py} | 3 -
9 files changed, 103 insertions(+), 89 deletions(-)
rename src/lib/python/isc/log/tests/{log_test.py.in => log_test.py} (99%)
-----------------------------------------------------------------------
diff --git a/configure.ac b/configure.ac
index d4eed99..cf70e3f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1174,7 +1174,6 @@ AC_OUTPUT([doc/version.ent
src/lib/python/isc/cc/tests/cc_test
src/lib/python/isc/notify/tests/notify_out_test
src/lib/python/isc/log/tests/log_console.py
- src/lib/python/isc/log/tests/log_test.py
src/lib/python/isc/log_messages/work/__init__.py
src/lib/dns/gen-rdatacode.py
src/lib/python/bind10_config.py
diff --git a/src/bin/bind10/bind10_src.py.in b/src/bin/bind10/bind10_src.py.in
index 37b845d..6b6bd64 100755
--- a/src/bin/bind10/bind10_src.py.in
+++ b/src/bin/bind10/bind10_src.py.in
@@ -64,6 +64,7 @@ import posix
import copy
from bind10_config import LIBEXECPATH
+import bind10_config
import isc.cc
import isc.util.process
import isc.net.parse
@@ -1122,6 +1123,24 @@ def unlink_pid_file(pid_file):
if error.errno is not errno.ENOENT:
raise
+def remove_lock_files():
+ """
+ Remove various lock files which were created by code such as in the
+ logger. This function should be called after BIND 10 shutdown.
+ """
+
+ lockfiles = ["logger_lockfile"]
+
+ lpath = bind10_config.DATA_PATH
+ if "B10_FROM_BUILD" in os.environ:
+ lpath = os.environ["B10_FROM_BUILD"]
+ if "B10_FROM_SOURCE_LOCALSTATEDIR" in os.environ:
+ lpath = os.environ["B10_FROM_SOURCE_LOCALSTATEDIR"]
+
+ for f in lockfiles:
+ os.unlink(lpath + '/' + f)
+
+ return
def main():
global options
@@ -1201,6 +1220,7 @@ def main():
finally:
# Clean up the filesystem
unlink_pid_file(options.pid_file)
+ remove_lock_files()
if boss_of_bind is not None:
boss_of_bind.remove_socket_srv()
sys.exit(boss_of_bind.exitcode)
diff --git a/src/lib/log/logger.cc b/src/lib/log/logger.cc
index cc158eb..d10e979 100644
--- a/src/lib/log/logger.cc
+++ b/src/lib/log/logger.cc
@@ -14,10 +14,6 @@
#include <stdarg.h>
#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
#include <log/logger.h>
#include <log/logger_impl.h>
@@ -33,36 +29,6 @@ using namespace std;
namespace isc {
namespace log {
-// Constructor
-
-Logger::Logger(const char* name) : loggerptr_(NULL) {
- assert(std::strlen(name) < sizeof(name_));
- // Do the copy. Note that the assertion above has checked that the
- // contents of "name" and a trailing null will fit within the space
- // allocated for name_, so we could use strcpy here and be safe.
- // However, a bit of extra paranoia doesn't hurt.
- std::strncpy(name_, name, sizeof(name_));
- assert(name_[sizeof(name_) - 1] == '\0');
-
- lockfile_path_ = LOCKFILE_DIR;
-
- const char* const env = getenv("B10_FROM_SOURCE");
- if (env != NULL) {
- lockfile_path_ = env;
- }
-
- const char* const env2 = getenv("B10_FROM_SOURCE_LOCALSTATEDIR");
- if (env2 != NULL) {
- lockfile_path_ = env2;
- }
-
- lockfile_path_ += "/logger_lockfile";
-
- // Open the lockfile in the constructor so it doesn't do the access
- // checks every time a message is logged.
- lock_fd_ = open(lockfile_path_.c_str(), O_CREAT | O_RDWR, 0600);
-}
-
// Initialize underlying logger, but only if logging has been initialized.
void Logger::initLoggerImpl() {
if (isLoggingInitialized()) {
@@ -76,11 +42,6 @@ void Logger::initLoggerImpl() {
// Destructor.
Logger::~Logger() {
- if (lock_fd_ != -1) {
- close(lock_fd_);
- }
- // The lockfile will continue to exist, as we mustn't delete it.
-
delete loggerptr_;
}
@@ -165,46 +126,7 @@ Logger::isFatalEnabled() {
void
Logger::output(const Severity& severity, const std::string& message) {
- // Use a lock file for mutual exclusion from other processes to
- // avoid log messages getting interspersed
-
- struct flock lock;
- int status;
-
- if (lock_fd_ == -1) {
- getLoggerPtr()->outputRaw(isc::log::WARN,
- "Unable to use logger lockfile: " +
- lockfile_path_);
- } else {
- memset(&lock, 0, sizeof lock);
- lock.l_type = F_WRLCK;
- lock.l_whence = SEEK_SET;
- lock.l_start = 0;
- lock.l_len = 1;
- status = fcntl(lock_fd_, F_SETLKW, &lock);
- if (status != 0) {
- getLoggerPtr()->outputRaw(isc::log::WARN,
- "Unable to lock logger lockfile: " +
- lockfile_path_);
- return;
- }
-
- // Output the message
- getLoggerPtr()->outputRaw(severity, message);
-
- // Release the exclusive lock
- memset(&lock, 0, sizeof lock);
- lock.l_type = F_UNLCK;
- lock.l_whence = SEEK_SET;
- lock.l_start = 0;
- lock.l_len = 1;
- status = fcntl(lock_fd_, F_SETLKW, &lock);
- if (status != 0) {
- getLoggerPtr()->outputRaw(isc::log::WARN,
- "Unable to unlock logger lockfile: " +
- lockfile_path_);
- }
- }
+ getLoggerPtr()->outputRaw(severity, message);
}
Logger::Formatter
diff --git a/src/lib/log/logger.h b/src/lib/log/logger.h
index 1ade2ce..5715bc4 100644
--- a/src/lib/log/logger.h
+++ b/src/lib/log/logger.h
@@ -133,7 +133,15 @@ public:
/// \note Note also that there is no constructor taking a std::string. This
/// minimises the possibility of initializing a static logger with a
/// string, so leading to problems mentioned above.
- Logger(const char* name);
+ Logger(const char* name) : loggerptr_(NULL) {
+ assert(std::strlen(name) < sizeof(name_));
+ // Do the copy. Note that the assertion above has checked that the
+ // contents of "name" and a trailing null will fit within the space
+ // allocated for name_, so we could use strcpy here and be safe.
+ // However, a bit of extra paranoia doesn't hurt.
+ std::strncpy(name_, name, sizeof(name_));
+ assert(name_[sizeof(name_) - 1] == '\0');
+ }
/// \brief Destructor
virtual ~Logger();
@@ -283,8 +291,6 @@ private:
LoggerImpl* loggerptr_; ///< Pointer to underlying logger
char name_[MAX_LOGGER_NAME_SIZE + 1]; ///< Copy of the logger name
- std::string lockfile_path_;
- int lock_fd_;
};
} // namespace log
diff --git a/src/lib/log/logger_impl.cc b/src/lib/log/logger_impl.cc
index 046da13..d36721b 100644
--- a/src/lib/log/logger_impl.cc
+++ b/src/lib/log/logger_impl.cc
@@ -18,6 +18,12 @@
#include <stdarg.h>
#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
#include <boost/lexical_cast.hpp>
#include <boost/static_assert.hpp>
@@ -50,11 +56,39 @@ namespace log {
LoggerImpl::LoggerImpl(const string& name) : name_(expandLoggerName(name)),
logger_(log4cplus::Logger::getInstance(name_))
{
+ lockfile_path_ = LOCKFILE_DIR;
+
+ const char* const env = getenv("B10_FROM_SOURCE");
+ if (env != NULL) {
+ lockfile_path_ = env;
+ }
+
+ const char* const env2 = getenv("B10_FROM_SOURCE_LOCALSTATEDIR");
+ if (env2 != NULL) {
+ lockfile_path_ = env2;
+ }
+
+ lockfile_path_ += "/logger_lockfile";
+
+ // Open the lockfile in the constructor so it doesn't do the access
+ // checks every time a message is logged.
+ mode_t mode = umask(0111);
+ lock_fd_ = open(lockfile_path_.c_str(), O_CREAT | O_RDWR, 0666);
+ umask(mode);
+
+ if (lock_fd_ == -1) {
+ LOG4CPLUS_ERROR(logger_, "Unable to use logger lockfile: " +
+ lockfile_path_);
+ }
}
// Destructor. (Here because of virtual declaration.)
LoggerImpl::~LoggerImpl() {
+ if (lock_fd_ != -1) {
+ close(lock_fd_);
+ }
+ // The lockfile will continue to exist, as we mustn't delete it.
}
// Set the severity for logging.
@@ -104,6 +138,28 @@ LoggerImpl::lookupMessage(const MessageID& ident) {
void
LoggerImpl::outputRaw(const Severity& severity, const string& message) {
+ // Use a lock file for mutual exclusion from other processes to
+ // avoid log messages getting interspersed
+
+ struct flock lock;
+ int status;
+
+ if (lock_fd_ != -1) {
+ // Acquire the exclusive lock
+ memset(&lock, 0, sizeof lock);
+ lock.l_type = F_WRLCK;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = 0;
+ lock.l_len = 1;
+ status = fcntl(lock_fd_, F_SETLKW, &lock);
+ if (status != 0) {
+ LOG4CPLUS_ERROR(logger_, "Unable to lock logger lockfile: " +
+ lockfile_path_);
+ return;
+ }
+ }
+
+ // Log the message
switch (severity) {
case DEBUG:
LOG4CPLUS_DEBUG(logger_, message);
@@ -124,6 +180,20 @@ LoggerImpl::outputRaw(const Severity& severity, const string& message) {
case FATAL:
LOG4CPLUS_FATAL(logger_, message);
}
+
+ if (lock_fd_ != -1) {
+ // Release the exclusive lock
+ memset(&lock, 0, sizeof lock);
+ lock.l_type = F_UNLCK;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = 0;
+ lock.l_len = 1;
+ status = fcntl(lock_fd_, F_SETLKW, &lock);
+ if (status != 0) {
+ LOG4CPLUS_ERROR(logger_, "Unable to unlock logger lockfile: " +
+ lockfile_path_);
+ }
+ }
}
} // namespace log
diff --git a/src/lib/log/logger_impl.h b/src/lib/log/logger_impl.h
index 90bd41a..164bf94 100644
--- a/src/lib/log/logger_impl.h
+++ b/src/lib/log/logger_impl.h
@@ -180,6 +180,8 @@ public:
private:
std::string name_; ///< Full name of this logger
log4cplus::Logger logger_; ///< Underlying log4cplus logger
+ std::string lockfile_path_;
+ int lock_fd_;
};
} // namespace log
diff --git a/src/lib/python/isc/log/tests/Makefile.am b/src/lib/python/isc/log/tests/Makefile.am
index 170eee6..4f96c0b 100644
--- a/src/lib/python/isc/log/tests/Makefile.am
+++ b/src/lib/python/isc/log/tests/Makefile.am
@@ -28,6 +28,7 @@ endif
$(LIBRARY_PATH_PLACEHOLDER) \
PYTHONPATH=$(COMMON_PYTHON_PATH):$(abs_top_builddir)/src/lib/python/isc/log:$(abs_top_builddir)/src/lib/log/python/.libs \
B10_TEST_PLUGIN_DIR=$(abs_top_srcdir)/src/bin/cfgmgr/plugins \
+ B10_FROM_SOURCE=$(abs_top_srcdir) \
$(PYCOVERAGE_RUN) $(abs_srcdir)/$$pytest || exit ; \
done ; \
for pytest in $(PYTESTS_GEN) ; do \
diff --git a/src/lib/python/isc/log/tests/log_console.py.in b/src/lib/python/isc/log/tests/log_console.py.in
index 277f4c7..af05f61 100755
--- a/src/lib/python/isc/log/tests/log_console.py.in
+++ b/src/lib/python/isc/log/tests/log_console.py.in
@@ -1,8 +1,5 @@
#!@PYTHON@
-import os
-os.environ['B10_FROM_SOURCE'] = '@abs_top_srcdir@'
-
import isc.log
# This would come from a dictionary in real life
MSG_ID = isc.log.create_message("MSG_ID", "Message with %2 %1")
diff --git a/src/lib/python/isc/log/tests/log_test.py b/src/lib/python/isc/log/tests/log_test.py
new file mode 100644
index 0000000..1337654
--- /dev/null
+++ b/src/lib/python/isc/log/tests/log_test.py
@@ -0,0 +1,204 @@
+# 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 tests it can be loaded, nothing more yet
+import isc.log
+import unittest
+import json
+import sys
+import bind10_config
+from isc.config.ccsession import path_search
+
+class LogDict(unittest.TestCase):
+ def setUp(self):
+ # We work on a test dictionary now.
+ isc.log.set_test_dictionary(True)
+ def tearDown(self):
+ # Return to the global dictionary
+ isc.log.set_test_dictionary(False)
+
+ def test_load_msgs(self):
+ # Try loading a message and see it's there, but nothing more
+ self.assertEqual(isc.log.create_message("ID", "Text"), "ID")
+ self.assertEqual(isc.log.get_message("ID"), "Text")
+ self.assertEqual(isc.log.get_message("no-ID"), None)
+
+class Manager(unittest.TestCase):
+ def tearDown(self):
+ isc.log.reset()
+
+ def test_init_debug(self):
+ # We try calling it now only, as we don't have any other functions
+ # to check the outcome by it. Once we add the logger class, we may
+ # check more.
+ isc.log.init("root", "DEBUG", 50, None)
+
+ def test_init_defaults(self):
+ # We try calling it now only, as we don't have any other functions
+ # to check the outcome by it. Once we add the logger class, we may
+ # check more.
+ isc.log.init("root")
+
+ def test_init_notfound(self):
+ # This should not throw, because the C++ one doesn't. Should we really
+ # ignore errors like missing file?
+ isc.log.init("root", "INFO", 0, "/no/such/file");
+
+ def test_log_config_update(self):
+ log_spec = json.dumps(isc.config.module_spec_from_file(path_search('logging.spec', bind10_config.PLUGIN_PATHS)).get_full_spec())
+
+ self.assertRaises(TypeError, isc.log.log_config_update)
+ self.assertRaises(TypeError, isc.log.log_config_update, 1)
+ self.assertRaises(TypeError, isc.log.log_config_update, 1, 1)
+ self.assertRaises(TypeError, isc.log.log_config_update, 1, 1, 1)
+
+ self.assertRaises(TypeError, isc.log.log_config_update, 1, log_spec)
+ self.assertRaises(TypeError, isc.log.log_config_update, [], log_spec)
+ self.assertRaises(TypeError, isc.log.log_config_update, "foo", log_spec)
+ self.assertRaises(TypeError, isc.log.log_config_update, "{ '", log_spec)
+
+ # empty should pass
+ isc.log.log_config_update("{}", log_spec)
+
+ # bad spec
+ self.assertRaises(TypeError, isc.log.log_config_update, "{}", json.dumps({"foo": "bar"}))
+
+ # Try a correct one
+ log_conf = json.dumps({"loggers":
+ [{"name": "b10-xfrout", "output_options":
+ [{"output": "/tmp/bind10.log",
+ "destination": "file",
+ "flush": True}]}]})
+ isc.log.log_config_update(log_conf, log_spec)
+
+class Logger(unittest.TestCase):
+ def tearDown(self):
+ isc.log.reset()
+
+ def setUp(self):
+ isc.log.init("root", "DEBUG", 50)
+ self.sevs = ['INFO', 'WARN', 'ERROR', 'FATAL']
+ self.TEST_MSG = isc.log.create_message('TEST_MESSAGE', '%1')
+
+ # Checks defaults of the logger
+ def defaults(self, logger):
+ self.assertEqual(logger.get_effective_severity(), "DEBUG")
+ self.assertEqual(logger.get_effective_debug_level(), 50)
+
+ def test_default_severity(self):
+ logger = isc.log.Logger("child")
+ self.defaults(logger)
+
+ # Try changing the severities little bit
+ def test_severity(self):
+ logger = isc.log.Logger("child")
+ logger.set_severity('DEBUG', 25)
+ self.assertEqual(logger.get_effective_severity(), "DEBUG")
+ self.assertEqual(logger.get_effective_debug_level(), 25)
+ for sev in self.sevs:
+ logger.set_severity(sev)
+ self.assertEqual(logger.get_effective_severity(), sev)
+ self.assertEqual(logger.get_effective_debug_level(), 0)
+ # Return to default
+ logger.set_severity(None)
+ self.defaults(logger)
+
+ def test_enabled(self):
+ logger = isc.log.Logger("child")
+ self.sevs.insert(0, 'DEBUG')
+ methods = {
+ 'DEBUG': logger.is_debug_enabled,
+ 'INFO': logger.is_info_enabled,
+ 'WARN': logger.is_warn_enabled,
+ 'ERROR': logger.is_error_enabled,
+ 'FATAL': logger.is_fatal_enabled
+ }
+ for sev in self.sevs:
+ logger.set_severity(sev)
+ enabled = False
+ for tested in self.sevs:
+ if tested == sev:
+ enabled = True
+ self.assertEqual(methods[tested](), enabled)
+ logger.set_severity('DEBUG', 50)
+ self.assertTrue(logger.is_debug_enabled())
+ self.assertTrue(logger.is_debug_enabled(0))
+ self.assertTrue(logger.is_debug_enabled(50))
+ self.assertFalse(logger.is_debug_enabled(99))
+
+ def test_invalid_params(self):
+ """
+ Tests invalid arguments for logging functions. The output is tested
+ in check_output.sh.
+ """
+ logger = isc.log.Logger("child")
+ methods = [
+ logger.info,
+ logger.warn,
+ logger.error,
+ logger.fatal
+ ]
+ for meth in methods:
+ # Not enough arguments
+ self.assertRaises(TypeError, meth)
+ # Bad type
+ self.assertRaises(TypeError, meth, 1)
+ # Too few arguments
+ self.assertRaises(TypeError, logger.debug, 42)
+ self.assertRaises(TypeError, logger.debug)
+ # Bad type
+ self.assertRaises(TypeError, logger.debug, "42", "hello")
+
+ def test_dbglevel_constants(self):
+ """
+ Just check a constant to make sure it is defined and is the
+ correct value. (The constant chosen has a non-zero value to
+ ensure that the code has both define the constant and set its
+ value correctly.)
+ """
+ logger = isc.log.Logger("child")
+ self.assertEqual(logger.DBGLVL_COMMAND, 10)
+
+ def test_param_reference(self):
+ """
+ Check whether passing a parameter to a logger causes a reference leak.
+ """
+ class LogParam:
+ def __str__(self):
+ return 'LogParam'
+ logger = isc.log.Logger("child")
+ param = LogParam()
+ orig_msgrefcnt = sys.getrefcount(param)
+ orig_idrefcnt = sys.getrefcount(self.TEST_MSG)
+ logger.info(self.TEST_MSG, param);
+ self.assertEqual(sys.getrefcount(self.TEST_MSG), orig_idrefcnt)
+ self.assertEqual(sys.getrefcount(param), orig_msgrefcnt)
+
+ # intentionally pass an invalid type for debug level. It will
+ # result in TypeError. The passed object still shouldn't leak a
+ # reference.
+ self.assertRaises(TypeError, logger.debug, param, self.TEST_MSG, param)
+ self.assertEqual(sys.getrefcount(param), orig_msgrefcnt)
+
+ def test_bad_parameter(self):
+ # a log parameter cannot be converted to a string object.
+ class LogParam:
+ def __str__(self):
+ raise ValueError("LogParam can't be converted to string")
+ logger = isc.log.Logger("child")
+ self.assertRaises(ValueError, logger.info, self.TEST_MSG, LogParam())
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/src/lib/python/isc/log/tests/log_test.py.in b/src/lib/python/isc/log/tests/log_test.py.in
deleted file mode 100644
index 09bdf22..0000000
--- a/src/lib/python/isc/log/tests/log_test.py.in
+++ /dev/null
@@ -1,207 +0,0 @@
-# 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 os
-os.environ['B10_FROM_SOURCE'] = '@abs_top_srcdir@'
-
-# This tests it can be loaded, nothing more yet
-import isc.log
-import unittest
-import json
-import sys
-import bind10_config
-from isc.config.ccsession import path_search
-
-class LogDict(unittest.TestCase):
- def setUp(self):
- # We work on a test dictionary now.
- isc.log.set_test_dictionary(True)
- def tearDown(self):
- # Return to the global dictionary
- isc.log.set_test_dictionary(False)
-
- def test_load_msgs(self):
- # Try loading a message and see it's there, but nothing more
- self.assertEqual(isc.log.create_message("ID", "Text"), "ID")
- self.assertEqual(isc.log.get_message("ID"), "Text")
- self.assertEqual(isc.log.get_message("no-ID"), None)
-
-class Manager(unittest.TestCase):
- def tearDown(self):
- isc.log.reset()
-
- def test_init_debug(self):
- # We try calling it now only, as we don't have any other functions
- # to check the outcome by it. Once we add the logger class, we may
- # check more.
- isc.log.init("root", "DEBUG", 50, None)
-
- def test_init_defaults(self):
- # We try calling it now only, as we don't have any other functions
- # to check the outcome by it. Once we add the logger class, we may
- # check more.
- isc.log.init("root")
-
- def test_init_notfound(self):
- # This should not throw, because the C++ one doesn't. Should we really
- # ignore errors like missing file?
- isc.log.init("root", "INFO", 0, "/no/such/file");
-
- def test_log_config_update(self):
- log_spec = json.dumps(isc.config.module_spec_from_file(path_search('logging.spec', bind10_config.PLUGIN_PATHS)).get_full_spec())
-
- self.assertRaises(TypeError, isc.log.log_config_update)
- self.assertRaises(TypeError, isc.log.log_config_update, 1)
- self.assertRaises(TypeError, isc.log.log_config_update, 1, 1)
- self.assertRaises(TypeError, isc.log.log_config_update, 1, 1, 1)
-
- self.assertRaises(TypeError, isc.log.log_config_update, 1, log_spec)
- self.assertRaises(TypeError, isc.log.log_config_update, [], log_spec)
- self.assertRaises(TypeError, isc.log.log_config_update, "foo", log_spec)
- self.assertRaises(TypeError, isc.log.log_config_update, "{ '", log_spec)
-
- # empty should pass
- isc.log.log_config_update("{}", log_spec)
-
- # bad spec
- self.assertRaises(TypeError, isc.log.log_config_update, "{}", json.dumps({"foo": "bar"}))
-
- # Try a correct one
- log_conf = json.dumps({"loggers":
- [{"name": "b10-xfrout", "output_options":
- [{"output": "/tmp/bind10.log",
- "destination": "file",
- "flush": True}]}]})
- isc.log.log_config_update(log_conf, log_spec)
-
-class Logger(unittest.TestCase):
- def tearDown(self):
- isc.log.reset()
-
- def setUp(self):
- isc.log.init("root", "DEBUG", 50)
- self.sevs = ['INFO', 'WARN', 'ERROR', 'FATAL']
- self.TEST_MSG = isc.log.create_message('TEST_MESSAGE', '%1')
-
- # Checks defaults of the logger
- def defaults(self, logger):
- self.assertEqual(logger.get_effective_severity(), "DEBUG")
- self.assertEqual(logger.get_effective_debug_level(), 50)
-
- def test_default_severity(self):
- logger = isc.log.Logger("child")
- self.defaults(logger)
-
- # Try changing the severities little bit
- def test_severity(self):
- logger = isc.log.Logger("child")
- logger.set_severity('DEBUG', 25)
- self.assertEqual(logger.get_effective_severity(), "DEBUG")
- self.assertEqual(logger.get_effective_debug_level(), 25)
- for sev in self.sevs:
- logger.set_severity(sev)
- self.assertEqual(logger.get_effective_severity(), sev)
- self.assertEqual(logger.get_effective_debug_level(), 0)
- # Return to default
- logger.set_severity(None)
- self.defaults(logger)
-
- def test_enabled(self):
- logger = isc.log.Logger("child")
- self.sevs.insert(0, 'DEBUG')
- methods = {
- 'DEBUG': logger.is_debug_enabled,
- 'INFO': logger.is_info_enabled,
- 'WARN': logger.is_warn_enabled,
- 'ERROR': logger.is_error_enabled,
- 'FATAL': logger.is_fatal_enabled
- }
- for sev in self.sevs:
- logger.set_severity(sev)
- enabled = False
- for tested in self.sevs:
- if tested == sev:
- enabled = True
- self.assertEqual(methods[tested](), enabled)
- logger.set_severity('DEBUG', 50)
- self.assertTrue(logger.is_debug_enabled())
- self.assertTrue(logger.is_debug_enabled(0))
- self.assertTrue(logger.is_debug_enabled(50))
- self.assertFalse(logger.is_debug_enabled(99))
-
- def test_invalid_params(self):
- """
- Tests invalid arguments for logging functions. The output is tested
- in check_output.sh.
- """
- logger = isc.log.Logger("child")
- methods = [
- logger.info,
- logger.warn,
- logger.error,
- logger.fatal
- ]
- for meth in methods:
- # Not enough arguments
- self.assertRaises(TypeError, meth)
- # Bad type
- self.assertRaises(TypeError, meth, 1)
- # Too few arguments
- self.assertRaises(TypeError, logger.debug, 42)
- self.assertRaises(TypeError, logger.debug)
- # Bad type
- self.assertRaises(TypeError, logger.debug, "42", "hello")
-
- def test_dbglevel_constants(self):
- """
- Just check a constant to make sure it is defined and is the
- correct value. (The constant chosen has a non-zero value to
- ensure that the code has both define the constant and set its
- value correctly.)
- """
- logger = isc.log.Logger("child")
- self.assertEqual(logger.DBGLVL_COMMAND, 10)
-
- def test_param_reference(self):
- """
- Check whether passing a parameter to a logger causes a reference leak.
- """
- class LogParam:
- def __str__(self):
- return 'LogParam'
- logger = isc.log.Logger("child")
- param = LogParam()
- orig_msgrefcnt = sys.getrefcount(param)
- orig_idrefcnt = sys.getrefcount(self.TEST_MSG)
- logger.info(self.TEST_MSG, param);
- self.assertEqual(sys.getrefcount(self.TEST_MSG), orig_idrefcnt)
- self.assertEqual(sys.getrefcount(param), orig_msgrefcnt)
-
- # intentionally pass an invalid type for debug level. It will
- # result in TypeError. The passed object still shouldn't leak a
- # reference.
- self.assertRaises(TypeError, logger.debug, param, self.TEST_MSG, param)
- self.assertEqual(sys.getrefcount(param), orig_msgrefcnt)
-
- def test_bad_parameter(self):
- # a log parameter cannot be converted to a string object.
- class LogParam:
- def __str__(self):
- raise ValueError("LogParam can't be converted to string")
- logger = isc.log.Logger("child")
- self.assertRaises(ValueError, logger.info, self.TEST_MSG, LogParam())
-
-if __name__ == '__main__':
- unittest.main()
More information about the bind10-changes
mailing list