[cpp-sp] branch main updated: Semi-finalized port of XML config support with tests.
Scott Cantor
cantor.2 at osu.edu
Thu Dec 5 19:11:45 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=8736c8a18a2726b131fcf89c055cac5355263483
The following commit(s) were added to refs/heads/main by this push:
new 8736c8a1 Semi-finalized port of XML config support with tests.
8736c8a1 is described below
commit 8736c8a18a2726b131fcf89c055cac5355263483
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Thu Dec 5 14:11:40 2024 -0500
Semi-finalized port of XML config support with tests.
---
shibsp/Makefile.am | 4 +-
.../{ReloadableFile.cpp => ReloadableXMLFile.cpp} | 112 +++++-----
.../util/{ReloadableFile.h => ReloadableXMLFile.h} | 62 +++---
tests/Makefile.am | 2 +-
.../data/util/reloadablefile/external-invalid.xml | 1 +
tests/data/util/reloadablefile/external.xml | 2 +-
tests/data/util/reloadablefile/inline-invalid.xml | 3 +
tests/data/util/reloadablefile/inline.xml | 7 +-
tests/data/util/reloadablefile/invalid.xml | 1 +
tests/util/ReloadableFileTests.cpp | 123 -----------
tests/util/ReloadableXMLFileTests.cpp | 225 +++++++++++++++++++++
11 files changed, 330 insertions(+), 212 deletions(-)
diff --git a/shibsp/Makefile.am b/shibsp/Makefile.am
index a531ea03..df56c005 100644
--- a/shibsp/Makefile.am
+++ b/shibsp/Makefile.am
@@ -74,7 +74,7 @@ utilinclude_HEADERS = \
util/Lockable.h \
util/PathResolver.h \
util/PropertySet.h \
- util/ReloadableFile.h \
+ util/ReloadableXMLFile.h \
util/SPConstants.h \
util/TemplateParameters.h \
util/URLEncoder.h
@@ -146,7 +146,7 @@ libshibsp_la_SOURCES = \
util/DOMPropertySet.cpp \
util/IPRange.cpp \
util/PathResolver.cpp \
- util/ReloadableFile.cpp \
+ util/ReloadableXMLFile.cpp \
util/SPConstants.cpp \
util/TemplateParameters.cpp \
util/URLEncoder.cpp
diff --git a/shibsp/util/ReloadableFile.cpp b/shibsp/util/ReloadableXMLFile.cpp
similarity index 55%
rename from shibsp/util/ReloadableFile.cpp
rename to shibsp/util/ReloadableXMLFile.cpp
index 5e4f9a45..a9875b11 100644
--- a/shibsp/util/ReloadableFile.cpp
+++ b/shibsp/util/ReloadableXMLFile.cpp
@@ -1,27 +1,21 @@
/**
- * Licensed to the University Corporation for Advanced Internet
- * Development, Inc. (UCAID) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for
- * additional information regarding copyright ownership.
+ * 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
*
- * UCAID licenses this file to you 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
*
- * 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.
+ * 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.
*/
/**
- * util/ReloadableFile.cpp
+ * util/ReloadableXMLFile.cpp
*
- * Base class for file-based configuration.
+ * Base class for XML file-based configuration.
*/
#include "internal.h"
@@ -29,7 +23,7 @@
#include "AgentConfig.h"
#include "logging/Category.h"
#include "util/PathResolver.h"
-#include "util/ReloadableFile.h"
+#include "util/ReloadableXMLFile.h"
#include <sys/types.h>
#include <sys/stat.h>
@@ -40,7 +34,7 @@ using namespace shibsp;
using namespace std;
namespace {
- // More an experiment than anything but it does encapsulate the conversion.
+ // More an experiment than anything but it does encapsulate the conversion...
struct string_to_bool_translator {
typedef std::string internal_type;
typedef bool external_type;
@@ -57,10 +51,11 @@ namespace {
};
};
-const char ReloadableFile::PATH_PROP_NAME[] = "path";
-const char ReloadableFile::RELOAD_CHANGES_PROP_NAME[] = "reloadChanges";
+const char ReloadableXMLFile::PATH_PROP_NAME[] = "<xmlattr>.path";
+const char ReloadableXMLFile::RELOAD_CHANGES_PROP_NAME[] = "<xmlattr>.reloadChanges";
-ReloadableFile::ReloadableFile(const ptree& pt, Category& log) : m_root(pt), m_log(log), m_filestamp(0)
+ReloadableXMLFile::ReloadableXMLFile(const string& rootElementName, const ptree& pt, Category& log)
+ : m_root(pt), m_log(log), m_rootElementName(rootElementName), m_filestamp(0)
#ifdef HAVE_CXX17
, m_lock(nullptr)
#elif HAVE_CXX14
@@ -74,6 +69,12 @@ ReloadableFile::ReloadableFile(const ptree& pt, Category& log) : m_root(pt), m_l
string_to_bool_translator tr;
bool reloadChanges = pt.get(RELOAD_CHANGES_PROP_NAME, false, tr);
+#ifndef HAVE_CXX14
+ if (reloadChanges) {
+ log.warn("C++ compiler level does not allow for reloadChanges, ignoring");
+ reloadChanges = false;
+ }
+#endif
log.info("using path (%s), will %smonitor for changes", m_source.c_str(), reloadChanges ? "" : "not ");
if (reloadChanges) {
#ifdef HAVE_CXX17
@@ -85,16 +86,16 @@ ReloadableFile::ReloadableFile(const ptree& pt, Category& log) : m_root(pt), m_l
}
}
-ReloadableFile::~ReloadableFile()
+ReloadableXMLFile::~ReloadableXMLFile()
{
}
-time_t ReloadableFile::getLastModified() const
+time_t ReloadableXMLFile::getLastModified() const
{
return m_filestamp;
}
-bool ReloadableFile::isUpdated() const
+bool ReloadableXMLFile::isUpdated() const
{
if (m_source.empty()) {
return false;
@@ -114,7 +115,7 @@ bool ReloadableFile::isUpdated() const
return stat_buf.st_mtime > m_filestamp;
}
-void ReloadableFile::updateModificationTime()
+void ReloadableXMLFile::updateModificationTime()
{
#ifdef WIN32
struct _stat stat_buf;
@@ -127,57 +128,68 @@ void ReloadableFile::updateModificationTime()
}
}
-void ReloadableFile::updateModificationTime(time_t t)
+void ReloadableXMLFile::updateModificationTime(time_t t)
{
m_filestamp = t;
}
-pair<bool,ptree*> ReloadableFile::load()
+pair<bool,ptree*> ReloadableXMLFile::load() noexcept
{
- if (m_source.empty()) {
- m_log.debug("loading inline configuration...");
- // Data comes from the tree we were handed.
- // Because property trees work differently from an XML DOM,
- // we return the actual root, and not the first child as before
- // so the caller can interrogate the name of the child tree to
- // ensure it's as expected.
- // The const_cast is safe because the flag is false,
- // preventing the caller from retaining ownership.
- return make_pair(false, const_cast<ptree*>(&m_root));
- }
-
try {
+ if (m_source.empty()) {
+ m_log.debug("loading inline configuration...");
+ // Data comes from the tree we were handed by locating a subtree of the expected name.
+ const boost::optional<const ptree&> child = m_root.get_child_optional(m_rootElementName);
+ if (!child) {
+ throw xml_parser_error("XML missing expected child element: " + m_rootElementName, "inline", 0);
+ }
+ // The const_cast is safe because the flag is false,
+ // preventing the caller from retaining ownership.
+ return make_pair(false, const_cast<ptree*>(&m_root));
+ }
+
unique_ptr<ptree> newtree = unique_ptr<ptree>(new ptree());
xml_parser::read_xml(m_source, *newtree, xml_parser::no_comments|xml_parser::trim_whitespace);
+
+ // Data comes from the tree we were handed by locating a subtree of the expected name.
+ const boost::optional<ptree&> child = newtree->get_child_optional(m_rootElementName);
+ if (!child) {
+ throw xml_parser_error("XML missing expected child element: " + m_rootElementName, m_source, 0);
+ }
+
return make_pair(true, newtree.release());
} catch (const bad_alloc& e) {
m_log.crit("out of memory parsing XML configuration (%s)", m_source.c_str());
} catch (const xml_parser_error& e) {
- m_log.error("failed to process XML configuration (%s): %s", m_source.c_str(), e.what());
+ m_log.error("failed to process XML configuration: %s", e.what());
}
+
+ return make_pair(false, nullptr);
}
-void ReloadableFile::lock()
+void ReloadableXMLFile::lock()
{
if (m_lock) {
m_lock->lock();
}
}
-bool ReloadableFile::try_lock()
+bool ReloadableXMLFile::try_lock()
{
if (m_lock) {
return m_lock->try_lock();
+ } else {
+ return true;
}
}
-void ReloadableFile::unlock()
+void ReloadableXMLFile::unlock()
{
if (m_lock)
m_lock->unlock();
}
-void ReloadableFile::lock_shared()
+void ReloadableXMLFile::lock_shared()
{
if (!m_lock) {
return;
@@ -198,16 +210,12 @@ void ReloadableFile::lock_shared()
// The result is handled entirely by the subclass so is ignored here.
// The original root tree is purely a means of communicating the object
// from the c'tor over to the load method for the inline case, at first load.
- try {
- load();
- } catch (...) {
- // Shouldn't happen but ensures we generally will acquire the lock before returning.
- }
+ load();
m_lock->lock_shared();
}
-bool ReloadableFile::try_lock_shared()
+bool ReloadableXMLFile::try_lock_shared()
{
if (m_lock)
return m_lock->try_lock_shared();
@@ -215,7 +223,7 @@ bool ReloadableFile::try_lock_shared()
return true;
}
-void ReloadableFile::unlock_shared()
+void ReloadableXMLFile::unlock_shared()
{
if (m_lock)
m_lock->unlock_shared();
diff --git a/shibsp/util/ReloadableFile.h b/shibsp/util/ReloadableXMLFile.h
similarity index 75%
rename from shibsp/util/ReloadableFile.h
rename to shibsp/util/ReloadableXMLFile.h
index 394bbc34..4ec4b96c 100644
--- a/shibsp/util/ReloadableFile.h
+++ b/shibsp/util/ReloadableXMLFile.h
@@ -13,13 +13,13 @@
*/
/**
- * @file shibsp/util/ReloadableFile.h
+ * @file shibsp/util/ReloadableXMLFile.h
*
- * Base class for reloadable file-based configuration.
+ * Base class for reloadable XML file-based configuration.
*/
-#ifndef __shibsp_reloadablefile_h__
-#define __shibsp_reloadablefile_h__
+#ifndef __shibsp_ReloadableXMLFile_h__
+#define __shibsp_ReloadableXMLFile_h__
#include <shibsp/util/Lockable.h>
@@ -38,20 +38,29 @@ namespace shibsp {
class SHIBSP_API Category;
/**
- * Base class for file-based configuration, provides locking and reload semantics.
+ * Base class for file-based XML configuration, provides locking and reload semantics.
*
* <p>Also supports "inliine" configuration that short-circuits most of this logic
* allowing for unified handling of the two cases by implementing classes and the
* consumers of a configuration interface.</p>
*/
- class SHIBSP_API ReloadableFile : public virtual BasicLockable, public virtual SharedLockable
+ class SHIBSP_API ReloadableXMLFile : public virtual BasicLockable, public virtual SharedLockable
{
- MAKE_NONCOPYABLE(ReloadableFile);
+ MAKE_NONCOPYABLE(ReloadableXMLFile);
public:
static const char PATH_PROP_NAME[];
static const char RELOAD_CHANGES_PROP_NAME[];
+ // BasicLockable
+ void lock();
+ bool try_lock();
+ void unlock();
+ // SharedLockable
+ void lock_shared();
+ bool try_lock_shared();
+ void unlock_shared();
+
protected:
/**
* Base class constructor.
@@ -64,12 +73,18 @@ namespace shibsp {
* inline as the content of the supplied tree and the base class essentially
* performs no activity, stubs out locking, etc.</p>
*
+ * <p>Note that the root element name specified applies to the content of the
+ * configuration itself and not the element that may be carrying the "path" key
+ * specifying an external file (i.e., in that case it's the external content whose
+ * root element would be expected to match).</p>
+ *
* @param pt root of property tree defining resource
+ * @param rootElementName name of expexcted root element of XML configuration
* @param log logging object to use
*/
- ReloadableFile(const boost::property_tree::ptree& pt, Category& log);
+ ReloadableXMLFile(const std::string& rootElementName, const boost::property_tree::ptree& pt, Category& log);
- virtual ~ReloadableFile();
+ virtual ~ReloadableXMLFile();
/**
* Loads (or reloads) configuration material.
@@ -78,17 +93,17 @@ namespace shibsp {
* initially and any time a change is detected but is not called
* initially unless by a subclass.</p>
*
- * <p>This method is not called with the object locked, so actual
- * modification of configuration state requires explicit locking
- * within the method.</p>
+ * <p>This method is not intended to throw.</p>
*
- * <p>This method should NOT throw exceptions.</p>
+ * <p>This method is not called with the object locked, and it does
+ * not modify implementation state. Subclasses are expected to override
+ * this method to lock and modify state as required.</p>
*
- * @return a pair containing a pointer to the property tree loaded
- * and a flag indicating whether the subclass should retain ownership
+ * @return a pair containing a (possibly null) pointer to the property tree
+ * loaded and a flag indicating whether the subclass should retain ownership
* of the tree and free it when done with it
*/
- virtual std::pair<bool,boost::property_tree::ptree*> load();
+ virtual std::pair<bool,boost::property_tree::ptree*> load() noexcept;
/**
* Gets the last time the configuration was updated.
@@ -143,6 +158,9 @@ namespace shibsp {
/** Resource path. */
std::string m_source;
+ /** Expected name of root element, i.e. subtree, after parsing. */
+ std::string m_rootElementName;
+
/** Last modification of local resource. */
time_t m_filestamp;
@@ -152,18 +170,8 @@ namespace shibsp {
#elif HAVE_CXX14
std::unique_ptr<std::shared_timed_mutex> m_lock;
#endif
-
- public:
- // BasicLockable
- void lock();
- bool try_lock();
- void unlock();
- // SharedLockable
- void lock_shared();
- bool try_lock_shared();
- void unlock_shared();
};
};
-#endif /* __shibsp_reloadablefile_h__ */
+#endif /* __shibsp_ReloadableXMLFile_h__ */
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 5db9ce9b..d66b43f2 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -14,7 +14,7 @@ shibsptest_SOURCES = \
AgentConfigTests.cpp \
util/PropertyTreeTests.cpp \
util/BoostPropertySetTests.cpp \
- util/ReloadableFileTests.cpp
+ util/ReloadableXMLFileTests.cpp
shibsptest_LDADD = \
$(top_builddir)/shibsp/libshibsp.la
diff --git a/tests/data/util/reloadablefile/external-invalid.xml b/tests/data/util/reloadablefile/external-invalid.xml
new file mode 100644
index 00000000..4e621a2f
--- /dev/null
+++ b/tests/data/util/reloadablefile/external-invalid.xml
@@ -0,0 +1 @@
+<RequestMapper type="XML" path="./data/util/reloadablefile/invalid.xml" reloadChanges="true" />
diff --git a/tests/data/util/reloadablefile/external.xml b/tests/data/util/reloadablefile/external.xml
index c2e362a9..23b9d0b4 100644
--- a/tests/data/util/reloadablefile/external.xml
+++ b/tests/data/util/reloadablefile/external.xml
@@ -1 +1 @@
-<RequestMapper type="XML" path="./data/util/reloadablefile/external.xml" reloadChanges="true" />
+<RequestMapper type="XML" path="./data/util/reloadablefile/requestmap.xml" reloadChanges="true" />
diff --git a/tests/data/util/reloadablefile/inline-invalid.xml b/tests/data/util/reloadablefile/inline-invalid.xml
new file mode 100644
index 00000000..3bb75e72
--- /dev/null
+++ b/tests/data/util/reloadablefile/inline-invalid.xml
@@ -0,0 +1,3 @@
+<RequestMapper type="XML">
+ <Foo/>
+</RequestMapper>
diff --git a/tests/data/util/reloadablefile/inline.xml b/tests/data/util/reloadablefile/inline.xml
index 977fc86f..8e8aca50 100644
--- a/tests/data/util/reloadablefile/inline.xml
+++ b/tests/data/util/reloadablefile/inline.xml
@@ -1,8 +1,3 @@
<RequestMapper type="XML">
- <RequestMap>
- <Host name="sp.example.org">
- <Path name="secure" requireSession="true" />
- </Host>
- <Host name="admin.example.org" applicationId="admin" requireSession="true" />
- </RequestMap>
+ <RequestMap/>
</RequestMapper>
diff --git a/tests/data/util/reloadablefile/invalid.xml b/tests/data/util/reloadablefile/invalid.xml
new file mode 100644
index 00000000..496e8bb8
--- /dev/null
+++ b/tests/data/util/reloadablefile/invalid.xml
@@ -0,0 +1 @@
+<Foo/>
diff --git a/tests/util/ReloadableFileTests.cpp b/tests/util/ReloadableFileTests.cpp
deleted file mode 100644
index e4660964..00000000
--- a/tests/util/ReloadableFileTests.cpp
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * 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.
- */
-
-/**
- * ReloadableFileTests.cpp
- *
- * Unit tests for reloadable file usage.
- */
-
-#include "AgentConfig.h"
-#include "logging/Category.h"
-#include "util/ReloadableFile.h"
-
-#include <boost/test/unit_test.hpp>
-#include <boost/property_tree/xml_parser.hpp>
-
-using namespace shibsp;
-using namespace boost::property_tree;
-using namespace std;
-
-#define DATA_PATH "./data/util/reloadablefile/"
-
-struct Inline_Fixture {
- Inline_Fixture() : data_path(DATA_PATH) {
- AgentConfig::getConfig().init(nullptr, (data_path + "console-shibboleth.ini").c_str(), true);
- xml_parser::read_xml(data_path + "inline.xml", tree, xml_parser::no_comments|xml_parser::trim_whitespace);
- }
- ~Inline_Fixture() {
- AgentConfig::getConfig().term();
- }
-
- string data_path;
- ptree tree;
-};
-
-class DummyXMLFile : virtual public ReloadableFile
-{
-public:
- DummyXMLFile(const ptree& pt)
- : ReloadableFile(pt, Category::getInstance("DummyXMLFile")),
- m_log(Category::getInstance("DummyXMLFile")), m_tree(nullptr), m_forceReload(false) {
-
- load();
- }
- ~DummyXMLFile() {}
-
- bool isUpdated() const {
- return m_forceReload;
- }
-
- void forceReload() {
- m_forceReload = true;
- }
-
- time_t getLastModified() const {
- return ReloadableFile::getLastModified();
- }
-
-protected:
- pair<bool,ptree*> load();
-
-private:
- Category& m_log;
- unique_ptr<ptree> m_tree;
- bool m_forceReload;
-};
-
-pair<bool,ptree*> DummyXMLFile::load()
-{
- pair<bool,ptree*> ret = ReloadableFile::load();
- if (ret.second) {
- if (ret.first) {
- m_log.debug("external config is valid");
- } else {
- m_log.debug("inline config is valid");
- return ret;
- }
- } else {
- m_log.error("initial configuration was invalid");
- return ret;
- }
-
- // Swap in external config and update timestamp.
-
-#ifdef HAVE_CXX14
- unique_lock<ReloadableFile> locker(*this);
-#endif
- unique_ptr<ptree> newtree(ret.second);
- m_tree.swap(newtree);
- updateModificationTime(time(nullptr));
-
- return ret;
-}
-
-BOOST_FIXTURE_TEST_CASE(ReloadableFileTest_no_reload, Inline_Fixture)
-{
- DummyXMLFile dummy(tree);
-
- dummy.lock_shared();
- time_t ts1 = dummy.getLastModified();
- BOOST_CHECK_EQUAL(ts1, 0);
- dummy.unlock();
-
- // No-op since there's no locking internally.
- dummy.forceReload();
- sleep(2);
-
- dummy.lock_shared();
- time_t ts2 = dummy.getLastModified();
- BOOST_CHECK_EQUAL(ts2, 0);
- dummy.unlock();
-}
diff --git a/tests/util/ReloadableXMLFileTests.cpp b/tests/util/ReloadableXMLFileTests.cpp
new file mode 100644
index 00000000..62e85f10
--- /dev/null
+++ b/tests/util/ReloadableXMLFileTests.cpp
@@ -0,0 +1,225 @@
+/*
+ * 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.
+ */
+
+/**
+ * ReloadableFileTests.cpp
+ *
+ * Unit tests for reloadable file usage.
+ */
+
+#include "AgentConfig.h"
+#include "logging/Category.h"
+#include "util/ReloadableXMLFile.h"
+
+#include <boost/test/unit_test.hpp>
+#include <boost/property_tree/xml_parser.hpp>
+
+using namespace shibsp;
+using namespace boost::property_tree;
+using namespace std;
+
+#define DATA_PATH "./data/util/reloadablefile/"
+
+class DummyXMLFile : virtual public ReloadableXMLFile
+{
+public:
+ DummyXMLFile(const ptree& pt)
+ : ReloadableXMLFile("RequestMap", pt, Category::getInstance("DummyXMLFile")),
+ m_log(Category::getInstance("DummyXMLFile")), m_tree(nullptr), m_forceReload(false) {
+ if (!load().second) {
+ throw domain_error("Invalid configuration.");
+ }
+ }
+ ~DummyXMLFile() {}
+
+ bool isUpdated() const {
+ return m_forceReload;
+ }
+
+ void forceReload() {
+ m_forceReload = true;
+ }
+
+ time_t getLastModified() const {
+ return ReloadableXMLFile::getLastModified();
+ }
+
+protected:
+ pair<bool,ptree*> load() noexcept;
+
+private:
+ Category& m_log;
+ unique_ptr<ptree> m_tree;
+ bool m_forceReload;
+};
+
+pair<bool,ptree*> DummyXMLFile::load() noexcept
+{
+ pair<bool,ptree*> ret = ReloadableXMLFile::load();
+ if (ret.second) {
+
+ // For test-sake, re-verify the child element.
+ const boost::optional<ptree&> child = ret.second->get_child_optional("RequestMap");
+ if (!child) {
+ return make_pair(false, nullptr);
+ }
+
+ if (ret.first) {
+ m_log.debug("external config is valid");
+ } else {
+ m_log.debug("inline config is valid");
+ return ret;
+ }
+ } else {
+ return make_pair(false, nullptr);
+ }
+
+ // Swap in external config and update timestamp.
+
+#ifdef HAVE_CXX14
+ unique_lock<ReloadableXMLFile> locker(*this);
+#endif
+ unique_ptr<ptree> newtree(ret.second);
+ m_tree.swap(newtree);
+ updateModificationTime(time(nullptr));
+
+ return ret;
+}
+
+class exceptionCheck {
+public:
+ exceptionCheck(const string& msg) : m_msg(msg) {}
+ bool check_message(const exception& e) {
+ cout << e.what() << endl;
+ return m_msg.compare(e.what()) == 0;
+ }
+private:
+ string m_msg;
+};
+
+struct BaseFixture
+{
+ BaseFixture() : data_path(DATA_PATH) {
+ AgentConfig::getConfig().init(nullptr, (data_path + "console-shibboleth.ini").c_str(), true);
+ }
+ ~BaseFixture() {
+ AgentConfig::getConfig().term();
+ }
+ string data_path;
+};
+
+/////////////
+
+struct External_Invalid_Fixture : public BaseFixture
+{
+ External_Invalid_Fixture() {
+ xml_parser::read_xml(data_path + "external-invalid.xml", tree, xml_parser::no_comments|xml_parser::trim_whitespace);
+ }
+ ~External_Invalid_Fixture() {
+ }
+
+ ptree tree;
+};
+
+BOOST_FIXTURE_TEST_CASE(ReloadableFileTest_external_invalid, External_Invalid_Fixture)
+{
+ BOOST_CHECK_EQUAL(tree.size(), 1);
+
+ exceptionCheck checker("Invalid configuration.");
+ BOOST_CHECK_EXCEPTION(DummyXMLFile dummy(tree.front().second), domain_error, checker.check_message);
+}
+
+/////////////
+
+struct Inline_Invalid_Fixture : public BaseFixture
+{
+ Inline_Invalid_Fixture() {
+ xml_parser::read_xml(data_path + "inline-invalid.xml", tree, xml_parser::no_comments|xml_parser::trim_whitespace);
+ }
+ ~Inline_Invalid_Fixture() {
+ }
+
+ ptree tree;
+};
+
+BOOST_FIXTURE_TEST_CASE(ReloadableFileTest_inline_invalid, Inline_Invalid_Fixture)
+{
+ BOOST_CHECK_EQUAL(tree.size(), 1);
+
+ exceptionCheck checker("Invalid configuration.");
+ BOOST_CHECK_EXCEPTION(DummyXMLFile dummy(tree.front().second), domain_error, checker.check_message);
+}
+
+/////////////
+
+struct Inline_Valid_Fixture : public BaseFixture
+{
+ Inline_Valid_Fixture() {
+ xml_parser::read_xml(data_path + "inline.xml", tree, xml_parser::no_comments|xml_parser::trim_whitespace);
+ }
+ ~Inline_Valid_Fixture() {
+ }
+
+ ptree tree;
+};
+
+BOOST_FIXTURE_TEST_CASE(ReloadableFileTest_inline_valid, Inline_Valid_Fixture)
+{
+ BOOST_CHECK_EQUAL(tree.size(), 1);
+ DummyXMLFile dummy(tree.front().second);
+
+ dummy.lock_shared();
+ time_t ts1 = dummy.getLastModified();
+ BOOST_CHECK_EQUAL(ts1, 0);
+ dummy.unlock();
+
+ // No-op since there's no locking internally.
+ dummy.forceReload();
+ sleep(2);
+
+ dummy.lock_shared();
+ time_t ts2 = dummy.getLastModified();
+ BOOST_CHECK_EQUAL(ts2, 0);
+ dummy.unlock();
+}
+
+struct External_Valid_Fixture : public BaseFixture
+{
+ External_Valid_Fixture() {
+ xml_parser::read_xml(data_path + "external.xml", tree, xml_parser::no_comments|xml_parser::trim_whitespace);
+ }
+ ~External_Valid_Fixture() {
+ }
+
+ ptree tree;
+};
+
+BOOST_FIXTURE_TEST_CASE(ReloadableFileTest_external_valid, External_Valid_Fixture)
+{
+ BOOST_CHECK_EQUAL(tree.size(), 1);
+ DummyXMLFile dummy(tree.front().second);
+
+ dummy.lock_shared();
+ time_t ts1 = dummy.getLastModified();
+ BOOST_CHECK_GT(ts1, 0);
+ dummy.unlock();
+
+ dummy.forceReload();
+ sleep(2);
+
+ dummy.lock_shared();
+ time_t ts2 = dummy.getLastModified();
+ BOOST_CHECK_GT(ts2, ts1);
+ dummy.unlock();
+}
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list