summaryrefslogtreecommitdiffstats
path: root/src/lib/log/tests/logger_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/log/tests/logger_unittest.cc')
-rw-r--r--src/lib/log/tests/logger_unittest.cc508
1 files changed, 508 insertions, 0 deletions
diff --git a/src/lib/log/tests/logger_unittest.cc b/src/lib/log/tests/logger_unittest.cc
new file mode 100644
index 0000000..cc2fb95
--- /dev/null
+++ b/src/lib/log/tests/logger_unittest.cc
@@ -0,0 +1,508 @@
+// Copyright (C) 2011-2022 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <gtest/gtest.h>
+
+#include <util/unittests/resource.h>
+#include <util/unittests/check_valgrind.h>
+
+#include <log/logger.h>
+#include <log/logger_manager.h>
+#include <log/logger_name.h>
+#include <log/logger_support.h>
+#include <log/log_messages.h>
+#include <log/interprocess/interprocess_sync_file.h>
+#include <log/output_option.h>
+#include <log/tests/log_test_messages.h>
+
+#include <iostream>
+#include <string>
+
+using namespace isc;
+using namespace isc::log;
+using namespace std;
+
+/// \brief Logger Test
+///
+/// As the logger is only a shell around the implementation, this tests also
+/// checks the logger implementation class as well.
+
+class LoggerTest : public ::testing::Test {
+public:
+ LoggerTest() {
+ // Initialize logging before each test, even if it is already done in main().
+ isc::log::initLogger();
+ }
+ ~LoggerTest() {
+ LoggerManager::reset();
+ }
+};
+
+// Check version
+
+TEST_F(LoggerTest, Version) {
+ EXPECT_NO_THROW(Logger::getVersion());
+}
+
+// Checks that the logger is named correctly.
+
+TEST_F(LoggerTest, Name) {
+
+ // Create a logger
+ Logger logger("alpha");
+
+ // ... and check the name
+ EXPECT_EQ(getRootLoggerName() + string(".alpha"), logger.getName());
+}
+
+// This test attempts to get two instances of a logger with the same name
+// and checks that they are in fact the same logger.
+
+TEST_F(LoggerTest, GetLogger) {
+
+ const char* name1 = "alpha";
+ const char* name2 = "beta";
+
+ // Instantiate two loggers that should be the same
+ Logger logger1(name1);
+ Logger logger2(name1);
+ // And check they equal
+ EXPECT_TRUE(logger1 == logger2);
+
+ // Instantiate another logger with another name and check that it
+ // is different to the previously instantiated ones.
+ Logger logger3(name2);
+ EXPECT_FALSE(logger1 == logger3);
+}
+
+// Check that the logger levels are get set properly.
+
+TEST_F(LoggerTest, Severity) {
+
+ // Create a logger
+ Logger logger("alpha");
+
+ // Now check the levels
+ logger.setSeverity(isc::log::NONE);
+ EXPECT_EQ(isc::log::NONE, logger.getSeverity());
+
+ logger.setSeverity(isc::log::FATAL);
+ EXPECT_EQ(isc::log::FATAL, logger.getSeverity());
+
+ logger.setSeverity(isc::log::ERROR);
+ EXPECT_EQ(isc::log::ERROR, logger.getSeverity());
+
+ logger.setSeverity(isc::log::WARN);
+ EXPECT_EQ(isc::log::WARN, logger.getSeverity());
+
+ logger.setSeverity(isc::log::INFO);
+ EXPECT_EQ(isc::log::INFO, logger.getSeverity());
+
+ logger.setSeverity(isc::log::DEBUG);
+ EXPECT_EQ(isc::log::DEBUG, logger.getSeverity());
+
+ logger.setSeverity(isc::log::DEFAULT);
+ EXPECT_EQ(isc::log::DEFAULT, logger.getSeverity());
+}
+
+// Check that the debug level is set correctly.
+
+TEST_F(LoggerTest, DebugLevels) {
+
+ // Create a logger
+ Logger logger("alpha");
+
+ // Debug level should be 0 if not at debug severity
+ logger.setSeverity(isc::log::NONE, 20);
+ EXPECT_EQ(0, logger.getDebugLevel());
+
+ logger.setSeverity(isc::log::INFO, 42);
+ EXPECT_EQ(0, logger.getDebugLevel());
+
+ // Should be the value set if the severity is set to DEBUG though.
+ logger.setSeverity(isc::log::DEBUG, 32);
+ EXPECT_EQ(32, logger.getDebugLevel());
+
+ logger.setSeverity(isc::log::DEBUG, 97);
+ EXPECT_EQ(97, logger.getDebugLevel());
+
+ // Try the limits
+ logger.setSeverity(isc::log::DEBUG, -1);
+ EXPECT_EQ(0, logger.getDebugLevel());
+
+ logger.setSeverity(isc::log::DEBUG, 0);
+ EXPECT_EQ(0, logger.getDebugLevel());
+
+ logger.setSeverity(isc::log::DEBUG, 1);
+ EXPECT_EQ(1, logger.getDebugLevel());
+
+ logger.setSeverity(isc::log::DEBUG, 98);
+ EXPECT_EQ(98, logger.getDebugLevel());
+
+ logger.setSeverity(isc::log::DEBUG, 99);
+ EXPECT_EQ(99, logger.getDebugLevel());
+
+ logger.setSeverity(isc::log::DEBUG, 100);
+ EXPECT_EQ(99, logger.getDebugLevel());
+}
+
+// Check that changing the parent and child severity does not affect the
+// other.
+
+TEST_F(LoggerTest, SeverityInheritance) {
+
+ // Create two loggers. We cheat here as we know that the underlying
+ // implementation will set a parent-child relationship if the loggers
+ // are named <parent> and <parent>.<child>.
+ Logger parent("alpha");
+ Logger child("alpha.beta");
+
+ // By default, newly created loggers should have a level of DEFAULT
+ // (i.e. default to parent)
+ EXPECT_EQ(isc::log::DEFAULT, parent.getSeverity());
+ EXPECT_EQ(isc::log::DEFAULT, child.getSeverity());
+
+ // Set the severity of the parent to debug and check what is
+ // reported by the child.
+ parent.setSeverity(isc::log::DEBUG, 42);
+ EXPECT_EQ(42, parent.getDebugLevel());
+ EXPECT_EQ(0, child.getDebugLevel());
+ EXPECT_EQ(42, child.getEffectiveDebugLevel());
+
+ // Setting the child to DEBUG severity should set its own
+ // debug level.
+ child.setSeverity(isc::log::DEBUG, 53);
+ EXPECT_EQ(53, child.getDebugLevel());
+ EXPECT_EQ(53, child.getEffectiveDebugLevel());
+
+ // If the child severity is set to something other than DEBUG,
+ // the debug level should be reported as 0.
+ child.setSeverity(isc::log::ERROR);
+ EXPECT_EQ(0, child.getDebugLevel());
+ EXPECT_EQ(0, child.getEffectiveDebugLevel());
+}
+
+// Check that changing the parent and child debug level does not affect
+// the other.
+
+TEST_F(LoggerTest, DebugLevelInheritance) {
+
+ // Create two loggers. We cheat here as we know that the underlying
+ // implementation will set a parent-child relationship if the loggers
+ // are named <parent> and <parent>.<child>.
+ Logger parent("alpha");
+ Logger child("alpha.beta");
+
+ // By default, newly created loggers should have a level of DEFAULT
+ // (i.e. default to parent)
+ EXPECT_EQ(isc::log::DEFAULT, parent.getSeverity());
+ EXPECT_EQ(isc::log::DEFAULT, child.getSeverity());
+
+ // Set the severity of the child to something other than the default -
+ // check it changes and that of the parent does not.
+ child.setSeverity(isc::log::INFO);
+ EXPECT_EQ(isc::log::DEFAULT, parent.getSeverity());
+ EXPECT_EQ(isc::log::INFO, child.getSeverity());
+
+ // Reset the child severity and set that of the parent
+ child.setSeverity(isc::log::DEFAULT);
+ EXPECT_EQ(isc::log::DEFAULT, parent.getSeverity());
+ EXPECT_EQ(isc::log::DEFAULT, child.getSeverity());
+ parent.setSeverity(isc::log::WARN);
+ EXPECT_EQ(isc::log::WARN, parent.getSeverity());
+ EXPECT_EQ(isc::log::DEFAULT, child.getSeverity());
+}
+
+// Check that severity is inherited.
+
+TEST_F(LoggerTest, EffectiveSeverityInheritance) {
+
+ // Create two loggers. We cheat here as we know that the underlying
+ // implementation will set a parent-child relationship if the loggers
+ // are named <parent> and <parent>.<child>.
+ Logger parent("test6");
+ Logger child("test6.beta");
+
+ // By default, newly created loggers should have a level of DEFAULT
+ // (i.e. default to parent) and the root should have a default severity
+ // of INFO. However, the latter is only enforced when created by the
+ // RootLogger class, so explicitly set it for the parent for now.
+ parent.setSeverity(isc::log::INFO);
+ EXPECT_EQ(isc::log::INFO, parent.getEffectiveSeverity());
+
+ EXPECT_EQ(isc::log::DEFAULT, child.getSeverity());
+ EXPECT_EQ(isc::log::INFO, child.getEffectiveSeverity());
+
+ // Set the severity of the child to something other than the default -
+ // check it changes and that of the parent does not.
+ child.setSeverity(isc::log::FATAL);
+ EXPECT_EQ(isc::log::INFO, parent.getEffectiveSeverity());
+ EXPECT_EQ(isc::log::FATAL, child.getEffectiveSeverity());
+
+ // Reset the child severity and check again.
+ child.setSeverity(isc::log::DEFAULT);
+ EXPECT_EQ(isc::log::INFO, parent.getEffectiveSeverity());
+ EXPECT_EQ(isc::log::INFO, child.getEffectiveSeverity());
+
+ // Change the parent's severity and check it is reflects in the child.
+ parent.setSeverity(isc::log::WARN);
+ EXPECT_EQ(isc::log::WARN, parent.getEffectiveSeverity());
+ EXPECT_EQ(isc::log::WARN, child.getEffectiveSeverity());
+}
+
+// Test the isXxxxEnabled methods.
+
+TEST_F(LoggerTest, IsXxxEnabled) {
+
+ Logger logger("test7");
+
+ logger.setSeverity(isc::log::INFO);
+ EXPECT_FALSE(logger.isDebugEnabled());
+ EXPECT_TRUE(logger.isInfoEnabled());
+ EXPECT_TRUE(logger.isWarnEnabled());
+ EXPECT_TRUE(logger.isErrorEnabled());
+ EXPECT_TRUE(logger.isFatalEnabled());
+
+ logger.setSeverity(isc::log::WARN);
+ EXPECT_FALSE(logger.isDebugEnabled());
+ EXPECT_FALSE(logger.isInfoEnabled());
+ EXPECT_TRUE(logger.isWarnEnabled());
+ EXPECT_TRUE(logger.isErrorEnabled());
+ EXPECT_TRUE(logger.isFatalEnabled());
+
+ logger.setSeverity(isc::log::ERROR);
+ EXPECT_FALSE(logger.isDebugEnabled());
+ EXPECT_FALSE(logger.isInfoEnabled());
+ EXPECT_FALSE(logger.isWarnEnabled());
+ EXPECT_TRUE(logger.isErrorEnabled());
+ EXPECT_TRUE(logger.isFatalEnabled());
+
+ logger.setSeverity(isc::log::FATAL);
+ EXPECT_FALSE(logger.isDebugEnabled());
+ EXPECT_FALSE(logger.isInfoEnabled());
+ EXPECT_FALSE(logger.isWarnEnabled());
+ EXPECT_FALSE(logger.isErrorEnabled());
+ EXPECT_TRUE(logger.isFatalEnabled());
+
+ // Check various debug levels
+
+ logger.setSeverity(isc::log::DEBUG);
+ EXPECT_TRUE(logger.isDebugEnabled());
+ EXPECT_TRUE(logger.isInfoEnabled());
+ EXPECT_TRUE(logger.isWarnEnabled());
+ EXPECT_TRUE(logger.isErrorEnabled());
+ EXPECT_TRUE(logger.isFatalEnabled());
+
+ logger.setSeverity(isc::log::DEBUG, 45);
+ EXPECT_TRUE(logger.isDebugEnabled());
+ EXPECT_TRUE(logger.isInfoEnabled());
+ EXPECT_TRUE(logger.isWarnEnabled());
+ EXPECT_TRUE(logger.isErrorEnabled());
+ EXPECT_TRUE(logger.isFatalEnabled());
+
+ // Create a child logger with no severity set, and check that it reflects
+ // the severity of the parent logger.
+
+ Logger child("test7.child");
+ logger.setSeverity(isc::log::FATAL);
+ EXPECT_FALSE(child.isDebugEnabled());
+ EXPECT_FALSE(child.isInfoEnabled());
+ EXPECT_FALSE(child.isWarnEnabled());
+ EXPECT_FALSE(child.isErrorEnabled());
+ EXPECT_TRUE(child.isFatalEnabled());
+
+ logger.setSeverity(isc::log::INFO);
+ EXPECT_FALSE(child.isDebugEnabled());
+ EXPECT_TRUE(child.isInfoEnabled());
+ EXPECT_TRUE(child.isWarnEnabled());
+ EXPECT_TRUE(child.isErrorEnabled());
+ EXPECT_TRUE(child.isFatalEnabled());
+}
+
+// Within the Debug level there are 100 debug levels. Test that we know
+// when to issue a debug message.
+
+TEST_F(LoggerTest, IsDebugEnabledLevel) {
+
+ Logger logger("test8");
+
+ int MID_LEVEL = (MIN_DEBUG_LEVEL + MAX_DEBUG_LEVEL) / 2;
+
+ logger.setSeverity(isc::log::DEBUG);
+ EXPECT_TRUE(logger.isDebugEnabled(MIN_DEBUG_LEVEL));
+ EXPECT_FALSE(logger.isDebugEnabled(MID_LEVEL));
+ EXPECT_FALSE(logger.isDebugEnabled(MAX_DEBUG_LEVEL));
+
+ logger.setSeverity(isc::log::DEBUG, MIN_DEBUG_LEVEL);
+ EXPECT_TRUE(logger.isDebugEnabled(MIN_DEBUG_LEVEL));
+ EXPECT_FALSE(logger.isDebugEnabled(MID_LEVEL));
+ EXPECT_FALSE(logger.isDebugEnabled(MAX_DEBUG_LEVEL));
+
+ logger.setSeverity(isc::log::DEBUG, MID_LEVEL);
+ EXPECT_TRUE(logger.isDebugEnabled(MIN_DEBUG_LEVEL));
+ EXPECT_TRUE(logger.isDebugEnabled(MID_LEVEL - 1));
+ EXPECT_TRUE(logger.isDebugEnabled(MID_LEVEL));
+ EXPECT_FALSE(logger.isDebugEnabled(MID_LEVEL + 1));
+ EXPECT_FALSE(logger.isDebugEnabled(MAX_DEBUG_LEVEL));
+
+ logger.setSeverity(isc::log::DEBUG, MAX_DEBUG_LEVEL);
+ EXPECT_TRUE(logger.isDebugEnabled(MIN_DEBUG_LEVEL));
+ EXPECT_TRUE(logger.isDebugEnabled(MID_LEVEL));
+ EXPECT_TRUE(logger.isDebugEnabled(MAX_DEBUG_LEVEL));
+}
+
+// Check that loggers with invalid names give an error.
+
+TEST_F(LoggerTest, LoggerNameLength) {
+ // Null name
+ EXPECT_THROW(Logger(NULL), LoggerNameNull);
+
+ // Declare space for the logger name. The length of names checked
+ // will range from 0 through MAX_LOGGER_NAME_SIZE + 1: to allow for
+ // the trailing null, at least one more byte than the longest name size
+ // must be reserved.
+ char name[Logger::MAX_LOGGER_NAME_SIZE + 2];
+
+ // Zero-length name should throw an exception
+ name[0] = '\0';
+ EXPECT_THROW({
+ Logger dummy(name);
+ }, LoggerNameError);
+
+ // Work through all valid names.
+ for (size_t i = 0; i < Logger::MAX_LOGGER_NAME_SIZE; ++i) {
+
+ // Append a character to the name and check that a logger with that
+ // name can be created without throwing an exception.
+ name[i] = 'X';
+ name[i + 1] = '\0';
+ EXPECT_NO_THROW({
+ Logger dummy(name);
+ }) << "Size of logger name is " << (i + 1);
+ }
+
+ // ... and check that an overly long name throws an exception.
+ name[Logger::MAX_LOGGER_NAME_SIZE] = 'X';
+ name[Logger::MAX_LOGGER_NAME_SIZE + 1] = '\0';
+ EXPECT_THROW({
+ Logger dummy(name);
+ }, LoggerNameError);
+
+}
+
+TEST_F(LoggerTest, setInterprocessSync) {
+ // Create a logger
+ Logger logger("alpha");
+
+ EXPECT_THROW(logger.setInterprocessSync(NULL), BadInterprocessSync);
+}
+
+class MockSync : public isc::log::interprocess::InterprocessSync {
+public:
+ /// \brief Constructor
+ MockSync(const std::string& component_name) :
+ InterprocessSync(component_name), was_locked_(false),
+ was_unlocked_(false)
+ {}
+
+ bool wasLocked() const {
+ return (was_locked_);
+ }
+
+ bool wasUnlocked() const {
+ return (was_unlocked_);
+ }
+
+protected:
+ bool lock() {
+ was_locked_ = true;
+ return (true);
+ }
+
+ bool tryLock() {
+ return (true);
+ }
+
+ bool unlock() {
+ was_unlocked_ = true;
+ return (true);
+ }
+
+private:
+ bool was_locked_;
+ bool was_unlocked_;
+};
+
+// Checks that the logger logs exclusively and other Kea components
+// are locked out.
+
+TEST_F(LoggerTest, Lock) {
+ // Create a logger
+ Logger logger("alpha");
+
+ // Setup our own mock sync object so that we can intercept the lock
+ // call and check if a lock has been taken.
+ MockSync* sync = new MockSync("logger");
+ logger.setInterprocessSync(sync);
+
+ // Log a message and put things into play.
+ logger.setSeverity(isc::log::INFO, 100);
+ logger.info(LOG_LOCK_TEST_MESSAGE);
+
+ EXPECT_TRUE(sync->wasLocked());
+ EXPECT_TRUE(sync->wasUnlocked());
+}
+
+// Checks that hasAppender() reports
+TEST_F(LoggerTest, HasAppender) {
+ // Create a logger.
+ Logger logger("logger");
+
+ // By default, loggers have a file appender to /dev/null.
+ EXPECT_FALSE(logger.hasAppender(OutputOption::DEST_CONSOLE));
+ EXPECT_TRUE(logger.hasAppender(OutputOption::DEST_FILE));
+ EXPECT_FALSE(logger.hasAppender(OutputOption::DEST_SYSLOG));
+
+ // -- Create some specifications. --
+
+ OutputOption console;
+ console.destination = OutputOption::DEST_CONSOLE;
+ LoggerSpecification spec_console("logger");
+ spec_console.addOutputOption(console);
+
+ OutputOption file;
+ file.destination = OutputOption::DEST_FILE;
+ file.filename = "/dev/null";
+ LoggerSpecification spec_file("logger");
+ spec_file.addOutputOption(file);
+
+ OutputOption syslog;
+ syslog.destination = OutputOption::DEST_SYSLOG;
+ LoggerSpecification spec_syslog("logger");
+ spec_syslog.addOutputOption(syslog);
+
+ LoggerManager manager;
+
+ // Check console.
+ manager.process(spec_console);
+ EXPECT_TRUE(logger.hasAppender(OutputOption::DEST_CONSOLE));
+ EXPECT_FALSE(logger.hasAppender(OutputOption::DEST_FILE));
+ EXPECT_FALSE(logger.hasAppender(OutputOption::DEST_SYSLOG));
+
+ // Check file.
+ manager.process(spec_file);
+ EXPECT_FALSE(logger.hasAppender(OutputOption::DEST_CONSOLE));
+ EXPECT_TRUE(logger.hasAppender(OutputOption::DEST_FILE));
+ EXPECT_FALSE(logger.hasAppender(OutputOption::DEST_SYSLOG));
+
+ // Check syslog.
+ manager.process(spec_syslog);
+ EXPECT_FALSE(logger.hasAppender(OutputOption::DEST_CONSOLE));
+ EXPECT_FALSE(logger.hasAppender(OutputOption::DEST_FILE));
+ EXPECT_TRUE(logger.hasAppender(OutputOption::DEST_SYSLOG));
+}