LCOV - code coverage report
Current view: top level - testutils - socket_request.h (source / functions) Hit Total Coverage
Test: report.info Lines: 35 37 94.6 %
Date: 2012-05-15 Functions: 4 5 80.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 42 126 33.3 %

           Branch data     Line data    Source code
       1                 :            : // Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
       2                 :            : //
       3                 :            : // Permission to use, copy, modify, and/or distribute this software for any
       4                 :            : // purpose with or without fee is hereby granted, provided that the above
       5                 :            : // copyright notice and this permission notice appear in all copies.
       6                 :            : //
       7                 :            : // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
       8                 :            : // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
       9                 :            : // AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
      10                 :            : // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
      11                 :            : // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
      12                 :            : // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
      13                 :            : // PERFORMANCE OF THIS SOFTWARE.
      14                 :            : 
      15                 :            : #ifndef __ISC_TESTUTILS_SOCKETREQUEST_H
      16                 :            : #define __ISC_TESTUTILS_SOCKETREQUEST_H 1
      17                 :            : 
      18                 :            : #include <server_common/socket_request.h>
      19                 :            : #include <server_common/portconfig.h>
      20                 :            : 
      21                 :            : #include <asiodns/asiodns.h>
      22                 :            : 
      23                 :            : #include <gtest/gtest.h>
      24                 :            : #include <boost/lexical_cast.hpp>
      25                 :            : 
      26                 :            : #include <vector>
      27                 :            : #include <string>
      28                 :            : 
      29                 :            : namespace isc {
      30                 :            : namespace testutils {
      31                 :            : 
      32                 :            : /// \brief A testcase part for faking the SocketRequestor in tests
      33                 :            : ///
      34                 :            : /// It's awkward to request real sockets from the real socket creator
      35                 :            : /// during tests (for one, because it would have to be running, for
      36                 :            : /// another, we need to block real ports).  If you instantiate this class in
      37                 :            : /// a test case, the socket requestor will be initialized to a test one which
      38                 :            : /// handles fake socket FDs and stores what was requested, etc.
      39                 :            : ///
      40                 :            : /// Furthermore, you can check if the code requested or released the correct
      41                 :            : /// list of sockets using the checkTokens() method.
      42                 :            : ///
      43                 :            : /// Some member variables are intentionally made public so that test cases
      44                 :            : /// can easily check the value of them.  We prefer convenience for tests over
      45                 :            : /// class integrity here.
      46                 :            : class TestSocketRequestor : public isc::server_common::SocketRequestor {
      47                 :            : public:
      48                 :            :     /// \brief Constructor
      49                 :            :     ///
      50                 :            :     /// \param dnss The DNS service. It is expected this gets initialized
      51                 :            :     ///     after the TestSocketRequestor constructor is called, as the
      52                 :            :     ///     TestSocketRequestor should be a base class and the service only
      53                 :            :     ///     a member.
      54                 :            :     /// \param store Address store used when cleaning up.
      55                 :            :     /// \param expect_port The port which is expected to be requested. If
      56                 :            :     ///     the application requests a different port, it is considered
      57                 :            :     ///     a failure.
      58                 :            :     /// \param expeted_app The share name for which all the requests should
      59                 :            :     ///     be made. This is not the usual app_name - the requestSocket does
      60                 :            :     ///     not fall back to this value if its share_name is left empty, if
      61                 :            :     ///     you want to check the code relies on the requestor to use the
      62                 :            :     ///     app name, you set this to empty string.
      63                 :            :     TestSocketRequestor(asiodns::DNSServiceBase& dnss,
      64                 :            :                         server_common::portconfig::AddressList& store,
      65                 :            :                         uint16_t expect_port,
      66                 :            :                         const std::string& expected_app) :
      67                 :            :         last_token_(0), break_rollback_(false), break_release_(false),
      68                 :            :         dnss_(dnss), store_(store), expect_port_(expect_port),
      69         [ +  - ]:        106 :         expected_app_(expected_app)
      70                 :            :     {
      71                 :            :         // Prepare the requestor (us) for the test
      72         [ -  + ]:        106 :         server_common::initTestSocketRequestor(this);
      73                 :            :     }
      74                 :            : 
      75                 :            :     /// \brief Destructor
      76                 :            :     ///
      77                 :            :     /// Removes the addresses (if any) installed by installListenAddresses,
      78                 :            :     /// resets the socket requestor to uninitialized state and turns off
      79                 :            :     /// the portconfig test mode.
      80                 :        106 :     virtual ~TestSocketRequestor() {
      81                 :            :         // Make sure no sockets are left inside (if installListenAddresses
      82                 :            :         // wasn't used, this is NOP, so it won't hurt).
      83                 :        106 :         server_common::portconfig::AddressList list;
      84         [ +  - ]:        106 :         server_common::portconfig::installListenAddresses(list, store_, dnss_);
      85                 :            :         // Don't leave invalid pointers here
      86         [ +  - ]:        106 :         server_common::initTestSocketRequestor(NULL);
      87                 :        106 :     }
      88                 :            : 
      89                 :            :     /// \brief Tokens released by releaseSocket
      90                 :            :     ///
      91                 :            :     /// They are stored here by this class and you can examine them.
      92                 :            :     std::vector<std::string> released_tokens_;
      93                 :            : 
      94                 :            :     /// \brief Tokens returned from requestSocket
      95                 :            :     ///
      96                 :            :     /// They are stored here by this class and you can examine them.
      97                 :            :     std::vector<std::string> given_tokens_;
      98                 :            : private:
      99                 :            :     // Last token number and fd given out
     100                 :            :     size_t last_token_;
     101                 :            : public:
     102                 :            :     /// \brief Support a broken rollback case
     103                 :            :     ///
     104                 :            :     /// If this is set to true, the requestSocket will throw when the
     105                 :            :     /// ::1 address is requested.
     106                 :            :     bool break_rollback_;
     107                 :            : 
     108                 :            :     /// \brief Throw on releaseSocket
     109                 :            :     ///
     110                 :            :     /// If this is set to true, the releaseSocket will throw SocketError.
     111                 :            :     /// Defaults to false.
     112                 :            :     bool break_release_;
     113                 :            : 
     114                 :            :     /// \brief Release a socket
     115                 :            :     ///
     116                 :            :     /// This only stores the token passed.
     117                 :            :     /// \param token The socket to release
     118                 :            :     ///
     119                 :            :     /// \throw SocketError in case the break_release_ is set to true. This is
     120                 :            :     ///     to test exception handling.
     121                 :         48 :     void releaseSocket(const std::string& token) {
     122         [ -  + ]:         48 :         if (break_release_) {
     123         [ #  # ]:          0 :             isc_throw(SocketError, "Fatal test socket error");
     124                 :            :         }
     125                 :         48 :         released_tokens_.push_back(token);
     126                 :         48 :     }
     127                 :            : 
     128                 :            :     /// \brief Request a socket
     129                 :            :     ///
     130                 :            :     /// This creates a new token and fakes a new socket and returns it.
     131                 :            :     /// The token is stored.
     132                 :            :     ///
     133                 :            :     /// In case the address is 192.0.2.2, it throws SocketAllocateError
     134                 :            :     /// or if the break_rollback_ is true and address is ::1, it throws
     135                 :            :     /// ShareError. If the address is 192.0.2.3, it throws SocketError.
     136                 :            :     ///
     137                 :            :     /// The tokens produced are in form of protocol:address:port:fd. The fds
     138                 :            :     /// start at 1 and increase by each successfull call.
     139                 :            :     ///
     140                 :            :     /// \param protocol The protocol to request
     141                 :            :     /// \param address to bind to
     142                 :            :     /// \param port to bind to
     143                 :            :     /// \param mode checked to be SHARE_SAME for now
     144                 :            :     /// \param name checked to be the same as expected_app parameter of the
     145                 :            :     ///      constructor. Note that this class does not provide the fallback
     146                 :            :     ///      to an app_name if this is empty string. To check the code relies
     147                 :            :     ///      on the fallback (wants to use the app_name instead of providing
     148                 :            :     ///      its own share name), you need to create this class with empty
     149                 :            :     ///      expected_app.
     150                 :            :     /// \return The token and FD
     151                 :            :     /// \throw SocketAllocateError as described above, to test error handling
     152                 :            :     /// \throw ShareError as described above, to test error handling
     153                 :            :     /// \throw SocketError as described above, to test error handling
     154                 :         56 :     SocketID requestSocket(Protocol protocol, const std::string& address,
     155                 :            :                            uint16_t port, ShareMode mode,
     156                 :            :                            const std::string& name)
     157                 :            :     {
     158         [ +  + ]:         56 :         if (address == "192.0.2.2") {
     159         [ +  - ]:         14 :             isc_throw(SocketAllocateError, "This address is not allowed");
     160                 :            :         }
     161         [ -  + ]:         49 :         if (address == "192.0.2.3") {
     162         [ #  # ]:          0 :             isc_throw(SocketError, "Fatal test error");
     163                 :            :         }
     164 [ +  + ][ +  + ]:         49 :         if (address == "::1" && break_rollback_) {
                 [ +  + ]
     165                 :            :             // This is valid address, but in case we need to break the
     166                 :            :             // rollback, it needs to be busy or whatever
     167                 :            :             //
     168                 :            :             // We break the second address to see the first one was
     169                 :            :             // allocated and then returned
     170         [ +  - ]:          2 :             isc_throw(ShareError,
     171                 :            :                       "This address is available, but not for you");
     172                 :            :         }
     173         [ +  + ]:         96 :         const std::string proto(protocol == TCP ? "TCP" : "UDP");
     174                 :         48 :         const size_t number = ++ last_token_;
     175 [ -  + ][ #  # ]:         48 :         EXPECT_EQ(expect_port_, port);
         [ #  # ][ #  # ]
         [ #  # ][ +  - ]
     176 [ -  + ][ #  # ]:         48 :         EXPECT_EQ(SHARE_SAME, mode);
         [ #  # ][ #  # ]
         [ #  # ][ +  - ]
     177 [ -  + ][ #  # ]:         48 :         EXPECT_EQ(expected_app_, name);
         [ #  # ][ #  # ]
         [ #  # ][ +  - ]
     178                 :         48 :         const std::string token(proto + ":" + address + ":" +
     179                 :         96 :                                 boost::lexical_cast<std::string>(port) + ":" +
     180 [ +  - ][ +  - ]:        144 :                                 boost::lexical_cast<std::string>(number));
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     181         [ +  - ]:         48 :         given_tokens_.push_back(token);
     182                 :         48 :         return (SocketID(number, token));
     183                 :            :     }
     184                 :            : 
     185                 :            :     /// \brief Check the list of tokens is as expected
     186                 :            :     ///
     187                 :            :     /// Compares the expected and real tokens.
     188                 :            :     ///
     189                 :            :     /// \param expected List of the expected tokens, as NULL-terminated array
     190                 :            :     ///     of C strings (it is more convenient to type as a constant than to
     191                 :            :     ///     manually push_back all the strings to a vector).
     192                 :            :     /// \param real The token list that was produced by this class (usually
     193                 :            :     ///     either given_tokens_ or released_tokens_).
     194                 :            :     /// \param scope Human readable identifier of which checkTokens call it is.
     195                 :            :     ///     It is printed as a part of failure message.
     196                 :         16 :     void checkTokens(const char** expected,
     197                 :            :                      const std::vector<std::string>& real,
     198                 :            :                      const char* scope) const
     199                 :            :     {
     200 [ +  - ][ +  - ]:         32 :         SCOPED_TRACE(scope);
     201                 :         16 :         size_t position(0);
     202         [ +  + ]:         76 :         while (expected[position] != NULL) {
     203 [ +  - ][ -  + ]:         76 :             ASSERT_LT(position, real.size());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ +  - ][ #  # ]
     204 [ -  + ][ #  # ]:         60 :             EXPECT_EQ(expected[position], real[position]) << position;
         [ #  # ][ #  # ]
         [ #  # ][ +  - ]
     205                 :         60 :             position ++;
     206                 :            :         }
     207 [ -  + ][ #  # ]:         16 :         EXPECT_EQ(position, real.size());
         [ #  # ][ #  # ]
         [ #  # ][ +  - ]
     208                 :            :     }
     209                 :            : 
     210                 :            : private:
     211                 :            :     asiodns::DNSServiceBase& dnss_;
     212                 :            :     server_common::portconfig::AddressList& store_;
     213                 :            :     const uint16_t expect_port_;
     214                 :            :     const std::string expected_app_;
     215                 :            : };
     216                 :            : 
     217                 :            : }
     218                 :            : }
     219                 :            : #endif  // __ISC_TESTUTILS_SOCKETREQUEST_H

Generated by: LCOV version 1.9