// Copyright (C) 2013-2021 Internet Systems Consortium, Inc. ("ISC") // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef COMMON_HOOKS_TEST_CLASS_H #define COMMON_HOOKS_TEST_CLASS_H #include #include #include #include #include #include /// @brief Common hooks test class /// /// This class is a shared parent of the test fixture class in the tests of the /// higher-level hooks classes (LibraryManager, LibraryManagerCollection and /// HooksManager). It /// /// - sets the ServerHooks object with three hooks and stores their /// indexes. /// - executes the callouts (which are assumed to perform a calculation) /// and checks the results. class HooksCommonTestClass { public: /// @brief Constructor HooksCommonTestClass() { // Set up the server hooks. ServerHooks is a singleton, so we reset it // between each test. isc::hooks::ServerHooks& hooks = isc::hooks::ServerHooks::getServerHooks(); hooks.reset(); hookpt_one_index_ = hooks.registerHook("hookpt_one"); hookpt_two_index_ = hooks.registerHook("hookpt_two"); hookpt_three_index_ = hooks.registerHook("hookpt_three"); } /// @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 hookpt_one, hookpt_two and hookpt_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 hookpt_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 = hookpt_one(r0, d1) @f] /// /// Callout hookpt_two is passed a value d2 and performs another simple /// arithmetic operation on it and d2, yielding r2, i.e. /// @f[ r2 = hookpt_two(d1, d2) @f] /// /// hookpt_three does a similar operation giving /// @f[ r3 = hookpt_three(r2, d3) @f]. /// /// The details of the operations hookpt_one, hookpt_two and hookpt_three /// depend on the library, so the results obtained not only depend on /// the data, but also on the library loaded. This method is passed both /// data and expected results. It executes the three callouts in sequence, /// checking the intermediate and final results. Only if the expected /// library has been loaded correctly and the callouts in it registered /// correctly will be the results be as expected. /// /// 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 manager CalloutManager to use for the test /// @param r0...r3, d1..d3 Data (dN) and expected results (rN) - both /// intermediate and final. The arguments are ordered so that they /// appear in the argument list in the order they are used. void executeCallCallouts( const boost::shared_ptr& manager, int r0, int d1, int r1, int d2, int r2, int d3, int r3) { static const char* COMMON_TEXT = " callout returned the wrong value"; static const char* RESULT = "result"; int result; // Set up a callout handle for the calls. isc::hooks::CalloutHandle handle(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. handle.setArgument(RESULT, -1); // Seed the calculation. manager->callCallouts(isc::hooks::ServerHooks::CONTEXT_CREATE, handle); handle.getArgument(RESULT, result); EXPECT_EQ(r0, result) << "context_create" << COMMON_TEXT; // Perform the first calculation. handle.setArgument("data_1", d1); manager->callCallouts(hookpt_one_index_, handle); handle.getArgument(RESULT, result); EXPECT_EQ(r1, result) << "hookpt_one" << COMMON_TEXT; // ... the second ... handle.setArgument("data_2", d2); manager->callCallouts(hookpt_two_index_, handle); handle.getArgument(RESULT, result); EXPECT_EQ(r2, result) << "hookpt_two" << COMMON_TEXT; // ... and the third. handle.setArgument("data_3", d3); manager->callCallouts(hookpt_three_index_, handle); handle.getArgument(RESULT, result); EXPECT_EQ(r3, result) << "hookpt_three" << COMMON_TEXT; } /// @brief Call command handlers test. /// /// This test is similar to @c executeCallCallouts but it uses /// @ref CalloutManager::callCommandHandlers to execute the command /// handlers for the following commands: 'command-one' and 'command-two'. /// /// @param manager CalloutManager to use for the test /// @param r1..r2, d1..d2 Data (dN) and expected results (rN). void executeCallCommandHandlers( const boost::shared_ptr& manager, int d1, int r1, int d2, int r2) { static const char* COMMON_TEXT = " command handler returned the wrong value"; static const char* RESULT = "result"; int result; // Set up a callout handle for the calls. isc::hooks::CalloutHandle handle(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. handle.setArgument(RESULT, -1); // Perform the first calculation: it should assign the data to the // result. handle.setArgument("data_1", d1); manager->callCommandHandlers("command-one", handle); handle.getArgument(RESULT, result); EXPECT_EQ(r1, result) << "command-one" << COMMON_TEXT; // Perform the second calculation: it should multiply the data by 10 // and return in the result. handle.setArgument("data_2", d2); manager->callCommandHandlers("command-two", handle); handle.getArgument(RESULT, result); EXPECT_EQ(r2, result) << "command-two" << COMMON_TEXT; } /// Hook indexes. These are are made public for ease of reference. int hookpt_one_index_; int hookpt_two_index_; int hookpt_three_index_; }; #endif // COMMON_HOOKS_TEST_CLASS_H