BIND 10 trac2974, updated. 71376fdfd9be70f5dc7f28fcec5bb75fbeb27ccd [2974] Created CalloutManager
BIND 10 source code commits
bind10-changes at lists.isc.org
Fri Jun 7 16:10:26 UTC 2013
The branch, trac2974 has been updated
via 71376fdfd9be70f5dc7f28fcec5bb75fbeb27ccd (commit)
via 226b4d1a1e9b94d5eb9eb92e6a35f24a1ea1d0bf (commit)
via c68b2f25695d5fc4c64d8a45a7414695a8281c53 (commit)
via 5cc7f89d8f2fc1ebb563556fa7e250ceb3d4aedb (commit)
from 64bc2cfab72d67bf9e4f3cd19fd6ebb586208e67 (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 71376fdfd9be70f5dc7f28fcec5bb75fbeb27ccd
Author: Stephen Morris <stephen at isc.org>
Date: Fri Jun 7 17:07:11 2013 +0100
[2974] Created CalloutManager
The LibraryHandleCollection, as a result of comments, has morphed
into the general class for handling callouts. This commit reflects
that change.
commit 226b4d1a1e9b94d5eb9eb92e6a35f24a1ea1d0bf
Author: Stephen Morris <stephen at isc.org>
Date: Fri Jun 7 12:27:22 2013 +0100
[2974] ServerHooks::getIndex now throws an exception for unknown hook
Prior to this, if the hook name was invalid, an index of -1 was returned.
commit c68b2f25695d5fc4c64d8a45a7414695a8281c53
Author: Stephen Morris <stephen at isc.org>
Date: Thu Jun 6 12:14:20 2013 +0100
[2974] Added hook function registration code
Added HookRegistrationFunction class to allow hook registration
functions to registered with the relevant server.
commit 5cc7f89d8f2fc1ebb563556fa7e250ceb3d4aedb
Author: Stephen Morris <stephen at isc.org>
Date: Thu Jun 6 10:53:18 2013 +0100
[2974] Removed library context area after review
The review correctly pointed out there there is no need for a
library-specific data area - the library can declare its own
global data. This change removed that section.
-----------------------------------------------------------------------
Summary of changes:
src/lib/util/Makefile.am | 4 +-
src/lib/util/hooks/callout_handle.h | 13 +-
src/lib/util/hooks/callout_manager.cc | 195 +++++++
src/lib/util/hooks/callout_manager.h | 315 +++++++++++
src/lib/util/hooks/library_handle.cc | 222 --------
src/lib/util/hooks/library_handle.h | 368 -------------
src/lib/util/hooks/server_hooks.cc | 35 +-
src/lib/util/hooks/server_hooks.h | 103 +++-
src/lib/util/tests/Makefile.am | 8 +-
src/lib/util/tests/callout_manager_unittest.cc | 546 ++++++++++++++++++++
src/lib/util/tests/handles_unittest.cc | 344 ++++--------
.../tests/library_handle_collection_unittest.cc | 447 ----------------
src/lib/util/tests/library_handle_unittest.cc | 235 +--------
src/lib/util/tests/server_hooks_unittest.cc | 122 ++++-
14 files changed, 1430 insertions(+), 1527 deletions(-)
create mode 100644 src/lib/util/hooks/callout_manager.cc
create mode 100644 src/lib/util/hooks/callout_manager.h
delete mode 100644 src/lib/util/hooks/library_handle.cc
delete mode 100644 src/lib/util/hooks/library_handle.h
create mode 100644 src/lib/util/tests/callout_manager_unittest.cc
delete mode 100644 src/lib/util/tests/library_handle_collection_unittest.cc
-----------------------------------------------------------------------
diff --git a/src/lib/util/Makefile.am b/src/lib/util/Makefile.am
index bae2a80..0f22a74 100644
--- a/src/lib/util/Makefile.am
+++ b/src/lib/util/Makefile.am
@@ -37,8 +37,8 @@ libb10_util_la_SOURCES += encode/base32hex_from_binary.h
libb10_util_la_SOURCES += encode/base_n.cc encode/hex.h
libb10_util_la_SOURCES += encode/binary_from_base32hex.h
libb10_util_la_SOURCES += encode/binary_from_base16.h
-libb10_util_la_SOURCES += hooks/callout_handle.h hooks/callout_handle.cc
-libb10_util_la_SOURCES += hooks/library_handle.h hooks/library_handle.cc
+libb10_util_la_SOURCES += hooks/callout_manager.h hooks/callout_manager.cc
+# libb10_util_la_SOURCES += hooks/callout_handle.h hooks/callout_handle.cc
libb10_util_la_SOURCES += hooks/server_hooks.h hooks/server_hooks.cc
libb10_util_la_SOURCES += random/qid_gen.h random/qid_gen.cc
libb10_util_la_SOURCES += random/random_number_generator.h
diff --git a/src/lib/util/hooks/callout_handle.h b/src/lib/util/hooks/callout_handle.h
index 3d09c45..87d9cb7 100644
--- a/src/lib/util/hooks/callout_handle.h
+++ b/src/lib/util/hooks/callout_handle.h
@@ -73,8 +73,8 @@ public:
// Forward declaration of the library handle and related collection classes.
+class CalloutManager;
class LibraryHandle;
-class LibraryHandleCollection;
/// @brief Per-packet callout handle
///
@@ -135,13 +135,13 @@ public:
/// Creates the object and calls the callouts on the "context_create"
/// hook.
///
- /// @param manager Pointer to the collection of library handles.
- CalloutHandle(boost::shared_ptr<LibraryHandleCollection>& collection);
+ /// @param manager Pointer to the callout manager object.
+ CalloutHandle(boost::shared_ptr<CalloutManager>& /* manager */) {}
/// @brief Destructor
///
/// Calls the context_destroy callback to release any per-packet context.
- ~CalloutHandle();
+ ~CalloutHandle() {}
/// @brief Set argument
///
@@ -364,9 +364,8 @@ private:
/// Context collection - there is one entry per library context.
ContextCollection context_collection_;
- /// Library handle collection, used to obtain the correct library handle
- /// during a call to a callout.
- boost::shared_ptr<LibraryHandleCollection> library_collection_;
+ /// Callout manager.
+ boost::shared_ptr<CalloutManager> manager_;
/// "Skip" flag, indicating if the caller should bypass remaining callouts.
bool skip_;
diff --git a/src/lib/util/hooks/callout_manager.cc b/src/lib/util/hooks/callout_manager.cc
new file mode 100644
index 0000000..1cae83f
--- /dev/null
+++ b/src/lib/util/hooks/callout_manager.cc
@@ -0,0 +1,195 @@
+// Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC 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.
+
+#include <util/hooks/callout_handle.h>
+#include <util/hooks/callout_manager.h>
+
+#include <algorithm>
+#include <functional>
+#include <utility>
+
+using namespace std;
+using namespace isc::util;
+
+namespace isc {
+namespace util {
+
+// Callout manipulation - all deferred to the CalloutManager.
+
+void
+LibraryHandle::registerCallout(const std::string& name, CalloutPtr callout) {
+ callout_manager_->registerCallout(library_index_, name, callout);
+}
+
+bool
+LibraryHandle::deregisterCallout(const std::string& name, CalloutPtr callout) {
+ return (callout_manager_->deregisterCallout(library_index_, name, callout));
+}
+
+bool
+LibraryHandle::deregisterAllCallouts(const std::string& name) {
+ return (callout_manager_->deregisterAllCallouts(library_index_, name));
+}
+
+// Register a callout for a particular library.
+
+void
+CalloutManager::registerCallout(int libindex, const std::string& name,
+ CalloutPtr callout) {
+ // Get the index associated with this hook (validating the name in the
+ // process).
+ int hook_index = hooks_->getIndex(name);
+
+ // Iterate through the callout vector for the hook from start to end,
+ // looking for the first entry where the library index is greater than
+ // the present index.
+ for (CalloutVector::iterator i = hook_vector_[hook_index].begin();
+ i != hook_vector_[hook_index].end(); ++i) {
+ if (i->first > libindex) {
+ // Found an element whose library number is greater than ours,
+ // so insert the new element ahead of this one.
+ hook_vector_[hook_index].insert(i,
+ std::make_pair(libindex, callout));
+ return;
+ }
+ }
+
+ // Reach the end of the vector, so no element in the (possibly empty)
+ // set of callouts with a library index greater that the one related to
+ // this callout, insert at the end.
+ hook_vector_[hook_index].push_back(std::make_pair(libindex, callout));
+}
+
+
+// Check if callouts are present for a given hook index.
+
+bool
+CalloutManager::calloutsPresent(int hook_index) const {
+ // Validate the hook index.
+ checkHookIndex(hook_index);
+
+ // Valid, so are there any callouts associated with that hook?
+ return (!hook_vector_[hook_index].empty());
+}
+
+// Call all the callouts for a given hook.
+
+int
+CalloutManager::callCallouts(int hook_index, CalloutHandle& callout_handle) {
+ // Validate the hook index.
+ checkHookIndex(hook_index);
+
+ // Clear the "skip" flag so we don't carry state from a previous
+ // call.
+ callout_handle.setSkip(false);
+
+ // Call all the callouts, stopping if the "skip" flag is set or if a
+ // non-zero status is returned.
+ int status = 0;
+ for (CalloutVector::const_iterator i = hook_vector_[hook_index].begin();
+ i != hook_vector_[hook_index].end() && (status == 0); ++i) {
+ status = (*i->second)(callout_handle);
+ }
+
+ return (status);
+}
+
+// Deregister a callout registered by a library on a particular hook.
+
+bool
+CalloutManager::deregisterCallout(int library_index, const std::string& name,
+ CalloutPtr callout) {
+
+ // Get the index associated with this hook (validating the name in the
+ // process).
+ int hook_index = hooks_->getIndex(name);
+
+ /// Construct a CalloutEntry matching the specified library and the callout
+ /// we want to remove.
+ CalloutEntry target(library_index, callout);
+
+ /// To decide if any entries were removed, we'll record the initial size
+ /// of the callout vector for the hook, and compare it with the size after
+ /// the removal.
+ size_t initial_size = hook_vector_[hook_index].size();
+
+ // The next bit is standard STL (see "Item 33" in "Effective STL" by
+ // Scott Meyers).
+ //
+ // remove_if reorders the hook vector so that all items not matching
+ // the predicate are at the start of the vector and returns a pointer
+ // to the next element. (In this case, the predicate is that the item
+ // is equal to the value of the passed callout.) The erase() call
+ // removes everything from that element to the end of the vector, i.e.
+ // all the matching elements.
+ hook_vector_[hook_index].erase(remove_if(hook_vector_[hook_index].begin(),
+ hook_vector_[hook_index].end(),
+ bind1st(equal_to<CalloutEntry>(),
+ target)),
+ hook_vector_[hook_index].end());
+
+ // Return an indication of whether anything was removed.
+ return (initial_size != hook_vector_[hook_index].size());
+}
+
+// Deregister all callouts on a given hook.
+
+bool
+CalloutManager::deregisterAllCallouts(int library_index,
+ const std::string& name) {
+
+ // Get the index associated with this hook (validating the name in the
+ // process).
+ int hook_index = hooks_->getIndex(name);
+
+ /// Construct a CalloutEntry matching the specified library we want to
+ /// remove (the callout pointer is NULL as we are not checking that).
+ CalloutEntry target(library_index, NULL);
+
+ /// To decide if any entries were removed, we'll record the initial size
+ /// of the callout vector for the hook, and compare it with the size after
+ /// the removal.
+ size_t initial_size = hook_vector_[hook_index].size();
+/*
+ // Remove all callouts matching this library.
+ hook_vector_[hook_index].erase(remove_if(hook_vector_[hook_index].begin(),
+ hook_vector_[hook_index].end(),
+ bind1st(CalloutLibraryEqual(),
+ target)),
+ hook_vector_[hook_index].end());
+
+ // Return an indication of whether anything was removed. */
+ return (initial_size != hook_vector_[hook_index].size());
+}
+
+// CalloutManager methods.
+
+// Return pointer to the current library handle.
+
+boost::shared_ptr<LibraryHandle>
+CalloutManager::createHandle() {
+ // Index is equal to the size of the current collection of handles
+ // (guarantees that every handle has a unique index, and that index
+ // is a pointer to the handle in the collection of handles.)
+ boost::shared_ptr<LibraryHandle> handle(new LibraryHandle(handles_.size(),
+ this));
+
+ // Add to the current collection of handles.
+ handles_.push_back(handle);
+
+ return (handle);
+}
+
+} // namespace util
+} // namespace isc
diff --git a/src/lib/util/hooks/callout_manager.h b/src/lib/util/hooks/callout_manager.h
new file mode 100644
index 0000000..f1b8d8c
--- /dev/null
+++ b/src/lib/util/hooks/callout_manager.h
@@ -0,0 +1,315 @@
+// Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC 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.
+
+#ifndef LIBRARY_HANDLE_H
+#define LIBRARY_HANDLE_H
+
+#include <exceptions/exceptions.h>
+#include <util/hooks/server_hooks.h>
+
+#include <boost/shared_ptr.hpp>
+
+#include <map>
+#include <string>
+
+namespace isc {
+namespace util {
+
+/// @brief No Such Context
+///
+/// Thrown if an attempt is made to obtain context that has not been previously
+/// set.
+
+class NoSuchLibraryContext : public Exception {
+public:
+ NoSuchLibraryContext(const char* file, size_t line, const char* what) :
+ isc::Exception(file, line, what) {}
+};
+
+/// @brief Invalid index
+///
+/// Thrown if an attempt is made to obtain a library handle but the current
+/// library handle index is invalid. This will occur if the method
+/// CalloutManager::getHandleVector() is called outside of a callout.
+
+class InvalidIndex : public Exception {
+public:
+ InvalidIndex(const char* file, size_t line, const char* what) :
+ isc::Exception(file, line, what) {}
+};
+
+// Forward declarations
+class CalloutHandle;
+class CalloutManager;
+
+/// Typedef for a callout pointer. (Callouts must have "C" linkage.)
+extern "C" {
+ typedef int (*CalloutPtr)(CalloutHandle&);
+};
+
+
+
+
+/// @brief Library handle
+///
+/// This class is used to manage a loaded library. It is used by the user
+/// library to register callouts.
+///
+/// The main processing is done by the CalloutManager class. By
+/// presenting this object to the user-library callouts, they can manage the
+/// callout list for their own library, but cannot affect the callouts registered
+/// by other libraries.
+
+class LibraryHandle {
+public:
+
+ /// @brief Constructor
+ ///
+ /// @param hooks Library index. A number (starting at 0) that represents
+ /// the index of the library in the list of libraries loaded by the
+ /// server.
+ /// @param collection Back pointer to the containing CalloutManager.
+ /// This pointer is used to access appropriate methods in the collection
+ /// object.
+ LibraryHandle(int library_index, CalloutManager* collection)
+ : library_index_(library_index), callout_manager_(collection)
+ {}
+
+ /// @brief Register a callout on a hook
+ ///
+ /// Registers a callout function with a given hook. The callout is added
+ /// to the end of the callouts for this library that are associated with
+ /// that hook.
+ ///
+ /// @param name Name of the hook to which the callout is added.
+ /// @param callout Pointer to the callout function to be registered.
+ ///
+ /// @throw NoSuchHook The hook name is unrecognised.
+ /// @throw Unexpected The hook name is valid but an internal data structure
+ /// is of the wrong size.
+ void registerCallout(const std::string& name, CalloutPtr callout);
+
+ /// @brief De-Register a callout on a hook
+ ///
+ /// Searches through the functions registered by this library with the named
+ /// hook and removes all entries matching the callout. It does not affect
+ /// callouts registered by other libraries.
+ ///
+ /// @param name Name of the hook from which the callout is removed.
+ /// @param callout Pointer to the callout function to be removed.
+ ///
+ /// @return true if a one or more callouts were deregistered.
+ ///
+ /// @throw NoSuchHook The hook name is unrecognised.
+ /// @throw Unexpected The hook name is valid but an internal data structure
+ /// is of the wrong size.
+ bool deregisterCallout(const std::string& name, CalloutPtr callout);
+
+ /// @brief Removes all callouts on a hook
+ ///
+ /// Removes all callouts associated with a given hook that were registered.
+ /// by this library. It does not affect callouts that were registered by
+ /// other libraries.
+ ///
+ /// @param name Name of the hook from which the callouts are removed.
+ ///
+ /// @return true if one or more callouts were deregistered.
+ ///
+ /// @throw NoSuchHook Thrown if the hook name is unrecognised.
+ bool deregisterAllCallouts(const std::string& name);
+
+ /// @brief Return handle index
+ ///
+ /// For test purposes only, this returns the index allocated to this
+ /// LibraryHandle.
+ ///
+ /// @return Handle index
+ int getIndex() const {
+ return (library_index_);
+ }
+
+private:
+ /// Index of this handle in the library handle list
+ int library_index_;
+
+ /// Back pointer to the collection object for the library
+ CalloutManager* callout_manager_;
+};
+
+
+/// @brief Callout Manager
+///
+/// This class manages the registration, deregistration and execution of the
+/// library callouts.
+///
+/// It is constructed using a @ref isc::util::ServerHooks object that holds the
+/// list of hooks registered for the server, which it uses to create the
+/// hook vector. This is a vector represting the callouts for each hook. Each
+/// element is itself a vector of callouts registered by the loaded libraries.
+///
+/// The class also holds the collection of library handles, used to allow the
+/// libraries to manipulate their callout list.
+
+class CalloutManager {
+private:
+
+ // Private typedefs
+
+ /// Vector of library handles.
+ typedef std::vector<boost::shared_ptr<LibraryHandle> > HandleVector;
+
+ /// Element in the vector of callouts. The elements in the pair are the
+ /// library index and the pointer to the callout.
+ typedef std::pair<int, CalloutPtr> CalloutEntry;
+
+ /// Entry in the list of callouts for an individual hook.
+ typedef std::vector<CalloutEntry> CalloutVector;
+
+public:
+
+ /// @brief Constructor
+ ///
+ /// Initializes member variables, in particular sizing the hook vector
+ /// (the vector of callouts) to the appropriate size.
+ ///
+ /// @param hook Collection of known hook names.
+ CalloutManager(const boost::shared_ptr<ServerHooks>& hooks) :
+ hooks_(hooks), handles_(), hook_vector_(hooks->getCount())
+ {}
+
+ /// @brief Register a callout on a hook
+ ///
+ /// Registers a callout function for a particular library with a given hook.
+ /// The callout is added to the end of the callouts for this library that
+ /// are associated with that hook.
+ ///
+ /// @param libindex Index of the library registering the callout
+ /// @param name Name of the hook to which the callout is added.
+ /// @param callout Pointer to the callout function to be registered.
+ ///
+ /// @throw NoSuchHook The hook name is unrecognised.
+ /// @throw Unexpected The hook name is valid but an internal data structure
+ /// is of the wrong size.
+ void registerCallout(int libindex, const std::string& name,
+ CalloutPtr callout);
+
+ /// @brief De-Register a callout on a hook
+ ///
+ /// Searches through the functions registered by the specified library with
+ /// the named hook and removes all entries matching the callout.
+ ///
+ /// @param libindex Index of the library deregistering the callout
+ /// @param name Name of the hook from which the callout is removed.
+ /// @param callout Pointer to the callout function to be removed.
+ ///
+ /// @return true if a one or more callouts were deregistered.
+ ///
+ /// @throw NoSuchHook The hook name is unrecognised.
+ /// @throw Unexpected The hook name is valid but an internal data structure
+ /// is of the wrong size.
+ bool deregisterCallout(int libindex, const std::string& name,
+ CalloutPtr callout);
+
+ /// @brief Removes all callouts on a hook
+ ///
+ /// Removes all callouts associated with a given hook that were registered
+ /// by the specified library.
+ ///
+ /// @param libindex Index of the library deregistering the callouts
+ /// @param name Name of the hook from which the callouts are removed.
+ ///
+ /// @return true if one or more callouts were deregistered.
+ ///
+ /// @throw NoSuchHook Thrown if the hook name is unrecognised.
+ bool deregisterAllCallouts(int libindex, const std::string& name);
+
+ /// @brief Checks if callouts are present on a hook
+ ///
+ /// Checks all loaded libraries and returns true if at least one callout
+ /// has been registered by any of them for the given hook.
+ ///
+ /// @param index Hook index for which callouts are checked.
+ ///
+ /// @return true if callouts are present, false if not.
+ ///
+ /// @throw NoSuchHook Given index does not correspond to a valid hook.
+ bool calloutsPresent(int index) const;
+
+ /// @brief Calls the callouts for a given hook
+ ///
+ /// Iterates through the libray handles and calls the callouts associated
+ /// with the given hook index.
+ ///
+ /// @param index Index of the hook to call.
+ /// @param callout_handle Reference to the CalloutHandle object for the
+ /// current object being processed.
+ ///
+ /// @return Status return.
+ int callCallouts(int index, CalloutHandle& callout_handle);
+
+
+ /// @brief Create library handle
+ ///
+ /// Creates a library handle. The handle is used when loading a library in
+ /// that the callouts are associated with the given library and when calling
+ /// a callout: the handle for the library can be obtained to allow dynamic
+ /// registration and de-registration.
+ boost::shared_ptr<LibraryHandle> createHandle();
+
+private:
+ /// @brief Check hook index
+ ///
+ /// Ensures that the passed hook index is valid.
+ ///
+ /// @param index Hook index to test
+ ///
+ /// @throw NoSuchHook
+ void checkHookIndex(int hook_index) const {
+ if ((hook_index < 0) || (hook_index >= hook_vector_.size())) {
+ isc_throw(NoSuchHook, "hook index " << hook_index <<
+ " is not valid for the list of registered hooks");
+ }
+ }
+
+ /// @brief Compare two callout entries for library equality
+ ///
+ /// This is used in callout removal code.
+ ///
+ /// @param ent1 First callout entry to check
+ /// @param ent2 Second callout entry to check
+ ///
+ /// @return bool true if the library entries are the same
+ class CalloutLibraryEqual {
+ public:
+ bool operator()(const CalloutEntry& ent1, const CalloutEntry& ent2) {
+ return (ent1.first == ent2.first);
+ }
+ };
+
+ /// List of server hooks. This is used
+ boost::shared_ptr<ServerHooks> hooks_;
+
+ /// Vector of pointers to library handles.
+ HandleVector handles_;
+
+ /// Vector of callout vectors. There is one entry in this outer vector for
+ /// each hook.
+ std::vector<CalloutVector> hook_vector_;
+
+};
+
+} // namespace util
+} // namespace isc
+
+#endif // LIBRARY_HANDLE_H
diff --git a/src/lib/util/hooks/library_handle.cc b/src/lib/util/hooks/library_handle.cc
deleted file mode 100644
index 1fabfc8..0000000
--- a/src/lib/util/hooks/library_handle.cc
+++ /dev/null
@@ -1,222 +0,0 @@
-// Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS. IN NO EVENT SHALL ISC 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.
-
-#include <util/hooks/callout_handle.h>
-#include <util/hooks/library_handle.h>
-
-#include <algorithm>
-#include <functional>
-
-using namespace std;
-using namespace isc::util;
-
-namespace isc {
-namespace util {
-
-// Check that an index is valid for the hook vector.
-
-void
-LibraryHandle::checkHookIndex(int index) const {
- if ((index < 0) || (index >= hook_vector_.size())) {
- isc_throw(NoSuchHook, "hook index " << index << " is invalid for the "
- " size of the hook vector (" << hook_vector_.size() << ")");
- }
-}
-
-// Get index for named hook.
-
-int
-LibraryHandle::getHookIndex(const std::string& name) const {
-
- // Get index of hook in the hook vector.
- int index = hooks_->getIndex(name);
- if (index < 0) {
- isc_throw(NoSuchHook, "unknown hook: " << name);
- } else if (index >= hook_vector_.size()) {
- isc_throw(Unexpected, "hook name " << name << " is valid, but the "
- "index returned (" << index << ") is invalid for the size of "
- "the LibraryHandle::hook_vector_ (" << hook_vector_.size() <<
- ")");
- }
-
- return (index);
-}
-
-// Register a callout for a hook, adding it to run after any previously
-// registered callouts on that hook.
-
-void
-LibraryHandle::registerCallout(const std::string& name, CalloutPtr callout) {
-
- // Get index of hook in the hook vector, validating the hook name as we
- // do so.
- int index = getHookIndex(name);
-
- // Index valid, so add the callout to the end of the list of callouts.
- hook_vector_[index].push_back(callout);
-}
-
-// Check if callouts are present for a given hook index.
-
-bool
-LibraryHandle::calloutsPresent(int index) const {
-
- // Validate the hook index.
- checkHookIndex(index);
-
- // Valid, so are there any callouts associated with that hook?
- return (!hook_vector_[index].empty());
-}
-
-// Call all the callouts for a given hook.
-
-int
-LibraryHandle::callCallouts(int index, CalloutHandle& callout_handle) {
-
- // Validate the hook index.
- checkHookIndex(index);
-
- // Call all the callouts, stopping if the "skip" flag is set or if a
- // non-zero status is returned.
- int status = 0;
- for (int i = 0;
- (i < hook_vector_[index].size()) && !callout_handle.getSkip() &&
- (status == 0);
- ++i) {
- status = (*hook_vector_[index][i])(callout_handle);
- }
-
- return (status);
-}
-
-// Deregister a callout on a given hook.
-
-void
-LibraryHandle::deregisterCallout(const std::string& name, CalloutPtr callout) {
-
- // Get the index associated with this hook (validating the name in the
- // process).
- int index = getHookIndex(name);
-
- if (!hook_vector_[index].empty()) {
- // The next bit is standard STL (see "Item 33" in "Effective STL" by
- // Scott Meyers).
- //
- // remove_if reorders the hook vector so that all items not matching
- // the predicate are at the start of the vector and returns a pointer
- // to the next element. (In this case, the predicate is that the item
- // is equal to the value of the passed callout.) The erase() call
- // removes everything from that element to the end of the vector, i.e.
- // all the matching elements.
- hook_vector_[index].erase(remove_if(hook_vector_[index].begin(),
- hook_vector_[index].end(),
- bind1st(equal_to<CalloutPtr>(),
- callout)),
- hook_vector_[index].end());
- }
-}
-
-// Deregister all callouts on a given hook.
-
-void
-LibraryHandle::deregisterAll(const std::string& name) {
-
- // Get the index associated with this hook (validating the name in the
- // process).
- int index = getHookIndex(name);
-
- // Get rid of everything.
- hook_vector_[index].clear();
-}
-
-// Return the name of all items in the library's context.
-
-vector<string>
-LibraryHandle::getContextNames() const {
-
- vector<string> names;
- ContextCollection::const_iterator i;
- for (i = context_.begin(); i != context_.end(); ++i) {
- names.push_back(i->first);
- }
-
- return (names);
-}
-
-// LibraryHandleCollection methods.
-
-// Return pointer to the current library handle.
-
-boost::shared_ptr<LibraryHandle>
-LibraryHandleCollection::getLibraryHandle() const {
- if ((curidx_ < 0) || (curidx_ >= handles_.size())) {
- isc_throw(InvalidIndex, "current library handle index of (" <<
- curidx_ << ") is not valid for the library handle vector "
- "(size = " << handles_.size() << ")");
- }
-
- return (handles_[curidx_]);
-}
-
-// Check if a any of the libraries have at least one callout present on a given
-// hook.
-
-bool
-LibraryHandleCollection::calloutsPresent(int index) const {
-
- // Method returns false if no LibraryHandles are present. Otherwise,
- // the validity of the index is checked by the calloutsPresent() method
- // on the first handle processed.
- bool present = false;
- for (int i = 0; (i < handles_.size()) && !present; ++i) {
- present = handles_[i]->calloutsPresent(index);
- }
-
- return (present);
-}
-
-// Call all the callouts for a given hook.
-
-int
-LibraryHandleCollection::callCallouts(int index,
- CalloutHandle& callout_handle) {
-
- // Don't validate the hook index here as it is checked in the call to the
- // callCallouts() method of the first library handle.
-
- // Clear the skip flag before we start so that no state from a previous
- // call of a hook accidentally leaks through.
- callout_handle.setSkip(false);
-
- // Call all the callouts, stopping if the "skip" flag is set or if a
- // non-zero status is returned. Note that we iterate using the current
- // index as the counter to allow callout handle object to retrieve the
- // current LibraryHandle.
- int status = 0;
- for (curidx_ = 0;
- (curidx_ < handles_.size()) && !callout_handle.getSkip() &&
- (status == 0);
- ++curidx_) {
- status = handles_[curidx_]->callCallouts(index, callout_handle);
- }
-
- // Reset current index to an invalid value as we are no longer calling
- // the callouts.
- curidx_ = -1;
-
- return (status);
-}
-
-} // namespace util
-} // namespace isc
diff --git a/src/lib/util/hooks/library_handle.h b/src/lib/util/hooks/library_handle.h
deleted file mode 100644
index b7ddf61..0000000
--- a/src/lib/util/hooks/library_handle.h
+++ /dev/null
@@ -1,368 +0,0 @@
-// Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS. IN NO EVENT SHALL ISC 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.
-
-#ifndef LIBRARY_HANDLE_H
-#define LIBRARY_HANDLE_H
-
-#include <exceptions/exceptions.h>
-#include <util/hooks/server_hooks.h>
-
-#include <boost/any.hpp>
-#include <boost/shared_ptr.hpp>
-
-#include <map>
-#include <string>
-
-namespace isc {
-namespace util {
-
-/// @brief No such hook
-///
-/// Thrown if an attempt is made to use an invalid hook name or hook index.
-
-class NoSuchHook : public Exception {
-public:
- NoSuchHook(const char* file, size_t line, const char* what) :
- isc::Exception(file, line, what) {}
-};
-
-/// @brief No Such Context
-///
-/// Thrown if an attempt is made to obtain context that has not been previously
-/// set.
-
-class NoSuchLibraryContext : public Exception {
-public:
- NoSuchLibraryContext(const char* file, size_t line, const char* what) :
- isc::Exception(file, line, what) {}
-};
-
-/// @brief Invalid index
-///
-/// Thrown if an attempt is made to obtain a library handle but the current
-/// library handle index is invalid. This will occur if the method
-/// LibraryHandleCollection::getLibraryHandle() is called outside of a callout.
-
-class InvalidIndex : public Exception {
-public:
- InvalidIndex(const char* file, size_t line, const char* what) :
- isc::Exception(file, line, what) {}
-};
-
-// Forward declaration for CalloutHandle
-class CalloutHandle;
-
-/// Typedef for a callout pointer. (Callouts must have "C" linkage.)
-extern "C" {
- typedef int (*CalloutPtr)(CalloutHandle&);
-};
-
-
-/// @brief Library handle
-///
-/// This class is used to manage a loaded library. It is used by the user
-/// library to register callouts and by the HookManager to call them. The
-/// class also contains storage for library-specific context.
-///
-/// The functions related to loading and unloading the asssociated library are
-/// handled in the related LibraryManager class - there is a 1:1 correspondence
-/// between LibraryManager and LibraryHandle objects. The separation prevents
-/// the user library callouts from tinkering around with the loading and
-/// unloading of libraries.
-
-class LibraryHandle {
-private:
-
- /// Typedef to allow abbreviation of iterator specification in methods
- typedef std::map<std::string, boost::any> ContextCollection;
-
-public:
-
- /// @brief Constructor
- ///
- /// This is passed the ServerHooks object, which is used both to size the
- /// internal hook vector and in the registration of callouts.
- ///
- /// @param hooks Pointer to the hooks registered by the server.
- LibraryHandle(boost::shared_ptr<ServerHooks>& hooks)
- : context_(), hooks_(hooks), hook_vector_(hooks->getCount())
- {}
-
- /// @brief Set context
- ///
- /// Sets an element in the library context. If an element of the name
- /// is already present, it is replaced.
- ///
- /// @param name Name of the element in the context to set
- /// @param value Value to set
- template <typename T>
- void setContext(const std::string& name, T value) {
- context_[name] = value;
- }
-
- /// @brief Get context
- ///
- /// Gets an element in the library context.
- ///
- /// @param name Name of the element in the context to get.
- /// @param value [out] retrieved value. The type of "value" is important:
- /// it must match the type of the value set.
- ///
- /// @throw NoSuchLibraryContext No context element with the given name
- /// is present.
- /// @throw boost::bad_any_cast The context element is present, but the
- /// type of the element does not match the type of the variable
- /// specified to receive it.
- template <typename T>
- void getContext(const std::string& name, T& value) const {
- ContextCollection::const_iterator element_ptr = context_.find(name);
- if (element_ptr == context_.end()) {
- isc_throw(NoSuchLibraryContext, "unable to find library context "
- "item " << name << " in library handle");
- }
-
- value = boost::any_cast<T>(element_ptr->second);
- }
-
- /// @brief Get context names
- ///
- /// Returns a vector holding the names of context items.
- ///
- /// @return Vector of strings reflecting argument names
- std::vector<std::string> getContextNames() const;
-
- /// @brief Delete context element
- ///
- /// Deletes context item of the given name. If an item of that name
- /// does not exist, the method is a no-op.
- ///
- /// N.B. If the element is a raw pointer, the pointed-to data is NOT deleted
- /// by this method.
- ///
- /// @param name Name of the element in the argument list to set.
- void deleteContext(const std::string& name) {
- static_cast<void>(context_.erase(name));
- }
-
- /// @brief Delete all arguments
- ///
- /// Deletes all arguments associated with this context.
- ///
- /// N.B. If any elements are raw pointers, the pointed-to data is NOT
- /// deleted by this method.
- void deleteAllContext() {
- context_.clear();
- }
-
- /// @brief Register a callout on a hook
- ///
- /// Registers a callout function with a given hook. The callout is added
- /// to the end of the callouts associated with the hook.
- ///
- /// @param name Name of the hook to which the callout is added.
- /// @param callout Pointer to the callout function to be registered.
- ///
- /// @throw NoSuchHook The hook name is unrecognised.
- /// @throw Unexpected The hook name is valid but an internal data structure
- /// is of the wrong size.
- void registerCallout(const std::string& name, CalloutPtr callout);
-
- /// @brief De-Register a callout on a hook
- ///
- /// Searches through the functions associated with the named hook and
- /// removes all entries matching the callout. If there are no matching
- /// callouts, the result is a no-op.
- ///
- /// @param name Name of the hook from which the callout is removed.
- /// @param callout Pointer to the callout function to be removed.
- ///
- /// @throw NoSuchHook The hook name is unrecognised.
- /// @throw Unexpected The hook name is valid but an internal data structure
- /// is of the wrong size.
- void deregisterCallout(const std::string& name, CalloutPtr callout);
-
- /// @brief Removes all callouts on a hook
- ///
- /// Removes all callouts associated with a given hook. This is a no-op
- /// if there are no callouts associated with the hook.
- ///
- /// @param name Name of the hook from which the callouts are removed.
- ///
- /// @throw NoSuchHook Thrown if the hook name is unrecognised.
- void deregisterAll(const std::string& name);
-
- /// @brief Checks if callouts are present on a hook
- ///
- /// @param index Hook index for which callouts are checked.
- ///
- /// @return true if callouts are present, false if not.
- ///
- /// @throw NoSuchHook Thrown if the index is not valid.
- bool calloutsPresent(int index) const;
-
- /// @brief Calls the callouts for a given hook
- ///
- /// Calls the callouts associated with the given hook index.
- ///
- /// @param index Index of the hook to call.
- /// @param callout_handle Reference to the CalloutHandle object for the
- /// current object being processed.
- ///
- /// @return Status return.
- int callCallouts(int index, CalloutHandle& callout_handle);
-
-private:
-
- /// @brief Check hook index
- ///
- /// Checks that the hook index is valid for the hook vector. If not,
- /// an exception is thrown.
- ///
- /// @param index Hooks index to check.
- ///
- /// @throw NoSuchHook The index is not valid for the hook vector (i.e.
- /// less than zero or equal to or greater than the size of the
- /// vector).
- void checkHookIndex(int index) const;
-
- /// @brief Get hook index
- ///
- /// Utility function to return the index associated with a hook name. It
- /// also checks for validity of the index: if the name is valid, the
- /// index should be valid. However, as the class only keeps a pointer to
- /// a shared ServerHooks object, it is possible that the object was modified
- /// after the hook_vector_ was sized: in this case the name could be valid
- /// but the index is invalid.
- ///
- /// @param name Name of the hook to check
- ///
- /// @return Index of the hook in the hook_vector_
- ///
- /// @throw NoSuchHook The hook name is unrecognised.
- /// @throw Unexpected Index of the hook name is not valid for the hook
- /// vector.
- int getHookIndex(const std::string& name) const;
-
- // Member variables
-
- /// Context - mapping of names variables that can be of different types.
- ContextCollection context_;
-
- /// Pointer to the list of hooks registered by the server
- boost::shared_ptr<ServerHooks> hooks_;
-
- /// Each element in the following vector corresponds to a single hook and
- /// is an ordered list of callouts for that hook.
- std::vector<std::vector<CalloutPtr> > hook_vector_;
-};
-
-
-/// @brief Collection of Library Handles
-///
-/// This simple class is a collection of handles for all libraries loaded.
-/// It is pointed to by the CalloutHandle object and is used by that object
-/// to locate the correct LibraryHandle should one be requested by a callout
-/// function.
-///
-/// To do this, the class contains an index indicating the "current" handle.
-/// This is updated during the calling of callouts: prior to calling a callout
-/// associated with a particular LibraryHandle, the index is updated to point to
-/// that handle. If the callout requests access to the LibraryHandle, it is
-/// passed a reference to the correct one.
-
-class LibraryHandleCollection {
-private:
-
- /// Private typedef to abbreviate statements in class methods.
- typedef std::vector<boost::shared_ptr<LibraryHandle> > HandleVector;
-
-public:
-
- /// @brief Constructor
- ///
- /// Initializes member variables, in particular setting the "current library
- /// handle index" to an invalid value.
- LibraryHandleCollection() : curidx_(-1), handles_()
- {}
-
- /// @brief Add library handle
- ///
- /// Adds a library handle to the collection. The collection is ordered,
- /// and this adds a library handle to the end of it.
- ///
- /// @param library_handle Pointer to the a library handle to be added.
- void addLibraryHandle(const boost::shared_ptr<LibraryHandle>& handle) {
- handles_.push_back(handle);
- }
-
- /// @brief Return current library index
- ///
- /// Returns the value of the "current library index". Although a callout
- /// callout can retrieve this information, it is of limited use: the
- /// value is intended for use by the CalloutHandle object to access the
- /// per-library context.
- ///
- /// @return Current library index value
- int getLibraryIndex() const {
- return (curidx_);
- }
-
- /// @brief Get current library handle
- ///
- /// Returns a pointer to the current library handle. This method can
- /// only be called while the code is iterating through the list of
- /// library handles: calling it at any other time is meaningless and will
- /// cause an exception to be thrown.
- ///
- /// @return Pointer to current library handle. This is the handle for the
- /// library on which the callout currently running is associated.
- boost::shared_ptr<LibraryHandle> getLibraryHandle() const;
-
- /// @brief Checks if callouts are present on a hook
- ///
- /// Checks all loaded libraries and returns true if at least one callout
- /// has been registered by any of them for the given hook.
- ///
- /// @param index Hook index for which callouts are checked.
- ///
- /// @return true if callouts are present, false if not.
- ///
- /// @throw NoSuchHook Given index does not correspond to a valid hook.
- bool calloutsPresent(int index) const;
-
- /// @brief Calls the callouts for a given hook
- ///
- /// Iterates through the libray handles and calls the callouts associated
- /// with the given hook index.
- ///
- /// @param index Index of the hook to call.
- /// @param callout_handle Reference to the CalloutHandle object for the
- /// current object being processed.
- ///
- /// @return Status return.
- int callCallouts(int index, CalloutHandle& callout_handle);
-
-private:
- /// Index of the library handle on which the currently called callout is
- /// registered.
- int curidx_;
-
- /// Vector of pointers to library handles.
- HandleVector handles_;
-};
-
-} // namespace util
-} // namespace isc
-
-#endif // LIBRARY_HANDLE_H
diff --git a/src/lib/util/hooks/server_hooks.cc b/src/lib/util/hooks/server_hooks.cc
index 1d7fcf5..9bb903b 100644
--- a/src/lib/util/hooks/server_hooks.cc
+++ b/src/lib/util/hooks/server_hooks.cc
@@ -16,6 +16,7 @@
#include <util/hooks/server_hooks.h>
#include <utility>
+#include <vector>
using namespace std;
using namespace isc;
@@ -69,9 +70,11 @@ ServerHooks::getIndex(const string& name) const {
// Get iterator to matching element.
HookCollection::const_iterator i = hooks_.find(name);
+ if (i == hooks_.end()) {
+ isc_throw(NoSuchHook, "hook name " << name << " is not recognised");
+ }
- // ... and convert this into a return value.
- return ((i == hooks_.end()) ? -1 : i->second);
+ return (i->second);
}
// Return vector of hook names. The names are not sorted - it is up to the
@@ -89,6 +92,34 @@ ServerHooks::getHookNames() const {
return (names);
}
+// Hook registration function methods
+
+// Constructor - add a registration function to the function vector
+
+HookRegistrationFunction::HookRegistrationFunction(
+ HookRegistrationFunction::RegistrationFunctionPtr reg_func) {
+ getFunctionVector().push_back(reg_func);
+}
+
+// Access the hook registration function vector itself
+
+std::vector<HookRegistrationFunction::RegistrationFunctionPtr>&
+HookRegistrationFunction::getFunctionVector() {
+ static std::vector<RegistrationFunctionPtr> reg_functions;
+ return (reg_functions);
+}
+
+// Execute all registered registration functions
+
+void
+HookRegistrationFunction::execute(ServerHooks& hooks) {
+ std::vector<RegistrationFunctionPtr>& reg_functions = getFunctionVector();
+ for (int i = 0; i < reg_functions.size(); ++i) {
+ (*reg_functions[i])(hooks);
+ }
+}
+
+
} // namespace util
} // namespace isc
diff --git a/src/lib/util/hooks/server_hooks.h b/src/lib/util/hooks/server_hooks.h
index 42bbb35..ca978f5 100644
--- a/src/lib/util/hooks/server_hooks.h
+++ b/src/lib/util/hooks/server_hooks.h
@@ -34,13 +34,22 @@ public:
isc::Exception(file, line, what) {}
};
+/// @brief Invalid hook
+///
+/// Thrown if an attempt is made to get the index for an invalid hook.
+class NoSuchHook : public Exception {
+public:
+ NoSuchHook(const char* file, size_t line, const char* what) :
+ isc::Exception(file, line, what) {}
+};
+
/// @brief Server hook collection
///
-/// This class is used by the server-side code to register hooks - points at
-/// in the server processing at which libraries can register functions
-/// (callouts) that the server will call. These functions can modify data and
-/// so affect the processing of the server.
+/// This class is used by the server-side code to register hooks - points in the
+/// server processing at which libraries can register functions (callouts) that
+/// the server will call. These functions can modify data and so affect the
+/// processing of the server.
///
/// The ServerHooks class is little more than a wrapper around the std::map
/// class. It stores a hook, assigning to it a unique index number. This
@@ -87,8 +96,9 @@ public:
///
/// @param name Name of the hook
///
- /// @return Index of the hook, to be used in subsequent calls. A value of
- /// -1 is returned if no hook of the given name is found.
+ /// @return Index of the hook, to be used in subsequent calls.
+ ///
+ /// @throw NoSuchHook if the hook name is unknown to the caller.
int getIndex(const std::string& name) const;
/// @brief Return number of hooks
@@ -113,6 +123,87 @@ private:
HookCollection hooks_; ///< Hook name/index collection
};
+
+/// @brief Hooks Registration
+///
+/// All hooks must be registered before libraries are loaded and callouts
+/// assigned to them. One way of doing this is to have a global list of hooks:
+/// the addition of any hook anywhere would require updating the list. The
+/// other way, chosen here, is to have each component in BIND 10 register the
+/// hooks they are using.
+///
+/// The chosen method requires that each component create a hook registration
+/// function of the form:
+///
+/// @code
+/// static int hook1_num = -1; // Initialize number for hook 1
+/// static int hook2_num = -1; // Initialize number for hook 2
+///
+/// void myModuleRegisterHooks(ServerHooks& hooks) {
+/// hook1_num = hooks.registerHook("hook1");
+/// hook2_num = hooks.registerHook("hook2");
+/// }
+/// @endcode
+///
+/// The server then calls each of these hook registration functions during its
+/// initialization before loading the libraries.
+///
+/// It is to avoid the need to add an explicit call to each of the hook
+/// registration functions to the server initialization code that this class
+/// has been created. Declaring an object of this class in the same file as
+/// the registration function and passing the registration function as an
+/// argument, e.g.
+///
+/// @code
+/// HookRegistrationFunction f(myModuleRegisterHooks);
+/// @code
+///
+/// is sufficient to add the registration function to a list of such functions.
+/// The server will execute all functions in the list wh3en it starts.
+
+class HookRegistrationFunction {
+public:
+ /// @brief Pointer to a hook registration function
+ typedef void (*RegistrationFunctionPtr)(ServerHooks&);
+
+ /// @brief Constructor
+ ///
+ /// For variables declared outside functions or methods, the constructors
+ /// are run after the program is loaded and before main() is called. This
+ /// constructor adds the passed pointer to a vector of such pointers.
+ HookRegistrationFunction(RegistrationFunctionPtr reg_func);
+
+ /// @brief Access registration function vector
+ ///
+ /// One of the problems with functions run prior to starting main() is the
+ /// "static initialization fiasco". This occurs because the order in which
+ /// objects outside functions is not defined. So if this constructor were
+ /// to depend on a vector declared externally, we would not be able to
+ /// guarantee that the vector had been initialised proerly before we used
+ /// it.
+ ///
+ /// To get round this situation, the vector is declared statically within
+ /// a function. The first time the function is called, the object is
+ /// initialized.
+ ///
+ /// This function returns a reference to the vector used to hold the
+ /// pointers.
+ ///
+ /// @return Reference to the (static) list of registration functions
+ static std::vector<RegistrationFunctionPtr>& getFunctionVector();
+
+ /// @brief Execute registration functions
+ ///
+ /// Called by the server initialization code, this function executes all
+ /// registered hook registration functions.
+ ///
+ /// @param hooks ServerHooks object to which hook information will be added.
+ static void execute(ServerHooks& hooks);
+};
+/// to the constructor
+/// any function
+///
+
} // namespace util
} // namespace isc
diff --git a/src/lib/util/tests/Makefile.am b/src/lib/util/tests/Makefile.am
index c968e56..55c4fa9 100644
--- a/src/lib/util/tests/Makefile.am
+++ b/src/lib/util/tests/Makefile.am
@@ -25,15 +25,15 @@ run_unittests_SOURCES = run_unittests.cc
run_unittests_SOURCES += base32hex_unittest.cc
run_unittests_SOURCES += base64_unittest.cc
run_unittests_SOURCES += buffer_unittest.cc
-run_unittests_SOURCES += callout_handle_unittest.cc
+# run_unittests_SOURCES += callout_handle_unittest.cc
+run_unittests_SOURCES += callout_manager_unittest.cc
run_unittests_SOURCES += fd_share_tests.cc
run_unittests_SOURCES += fd_tests.cc
run_unittests_SOURCES += filename_unittest.cc
run_unittests_SOURCES += hex_unittest.cc
-run_unittests_SOURCES += handles_unittest.cc
+# run_unittests_SOURCES += handles_unittest.cc
run_unittests_SOURCES += io_utilities_unittest.cc
-run_unittests_SOURCES += library_handle_unittest.cc
-run_unittests_SOURCES += library_handle_collection_unittest.cc
+# run_unittests_SOURCES += library_handle_unittest.cc
run_unittests_SOURCES += lru_list_unittest.cc
run_unittests_SOURCES += memory_segment_local_unittest.cc
if USE_SHARED_MEMORY
diff --git a/src/lib/util/tests/callout_manager_unittest.cc b/src/lib/util/tests/callout_manager_unittest.cc
new file mode 100644
index 0000000..214eec2
--- /dev/null
+++ b/src/lib/util/tests/callout_manager_unittest.cc
@@ -0,0 +1,546 @@
+// Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC 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.
+
+#include <exceptions/exceptions.h>
+#include <util/hooks/callout_handle.h>
+#include <util/hooks/callout_manager.h>
+#include <util/hooks/server_hooks.h>
+
+#include <gtest/gtest.h>
+
+#include <algorithm>
+#include <string>
+#include <vector>
+
+using namespace isc;
+using namespace isc::util;
+using namespace std;
+
+namespace {
+
+class CalloutManagerTest : public ::testing::Test {
+public:
+ /// @brief Constructor
+ ///
+ /// Sets up a collection of three LibraryHandle objects to use in the test.
+ CalloutManagerTest() : hooks_(new ServerHooks()) {
+
+ // Set up the server hooks
+ one_index_ = hooks_->registerHook("one");
+ two_index_ = hooks_->registerHook("two");
+ three_index_ = hooks_->registerHook("three");
+ four_index_ = hooks_->registerHook("four");
+
+ // Set up the callout manager with these hooks
+ callout_manager_.reset(new CalloutManager(hooks_));
+
+ // Set up four library handles.
+ library_handle_.push_back(callout_manager_->createHandle());
+ library_handle_.push_back(callout_manager_->createHandle());
+ library_handle_.push_back(callout_manager_->createHandle());
+ library_handle_.push_back(callout_manager_->createHandle());
+
+ // Set up the callout handle.
+ callout_handle_.reset(new CalloutHandle(callout_manager_));
+ }
+
+ /// @brief Return the callout handle
+ CalloutHandle& getCalloutHandle() {
+ return (*callout_handle_);
+ }
+
+ /// @brief Return the callout manager
+ boost::shared_ptr<CalloutManager> getCalloutManager() {
+ return (callout_manager_);
+ }
+
+ /// Static variable used for accumulating information
+ static int callout_value_;
+
+ /// Hook indexes. These are somewhat ubiquitous, so are made public for
+ /// ease of reference instead of being accessible by a function.
+ int one_index_;
+ int two_index_;
+ int three_index_;
+ int four_index_;
+
+private:
+ /// Callout manager used for the test
+ boost::shared_ptr<CalloutManager> callout_manager_;
+
+ /// Server hooks
+ boost::shared_ptr<ServerHooks> hooks_;
+
+ /// Set up three library handles.
+ std::vector<boost::shared_ptr<LibraryHandle> > library_handle_;
+
+ /// Callout handle used in calls
+ boost::shared_ptr<CalloutHandle> callout_handle_;
+
+};
+
+// Definition of the static variable.
+int CalloutManagerTest::callout_value_ = 0;
+
+// *** Callout Tests ***
+//
+// The next set of tests check that callouts can be called.
+
+// The callouts defined here are structured in such a way that it is possible
+// to determine the order in which they are called and whether they are called
+// at all. The method used is simple - after a sequence of callouts, the digits
+// in the value, reading left to right, determines the order of the callouts
+// called. For example, callout one followed by two followed by three followed
+// by two followed by one results in a value of 12321.
+//
+// Functions return a zero to indicate success.
+
+extern "C" {
+int manager_general(int number) {
+ CalloutManagerTest::callout_value_ =
+ 10 * CalloutManagerTest::callout_value_ + number;
+ return (0);
+}
+
+int manager_one(CalloutHandle&) {
+ return (manager_general(1));
+}
+
+int manager_two(CalloutHandle&) {
+ return (manager_general(2));
+}
+
+int manager_three(CalloutHandle&) {
+ return (manager_general(3));
+}
+
+int manager_four(CalloutHandle&) {
+ return (manager_general(4));
+}
+
+int manager_five(CalloutHandle&) {
+ return (manager_general(5));
+}
+
+int manager_six(CalloutHandle&) {
+ return (manager_general(6));
+}
+
+int manager_seven(CalloutHandle&) {
+ return (manager_general(7));
+}
+
+// The next functions are duplicates of some of the above, but return an error.
+
+int manager_one_error(CalloutHandle& handle) {
+ (void) manager_one(handle);
+ return (1);
+}
+
+int manager_two_error(CalloutHandle& handle) {
+ (void) manager_two(handle);
+ return (1);
+}
+
+int manager_three_error(CalloutHandle& handle) {
+ (void) manager_three(handle);
+ return (1);
+}
+
+int manager_four_error(CalloutHandle& handle) {
+ (void) manager_four(handle);
+ return (1);
+}
+
+}; // extern "C"
+
+// Check we can register callouts appropriately.
+
+TEST_F(CalloutManagerTest, RegisterCallout) {
+ // Ensure that no callouts are attached to any of the hooks.
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(one_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(two_index_));
+
+ // Set up so that hooks "one" and "two" have callouts attached from a
+ // single library.
+
+ getCalloutManager()->registerCallout(0, "one", manager_one);
+ getCalloutManager()->registerCallout(1, "two", manager_two);
+
+ // Check all is as expected.
+ EXPECT_TRUE(getCalloutManager()->calloutsPresent(one_index_));
+ EXPECT_TRUE(getCalloutManager()->calloutsPresent(two_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(three_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(four_index_));
+
+ int status = 0;
+
+ // Check that calling the callouts returns as expected.
+ callout_value_ = 0;
+ status = getCalloutManager()->callCallouts(one_index_, getCalloutHandle());
+ EXPECT_EQ(0, status);
+ EXPECT_EQ(1, callout_value_);
+
+ callout_value_ = 0;
+ status = getCalloutManager()->callCallouts(two_index_, getCalloutHandle());
+ EXPECT_EQ(0, status);
+ EXPECT_EQ(2, callout_value_);
+
+ // Register some more callouts from different libraries on hook 1.
+ getCalloutManager()->registerCallout(2, "one", manager_three);
+ getCalloutManager()->registerCallout(2, "one", manager_four);
+ getCalloutManager()->registerCallout(3, "one", manager_five);
+
+ // Check it is as expected.
+ callout_value_ = 0;
+ status = getCalloutManager()->callCallouts(one_index_, getCalloutHandle());
+ EXPECT_EQ(0, status);
+ EXPECT_EQ(1345, callout_value_);
+
+ callout_value_ = 0;
+ status = getCalloutManager()->callCallouts(two_index_, getCalloutHandle());
+ EXPECT_EQ(0, status);
+ EXPECT_EQ(2, callout_value_);
+
+ // Add another callout to hook one from library iindex 2 - this should
+ // appear at the end of the callout list for that library.
+ getCalloutManager()->registerCallout(2, "one", manager_six);
+ callout_value_ = 0;
+ status = getCalloutManager()->callCallouts(one_index_, getCalloutHandle());
+ EXPECT_EQ(0, status);
+ EXPECT_EQ(13465, callout_value_);
+
+ // Add a callout from library index 1 - this should appear between the
+ // callouts from library index 0 and linrary index 2.
+ getCalloutManager()->registerCallout(1, "one", manager_seven);
+ callout_value_ = 0;
+ status = getCalloutManager()->callCallouts(one_index_, getCalloutHandle());
+ EXPECT_EQ(0, status);
+ EXPECT_EQ(173465, callout_value_);
+
+
+}
+
+// Check the "calloutsPresent()" method.
+
+TEST_F(CalloutManagerTest, CalloutsPresent) {
+ // Ensure that no callouts are attached to any of the hooks.
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(one_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(two_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(three_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(four_index_));
+
+ // Set up so that hooks "one", "two" and "four" have callouts attached
+ // to them, and callout "three" does not. (In the statements below, the
+ // exact callouts attached to a hook are not relevant - only the fact
+ // that some callouts are). Chose the libraries for which the callouts
+ // are registered randomly.
+
+ getCalloutManager()->registerCallout(0, "one", manager_one);
+
+ getCalloutManager()->registerCallout(1, "one", manager_two);
+ getCalloutManager()->registerCallout(1, "two", manager_two);
+
+ getCalloutManager()->registerCallout(3, "one", manager_three);
+ getCalloutManager()->registerCallout(3, "four", manager_four);
+
+ // Check all is as expected.
+ EXPECT_TRUE(getCalloutManager()->calloutsPresent(one_index_));
+ EXPECT_TRUE(getCalloutManager()->calloutsPresent(two_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(three_index_));
+ EXPECT_TRUE(getCalloutManager()->calloutsPresent(four_index_));
+
+ // Check we fail on an invalid index.
+ EXPECT_THROW(getCalloutManager()->calloutsPresent(42), NoSuchHook);
+ EXPECT_THROW(getCalloutManager()->calloutsPresent(-1), NoSuchHook);
+}
+
+// Test that calling a hook with no callouts on it returns success.
+
+TEST_F(CalloutManagerTest, CallNoCallouts) {
+ // Ensure that no callouts are attached to any of the hooks.
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(one_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(two_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(three_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(four_index_));
+
+ // Call the callouts on an arbitrary hook and ensure that nothing happens.
+ callout_value_ = 475;
+ int status = getCalloutManager()->callCallouts(one_index_,
+ getCalloutHandle());
+ EXPECT_EQ(0, status);
+ EXPECT_EQ(475, callout_value_); // Unchanged
+}
+
+// Test that the callouts are called in the correct order.
+
+TEST_F(CalloutManagerTest, CallCalloutsSuccess) {
+ // Ensure that no callouts are attached to any of the hooks.
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(one_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(two_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(three_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(four_index_));
+
+ int status = 0;
+
+ // Each library contributes one callout on hook "one".
+ callout_value_ = 0;
+ getCalloutManager()->registerCallout(0, "one", manager_one);
+ getCalloutManager()->registerCallout(1, "one", manager_two);
+ getCalloutManager()->registerCallout(2, "one", manager_three);
+ getCalloutManager()->registerCallout(3, "one", manager_four);
+ status = getCalloutManager()->callCallouts(one_index_, getCalloutHandle());
+ EXPECT_EQ(0, status);
+ EXPECT_EQ(1234, callout_value_);
+
+ // Do a random selection of callouts on hook "two".
+ callout_value_ = 0;
+ getCalloutManager()->registerCallout(0, "two", manager_one);
+ getCalloutManager()->registerCallout(0, "two", manager_three);
+ getCalloutManager()->registerCallout(1, "two", manager_two);
+ getCalloutManager()->registerCallout(3, "two", manager_four);
+ status = getCalloutManager()->callCallouts(two_index_, getCalloutHandle());
+ EXPECT_EQ(0, status);
+ EXPECT_EQ(1324, callout_value_);
+
+ // Ensure that calling the callouts on a hook with no callouts works.
+ callout_value_ = 0;
+ status = getCalloutManager()->callCallouts(three_index_,
+ getCalloutHandle());
+ EXPECT_EQ(0, status);
+ EXPECT_EQ(0, callout_value_);
+}
+
+// Test that the callouts are called in order, but that callouts occurring
+// after a callout that returns an error are not called.
+//
+// (Note: in this test, the callouts that return an error set the value of
+// callout_value_ before they return the error code.)
+
+TEST_F(CalloutManagerTest, CallCalloutsError) {
+ // Ensure that no callouts are attached to any of the hooks.
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(one_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(two_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(three_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(four_index_));
+
+ int status = 0;
+
+ // Each library contributing one callout on hook "one". The first callout
+ // returns an error (after adding its value to the result).
+ callout_value_ = 0;
+ getCalloutManager()->registerCallout(0, "one", manager_one_error);
+ getCalloutManager()->registerCallout(1, "one", manager_two);
+ getCalloutManager()->registerCallout(2, "one", manager_three);
+ getCalloutManager()->registerCallout(3, "one", manager_four);
+ status = getCalloutManager()->callCallouts(one_index_, getCalloutHandle());
+ EXPECT_EQ(1, status);
+ EXPECT_EQ(1, callout_value_);
+
+ // Each library contributing multiple callouts on hook "two". The last
+ // callout on the first library returns an error.
+ callout_value_ = 0;
+ getCalloutManager()->registerCallout(0, "two", manager_one);
+ getCalloutManager()->registerCallout(0, "two", manager_one_error);
+ getCalloutManager()->registerCallout(1, "two", manager_two);
+ getCalloutManager()->registerCallout(1, "two", manager_two);
+ getCalloutManager()->registerCallout(1, "two", manager_three);
+ getCalloutManager()->registerCallout(1, "two", manager_three);
+ getCalloutManager()->registerCallout(3, "two", manager_four);
+ getCalloutManager()->registerCallout(3, "two", manager_four);
+ status = getCalloutManager()->callCallouts(two_index_, getCalloutHandle());
+ EXPECT_EQ(1, status);
+ EXPECT_EQ(11, callout_value_);
+
+ // A callout in a random position in the callout list returns an error.
+ callout_value_ = 0;
+ getCalloutManager()->registerCallout(0, "three", manager_one);
+ getCalloutManager()->registerCallout(0, "three", manager_one);
+ getCalloutManager()->registerCallout(1, "three", manager_two);
+ getCalloutManager()->registerCallout(1, "three", manager_two);
+ getCalloutManager()->registerCallout(3, "three", manager_four_error);
+ getCalloutManager()->registerCallout(3, "three", manager_four);
+ status = getCalloutManager()->callCallouts(three_index_,
+ getCalloutHandle());
+ EXPECT_EQ(1, status);
+ EXPECT_EQ(11224, callout_value_);
+
+ // The last callout on a hook returns an error.
+ callout_value_ = 0;
+ getCalloutManager()->registerCallout(0, "four", manager_one);
+ getCalloutManager()->registerCallout(0, "four", manager_one);
+ getCalloutManager()->registerCallout(1, "four", manager_two);
+ getCalloutManager()->registerCallout(1, "four", manager_two);
+ getCalloutManager()->registerCallout(2, "four", manager_three);
+ getCalloutManager()->registerCallout(2, "four", manager_three);
+ getCalloutManager()->registerCallout(3, "four", manager_four);
+ getCalloutManager()->registerCallout(3, "four", manager_four_error);
+ status = getCalloutManager()->callCallouts(four_index_, getCalloutHandle());
+ EXPECT_EQ(1, status);
+ EXPECT_EQ(11223344, callout_value_);
+}
+
+// Now test that we can deregister a single callout on a hook.
+
+TEST_F(CalloutManagerTest, DeregisterSingleCallout) {
+ // Ensure that no callouts are attached to any of the hooks.
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(one_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(two_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(three_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(four_index_));
+
+ int status = 0;
+
+ // Each library contributes one callout on hook "one".
+ callout_value_ = 0;
+ getCalloutManager()->registerCallout(0, "one", manager_two);
+ status = getCalloutManager()->callCallouts(one_index_, getCalloutHandle());
+ EXPECT_EQ(0, status);
+ EXPECT_EQ(2, callout_value_);
+
+ // Remove it and check that the no callouts are present.
+ EXPECT_TRUE(getCalloutManager()->calloutsPresent(one_index_));
+ EXPECT_TRUE(getCalloutManager()->deregisterCallout(0, "one", manager_two));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(one_index_));
+}
+
+// Now test that we can deregister a single callout on a hook that has multiple
+// callouts from the same library.
+
+TEST_F(CalloutManagerTest, DeregisterSingleCalloutSameLibrary) {
+ // Ensure that no callouts are attached to any of the hooks.
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(one_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(two_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(three_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(four_index_));
+
+ int status = 0;
+
+ // Each library contributes one callout on hook "one".
+ callout_value_ = 0;
+ getCalloutManager()->registerCallout(0, "one", manager_one);
+ getCalloutManager()->registerCallout(0, "one", manager_two);
+ getCalloutManager()->registerCallout(0, "one", manager_three);
+ getCalloutManager()->registerCallout(0, "one", manager_four);
+ status = getCalloutManager()->callCallouts(one_index_, getCalloutHandle());
+ EXPECT_EQ(0, status);
+ EXPECT_EQ(1234, callout_value_);
+
+ // Remove the manager_two callout.
+ EXPECT_TRUE(getCalloutManager()->deregisterCallout(0, "one", manager_two));
+ callout_value_ = 0;
+ status = getCalloutManager()->callCallouts(one_index_, getCalloutHandle());
+ EXPECT_EQ(0, status);
+ EXPECT_EQ(134, callout_value_);
+
+ // Try removing it again.
+ EXPECT_FALSE(getCalloutManager()->deregisterCallout(0, "one", manager_two));
+ callout_value_ = 0;
+ status = getCalloutManager()->callCallouts(one_index_, getCalloutHandle());
+ EXPECT_EQ(0, status);
+ EXPECT_EQ(134, callout_value_);
+
+}
+
+// Check we can deregister multiple callouts from the same library.
+
+TEST_F(CalloutManagerTest, DeregisterMultipleCalloutsSameLibrary) {
+ // Ensure that no callouts are attached to any of the hooks.
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(one_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(two_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(three_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(four_index_));
+
+ int status = 0;
+
+ // Each library contributes one callout on hook "one".
+ callout_value_ = 0;
+ getCalloutManager()->registerCallout(0, "one", manager_one);
+ getCalloutManager()->registerCallout(0, "one", manager_one);
+ getCalloutManager()->registerCallout(0, "one", manager_two);
+ getCalloutManager()->registerCallout(0, "one", manager_two);
+ getCalloutManager()->registerCallout(0, "one", manager_three);
+ getCalloutManager()->registerCallout(0, "one", manager_three);
+ getCalloutManager()->registerCallout(0, "one", manager_four);
+ getCalloutManager()->registerCallout(0, "one", manager_four);
+ status = getCalloutManager()->callCallouts(one_index_, getCalloutHandle());
+ EXPECT_EQ(0, status);
+ EXPECT_EQ(11223344, callout_value_);
+
+ // Remove the manager_two callout.
+ EXPECT_TRUE(getCalloutManager()->deregisterCallout(0, "one", manager_two));
+ callout_value_ = 0;
+ status = getCalloutManager()->callCallouts(one_index_, getCalloutHandle());
+ EXPECT_EQ(0, status);
+ EXPECT_EQ(113344, callout_value_);
+
+ // Try removing multiple callouts from the end of the list.
+ EXPECT_TRUE(getCalloutManager()->deregisterCallout(0, "one", manager_four));
+ callout_value_ = 0;
+ status = getCalloutManager()->callCallouts(one_index_, getCalloutHandle());
+ EXPECT_EQ(0, status);
+ EXPECT_EQ(1133, callout_value_);
+
+ // ... and from the start.
+ EXPECT_TRUE(getCalloutManager()->deregisterCallout(0, "one", manager_one));
+ callout_value_ = 0;
+ status = getCalloutManager()->callCallouts(one_index_, getCalloutHandle());
+ EXPECT_EQ(0, status);
+ EXPECT_EQ(33, callout_value_);
+
+ // ... and the remaining callouts.
+ EXPECT_TRUE(getCalloutManager()->deregisterCallout(0, "one",
+ manager_three));
+ callout_value_ = 0;
+ status = getCalloutManager()->callCallouts(one_index_, getCalloutHandle());
+ EXPECT_EQ(0, status);
+ EXPECT_EQ(0, callout_value_);
+
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(one_index_));
+}
+
+// Check we can deregister multiple callouts from multiple libraries
+
+TEST_F(CalloutManagerTest, DeregisterMultipleCalloutsMultipleLibraries) {
+ // Ensure that no callouts are attached to any of the hooks.
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(one_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(two_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(three_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(four_index_));
+
+ int status = 0;
+
+ // Each library contributes two callouts to hook "one".
+ callout_value_ = 0;
+ getCalloutManager()->registerCallout(0, "one", manager_one);
+ getCalloutManager()->registerCallout(0, "one", manager_two);
+ getCalloutManager()->registerCallout(1, "one", manager_three);
+ getCalloutManager()->registerCallout(1, "one", manager_four);
+ getCalloutManager()->registerCallout(2, "one", manager_five);
+ getCalloutManager()->registerCallout(2, "one", manager_two);
+ status = getCalloutManager()->callCallouts(one_index_, getCalloutHandle());
+ EXPECT_EQ(0, status);
+ EXPECT_EQ(123452, callout_value_);
+
+ // Remove the manager_two callout from library 0. It should not affect
+ // the second manager_two callout.
+ EXPECT_TRUE(getCalloutManager()->deregisterCallout(0, "one", manager_two));
+ callout_value_ = 0;
+ status = getCalloutManager()->callCallouts(one_index_, getCalloutHandle());
+ EXPECT_EQ(0, status);
+ EXPECT_EQ(13452, callout_value_);
+}
+
+
+} // Anonymous namespace
diff --git a/src/lib/util/tests/handles_unittest.cc b/src/lib/util/tests/handles_unittest.cc
index cb0ac1b..34ecc51 100644
--- a/src/lib/util/tests/handles_unittest.cc
+++ b/src/lib/util/tests/handles_unittest.cc
@@ -23,18 +23,15 @@
#include <string>
/// @file
-/// CalloutHandle/LibraryCalloutHandle interaction tests
+/// CalloutHandle/LibraryHandle interaction tests
///
/// This file holds unit tests checking the interaction between the
-/// CalloutHandle and LibraryCalloutHandle[Collection] classes. In particular,
+/// CalloutHandle and LibraryHandle[Collection] classes. In particular,
/// they check that:
///
/// - A CalloutHandle's context is shared between callouts from the same
/// library, but there is a separate context for each library.
///
-/// - The LibraryHandle retrieved by the CalloutHandle is the same for each
-/// callout in the library, but different for different libraries.
-///
/// - The various methods manipulating the items in the CalloutHandle's context
/// work correctly.
///
@@ -49,32 +46,17 @@ namespace {
// The next set of functions define the callouts used by the tests. They
// manipulate the data in such a way that callouts called - and the order in
// which they were called - can be determined. The functions also check that
-// the "callout context" and "library context" data areas are separate.
+// the "callout context" data areas are separate.
//
// Three libraries are assumed, and each supplies four callouts. All callouts
-// manipulate four context elements - two in the CalloutHandle and two in the
-// LibraryHandle, the elements being called "string" and "int" (which describe
-// the type of data manipulated).
+// manipulate two context elements the CalloutHandle, the elements being called
+// "string" and "int" (which describe the type of data manipulated).
//
// For the string item, each callout shifts data to the left and inserts its own
-// data. The data is a string of the form "nmwc", where "n" is the number of
-// the library, "m" is the callout number and "w" is an indication of what is
-// being altered (library context ["x"] or callout context ["c"]) and "y" is the
-// indication of what callout was passed as an argument ("a" or "b" - "" is
-// entered if no argument is supplied). ("x" is used instead of "l" to indicate
-// that library context is being altered since in the results, these single
-// characters will be mixed with digits and "l" " looks too much like "1".)
-// Hence we have:
-//
-// - "xa" if library context is being altered from a callout made with the
-// first callout handle indicator passed as argument.
-// - "xb" if library context is being altered from a callout made with the
-// second callout handle indicator passed as argument.
-// - "x" if library context is being altered and no argument is set.
-// - "ca" if the first callout handle's context is being manipulated.
-// - "cb" if the second callout handle's context is being manipulated.
-// - "c" if the a callout handle's context is being manipulated and it is not
-// possible to identify the callout handle.
+// data. The data is a string of the form "nmc", where "n" is the number of
+// the library, "m" is the callout number and "y" is the indication of what
+// callout handle was passed as an argument ("1" or "2": "0" is used when no
+// identification has been set in the callout handle).
//
// For simplicity, and to cut down the number of functions actually written,
// the callout indicator ("a" or "b") ) used in the in the CalloutHandle
@@ -85,14 +67,7 @@ namespace {
// For integer data, the value starts at zero and an increment is added on each
// call. This increment is equal to:
//
-// 1000 * library number + 100 * callout_number + 10 * lib/callout + indicator
-//
-// where "lib/callout" is 1 if a library context is updated and 2 if a
-// callout context is changed. "indicator" is 1 for callout a, 2 for callout
-// b and 0 if unknown. This scheme gives a direct correspondence between the
-// characters appended to the string context item and the amount by which the
-// integer context item is incremented. For example, the string "21cb"
-// corresponds to a value of 2122.
+// 100 * library number + 10 * callout number + callout handle
//
// Although this gives less information than the string value, the reasons for
// using it are:
@@ -102,19 +77,6 @@ namespace {
// - It provides an item that can be deleted by the context deletion
// methods.
-// Values set in the LibraryHandle context. There are three libraries, so
-// there are three sets of library context. To avoid a static initialization
-// fiasco, encapsulate these in a function.
-
-std::string& resultLibraryString(int index) {
- static std::string result_library_string[3];
- return (result_library_string[index]);
-}
-
-int& resultLibraryInt(int index) {
- static int result_library_int[3];
- return (result_library_int[index]);
-}
// Values set in the CalloutHandle context. There are three libraries, so
// there are three contexts for the callout, one for each library.
@@ -133,8 +95,6 @@ int& resultCalloutInt(int index) {
static void zero_results() {
for (int i = 0; i < 3; ++i) {
- resultLibraryString(i) = "";
- resultLibraryInt(i) = 0;
resultCalloutString(i) = "";
resultCalloutInt(i) = 0;
}
@@ -143,79 +103,54 @@ static void zero_results() {
// Library callouts.
-// Common code for setting the callout and library context values.
+// Common code for setting the callout context values.
int
execute(CalloutHandle& callout_handle, int library_num, int callout_num) {
- // Obtain the callout handle indicator and set a number for it.
- string sindicator = "";
- int indicator = 0;
+ // Obtain the callout handle number
+ int handle_num = 0;
try {
- callout_handle.getArgument("string", sindicator);
- indicator = (sindicator == "a") ? 1 : 2;
+ callout_handle.getArgument("handle_num", handle_num);
} catch (const NoSuchArgument&) {
- indicator = 0;
+ // handle_num argument not set: this is the case in the tests where
+ // the context_create hook check is tested.
+ handle_num = 0;
}
// Create the basic data to be appended to the context value.
- int idata = 1000 * library_num + 100 * callout_num;
- string sdata = boost::lexical_cast<string>(10 * library_num + callout_num);
-
- // Get the library context data. As the context will not exist on the
- // first call, catch the exception and create it. (In real life, the context
- // should have been created by the libraries' "load()" function.)
- string string_value = "";
- try {
- callout_handle.getLibraryHandle().getContext("string", string_value);
- } catch (const NoSuchLibraryContext&) {
- string_value = "";
- }
-
- int int_value = 0;
- try {
- callout_handle.getLibraryHandle().getContext("int", int_value);
- } catch (const NoSuchLibraryContext&) {
- int_value = 0;
- }
-
- // Update the context value with the library/callout indication (and the
- // suffix "x" to denote library) and set it.
- string_value += (sdata + string("x") + sindicator);
- callout_handle.getLibraryHandle().setContext("string", string_value);
-
- int_value += (idata + 10 + indicator);
- callout_handle.getLibraryHandle().setContext("int", int_value);
+ int idata = 100 * library_num + 10 * callout_num + handle_num;
+ string sdata = boost::lexical_cast<string>(idata);
// Get the context data. As before, this will not exist for the first
// callout called. (In real life, the library should create it when the
// "context_create" hook gets called before any packet processing takes
// place.)
- string_value = "";
+ int int_value = 0;
try {
- callout_handle.getContext("string", string_value);
+ callout_handle.getContext("int", int_value);
} catch (const NoSuchCalloutContext&) {
- string_value = "";
+ int_value = 0;
}
- int_value = 0;
+ string string_value = "";
try {
- callout_handle.getContext("int", int_value);
+ callout_handle.getContext("string", string_value);
} catch (const NoSuchCalloutContext&) {
- int_value = 0;
+ string_value = "";
}
// Update the values and set them.
- string_value += (sdata + string("c") + sindicator);
- callout_handle.setContext("string", string_value);
-
- int_value += (idata + 20 + indicator);
+ int_value += idata;
callout_handle.setContext("int", int_value);
+ string_value += sdata;
+ callout_handle.setContext("string", string_value);
+
return (0);
}
-// The following functions are the actual callouts - ther name is of the
+// The following functions are the actual callouts - the name is of the
// form "callout_<library number>_<callout number>"
int
@@ -268,15 +203,6 @@ callout33(CalloutHandle& callout_handle) {
// variables.
int printExecute(CalloutHandle& callout_handle, int library_num) {
-
- // Print per-library context values.
- callout_handle.getLibraryHandle()
- .getContext("string", resultLibraryString(library_num - 1));
- callout_handle.getLibraryHandle()
- .getContext("int", resultLibraryInt(library_num - 1));
-
-
- // Print callout context.
callout_handle.getContext("string", resultCalloutString(library_num - 1));
callout_handle.getContext("int", resultCalloutInt(library_num - 1));
@@ -300,12 +226,11 @@ print3(CalloutHandle& callout_handle) {
return (printExecute(callout_handle, 3));
}
-// This test checks the many-faced nature of the context for both the
-// CalloutContext and the LibraryContext.
+// This test checks the many-faced nature of the context for the CalloutContext.
TEST(HandlesTest, ContextAccessCheck) {
- // Create the LibraryHandleCollection with a set of four callouts
- // (the test does not use the context_create and context_destroy callouts.)
+ // Create the LibraryHandleCollection with a set of four callouts (the test
+ // does not use the context_create and context_destroy callouts).
boost::shared_ptr<ServerHooks> server_hooks(new ServerHooks());
const int one_index = server_hooks->registerHook("one");
@@ -338,113 +263,81 @@ TEST(HandlesTest, ContextAccessCheck) {
handle->registerCallout("four", print3);
collection->addLibraryHandle(handle);
- // Create the callout handles and distinguish them by setting the "long"
- // argument.
- CalloutHandle callout_handle_a(collection);
- callout_handle_a.setArgument("string", string("a"));
+ // Create the callout handles and distinguish them by setting the
+ // "handle_num" argument.
+ CalloutHandle callout_handle_1(collection);
+ callout_handle_1.setArgument("handle_num", static_cast<int>(1));
- CalloutHandle callout_handle_b(collection);
- callout_handle_b.setArgument("string", string("b"));
+ CalloutHandle callout_handle_2(collection);
+ callout_handle_2.setArgument("handle_num", static_cast<int>(2));
// Now call the callouts attached to the first three hooks. Each hook is
// called twice (once for each callout handle) before the next hook is
// called.
- collection->callCallouts(one_index, callout_handle_a);
- collection->callCallouts(one_index, callout_handle_b);
- collection->callCallouts(two_index, callout_handle_a);
- collection->callCallouts(two_index, callout_handle_b);
- collection->callCallouts(three_index, callout_handle_a);
- collection->callCallouts(three_index, callout_handle_b);
+ collection->callCallouts(one_index, callout_handle_1);
+ collection->callCallouts(one_index, callout_handle_2);
+ collection->callCallouts(two_index, callout_handle_1);
+ collection->callCallouts(two_index, callout_handle_2);
+ collection->callCallouts(three_index, callout_handle_1);
+ collection->callCallouts(three_index, callout_handle_2);
// Get the results for each callout. Explicitly zero the variables before
// getting the results so we are certain that the values are the results
// of the callouts.
zero_results();
- collection->callCallouts(four_index, callout_handle_a);
-
- // To explain the expected library context results:
- //
- // The first callCallouts() call above calls the callouts for hook "one"
- // with callout handle "a". This calls the callout attached to hook "one"
- // from library 1, then that attached to hook "one" from library 2, then
- // from library 3. The callout in library 1 appends "11xa" to the first
- // library's context. The callout in library 2 appends "21xa" to its
- // library's context. Finally, the third library's context gets "31xa"
- // appended to it.
- //
- // The next callCallouts() call repeats the calls to the callouts attached
- // to hook "one", which result in "11xb", "21xb", "31xb" being appended to
- // the context of libraries 1, 2, and 3 respectively.
- //
- // The process is then repeated for hooks "two" and "three", leading to
- // the expected context values listed below.
- //
- // The expected integer values can be found by summing up the values
- // corresponding to the elements of the strings.
-
- EXPECT_EQ("11xa11xb12xa12xb13xa13xb", resultLibraryString(0));
- EXPECT_EQ("21xa21xb22xa22xb23xa23xb", resultLibraryString(1));
- EXPECT_EQ("31xa31xb32xa32xb33xa33xb", resultLibraryString(2));
-
- EXPECT_EQ((1111 + 1112 + 1211 + 1212 + 1311 + 1312), resultLibraryInt(0));
- EXPECT_EQ((2111 + 2112 + 2211 + 2212 + 2311 + 2312), resultLibraryInt(1));
- EXPECT_EQ((3111 + 3112 + 3211 + 3212 + 3311 + 3312), resultLibraryInt(2));
+ collection->callCallouts(four_index, callout_handle_1);
// To explain the expected callout context results.
//
// The callout handle maintains a separate context for each library. When
- // the first call to callCallouts() is made, "11ca" gets appended to
- // the context for library 1 maintained by by the callout handle, "21ca"
- // gets appended to the context maintained for library 2, and "31ca" to
- // the context maintained for library 3.
+ // the first call to callCallouts() is made, "111" gets appended to
+ // the context for library 1 maintained by by the callout handle, "211"
+ // gets appended to the context maintained for library 2, and "311" to
+ // the context maintained for library 3. In each case, the first digit
+ // corresponds to the library number, the second to the callout number and
+ // the third to the "handle_num" of the callout handle. For the first call
+ // to callCallouts, handle 1 is used, so the last digit is always 1.
//
- // The next call to callCallouts() calls the same callouts but for a
- // different callout handle. It also maintains three contexts (one for
- // each library) and they will get "11cb", "21cb", "31cb" appended to
- // them. These don't affect the contexts maintained by callout handle a.
+ // The next call to callCallouts() calls the same callouts but for the
+ // second callout handle. It also maintains three contexts (one for
+ // each library) and they will get "112", "212", "312" appended to
+ // them. The explanation for the digits is the same as before, except that
+ // in this case, the callout handle is number 2, so the third digit is
+ // always 2. These additions don't affect the contexts maintained by
+ // callout handle 1.
//
- // The process is then repeated for hooks "two" and "three", which append
- // "12ca", "22ca" and "32ca" for hook "two" and "31ca", "32ca" and "33ca"
- // for hook "three".
+ // The process is then repeated for hooks "two" and "three" which, for
+ // callout handle 1, append "121", "221" and "321" for hook "two" and "311",
+ // "321" and "331" for hook "three".
//
// The expected integer values can be found by summing up the values
// corresponding to the elements of the strings.
// At this point, we have only called the "print" function for callout
- // handle "a", so the following results are checking the context values
+ // handle "1", so the following results are checking the context values
// maintained in that callout handle.
- EXPECT_EQ("11ca12ca13ca", resultCalloutString(0));
- EXPECT_EQ("21ca22ca23ca", resultCalloutString(1));
- EXPECT_EQ("31ca32ca33ca", resultCalloutString(2));
+ EXPECT_EQ("111121131", resultCalloutString(0));
+ EXPECT_EQ("211221231", resultCalloutString(1));
+ EXPECT_EQ("311321331", resultCalloutString(2));
- EXPECT_EQ((1121 + 1221 + 1321), resultCalloutInt(0));
- EXPECT_EQ((2121 + 2221 + 2321), resultCalloutInt(1));
- EXPECT_EQ((3121 + 3221 + 3321), resultCalloutInt(2));
+ EXPECT_EQ((111 + 121 + 131), resultCalloutInt(0));
+ EXPECT_EQ((211 + 221 + 231), resultCalloutInt(1));
+ EXPECT_EQ((311 + 321 + 331), resultCalloutInt(2));
- // Repeat the checks for callout b. The library handle context values
- // should not change, but the context maintained by the callout handle
- // should.
+ // Repeat the checks for callout 2.
zero_results();
- collection->callCallouts(four_index, callout_handle_b);
-
- EXPECT_EQ("11xa11xb12xa12xb13xa13xb", resultLibraryString(0));
- EXPECT_EQ("21xa21xb22xa22xb23xa23xb", resultLibraryString(1));
- EXPECT_EQ("31xa31xb32xa32xb33xa33xb", resultLibraryString(2));
+ collection->callCallouts(four_index, callout_handle_2);
- EXPECT_EQ((1111 + 1112 + 1211 + 1212 + 1311 + 1312), resultLibraryInt(0));
- EXPECT_EQ((2111 + 2112 + 2211 + 2212 + 2311 + 2312), resultLibraryInt(1));
- EXPECT_EQ((3111 + 3112 + 3211 + 3212 + 3311 + 3312), resultLibraryInt(2));
+ EXPECT_EQ((112 + 122 + 132), resultCalloutInt(0));
+ EXPECT_EQ((212 + 222 + 232), resultCalloutInt(1));
+ EXPECT_EQ((312 + 322 + 332), resultCalloutInt(2));
- EXPECT_EQ("11cb12cb13cb", resultCalloutString(0));
- EXPECT_EQ("21cb22cb23cb", resultCalloutString(1));
- EXPECT_EQ("31cb32cb33cb", resultCalloutString(2));
-
- EXPECT_EQ((1122 + 1222 + 1322), resultCalloutInt(0));
- EXPECT_EQ((2122 + 2222 + 2322), resultCalloutInt(1));
- EXPECT_EQ((3122 + 3222 + 3322), resultCalloutInt(2));
+ EXPECT_EQ("112122132", resultCalloutString(0));
+ EXPECT_EQ("212222232", resultCalloutString(1));
+ EXPECT_EQ("312322332", resultCalloutString(2));
}
// Now repeat the test, but add a deletion callout to the list. The "two"
@@ -544,76 +437,53 @@ TEST(HandlesTest, ContextDeletionCheck) {
// Create the callout handles and distinguish them by setting the "long"
// argument.
- CalloutHandle callout_handle_a(collection);
- callout_handle_a.setArgument("string", string("a"));
+ CalloutHandle callout_handle_1(collection);
+ callout_handle_1.setArgument("handle_num", static_cast<int>(1));
- CalloutHandle callout_handle_b(collection);
- callout_handle_b.setArgument("string", string("b"));
+ CalloutHandle callout_handle_2(collection);
+ callout_handle_2.setArgument("handle_num", static_cast<int>(2));
// Now call the callouts attached to the first three hooks. Each hook is
// called twice (once for each callout handle) before the next hook is
// called.
- collection->callCallouts(one_index, callout_handle_a);
- collection->callCallouts(one_index, callout_handle_b);
- collection->callCallouts(two_index, callout_handle_a);
- collection->callCallouts(two_index, callout_handle_b);
- collection->callCallouts(three_index, callout_handle_a);
- collection->callCallouts(three_index, callout_handle_b);
+ collection->callCallouts(one_index, callout_handle_1);
+ collection->callCallouts(one_index, callout_handle_2);
+ collection->callCallouts(two_index, callout_handle_1);
+ collection->callCallouts(two_index, callout_handle_2);
+ collection->callCallouts(three_index, callout_handle_1);
+ collection->callCallouts(three_index, callout_handle_2);
// Get the results for each callout. Explicitly zero the variables before
// getting the results so we are certain that the values are the results
// of the callouts.
zero_results();
- collection->callCallouts(four_index, callout_handle_a);
+ collection->callCallouts(four_index, callout_handle_1);
// The logic by which the expected results are arrived at is described
// in the ContextAccessCheck test. The results here are different
// because context items have been modified along the way.
- //
- // As only the ContextHandle context is modified, the LibraryHandle
- // context is unaltered from the values obtained in the previous test.
-
- EXPECT_EQ("11xa11xb12xa12xb13xa13xb", resultLibraryString(0));
- EXPECT_EQ("21xa21xb22xa22xb23xa23xb", resultLibraryString(1));
- EXPECT_EQ("31xa31xb32xa32xb33xa33xb", resultLibraryString(2));
-
- EXPECT_EQ((1111 + 1112 + 1211 + 1212 + 1311 + 1312), resultLibraryInt(0));
- EXPECT_EQ((2111 + 2112 + 2211 + 2212 + 2311 + 2312), resultLibraryInt(1));
- EXPECT_EQ((3111 + 3112 + 3211 + 3212 + 3311 + 3312), resultLibraryInt(2));
- // ContextHandle context results.
+ EXPECT_EQ((111 + 121 + 131), resultCalloutInt(0));
+ EXPECT_EQ(( 231), resultCalloutInt(1));
+ EXPECT_EQ(( 331), resultCalloutInt(2));
- EXPECT_EQ("11ca12ca13ca", resultCalloutString(0));
- EXPECT_EQ("21ca22ca23ca", resultCalloutString(1));
- EXPECT_EQ( "33ca", resultCalloutString(2));
+ EXPECT_EQ("111121131", resultCalloutString(0));
+ EXPECT_EQ("211221231", resultCalloutString(1));
+ EXPECT_EQ( "331", resultCalloutString(2));
- EXPECT_EQ((1121 + 1221 + 1321), resultCalloutInt(0));
- EXPECT_EQ(( 2321), resultCalloutInt(1));
- EXPECT_EQ(( 3321), resultCalloutInt(2));
-
- // Repeat the checks for callout b. The library handle context values
- // should not change, but the context maintained by the callout handle
- // should.
+ // Repeat the checks for callout handle 2.
zero_results();
- collection->callCallouts(four_index, callout_handle_b);
-
- EXPECT_EQ("11xa11xb12xa12xb13xa13xb", resultLibraryString(0));
- EXPECT_EQ("21xa21xb22xa22xb23xa23xb", resultLibraryString(1));
- EXPECT_EQ("31xa31xb32xa32xb33xa33xb", resultLibraryString(2));
-
- EXPECT_EQ((1111 + 1112 + 1211 + 1212 + 1311 + 1312), resultLibraryInt(0));
- EXPECT_EQ((2111 + 2112 + 2211 + 2212 + 2311 + 2312), resultLibraryInt(1));
- EXPECT_EQ((3111 + 3112 + 3211 + 3212 + 3311 + 3312), resultLibraryInt(2));
+ collection->callCallouts(four_index, callout_handle_2);
- EXPECT_EQ("11cb12cb13cb", resultCalloutString(0));
- EXPECT_EQ("21cb22cb23cb", resultCalloutString(1));
- EXPECT_EQ( "33cb", resultCalloutString(2));
+ EXPECT_EQ((112 + 122 + 132), resultCalloutInt(0));
+ EXPECT_EQ(( 232), resultCalloutInt(1));
+ EXPECT_EQ(( 332), resultCalloutInt(2));
- EXPECT_EQ((1122 + 1222 + 1322), resultCalloutInt(0));
- EXPECT_EQ(( 2322), resultCalloutInt(1));
- EXPECT_EQ(( 3322), resultCalloutInt(2));
+ EXPECT_EQ("112122132", resultCalloutString(0));
+ EXPECT_EQ("212222232", resultCalloutString(1));
+ EXPECT_EQ( "332", resultCalloutString(2));
// ... and check what the names of the context items are after the callouts
// for hook "two". We know they are in sorted order.
@@ -660,8 +530,8 @@ TEST(HandlesTest, ConstructionDestructionCallouts) {
boost::shared_ptr<CalloutHandle>
callout_handle(new CalloutHandle(collection));
- EXPECT_EQ("11x", resultLibraryString(0));
- EXPECT_EQ(1110, resultLibraryInt(0));
+ EXPECT_EQ("110", resultCalloutString(0));
+ EXPECT_EQ(110, resultCalloutInt(0));
// Check that the destructor callout runs. Note that the "print1" callout
// didn't destroy the library context - it only copied it to where it
@@ -670,8 +540,8 @@ TEST(HandlesTest, ConstructionDestructionCallouts) {
zero_results();
callout_handle.reset();
- EXPECT_EQ("11x12x", resultLibraryString(0));
- EXPECT_EQ((1110 + 1210), resultLibraryInt(0));
+ EXPECT_EQ("110120", resultCalloutString(0));
+ EXPECT_EQ((110 + 120), resultCalloutInt(0));
// Test that the destructor throws an error if the context_destroy
// callout returns an error.
diff --git a/src/lib/util/tests/library_handle_collection_unittest.cc b/src/lib/util/tests/library_handle_collection_unittest.cc
deleted file mode 100644
index 953c300..0000000
--- a/src/lib/util/tests/library_handle_collection_unittest.cc
+++ /dev/null
@@ -1,447 +0,0 @@
-// Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS. IN NO EVENT SHALL ISC 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.
-
-#include <exceptions/exceptions.h>
-#include <util/hooks/callout_handle.h>
-#include <util/hooks/library_handle.h>
-#include <util/hooks/server_hooks.h>
-
-#include <gtest/gtest.h>
-
-#include <algorithm>
-#include <string>
-#include <vector>
-
-using namespace isc;
-using namespace isc::util;
-using namespace std;
-
-namespace {
-
-/// @brief No such hook
-///
-/// Thrown if an attempt it made to obtain an invalid library handle.
-class InvalidIndex : public isc::Exception {
-public:
- InvalidIndex(const char* file, size_t line, const char* what) :
- isc::Exception(file, line, what) {}
-};
-
-class LibraryHandleCollectionTest : public ::testing::Test {
-public:
- /// @brief Constructor
- ///
- /// Sets up a collection of three LibraryHandle objects to use in the test.
- LibraryHandleCollectionTest()
- : collection_(new LibraryHandleCollection()), handles_(),
- hooks_(new ServerHooks()) {
-
- // Set up the server hooks
- hooks_->registerHook("one");
- hooks_->registerHook("two");
- hooks_->registerHook("three");
- hooks_->registerHook("four");
-
- // Set up the library handles and collection.
- for (int i = 0; i < 4; ++i) {
- boost::shared_ptr<LibraryHandle> handle(new LibraryHandle(hooks_));
- handles_.push_back(handle);
- collection_->addLibraryHandle(handle);
- }
-
- callout_value_ = 0;
- }
-
- /// @brief Obtain constructed server hooks
- ///
- /// @return Reference to shared pointer pointing to server hooks object.
- boost::shared_ptr<ServerHooks>& getServerHooks() {
- return (hooks_);
- }
-
- /// @brief Obtain LibraryHandleCollection object
- ///
- /// @return Reference to shared pointer pointing to handle collection
- boost::shared_ptr<LibraryHandleCollection>& getLibraryHandleCollection() {
- return (collection_);
- }
-
- /// @brief Obtain individual LibraryHandle.
- ///
- /// @param i Index of the library handle required.
- ///
- /// @return Reference to shared pointer pointing to the relevant handle.
- ///
- /// @throws InvalidIndex if the requested index is not valid.
- boost::shared_ptr<LibraryHandle>& getLibraryHandle(int i) {
- if ((i < 0) || (i >= handles_.size())) {
- isc_throw(InvalidIndex, "handle index of " << i << " not valid for "
- " size of handle vector (" << handles_.size() << ")");
- }
- return (handles_[i]);
- }
-
- /// Variable for callouts test. This is public and static to allow non-
- /// member functions to access it. It is initialized every time a
- /// new test starts.
- static int callout_value_;
-
-private:
-
- /// Library handle collection and the individual handles (as the
- /// collection has no method for accessing an individual member).
- boost::shared_ptr<LibraryHandleCollection> collection_;
- std::vector<boost::shared_ptr<LibraryHandle> > handles_;
-
- /// Server hooks and hooks manager
- boost::shared_ptr<ServerHooks> hooks_;
-};
-
-// Definition of the static variable.
-int LibraryHandleCollectionTest::callout_value_ = 0;
-
-// *** Callout Tests ***
-//
-// The next set of tests check that callouts can be called.
-
-// The callouts defined here are structured in such a way that it is possible
-// to determine the order in which they are called and whether they are called
-// at all. The method used is simple - after a sequence of callouts, the digits
-// in the value, reading left to right, determines the order of the callouts
-// called. For example, callout one followed by two followed by three followed
-// by two followed by one results in a value of 12321.
-//
-// Functions return a zero to indicate success.
-
-extern "C" {
-int collection_one(CalloutHandle&) {
- LibraryHandleCollectionTest::callout_value_ =
- 10 * LibraryHandleCollectionTest::callout_value_ + 1;
- return (0);
-}
-
-int collection_two(CalloutHandle&) {
- LibraryHandleCollectionTest::callout_value_ =
- 10 * LibraryHandleCollectionTest::callout_value_ + 2;
- return (0);
-}
-
-int collection_three(CalloutHandle&) {
- LibraryHandleCollectionTest::callout_value_ =
- 10 * LibraryHandleCollectionTest::callout_value_ + 3;
- return (0);
-}
-
-int collection_four(CalloutHandle&) {
- LibraryHandleCollectionTest::callout_value_ =
- 10 * LibraryHandleCollectionTest::callout_value_ + 4;
- return (0);
-}
-
-// The next functions are duplicates of the above, but return an error.
-
-int collection_one_error(CalloutHandle& handle) {
- (void) collection_one(handle);
- return (1);
-}
-
-int collection_two_error(CalloutHandle& handle) {
- (void) collection_two(handle);
- return (1);
-}
-
-int collection_three_error(CalloutHandle& handle) {
- (void) collection_three(handle);
- return (1);
-}
-
-int collection_four_error(CalloutHandle& handle) {
- (void) collection_four(handle);
- return (1);
-}
-
-// The next functions are duplicates of the above, but set the skip flag.
-
-int collection_one_skip(CalloutHandle& handle) {
- handle.setSkip(true);
- return (collection_one(handle));
-}
-
-int collection_two_skip(CalloutHandle& handle) {
- handle.setSkip(true);
- return (collection_two(handle));
-}
-
-int collection_three_skip(CalloutHandle& handle) {
- handle.setSkip(true);
- return (collection_three(handle));
-}
-
-int collection_four_skip(CalloutHandle& handle) {
- handle.setSkip(true);
- return (collection_four(handle));
-}
-
-}; // extern "C"
-
-// Check the "calloutsPresent()" method.
-//
-// Note: as we needed to use the addHandleMethod() to set up the handles to
-// which the callouts are attached, this can also be construed as a test
-// of the addLibraryHandle method as well.
-
-TEST_F(LibraryHandleCollectionTest, CalloutsPresent) {
- const int one_index = getServerHooks()->getIndex("one");
- const int two_index = getServerHooks()->getIndex("two");
- const int three_index = getServerHooks()->getIndex("three");
- const int four_index = getServerHooks()->getIndex("four");
-
- // Ensure that no callouts are attached to any of the hooks.
- EXPECT_FALSE(getLibraryHandleCollection()->calloutsPresent(one_index));
- EXPECT_FALSE(getLibraryHandleCollection()->calloutsPresent(two_index));
- EXPECT_FALSE(getLibraryHandleCollection()->calloutsPresent(three_index));
- EXPECT_FALSE(getLibraryHandleCollection()->calloutsPresent(four_index));
-
- // Set up so that hooks "one", "two" and "four" have callouts attached
- // to them, and callout "three" does not. (In the statements below, the
- // exact callouts attached to a hook are not relevant - only the fact
- // that some callouts are).
-
- getLibraryHandle(0)->registerCallout("one", collection_one);
-
- getLibraryHandle(1)->registerCallout("one", collection_two);
- getLibraryHandle(1)->registerCallout("two", collection_two);
-
- getLibraryHandle(3)->registerCallout("one", collection_four);
- getLibraryHandle(3)->registerCallout("four", collection_two);
-
- // Check all is as expected.
- EXPECT_TRUE(getLibraryHandleCollection()->calloutsPresent(one_index));
- EXPECT_TRUE(getLibraryHandleCollection()->calloutsPresent(two_index));
- EXPECT_FALSE(getLibraryHandleCollection()->calloutsPresent(three_index));
- EXPECT_TRUE(getLibraryHandleCollection()->calloutsPresent(four_index));
-
- // Check we fail on an invalid index.
- EXPECT_THROW(getLibraryHandleCollection()->calloutsPresent(42), NoSuchHook);
- EXPECT_THROW(getLibraryHandleCollection()->calloutsPresent(-1), NoSuchHook);
-
- // Check we get a negative result on an empty collection.
- LibraryHandleCollection empty_collection;
- EXPECT_FALSE(empty_collection.calloutsPresent(-1));
-}
-
-// Test that the callouts are called in the correct order.
-
-TEST_F(LibraryHandleCollectionTest, CallCalloutsSuccess) {
- const int one_index = getServerHooks()->getIndex("one");
- const int two_index = getServerHooks()->getIndex("two");
- const int three_index = getServerHooks()->getIndex("three");
- const int four_index = getServerHooks()->getIndex("four");
-
- // Ensure that no callouts are attached to any of the hooks.
- EXPECT_FALSE(getLibraryHandleCollection()->calloutsPresent(one_index));
- EXPECT_FALSE(getLibraryHandleCollection()->calloutsPresent(two_index));
- EXPECT_FALSE(getLibraryHandleCollection()->calloutsPresent(three_index));
- EXPECT_FALSE(getLibraryHandleCollection()->calloutsPresent(four_index));
-
- // Set up different sequences of callouts on different handles.
- CalloutHandle callout_handle(getLibraryHandleCollection());
- int status;
-
- // Each library contributing one callout on hook "one".
- callout_value_ = 0;
- getLibraryHandle(0)->registerCallout("one", collection_one);
- getLibraryHandle(1)->registerCallout("one", collection_two);
- getLibraryHandle(2)->registerCallout("one", collection_three);
- getLibraryHandle(3)->registerCallout("one", collection_four);
- status = getLibraryHandleCollection()->callCallouts(one_index,
- callout_handle);
- EXPECT_EQ(0, status);
- EXPECT_EQ(1234, callout_value_);
-
- // Do a random selection of callouts on hook "two".
- callout_value_ = 0;
- getLibraryHandle(0)->registerCallout("two", collection_one);
- getLibraryHandle(0)->registerCallout("two", collection_one);
- getLibraryHandle(1)->registerCallout("two", collection_two);
- getLibraryHandle(3)->registerCallout("two", collection_four);
- status = getLibraryHandleCollection()->callCallouts(two_index,
- callout_handle);
- EXPECT_EQ(0, status);
- EXPECT_EQ(1124, callout_value_);
-
- // Ensure that calling the callouts on a hook with no callouts works.
- callout_value_ = 0;
- status = getLibraryHandleCollection()->callCallouts(three_index,
- callout_handle);
- EXPECT_EQ(0, status);
- EXPECT_EQ(0, callout_value_);
-}
-
-// Test that the callouts are called in order, but that callouts occurring
-// after a callout that returns an error are not called.
-//
-// (Note: in this test, the callouts that return an error set the value of
-// callout_value_ before they return the error code.)
-
-TEST_F(LibraryHandleCollectionTest, CallCalloutsError) {
- const int one_index = getServerHooks()->getIndex("one");
- const int two_index = getServerHooks()->getIndex("two");
- const int three_index = getServerHooks()->getIndex("three");
- const int four_index = getServerHooks()->getIndex("four");
-
- // Ensure that no callouts are attached to any of the hooks.
- EXPECT_FALSE(getLibraryHandleCollection()->calloutsPresent(one_index));
- EXPECT_FALSE(getLibraryHandleCollection()->calloutsPresent(two_index));
- EXPECT_FALSE(getLibraryHandleCollection()->calloutsPresent(three_index));
- EXPECT_FALSE(getLibraryHandleCollection()->calloutsPresent(four_index));
-
- // Set up different sequences of callouts on different handles.
- CalloutHandle callout_handle(getLibraryHandleCollection());
- int status;
-
- // Each library contributing one callout on hook "one". The first callout
- // returns an error.
- callout_value_ = 0;
- getLibraryHandle(0)->registerCallout("one", collection_one_error);
- getLibraryHandle(1)->registerCallout("one", collection_two);
- getLibraryHandle(2)->registerCallout("one", collection_three);
- getLibraryHandle(3)->registerCallout("one", collection_four);
- status = getLibraryHandleCollection()->callCallouts(one_index,
- callout_handle);
- EXPECT_EQ(1, status);
- EXPECT_EQ(1, callout_value_);
-
- // Each library contributing multiple callouts on hook "two". The last
- // callout on the first library returns an error.
- callout_value_ = 0;
- getLibraryHandle(0)->registerCallout("two", collection_one);
- getLibraryHandle(0)->registerCallout("two", collection_one_error);
- getLibraryHandle(1)->registerCallout("two", collection_two);
- getLibraryHandle(1)->registerCallout("two", collection_two);
- getLibraryHandle(1)->registerCallout("two", collection_three);
- getLibraryHandle(1)->registerCallout("two", collection_three);
- getLibraryHandle(3)->registerCallout("two", collection_four);
- getLibraryHandle(3)->registerCallout("two", collection_four);
- status = getLibraryHandleCollection()->callCallouts(two_index,
- callout_handle);
- EXPECT_EQ(1, status);
- EXPECT_EQ(11, callout_value_);
-
- // A callout in a random position in the callout list returns an error.
- callout_value_ = 0;
- getLibraryHandle(0)->registerCallout("three", collection_one);
- getLibraryHandle(0)->registerCallout("three", collection_one);
- getLibraryHandle(1)->registerCallout("three", collection_two);
- getLibraryHandle(1)->registerCallout("three", collection_two);
- getLibraryHandle(3)->registerCallout("three", collection_four_error);
- getLibraryHandle(3)->registerCallout("three", collection_four);
- status = getLibraryHandleCollection()->callCallouts(three_index,
- callout_handle);
- EXPECT_EQ(1, status);
- EXPECT_EQ(11224, callout_value_);
-
- // The last callout on a hook returns an error.
- callout_value_ = 0;
- getLibraryHandle(0)->registerCallout("four", collection_one);
- getLibraryHandle(0)->registerCallout("four", collection_one);
- getLibraryHandle(1)->registerCallout("four", collection_two);
- getLibraryHandle(1)->registerCallout("four", collection_two);
- getLibraryHandle(2)->registerCallout("four", collection_three);
- getLibraryHandle(2)->registerCallout("four", collection_three);
- getLibraryHandle(3)->registerCallout("four", collection_four);
- getLibraryHandle(3)->registerCallout("four", collection_four_error);
- status = getLibraryHandleCollection()->callCallouts(four_index,
- callout_handle);
- EXPECT_EQ(1, status);
- EXPECT_EQ(11223344, callout_value_);
-}
-
-// Same test as CallCalloutsSucess, but with functions returning a "skip"
-// instead.
-
-TEST_F(LibraryHandleCollectionTest, CallCalloutsSkip) {
- const int one_index = getServerHooks()->getIndex("one");
- const int two_index = getServerHooks()->getIndex("two");
- const int three_index = getServerHooks()->getIndex("three");
- const int four_index = getServerHooks()->getIndex("four");
-
- // Ensure that no callouts are attached to any of the hooks.
- EXPECT_FALSE(getLibraryHandleCollection()->calloutsPresent(one_index));
- EXPECT_FALSE(getLibraryHandleCollection()->calloutsPresent(two_index));
- EXPECT_FALSE(getLibraryHandleCollection()->calloutsPresent(three_index));
- EXPECT_FALSE(getLibraryHandleCollection()->calloutsPresent(four_index));
-
- // Set up different sequences of callouts on different handles.
- CalloutHandle callout_handle(getLibraryHandleCollection());
- int status;
-
- // Each library contributing one callout on hook "one". The first callout
- // sets the "skip" flag.
- callout_value_ = 0;
- getLibraryHandle(0)->registerCallout("one", collection_one_skip);
- getLibraryHandle(1)->registerCallout("one", collection_two);
- getLibraryHandle(2)->registerCallout("one", collection_three);
- getLibraryHandle(3)->registerCallout("one", collection_four);
- status = getLibraryHandleCollection()->callCallouts(one_index,
- callout_handle);
- EXPECT_EQ(0, status);
- EXPECT_EQ(1, callout_value_);
-
- // Each library contributing multiple callouts on hook "two". The last
- // callout on the first library sets the "skip" flag.
- callout_value_ = 0;
- getLibraryHandle(0)->registerCallout("two", collection_one);
- getLibraryHandle(0)->registerCallout("two", collection_one_skip);
- getLibraryHandle(1)->registerCallout("two", collection_two);
- getLibraryHandle(1)->registerCallout("two", collection_two);
- getLibraryHandle(1)->registerCallout("two", collection_three);
- getLibraryHandle(1)->registerCallout("two", collection_three);
- getLibraryHandle(3)->registerCallout("two", collection_four);
- getLibraryHandle(3)->registerCallout("two", collection_four);
- status = getLibraryHandleCollection()->callCallouts(two_index,
- callout_handle);
- EXPECT_EQ(0, status);
- EXPECT_EQ(11, callout_value_);
-
- // A callout in a random position in the callout list sets the "skip" flag.
- callout_value_ = 0;
- getLibraryHandle(0)->registerCallout("three", collection_one);
- getLibraryHandle(0)->registerCallout("three", collection_one);
- getLibraryHandle(1)->registerCallout("three", collection_two);
- getLibraryHandle(1)->registerCallout("three", collection_two);
- getLibraryHandle(3)->registerCallout("three", collection_four_skip);
- getLibraryHandle(3)->registerCallout("three", collection_four);
- status = getLibraryHandleCollection()->callCallouts(three_index,
- callout_handle);
- EXPECT_EQ(0, status);
- EXPECT_EQ(11224, callout_value_);
-
- // The last callout on a hook sets the "skip" flag.
- callout_value_ = 0;
- getLibraryHandle(0)->registerCallout("four", collection_one);
- getLibraryHandle(0)->registerCallout("four", collection_one);
- getLibraryHandle(1)->registerCallout("four", collection_two);
- getLibraryHandle(1)->registerCallout("four", collection_two);
- getLibraryHandle(2)->registerCallout("four", collection_three);
- getLibraryHandle(2)->registerCallout("four", collection_three);
- getLibraryHandle(3)->registerCallout("four", collection_four);
- getLibraryHandle(3)->registerCallout("four", collection_four_skip);
- status = getLibraryHandleCollection()->callCallouts(four_index,
- callout_handle);
- EXPECT_EQ(0, status);
- EXPECT_EQ(11223344, callout_value_);
-}
-
-} // Anonymous namespace
diff --git a/src/lib/util/tests/library_handle_unittest.cc b/src/lib/util/tests/library_handle_unittest.cc
index 912c244..f8e54aa 100644
--- a/src/lib/util/tests/library_handle_unittest.cc
+++ b/src/lib/util/tests/library_handle_unittest.cc
@@ -33,12 +33,11 @@ public:
///
/// Sets up an appropriate number of server hooks to pass to the
/// constructed callout handle objects.
- LibraryHandleTest()
- : hooks_(new ServerHooks()),
- collection_(new LibraryHandleCollection()) {
+ LibraryHandleTest() : hooks_(new ServerHooks()) {
hooks_->registerHook("alpha");
hooks_->registerHook("beta");
hooks_->registerHook("gamma");
+ collection_.reset(new LibraryHandleCollection(hooks_));
// Also initialize the variable used to pass information back from the
// callouts to the tests.
@@ -63,239 +62,13 @@ public:
private:
boost::shared_ptr<ServerHooks> hooks_;
boost::shared_ptr<LibraryHandleCollection> collection_;
+ boost::shared_ptr<LibraryHandle> handle_0_;
+ boost::shared_ptr<LibraryHandle> handle_1_;
};
// Definition of the static variable.
int LibraryHandleTest::callout_value = 0;
-// *** Context Tests ***
-//
-// The first set of tests check that the LibraryHandle can store and retrieve
-// context.
-
-// Test that we can store multiple values of the same type and that they are
-// distinct.
-
-TEST_F(LibraryHandleTest, ContextDistinctSimpleType) {
- LibraryHandle handle(getServerHooks());
-
- // Store and retrieve an int (random value).
- int a = 42;
- handle.setContext("integer1", a);
- EXPECT_EQ(42, a);
-
- int b = 0;
- handle.getContext("integer1", b);
- EXPECT_EQ(42, b);
-
- // Add another integer (another random value).
- int c = 142;
- handle.setContext("integer2", c);
- EXPECT_EQ(142, c);
-
- int d = 0;
- handle.getContext("integer2", d);
- EXPECT_EQ(142, d);
-
- // Add a short (random value).
- short e = -81;
- handle.setContext("short", e);
- EXPECT_EQ(-81, e);
-
- short f = 0;
- handle.getContext("short", f);
- EXPECT_EQ(-81, f);
-}
-
-// Test that trying to get something with an incorrect name throws an
-// exception.
-
-TEST_F(LibraryHandleTest, ContextUnknownName) {
- LibraryHandle handle(getServerHooks());
-
- // Set an integer
- int a = 42;
- handle.setContext("integer1", a);
- EXPECT_EQ(42, a);
-
- // Check we can retrieve it
- int b = 0;
- handle.getContext("integer1", b);
- EXPECT_EQ(42, b);
-
- // Check that getting an unknown name throws an exception.
- int c = -1;
- EXPECT_THROW(handle.getContext("unknown", c), NoSuchLibraryContext);
-}
-
-// Test that trying to get something with an incorrect type throws an exception.
-
-TEST_F(LibraryHandleTest, ContextIncorrectType) {
- LibraryHandle handle(getServerHooks());
-
- // Set an integer
- int a = 42;
- handle.setContext("integer1", a);
- EXPECT_EQ(42, a);
-
- // Check we can't retrieve it using a variable of the wrong type.
- long b = 0;
- EXPECT_THROW(handle.getContext("integer1", b), boost::bad_any_cast);
-}
-
-// Now try with some very complex types. The types cannot be defined within
-// the function and they should contain a copy constructor. For this reason,
-// a simple "struct" is used.
-
-struct Alpha {
- int a;
- int b;
- Alpha(int first = 0, int second = 0) : a(first), b(second) {}
-};
-
-struct Beta {
- int c;
- int d;
- Beta(int first = 0, int second = 0) : c(first), d(second) {}
-};
-
-TEST_F(LibraryHandleTest, ComplexTypes) {
- LibraryHandle handle(getServerHooks());
-
- // Declare two variables of different (complex) types. (Note as to the
- // variable names: aleph and beth are the first two letters of the Hebrew
- // alphabet.)
- Alpha aleph(1, 2);
- EXPECT_EQ(1, aleph.a);
- EXPECT_EQ(2, aleph.b);
- handle.setContext("aleph", aleph);
-
- Beta beth(11, 22);
- EXPECT_EQ(11, beth.c);
- EXPECT_EQ(22, beth.d);
- handle.setContext("beth", beth);
-
- // Ensure we can extract the data correctly
- Alpha aleph2;
- EXPECT_EQ(0, aleph2.a);
- EXPECT_EQ(0, aleph2.b);
- handle.getContext("aleph", aleph2);
- EXPECT_EQ(1, aleph2.a);
- EXPECT_EQ(2, aleph2.b);
-
- Beta beth2;
- EXPECT_EQ(0, beth2.c);
- EXPECT_EQ(0, beth2.d);
- handle.getContext("beth", beth2);
- EXPECT_EQ(11, beth2.c);
- EXPECT_EQ(22, beth2.d);
-
- // Ensure that complex types also thrown an exception if we attempt to
- // get a context element of the wrong type.
- EXPECT_THROW(handle.getContext("aleph", beth), boost::bad_any_cast);
-}
-
-// Check that the context can store pointers. Also check that it respects
-// that a "pointer to X" is not the same as a "pointer to const X".
-
-TEST_F(LibraryHandleTest, PointerTypes) {
- LibraryHandle handle(getServerHooks());
-
- // Declare a couple of variables, const and non-const.
- Alpha aleph(5, 10);
- const Beta beth(15, 20);
-
- Alpha* pa = ℵ
- const Beta* pcb = ℶ
-
- // Check pointers can be set and retrieved OK
- handle.setContext("non_const_pointer", pa);
- handle.setContext("const_pointer", pcb);
-
- Alpha* pa2 = 0;
- handle.getContext("non_const_pointer", pa2);
- EXPECT_TRUE(pa == pa2);
-
- const Beta* pcb2 = 0;
- handle.getContext("const_pointer", pcb2);
- EXPECT_TRUE(pcb == pcb2);
-
- // Check that the "const" is protected in the context.
- const Alpha* pca3;
- EXPECT_THROW(handle.getContext("non_const_pointer", pca3),
- boost::bad_any_cast);
-
- Beta* pb3;
- EXPECT_THROW(handle.getContext("const_pointer", pb3),
- boost::bad_any_cast);
-}
-
-// Check that we can get the names of the context items.
-
-TEST_F(LibraryHandleTest, ContextItemNames) {
- LibraryHandle handle(getServerHooks());
-
- vector<string> expected_names;
- int value = 42;
-
- expected_names.push_back("faith");
- handle.setContext("faith", value++);
- expected_names.push_back("hope");
- handle.setContext("hope", value++);
- expected_names.push_back("charity");
- handle.setContext("charity", value++);
-
- // Get the names and check against the expected names. We'll sort
- // both arrays to simplify the checking.
- vector<string> actual_names = handle.getContextNames();
-
- sort(actual_names.begin(), actual_names.end());
- sort(expected_names.begin(), expected_names.end());
- EXPECT_TRUE(expected_names == actual_names);
-}
-
-// Check that we can delete one item of context.
-
-TEST_F(LibraryHandleTest, DeleteContext) {
- LibraryHandle handle(getServerHooks());
-
- int value = 42;
- handle.setContext("faith", value++);
- handle.setContext("hope", value++);
-
- // Delete "faith" and verify that getting it throws an exception
- handle.deleteContext("faith");
- EXPECT_THROW(handle.getContext("faith", value), NoSuchLibraryContext);
-
- // Check that the other item is untouched.
- value = 0;
- EXPECT_NO_THROW(handle.getContext("hope", value));
- EXPECT_EQ(43, value);
-}
-
-// Check we can delete all all items of context.
-
-TEST_F(LibraryHandleTest, DeleteAllContext) {
- LibraryHandle handle(getServerHooks());
-
- int value = 42;
- handle.setContext("faith", value++);
- handle.setContext("hope", value++);
- handle.setContext("charity", value++);
-
- // Delete all items of context and verify that they are gone.
- handle.deleteAllContext();
-
- value = 0;
- EXPECT_THROW(handle.getContext("faith", value), NoSuchLibraryContext);
- EXPECT_THROW(handle.getContext("hope", value), NoSuchLibraryContext);
- EXPECT_THROW(handle.getContext("charity", value), NoSuchLibraryContext);
-}
-
-
-
-// *** Callout Tests ***
-//
// The next set of tests check that callouts can be registered.
// The callouts defined here are structured in such a way that it is possible
diff --git a/src/lib/util/tests/server_hooks_unittest.cc b/src/lib/util/tests/server_hooks_unittest.cc
index 478c28f..287c4fe 100644
--- a/src/lib/util/tests/server_hooks_unittest.cc
+++ b/src/lib/util/tests/server_hooks_unittest.cc
@@ -60,7 +60,7 @@ TEST(ServerHooksTest, RegisterHooks) {
EXPECT_EQ(4, hooks.getCount());
}
-// Check that duplcate names cannot be registered.
+// Check that duplicate names cannot be registered.
TEST(ServerHooksTest, DuplicateHooks) {
ServerHooks hooks;
@@ -104,6 +104,14 @@ TEST(ServerHooksTest, GetHookNames) {
EXPECT_TRUE(expected_names == actual_names);
}
+// Check that getting an unknown name throws an exception.
+
+TEST(ServerHooksTest, UnknownHookName) {
+ ServerHooks hooks;
+
+ EXPECT_THROW(static_cast<void>(hooks.getIndex("unknown")), NoSuchHook);
+}
+
// Check that the count of hooks is correct.
TEST(ServerHooksTest, HookCount) {
@@ -119,4 +127,116 @@ TEST(ServerHooksTest, HookCount) {
EXPECT_EQ(6, hooks.getCount());
}
+// HookRegistrationFunction tests
+
+// Declare some hook registration functions.
+
+int alpha = 0;
+int beta = 0;
+int gamma = 0;
+int delta = 0;
+
+void registerAlphaBeta(ServerHooks& hooks) {
+ alpha = hooks.registerHook("alpha");
+ beta = hooks.registerHook("beta");
+}
+
+void registerGammaDelta(ServerHooks& hooks) {
+ gamma = hooks.registerHook("gamma");
+ delta = hooks.registerHook("delta");
+}
+
+// Add them to the registration vector. This addition should happen before
+// any tests are run, so we should start off with two functions in the
+// registration vector.
+
+HookRegistrationFunction f1(registerAlphaBeta);
+HookRegistrationFunction f2(registerGammaDelta);
+
+// This is not registered statically: it is used in the latter part of the
+// test.
+
+int epsilon = 0;
+void registerEpsilon(ServerHooks& hooks) {
+ epsilon = hooks.registerHook("epsilon");
+}
+
+// Test that the registration functions were defined and can be executed.
+
+TEST(HookRegistrationFunction, Registration) {
+
+ // The first part of the tests checks the static registration. As there
+ // is only one list of registration functions, we have to do this first
+ // as the static registration is done outside our control, before the
+ // tests are loaded.
+
+ // Ensure that the hook numbers are initialized.
+ EXPECT_EQ(0, alpha);
+ EXPECT_EQ(0, beta);
+ EXPECT_EQ(0, gamma);
+ EXPECT_EQ(0, delta);
+
+ // Should have two hook registration functions registered.
+ EXPECT_EQ(2, HookRegistrationFunction::getFunctionVector().size());
+
+ // Execute the functions and check that four new hooks were defined.
+
+ ServerHooks hooks;
+ EXPECT_EQ(2, hooks.getCount());
+ HookRegistrationFunction::execute(hooks);
+ EXPECT_EQ(6, hooks.getCount());
+
+ // Check the hook names
+ vector<string> names = hooks.getHookNames();
+ ASSERT_EQ(6, names.size());
+ sort(names.begin(), names.end());
+ EXPECT_EQ(string("alpha"), names[0]);
+ EXPECT_EQ(string("beta"), names[1]);
+ EXPECT_EQ(string("context_create"), names[2]);
+ EXPECT_EQ(string("context_destroy"), names[3]);
+ EXPECT_EQ(string("delta"), names[4]);
+ EXPECT_EQ(string("gamma"), names[5]);
+
+ // Check that numbers in the range 2-5 inclusive were assigned as the
+ // hook indexes (0 and 1 being reserved for context_create and
+ // context_destroy).
+ vector<int> indexes;
+ indexes.push_back(alpha);
+ indexes.push_back(beta);
+ indexes.push_back(gamma);
+ indexes.push_back(delta);
+ sort(indexes.begin(), indexes.end());
+ EXPECT_EQ(2, indexes[0]);
+ EXPECT_EQ(3, indexes[1]);
+ EXPECT_EQ(4, indexes[2]);
+ EXPECT_EQ(5, indexes[3]);
+
+ // One last check. We'll test that the constructor of does indeed
+ // add a function to the function vector and that the static initialization
+ // was not somehow by chance.
+ HookRegistrationFunction::getFunctionVector().clear();
+ EXPECT_TRUE(HookRegistrationFunction::getFunctionVector().empty());
+ epsilon = 0;
+
+ // Register a single registration function.
+ HookRegistrationFunction f3(registerEpsilon);
+ EXPECT_EQ(1, HookRegistrationFunction::getFunctionVector().size());
+
+ // Execute it and check that the hook was registered.
+ ServerHooks hooks2;
+ EXPECT_EQ(0, epsilon);
+ EXPECT_EQ(2, hooks2.getCount());
+ HookRegistrationFunction::execute(hooks2);
+
+ // Should be three hooks, with the new one assigned an index of 2.
+ names = hooks2.getHookNames();
+ ASSERT_EQ(3, names.size());
+ sort(names.begin(), names.end());
+ EXPECT_EQ(string("context_create"), names[0]);
+ EXPECT_EQ(string("context_destroy"), names[1]);
+ EXPECT_EQ(string("epsilon"), names[2]);
+
+ EXPECT_EQ(2, epsilon);
+}
+
} // Anonymous namespace
More information about the bind10-changes
mailing list