Parcourir la source

[2980] Abstracted names of test libraries into a common header file

Stephen Morris il y a 12 ans
Parent
commit
cc8e7feaf3

+ 1 - 2
configure.ac

@@ -1402,9 +1402,8 @@ AC_OUTPUT([doc/version.ent
            src/lib/cc/session_config.h.pre
            src/lib/cc/tests/session_unittests_config.h
            src/lib/datasrc/datasrc_config.h.pre
-           src/lib/hooks/tests/library_manager_collection_unittest.cc
-           src/lib/hooks/tests/library_manager_unittest.cc
            src/lib/hooks/tests/marker_file.h
+           src/lib/hooks/tests/test_libraries.h
            src/lib/log/tests/console_test.sh
            src/lib/log/tests/destination_test.sh
            src/lib/log/tests/init_logger_test.sh

+ 1 - 1
src/lib/hooks/tests/Makefile.am

@@ -89,4 +89,4 @@ endif
 
 noinst_PROGRAMS = $(TESTS)
 
-EXTRA_DIST = library_manager_unittest.cc.in marker_file.h.in
+EXTRA_DIST = marker_file.h.in test_libraries.h.in

+ 293 - 0
src/lib/hooks/tests/library_manager_collection_unittest.cc

@@ -0,0 +1,293 @@
+// 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/callout_manager.h>
+#include <hooks/library_manager.h>
+#include <hooks/library_manager_collection.h>
+#include <hooks/server_hooks.h>
+
+#include <hooks/tests/marker_file.h>
+#include <hooks/tests/test_libraries.h>
+
+#include <boost/shared_ptr.hpp>
+#include <gtest/gtest.h>
+
+#include <algorithm>
+#include <fstream>
+#include <string>
+
+#include <unistd.h>
+
+
+using namespace isc;
+using namespace isc::hooks;
+using namespace std;
+
+namespace {
+
+/// @brief Library manager collection test class
+
+class LibraryManagerCollectionTest : public ::testing::Test {
+public:
+    /// @brief Constructor
+    LibraryManagerCollectionTest() {
+
+        // Set up the server hooks.  ServerHooks is a singleton, so we reset it
+        // between each test.
+        ServerHooks& hooks = ServerHooks::getServerHooks();
+        hooks.reset();
+        lm_one_index_ = hooks.registerHook("lm_one");
+        lm_two_index_ = hooks.registerHook("lm_two");
+        lm_three_index_ = hooks.registerHook("lm_three");
+
+        // Ensure the marker file is not present at the start of a test.
+        static_cast<void>(unlink(MARKER_FILE));
+    }
+
+    /// @brief Destructor
+    ///
+    /// Ensures a marker file is removed after each test.
+    ~LibraryManagerCollectionTest() {
+        static_cast<void>(unlink(MARKER_FILE));
+    }
+
+    /// @brief Call callouts test
+    ///
+    /// All of the loaded libraries for which callouts are called register four
+    /// callouts: a context_create callout and three callouts that are attached
+    /// to hooks lm_one, lm_two and lm_three.  These four callouts, executed
+    /// in sequence, perform a series of calculations. Data is passed between
+    /// callouts in the argument list, in a variable named "result".
+    ///
+    /// context_create initializes the calculation by setting a seed
+    /// value, called r0 here.  This value is dependent on the library being
+    /// loaded.  Prior to that, the argument "result" is initialized to -1,
+    /// the purpose being to avoid exceptions when running this test with no
+    /// libraries loaded.
+    ///
+    /// Callout lm_one is passed a value d1 and performs a simple arithmetic
+    /// operation on it and r0 yielding a result r1.  Hence we can say that
+    /// @f[ r1 = lm1(r0, d1) @f]
+    ///
+    /// Callout lm_two is passed a value d2 and peforms another simple
+    /// arithmetic operation on it and d2, yielding r2, i.e.
+    /// @f[ r2 = lm2(d1, d2) @f]
+    ///
+    /// lm_three does a similar operation giving @f[ r3 = lm3(r2, d3) @f].
+    ///
+    /// The details of the operations lm1, lm2 and lm3 depend on the library.
+    /// However the sequence of calls needed to do this set of calculations
+    /// is identical regardless of the exact functions. This method performs
+    /// those operations and checks the results of each step.
+    ///
+    /// It is assumed that callout_manager_ has been set up appropriately.
+    ///
+    /// @note The CalloutHandle used in the calls is declared locally here.
+    ///       The advantage of this (apart from scope reduction) is that on
+    ///       exit, it is destroyed.  This removes any references to memory
+    ///       allocated by loaded libraries while they are still loaded.
+    ///
+    /// @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";
+
+        int result;
+
+        // Set up a callout handle for the calls.
+        CalloutHandle callout_handle(callout_manager_);
+
+        // 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.
+        callout_handle.setArgument(RESULT, -1);
+
+        // Seed the calculation.
+        callout_manager_->callCallouts(ServerHooks::CONTEXT_CREATE,
+                                       callout_handle);
+        callout_handle.getArgument(RESULT, result);
+        EXPECT_EQ(r0, result) << "context_create" << COMMON_TEXT;
+
+        // Perform the first calculation.
+        callout_handle.setArgument("data_1", d1);
+        callout_manager_->callCallouts(lm_one_index_, callout_handle);
+        callout_handle.getArgument(RESULT, result);
+        EXPECT_EQ(r1, result) << "lm_one" << COMMON_TEXT;
+
+        // ... the second ...
+        callout_handle.setArgument("data_2", d2);
+        callout_manager_->callCallouts(lm_two_index_, callout_handle);
+        callout_handle.getArgument(RESULT, result);
+        EXPECT_EQ(r2, result) << "lm_two" << COMMON_TEXT;
+
+        // ... and the third.
+        callout_handle.setArgument("data_3", d3);
+        callout_manager_->callCallouts(lm_three_index_, callout_handle);
+        callout_handle.getArgument(RESULT, result);
+        EXPECT_EQ(r3, result) << "lm_three" << COMMON_TEXT;
+    }
+
+    /// Hook indexes.  These are are made public for ease of reference.
+    int lm_one_index_;
+    int lm_two_index_;
+    int lm_three_index_;
+
+    /// Callout manager used in the executeCallCallouts() call.
+    boost::shared_ptr<CalloutManager> callout_manager_;
+};
+
+/// @brief Public library manager collection class
+///
+/// This is an instance of the LibraryManagerCollection class but with the
+/// protected methods made public for test purposes.
+
+class PublicLibraryManagerCollection
+                : public isc::hooks::LibraryManagerCollection {
+public:
+    /// @brief Constructor
+    ///
+    /// @param List of libraries that this collection will manage.  The order
+    ///        of the libraries is important.
+    PublicLibraryManagerCollection(const std::vector<std::string>& libraries)
+        : LibraryManagerCollection(libraries)
+    {}
+
+    /// Public methods that call protected methods on the superclass.
+    using LibraryManagerCollection::unloadLibraries;
+};
+
+
+// This is effectively the same test as for LibraryManager, but using the
+// LibraryManagerCollection object.
+
+TEST_F(LibraryManagerCollectionTest, 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());
+    callout_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(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(-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());
+    callout_manager_ = lm_collection.getCalloutManager();
+
+    // Expect only two libraries were loaded.
+    EXPECT_EQ(2, callout_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(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(-1, 3, -1, 22, -1, 83, -1);
+    }
+}
+
+// Check that everything works even with no libraries loaded.
+
+TEST_F(LibraryManagerCollectionTest, NoLibrariesLoaded) {
+    // Set up the list of libraries to be loaded.
+    std::vector<std::string> library_names;
+
+    // Set up the library manager collection and get the callout manager we'll
+    // be using.
+    LibraryManagerCollection lm_collection(library_names);
+    EXPECT_TRUE(lm_collection.loadLibraries());
+    callout_manager_ = lm_collection.getCalloutManager();
+
+    // Load the libraries.
+    EXPECT_TRUE(lm_collection.loadLibraries());
+
+    // Eecute the calculation - callouts can be called but as nothing
+    // happens, the result should always be -1.
+    executeCallCallouts(-1, 3, -1, 22, -1, 83, -1);
+}
+
+} // Anonymous namespace

+ 2 - 14
src/lib/hooks/tests/library_manager_unittest.cc.in

@@ -16,7 +16,9 @@
 #include <hooks/callout_manager.h>
 #include <hooks/library_manager.h>
 #include <hooks/server_hooks.h>
+
 #include <hooks/tests/marker_file.h>
+#include <hooks/tests/test_libraries.h>
 
 #include <gtest/gtest.h>
 
@@ -33,20 +35,6 @@ using namespace std;
 
 namespace {
 
-// Names of the libraries used in these tests.  These libraries are built using
-// libtool, so we need to look in the hidden ".libs" directory to locate the
-// .so file.  Note that we access the .so file - libtool creates this as a
-// like to the real shared library.
-static const char* BASIC_CALLOUT_LIBRARY = "@abs_builddir@/.libs/libbcl.so";
-static const char* FULL_CALLOUT_LIBRARY = "@abs_builddir@/.libs/libfcl.so";
-static const char* INCORRECT_VERSION_LIBRARY = "@abs_builddir@/.libs/libivl.so";
-static const char* LOAD_CALLOUT_LIBRARY = "@abs_builddir@/.libs/liblcl.so";
-static const char* LOAD_ERROR_CALLOUT_LIBRARY =
-    "@abs_builddir@/.libs/liblecl.so";
-static const char* NOT_PRESENT_LIBRARY = "@abs_builddir@/.libs/libnothere.so";
-static const char* NO_VERSION_LIBRARY = "@abs_builddir@/.libs/libnvl.so";
-static const char* UNLOAD_CALLOUT_LIBRARY = "@abs_builddir@/.libs/libucl.so";
-
 /// @brief Library manager test class
 
 class LibraryManagerTest : public ::testing::Test {

+ 55 - 0
src/lib/hooks/tests/test_libraries.h.in

@@ -0,0 +1,55 @@
+// 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 TEST_LIBRARIES_H
+#define TEST_LIBRARIES_H
+
+namespace {
+
+// Names of the libraries used in these tests.  These libraries are built using
+// libtool, so we need to look in the hidden ".libs" directory to locate the
+// .so file.  Note that we access the .so file - libtool creates this as a
+// like to the real shared library.
+
+// Basic library with context_create and three "standard" callouts.
+static const char* BASIC_CALLOUT_LIBRARY = "@abs_builddir@/.libs/libbcl.so";
+
+// Library with context_create and three "standard" callouts, as well as
+// load() and unload() functions.
+static const char* FULL_CALLOUT_LIBRARY = "@abs_builddir@/.libs/libfcl.so";
+
+// Library where the version() function returns an incorrect result.
+static const char* INCORRECT_VERSION_LIBRARY = "@abs_builddir@/.libs/libivl.so";
+
+// Library where some of the callout registration is done with the load()
+// function.
+static const char* LOAD_CALLOUT_LIBRARY = "@abs_builddir@/.libs/liblcl.so";
+
+// Library where the load() function returns an error.
+static const char* LOAD_ERROR_CALLOUT_LIBRARY =
+    "@abs_builddir@/.libs/liblecl.so";
+
+// Name of a library which is not present.
+static const char* NOT_PRESENT_LIBRARY = "@abs_builddir@/.libs/libnothere.so";
+
+// Library that does not include a version function.
+static const char* NO_VERSION_LIBRARY = "@abs_builddir@/.libs/libnvl.so";
+
+// Library where there is an unload() function.
+static const char* UNLOAD_CALLOUT_LIBRARY = "@abs_builddir@/.libs/libucl.so";
+
+} // anonymous namespace
+
+
+#endif // TEST_LIBRARIES_H