Browse Source

[2974] Added first part of CalloutHandle code

This part sets and gets the argument list and the skip flag.
Also modified the LibraryCallback code to handle the skip flag, and
added another using test to check that.
Stephen Morris 12 years ago
parent
commit
26f53e4d06

+ 1 - 0
src/lib/util/Makefile.am

@@ -37,6 +37,7 @@ libb10_util_la_SOURCES += encode/base32hex_from_binary.h
 libb10_util_la_SOURCES += encode/base_n.cc encode/hex.h
 libb10_util_la_SOURCES += encode/binary_from_base32hex.h
 libb10_util_la_SOURCES += encode/binary_from_base16.h
+libb10_util_la_SOURCES += hooks/callout_handle.h
 libb10_util_la_SOURCES += hooks/library_handle.h hooks/library_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

+ 162 - 0
src/lib/util/hooks/callout_handle.h

@@ -0,0 +1,162 @@
+// 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 CALLOUT_HANDLE_H
+#define CALLOUT_HANDLE_H
+
+#include <exceptions/exceptions.h>
+
+#include <boost/any.hpp>
+#include <boost/shared_ptr.hpp>
+
+#include <map>
+#include <string>
+#include <vector>
+
+namespace isc {
+namespace util {
+
+/// @brief No such argument
+///
+/// Thrown if an attempt is made to use an invalid argument name.
+class NoSuchArgument : public Exception {
+public:
+    NoSuchArgument(const char* file, size_t line, const char* what) :
+        isc::Exception(file, line, what) {}
+};
+
+// Forward declaration of the hook manager class
+class HookManager;
+
+/// @brief Per-Packet callout handle
+///
+/// An object of this class is associated with every packet (or request)
+/// processed by the server.  It forms the principle means of passing 
+/// data between the server and the user-library callouts.
+
+class CalloutHandle {
+private:
+    /// Typedef to allow abbreviation of iterator specification in methods
+    typedef std::map<std::string, boost::any> ArgumentCollection;
+
+public:
+
+    /// @brief Constructor
+    ///
+    /// @param manager Pointer to the HookManager object controlling the
+    ///        the operations of the hooks.
+    CalloutHandle(boost::shared_ptr<HookManager>& manager)
+        : arguments_(), manager_(manager), skip_(false)
+    {}
+
+    /// @brief Set argument
+    ///
+    /// Sets an argument.  If the argument is already present, it is replaced.
+    ///
+    /// @param name Name of the element in the context to set
+    /// @param value Value to set
+    template <typename T>
+    void setArgument(const std::string& name, T value) {
+        arguments_[name] = value;
+    }
+
+    /// @brief Get argument
+    ///
+    /// Gets an argument.  If an argument of the given name does not exist,
+    /// a "NoSuchArgument" exception is thrown.
+    ///
+    /// @param name Name of the element in the argument list to set.
+    /// @param value [out] Value to set.  The type of "value" is important:
+    ///        it must match the type of the value set.
+    ///
+    /// @throw NoSuchArgument Thrown if no argument with the name "name" is
+    ///        present.
+    /// @throw boost::bad_any_cast Thrown if the context element is present,
+    ///        but the type of the element is not that expected
+    template <typename T>
+    void getArgument(const std::string& name, T& value) const {
+        ArgumentCollection::const_iterator element_ptr = arguments_.find(name);
+        if (element_ptr == arguments_.end()) {
+            isc_throw(NoSuchArgument, "unable to find argument with name " <<
+                      name);
+        }
+
+        value = boost::any_cast<T>(element_ptr->second);
+    }
+    
+    /// @brief Get argument names
+    ///
+    /// Returns a vector holding the names of arguments in the argument
+    /// vector.
+    ///
+    /// @return Vector of strings reflecting argument names
+    std::vector<std::string> getArgumentNames() const {
+        std::vector<std::string> a;
+        return (a);
+    }
+
+    /// @brief Delete argument
+    ///
+    /// Deletes an argument of the given name.  If an argument of that name
+    /// does not exist, the method is a no-op.
+    ///
+    /// @param name Name of the element in the argument list to set.
+    void deleteArgument(const std::string& name) {
+        static_cast<void>(arguments_.erase(name));
+    }
+
+    /// @brief Delete all arguments
+    ///
+    /// Deletes all arguments associated with this context.
+    void deleteAllArguments() {
+        arguments_.clear();
+    }
+
+    /// @brief Set skip flag
+    ///
+    /// Sets the "skip" variable in the callout handle.  This variable is
+    /// interrogated by the server to see if the remaining callouts should be
+    /// bypassed.
+    ///
+    /// @param skip New value of the "skip" flag.
+    void setSkip(bool skip) {
+        skip_ = skip;
+    }
+
+    /// @brief Get skip flag
+    ///
+    /// Gets the current value of the "skip" flag.
+    ///
+    /// @return Current value of the skip flag.
+    bool getSkip() const {
+        return (skip_);
+    }
+
+
+private:
+    /// Collection of arguments passed to the callouts
+    ArgumentCollection arguments_;
+
+    /// Controlling hook manager
+    boost::shared_ptr<HookManager> manager_;   ///< Controlling hook manager
+
+    /// "Skip" flag, indicating if the caller should bypass remaining callouts.
+    bool skip_;
+};
+
+} // namespace util
+} // namespace isc
+
+
+#endif // CALLOUT_HANDLE_H

+ 4 - 1
src/lib/util/hooks/library_handle.cc

@@ -12,6 +12,7 @@
 // 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>
@@ -87,7 +88,9 @@ LibraryHandle::callCallouts(int index, CalloutHandle& handle) {
     // Call all the callouts, stopping if a non-zero status is returned.
     // @todo also need to stop if the callout handle "skip" flag is set.
     int status = 0;
-    for (int i = 0; (i < hook_vector_[index].size()) && (status == 0); ++i) {
+    for (int i = 0;
+         (i < hook_vector_[index].size()) && !handle.getSkip() && (status == 0);
+          ++i) {
         status = (*hook_vector_[index][i])(handle);
     }
 

+ 1 - 1
src/lib/util/hooks/library_handle.h

@@ -81,7 +81,7 @@ public:
     ///
     /// @param hooks Pointer to the hooks registered by the server.
     /// @param index Index of this library in the list of loaded libraries.
-    LibraryHandle(boost::shared_ptr<ServerHooks> hooks, int index)
+    LibraryHandle(boost::shared_ptr<ServerHooks>& hooks, int index)
         : context_(), hooks_(hooks), hook_vector_(hooks->getCount()),
           index_(index)
     {}

+ 1 - 0
src/lib/util/tests/Makefile.am

@@ -25,6 +25,7 @@ run_unittests_SOURCES  = run_unittests.cc
 run_unittests_SOURCES += base32hex_unittest.cc
 run_unittests_SOURCES += base64_unittest.cc
 run_unittests_SOURCES += buffer_unittest.cc
+run_unittests_SOURCES += callout_handle_unittest.cc
 run_unittests_SOURCES += fd_share_tests.cc
 run_unittests_SOURCES += fd_tests.cc
 run_unittests_SOURCES += filename_unittest.cc

+ 305 - 0
src/lib/util/tests/callout_handle_unittest.cc

@@ -0,0 +1,305 @@
+// 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 <util/hooks/server_hooks.h>
+
+#include <boost/shared_ptr.hpp>
+
+#include <gtest/gtest.h>
+
+using namespace isc::util;
+using namespace std;
+
+// Dummy class for testing
+namespace isc {
+namespace util {
+class HookManager {
+public:
+    HookManager() {}
+};
+}
+}
+
+using namespace isc::util;
+using namespace std;
+
+namespace {
+
+class CalloutHandleTest : public ::testing::Test {
+public:
+    /// @brief Constructor
+    ///
+    /// Sets up an appropriate number of server hooks to pass to the
+    /// constructed callout handle objects.
+    CalloutHandleTest() : manager_(new HookManager()) {
+    }
+
+    /// Obtain hook manager
+    boost::shared_ptr<HookManager>& getHookManager() {
+        return (manager_);
+    }
+
+private:
+    boost::shared_ptr<HookManager> manager_;
+};
+
+// *** Argument Tests ***
+//
+// The first set of tests check that the CalloutHandle can store and retrieve
+// arguments.  These are very similar to the LibraryHandle context tests.
+
+// Test that we can store multiple values of the same type and that they
+// are distinct.
+
+TEST_F(CalloutHandleTest, ArgumentDistinctSimpleType) {
+    CalloutHandle handle(getHookManager());
+
+    // Store and retrieve an int (random value).
+    int a = 42;
+    handle.setArgument("integer1", a);
+    EXPECT_EQ(42, a);
+
+    int b = 0;
+    handle.getArgument("integer1", b);
+    EXPECT_EQ(42, b);
+
+    // Add another integer (another random value).
+    int c = 142;
+    handle.setArgument("integer2", c);
+    EXPECT_EQ(142, c);
+
+    int d = -1;
+    handle.getArgument("integer2", d);
+    EXPECT_EQ(142, d);
+
+    // Add a short (random value).
+    short e = 81; 
+    handle.setArgument("short", e);
+    EXPECT_EQ(81, e);
+
+    short f = -1;
+    handle.getArgument("short", f);
+    EXPECT_EQ(81, f);
+}
+
+// Test that trying to get something with an incorrect name throws an
+// exception.
+
+TEST_F(CalloutHandleTest, ArgumentUnknownName) {
+    CalloutHandle handle(getHookManager());
+
+    // Set an integer
+    int a = 42;
+    handle.setArgument("integer1", a);
+    EXPECT_EQ(42, a);
+
+    // Check we can retrieve it
+    int b = 0;
+    handle.getArgument("integer1", b);
+    EXPECT_EQ(42, b);
+
+    // Check that getting an unknown name throws an exception.
+    int c = -1;
+    EXPECT_THROW(handle.getArgument("unknown", c), NoSuchArgument);
+}
+
+// Test that trying to get something with an incorrect type throws an exception.
+
+TEST_F(CalloutHandleTest, ArgumentIncorrectType) {
+    CalloutHandle handle(getHookManager());
+
+    // Set an integer
+    int a = 42;
+    handle.setArgument("integer1", a);
+    EXPECT_EQ(42, a);
+
+    // Check we can retrieve it
+    long b = 0;
+    EXPECT_THROW(handle.getArgument("integer1", b), boost::bad_any_cast);
+}
+
+// Now try with some very complex types.  The types cannot be defined within
+// the function and they should contain a copy constructor.  For this reason,
+// a simple "struct" is used.
+
+struct Alpha {
+    int a;
+    int b;
+    Alpha(int first = 0, int second = 0) : a(first), b(second) {}
+};
+
+struct Beta {
+    int c;
+    int d;
+    Beta(int first = 0, int second = 0) : c(first), d(second) {}
+};
+
+TEST_F(CalloutHandleTest, ComplexTypes) {
+    CalloutHandle handle(getHookManager());
+
+    // Declare two variables of different (complex) types. (Note as to the
+    // variable names: aleph and beth are the first two letters of the Hebrew
+    // alphabet.)
+    Alpha aleph(1, 2);
+    EXPECT_EQ(1, aleph.a);
+    EXPECT_EQ(2, aleph.b);
+    handle.setArgument("aleph", aleph);
+
+    Beta beth(11, 22);
+    EXPECT_EQ(11, beth.c);
+    EXPECT_EQ(22, beth.d);
+    handle.setArgument("beth", beth);
+
+    // Ensure we can extract the data correctly
+    Alpha aleph2;
+    EXPECT_EQ(0, aleph2.a);
+    EXPECT_EQ(0, aleph2.b);
+    handle.getArgument("aleph", aleph2);
+    EXPECT_EQ(1, aleph2.a);
+    EXPECT_EQ(2, aleph2.b);
+
+    Beta beth2;
+    EXPECT_EQ(0, beth2.c);
+    EXPECT_EQ(0, beth2.d);
+    handle.getArgument("beth", beth2);
+    EXPECT_EQ(11, beth2.c);
+    EXPECT_EQ(22, beth2.d);
+
+    // Ensure that complex types also thrown an exception if we attempt to
+    // get a context element of the wrong type.
+    EXPECT_THROW(handle.getArgument("aleph", beth), boost::bad_any_cast);
+}
+
+// Check that the context can store pointers. And also check that it respects
+// that a "pointer to X" is not the same as a "pointer to const X".
+
+TEST_F(CalloutHandleTest, PointerTypes) {
+    CalloutHandle handle(getHookManager());
+
+    // Declare a couple of variables, const and non-const.
+    Alpha aleph(5, 10);
+    const Beta beth(15, 20);
+
+    Alpha* pa = &aleph;
+    const Beta* pcb = &beth;
+
+    // Check pointers can be set and retrieved OK
+    handle.setArgument("non_const_pointer", pa);
+    handle.setArgument("const_pointer", pcb);
+
+    Alpha* pa2 = 0;
+    handle.getArgument("non_const_pointer", pa2);
+    EXPECT_TRUE(pa == pa2);
+
+    const Beta* pcb2 = 0;
+    handle.getArgument("const_pointer", pcb2);
+    EXPECT_TRUE(pcb == pcb2);
+
+    // Check that the "const" is protected in the context.
+    const Alpha* pca3;
+    EXPECT_THROW(handle.getArgument("non_const_pointer", pca3),
+                 boost::bad_any_cast);
+
+    Beta* pb3;
+    EXPECT_THROW(handle.getArgument("const_pointer", pb3),
+                 boost::bad_any_cast);
+}
+
+// Test that we can delete and argument.
+
+TEST_F(CalloutHandleTest, DeleteArgument) {
+    CalloutHandle handle(getHookManager());
+
+    int one = 1;
+    int two = 2;
+    int three = 3;
+    int four = 4;
+    int value;      // Return value
+
+    handle.setArgument("one", one);
+    handle.setArgument("two", two);
+    handle.setArgument("three", three);
+    handle.setArgument("four", four);
+
+    // Delete "one"
+    handle.getArgument("one", value);
+    EXPECT_EQ(1, value);
+    handle.deleteArgument("one");
+
+    EXPECT_THROW(handle.getArgument("one", value), NoSuchArgument);
+    handle.getArgument("two", value);
+    EXPECT_EQ(2, value);
+    handle.getArgument("three", value);
+    EXPECT_EQ(3, value);
+    handle.getArgument("four", value);
+    EXPECT_EQ(4, value);
+
+    // Delete "three".
+    handle.getArgument("three", value);
+    EXPECT_EQ(3, value);
+    handle.deleteArgument("three");
+
+    EXPECT_THROW(handle.getArgument("one", value), NoSuchArgument);
+    handle.getArgument("two", value);
+    EXPECT_EQ(2, value);
+    EXPECT_THROW(handle.getArgument("three", value), NoSuchArgument);
+    handle.getArgument("four", value);
+    EXPECT_EQ(4, value);
+}
+
+// Test that we can delete all arguments
+
+TEST_F(CalloutHandleTest, DeleteAllArguments) {
+    CalloutHandle handle(getHookManager());
+
+    int one = 1;
+    int two = 2;
+    int three = 3;
+    int four = 4;
+    int value;      // Return value
+
+    // Set the arguments.  The previous test verifies that this works.
+    handle.setArgument("one", one);
+    handle.setArgument("two", two);
+    handle.setArgument("three", three);
+    handle.setArgument("four", four);
+
+    // Delete all arguments...
+    handle.deleteAllArguments();
+
+    // ... and check that none are left.
+    EXPECT_THROW(handle.getArgument("one", value), NoSuchArgument);
+    EXPECT_THROW(handle.getArgument("two", value), NoSuchArgument);
+    EXPECT_THROW(handle.getArgument("three", value), NoSuchArgument);
+    EXPECT_THROW(handle.getArgument("four", value), NoSuchArgument);
+}
+
+// Test the "skip" flag.
+
+TEST_F(CalloutHandleTest, SkipFlag) {
+    CalloutHandle handle(getHookManager());
+
+    // Should be false on construction.
+    EXPECT_FALSE(handle.getSkip());
+
+    handle.setSkip(true);
+    EXPECT_TRUE(handle.getSkip());
+
+    handle.setSkip(false);
+    EXPECT_FALSE(handle.getSkip());
+}
+
+} // Anonymous namespace

+ 60 - 17
src/lib/util/tests/library_handle_unittest.cc

@@ -12,6 +12,7 @@
 // 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 <util/hooks/server_hooks.h>
 
@@ -23,7 +24,7 @@ using namespace std;
 // Dummy class for testing
 namespace isc {
 namespace util {
-class CalloutHandle {};
+class HookManager {};
 }
 }
 
@@ -35,7 +36,8 @@ public:
     ///
     /// Sets up an appropriate number of server hooks to pass to the
     /// constructed callout handle objects.
-    LibraryHandleTest() : hooks_(new ServerHooks()) {
+    LibraryHandleTest()
+        : hooks_(new ServerHooks()), manager_(new HookManager()) {
         hooks_->registerHook("alpha");
         hooks_->registerHook("beta");
         hooks_->registerHook("gamma");
@@ -47,10 +49,15 @@ public:
     }
 
     /// Obtain constructed server hooks
-    boost::shared_ptr<ServerHooks> getServerHooks() {
+    boost::shared_ptr<ServerHooks>& getServerHooks() {
         return (hooks_);
     }
 
+    // Obtain constructed hook manager
+    boost::shared_ptr<HookManager>& getHookManager() {
+        return (manager_);
+    }
+
     /// Variables for callouts test. These are public and static to allow non-
     /// member functions to access them, but declared as class variables to
     /// allow initialization every time the test starts.
@@ -60,6 +67,7 @@ public:
 
 private:
     boost::shared_ptr<ServerHooks> hooks_;
+    boost::shared_ptr<HookManager> manager_;
 };
 
 // Definition of the static variables.
@@ -278,6 +286,14 @@ int one_error(CalloutHandle& handle) {
     return (1);
 }
 
+// The next function is a duplicate of "one", but sets the skip flag.
+
+int one_skip(CalloutHandle& handle) {
+    (void) one(handle);
+    handle.setSkip(true);
+    return (0);
+}
+
 };  // extern "C"
 
 // Check that we can register callouts on a particular hook.
@@ -315,8 +331,8 @@ TEST_F(LibraryHandleTest, CallSingleCallout) {
     EXPECT_EQ(0, LibraryHandleTest::callout_value);
 
     int index = getServerHooks()->getIndex("alpha");
-    CalloutHandle dummy;
-    int status = handle.callCallouts(index, dummy);
+    CalloutHandle callout_handle(getHookManager());
+    int status = handle.callCallouts(index, callout_handle);
 
     EXPECT_EQ(0, status);
     EXPECT_EQ(1, LibraryHandleTest::one_count);
@@ -341,8 +357,8 @@ TEST_F(LibraryHandleTest, TwoCallouts) {
     EXPECT_EQ(0, LibraryHandleTest::callout_value);
 
     int index = getServerHooks()->getIndex("alpha");
-    CalloutHandle dummy;
-    int status = handle.callCallouts(index, dummy);
+    CalloutHandle callout_handle(getHookManager());
+    int status = handle.callCallouts(index, callout_handle);
 
     EXPECT_EQ(0, status);
     EXPECT_EQ(1, LibraryHandleTest::one_count);
@@ -366,8 +382,8 @@ TEST_F(LibraryHandleTest, TwoCalloutsWithError) {
     EXPECT_EQ(0, LibraryHandleTest::callout_value);
 
     int index = getServerHooks()->getIndex("alpha");
-    CalloutHandle dummy;
-    int status = handle.callCallouts(index, dummy);
+    CalloutHandle callout_handle(getHookManager());
+    int status = handle.callCallouts(index, callout_handle);
 
     EXPECT_EQ(1, status);
     EXPECT_EQ(1, LibraryHandleTest::one_count);
@@ -375,6 +391,31 @@ TEST_F(LibraryHandleTest, TwoCalloutsWithError) {
     EXPECT_EQ(10, LibraryHandleTest::callout_value);
 }
 
+// Check that we can register two callouts for a hook and that the second is not
+// called if the first returns a non-zero status.
+
+TEST_F(LibraryHandleTest, TwoCalloutsWithSkip) {
+    LibraryHandle handle(getServerHooks(), 1);
+
+    // Register callout for hook alpha...
+    handle.registerCallout("alpha", one_skip);
+    handle.registerCallout("alpha", two);
+
+    // Call them.
+    EXPECT_EQ(0, LibraryHandleTest::one_count);
+    EXPECT_EQ(0, LibraryHandleTest::two_count);
+    EXPECT_EQ(0, LibraryHandleTest::callout_value);
+
+    int index = getServerHooks()->getIndex("alpha");
+    CalloutHandle callout_handle(getHookManager());
+    int status = handle.callCallouts(index, callout_handle);
+
+    EXPECT_EQ(0, status);
+    EXPECT_EQ(1, LibraryHandleTest::one_count);
+    EXPECT_EQ(0, LibraryHandleTest::two_count);
+    EXPECT_EQ(10, LibraryHandleTest::callout_value);
+}
+
 // Check that a callout can be registered more than once.
 
 TEST_F(LibraryHandleTest, MultipleRegistration) {
@@ -391,8 +432,8 @@ TEST_F(LibraryHandleTest, MultipleRegistration) {
     EXPECT_EQ(0, LibraryHandleTest::callout_value);
 
     int index = getServerHooks()->getIndex("alpha");
-    CalloutHandle dummy;
-    int status = handle.callCallouts(index, dummy);
+    CalloutHandle callout_handle(getHookManager());
+    int status = handle.callCallouts(index, callout_handle);
 
     EXPECT_EQ(0, status);
     EXPECT_EQ(2, LibraryHandleTest::one_count);
@@ -402,7 +443,7 @@ TEST_F(LibraryHandleTest, MultipleRegistration) {
 
 // Check that a callout can be deregistered.
 
-TEST_F(LibraryHandleTest, Degreister) {
+TEST_F(LibraryHandleTest, Deregister) {
     LibraryHandle handle(getServerHooks(), 1);
 
     // Register callouts for hook alpha...
@@ -419,8 +460,8 @@ TEST_F(LibraryHandleTest, Degreister) {
     EXPECT_EQ(0, LibraryHandleTest::callout_value);
 
     int index = getServerHooks()->getIndex("alpha");
-    CalloutHandle dummy;
-    int status = handle.callCallouts(index, dummy);
+    CalloutHandle callout_handle(getHookManager());
+    int status = handle.callCallouts(index, callout_handle);
 
     EXPECT_EQ(0, status);
     EXPECT_EQ(0, LibraryHandleTest::one_count);
@@ -457,9 +498,11 @@ TEST_F(LibraryHandleTest, InvalidNameAndIndex) {
     EXPECT_THROW(static_cast<void>(handle.calloutsPresent(-1)), NoSuchHook);
     EXPECT_THROW(static_cast<void>(handle.calloutsPresent(5)), NoSuchHook);
 
-    CalloutHandle dummy;
-    EXPECT_THROW(static_cast<void>(handle.callCallouts(-1, dummy)), NoSuchHook);
-    EXPECT_THROW(static_cast<void>(handle.callCallouts(10, dummy)), NoSuchHook);
+    CalloutHandle callout_handle(getHookManager());
+    EXPECT_THROW(static_cast<void>(handle.callCallouts(-1, callout_handle)),
+                 NoSuchHook);
+    EXPECT_THROW(static_cast<void>(handle.callCallouts(10, callout_handle)),
+                 NoSuchHook);
 }