[cpp-sp] branch main updated: Logging API adjustments and tests for config.

Scott Cantor cantor.2 at osu.edu
Tue Nov 26 18:33:43 UTC 2024


This is an automated email from the git hooks/post-receive script.

scantor pushed a commit to branch main
in repository cpp-sp.

View the commit online:
http://git.shibboleth.net/view/?p=cpp-sp.git;a=commit;h=2bf4341d79c7030931e2c60c8aa5490cefc7baf1

The following commit(s) were added to refs/heads/main by this push:
     new 2bf4341d Logging API adjustments and tests for config.
2bf4341d is described below

commit 2bf4341d79c7030931e2c60c8aa5490cefc7baf1
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Tue Nov 26 13:33:32 2024 -0500

    Logging API adjustments and tests for config.
---
 shibsp/Makefile.am                             |   1 +
 shibsp/SPConfig.cpp                            |  18 ----
 shibsp/base.h                                  |  14 +--
 shibsp/impl/AgentConfig.cpp                    | 138 ++++++++++++-------------
 shibsp/logging/LoggingService.h                |   4 +-
 shibsp/logging/impl/AbstractLoggingService.cpp |  18 +++-
 shibsp/logging/impl/AbstractLoggingService.h   |   6 +-
 shibsp/logging/impl/Category.cpp               |   6 +-
 shibsp/logging/impl/ConsoleLoggingService.cpp  |  16 ++-
 shibsp/logging/impl/LoggingServiceSPI.h        |  16 +--
 shibsp/logging/impl/Priority.cpp               |  12 ++-
 shibsp/util/PathResolver.cpp                   |   2 +-
 tests/AgentConfigTests.cpp                     |  87 ++++++++++++++++
 tests/Makefile.am                              |   1 +
 tests/data/dupproperty_shibboleth.ini          |   3 +
 tests/data/dupsection_shibboleth.ini           |   5 +
 tests/data/noequals_shibboleth.ini             |   2 +
 tests/data/nokey_shibboleth.ini                |   2 +
 tests/data/shibboleth.ini                      |   6 ++
 tests/data/unmatched_shibboleth.ini            |   1 +
 20 files changed, 222 insertions(+), 136 deletions(-)

diff --git a/shibsp/Makefile.am b/shibsp/Makefile.am
index 94057762..53d2fac2 100644
--- a/shibsp/Makefile.am
+++ b/shibsp/Makefile.am
@@ -111,6 +111,7 @@ libshibsp_la_SOURCES = \
 	handler/impl/SessionHandler.cpp \
 	handler/impl/SessionInitiator.cpp \
 	handler/impl/StatusHandler.cpp \
+	impl/AgentConfig.cpp \
 	impl/XMLAccessControl.cpp \
 	impl/ChainingAccessControl.cpp \
 	impl/StoredSession.cpp \
diff --git a/shibsp/SPConfig.cpp b/shibsp/SPConfig.cpp
index beb77e7e..7346d49a 100644
--- a/shibsp/SPConfig.cpp
+++ b/shibsp/SPConfig.cpp
@@ -139,24 +139,6 @@ bool SPConfig::init(const char* catalog_path, const char* inst_prefix)
         ++inst_prefix;
     }
 
-    const char* logconf = getenv("SHIBSP_LOGGING");
-    if (!logconf || !*logconf) {
-        if (isEnabled(SPConfig::Logging) && isEnabled(SPConfig::OutOfProcess) && !isEnabled(SPConfig::InProcess))
-            logconf = SHIBSP_OUTOFPROC_LOGGING;
-        else if (isEnabled(SPConfig::Logging) && isEnabled(SPConfig::InProcess) && !isEnabled(SPConfig::OutOfProcess))
-            logconf = SHIBSP_INPROC_LOGGING;
-        else
-            logconf = SHIBSP_LOGGING;
-    }
-    PathResolver localpr;
-    localpr.setDefaultPrefix(inst_prefix2.c_str());
-    inst_prefix = getenv("SHIBSP_CFGDIR");
-    if (!inst_prefix || !*inst_prefix)
-        inst_prefix = SHIBSP_CFGDIR;
-    localpr.setCfgDir(inst_prefix);
-    std::string lc(logconf);
-    XMLToolingConfig::getConfig().log_config(localpr.resolve(lc, PathResolver::XMLTOOLING_CFG_FILE, PACKAGE_NAME).c_str());
-
     Category& log=Category::getInstance(SHIBSP_LOGCAT ".Config");
     log.debug("%s library initialization started", PACKAGE_STRING);
 
diff --git a/shibsp/base.h b/shibsp/base.h
index 0b2c5215..560a172b 100644
--- a/shibsp/base.h
+++ b/shibsp/base.h
@@ -76,18 +76,6 @@
   #define SHIBSP_EXCEPTIONAPI(api)
 #endif
 
-/**
- * Controls default logging level of console tools and other situations
- * where fully-configured logging isn't used.
- */
-#define SHIBSP_LOGGING  "console.logger"
-
-/** Default name of SP in-process logging config file. */
-#define SHIBSP_INPROC_LOGGING "native.logger"
-
-/** Default name of SP out-of-process logging config file. */
-#define SHIBSP_OUTOFPROC_LOGGING "shibd.logger"
-
 /** Logging category for Service Provider functions. */
 #define SHIBSP_LOGCAT "Shibboleth"
 
@@ -95,7 +83,7 @@
 #define SHIBSP_TX_LOGCAT "Shibboleth-TRANSACTION"
 
 /** Default name of configuration file. */
-# define SHIBSP_CONFIG  "shibboleth2.xml"
+# define SHIBSP_CONFIG  "shibboleth.ini"
 
 #ifdef WIN32
 
diff --git a/shibsp/impl/AgentConfig.cpp b/shibsp/impl/AgentConfig.cpp
index 70885df9..2ac591d2 100644
--- a/shibsp/impl/AgentConfig.cpp
+++ b/shibsp/impl/AgentConfig.cpp
@@ -27,8 +27,10 @@
 #include "util/PathResolver.h"
 
 #include <ctime>
+#include <stdexcept>
 #include <thread>
 #include <boost/property_tree/ptree.hpp>
+#include <boost/property_tree/ini_parser.hpp>
 
 using namespace shibsp;
 using namespace xmltooling;
@@ -56,20 +58,22 @@ namespace shibsp {
         bool _init(const char* inst_prefix=nullptr, const char* config_file=nullptr, bool rethrow=false);
         void _term();
 
+        bool initLogging();
+
         unsigned int m_initCount;
         mutex m_lock;
+        ptree m_config;
         PathResolver m_pathResolver;
-        unique_ptr<Agent> m_agent;
         unique_ptr<LoggingService> m_logging;
-        unique_ptr<ptree> m_config;
+        //unique_ptr<Agent> m_agent;
     };
     
-    AgentInternalConfig g_config;
+    static AgentInternalConfig g_agentConfig;
 }
 
 AgentConfig& AgentConfig::getConfig()
 {
-    return g_config;
+    return g_agentConfig;
 }
 
 AgentConfig::AgentConfig()
@@ -95,9 +99,9 @@ LoggingService& AgentInternalConfig::getLoggingService() const
 
 Agent& AgentInternalConfig::getAgent() const
 {
-    if (m_agent) {
-        return *m_agent;
-    }
+//    if (m_agent) {
+//        return *m_agent;
+//    }
     throw logic_error("Agent not initialized.");
 }
 
@@ -132,12 +136,13 @@ bool AgentInternalConfig::_init(const char* inst_prefix, const char* config_file
         inst_prefix = getenv("SHIBSP_PREFIX");
     if (!inst_prefix)
         inst_prefix = SHIBSP_PREFIX;
-    std::string inst_prefix2;
+    string inst_prefix2;
     while (*inst_prefix) {
         inst_prefix2.push_back((*inst_prefix=='\\') ? ('/') : (*inst_prefix));
         ++inst_prefix;
     }
 
+    // Set up PathResolver component.
     m_pathResolver.setDefaultPackageName(PACKAGE_NAME);
     m_pathResolver.setDefaultPrefix(inst_prefix2.c_str());
     m_pathResolver.setCfgDir(inst_prefix);
@@ -158,13 +163,43 @@ bool AgentInternalConfig::_init(const char* inst_prefix, const char* config_file
         inst_prefix = SHIBSP_CACHEDIR;
     m_pathResolver.setCacheDir(inst_prefix);
 
+    // Resolve primary config path and parse as INI file.
+    if (!config_file)
+        config_file = getenv("SHIBSP_CONFIG");
+    if (!config_file) {
+        config_file = SHIBSP_CONFIG;
+    }
+    string config_file_resolved(config_file);
+    m_pathResolver.resolve(config_file_resolved, PathResolver::SHIBSP_CFG_FILE);
+
+    try {
+        ini_parser::read_ini(config_file_resolved, m_config);
+    } catch (const ini_parser_error& e) {
+        if (rethrow) {
+            throw;
+        }
+        return false;
+    }
+
     registerLoggingServices();
 
-/*
+    try {
+        if (!initLogging()) {
+            return false;
+        }
+    } catch (const std::exception& e) {
+        if (rethrow) {
+            throw;
+        }
+        return false;
+    }
+
+    // At this point, logging is active/usable.
 
-    Category& log=Category::getInstance(SHIBSP_LOGCAT ".Config");
-    log.debug("%s library initialization started", PACKAGE_STRING);
+    Category& log=Category::getInstance(SHIBSP_LOGCAT ".AgentConfig");
+    log.info("%s agent initialization underway", PACKAGE_STRING);
 
+    /*
     XMLToolingConfig::getConfig().user_agent = string(PACKAGE_NAME) + '/' + PACKAGE_VERSION;
 
     registerAttributeFactories();
@@ -197,63 +232,22 @@ bool AgentInternalConfig::_init(const char* inst_prefix, const char* config_file
     return true;
 }
 
-    /*
-bool SPConfig::instantiate(const char* config, bool rethrow)
+bool AgentInternalConfig::initLogging()
 {
-    if (!config)
-        config = getenv("SHIBSP_CONFIG");
-    if (!config) {
-        config = SHIBSP_CONFIG;
-    }
-    try {
-        xercesc::DOMDocument* dummydoc;
-        if (*config == '"' || *config == '\'') {
-            throw ConfigurationException("The value of SHIBSP_CONFIG started with a quote.");
-        }
-        else if (*config != '<') {
-            // Mock up some XML.
-            string resolved(config);
-            stringstream snippet;
-            snippet
-                << "<Dummy path='"
-                << XMLToolingConfig::getConfig().getPathResolver()->resolve(resolved, PathResolver::XMLTOOLING_CFG_FILE)
-                << "' validate='1'/>";
-            dummydoc = XMLToolingConfig::getConfig().getParser().parse(snippet);
-            XercesJanitor<xercesc::DOMDocument> docjanitor(dummydoc);
-            setServiceProvider(ServiceProviderManager.newPlugin(XML_SERVICE_PROVIDER, dummydoc->getDocumentElement(), true));
-            if (m_configDoc)
-                m_configDoc->release();
-            m_configDoc = docjanitor.release();
-        }
-        else {
-            stringstream snippet(config);
-            dummydoc = XMLToolingConfig::getConfig().getParser().parse(snippet);
-            XercesJanitor<xercesc::DOMDocument> docjanitor(dummydoc);
-            static const XMLCh _type[] = UNICODE_LITERAL_4(t,y,p,e);
-            auto_ptr_char type(dummydoc->getDocumentElement()->getAttributeNS(nullptr,_type));
-            if (type.get() && *type.get())
-                setServiceProvider(ServiceProviderManager.newPlugin(type.get(), dummydoc->getDocumentElement(), true));
-            else
-                throw ConfigurationException("The supplied XML bootstrapping configuration did not include a type attribute.");
-            if (m_configDoc)
-                m_configDoc->release();
-            m_configDoc = docjanitor.release();
-        }
-
-        getServiceProvider()->init();
-        return true;
-    }
-    catch (const std::exception& ex) {
-        if (rethrow) {
-            throw;
-        }
-        else {
-            Category::getInstance(SHIBSP_LOGCAT ".Config").fatal("caught exception while loading configuration: %s", ex.what());
-        }
+    // Config is loaded, look for logging section and type to instantiate.
+    string type = m_config.get(LoggingService::LOGGING_TYPE_PROP_PATH,
+#ifdef WIN32
+        WINDOWS_LOGGING_SERVICE
+#else
+        SYSLOG_LOGGING_SERVICE
+#endif
+        );
+    m_logging = unique_ptr<LoggingService>(LoggingServiceManager.newPlugin(type, m_config, false));
+    if (!m_logging->init()) {
+        return false;
     }
-    return false;
+    return true;
 }
-*/
 
 void AgentInternalConfig::term()
 {
@@ -272,10 +266,16 @@ void AgentInternalConfig::term()
 
 void AgentInternalConfig::_term()
 {
-    /*
-    Category& log=Category::getInstance(SHIBSP_LOGCAT ".Config");
-    log.info("%s library shutting down", PACKAGE_STRING);
+    Category& log=Category::getInstance(SHIBSP_LOGCAT ".AgentConfig");
+    log.info("%s agent shutting down", PACKAGE_STRING);
 
+    LoggingServiceManager.deregisterFactories();
+
+    log.info("%s agent shutdown complete", PACKAGE_STRING);
+
+    m_logging->term();
+
+    /*
     setServiceProvider(nullptr);
     if (m_configDoc)
         m_configDoc->release();
@@ -302,7 +302,5 @@ void AgentInternalConfig::_term()
 
     if (isEnabled(Caching))
         SessionCacheManager.deregisterFactories();
-
-    log.info("%s library shutdown complete", PACKAGE_STRING);
     */
 }
diff --git a/shibsp/logging/LoggingService.h b/shibsp/logging/LoggingService.h
index cecef4f0..b03911e2 100644
--- a/shibsp/logging/LoggingService.h
+++ b/shibsp/logging/LoggingService.h
@@ -40,6 +40,8 @@ namespace shibsp {
     public:
         virtual ~LoggingService();
 
+        static const char LOGGING_TYPE_PROP_PATH[];
+
         /**
          * Initializes the designated logging service.
          */
@@ -48,7 +50,7 @@ namespace shibsp {
         /**
          * Terminates the designated logging service.
          */
-        virtual bool term()=0;
+        virtual void term()=0;
 
         /**
          * Retrieves an instance of a logging Category of the specified name (empty is permitted).
diff --git a/shibsp/logging/impl/AbstractLoggingService.cpp b/shibsp/logging/impl/AbstractLoggingService.cpp
index dcf7115f..2c486a11 100644
--- a/shibsp/logging/impl/AbstractLoggingService.cpp
+++ b/shibsp/logging/impl/AbstractLoggingService.cpp
@@ -23,6 +23,8 @@
 #include "AgentConfig.h"
 #include "logging/impl/AbstractLoggingService.h"
 
+#include <stdexcept>
+
 #include <boost/property_tree/ptree.hpp>
 
 using namespace shibsp;
@@ -56,7 +58,7 @@ void SHIBSP_API shibsp::registerLoggingServices()
 #endif
 }
 
-const char AbstractLoggingService::LOGGING_SECTION_NAME[] = "logging";
+const char LoggingService::LOGGING_TYPE_PROP_PATH[] = "logging.type";
 const char AbstractLoggingService::CATEGORIES_SECTION_NAME[] = "logging-categories";
 const char AbstractLoggingService::DEFAULT_LEVEL_PROP_PATH[] = "logging.default-level";
 
@@ -70,18 +72,22 @@ LoggingServiceSPI::~LoggingServiceSPI() {}
 
 AbstractLoggingService::~AbstractLoggingService() {}
 
-AbstractLoggingService::AbstractLoggingService(const ptree& pt)
+AbstractLoggingService::AbstractLoggingService(const ptree& pt) : m_config(pt)
+{
+}
+
+bool AbstractLoggingService::init()
 {
     // Processes property tree to create mappings from category name to logging level.
     // If an invalid property token is seen, the default level is INFO.
 
     try {
-        m_defaultPriority = Priority::getPriorityValue(pt.get(DEFAULT_LEVEL_PROP_PATH, "INFO"));
+        m_defaultPriority = Priority::getPriorityValue(m_config.get(DEFAULT_LEVEL_PROP_PATH, "INFO"));
     } catch (const invalid_argument& e) {
         m_defaultPriority = Priority::PriorityLevel::SHIB_INFO;
     }
 
-    const boost::optional<const ptree&> categories = pt.get_child_optional(CATEGORIES_SECTION_NAME);
+    const boost::optional<const ptree&> categories = m_config.get_child_optional(CATEGORIES_SECTION_NAME);
     if (categories) {
         for (const auto& mapping : categories.get()) {
             try {
@@ -91,8 +97,12 @@ AbstractLoggingService::AbstractLoggingService(const ptree& pt)
             }
         }
     }
+
+    return true;
 }
 
+void AbstractLoggingService::term() {}
+
 Category& AbstractLoggingService::getCategory(const std::string& name)
 {
     lock_guard<mutex> locker(m_lock);
diff --git a/shibsp/logging/impl/AbstractLoggingService.h b/shibsp/logging/impl/AbstractLoggingService.h
index 57aaa60f..18f474ff 100644
--- a/shibsp/logging/impl/AbstractLoggingService.h
+++ b/shibsp/logging/impl/AbstractLoggingService.h
@@ -58,13 +58,17 @@ namespace shibsp {
     public:
         virtual ~AbstractLoggingService();
 
+        bool init();
+        void term();
+
         Category& getCategory(const std::string& name);
 
-        static const char LOGGING_SECTION_NAME[];
         static const char CATEGORIES_SECTION_NAME[];
         static const char DEFAULT_LEVEL_PROP_PATH[];
 
     private:
+        const boost::property_tree::ptree& m_config;
+
         // Default logging level.
         Priority::Value m_defaultPriority;
 
diff --git a/shibsp/logging/impl/Category.cpp b/shibsp/logging/impl/Category.cpp
index 17b43027..b72f14b1 100644
--- a/shibsp/logging/impl/Category.cpp
+++ b/shibsp/logging/impl/Category.cpp
@@ -12,14 +12,16 @@
  * limitations under the License.
  */
 
+#include "AgentConfig.h"
 #include "logging/Category.h"
+#include "logging/LoggingService.h"
 #include "logging/impl/LoggingServiceSPI.h"
 #include "logging/impl/StringUtil.h"
 
 using namespace shibsp;
 
 Category& Category::getInstance(const std::string& name) {
-    //return HierarchyMaintainer::getDefaultMaintainer().getInstance(name);
+    return AgentConfig::getConfig().getLoggingService().getCategory(name);
 }
 
 Category::Category(LoggingServiceSPI& spi, const std::string& name, Priority::Value priority)
@@ -42,7 +44,7 @@ void Category::_logUnconditionally(Priority::Value priority, const char* format,
 }
 
 void Category::_logUnconditionally2(Priority::Value priority, const std::string& message) throw() {
-    m_spi.outputMessage(*this, message);
+    m_spi.outputMessage(*this, priority, message);
 }
 
 bool Category::isPriorityEnabled(Priority::Value priority) const {
diff --git a/shibsp/logging/impl/ConsoleLoggingService.cpp b/shibsp/logging/impl/ConsoleLoggingService.cpp
index 80c9347e..376cecbf 100644
--- a/shibsp/logging/impl/ConsoleLoggingService.cpp
+++ b/shibsp/logging/impl/ConsoleLoggingService.cpp
@@ -35,12 +35,10 @@ namespace shibsp {
     public:
         ConsoleLoggingService(const ptree& pt);
 
-        bool init() {}
-        bool term() {}
-        void outputMessage(const Category& category, const string& message) {
-            outputMessage(category, message.c_str());
+        void outputMessage(const Category& category, Priority::Value prio, const string& message) {
+            outputMessage(category, prio, message.c_str());
         }
-        void outputMessage(const Category& category, const char* message);
+        void outputMessage(const Category& category, Priority::Value prio, const char* message);
 
     };
 
@@ -56,13 +54,13 @@ ConsoleLoggingService::ConsoleLoggingService(const ptree& pt) : AbstractLoggingS
     // message formatting.
 }
 
-void ConsoleLoggingService::outputMessage(const Category& category, const char* message)
+void ConsoleLoggingService::outputMessage(const Category& category, Priority::Value prio, const char* message)
 {
     auto now = chrono::system_clock::now();
 
-    cerr << date::format("%FT%TZ", date::floor<chrono::milliseconds>(now)) << " - "
-        << Priority::getPriorityName(category.getPriority())
-        << ' [' << category.getName() << "] - "
+    cout << date::format("%FT%TZ", date::floor<chrono::milliseconds>(now)) << " - "
+        << Priority::getPriorityName(prio)
+        << " [" << category.getName() << "] - "
         << message
         << endl;
 }
\ No newline at end of file
diff --git a/shibsp/logging/impl/LoggingServiceSPI.h b/shibsp/logging/impl/LoggingServiceSPI.h
index 9b3bf5b2..38e95534 100644
--- a/shibsp/logging/impl/LoggingServiceSPI.h
+++ b/shibsp/logging/impl/LoggingServiceSPI.h
@@ -39,31 +39,23 @@ namespace shibsp {
     public:
         virtual ~LoggingServiceSPI();
 
-        /**
-         * Initializes the designated logging service.
-         */
-        virtual bool init()=0;
-
-        /**
-         * Terminates the designated logging service.
-         */
-        virtual bool term()=0;
-
         /**
          * Outputs a logging message in whatever manner is defined by the underlying implementation.
          * 
          * @param category logging category
+         * @param prio logging priority
          * @param message logging message
          */
-        virtual void outputMessage(const Category& category, const std::string& message)=0;
+        virtual void outputMessage(const Category& category, Priority::Value prio, const std::string& message)=0;
 
         /**
          * Outputs a logging message in whatever manner is defined by the underlying implementation.
          * 
          * @param category logging category
+         * @param prio logging priority
          * @param message logging message
          */
-        virtual void outputMessage(const Category& category, const char* message)=0;
+        virtual void outputMessage(const Category& category, Priority::Value prio, const char* message)=0;
     };
 
 };
diff --git a/shibsp/logging/impl/Priority.cpp b/shibsp/logging/impl/Priority.cpp
index efc4b9ff..bebf60f5 100644
--- a/shibsp/logging/impl/Priority.cpp
+++ b/shibsp/logging/impl/Priority.cpp
@@ -15,23 +15,25 @@
 #include <shibsp/logging/Priority.h>
 
 #include <cstdlib>
+#include <stdexcept>
 
 using namespace shibsp;
+using namespace std;
 
 namespace {
-	const std::string names[7] = {
+	const string names[7] = {
 		"CRIT", "ERROR", "WARN", "INFO", "DEBUG", "NOTSET", "UNKNOWN"
 	};
 }
 
-const std::string& Priority::getPriorityName(int priority) throw() {
+const string& Priority::getPriorityName(int priority) throw() {
 		
 	priority++;
 	priority /= 100;
 	return names[((priority < 0) || (priority > 5)) ? 5 : priority];
 }
 
-Priority::Value Priority::getPriorityValue(const std::string& priorityName) {
+Priority::Value Priority::getPriorityValue(const string& priorityName) {
 	Priority::Value value = -1;
 
 	for (unsigned int i = 0; i < 7; i++) {
@@ -43,9 +45,9 @@ Priority::Value Priority::getPriorityValue(const std::string& priorityName) {
 
 	if (value == -1) {
 		char* endPointer;
-		value = std::strtoul(priorityName.c_str(), &endPointer, 10);
+		value = strtoul(priorityName.c_str(), &endPointer, 10);
 		if (*endPointer != 0) {
-			throw std::invalid_argument(std::string("unknown priority name: '") + priorityName + "'");
+			throw invalid_argument(string("unknown priority name: '") + priorityName + "'");
 		}
 	}
 
diff --git a/shibsp/util/PathResolver.cpp b/shibsp/util/PathResolver.cpp
index a1db5fd3..1e63c6f0 100644
--- a/shibsp/util/PathResolver.cpp
+++ b/shibsp/util/PathResolver.cpp
@@ -27,7 +27,7 @@
 #include "internal.h"
 #include "util/PathResolver.h"
 
-#include <exception>
+#include <stdexcept>
 
 #ifdef WIN32
 # include <Shlobj.h>
diff --git a/tests/AgentConfigTests.cpp b/tests/AgentConfigTests.cpp
new file mode 100644
index 00000000..e799069a
--- /dev/null
+++ b/tests/AgentConfigTests.cpp
@@ -0,0 +1,87 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * AgentConfigTests.cpp
+ *
+ * Unit tests for agent config machinery and logging.
+ */
+
+#include <boost/test/unit_test.hpp>
+#include <boost/property_tree/ini_parser.hpp>
+
+#include "AgentConfig.h"
+
+using namespace boost::property_tree::ini_parser;
+using namespace shibsp;
+using namespace std;
+
+// The ./ bypasses the usual path resolution for relative paths.
+#define DATA_PATH "./data/"
+
+struct AC_Fixture {
+    AC_Fixture() : data_path(DATA_PATH) {}
+    string data_path;
+};
+
+class exceptionCheck {
+public:
+    exceptionCheck(const string& msg) : m_msg(msg) {}
+    bool check_message(const ini_parser_error& e) {
+        return e.message().compare(m_msg) == 0;
+    }
+private:
+    string m_msg;
+};
+
+BOOST_FIXTURE_TEST_CASE(AgentConfig_init_bad_path, AC_Fixture)
+{
+    // No throw.
+    BOOST_CHECK(!AgentConfig::getConfig().init(nullptr, (data_path + "missing.ini").c_str(), false));
+
+    exceptionCheck checker("cannot open file");
+
+    // Throw.
+    BOOST_CHECK_EXCEPTION(AgentConfig::getConfig().init(nullptr, (data_path + "missing.ini").c_str(), true),
+        ini_parser_error, checker.check_message);
+}
+
+BOOST_FIXTURE_TEST_CASE(AgentConfig_init_bad_format, AC_Fixture)
+{
+    exceptionCheck checker_unmatched("unmatched '['");
+    BOOST_CHECK_EXCEPTION(AgentConfig::getConfig().init(nullptr, (data_path + "unmatched_shibboleth.ini").c_str(), true),
+        ini_parser_error, checker_unmatched.check_message);
+
+    exceptionCheck checker_dupsection("duplicate section name");
+    BOOST_CHECK_EXCEPTION(AgentConfig::getConfig().init(nullptr, (data_path + "dupsection_shibboleth.ini").c_str(), true),
+        ini_parser_error, checker_dupsection.check_message);
+
+    exceptionCheck checker_noequals("'=' character not found in line");
+    BOOST_CHECK_EXCEPTION(AgentConfig::getConfig().init(nullptr, (data_path + "noequals_shibboleth.ini").c_str(), true),
+        ini_parser_error, checker_noequals.check_message);
+
+    exceptionCheck checker_dupproperty("duplicate key name");
+    BOOST_CHECK_EXCEPTION(AgentConfig::getConfig().init(nullptr, (data_path + "dupproperty_shibboleth.ini").c_str(), true),
+        ini_parser_error, checker_dupproperty.check_message);
+
+    exceptionCheck checker_nokey("key expected");
+    BOOST_CHECK_EXCEPTION(AgentConfig::getConfig().init(nullptr, (data_path + "nokey_shibboleth.ini").c_str(), true),
+        ini_parser_error, checker_nokey.check_message);
+}
+
+BOOST_FIXTURE_TEST_CASE(AgentConfig_init_success, AC_Fixture)
+{
+    BOOST_CHECK(AgentConfig::getConfig().init(nullptr, (data_path + "shibboleth.ini").c_str(), true));
+    AgentConfig::getConfig().term();
+}
diff --git a/tests/Makefile.am b/tests/Makefile.am
index edf67c90..b6b61a25 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -11,6 +11,7 @@ shibsptest_CXXFLAGS = \
 
 shibsptest_SOURCES = \
 	AgentTestSuite.cpp \
+	AgentConfigTests.cpp \
 	util/PropertyTreeTests.cpp \
 	util/BoostPropertySetTests.cpp
 
diff --git a/tests/data/dupproperty_shibboleth.ini b/tests/data/dupproperty_shibboleth.ini
new file mode 100644
index 00000000..b95a216f
--- /dev/null
+++ b/tests/data/dupproperty_shibboleth.ini
@@ -0,0 +1,3 @@
+[bar]
+foo = bar
+foo = bar
diff --git a/tests/data/dupsection_shibboleth.ini b/tests/data/dupsection_shibboleth.ini
new file mode 100644
index 00000000..68985037
--- /dev/null
+++ b/tests/data/dupsection_shibboleth.ini
@@ -0,0 +1,5 @@
+[foo]
+bar = baz
+
+[foo]
+baz = baf
diff --git a/tests/data/noequals_shibboleth.ini b/tests/data/noequals_shibboleth.ini
new file mode 100644
index 00000000..9bc83d60
--- /dev/null
+++ b/tests/data/noequals_shibboleth.ini
@@ -0,0 +1,2 @@
+[foo]
+bar
diff --git a/tests/data/nokey_shibboleth.ini b/tests/data/nokey_shibboleth.ini
new file mode 100644
index 00000000..ca45a379
--- /dev/null
+++ b/tests/data/nokey_shibboleth.ini
@@ -0,0 +1,2 @@
+[foo]
+=bar
diff --git a/tests/data/shibboleth.ini b/tests/data/shibboleth.ini
new file mode 100644
index 00000000..c8471aa8
--- /dev/null
+++ b/tests/data/shibboleth.ini
@@ -0,0 +1,6 @@
+[logging]
+type = console
+default-level = WARN
+
+[logging-categories]
+Shibboleth.AgentConfig = DEBUG
diff --git a/tests/data/unmatched_shibboleth.ini b/tests/data/unmatched_shibboleth.ini
new file mode 100644
index 00000000..3316e1e1
--- /dev/null
+++ b/tests/data/unmatched_shibboleth.ini
@@ -0,0 +1 @@
+[unmatched

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the commits mailing list