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
// Forward declaration of the library handle and related collection classes.
+class CalloutManager;
class LibraryHandle;
-class LibraryHandleCollection;
/// @brief Per-packet callout handle
///
/// 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
///
/// 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_;
--- /dev/null
+// 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
--- /dev/null
+// 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
+++ /dev/null
-// 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() << ")");
- }
-}
-
-// 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 = hooks_->getIndex(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 = hooks_->getIndex(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 = hooks_->getIndex(name);
-
- // Get rid of everything.
- hook_vector_[index].clear();
-}
-
-// 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
+++ /dev/null
-// 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
-/// 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 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 {
-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)
- : hooks_(hooks), hook_vector_(hooks->getCount())
- {}
-
- /// @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;
-
- // Member variables
-
- /// 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
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
--- /dev/null
+// 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
+++ /dev/null
-// 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
///
/// 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.
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.