// Copyright (C) 2012-2015 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 UTIL_UNITTESTS_MOCKSOCKETSESSION_H #define UTIL_UNITTESTS_MOCKSOCKETSESSION_H 1 #include #include #include #include #include #include #include #include namespace isc { namespace util { namespace unittests { /// \brief Mock socket session forwarder. /// /// It emulates the behavior of SocketSessionForwarder without involving /// network communication, and allowing the tester to customize the behavior /// and to examine forwarded data afterwards. class MockSocketSessionForwarder : public isc::util::io::BaseSocketSessionForwarder { public: MockSocketSessionForwarder() : is_connected_(false), connect_ok_(true), push_ok_(true), close_ok_(true), // These are not used until set, but we set them anyway here, // partly to silence cppcheck, and partly to be cleaner. Put some // invalid values in. pushed_sock_(-1), pushed_family_(-1), pushed_type_(-1), pushed_protocol_(-1) {} virtual void connectToReceiver() { if (!connect_ok_) { isc_throw(isc::util::io::SocketSessionError, "socket session " "forwarding connection disabled for test"); } if (is_connected_) { isc_throw(isc::util::io::SocketSessionError, "duplicate connect"); } is_connected_ = true; } virtual void close() { if (!is_connected_) { isc_throw(isc::util::io::SocketSessionError, "duplicate close"); } is_connected_ = false; } // Pushing a socket session. It copies the given session data // so that the test code can check the values later via the getter // methods. Complete deep copy will be created, so the caller doesn't // have to keep the parameters valid after the call to this method. virtual void push(int sock, int family, int type, int protocol, const struct sockaddr& local_end, const struct sockaddr& remote_end, const void* data, size_t data_len) { if (!push_ok_) { isc_throw(isc::util::io::SocketSessionError, "socket session forwarding is disabled for test"); } if (!is_connected_) { isc_throw(isc::util::io::SocketSessionError, "socket session is being pushed before connected"); } // Copy parameters for later checks pushed_sock_ = sock; pushed_family_ = family; pushed_type_ = type; pushed_protocol_ = protocol; assert(io::internal::getSALength(local_end) <= sizeof(pushed_local_end_ss_)); std::memcpy(&pushed_local_end_ss_, &local_end, io::internal::getSALength(local_end)); assert(io::internal::getSALength(remote_end) <= sizeof(pushed_remote_end_ss_)); std::memcpy(&pushed_remote_end_ss_, &remote_end, io::internal::getSALength(remote_end)); pushed_data_.resize(data_len); std::memcpy(&pushed_data_[0], data, data_len); } // Allow the test code to check if the connection is established. bool isConnected() const { return (is_connected_); } // Allow the test code to customize the forwarder behavior wrt whether // a specific operation should succeed or fail. void disableConnect() { connect_ok_ = false; } void enableConnect() { connect_ok_ = true; } void disableClose() { close_ok_ = false; } void disablePush() { push_ok_ = false; } void enablePush() { push_ok_ = true; } // Read-only accessors to recorded parameters to the previous successful // call to push(). Return values are undefined if there has been no // successful call to push(). // Note that we use convertSockAddr() to convert sockaddr_storage to // sockaddr. It should be safe since we use the storage in its literal // sense; it was originally filled with the binary image of another // sockaddr structure, and we are going to return the image opaquely // as a sockaddr structure without touching the data. int getPushedSock() const { return (pushed_sock_); } int getPushedFamily() const { return (pushed_family_); } int getPushedType() const { return (pushed_type_); } int getPushedProtocol() const { return (pushed_protocol_); } const struct sockaddr& getPushedLocalend() const { return (*io::internal::convertSockAddr(&pushed_local_end_ss_)); } const struct sockaddr& getPushedRemoteend() const { return (*io::internal::convertSockAddr(&pushed_remote_end_ss_)); } const std::vector& getPushedData() const { return (pushed_data_); } private: bool is_connected_; bool connect_ok_; bool push_ok_; bool close_ok_; int pushed_sock_; int pushed_family_; int pushed_type_; int pushed_protocol_; struct sockaddr_storage pushed_local_end_ss_; struct sockaddr_storage pushed_remote_end_ss_; std::vector pushed_data_; }; } // end of unittests } // end of util } // end of isc #endif // UTIL_UNITTESTS_MOCKSOCKETSESSION_H // Local Variables: // mode: c++ // End: