Commit 49ee4eaf authored by Stephen Morris's avatar Stephen Morris
Browse files

[2980] Checkpoint - HooksManager class partially working

parent db3f2d81
......@@ -31,6 +31,7 @@ libb10_hooks_la_SOURCES += callout_handle.cc callout_handle.h
libb10_hooks_la_SOURCES += callout_manager.cc callout_manager.h
libb10_hooks_la_SOURCES += hooks.h
libb10_hooks_la_SOURCES += hooks_log.cc hooks_log.h
libb10_hooks_la_SOURCES += hooks_manager.cc hooks_manager.h
libb10_hooks_la_SOURCES += library_handle.cc library_handle.h
libb10_hooks_la_SOURCES += library_manager.cc library_manager.h
libb10_hooks_la_SOURCES += library_manager_collection.cc library_manager_collection.h
......
......@@ -356,7 +356,7 @@ private:
/// A shared pointer to a CalloutHandle object.
typedef boost::shared_ptr<CalloutHandle> CalloutHandlePtr;
} // namespace util
} // namespace hooks
} // namespace isc
......
// 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.
// TODO - This is a temporary implementation of the hooks manager - it is
// likely to be completely rewritte
#include <hooks/callout_handle.h>
#include <hooks/callout_manager.h>
#include <hooks/callout_manager.h>
#include <hooks/library_handle.h>
#include <hooks/library_manager_collection.h>
#include <hooks/hooks_manager.h>
#include <hooks/server_hooks.h>
#include <boost/shared_ptr.hpp>
#include <string>
#include <vector>
using namespace std;
namespace isc {
namespace hooks {
// Constructor
HooksManager::HooksManager() {
}
// Return reference to singleton hooks manager.
HooksManager&
HooksManager::getHooksManager() {
static HooksManager manager;
return (manager);
}
// Perform conditional initialization if nothing is loaded.
void
HooksManager::conditionallyInitialize() {
if (!lm_collection_) {
// Nothing present, so create the collection with any empty set of
// libraries, and get the CalloutManager.
vector<string> libraries;
lm_collection_.reset(new LibraryManagerCollection(libraries));
lm_collection_->loadLibraries();
callout_manager_ = lm_collection_->getCalloutManager();
}
}
// Create a callout handle
boost::shared_ptr<CalloutHandle>
HooksManager::createCalloutHandleInternal() {
conditionallyInitialize();
return (boost::shared_ptr<CalloutHandle>(
new CalloutHandle(callout_manager_)));
}
boost::shared_ptr<CalloutHandle>
HooksManager::createCalloutHandle() {
return (getHooksManager().createCalloutHandleInternal());
}
// Are callouts present?
bool
HooksManager::calloutsPresentInternal(int index) {
conditionallyInitialize();
return (callout_manager_->calloutsPresent(index));
}
bool
HooksManager::calloutsPresent(int index) {
return (getHooksManager().calloutsPresentInternal(index));
}
// Call the callouts
void
HooksManager::callCalloutsInternal(int index, CalloutHandle& handle) {
conditionallyInitialize();
return (callout_manager_->callCallouts(index, handle));
}
void
HooksManager::callCallouts(int index, CalloutHandle& handle) {
return (getHooksManager().callCalloutsInternal(index, handle));
}
} // namespace util
} // namespace isc
// 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 HOOKS_MANAGER_H
#define HOOKS_MANAGER_H
#include <boost/noncopyable.hpp>
#include <boost/shared_ptr.hpp>
#include <string>
#include <vector>
namespace isc {
namespace hooks {
// Forward declarations
class CalloutHandle;
class CalloutManager;
class LibraryHandle;
class LibraryManagerCollection;
/// @brief Hooks Manager
///
/// This is the overall manager of the hooks framework and is the main class
/// used by a BIND 10 module when handling hooks. It is responsible for the
/// loading and unloading of user libraries, and for calling the callouts on
/// each hook point.
///
/// The class is a singleton, the single instance of the object being accessed
/// through the static getHooksManager() method.
class HooksManager : boost::noncopyable {
public:
/// @brief Get singleton hooks manager
///
/// @return Reference to the singleton hooks manager.
static HooksManager& getHooksManager();
/// @brief Reset hooks manager
///
/// Resets the hooks manager to the initial state. This should only be
/// called by test functions, so causes a warning message to be output.
void reset() {}
/// @brief Load and reload libraries
///
/// Loads the list of libraries into the server address space. For each
/// library, the "standard" functions (ones with the same names as the
/// hook points) are configured and the libraries' "load" function
/// called.
///
/// If libraries are already loaded, they are unloaded and the new
/// libraries loaded.
///
/// If any library fails to load, an error message will be logged. The
/// remaining libraries will be loaded if possible.
///
/// @param libraries List of libraries to be loaded. The order is
/// important, as it determines the order that callouts on the same
/// hook will be called.
///
/// @return true if all libraries loaded without a problem, false if one or
/// more libraries failed to load. In the latter case, message will
/// be logged that give the reason.
bool loadLibraries(const std::vector<std::string>& /* libraries */) {return false;}
/// @brief Unload libraries
///
/// Unloads the loaded libraries and leaves the hooks subsystem in the
/// state it was after construction but before loadLibraries() is called.
///
/// @note: This method should be used with caution - see the notes for
/// the class LibraryManager for pitfalls. In general, a server
/// should not call this method: library unloading will automatically
/// take place when new libraries are loaded, and when appropriate
/// objects are destroyed.
///
/// @return true if all libraries unloaded successfully, false on an error.
/// In the latter case, an error message will have been output.
bool unloadLibraries() {return false;}
/// @brief Are callouts present?
///
/// Checks loaded libraries and returns true if at lease one callout
/// has been registered by them for the given hook.
///
/// @param index Hooks 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.
static bool calloutsPresent(int index);
/// @brief Calls the callouts for a given hook
///
/// Iterates through the libray handles and calls the callouts associated
/// with the given hook index.
///
/// @note This method invalidates the current library index set with
/// setLibraryIndex().
///
/// @param index Index of the hook to call.
/// @param handle Reference to the CalloutHandle object for the current
/// object being processed.
static void callCallouts(int index, CalloutHandle& handle);
/// @brief Return pre-callouts library handle
///
/// Returns a library handle that can be used by the server to register
/// callouts on a hook that are called _before_ any callouts belonging
/// to a library.
///
/// @note This library handle is valid only after loadLibraries() is
/// called and before another call to loadLibraries(). Its use
/// at any other time may cause severe problems.
///
/// TODO: This is also invalidated by a call to obtaining the
/// post-callout function.
///
/// @return Shared pointer to library handle associated with pre-library
/// callout registration.
boost::shared_ptr<LibraryHandle> preCalloutLibraryHandle() const;
/// @brief Return post-callouts library handle
///
/// Returns a library handle that can be used by the server to register
/// callouts on a hook that are called _after any callouts belonging
/// to a library.
///
/// @note This library handle is valid only after loadLibraries() is
/// called and before another call to loadLibraries(). Its use
/// at any other time may cause severe problems.
///
/// TODO: This is also invalidated by a call to obtaining the
/// pret-callout function.
///
/// @return Shared pointer to library handle associated with post-library
/// callout registration.
boost::shared_ptr<LibraryHandle> postCalloutLibraryHandle() const;
/// @brief Return callout handle
///
/// Returns a callout handle to be associated with a request passed round
/// the system.
///
/// @note This handle is valid only after a loadLibraries() call and then
/// only up to the next loadLibraries() call.
///
/// @return Shared pointer to a CalloutHandle object.
static boost::shared_ptr<CalloutHandle> createCalloutHandle();
private:
/// @brief Constructor
///
/// This is private as the object is a singleton and can only be addessed
/// through the getHooksManager() static method.
HooksManager();
//@{
/// The following correspond to the each of the static methods above
/// but operate on the current instance.
/// @brief Are callouts present?
///
/// @param index Hooks 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 calloutsPresentInternal(int index);
/// @brief Calls the callouts for a given hook
///
/// @param index Index of the hook to call.
/// @param handle Reference to the CalloutHandle object for the current
/// object being processed.
void callCalloutsInternal(int index, CalloutHandle& handle);
/// @brief Return callout handle
///
/// @note This handle is valid only after a loadLibraries() call and then
/// only up to the next loadLibraries() call.
///
/// @return Shared pointer to a CalloutHandle object.
boost::shared_ptr<CalloutHandle> createCalloutHandleInternal();
//@}
/// @brief Conditional initialization of the hooks manager
///
/// loadLibraries() performs the initialization of the HooksManager,
/// setting up the internal structures and loading libraries. However,
/// in some cases, server authors may not do that. This method is called
/// whenever any hooks execution function is invoked (checking callouts,
/// calling callouts or returning a callout handle). If the HooksManager
/// is unitialised, it will initialize it with an "empty set" of libraries.
void conditionallyInitialize();
// Members
/// Set of library managers.
boost::shared_ptr<LibraryManagerCollection> lm_collection_;
/// Callout manager for the set of library managers.
boost::shared_ptr<CalloutManager> callout_manager_;
};
} // namespace util
} // namespace hooks
#endif // HOOKS_MANAGER_H
......@@ -73,10 +73,14 @@ run_unittests_SOURCES += callout_handle_unittest.cc
run_unittests_SOURCES += callout_manager_unittest.cc
run_unittests_SOURCES += common_test_class.h
run_unittests_SOURCES += handles_unittest.cc
run_unittests_SOURCES += hooks_manager_unittest.cc
run_unittests_SOURCES += library_manager_collection_unittest.cc
run_unittests_SOURCES += library_manager_unittest.cc
run_unittests_SOURCES += server_hooks_unittest.cc
nodist_run_unittests_SOURCES = marker_file.h
nodist_run_unittests_SOURCES += test_libraries.h
run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
run_unittests_LDADD = $(AM_LDADD) $(GTEST_LDADD)
......
// 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 <hooks/callout_handle.h>
#include <hooks/hooks_manager.h>
#include <hooks/tests/common_test_class.h>
#include <hooks/tests/test_libraries.h>
#include <boost/shared_ptr.hpp>
#include <gtest/gtest.h>
#include <algorithm>
#include <string>
using namespace isc;
using namespace isc::hooks;
using namespace std;
namespace {
/// @brief Hooks manager collection test class
class HooksManagerTest : public ::testing::Test,
public HooksCommonTestClass {
public:
/// @brief Constructor
///
/// Reset the hooks manager. The hooks manager is a singleton, so needs
/// to be reset for each test.
HooksManagerTest() {
HooksManager::getHooksManager().reset();
}
/// @brief Call callouts test
///
/// See the header for HooksCommonTestClass::execute for details.
///
/// @param r0...r3, d1..d3 Values and intermediate values expected. They
/// are ordered so that the variables appear in the argument list in
/// the order they are used.
void executeCallCallouts(int r0, int d1, int r1, int d2, int r2, int d3,
int r3) {
static const char* COMMON_TEXT = " callout returned the wong value";
static const char* RESULT = "result";
// Get a CalloutHandle for the calculation.
CalloutHandlePtr handle = HooksManager::createCalloutHandle();
// Initialize the argument RESULT. This simplifies testing by
// eliminating the generation of an exception when we try the unload
// test. In that case, RESULT is unchanged.
int result = -1;
handle->setArgument(RESULT, result);
// Seed the calculation.
HooksManager::callCallouts(isc::hooks::ServerHooks::CONTEXT_CREATE,
*handle);
handle->getArgument(RESULT, result);
EXPECT_EQ(r0, result) << "context_create" << COMMON_TEXT;
// Perform the first calculation.
handle->setArgument("data_1", d1);
HooksManager::callCallouts(lm_one_index_, *handle);
handle->getArgument(RESULT, result);
EXPECT_EQ(r1, result) << "lm_one" << COMMON_TEXT;
// ... the second ...
handle->setArgument("data_2", d2);
HooksManager::callCallouts(lm_two_index_, *handle);
handle->getArgument(RESULT, result);
EXPECT_EQ(r2, result) << "lm_two" << COMMON_TEXT;
// ... and the third.
handle->setArgument("data_3", d3);
HooksManager::callCallouts(lm_three_index_, *handle);
handle->getArgument(RESULT, result);
EXPECT_EQ(r3, result) << "lm_three" << COMMON_TEXT;
}
};
/*
// This is effectively the same test as for LibraryManager, but using the
// LibraryManagerCollection object.
TEST_F(HooksManagerTest, LoadLibraries) {
// Set up the list of libraries to be loaded.
std::vector<std::string> library_names;
library_names.push_back(std::string(FULL_CALLOUT_LIBRARY));
library_names.push_back(std::string(BASIC_CALLOUT_LIBRARY));
// Set up the library manager collection and get the callout manager we'll
// be using.
PublicLibraryManagerCollection lm_collection(library_names);
// Load the libraries.
EXPECT_TRUE(lm_collection.loadLibraries());
boost::shared_ptr<CalloutManager> manager =
lm_collection.getCalloutManager();
// Execute the callouts. The first library implements the calculation.
//
// r3 = (7 * d1 - d2) * d3
//
// The last-loaded library implements the calculation
//
// r3 = (10 + d1) * d2 - d3
//
// Putting the processing for each library together in the appropriate
// order, we get:
//
// r3 = ((10 * d1 + d1) - d2) * d2 * d3 - d3
{
SCOPED_TRACE("Doing calculation with libraries loaded");
executeCallCallouts(manager, 10, 3, 33, 2, 62, 3, 183);
}
// Try unloading the libraries.
EXPECT_NO_THROW(lm_collection.unloadLibraries());
// Re-execute the calculation - callouts can be called but as nothing
// happens, the result should always be -1.
{
SCOPED_TRACE("Doing calculation with libraries not loaded");
executeCallCallouts(manager, -1, 3, -1, 22, -1, 83, -1);
}
}
// This is effectively the same test as above, but with a library generating
// an error when loaded. It is expected that the failing library will not be
// loaded, but others will be.
TEST_F(LibraryManagerCollectionTest, LoadLibrariesWithError) {
// Set up the list of libraries to be loaded.
std::vector<std::string> library_names;
library_names.push_back(std::string(FULL_CALLOUT_LIBRARY));
library_names.push_back(std::string(INCORRECT_VERSION_LIBRARY));
library_names.push_back(std::string(BASIC_CALLOUT_LIBRARY));
// Set up the library manager collection and get the callout manager we'll
// be using.
PublicLibraryManagerCollection lm_collection(library_names);
// Load the libraries. We expect a failure status to be returned as
// one of the libraries failed to load.
EXPECT_FALSE(lm_collection.loadLibraries());
boost::shared_ptr<CalloutManager> manager =
lm_collection.getCalloutManager();
// Expect only two libraries were loaded.
EXPECT_EQ(2, manager->getNumLibraries());
// Execute the callouts. The first library implements the calculation.
//
// r3 = (7 * d1 - d2) * d3
//
// The last-loaded library implements the calculation
//
// r3 = (10 + d1) * d2 - d3
//
// Putting the processing for each library together in the appropriate
// order, we get:
//
// r3 = ((10 * d1 + d1) - d2) * d2 * d3 - d3
{
SCOPED_TRACE("Doing calculation with libraries loaded");
executeCallCallouts(manager, 10, 3, 33, 2, 62, 3, 183);
}
// Try unloading the libraries.
EXPECT_NO_THROW(lm_collection.unloadLibraries());
// Re-execute the calculation - callouts can be called but as nothing
// happens, the result should always be -1.
{
SCOPED_TRACE("Doing calculation with libraries not loaded");
executeCallCallouts(manager, -1, 3, -1, 22, -1, 83, -1);
}
}
*/
// Check that everything works even with no libraries loaded. First that
// calloutsPresent() always returns false.
TEST_F(HooksManagerTest, NoLibrariesCalloutsPresent) {
// No callouts should be present on any hooks.
EXPECT_FALSE(HooksManager::calloutsPresent(lm_one_index_));
EXPECT_FALSE(HooksManager::calloutsPresent(lm_two_index_));
EXPECT_FALSE(HooksManager::calloutsPresent(lm_three_index_));
}
TEST_F(HooksManagerTest, NoLibrariesCallCallouts) {
executeCallCallouts(-1, 3, -1, 22, -1, 83, -1);
}
} // Anonymous namespace
......@@ -16,10 +16,8 @@
#include <hooks/callout_manager.h>
#include <hooks/library_manager.h>
#include <hooks/library_manager_collection.h>
#include <hooks/server_hooks.h>
#include <hooks/tests/common_test_class.h>
#include <hooks/tests/marker_file.h>
#include <hooks/tests/test_libraries.h>
#include <boost/shared_ptr.hpp>
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment