123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448 |
- // 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/library_handle.h>
- #include <util/hooks/server_hooks.h>
- #include <gtest/gtest.h>
- using namespace isc::util;
- using namespace std;
- // Dummy class for testing
- namespace isc {
- namespace util {
- class CalloutHandle {};
- }
- }
- namespace {
- class LibraryHandleTest : public ::testing::Test {
- public:
- /// @brief Constructor
- ///
- /// Sets up an appropriate number of server hooks to pass to the
- /// constructed callout handle objects.
- LibraryHandleTest() : hooks_(new ServerHooks()) {
- hooks_->registerHook("alpha");
- hooks_->registerHook("beta");
- hooks_->registerHook("gamma");
- // Also initialize the callout variables.
- one_count = 0;
- two_count = 0;
- callout_value = 0;
- }
- /// Obtain constructed server hooks
- boost::shared_ptr<ServerHooks> getServerHooks() {
- return (hooks_);
- }
- /// 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.
- static int one_count;
- static int two_count;
- static int callout_value;
- private:
- boost::shared_ptr<ServerHooks> hooks_;
- };
- // Definition of the static variables.
- int LibraryHandleTest::one_count = 0;
- int LibraryHandleTest::two_count = 0;
- int LibraryHandleTest::callout_value = 0;
- // *** Context Tests ***
- //
- // The first set of tests check that the LibraryHandle can store and retrieve
- // context.
- // Test that we can store multiple values of the same type and that they
- // are distinct.
- TEST_F(LibraryHandleTest, ContextDistinctSimpleType) {
- LibraryHandle handle(getServerHooks(), 1);
- // Store and retrieve an int (random value).
- int a = 42;
- handle.setContext("integer1", a);
- EXPECT_EQ(42, a);
- int b = 0;
- handle.getContext("integer1", b);
- EXPECT_EQ(42, b);
- // Add another integer (another random value).
- int c = 142;
- handle.setContext("integer2", c);
- EXPECT_EQ(142, c);
- int d = -1;
- handle.getContext("integer2", d);
- EXPECT_EQ(142, d);
- // Add a short (random value).
- short e = 81;
- handle.setContext("short", e);
- EXPECT_EQ(81, e);
- short f = -1;
- handle.getContext("short", f);
- EXPECT_EQ(81, f);
- }
- // Test that trying to get something with an incorrect name throws an
- // exception.
- TEST_F(LibraryHandleTest, ContextUnknownName) {
- LibraryHandle handle(getServerHooks(), 1);
- // Set an integer
- int a = 42;
- handle.setContext("integer1", a);
- EXPECT_EQ(42, a);
- // Check we can retrieve it
- int b = 0;
- handle.getContext("integer1", b);
- EXPECT_EQ(42, b);
- // Check that getting an unknown name throws an exception.
- int c = -1;
- EXPECT_THROW(handle.getContext("unknown", c), NoSuchContext);
- }
- // Test that trying to get something with an incorrect type throws an exception.
- TEST_F(LibraryHandleTest, ContextIncorrectType) {
- LibraryHandle handle(getServerHooks(), 1);
- // Set an integer
- int a = 42;
- handle.setContext("integer1", a);
- EXPECT_EQ(42, a);
- // Check we can retrieve it
- long b = 0;
- EXPECT_THROW(handle.getContext("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(LibraryHandleTest, ComplexTypes) {
- LibraryHandle handle(getServerHooks(), 1);
- // 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.setContext("aleph", aleph);
- Beta beth(11, 22);
- EXPECT_EQ(11, beth.c);
- EXPECT_EQ(22, beth.d);
- handle.setContext("beth", beth);
- // Ensure we can extract the data correctly
- Alpha aleph2;
- EXPECT_EQ(0, aleph2.a);
- EXPECT_EQ(0, aleph2.b);
- handle.getContext("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.getContext("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.getContext("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(LibraryHandleTest, PointerTypes) {
- LibraryHandle handle(getServerHooks(), 1);
- // Declare a couple of variables, const and non-const.
- Alpha aleph(5, 10);
- const Beta beth(15, 20);
- Alpha* pa = ℵ
- const Beta* pcb = ℶ
- // Check pointers can be set and retrieved OK
- handle.setContext("non_const_pointer", pa);
- handle.setContext("const_pointer", pcb);
- Alpha* pa2 = 0;
- handle.getContext("non_const_pointer", pa2);
- EXPECT_TRUE(pa == pa2);
- const Beta* pcb2 = 0;
- handle.getContext("const_pointer", pcb2);
- EXPECT_TRUE(pcb == pcb2);
- // Check that the "const" is protected in the context.
- const Alpha* pca3;
- EXPECT_THROW(handle.getContext("non_const_pointer", pca3),
- boost::bad_any_cast);
- Beta* pb3;
- EXPECT_THROW(handle.getContext("const_pointer", pb3),
- boost::bad_any_cast);
- }
- // *** Callout Tests ***
- //
- // The next set of tests check that callouts can be registered.
- // Supply callouts structured in such a way that we can determine the order
- // that they are called and whether they are called at all. In particular
- // if the callout order is:
- //
- // * one followed by two, the resulting value is 20
- // * two followed by one, the resuling value is -10
- // * one and two is not called, the resulting value is 10
- // * two and one is not called, the resulting value is -20
- // * neither called, the resulting value is 0
- //
- // The variable xxx_count is the number of times the function has been called
- // in the current test.
- extern "C" {
- int one(CalloutHandle&) {
- ++LibraryHandleTest::one_count;
- if (LibraryHandleTest::callout_value == 0) {
- LibraryHandleTest::callout_value = 10;
- } else {
- LibraryHandleTest::callout_value = -10;
- }
- return (0);
- }
- int two(CalloutHandle&) {
- ++LibraryHandleTest::two_count;
- if (LibraryHandleTest::callout_value == 10) {
- LibraryHandleTest::callout_value = 20;
- } else {
- LibraryHandleTest::callout_value = -20;
- }
- return (0);
- }
- // The next function is a duplicate of "one", but returns an error status.
- int one_error(CalloutHandle& handle) {
- (void) one(handle);
- return (1);
- }
- }; // extern "C"
- // Check that we can register callouts on a particular hook.
- TEST_F(LibraryHandleTest, RegisterSingleCallout) {
- LibraryHandle handle(getServerHooks(), 1);
- // Register callouts for hooks alpha and see that it is registered.
- EXPECT_FALSE(handle.calloutsPresent(getServerHooks()->getIndex("alpha")));
- handle.registerCallout("alpha", one);
- EXPECT_TRUE(handle.calloutsPresent(getServerHooks()->getIndex("alpha")));
- // Do the same for beta (which checks that the hooks are independent).
- EXPECT_FALSE(handle.calloutsPresent(getServerHooks()->getIndex("beta")));
- handle.registerCallout("beta", one);
- EXPECT_TRUE(handle.calloutsPresent(getServerHooks()->getIndex("beta")));
- }
- // Check that we can call a single callout on a particular hook. Refer
- // to the above definition of the callouts "one" and "two" to understand
- // the expected return values.
- TEST_F(LibraryHandleTest, CallSingleCallout) {
- LibraryHandle handle(getServerHooks(), 1);
- // Register callout for hook alpha...
- EXPECT_FALSE(handle.calloutsPresent(getServerHooks()->getIndex("alpha")));
- handle.registerCallout("alpha", one);
- EXPECT_TRUE(handle.calloutsPresent(getServerHooks()->getIndex("alpha")));
- // Call it.
- EXPECT_EQ(0, LibraryHandleTest::one_count);
- EXPECT_EQ(0, LibraryHandleTest::two_count);
- EXPECT_EQ(0, LibraryHandleTest::callout_value);
- int index = getServerHooks()->getIndex("alpha");
- CalloutHandle dummy;
- int status = handle.callCallouts(index, dummy);
- EXPECT_EQ(0, status);
- EXPECT_EQ(1, LibraryHandleTest::one_count);
- EXPECT_EQ(0, LibraryHandleTest::two_count);
- EXPECT_EQ(10, LibraryHandleTest::callout_value);
- }
- // Check that we can register two callouts for a hook and that they are called
- // in order.
- TEST_F(LibraryHandleTest, TwoCallouts) {
- LibraryHandle handle(getServerHooks(), 1);
- // Register two callouts for hook alpha...
- handle.registerCallout("alpha", one);
- handle.registerCallout("alpha", two);
- // ... and 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 dummy;
- int status = handle.callCallouts(index, dummy);
- EXPECT_EQ(0, status);
- EXPECT_EQ(1, LibraryHandleTest::one_count);
- EXPECT_EQ(1, LibraryHandleTest::two_count);
- EXPECT_EQ(20, 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, TwoCalloutsWithError) {
- LibraryHandle handle(getServerHooks(), 1);
- // Register callout for hook alpha...
- handle.registerCallout("alpha", one_error);
- 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 dummy;
- int status = handle.callCallouts(index, dummy);
- EXPECT_EQ(1, 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) {
- LibraryHandle handle(getServerHooks(), 1);
- // Register callouts for hook alpha...
- handle.registerCallout("alpha", one);
- handle.registerCallout("alpha", two);
- handle.registerCallout("alpha", one);
- // 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 dummy;
- int status = handle.callCallouts(index, dummy);
- EXPECT_EQ(0, status);
- EXPECT_EQ(2, LibraryHandleTest::one_count);
- EXPECT_EQ(1, LibraryHandleTest::two_count);
- EXPECT_EQ(-10, LibraryHandleTest::callout_value);
- }
- // Check that a callout can be deregistered.
- TEST_F(LibraryHandleTest, Degreister) {
- LibraryHandle handle(getServerHooks(), 1);
- // Register callouts for hook alpha...
- handle.registerCallout("alpha", one);
- handle.registerCallout("alpha", two);
- handle.registerCallout("alpha", one);
- // Get rid of all the "one" callbacks.
- handle.deregisterCallout("alpha", one);
- // Call it.
- EXPECT_EQ(0, LibraryHandleTest::one_count);
- EXPECT_EQ(0, LibraryHandleTest::two_count);
- EXPECT_EQ(0, LibraryHandleTest::callout_value);
- int index = getServerHooks()->getIndex("alpha");
- CalloutHandle dummy;
- int status = handle.callCallouts(index, dummy);
- EXPECT_EQ(0, status);
- EXPECT_EQ(0, LibraryHandleTest::one_count);
- EXPECT_EQ(1, LibraryHandleTest::two_count);
- EXPECT_EQ(-20, LibraryHandleTest::callout_value);
- }
- // Check that all callouts can be deregistered.
- TEST_F(LibraryHandleTest, DeregisterAll) {
- LibraryHandle handle(getServerHooks(), 1);
- // Register callouts for hook alpha...
- EXPECT_FALSE(handle.calloutsPresent(getServerHooks()->getIndex("alpha")));
- handle.registerCallout("alpha", one);
- handle.registerCallout("alpha", two);
- EXPECT_TRUE(handle.calloutsPresent(getServerHooks()->getIndex("alpha")));
- // ... and remove them.
- handle.deregisterAll("alpha");
- EXPECT_FALSE(handle.calloutsPresent(getServerHooks()->getIndex("alpha")));
- }
- } // Anonymous namespace
|