nc_test_utils.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. // Copyright (C) 2013 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. #ifndef NC_TEST_UTILS_H
  15. #define NC_TEST_UTILS_H
  16. /// @file nc_test_utils.h prototypes for functions related transaction testing.
  17. #include <d2/nc_trans.h>
  18. #include <asio/ip/udp.hpp>
  19. #include <asio/socket_base.hpp>
  20. #include <gtest/gtest.h>
  21. namespace isc {
  22. namespace d2 {
  23. extern const char* TEST_DNS_SERVER_IP;
  24. extern size_t TEST_DNS_SERVER_PORT;
  25. // Not extern'ed to allow use as array size
  26. const int TEST_MSG_MAX = 1024;
  27. typedef boost::shared_ptr<asio::ip::udp::socket> SocketPtr;
  28. /// @brief This class simulates a DNS server. It is capable of performing
  29. /// an asynchronous read, governed by an IOService, and responding to received
  30. /// requests in a given manner.
  31. class FauxServer {
  32. public:
  33. enum ResponseMode {
  34. USE_RCODE, // Generate a response with a given RCODE
  35. CORRUPT_RESP // Generate a corrupt response
  36. };
  37. asiolink::IOService& io_service_;
  38. const asiolink::IOAddress& address_;
  39. size_t port_;
  40. SocketPtr server_socket_;
  41. asio::ip::udp::endpoint remote_;
  42. uint8_t receive_buffer_[TEST_MSG_MAX];
  43. bool receive_pending_;
  44. bool perpetual_receive_;
  45. /// @brief Constructor
  46. ///
  47. /// @param io_service IOService to be used for socket IO.
  48. /// @param address IP address at which the server should listen.
  49. /// @param port Port number at which the server should listen.
  50. FauxServer(asiolink::IOService& io_service, asiolink::IOAddress& address,
  51. size_t port);
  52. /// @brief Constructor
  53. ///
  54. /// @param io_service IOService to be used for socket IO.
  55. /// @param server DnServerInfo of server the DNS server. This supplies the
  56. /// server's ip address and port.
  57. FauxServer(asiolink::IOService& io_service, DnsServerInfo& server);
  58. /// @brief Destructor
  59. virtual ~FauxServer();
  60. /// @brief Initiates an asynchronous receive
  61. ///
  62. /// Starts the server listening for requests. Upon completion of the
  63. /// listen, the callback method, requestHandler, is invoked.
  64. ///
  65. /// @param response_mode Selects how the server responds to a request
  66. /// @param response_rcode The Rcode value set in the response. Not used
  67. /// for all modes.
  68. void receive (const ResponseMode& response_mode,
  69. const dns::Rcode& response_rcode=dns::Rcode::NOERROR());
  70. /// @brief Socket IO Completion callback
  71. ///
  72. /// This method servers as the Server's UDP socket receive callback handler.
  73. /// When the receive completes the handler is invoked with the
  74. /// @param error result code of the receive (determined by asio layer)
  75. /// @param bytes_recvd number of bytes received, if any
  76. /// @param response_mode type of response the handler should produce
  77. /// @param response_rcode value of Rcode in the response constructed by
  78. /// handler
  79. void requestHandler(const asio::error_code& error,
  80. std::size_t bytes_recvd,
  81. const ResponseMode& response_mode,
  82. const dns::Rcode& response_rcode);
  83. bool isReceivePending() {
  84. return receive_pending_;
  85. }
  86. };
  87. class TimedIO {
  88. public:
  89. IOServicePtr io_service_;
  90. asiolink::IntervalTimer timer_;
  91. int run_time_;
  92. // Constructor
  93. TimedIO();
  94. // Destructor
  95. virtual ~TimedIO();
  96. /// @brief IO Timer expiration handler
  97. ///
  98. /// Stops the IOService and fails the current test.
  99. virtual void timesUp();
  100. /// @brief Runs IOService till time expires or at least one handler executes.
  101. ///
  102. /// This method first polls IOService to run any ready handlers. If no
  103. /// handlers are ready, it starts the internal time to run for the given
  104. /// amount of time and invokes service's run_one method. This method
  105. /// blocks until at least one handler executes or the IO Service is stopped.
  106. /// Upon completion of this method the timer is cancelled. Should the
  107. /// timer expires prior to run_one returning, the timesUp handler will be
  108. /// invoked which stops the IO service and fails the test.
  109. ///
  110. /// Note that this method closely mimics the runIO method in D2Process.
  111. ///
  112. /// @param run_time maximum length of time to run in milliseconds before
  113. /// timing out.
  114. ///
  115. /// @return Returns the number of handlers executed or zero. A return of
  116. /// zero indicates that the IOService has been stopped.
  117. int runTimedIO(int run_time);
  118. };
  119. /// @brief Base class Test fixture for testing transactions.
  120. class TransactionTest : public TimedIO, public ::testing::Test {
  121. public:
  122. dhcp_ddns::NameChangeRequestPtr ncr_;
  123. DdnsDomainPtr forward_domain_;
  124. DdnsDomainPtr reverse_domain_;
  125. /// #brief constants used to specify change directions for a transaction.
  126. static const unsigned int FORWARD_CHG; // Only forward change.
  127. static const unsigned int REVERSE_CHG; // Only reverse change.
  128. static const unsigned int FWD_AND_REV_CHG; // Both forward and reverse.
  129. TransactionTest();
  130. virtual ~TransactionTest();
  131. /// @brief Creates a transaction which requests an IPv4 DNS update.
  132. ///
  133. /// The transaction is constructed around a predefined (i.e. "canned")
  134. /// IPv4 NameChangeRequest. The request has both forward and reverse DNS
  135. /// changes requested. Based upon the change mask, the transaction
  136. /// will have either the forward, reverse, or both domains populated.
  137. ///
  138. /// @param change_type selects the type of change requested, CHG_ADD or
  139. /// CHG_REMOVE.
  140. /// @param change_mask determines which change directions are requested
  141. /// FORWARD_CHG, REVERSE_CHG, or FWD_AND_REV_CHG.
  142. void setupForIPv4Transaction(dhcp_ddns::NameChangeType change_type,
  143. int change_mask);
  144. /// @brief Creates a transaction which requests an IPv6 DNS update.
  145. ///
  146. /// The transaction is constructed around a predefined (i.e. "canned")
  147. /// IPv6 NameChangeRequest. The request has both forward and reverse DNS
  148. /// changes requested. Based upon the change mask, the transaction
  149. /// will have either the forward, reverse, or both domains populated.
  150. ///
  151. /// @param change_type selects the type of change requested, CHG_ADD or
  152. /// CHG_REMOVE.
  153. /// @param change_mask determines which change directions are requested
  154. /// FORWARD_CHG, REVERSE_CHG, or FWD_AND_REV_CHG.
  155. void setupForIPv6Transaction(dhcp_ddns::NameChangeType change_type,
  156. int change_mask);
  157. };
  158. /// @brief Tests the number of RRs in a request section against a given count.
  159. ///
  160. /// This function actually returns the number of RRsetPtrs in a section. Since
  161. /// D2 only uses RRsets with a single RData in each (i.e. 1 RR), it is used
  162. /// as the number of RRs. The dns::Message::getRRCount() cannot be used for
  163. /// this as it returns the number of RDatas in an RRSet which does NOT equate
  164. /// to the number of RRs. RRs with no RData, those with class or type of ANY,
  165. /// are not counted.
  166. ///
  167. /// @param request DNS update request to test
  168. /// @param section enum value of the section to count
  169. /// @param count the expected number of RRs
  170. extern void checkRRCount(const D2UpdateMessagePtr& request,
  171. D2UpdateMessage::UpdateMsgSection section, int count);
  172. /// @brief Tests the zone content of a given request.
  173. ///
  174. /// @param request DNS update request to validate
  175. /// @param exp_zone_name expected value of the zone name in the zone section
  176. extern void checkZone(const D2UpdateMessagePtr& request,
  177. const std::string& exp_zone_name);
  178. /// @brief Tests the contents of an RRset
  179. ///
  180. /// @param rrset Pointer the RRset to test
  181. /// @param exp_name expected value of RRset name (FQDN or reverse ip)
  182. /// @param exp_class expected RRClass value of RRset
  183. /// @param exp_typ expected RRType value of RRset
  184. /// @param exp_ttl expected TTL value of RRset
  185. /// @param ncr NameChangeRequest on which the RRset is based
  186. /// @param has_rdata if true, RRset's rdata will be checked based on it's
  187. /// RRType. Set this to false if the RRset's type supports Rdata but it does
  188. /// not contain it. For instance, prerequisites of type NONE have no Rdata
  189. /// where updates of type NONE may.
  190. extern void checkRR(dns::RRsetPtr rrset, const std::string& exp_name,
  191. const dns::RRClass& exp_class, const dns::RRType& exp_type,
  192. unsigned int exp_ttl, dhcp_ddns::NameChangeRequestPtr ncr,
  193. bool has_rdata=true);
  194. /// @brief Fetches an RR(set) from a given section of a request
  195. ///
  196. /// @param request DNS update request from which the RR should come
  197. /// @param section enum value of the section from which the RR should come
  198. /// @param index zero-based index of the RR of interest.
  199. ///
  200. /// @return Pointer to the RR of interest, empty pointer if the index is out
  201. /// of range.
  202. extern dns::RRsetPtr getRRFromSection(const D2UpdateMessagePtr& request,
  203. D2UpdateMessage::UpdateMsgSection section,
  204. int index);
  205. /// @brief Creates a NameChangeRequest from a JSON string
  206. ///
  207. /// @param ncr_str JSON string form of a NameChangeRequest. Example:
  208. /// @code
  209. /// const char* msg_str =
  210. /// "{"
  211. /// " \"change_type\" : 0 , "
  212. /// " \"forward_change\" : true , "
  213. /// " \"reverse_change\" : true , "
  214. /// " \"fqdn\" : \"my.example.com.\" , "
  215. /// " \"ip_address\" : \"192.168.2.1\" , "
  216. /// " \"dhcid\" : \"0102030405060708\" , "
  217. /// " \"lease_expires_on\" : \"20130121132405\" , "
  218. /// " \"lease_length\" : 1300 "
  219. /// "}";
  220. ///
  221. /// @endcode
  222. /// @brief Verifies a forward mapping addition DNS update request
  223. ///
  224. /// Tests that the DNS Update request for a given transaction, is correct for
  225. /// adding a forward DNS mapping.
  226. ///
  227. /// @param tran Transaction containing the request to be verified.
  228. extern void checkAddFwdAddressRequest(NameChangeTransaction& tran);
  229. /// @brief Verifies a forward mapping replacement DNS update request
  230. ///
  231. /// Tests that the DNS Update request for a given transaction, is correct for
  232. /// replacing a forward DNS mapping.
  233. ///
  234. /// @param tran Transaction containing the request to be verified.
  235. extern void checkReplaceFwdAddressRequest(NameChangeTransaction& tran);
  236. /// @brief Verifies a reverse mapping replacement DNS update request
  237. ///
  238. /// Tests that the DNS Update request for a given transaction, is correct for
  239. /// replacing a reverse DNS mapping.
  240. ///
  241. /// @param tran Transaction containing the request to be verified.
  242. extern void checkReplaceRevPtrsRequest(NameChangeTransaction& tran);
  243. /// @brief Verifies a forward address removal DNS update request
  244. ///
  245. /// Tests that the DNS Update request for a given transaction, is correct for
  246. /// removing the forward address DNS entry.
  247. ///
  248. /// @param tran Transaction containing the request to be verified.
  249. extern void checkRemoveFwdAddressRequest(NameChangeTransaction& tran);
  250. /// @brief Verifies a forward RR removal DNS update request
  251. ///
  252. /// Tests that the DNS Update request for a given transaction, is correct for
  253. /// removing forward RR DNS entries.
  254. ///
  255. /// @param tran Transaction containing the request to be verified.
  256. extern void checkRemoveFwdRRsRequest(NameChangeTransaction& tran);
  257. /// @brief Verifies a reverse mapping removal DNS update request
  258. ///
  259. /// Tests that the DNS Update request for a given transaction, is correct for
  260. /// removing a reverse DNS mapping.
  261. ///
  262. /// @param tran Transaction containing the request to be verified.
  263. extern void checkRemoveRevPtrsRequest(NameChangeTransaction& tran);
  264. /// @brief Creates a NameChangeRequest from JSON string.
  265. ///
  266. /// @param ncr_str string of JSON text from which to make the request.
  267. ///
  268. /// @return Pointer to newly created request.
  269. ///
  270. /// @throw Underlying methods may throw.
  271. extern
  272. dhcp_ddns::NameChangeRequestPtr makeNcrFromString(const std::string& ncr_str);
  273. /// @brief Creates a DdnsDomain with the one server.
  274. ///
  275. /// @param zone_name zone name of the domain
  276. /// @param key_name TSIG key name of the TSIG key for this domain
  277. ///
  278. /// @throw Underlying methods may throw.
  279. extern DdnsDomainPtr makeDomain(const std::string& zone_name,
  280. const std::string& key_name = "");
  281. /// @brief Creates a DnsServerInfo and adds it to the given DdnsDomain.
  282. ///
  283. /// The server is created and added to the domain, without duplicate entry
  284. /// checking.
  285. ///
  286. /// @param domain DdnsDomain to which to add the server
  287. /// @param name new server's host name of the server
  288. /// @param ip new server's ip address
  289. /// @param port new server's port
  290. ///
  291. /// @throw Underlying methods may throw.
  292. extern void addDomainServer(DdnsDomainPtr& domain, const std::string& name,
  293. const std::string& ip = TEST_DNS_SERVER_IP,
  294. const size_t port = TEST_DNS_SERVER_PORT);
  295. /// @brief Creates a hex text dump of the given data buffer.
  296. ///
  297. /// @param data pointer to the data to dump
  298. /// @param len size (in bytes) of data
  299. extern std::string toHexText(const uint8_t* data, size_t len);
  300. }; // namespace isc::d2
  301. }; // namespace isc
  302. #endif