From: Stephen Morris Date: Mon, 10 Jun 2013 16:23:48 +0000 (+0100) Subject: [2974] Updated CalloutHandle to use the new CalloutManager X-Git-Tag: bind10-1.2.0beta1-release~402^2~3 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=b1c398bbc0d7b7b066347cff13ea8fb310bf4f10;p=thirdparty%2Fkea.git [2974] Updated CalloutHandle to use the new CalloutManager --- diff --git a/src/lib/util/hooks/callout_handle.cc b/src/lib/util/hooks/callout_handle.cc index 4aab9fe94c..5b6b3b221a 100644 --- a/src/lib/util/hooks/callout_handle.cc +++ b/src/lib/util/hooks/callout_handle.cc @@ -106,7 +106,8 @@ CalloutHandle::getContextForLibrary() const { context_collection_.find(libindex); if (libcontext == context_collection_.end()) { isc_throw(NoSuchCalloutContext, "unable to find callout context " - "associated with the current library handle"); + "associated with the current library index (" << libindex << + ")"); } // Return a reference to the context's element collection. diff --git a/src/lib/util/hooks/callout_manager.cc b/src/lib/util/hooks/callout_manager.cc index 0b88888449..7ab6131e7d 100644 --- a/src/lib/util/hooks/callout_manager.cc +++ b/src/lib/util/hooks/callout_manager.cc @@ -78,14 +78,32 @@ CalloutManager::callCallouts(int hook_index, CalloutHandle& callout_handle) { // call. callout_handle.setSkip(false); - // Call all the callouts, stopping if the "skip" flag is set or if a - // non-zero status is returned. + // Duplicate the callout vector for this hook and work through that. + // This step is needed because we allow dynamic registration and + // deregistration of callouts. If a callout attached to a hook modified + // the list of callouts, the underlying CalloutVector would change and + // potentially affect the iteration through that vector. + CalloutVector callouts(hook_vector_[hook_index]); + + // Call all the callouts, stopping 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) { + + for (CalloutVector::const_iterator i = callouts.begin(); + i != callouts.end() && (status == 0); ++i) { + // In case the callout tries to register or deregister a callout, set + // the current library index to the index associated with the callout + // being called. + current_library_ = i->first; + + // Call the callout status = (*i->second)(callout_handle); } + // Reset the current library index to an invalid value to catch any + // programming errors. + current_library_ = -1; + + return (status); } diff --git a/src/lib/util/hooks/callout_manager.h b/src/lib/util/hooks/callout_manager.h index df3f505bab..f42901ba7e 100644 --- a/src/lib/util/hooks/callout_manager.h +++ b/src/lib/util/hooks/callout_manager.h @@ -168,6 +168,9 @@ public: /// 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 hook_index Index of the hook to call. /// @param callout_handle Reference to the CalloutHandle object for the /// current object being processed. diff --git a/src/lib/util/tests/Makefile.am b/src/lib/util/tests/Makefile.am index 8f9306034d..ceb8b95c03 100644 --- a/src/lib/util/tests/Makefile.am +++ b/src/lib/util/tests/Makefile.am @@ -31,7 +31,7 @@ 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 += lru_list_unittest.cc run_unittests_SOURCES += memory_segment_local_unittest.cc diff --git a/src/lib/util/tests/callout_manager_unittest.cc b/src/lib/util/tests/callout_manager_unittest.cc index 630b18bd23..ebd4773d9f 100644 --- a/src/lib/util/tests/callout_manager_unittest.cc +++ b/src/lib/util/tests/callout_manager_unittest.cc @@ -506,7 +506,10 @@ TEST_F(CalloutManagerTest, DeregisterSingleCallout) { EXPECT_EQ(0, status); EXPECT_EQ(2, callout_value_); - // Remove it and check that the no callouts are present. + // Remove it and check that the no callouts are present. We have to reset + // the current library index here as it was invalidated by the call + // to callCallouts(). + getCalloutManager()->setLibraryIndex(0); EXPECT_TRUE(getCalloutManager()->calloutsPresent(alpha_index_)); EXPECT_TRUE(getCalloutManager()->deregisterCallout("alpha", manager_two)); EXPECT_FALSE(getCalloutManager()->calloutsPresent(alpha_index_)); @@ -536,7 +539,9 @@ TEST_F(CalloutManagerTest, DeregisterSingleCalloutSameLibrary) { EXPECT_EQ(0, status); EXPECT_EQ(1234, callout_value_); - // Remove the manager_two callout. + // Remove the manager_two callout. We have to reset the current library + // index here as it was invalidated by the call to callCallouts(). + getCalloutManager()->setLibraryIndex(0); EXPECT_TRUE(getCalloutManager()->deregisterCallout("alpha", manager_two)); callout_value_ = 0; status = getCalloutManager()->callCallouts(alpha_index_, @@ -545,6 +550,7 @@ TEST_F(CalloutManagerTest, DeregisterSingleCalloutSameLibrary) { EXPECT_EQ(134, callout_value_); // Try removing it again. + getCalloutManager()->setLibraryIndex(0); EXPECT_FALSE(getCalloutManager()->deregisterCallout("alpha", manager_two)); callout_value_ = 0; status = getCalloutManager()->callCallouts(alpha_index_, @@ -581,7 +587,9 @@ TEST_F(CalloutManagerTest, DeregisterMultipleCalloutsSameLibrary) { EXPECT_EQ(0, status); EXPECT_EQ(12123434, callout_value_); - // Remove the manager_two callouts. + // Remove the manager_two callouts. We have to reset the current library + // index here as it was invalidated by the call to callCallouts(). + getCalloutManager()->setLibraryIndex(0); EXPECT_TRUE(getCalloutManager()->deregisterCallout("alpha", manager_two)); callout_value_ = 0; status = getCalloutManager()->callCallouts(alpha_index_, @@ -591,6 +599,7 @@ TEST_F(CalloutManagerTest, DeregisterMultipleCalloutsSameLibrary) { // Try removing multiple callouts that includes one at the end of the // list of callouts. + getCalloutManager()->setLibraryIndex(0); EXPECT_TRUE(getCalloutManager()->deregisterCallout("alpha", manager_four)); callout_value_ = 0; status = getCalloutManager()->callCallouts(alpha_index_, @@ -599,6 +608,7 @@ TEST_F(CalloutManagerTest, DeregisterMultipleCalloutsSameLibrary) { EXPECT_EQ(1133, callout_value_); // ... and from the start. + getCalloutManager()->setLibraryIndex(0); EXPECT_TRUE(getCalloutManager()->deregisterCallout("alpha", manager_one)); callout_value_ = 0; status = getCalloutManager()->callCallouts(alpha_index_, @@ -607,6 +617,7 @@ TEST_F(CalloutManagerTest, DeregisterMultipleCalloutsSameLibrary) { EXPECT_EQ(33, callout_value_); // ... and the remaining callouts. + getCalloutManager()->setLibraryIndex(0); EXPECT_TRUE(getCalloutManager()->deregisterCallout("alpha", manager_three)); callout_value_ = 0; status = getCalloutManager()->callCallouts(alpha_index_, diff --git a/src/lib/util/tests/handles_unittest.cc b/src/lib/util/tests/handles_unittest.cc index 34ecc51d21..7bcc232aef 100644 --- a/src/lib/util/tests/handles_unittest.cc +++ b/src/lib/util/tests/handles_unittest.cc @@ -13,10 +13,12 @@ // PERFORMANCE OF THIS SOFTWARE. #include +#include #include #include #include +#include #include #include @@ -35,14 +37,52 @@ /// - The various methods manipulating the items in the CalloutHandle's context /// work correctly. /// -/// Some minor interactions between the two classes are checked in the unit -/// tests for each class (mainly the use of the "skip" flag). +/// - An active callout can only modify the registration of callouts registered +/// by its own library. using namespace isc::util; using namespace std; namespace { +class HandlesTest : public ::testing::Test { +public: + /// @brief Constructor + /// + /// Sets up the various elements used in each test. + HandlesTest() : hooks_(new ServerHooks()), manager_() + { + // Set up four hooks, although through gamma + alpha_index_ = hooks_->registerHook("alpha"); + beta_index_ = hooks_->registerHook("beta"); + gamma_index_ = hooks_->registerHook("gamma"); + delta_index_ = hooks_->registerHook("delta"); + + // Set up for three libraries. + manager_.reset(new CalloutManager(hooks_, 3)); + } + + /// @brief Return callout manager + boost::shared_ptr getCalloutManager() { + return (manager_); + } + + /// Hook indexes - these are frequently accessed, so are accessed directly. + int alpha_index_; + int beta_index_; + int gamma_index_; + int delta_index_; + +private: + /// Server hooks + boost::shared_ptr hooks_; + + /// Callout manager. Declared static so that the callout functions can + /// access it. + boost::shared_ptr manager_; + +}; + // The next set of functions define the callouts used by the tests. They // manipulate the data in such a way that callouts called - and the order in // which they were called - can be determined. The functions also check that @@ -59,7 +99,7 @@ namespace { // identification has been set in the callout handle). // // For simplicity, and to cut down the number of functions actually written, -// the callout indicator ("a" or "b") ) used in the in the CalloutHandle +// the callout indicator ("1" or "2") ) used in the in the CalloutHandle // functions is passed via a CalloutArgument. The argument is named "string": // use of a name the same as that of one of the context elements serves as a // check that the argument name space and argument context space are separate. @@ -140,7 +180,7 @@ execute(CalloutHandle& callout_handle, int library_num, int callout_num) { string_value = ""; } - // Update the values and set them. + // Update the values and set them back in the callout context. int_value += idata; callout_handle.setContext("int", int_value); @@ -228,71 +268,59 @@ print3(CalloutHandle& callout_handle) { // This test checks the many-faced nature of the context for the CalloutContext. -TEST(HandlesTest, ContextAccessCheck) { - // Create the LibraryHandleCollection with a set of four callouts (the test - // does not use the context_create and context_destroy callouts). - - boost::shared_ptr server_hooks(new ServerHooks()); - const int one_index = server_hooks->registerHook("one"); - const int two_index = server_hooks->registerHook("two"); - const int three_index = server_hooks->registerHook("three"); - const int four_index = server_hooks->registerHook("four"); - - // Create the library handle collection and the library handles. - boost::shared_ptr - collection(new LibraryHandleCollection()); - - boost::shared_ptr handle(new LibraryHandle(server_hooks)); - handle->registerCallout("one", callout11); - handle->registerCallout("two", callout12); - handle->registerCallout("three", callout13); - handle->registerCallout("four", print1); - collection->addLibraryHandle(handle); - - handle.reset(new LibraryHandle(server_hooks)); - handle->registerCallout("one", callout21); - handle->registerCallout("two", callout22); - handle->registerCallout("three", callout23); - handle->registerCallout("four", print2); - collection->addLibraryHandle(handle); - - handle.reset(new LibraryHandle(server_hooks)); - handle->registerCallout("one", callout31); - handle->registerCallout("two", callout32); - handle->registerCallout("three", callout33); - handle->registerCallout("four", print3); - collection->addLibraryHandle(handle); +TEST_F(HandlesTest, ContextAccessCheck) { + // Register callouts for the different libraries. + CalloutHandle handle(getCalloutManager()); + + // Library 0. + getCalloutManager()->setLibraryIndex(0); + getCalloutManager()->registerCallout("alpha", callout11); + getCalloutManager()->registerCallout("beta", callout12); + getCalloutManager()->registerCallout("gamma", callout13); + getCalloutManager()->registerCallout("delta", print1); + + getCalloutManager()->setLibraryIndex(1); + getCalloutManager()->registerCallout("alpha", callout21); + getCalloutManager()->registerCallout("beta", callout22); + getCalloutManager()->registerCallout("gamma", callout23); + getCalloutManager()->registerCallout("delta", print2); + + getCalloutManager()->setLibraryIndex(2); + getCalloutManager()->registerCallout("alpha", callout31); + getCalloutManager()->registerCallout("beta", callout32); + getCalloutManager()->registerCallout("gamma", callout33); + getCalloutManager()->registerCallout("delta", print3); // Create the callout handles and distinguish them by setting the // "handle_num" argument. - CalloutHandle callout_handle_1(collection); + CalloutHandle callout_handle_1(getCalloutManager()); callout_handle_1.setArgument("handle_num", static_cast(1)); - CalloutHandle callout_handle_2(collection); + CalloutHandle callout_handle_2(getCalloutManager()); callout_handle_2.setArgument("handle_num", static_cast(2)); // Now call the callouts attached to the first three hooks. Each hook is // called twice (once for each callout handle) before the next hook is // called. - collection->callCallouts(one_index, callout_handle_1); - collection->callCallouts(one_index, callout_handle_2); - collection->callCallouts(two_index, callout_handle_1); - collection->callCallouts(two_index, callout_handle_2); - collection->callCallouts(three_index, callout_handle_1); - collection->callCallouts(three_index, callout_handle_2); - - // Get the results for each callout. Explicitly zero the variables before - // getting the results so we are certain that the values are the results - // of the callouts. + getCalloutManager()->callCallouts(alpha_index_, callout_handle_1); + getCalloutManager()->callCallouts(alpha_index_, callout_handle_2); + getCalloutManager()->callCallouts(beta_index_, callout_handle_1); + getCalloutManager()->callCallouts(beta_index_, callout_handle_2); + getCalloutManager()->callCallouts(gamma_index_, callout_handle_1); + getCalloutManager()->callCallouts(gamma_index_, callout_handle_2); + + // Get the results for each callout (the callout on hook "delta" copies + // the context values into a location the test can access). Explicitly + // zero the variables before getting the results so we are certain that + // the values are the results of the callouts. zero_results(); - collection->callCallouts(four_index, callout_handle_1); // To explain the expected callout context results. // - // The callout handle maintains a separate context for each library. When + // Each callout handle maintains a separate context for each library. When // the first call to callCallouts() is made, "111" gets appended to - // the context for library 1 maintained by by the callout handle, "211" + // the context for library 1 maintained by the first callout handle, "211" // gets appended to the context maintained for library 2, and "311" to // the context maintained for library 3. In each case, the first digit // corresponds to the library number, the second to the callout number and @@ -307,9 +335,9 @@ TEST(HandlesTest, ContextAccessCheck) { // always 2. These additions don't affect the contexts maintained by // callout handle 1. // - // The process is then repeated for hooks "two" and "three" which, for - // callout handle 1, append "121", "221" and "321" for hook "two" and "311", - // "321" and "331" for hook "three". + // The process is then repeated for hooks "beta" and "gamma" which, for + // callout handle 1, append "121", "221" and "321" for hook "beta" and + // "311", "321" and "331" for hook "gamma". // // The expected integer values can be found by summing up the values // corresponding to the elements of the strings. @@ -318,6 +346,7 @@ TEST(HandlesTest, ContextAccessCheck) { // handle "1", so the following results are checking the context values // maintained in that callout handle. + getCalloutManager()->callCallouts(delta_index_, callout_handle_1); EXPECT_EQ("111121131", resultCalloutString(0)); EXPECT_EQ("211221231", resultCalloutString(1)); EXPECT_EQ("311321331", resultCalloutString(2)); @@ -329,7 +358,7 @@ TEST(HandlesTest, ContextAccessCheck) { // Repeat the checks for callout 2. zero_results(); - collection->callCallouts(four_index, callout_handle_2); + getCalloutManager()->callCallouts(delta_index_, callout_handle_2); EXPECT_EQ((112 + 122 + 132), resultCalloutInt(0)); EXPECT_EQ((212 + 222 + 232), resultCalloutInt(1)); @@ -340,7 +369,7 @@ TEST(HandlesTest, ContextAccessCheck) { EXPECT_EQ("312322332", resultCalloutString(2)); } -// Now repeat the test, but add a deletion callout to the list. The "two" +// Now repeat the test, but add a deletion callout to the list. The "beta" // hook of library 2 will have an additional callout to delete the "int" // element: the same hook for library 3 will delete both elements. In // addition, the names of context elements for the libraries at this point @@ -395,70 +424,55 @@ printContextNames3(CalloutHandle& handle) { // Perform the test including deletion of context items. -TEST(HandlesTest, ContextDeletionCheck) { - // Create the LibraryHandleCollection with a set of four callouts - // (the test does not use the context_create and context_destroy callouts.) - - boost::shared_ptr server_hooks(new ServerHooks()); - const int one_index = server_hooks->registerHook("one"); - const int two_index = server_hooks->registerHook("two"); - const int three_index = server_hooks->registerHook("three"); - const int four_index = server_hooks->registerHook("four"); - - // Create the library handle collection and the library handles. - boost::shared_ptr - collection(new LibraryHandleCollection()); - - boost::shared_ptr handle(new LibraryHandle(server_hooks)); - handle->registerCallout("one", callout11); - handle->registerCallout("two", callout12); - handle->registerCallout("two", printContextNames1); - handle->registerCallout("three", callout13); - handle->registerCallout("four", print1); - collection->addLibraryHandle(handle); - - handle.reset(new LibraryHandle(server_hooks)); - handle->registerCallout("one", callout21); - handle->registerCallout("two", callout22); - handle->registerCallout("two", deleteIntContextItem); - handle->registerCallout("two", printContextNames2); - handle->registerCallout("three", callout23); - handle->registerCallout("four", print2); - collection->addLibraryHandle(handle); - - handle.reset(new LibraryHandle(server_hooks)); - handle->registerCallout("one", callout31); - handle->registerCallout("two", callout32); - handle->registerCallout("two", deleteAllContextItems); - handle->registerCallout("two", printContextNames3); - handle->registerCallout("three", callout33); - handle->registerCallout("four", print3); - collection->addLibraryHandle(handle); +TEST_F(HandlesTest, ContextDeletionCheck) { + + getCalloutManager()->setLibraryIndex(0); + getCalloutManager()->registerCallout("alpha", callout11); + getCalloutManager()->registerCallout("beta", callout12); + getCalloutManager()->registerCallout("beta", printContextNames1); + getCalloutManager()->registerCallout("gamma", callout13); + getCalloutManager()->registerCallout("delta", print1); + + getCalloutManager()->setLibraryIndex(1); + getCalloutManager()->registerCallout("alpha", callout21); + getCalloutManager()->registerCallout("beta", callout22); + getCalloutManager()->registerCallout("beta", deleteIntContextItem); + getCalloutManager()->registerCallout("beta", printContextNames2); + getCalloutManager()->registerCallout("gamma", callout23); + getCalloutManager()->registerCallout("delta", print2); + + getCalloutManager()->setLibraryIndex(2); + getCalloutManager()->registerCallout("alpha", callout31); + getCalloutManager()->registerCallout("beta", callout32); + getCalloutManager()->registerCallout("beta", deleteAllContextItems); + getCalloutManager()->registerCallout("beta", printContextNames3); + getCalloutManager()->registerCallout("gamma", callout33); + getCalloutManager()->registerCallout("delta", print3); // Create the callout handles and distinguish them by setting the "long" // argument. - CalloutHandle callout_handle_1(collection); + CalloutHandle callout_handle_1(getCalloutManager()); callout_handle_1.setArgument("handle_num", static_cast(1)); - CalloutHandle callout_handle_2(collection); + CalloutHandle callout_handle_2(getCalloutManager()); callout_handle_2.setArgument("handle_num", static_cast(2)); // Now call the callouts attached to the first three hooks. Each hook is // called twice (once for each callout handle) before the next hook is // called. - collection->callCallouts(one_index, callout_handle_1); - collection->callCallouts(one_index, callout_handle_2); - collection->callCallouts(two_index, callout_handle_1); - collection->callCallouts(two_index, callout_handle_2); - collection->callCallouts(three_index, callout_handle_1); - collection->callCallouts(three_index, callout_handle_2); + getCalloutManager()->callCallouts(alpha_index_, callout_handle_1); + getCalloutManager()->callCallouts(alpha_index_, callout_handle_2); + getCalloutManager()->callCallouts(beta_index_, callout_handle_1); + getCalloutManager()->callCallouts(beta_index_, callout_handle_2); + getCalloutManager()->callCallouts(gamma_index_, callout_handle_1); + getCalloutManager()->callCallouts(gamma_index_, callout_handle_2); // Get the results for each callout. Explicitly zero the variables before // getting the results so we are certain that the values are the results // of the callouts. zero_results(); - collection->callCallouts(four_index, callout_handle_1); + getCalloutManager()->callCallouts(delta_index_, callout_handle_1); // The logic by which the expected results are arrived at is described // in the ContextAccessCheck test. The results here are different @@ -475,7 +489,7 @@ TEST(HandlesTest, ContextDeletionCheck) { // Repeat the checks for callout handle 2. zero_results(); - collection->callCallouts(four_index, callout_handle_2); + getCalloutManager()->callCallouts(delta_index_, callout_handle_2); EXPECT_EQ((112 + 122 + 132), resultCalloutInt(0)); EXPECT_EQ(( 232), resultCalloutInt(1)); @@ -486,7 +500,7 @@ TEST(HandlesTest, ContextDeletionCheck) { EXPECT_EQ( "332", resultCalloutString(2)); // ... and check what the names of the context items are after the callouts - // for hook "two". We know they are in sorted order. + // for hook "beta". We know they are in sorted order. EXPECT_EQ(2, getItemNames(0).size()); EXPECT_EQ(string("int"), getItemNames(0)[0]); @@ -507,29 +521,20 @@ int returnError(CalloutHandle&) { return (1); } -TEST(HandlesTest, ConstructionDestructionCallouts) { - // Create the LibraryHandleCollection comprising two LibraryHandles. - // Register callouts for the context_create and context_destroy hooks. - - boost::shared_ptr server_hooks(new ServerHooks()); +TEST_F(HandlesTest, ConstructionDestructionCallouts) { - // Create the library handle collection and the library handles. - boost::shared_ptr - collection(new LibraryHandleCollection()); - - boost::shared_ptr handle(new LibraryHandle(server_hooks)); - handle->registerCallout("context_create", callout11); - handle->registerCallout("context_create", print1); - handle->registerCallout("context_destroy", callout12); - handle->registerCallout("context_destroy", print1); - collection->addLibraryHandle(handle); + // Register context callouts. + getCalloutManager()->setLibraryIndex(0); + getCalloutManager()->registerCallout("context_create", callout11); + getCalloutManager()->registerCallout("context_create", print1); + getCalloutManager()->registerCallout("context_destroy", callout12); + getCalloutManager()->registerCallout("context_destroy", print1); // Create the CalloutHandle and check that the constructor callout // has run. zero_results(); - boost::shared_ptr - callout_handle(new CalloutHandle(collection)); - + boost::scoped_ptr + callout_handle(new CalloutHandle(getCalloutManager())); EXPECT_EQ("110", resultCalloutString(0)); EXPECT_EQ(110, resultCalloutInt(0)); @@ -544,19 +549,220 @@ TEST(HandlesTest, ConstructionDestructionCallouts) { EXPECT_EQ((110 + 120), resultCalloutInt(0)); // Test that the destructor throws an error if the context_destroy - // callout returns an error. - handle->registerCallout("context_destroy", returnError); - callout_handle.reset(new CalloutHandle(collection)); + // callout returns an error. (As the constructor and destructor will + // have implicitly run the CalloutManager's callCallouts method, we need + // to set the library index again.) + getCalloutManager()->setLibraryIndex(0); + getCalloutManager()->registerCallout("context_destroy", returnError); + callout_handle.reset(new CalloutHandle(getCalloutManager())); EXPECT_THROW(callout_handle.reset(), ContextDestroyFail); // We don't know what callout_handle is pointing to - it could be to a // half-destroyed object - so use a new CalloutHandle to test construction // failure. - handle->registerCallout("context_create", returnError); - boost::shared_ptr callout_handle2; - EXPECT_THROW(callout_handle2.reset(new CalloutHandle(collection)), + getCalloutManager()->setLibraryIndex(0); + getCalloutManager()->registerCallout("context_create", returnError); + boost::scoped_ptr callout_handle2; + EXPECT_THROW(callout_handle2.reset(new CalloutHandle(getCalloutManager())), ContextCreateFail); +} + +// Dynamic callout registration and deregistration. +// The following are the dynamic registration/deregistration callouts. + + +// Add callout_78_alpha - adds a callout to hook alpha that appends "78x" +// (where "x" is the callout handle) to the current output. +int +callout78(CalloutHandle& callout_handle) { + return (execute(callout_handle, 7, 8)); +} + +int +add_callout78_alpha(CalloutHandle& callout_handle) { + callout_handle.getLibraryHandle().registerCallout("alpha", callout78); + return (0); +} + +int +delete_callout78_alpha(CalloutHandle& callout_handle) { + static_cast( + callout_handle.getLibraryHandle().deregisterCallout("alpha", + callout78)); + return (0); +} + +// Check that a callout can register another callout on a different hook. + +TEST_F(HandlesTest, DynamicRegistrationAnotherHook) { + // Register callouts for the different libraries. + CalloutHandle handle(getCalloutManager()); + + // Set up callouts on "alpha". + getCalloutManager()->setLibraryIndex(0); + getCalloutManager()->registerCallout("alpha", callout11); + getCalloutManager()->registerCallout("delta", print1); + getCalloutManager()->setLibraryIndex(1); + getCalloutManager()->registerCallout("alpha", callout21); + getCalloutManager()->registerCallout("delta", print2); + getCalloutManager()->setLibraryIndex(2); + getCalloutManager()->registerCallout("alpha", callout31); + getCalloutManager()->registerCallout("delta", print3); + + // ... and on "beta", set up the function to add a hook to alpha (but only + // for library 1). + getCalloutManager()->setLibraryIndex(1); + getCalloutManager()->registerCallout("beta", add_callout78_alpha); + + // See what we get for calling the callouts on alpha first. + CalloutHandle callout_handle_1(getCalloutManager()); + callout_handle_1.setArgument("handle_num", static_cast(1)); + getCalloutManager()->callCallouts(alpha_index_, callout_handle_1); + + zero_results(); + getCalloutManager()->callCallouts(delta_index_, callout_handle_1); + EXPECT_EQ("111", resultCalloutString(0)); + EXPECT_EQ("211", resultCalloutString(1)); + EXPECT_EQ("311", resultCalloutString(2)); + + // All as expected, now call the callouts on beta. This should add a + // callout to the list of callouts for alpha, which we should see when + // we run the test again. + getCalloutManager()->callCallouts(beta_index_, callout_handle_1); + + // Use a new callout handle so as to get fresh callout context. + CalloutHandle callout_handle_2(getCalloutManager()); + callout_handle_2.setArgument("handle_num", static_cast(2)); + getCalloutManager()->callCallouts(alpha_index_, callout_handle_2); + + zero_results(); + getCalloutManager()->callCallouts(delta_index_, callout_handle_2); + EXPECT_EQ("112", resultCalloutString(0)); + EXPECT_EQ("212782", resultCalloutString(1)); + EXPECT_EQ("312", resultCalloutString(2)); +} + +// Check that a callout can register another callout on the same hook. +// Note that the registration only applies to a subsequent invocation of +// callCallouts, not to the current one. In other words, if +// +// * the callout list for a library is "A then B then C" +// * when callCallouts is executed "B" adds "D" to that list, +// +// ... the current execution of callCallouts only executes A, B and C. A +// subsequent invocation will execute A, B, C then D. + +TEST_F(HandlesTest, DynamicRegistrationSameHook) { + // Register callouts for the different libraries. + CalloutHandle handle(getCalloutManager()); + + // Set up callouts on "alpha". + getCalloutManager()->setLibraryIndex(0); + getCalloutManager()->registerCallout("alpha", callout11); + getCalloutManager()->registerCallout("alpha", add_callout78_alpha); + getCalloutManager()->registerCallout("delta", print1); + + // See what we get for calling the callouts on alpha first. + CalloutHandle callout_handle_1(getCalloutManager()); + callout_handle_1.setArgument("handle_num", static_cast(1)); + getCalloutManager()->callCallouts(alpha_index_, callout_handle_1); + zero_results(); + getCalloutManager()->callCallouts(delta_index_, callout_handle_1); + EXPECT_EQ("111", resultCalloutString(0)); + + // Run it again - we should have added something to this hook. + CalloutHandle callout_handle_2(getCalloutManager()); + callout_handle_2.setArgument("handle_num", static_cast(2)); + getCalloutManager()->callCallouts(alpha_index_, callout_handle_2); + zero_results(); + getCalloutManager()->callCallouts(delta_index_, callout_handle_2); + EXPECT_EQ("112782", resultCalloutString(0)); + + // And a third time... + CalloutHandle callout_handle_3(getCalloutManager()); + callout_handle_3.setArgument("handle_num", static_cast(3)); + getCalloutManager()->callCallouts(alpha_index_, callout_handle_3); + zero_results(); + getCalloutManager()->callCallouts(delta_index_, callout_handle_3); + EXPECT_EQ("113783783", resultCalloutString(0)); +} + +// Deregistration of a callout from a different hook + +TEST_F(HandlesTest, DynamicDeregistrationDifferentHook) { + // Register callouts for the different libraries. + CalloutHandle handle(getCalloutManager()); + + // Set up callouts on "alpha". + getCalloutManager()->setLibraryIndex(0); + getCalloutManager()->registerCallout("alpha", callout11); + getCalloutManager()->registerCallout("alpha", callout78); + getCalloutManager()->registerCallout("alpha", callout11); + getCalloutManager()->registerCallout("delta", print1); + + getCalloutManager()->registerCallout("beta", delete_callout78_alpha); + + // Call the callouts on alpha + CalloutHandle callout_handle_1(getCalloutManager()); + callout_handle_1.setArgument("handle_num", static_cast(1)); + getCalloutManager()->callCallouts(alpha_index_, callout_handle_1); + + zero_results(); + getCalloutManager()->callCallouts(delta_index_, callout_handle_1); + EXPECT_EQ("111781111", resultCalloutString(0)); + + // Run the callouts on hook beta to remove the callout on alpha. + getCalloutManager()->callCallouts(beta_index_, callout_handle_1); + + // The run of the callouts should have altered the callout list on the + // first library for hook alpha, so call again to make sure. + CalloutHandle callout_handle_2(getCalloutManager()); + callout_handle_2.setArgument("handle_num", static_cast(2)); + getCalloutManager()->callCallouts(alpha_index_, callout_handle_2); + + zero_results(); + getCalloutManager()->callCallouts(delta_index_, callout_handle_2); + EXPECT_EQ("112112", resultCalloutString(0)); +} + +// Deregistration of a callout from the same hook + +TEST_F(HandlesTest, DynamicDeregistrationSameHook) { + // Register callouts for the different libraries. + CalloutHandle handle(getCalloutManager()); + + // Set up callouts on "alpha". + getCalloutManager()->setLibraryIndex(0); + getCalloutManager()->registerCallout("alpha", callout11); + getCalloutManager()->registerCallout("alpha", delete_callout78_alpha); + getCalloutManager()->registerCallout("alpha", callout78); + getCalloutManager()->registerCallout("delta", print1); + getCalloutManager()->setLibraryIndex(1); + getCalloutManager()->registerCallout("alpha", callout21); + getCalloutManager()->registerCallout("alpha", callout78); + getCalloutManager()->registerCallout("delta", print2); + + // Call the callouts on alpha + CalloutHandle callout_handle_1(getCalloutManager()); + callout_handle_1.setArgument("handle_num", static_cast(1)); + getCalloutManager()->callCallouts(alpha_index_, callout_handle_1); + + zero_results(); + getCalloutManager()->callCallouts(delta_index_, callout_handle_1); + EXPECT_EQ("111781", resultCalloutString(0)); + EXPECT_EQ("211781", resultCalloutString(1)); + + // The run of the callouts should have altered the callout list on the + // first library for hook alpha, so call again to make sure. + CalloutHandle callout_handle_2(getCalloutManager()); + callout_handle_2.setArgument("handle_num", static_cast(2)); + getCalloutManager()->callCallouts(alpha_index_, callout_handle_2); + + zero_results(); + getCalloutManager()->callCallouts(delta_index_, callout_handle_2); + EXPECT_EQ("112", resultCalloutString(0)); + EXPECT_EQ("212782", resultCalloutString(1)); }