Commit 7e9a2b00 authored by Francis Dupont's avatar Francis Dupont

[#1282] Checkpoint: hooks library done - correct use to do

parent 6a7bb8b8
......@@ -15,6 +15,7 @@
#include <hooks/server_hooks.h>
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
#include <string>
#include <vector>
......@@ -96,8 +97,19 @@ HooksManager::loadLibrariesInternal(const HookLibsCollection& libraries) {
ServerHooks::getServerHooks().getParkingLotsPtr()->clear();
// Create the library manager and load the libraries.
// Keep a weak pointer on the existing library manager collection.
boost::weak_ptr<LibraryManagerCollection> weak_lmc(lm_collection_);
// Create the library manager collection.
lm_collection_.reset(new LibraryManagerCollection(libraries));
// If there was another owner the previous library manager collection
// was not destroyed and libraries not closed.
if (!weak_lmc.expired()) {
isc_throw(LibrariesStillOpened, "some libraries are still opened");
}
// Load the libraries.
bool status = lm_collection_->loadLibraries();
if (status) {
......@@ -121,14 +133,45 @@ HooksManager::loadLibraries(const HookLibsCollection& libraries) {
// cause the libraries to be unloaded) and initializes them with empty list if
// requested.
void
bool
HooksManager::unloadLibrariesInternal() {
ServerHooks::getServerHooks().getParkingLotsPtr()->clear();
init();
// Keep a weak pointer on the existing library manager collection.
boost::weak_ptr<LibraryManagerCollection> weak_lmc(lm_collection_);
// Create the collection with any empty set of libraries.
HookLibsCollection libraries;
lm_collection_.reset(new LibraryManagerCollection(libraries));
// If there was another owner the previous library manager collection
// was not destroyed and libraries not closed.
if (!weak_lmc.expired()) {
// Restore the library manager collection.
lm_collection_ = weak_lmc.lock();
return (false);
}
// Load the empty set of libraries.
lm_collection_->loadLibraries();
// Get the CalloutManager.
callout_manager_ = lm_collection_->getCalloutManager();
return (true);
}
bool HooksManager::unloadLibraries() {
return (getHooksManager().unloadLibrariesInternal());
}
void
HooksManager::prepareUnloadLibrariesInternal() {
static_cast<void>(lm_collection_->prepareUnloadLibraries());
}
void HooksManager::unloadLibraries() {
getHooksManager().unloadLibrariesInternal();
void HooksManager::prepareUnloadLibraries() {
getHooksManager().prepareUnloadLibrariesInternal();
}
// Create a callout handle
......
......@@ -19,6 +19,18 @@
namespace isc {
namespace hooks {
/// @brief Libraries still opened.
///
/// Thrown if an attempt is made to load libraries when some are still
/// in memory likely because they were not unloaded (logic error in Kea)
/// or they have some visible dangling pointers (logic error in a hook
/// library).
class LibrariesStillOpened : public Exception {
public:
LibrariesStillOpened(const char* file, size_t line, const char* what) :
isc::Exception(file, line, what) {}
};
// Forward declarations
class CalloutHandle;
class CalloutManager;
......@@ -45,8 +57,8 @@ public:
/// hook points) are configured and the libraries' "load" function
/// called.
///
/// If libraries are already loaded, they are unloaded and the new
/// libraries loaded.
/// @note this method now requires the libraries are unloaded before
/// being called.
///
/// If any library fails to load, an error message will be logged. The
/// remaining libraries will be loaded if possible.
......@@ -58,6 +70,7 @@ public:
/// @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.
/// @throw LibrariesStillOpened when some libraries are already loaded.
static bool loadLibraries(const HookLibsCollection& libraries);
/// @brief Unload libraries
......@@ -65,15 +78,37 @@ public:
/// 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.
static void unloadLibraries();
/// @note: This method should be called after @ref prepareUnloadLibraries
/// in order to destroy appropriate objects. See notes for
/// the class LibraryManager for pitfalls.
/// @note: if even after @ref prepareUnloadLibraries there are still
/// visible pointers (i.e. callout handles owning the
/// library manager collection) the method will fail to close
/// libraries and returns false. It is a fatal error as there
/// is no possible recovery. It is a logic error in the hook
/// code too so the solution is to fix the it and to restart
/// the server with a correct hook library binary.
///
/// @return true if all libraries unloaded successfully, false if they
/// are still in memory.
static bool unloadLibraries();
/// @brief Prepare the unloading of libraries
///
/// Calls the unload functions when they exists and removes callouts.
///
/// @note: after the call to this method there should be no visible
/// dangling pointers (i.e. callout handles owning the library
/// manager collection) nor invisible dangling pointers.
/// In the first case it will be impossible to close libraries
/// so they will remain in memory, in the second case a crash
/// is possible in particular at exit time during global
/// object finalization. In both cases the hook library code
/// causing the problem is incorrect and must be fixed.
/// @note: it is a logic error to not call this method before
/// @ref unloadLibraries even it hurts only with particular
/// hooks libraries.
static void prepareUnloadLibraries();
/// @brief Are callouts present?
///
......@@ -367,7 +402,13 @@ private:
bool loadLibrariesInternal(const HookLibsCollection& libraries);
/// @brief Unload libraries
void unloadLibrariesInternal();
///
/// @return true if all libraries unloaded successfully, false on an error.
/// In the latter case, an error message will have been output.
bool unloadLibrariesInternal();
/// @brief Prepare the unloading of libraries
void prepareUnloadLibrariesInternal();
/// @brief Are callouts present?
///
......
// File created from ../../../src/lib/hooks/hooks_messages.mes on Mon Jun 22 2020 17:18
// File created from ../../../src/lib/hooks/hooks_messages.mes on Wed Jun 24 2020 22:17
#include <cstddef>
#include <log/message_types.h>
......@@ -19,12 +19,14 @@ extern const isc::log::MessageID HOOKS_CALLOUT_REGISTRATION = "HOOKS_CALLOUT_REG
extern const isc::log::MessageID HOOKS_CLOSE_ERROR = "HOOKS_CLOSE_ERROR";
extern const isc::log::MessageID HOOKS_HOOK_LIST_RESET = "HOOKS_HOOK_LIST_RESET";
extern const isc::log::MessageID HOOKS_INCORRECT_VERSION = "HOOKS_INCORRECT_VERSION";
extern const isc::log::MessageID HOOKS_LIBRARY_CLOSED = "HOOKS_LIBRARY_CLOSED";
extern const isc::log::MessageID HOOKS_LIBRARY_LOADED = "HOOKS_LIBRARY_LOADED";
extern const isc::log::MessageID HOOKS_LIBRARY_LOADING = "HOOKS_LIBRARY_LOADING";
extern const isc::log::MessageID HOOKS_LIBRARY_MULTI_THREADING_COMPATIBLE = "HOOKS_LIBRARY_MULTI_THREADING_COMPATIBLE";
extern const isc::log::MessageID HOOKS_LIBRARY_MULTI_THREADING_NOT_COMPATIBLE = "HOOKS_LIBRARY_MULTI_THREADING_NOT_COMPATIBLE";
extern const isc::log::MessageID HOOKS_LIBRARY_UNLOADED = "HOOKS_LIBRARY_UNLOADED";
extern const isc::log::MessageID HOOKS_LIBRARY_UNLOADING = "HOOKS_LIBRARY_UNLOADING";
extern const isc::log::MessageID HOOKS_LIBRARY_UNLOAD_ALREADY_CALLED = "HOOKS_LIBRARY_UNLOAD_ALREADY_CALLED";
extern const isc::log::MessageID HOOKS_LIBRARY_VERSION = "HOOKS_LIBRARY_VERSION";
extern const isc::log::MessageID HOOKS_LOAD_ERROR = "HOOKS_LOAD_ERROR";
extern const isc::log::MessageID HOOKS_LOAD_EXCEPTION = "HOOKS_LOAD_EXCEPTION";
......@@ -60,12 +62,14 @@ const char* values[] = {
"HOOKS_CLOSE_ERROR", "failed to close hook library %1: %2",
"HOOKS_HOOK_LIST_RESET", "the list of hooks has been reset",
"HOOKS_INCORRECT_VERSION", "hook library %1 is at version %2, require version %3",
"HOOKS_LIBRARY_CLOSED", "hooks library %1 successfully closed",
"HOOKS_LIBRARY_LOADED", "hooks library %1 successfully loaded",
"HOOKS_LIBRARY_LOADING", "loading hooks library %1",
"HOOKS_LIBRARY_MULTI_THREADING_COMPATIBLE", "hooks library %1 reports its multi-threading compatibility as %2",
"HOOKS_LIBRARY_MULTI_THREADING_NOT_COMPATIBLE", "hooks library %1 is not compatible with multi-threading",
"HOOKS_LIBRARY_UNLOADED", "hooks library %1 successfully unloaded",
"HOOKS_LIBRARY_UNLOADING", "unloading library %1",
"HOOKS_LIBRARY_UNLOAD_ALREADY_CALLED", "hooks library %1 unload() was already called",
"HOOKS_LIBRARY_VERSION", "hooks library %1 reports its version as %2",
"HOOKS_LOAD_ERROR", "'load' function in hook library %1 returned error %2",
"HOOKS_LOAD_EXCEPTION", "'load' function in hook library %1 threw an exception",
......
// File created from ../../../src/lib/hooks/hooks_messages.mes on Mon Jun 22 2020 17:18
// File created from ../../../src/lib/hooks/hooks_messages.mes on Wed Jun 24 2020 22:17
#ifndef HOOKS_MESSAGES_H
#define HOOKS_MESSAGES_H
......@@ -20,12 +20,14 @@ extern const isc::log::MessageID HOOKS_CALLOUT_REGISTRATION;
extern const isc::log::MessageID HOOKS_CLOSE_ERROR;
extern const isc::log::MessageID HOOKS_HOOK_LIST_RESET;
extern const isc::log::MessageID HOOKS_INCORRECT_VERSION;
extern const isc::log::MessageID HOOKS_LIBRARY_CLOSED;
extern const isc::log::MessageID HOOKS_LIBRARY_LOADED;
extern const isc::log::MessageID HOOKS_LIBRARY_LOADING;
extern const isc::log::MessageID HOOKS_LIBRARY_MULTI_THREADING_COMPATIBLE;
extern const isc::log::MessageID HOOKS_LIBRARY_MULTI_THREADING_NOT_COMPATIBLE;
extern const isc::log::MessageID HOOKS_LIBRARY_UNLOADED;
extern const isc::log::MessageID HOOKS_LIBRARY_UNLOADING;
extern const isc::log::MessageID HOOKS_LIBRARY_UNLOAD_ALREADY_CALLED;
extern const isc::log::MessageID HOOKS_LIBRARY_VERSION;
extern const isc::log::MessageID HOOKS_LOAD_ERROR;
extern const isc::log::MessageID HOOKS_LOAD_EXCEPTION;
......
......@@ -79,6 +79,10 @@ This is most likely due to the installation of a new version of Kea
without rebuilding the hook library. A rebuild and re-install of the
library should fix the problem in most cases.
% HOOKS_LIBRARY_CLOSED hooks library %1 successfully closed
This information message is issued when a user-supplied hooks library
has been successfully closed.
% HOOKS_LIBRARY_LOADED hooks library %1 successfully loaded
This information message is issued when a user-supplied hooks library
has been successfully loaded.
......@@ -103,6 +107,10 @@ from the configuration or the multi-threading disabled.
This information message is issued when a user-supplied hooks library
has been successfully unloaded.
% HOOKS_LIBRARY_UNLOAD_ALREADY_CALLED hooks library %1 unload() was already called
This warning message is issued when the unload() function of a
user-supplied hooks library was already called.
% HOOKS_LIBRARY_UNLOADING unloading library %1
This is a debug message called when the specified library is
being unloaded. If all is successful, it will be followed by the
......
......@@ -55,15 +55,15 @@ LibraryManager::LibraryManager(const std::string& name)
// Destructor.
LibraryManager::~LibraryManager() {
if (manager_) {
if (index_ >= 0) {
// LibraryManager instantiated to load a library, so ensure that
// it is unloaded before exiting.
static_cast<void>(unloadLibrary());
} else {
// LibraryManager instantiated to validate a library, so just ensure
// that it is closed before exiting.
static_cast<void>(closeLibrary());
static_cast<void>(prepareUnloadLibrary());
}
// LibraryManager instantiated to validate a library, so just ensure
// that it is closed before exiting.
static_cast<void>(closeLibrary());
}
// Open the library
......@@ -95,6 +95,8 @@ LibraryManager::closeLibrary() {
if (status != 0) {
LOG_ERROR(hooks_logger, HOOKS_CLOSE_ERROR).arg(library_name_)
.arg(dlerror());
} else {
LOG_INFO(hooks_logger, HOOKS_LIBRARY_CLOSED).arg(library_name_);
}
}
......@@ -242,9 +244,22 @@ LibraryManager::runLoad() {
// Run the "unload" function if present.
bool
LibraryManager::runUnload() {
LibraryManager::prepareUnloadLibrary() {
// Nothing to do.
if (dl_handle_ == NULL) {
return (true);
}
// Call once.
if (index_ < 0) {
LOG_WARN(hooks_logger, HOOKS_LIBRARY_UNLOAD_ALREADY_CALLED)
.arg(library_name_);
return (false);
}
// Get the pointer to the "load" function.
bool result = false;
PointerConverter pc(dlsym(dl_handle_, UNLOAD_FUNCTION_NAME));
if (pc.unloadPtr() != NULL) {
......@@ -254,31 +269,48 @@ LibraryManager::runUnload() {
int status = -1;
try {
status = (*pc.unloadPtr())();
result = true;
} catch (const isc::Exception& ex) {
LOG_ERROR(hooks_logger, HOOKS_UNLOAD_FRAMEWORK_EXCEPTION)
.arg(library_name_).arg(ex.what());
return (false);
} catch (...) {
// Exception generated. Note a warning as the unload will occur
// anyway.
LOG_WARN(hooks_logger, HOOKS_UNLOAD_EXCEPTION).arg(library_name_);
return (false);
}
if (status != 0) {
LOG_ERROR(hooks_logger, HOOKS_UNLOAD_ERROR).arg(library_name_)
.arg(status);
return (false);
} else {
LOG_DEBUG(hooks_logger, HOOKS_DBG_TRACE, HOOKS_UNLOAD_SUCCESS)
.arg(library_name_);
if (result) {
if (status != 0) {
LOG_ERROR(hooks_logger, HOOKS_UNLOAD_ERROR).arg(library_name_)
.arg(status);
result = false;
} else {
LOG_DEBUG(hooks_logger, HOOKS_DBG_TRACE, HOOKS_UNLOAD_SUCCESS)
.arg(library_name_);
}
}
} else {
LOG_DEBUG(hooks_logger, HOOKS_DBG_TRACE, HOOKS_NO_UNLOAD)
.arg(library_name_);
result = true;
}
return (true);
// Regardless of status, remove all callouts associated with this
// library on all hooks.
vector<string> hooks = ServerHooks::getServerHooks().getHookNames();
manager_->setLibraryIndex(index_);
for (size_t i = 0; i < hooks.size(); ++i) {
bool removed = manager_->deregisterAllCallouts(hooks[i], index_);
if (removed) {
LOG_DEBUG(hooks_logger, HOOKS_DBG_CALLS, HOOKS_CALLOUTS_REMOVED)
.arg(hooks[i]).arg(library_name_);
}
}
// Mark as unload() ran.
index_ = -1;
return (result);
}
// The main library loading function.
......@@ -327,7 +359,7 @@ LibraryManager::loadLibrary() {
// function (if present) in case "load" allocated resources that
// need to be freed and (b) we need to remove any callouts that
// have been installed.
static_cast<void>(unloadLibrary());
static_cast<void>(prepareUnloadLibrary());
}
}
......@@ -355,18 +387,8 @@ LibraryManager::unloadLibrary() {
// Call the unload() function if present. Note that this is done first
// - operations take place in the reverse order to which they were done
// when the library was loaded.
result = runUnload();
// Regardless of status, remove all callouts associated with this
// library on all hooks.
vector<string> hooks = ServerHooks::getServerHooks().getHookNames();
manager_->setLibraryIndex(index_);
for (size_t i = 0; i < hooks.size(); ++i) {
bool removed = manager_->deregisterAllCallouts(hooks[i], index_);
if (removed) {
LOG_DEBUG(hooks_logger, HOOKS_DBG_CALLS, HOOKS_CALLOUTS_REMOVED)
.arg(hooks[i]).arg(library_name_);
}
if (index_ >= 0) {
result = prepareUnloadLibrary();
}
// ... and close the library.
......
......@@ -41,15 +41,16 @@ class LibraryManager;
/// known hooks and locates their symbols, registering each callout as it does
/// so. Finally it locates the "load" function (if present) and calls it.
///
/// On unload, it calls the "unload" method if present, clears the callouts on
/// all hooks, and closes the library.
/// On unload, it clears the callouts on all hooks, calls the "unload"
/// method if present, clears the callouts on all hooks, and
/// closes the library.
///
/// @note Caution needs to be exercised when using the unload method. During
/// @note Caution needs to be exercised when using the close method. During
/// normal use, data will pass between the server and the library. In
/// this process, the library may allocate memory and pass it back to the
/// server. This could happen by the server setting arguments or context
/// in the CalloutHandle object, or by the library modifying the content
/// of pointed-to data. If the library is unloaded, this memory may lie
/// of pointed-to data. If the library is closed, this memory may lie
/// in the virtual address space deleted in that process. (The word "may"
/// is used, as this could be operating-system specific.) Should this
/// happen, any reference to the memory will cause a segmentation fault.
......@@ -57,7 +58,7 @@ class LibraryManager;
/// a destructor of an STL class when it is deleting memory allocated
/// when the data structure was extended by a function in the library.
///
/// @note The only safe way to run the "unload" function is to ensure that all
/// @note The only safe way to run the "close" function is to ensure that all
/// possible references to it are removed first. This means that all
/// CalloutHandles must be destroyed, as must any data items that were
/// passed to the callouts. In practice, it could mean that a server
......@@ -92,7 +93,7 @@ public:
/// If the library is open, closes it. This is principally a safety
/// feature to ensure closure in the case of an exception destroying this
/// object. However, see the caveat in the class header about when it is
/// safe to unload libraries.
/// safe to close libraries.
~LibraryManager();
/// @brief Validate library
......@@ -122,6 +123,27 @@ public:
/// In the latter case, the library will be unloaded if possible.
bool loadLibrary();
/// @brief Prepares library unloading
///
/// Searches for the "unload" framework function and, if present, runs it.
/// Regardless of status, remove all callouts associated with this
/// library on all hooks.
///
/// @return bool true if not found or found and run successfully,
/// false on an error. In this case, an error message will
/// have been output.
bool prepareUnloadLibrary();
/// @brief Return library name
///
/// @return Name of this library
std::string getName() const {
return (library_name_);
}
protected:
// The following methods are protected as they are accessed in testing.
/// @brief Unloads a library
///
/// Calls the libraries "unload" function if present, the closes the
......@@ -136,16 +158,6 @@ public:
/// the library is closed if possible.
bool unloadLibrary();
/// @brief Return library name
///
/// @return Name of this library
std::string getName() const {
return (library_name_);
}
protected:
// The following methods are protected as they are accessed in testing.
/// @brief Open library
///
/// Opens the library associated with this LibraryManager. A message is
......@@ -204,15 +216,6 @@ protected:
/// have been output.
bool runLoad();
/// @brief Run the unload function if present
///
/// Searches for the "unload" framework function and, if present, runs it.
///
/// @return bool true if not found or found and run successfully,
/// false on an error. In this case, an error message will
/// have been output.
bool runUnload();
private:
/// @brief Validating constructor
///
......
......@@ -52,8 +52,10 @@ LibraryManagerCollection::LibraryManagerCollection(const HookLibsCollection& lib
bool
LibraryManagerCollection::loadLibraries() {
// Unload libraries if any are loaded.
static_cast<void>(unloadLibraries());
// There must be not libraries still in memory.
if (!lib_managers_.empty()) {
isc_throw(LibrariesStillOpened, "some libraries are still opened");
}
// Access the callout manager, (re)creating it if required.
//
......@@ -106,16 +108,26 @@ LibraryManagerCollection::unloadLibraries() {
// Delete the library managers in the reverse order to which they were
// created, then clear the library manager vector.
for (int i = lib_managers_.size() - 1; i >= 0; --i) {
lib_managers_[i].reset();
while (!lib_managers_.empty()) {
lib_managers_.pop_back();
}
lib_managers_.clear();
// Get rid of the callout manager. (The other member, the list of library
// names, was cleared when the libraries were loaded.)
callout_manager_.reset();
}
// Prepare the unloading of libraries.
bool
LibraryManagerCollection::prepareUnloadLibraries() {
bool result = true;
// Iterate on library managers in reverse order.
for (auto lm = lib_managers_.rbegin(); lm != lib_managers_.rend(); ++lm) {
result = (*lm)->prepareUnloadLibrary() && result;
}
return (result);
}
// Return number of loaded libraries.
int
LibraryManagerCollection::getLoadedLibraryCount() const {
......
......@@ -42,14 +42,14 @@ class LibraryManager;
///
/// As described in the LibraryManager documentation, a CalloutHandle may end
/// up with pointers to memory within the address space of a loaded library.
/// If the library is unloaded before this address space is deleted, the
/// If the library is closed before this address space is deleted, the
/// deletion of the CalloutHandle may attempt to free memory into the newly-
/// unmapped address space and cause a segmentation fault.
///
/// To prevent this, each CalloutHandle maintains a shared pointer to the
/// LibraryManagerCollection current when it was created. In addition, the
/// containing HooksManager object also maintains a shared pointer to it. A
/// a LibraryManagerCollection is never explicitly deleted: when a new set
/// containing HooksManager object also maintains a shared pointer to it.
/// A LibraryManagerCollection is never explicitly deleted: when a new set
/// of libraries is loaded, the HooksManager clears its pointer to the
/// collection. The LibraryManagerCollection is only destroyed when all
/// CallHandle objects referencing it are destroyed.
......@@ -144,6 +144,19 @@ public:
static std::vector<std::string>
validateLibraries(const std::vector<std::string>& libraries);
/// @brief Prepare libaries unloading
///
/// Utility function to call before closing libraries. It runs the
/// unload() function when it exists and removes associated callout.
/// When this function returns either there is only one owner
/// (the hook manager) or some visible dangling pointers so
/// libraries are not closed to lower the probability of a crash.
/// See @ref LibraryManager::prepareUnloadLibrary.
///
/// @return true if all libraries unload were not found or run
/// successfully, false on an error.
bool prepareUnloadLibraries();
protected:
/// @brief Unload libraries
///
......
......@@ -19,8 +19,11 @@
#include <gtest/gtest.h>
#include <algorithm>
#include <fstream>
#include <string>
#include <unistd.h>
using namespace isc;
using namespace isc::hooks;
using namespace isc::data;
......@@ -39,17 +42,48 @@ public:
/// to be reset for each test.
HooksManagerTest() {
HooksManager::setTestMode(false);
HooksManager::unloadLibraries();
HooksManager::prepareUnloadLibraries();
bool status = HooksManager::unloadLibraries();
if (!status) {
cerr << "(fixture ctor) unloadLibraries failed" << endl;
}
// Ensure the marker file is not present at the start of a test.
static_cast<void>(remove(MARKER_FILE));
}
/// @brief Destructor
///
/// Unload all libraries.
~HooksManagerTest() {
static_cast<void>(remove(MARKER_FILE));
HooksManager::setTestMode(false);
HooksManager::unloadLibraries();
HooksManager::prepareUnloadLibraries();
bool status = HooksManager::unloadLibraries();
if (!status) {
cerr << "(fixture dtor) unloadLibraries failed" << endl;
}
}
/// @brief Marker file present
///
/// Convenience function to check whether a marker file is present. It
/// does this by opening the file.
///
/// @return true if the marker file is present.
bool markerFilePresent() const {
// Try to open it.
std::fstream marker;
marker.open(MARKER_FILE, std::fstream::in);
// Check if it is open and close it if so.
bool exists = marker.is_open();
if (exists) {
marker.close();
}
return (exists);
}
/// @brief Call callouts test
///
......@@ -137,8 +171,6 @@ private:
/// To avoid unused variable errors
std::string dummy(int i) {
if (i == 0) {
return (MARKER_FILE);
} else if (i > 0) {
return (LOAD_CALLOUT_LIBRARY);
} else {
return (LOAD_ERROR_CALLOUT_LIBRARY);
......@@ -185,7 +217,10 @@ TEST_F(HooksManagerTest, LoadLibraries) {
}
// Try unloading the libraries.
EXPECT_NO_THROW(HooksManager::unloadLibraries());
EXPECT_NO_THROW(HooksManager::prepareUnloadLibraries());
bool status = false;
EXPECT_NO_THROW(status = HooksManager::unloadLibraries());
EXPECT_TRUE(status);
// Re-execute the calculation - callouts can be called but as nothing
// happens, the result should always be -1.
......@@ -244,10 +279,14 @@ TEST_F(HooksManagerTest, CalloutHandleUnloadLibrary) {
HooksManager::callCallouts(ServerHooks::CONTEXT_CREATE, *handle);
// Unload the libraries.
HooksManager::unloadLibraries();
HooksManager::prepareUnloadLibraries();
EXPECT_FALSE(HooksManager::unloadLibraries());
// Deleting the callout handle should not cause a segmentation fault.
handle.reset();
// And allows unload.
EXPECT_TRUE(HooksManager::unloadLibraries());
}
// Test that we can load a new set of libraries while we have a CalloutHandle
......@@ -285,17 +324,20 @@ TEST_F(HooksManagerTest, CalloutHandleLoadLibrary) {
data::ConstElementPtr()));
// Load the libraries.
EXPECT_THROW(HooksManager::loadLibraries(new_library_names),
LibrariesStillOpened);
// Deleting the old callout handle should not cause a segmentation fault.
handle.reset();
// But it allows the load of the new library.
EXPECT_TRUE(HooksManager::loadLibraries(new_library_names));
// Execute the calculation. Note that we still have the CalloutHandle
// for the old library: however, this should not affect the new calculation.
// Execute the calculation.
{
SCOPED_TRACE("Calculation with basic callout library loaded");
executeCallCallouts(10, 7, 17, 3, 51, 16, 35);