namespace testutils {
-// TODO Docs
-
+/// \brief A testcase part for faking the SocketRequestor in tests
+///
+/// It's awkward to request real sockets from the real socket creator
+/// during tests (for one, because it would have to be running, for
+/// another, we need to block real ports). If you inherit this class,
+/// the socket requestor will be initialized to a test one which handles
+/// fake socket FDs and stores what was requested, etc. Make sure to
+/// call the inherited SetUp and TearDown if you define your own (eg.
+/// chain them instead of override).
+///
+/// Furthermore, you can check if the code requested or released the correct
+/// list of sockets.
+///
+/// \note This class breaks many recommendations about "clean" object
+/// design. It is mostly because the recommendations are too paranoid
+/// and we better use the powerful tools we have, when we have a reason.
+/// We inherit both the testing::Test and SocketRequestor, so we can
+/// access both the testing macros and store the requests conveniently.
+/// The virtual inheritance is necessary, because some tests need more
+/// than one such "component" to be build from.
class TestSocketRequestor : public isc::server_common::SocketRequestor,
virtual public ::testing::Test {
protected:
+ /// \brief Constructor
+ ///
+ /// \param dnss The DNS service. It is expected this gets initialized
+ /// after the TestSocketRequestor constructor is called, as the
+ /// TestSocketRequestor should be a base class and the service only
+ /// a member.
+ /// \param store Address store used when cleaning up.
+ /// \param expect_port The port which is expected to be requested. If
+ /// the application requests a different port, it is considered
+ /// a failure.
TestSocketRequestor(asiodns::DNSService& dnss,
server_common::portconfig::AddressList& store,
uint16_t expect_port) :
last_token_(0), break_rollback_(false), dnss_(dnss), store_(store),
expect_port_(expect_port)
{}
+ /// \brief Destructor
virtual ~ TestSocketRequestor() {}
- // Store the tokens as they go in and out
+ /// \brief Tokens released by releaseSocket
+ ///
+ /// They are stored here by this class and you can examine them.
std::vector<std::string> released_tokens_;
+ /// \brief Tokens returned from requestSocket
+ ///
+ /// They are stored here by this class and you can examine them.
std::vector<std::string> given_tokens_;
+private:
// Last token number and fd given out
size_t last_token_;
- // Should we break the rollback?
+protected:
+ /// \brief Support a broken rollback case
+ ///
+ /// If this is set to true, the requestSocket will throw when the
+ /// ::1 address is requested.
bool break_rollback_;
+ /// \brief Release a socket
+ ///
+ /// This only stores the token passed.
+ /// \param token The socket to release
void releaseSocket(const std::string& token) {
released_tokens_.push_back(token);
}
+ /// \brief Request a socket
+ ///
+ /// This creates a new token and fakes a new socket and returs it.
+ /// The token is stored.
+ ///
+ /// In case the address is 192.0.2.2 or if the break_rollback_ is true
+ /// and address is ::1, it throws.
+ ///
+ /// The tokens produced are in form of protocol:address:port:fd. The fds
+ /// start at 1 and increase by each successfull call.
+ ///
+ /// \param protocol The protocol to request
+ /// \param address to bind to
+ /// \param port to bind to
+ /// \param mode checked to be DONT_SHARE for now
+ /// \param name checked to be dummy_app for now
+ /// \return The token and FD
+ /// \throw SocketError as described above, to test error handling
SocketID requestSocket(Protocol protocol, const std::string& address,
uint16_t port, ShareMode mode,
const std::string& name)
given_tokens_.push_back(token);
return (SocketID(number, token));
}
+ /// \brief Initialize the test
+ ///
+ /// It installs itself as the socket requestor. It also turns on portconfig
+ /// test mode where it doesn't really put the sockets into ASIO (as the FDs
+ /// are fake ones and would get closed).
+ ///
+ /// Make sure you call it in case you need to define your own SetUp.
void SetUp() {
// Prepare the requestor (us) for the test
SocketRequestor::initTest(this);
// Don't manipulate the real sockets
server_common::portconfig::test_mode = true;
}
+ /// \brief Cleanup after the test
+ ///
+ /// Removes the addresses (if any) installed by installListenAddresses,
+ /// resets the socket requestor to uninitialized state and turns off
+ /// the portconfig test mode.
+ ///
+ /// Make sure you call it in case you need to define your own TearDown.
void TearDown() {
// Make sure no sockets are left inside (if installListenAddresses
// wasn't used, this is NOP, so it won't hurt).
// And return the mode
server_common::portconfig::test_mode = false;
}
- // This checks the set of tokens is the same
+ /// \brief Check the list of tokens is as expected
+ ///
+ /// Compares the expected and real tokens.
+ ///
+ /// \param expected List of the expected tokens, as NULL-terminated array
+ /// of C strings (it is more convenient to type as a constant than to
+ /// manually push_back all the strings to a vector).
+ /// \param real The token list that was produced by this class (usually
+ /// either given_tokens_ or released_tokens_).
+ /// \param scope Human readable identifier of which checkTokens call it is.
+ /// It is printed as a part of failure message.
void checkTokens(const char** expected,
const std::vector<std::string>& real,
const char* scope)