test_control_unittest.cc 45 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063
  1. // Copyright (C) 2012 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. #include <cstddef>
  15. #include <stdint.h>
  16. #include <string>
  17. #include <fstream>
  18. #include <gtest/gtest.h>
  19. #include <boost/date_time/posix_time/posix_time.hpp>
  20. #include <exceptions/exceptions.h>
  21. #include <asiolink/io_address.h>
  22. #include <dhcp/dhcp4.h>
  23. #include <dhcp/iface_mgr.h>
  24. #include "command_options_helper.h"
  25. #include "../test_control.h"
  26. using namespace std;
  27. using namespace boost::posix_time;
  28. using namespace isc;
  29. using namespace isc::dhcp;
  30. using namespace isc::perfdhcp;
  31. /// \brief Test Control class with protected members made public.
  32. ///
  33. /// This class makes protected TestControl class'es member public
  34. /// to allow unit testing.
  35. class NakedTestControl: public TestControl {
  36. public:
  37. /// \brief Incremental transaction id generaator.
  38. ///
  39. /// This is incremental transaction id generator. It overrides
  40. /// the default transaction id generator that generates transaction
  41. /// ids using random function. This generator will generate values
  42. /// like: 1,2,3 etc.
  43. class IncrementalGenerator : public TestControl::NumberGenerator {
  44. public:
  45. /// \brief Default constructor.
  46. IncrementalGenerator() :
  47. NumberGenerator(),
  48. transid_(0) {
  49. }
  50. /// \brief Generate unique transaction id.
  51. ///
  52. /// Generate unique transaction ids incrementally:
  53. /// 1,2,3,4 etc.
  54. ///
  55. /// \return generated transaction id.
  56. virtual uint32_t generate() {
  57. return (++transid_);
  58. }
  59. private:
  60. uint32_t transid_; ///< Last generated transaction id.
  61. };
  62. using TestControl::checkExitConditions;
  63. using TestControl::factoryElapsedTime6;
  64. using TestControl::factoryGeneric;
  65. using TestControl::factoryIana6;
  66. using TestControl::factoryOptionRequestOption6;
  67. using TestControl::factoryRapidCommit6;
  68. using TestControl::factoryRequestList4;
  69. using TestControl::generateDuid;
  70. using TestControl::generateMacAddress;
  71. using TestControl::getNextExchangesNum;
  72. using TestControl::getTemplateBuffer;
  73. using TestControl::initPacketTemplates;
  74. using TestControl::initializeStatsMgr;
  75. using TestControl::openSocket;
  76. using TestControl::processReceivedPacket4;
  77. using TestControl::processReceivedPacket6;
  78. using TestControl::registerOptionFactories;
  79. using TestControl::sendDiscover4;
  80. using TestControl::sendSolicit6;
  81. using TestControl::setDefaults4;
  82. using TestControl::setDefaults6;
  83. NakedTestControl() : TestControl() {
  84. uint32_t clients_num = CommandOptions::instance().getClientsNum() == 0 ?
  85. 1 : CommandOptions::instance().getClientsNum();
  86. setMacAddrGenerator(NumberGeneratorPtr(new TestControl::SequentialGenerator(clients_num)));
  87. };
  88. };
  89. /// \brief Test Fixture Class
  90. ///
  91. /// This test fixture class is used to perform
  92. /// unit tests on perfdhcp TestControl class.
  93. class TestControlTest : public virtual ::testing::Test
  94. {
  95. public:
  96. typedef std::vector<uint8_t> MacAddress;
  97. typedef MacAddress::iterator MacAddressIterator;
  98. typedef std::vector<uint8_t> Duid;
  99. typedef Duid::iterator DuidIterator;
  100. /// \brief Default Constructor
  101. TestControlTest() { }
  102. /// \brief Create packet template file from binary data.
  103. ///
  104. /// Function creates file containing data from the provided buffer
  105. /// in hexadecimal format. The size parameter specifies the maximum
  106. /// size of the file. If total number of hexadecimal digits resulting
  107. /// from buffer size is greater than maximum file size the file is
  108. /// truncated.
  109. ///
  110. /// \param filename template file to be created.
  111. /// \param buffer with binary datato be stored in file.
  112. /// \param size target size of the file.
  113. /// \param invalid_chars inject invalid chars to the template file.
  114. /// \return true if file creation successful.
  115. bool createTemplateFile(const std::string& filename,
  116. const std::vector<uint8_t>& buf,
  117. const size_t size,
  118. const bool invalid_chars = false) const {
  119. std::ofstream temp_file;
  120. temp_file.open(filename.c_str(), ios::out | ios::trunc);
  121. if (!temp_file.is_open()) {
  122. return (false);
  123. }
  124. for (int i = 0; i < buf.size(); ++i) {
  125. int first_digit = buf[i] / 16;
  126. int second_digit = buf[i] % 16;
  127. // Insert two spaces between two hexadecimal digits.
  128. // Spaces are allowed in template files.
  129. temp_file << std::string(2, ' ');
  130. if (2 * i + 1 < size) {
  131. if (!invalid_chars) {
  132. temp_file << std::hex << first_digit << second_digit << std::dec;
  133. } else {
  134. temp_file << "XY";
  135. }
  136. } else if (2 * i < size) {
  137. if (!invalid_chars) {
  138. temp_file << std::hex << first_digit;
  139. } else {
  140. temp_file << "X";
  141. }
  142. } else {
  143. break;
  144. }
  145. }
  146. temp_file.close();
  147. return (true);
  148. }
  149. /// \brief Get local loopback interface name.
  150. ///
  151. /// Scan available network interfaces for local loopback
  152. /// interface and get its name. On Linux this interface is
  153. /// usually called 'lo' but on other systems, e.g. BSD
  154. /// it will have slightly different name. Local loopback
  155. /// interface is required for unit tests that require
  156. /// socket creation.
  157. ///
  158. /// \return local loopback interface name.
  159. std::string getLocalLoopback() const {
  160. const IfaceMgr::IfaceCollection& ifaces =
  161. IfaceMgr::instance().getIfaces();
  162. for (IfaceMgr::IfaceCollection::const_iterator iface = ifaces.begin();
  163. iface != ifaces.end();
  164. ++iface) {
  165. if (iface->flag_loopback_) {
  166. return (iface->getName());
  167. }
  168. }
  169. return ("");
  170. }
  171. /// \brief Match requested options in the buffer with given list.
  172. ///
  173. /// This method iterates through options provided in the buffer
  174. /// and matches them with the options specified with first parameter.
  175. /// Options in both vectors may be laid in different order.
  176. ///
  177. /// \param requested_options reference buffer with options.
  178. /// \param buf test buffer with options that will be matched.
  179. /// \return number of options from the buffer matched with options
  180. /// in the reference buffer.
  181. int matchRequestedOptions(const dhcp::OptionBuffer& requested_options,
  182. const dhcp::OptionBuffer& buf) const {
  183. size_t matched_num = 0;
  184. for (size_t i = 0; i < buf.size(); ++i) {
  185. for (int j = 0; j < requested_options.size(); ++j) {
  186. if (requested_options[j] == buf[i]) {
  187. // Requested option has been found.
  188. ++matched_num;
  189. }
  190. }
  191. }
  192. return (matched_num);
  193. }
  194. /// \brief Match requested DHCPv6 options in the buffer with given list.
  195. ///
  196. /// This method iterates through options provided in the buffer and
  197. /// matches them with the options specified with first parameter.
  198. /// Options in both vectors ma be laid in different order.
  199. ///
  200. /// \param requested_options reference buffer with options.
  201. /// \param buf test buffer with options that will be matched.
  202. /// \return number of options from the buffer matched with options in
  203. /// the reference buffer or -1 if error occured.
  204. int matchRequestedOptions6(const dhcp::OptionBuffer& requested_options,
  205. const dhcp::OptionBuffer& buf) const {
  206. // Sanity check.
  207. if ((requested_options.size() % 2 != 0) ||
  208. (buf.size() % 2 != 0)) {
  209. return -1;
  210. }
  211. size_t matched_num = 0;
  212. for (size_t i = 0; i < buf.size(); i += 2) {
  213. for (int j = 0; j < requested_options.size(); j += 2) {
  214. uint16_t opt_i = buf[i + 1] << 8 + buf[i] & 0xFF;
  215. uint16_t opt_j = requested_options[j + 1] << 8 + requested_options[j] & 0xFF;
  216. if (opt_i == opt_j) {
  217. // Requested option has been found.
  218. ++matched_num;
  219. }
  220. }
  221. }
  222. return (matched_num);
  223. }
  224. /// \brief Calculate the maximum vectors' mismatch position.
  225. ///
  226. /// This helper function calculates the maximum mismatch position
  227. /// between two vectors (two different DUIDs or MAC addresses).
  228. /// Calculated position is counted from the end of vectors.
  229. /// Calculation is based on number of simulated clients. When number
  230. /// of clients is less than 256 different DUIDs or MAC addresses can
  231. /// can be coded in such a way that they differ on last vector element.
  232. /// If number of clients is between 257 and 65536 they can differ
  233. /// on two last positions so the returned value will be 2 and so on.
  234. ///
  235. /// \param clients_num number of simulated clinets
  236. /// \return maximum mismatch position
  237. int unequalOctetPosition(int clients_num) const {
  238. if (!clients_num) {
  239. return (0);
  240. }
  241. clients_num--;
  242. int cnt = 0;
  243. while (clients_num) {
  244. clients_num >>= 8;
  245. ++cnt;
  246. }
  247. return (cnt);
  248. }
  249. /// brief Test generation of mulitple DUIDs
  250. ///
  251. /// Thie method checks the generation of multiple DUIDs. Number
  252. /// of iterations depends on the number of simulated clients.
  253. /// It is expected that DUID's size is 14 (consists of DUID-LLT
  254. /// HW type field, 4 octets of time value and MAC address). The
  255. /// MAC address can be randomized depending on the number of
  256. /// simulated clients. The DUID-LLT and HW type are expected to
  257. /// be constant. The time value has to be properly calculated
  258. /// as the number of seconds since DUID time epoch. The parts
  259. /// of MAC address has to change if multiple clients are simulated
  260. /// and do not change if single client is simulated.
  261. void testDuid() const {
  262. int clients_num = CommandOptions::instance().getClientsNum();
  263. // Initialize Test Control class.
  264. NakedTestControl tc;
  265. // The old duid will be holding the previously generated DUID.
  266. // It will be used to compare against the new one. If we have
  267. // multiple clients we want to make sure that duids differ.
  268. uint8_t randomized = 0;
  269. Duid old_duid(tc.generateDuid(randomized));
  270. Duid new_duid(0);
  271. // total_dist shows the total difference between generated duid.
  272. // It has to be greater than zero if multiple clients are simulated.
  273. size_t total_dist = 0;
  274. // Number of unique DUIDs.
  275. size_t unique_duids = 0;
  276. // Holds the position if the octet on which two DUIDS can be different.
  277. // If number of clients is 256 or less it is last DUID octet (except for
  278. // single client when subsequent DUIDs have to be equal). If number of
  279. // clients is between 257 and 65536 the last two octets can differ etc.
  280. int unequal_pos = unequalOctetPosition(clients_num);
  281. // Keep generated DUIDs in this container.
  282. std::list<std::vector<uint8_t> > duids;
  283. // Perform number of iterations to generate number of DUIDs.
  284. for (int i = 0; i < 10 * clients_num; ++i) {
  285. if (new_duid.empty()) {
  286. new_duid = old_duid;
  287. } else {
  288. std::swap(old_duid, new_duid);
  289. new_duid = tc.generateDuid(randomized);
  290. }
  291. // The DUID-LLT is expected to start with DUID_LLT value
  292. // of 1 and hardware ethernet type equal to 1 (HWETHER_TYPE).
  293. const uint8_t duid_llt_and_hw[4] = { 0x0, 0x1, 0x0, 0x1 };
  294. // We assume DUID-LLT length 14. This includes 4 octets of
  295. // DUID_LLT value, two octets of hardware type, 4 octets
  296. // of time value and 6 octets of variable link layer (MAC)
  297. // address.
  298. const int duid_llt_size = 14;
  299. ASSERT_EQ(duid_llt_size, new_duid.size());
  300. // The first four octets do not change.
  301. EXPECT_TRUE(std::equal(new_duid.begin(), new_duid.begin() + 4,
  302. duid_llt_and_hw));
  303. // As described in RFC3315: 'the time value is the time
  304. // that the DUID is generated represented in seconds
  305. // since midnight (UTC), January 1, 2000, modulo 2^32.'
  306. uint32_t duid_time = 0;
  307. // Pick 4 bytes of the time from generated DUID and put them
  308. // in reverse order (in DUID they are stored in network order).
  309. for (int j = 4; j < 8; ++j) {
  310. duid_time |= new_duid[j] << (j - 4);
  311. }
  312. // Calculate the duration since epoch time.
  313. ptime now = microsec_clock::universal_time();
  314. ptime duid_epoch(from_iso_string("20000101T000000"));
  315. time_period period(duid_epoch, now);
  316. // Current time is the same or later than time from the DUID because
  317. // DUID had been generated before reference duration was calculated.
  318. EXPECT_GE(period.length().total_seconds(), duid_time);
  319. // Get the mismatch position (counting from the end) of
  320. // mismatched octet between previously generated DUID
  321. // and current.
  322. std::pair<DuidIterator, DuidIterator> mismatch_pos =
  323. std::mismatch(old_duid.begin(), old_duid.end(),
  324. new_duid.begin());
  325. size_t mismatch_dist =
  326. std::distance(mismatch_pos.first, old_duid.end());
  327. // For single client total_dist is expected to be 0 because
  328. // old_duid and new_duid should always match. If we have
  329. // more clients then duids have to differ except the case
  330. // if randomization algorithm generates the same values but
  331. // this would be an error in randomization algorithm.
  332. total_dist += mismatch_dist;
  333. // Mismatch may have occured on the DUID octet position
  334. // up to calculated earlier unequal_pos.
  335. ASSERT_LE(mismatch_dist, unequal_pos);
  336. // unique will inform if tested DUID is unique.
  337. bool unique = true;
  338. for (std::list<std::vector<uint8_t> >::const_iterator it =
  339. duids.begin();
  340. it != duids.end(); ++it) {
  341. // DUIDs should be of the same size if we want to compare them.
  342. ASSERT_EQ(new_duid.size(), it->size());
  343. // Check if DUID is unique.
  344. if (std::equal(new_duid.begin(), new_duid.end(), it->begin())) {
  345. unique = false;
  346. }
  347. }
  348. // Expecting that DUIDs will be unique only when
  349. // first clients-num iterations is performed.
  350. // After that, DUIDs become non unique.
  351. if (unique) {
  352. ++unique_duids;
  353. }
  354. // For number of iterations equal to clients_num,2*clients_num
  355. // 3*clients_num ... we have to have number of unique duids
  356. // equal to clients_num.
  357. if ((i != 0) && (i % clients_num == 0)) {
  358. ASSERT_EQ(clients_num, unique_duids);
  359. }
  360. // Remember generated DUID.
  361. duids.push_back(new_duid);
  362. }
  363. // If we have more than one client at least one mismatch occured.
  364. if (clients_num < 2) {
  365. EXPECT_EQ(0, total_dist);
  366. }
  367. }
  368. /// \brief Test DHCPv4 exchanges.
  369. ///
  370. /// Function simulates DHCPv4 exchanges. Function caller specifies
  371. /// number of exchanges to be simulated and number of simulated
  372. /// responses. When number of responses is lower than number of
  373. /// iterations than the difference between them is the number
  374. /// of simulated packet drops. This is useful to test if program
  375. /// exit conditions are handled properly (maximum number of packet
  376. /// drops specified as -D<max-drops> is taken into account).
  377. ///
  378. /// \param iterations_num number of exchanges to simulate.
  379. /// \param receive_num number of received OFFER packets.
  380. /// \param iterations_performed actual number of iterations.
  381. void testPkt4Exchange(int iterations_num,
  382. int receive_num,
  383. bool use_templates,
  384. int& iterations_performed) const {
  385. int sock_handle = 0;
  386. NakedTestControl tc;
  387. tc.initializeStatsMgr();
  388. // Use templates files to crate packets.
  389. if (use_templates) {
  390. tc.initPacketTemplates();
  391. ASSERT_NO_THROW(tc.getTemplateBuffer(0));
  392. ASSERT_NO_THROW(tc.getTemplateBuffer(1));
  393. }
  394. // Incremental transaction id generator will generate
  395. // predictable values of transaction id for each iteration.
  396. // This is important because we need to simulate responses
  397. // from the server and use the same transaction ids as in
  398. // packets sent by client.
  399. TestControl::NumberGeneratorPtr
  400. generator(new NakedTestControl::IncrementalGenerator());
  401. tc.setTransidGenerator(generator);
  402. // Socket is needed to send packets through the interface.
  403. ASSERT_NO_THROW(sock_handle = tc.openSocket());
  404. TestControl::TestControlSocket sock(sock_handle);
  405. uint32_t transid = 0;
  406. for (int i = 0; i < iterations_num; ++i) {
  407. if (use_templates) {
  408. ASSERT_NO_THROW(tc.sendDiscover4(sock, tc.getTemplateBuffer(0)));
  409. } else {
  410. ASSERT_NO_THROW(tc.sendDiscover4(sock));
  411. }
  412. ++transid;
  413. // Do not simulate responses for packets later
  414. // that specified as receive_num. This simulates
  415. // packet drops.
  416. if (i < receive_num) {
  417. boost::shared_ptr<Pkt4> offer_pkt4(createOfferPkt4(transid));
  418. ASSERT_NO_THROW(tc.processReceivedPacket4(sock, offer_pkt4));
  419. ++transid;
  420. }
  421. if (tc.checkExitConditions()) {
  422. iterations_performed = i + 1;
  423. break;
  424. }
  425. iterations_performed = i + 1;
  426. }
  427. }
  428. /// \brief Test DHCPv6 exchanges.
  429. ///
  430. /// Function simulates DHCPv6 exchanges. Function caller specifies
  431. /// number of exchanges to be simulated and number of simulated
  432. /// responses. When number of responses is lower than number of
  433. /// iterations than the difference between them is the number
  434. /// of simulated packet drops. This is useful to test if program
  435. /// exit conditions are handled properly (maximum number of packet
  436. /// drops specified as -D<max-drops> is taken into account).
  437. ///
  438. /// \param iterations_num number of exchanges to simulate.
  439. /// \param receive_num number of received OFFER packets.
  440. /// \param iterations_performed actual number of iterations.
  441. void testPkt6Exchange(int iterations_num,
  442. int receive_num,
  443. bool use_templates,
  444. int& iterations_performed) const {
  445. int sock_handle = 0;
  446. NakedTestControl tc;
  447. tc.initializeStatsMgr();
  448. // Use templates files to crate packets.
  449. if (use_templates) {
  450. tc.initPacketTemplates();
  451. ASSERT_NO_THROW(tc.getTemplateBuffer(0));
  452. ASSERT_NO_THROW(tc.getTemplateBuffer(1));
  453. }
  454. // Incremental transaction id generator will generate
  455. // predictable values of transaction id for each iteration.
  456. // This is important because we need to simulate reponses
  457. // from the server and use the same transaction ids as in
  458. // packets sent by client.
  459. TestControl::NumberGeneratorPtr
  460. generator(new NakedTestControl::IncrementalGenerator());
  461. tc.setTransidGenerator(generator);
  462. // Socket is needed to send packets through the interface.
  463. ASSERT_NO_THROW(sock_handle = tc.openSocket());
  464. TestControl::TestControlSocket sock(sock_handle);
  465. uint32_t transid = 0;
  466. for (int i = 0; i < iterations_num; ++i) {
  467. // Do not simulate responses for packets later
  468. // that specified as receive_num. This simulates
  469. // packet drops.
  470. if (use_templates) {
  471. ASSERT_NO_THROW(tc.sendSolicit6(sock, tc.getTemplateBuffer(0)));
  472. } else {
  473. ASSERT_NO_THROW(tc.sendSolicit6(sock));
  474. }
  475. ++transid;
  476. if (i < receive_num) {
  477. boost::shared_ptr<Pkt6>
  478. advertise_pkt6(createAdvertisePkt6(transid));
  479. // Receive ADVERTISE and send REQUEST.
  480. ASSERT_NO_THROW(tc.processReceivedPacket6(sock, advertise_pkt6));
  481. ++transid;
  482. }
  483. if (tc.checkExitConditions()) {
  484. iterations_performed = i + 1;
  485. break;
  486. }
  487. iterations_performed = i + 1;
  488. }
  489. }
  490. /// \brief Test generation of multiple MAC addresses.
  491. ///
  492. /// This method validates generation of multiple MAC addresses.
  493. /// The MAC address can be randomized depending on the number
  494. /// of simulated clients. This test checks if different MAC
  495. /// addresses are generated if number of simulated clients is
  496. /// greater than 1. It also checks if the same MAC addresses is
  497. /// generated if only 1 client is simulated.
  498. void testMacAddress() const {
  499. int clients_num = CommandOptions::instance().getClientsNum();
  500. // The old_mac will be holding the value of previously generated
  501. // MAC address. We will be comparing the newly generated one with it
  502. // to see if it changes when mulitple clients are simulated or if it
  503. // does not change when single client is simulated.
  504. MacAddress old_mac(CommandOptions::instance().getMacTemplate());
  505. // Holds the position if the octet on which two MAC addresses can
  506. // be different. If number of clients is 256 or less it is last MAC
  507. // octet (except for single client when subsequent MAC addresses
  508. // have to be equal). If number of clients is between 257 and 65536
  509. // the last two octets can differ etc.
  510. int unequal_pos = unequalOctetPosition(clients_num);
  511. // Number of unique MACs.
  512. size_t unique_macs = 0;
  513. // Initialize Test Controller.
  514. NakedTestControl tc;
  515. size_t total_dist = 0;
  516. // Keep generated MACs in this container.
  517. std::list<std::vector<uint8_t> > macs;
  518. // Do many iterations to generate and test MAC address values.
  519. for (int i = 0; i < clients_num * 10; ++i) {
  520. // Generate new MAC address.
  521. uint8_t randomized = 0;
  522. MacAddress new_mac(tc.generateMacAddress(randomized));
  523. // Get the mismatch position (counting from the end) of
  524. // mismatched octet between previously generated MAC address
  525. // and current.
  526. std::pair<MacAddressIterator, MacAddressIterator> mismatch_pos =
  527. std::mismatch(old_mac.begin(), old_mac.end(), new_mac.begin());
  528. size_t mismatch_dist =
  529. std::distance(mismatch_pos.first, old_mac.end());
  530. // For single client total_dist is expected to be 0 because
  531. // old_mac and new_mac should always match. If we have
  532. // more clients then MAC addresses have to differ except
  533. // the case if randomization algorithm generates the same
  534. // values but this would be an error in randomization algorithm.
  535. total_dist += mismatch_dist;
  536. // Mismatch may have occured on the MAC address'es octet position
  537. // up to calculated earlier unequal_pos.
  538. ASSERT_LE(mismatch_dist, unequal_pos);
  539. // unique will inform if tested DUID is unique.
  540. bool unique = true;
  541. for (std::list<std::vector<uint8_t> >::const_iterator it =
  542. macs.begin();
  543. it != macs.end(); ++it) {
  544. // MACs should be of the same size if we want to compare them.
  545. ASSERT_EQ(new_mac.size(), it->size());
  546. // Check if MAC is unique.
  547. if (std::equal(new_mac.begin(), new_mac.end(), it->begin())) {
  548. unique = false;
  549. }
  550. }
  551. // Expecting that MACs will be unique only when
  552. // first clients-num iterations is performed.
  553. // After that, MACs become non unique.
  554. if (unique) {
  555. ++unique_macs;
  556. }
  557. // For number of iterations equal to clients_num,2*clients_num
  558. // 3*clients_num ... we have to have number of unique MACs
  559. // equal to clients_num.
  560. if ((i != 0) && (i % clients_num == 0)) {
  561. ASSERT_EQ(clients_num, unique_macs);
  562. }
  563. // Remember generated MAC.
  564. macs.push_back(new_mac);
  565. }
  566. if (clients_num < 2) {
  567. EXPECT_EQ(total_dist, 0);
  568. }
  569. }
  570. /// \brief Parse command line string with CommandOptions.
  571. ///
  572. /// \param cmdline command line string to be parsed.
  573. /// \throw isc::Unexpected if unexpected error occured.
  574. /// \throw isc::InvalidParameter if command line is invalid.
  575. void processCmdLine(const std::string& cmdline) const {
  576. CommandOptionsHelper::process(cmdline);
  577. }
  578. private:
  579. /// \brief Create DHCPv4 OFFER packet.
  580. ///
  581. /// \param transid transaction id.
  582. /// \return instance of the packet.
  583. boost::shared_ptr<Pkt4>
  584. createOfferPkt4(uint32_t transid) const {
  585. boost::shared_ptr<Pkt4> offer(new Pkt4(DHCPOFFER, transid));
  586. OptionPtr opt_msg_type = Option::factory(Option::V4, DHO_DHCP_MESSAGE_TYPE,
  587. OptionBuffer(DHCPOFFER));
  588. OptionPtr opt_serverid = Option::factory(Option::V4,
  589. DHO_DHCP_SERVER_IDENTIFIER,
  590. OptionBuffer(4, 1));
  591. offer->setYiaddr(asiolink::IOAddress("127.0.0.1"));
  592. offer->addOption(opt_msg_type);
  593. offer->addOption(opt_serverid);
  594. offer->updateTimestamp();
  595. return (offer);
  596. }
  597. /// \brief Create DHCPv6 ADVERTISE packet.
  598. ///
  599. /// \param transid transaction id.
  600. /// \return instance of the packet.
  601. boost::shared_ptr<Pkt6>
  602. createAdvertisePkt6(uint32_t transid) const {
  603. OptionPtr opt_ia_na = Option::factory(Option::V6, D6O_IA_NA);
  604. OptionPtr opt_serverid(new Option(Option::V6, D6O_SERVERID));
  605. NakedTestControl tc;
  606. uint8_t randomized = 0;
  607. std::vector<uint8_t> duid(tc.generateDuid(randomized));
  608. OptionPtr opt_clientid(Option::factory(Option::V6, D6O_CLIENTID, duid));
  609. boost::shared_ptr<Pkt6> advertise(new Pkt6(DHCPV6_ADVERTISE, transid));
  610. advertise->addOption(opt_ia_na);
  611. advertise->addOption(opt_serverid);
  612. advertise->addOption(opt_clientid);
  613. advertise->updateTimestamp();
  614. return (advertise);
  615. }
  616. };
  617. TEST_F(TestControlTest, GenerateDuid) {
  618. // Simple command line that simulates one client only. Always the
  619. // same DUID will be generated.
  620. ASSERT_NO_THROW(processCmdLine("perfdhcp -l 127.0.0.1 all"));
  621. testDuid();
  622. // Simulate 50 clients. Different DUID will be generated.
  623. ASSERT_NO_THROW(processCmdLine("perfdhcp -l 127.0.0.1 -R 50 all"));
  624. testDuid();
  625. }
  626. TEST_F(TestControlTest, GenerateMacAddress) {
  627. // Simulate one client only. Always the same MAC address will be
  628. // generated.
  629. ASSERT_NO_THROW(processCmdLine("perfdhcp -l 127.0.0.1 all"));
  630. testMacAddress();
  631. // Simulate 50 clients. Different MAC addresses will be generated.
  632. ASSERT_NO_THROW(processCmdLine("perfdhcp -l 127.0.0.1 -R 50 all"));
  633. testMacAddress();
  634. }
  635. TEST_F(TestControlTest, Options4) {
  636. using namespace isc::dhcp;
  637. NakedTestControl tc;
  638. // By default the IP version mode is V4 so there is no need to
  639. // parse command line to override the IP version. Note that
  640. // registerOptionFactories is used for both V4 and V6.
  641. tc.registerOptionFactories();
  642. // Create option with buffer size equal to 1 and holding DHCPDISCOVER
  643. // message type.
  644. OptionPtr opt_msg_type(Option::factory(Option::V4, DHO_DHCP_MESSAGE_TYPE,
  645. OptionBuffer(1, DHCPDISCOVER)));
  646. // Validate the option type and universe.
  647. EXPECT_EQ(Option::V4, opt_msg_type->getUniverse());
  648. EXPECT_EQ(DHO_DHCP_MESSAGE_TYPE, opt_msg_type->getType());
  649. // Validate the message type from the option we have now created.
  650. uint8_t msg_type = 0;
  651. ASSERT_NO_THROW(msg_type = opt_msg_type->getUint8());
  652. EXPECT_EQ(DHCPDISCOVER, msg_type);
  653. // Create another option: DHCP_PARAMETER_REQUEST_LIST
  654. OptionPtr
  655. opt_requested_options(Option::factory(Option::V4,
  656. DHO_DHCP_PARAMETER_REQUEST_LIST));
  657. // Here is a list of options that we are requesting in the
  658. // server's response.
  659. const uint8_t requested_options[] = {
  660. DHO_SUBNET_MASK,
  661. DHO_BROADCAST_ADDRESS,
  662. DHO_TIME_OFFSET,
  663. DHO_ROUTERS,
  664. DHO_DOMAIN_NAME,
  665. DHO_DOMAIN_NAME_SERVERS,
  666. DHO_HOST_NAME
  667. };
  668. OptionBuffer
  669. requested_options_ref(requested_options,
  670. requested_options + sizeof(requested_options));
  671. // Get the option buffer. It should hold the combination of values
  672. // listed in requested_options array. However their order can be
  673. // different in general so we need to search each value separatelly.
  674. const OptionBuffer& requested_options_buf =
  675. opt_requested_options->getData();
  676. EXPECT_EQ(requested_options_ref.size(), requested_options_buf.size());
  677. size_t matched_num = matchRequestedOptions(requested_options_ref,
  678. requested_options_buf);
  679. // We want exactly the same requested options as listed in
  680. // requested_options array - nothing more or less.
  681. EXPECT_EQ(requested_options_ref.size(), matched_num);
  682. }
  683. TEST_F(TestControlTest, Options6) {
  684. using namespace isc::dhcp;
  685. // Lets override the IP version to test V6 options (-6 parameter)
  686. ASSERT_NO_THROW(processCmdLine("perfdhcp -l 127.0.0.1 -6 all"));
  687. NakedTestControl tc;
  688. tc.registerOptionFactories();
  689. // Validate the D6O_ELAPSED_TIME option.
  690. OptionPtr opt_elapsed_time(Option::factory(Option::V6, D6O_ELAPSED_TIME));
  691. // Validate the option type and universe.
  692. EXPECT_EQ(Option::V6, opt_elapsed_time->getUniverse());
  693. EXPECT_EQ(D6O_ELAPSED_TIME, opt_elapsed_time->getType());
  694. // The default value of elapsed time is zero.
  695. uint16_t elapsed_time;
  696. ASSERT_NO_THROW(elapsed_time = opt_elapsed_time->getUint16());
  697. EXPECT_EQ(0, elapsed_time);
  698. // With the factory function we may also specify the actual
  699. // value of elapsed time. Let's make use of std::vector
  700. // constructor to create the option buffer, 2 octets long
  701. // with each octet initialized to 0x1.
  702. size_t elapsed_time_buf_size = 2;
  703. uint8_t elapsed_time_pattern = 0x1;
  704. OptionPtr
  705. opt_elapsed_time2(Option::factory(Option::V6, D6O_ELAPSED_TIME,
  706. OptionBuffer(elapsed_time_buf_size,
  707. elapsed_time_pattern)));
  708. // Any buffer that has size neither equal to 0 nor 2 is considered invalid.
  709. elapsed_time_buf_size = 1;
  710. EXPECT_THROW(
  711. Option::factory(Option::V6, D6O_ELAPSED_TIME,
  712. OptionBuffer(elapsed_time_buf_size, elapsed_time_pattern)),
  713. isc::BadValue
  714. );
  715. // Validate the option type and universe.
  716. EXPECT_EQ(Option::V6, opt_elapsed_time2->getUniverse());
  717. EXPECT_EQ(D6O_ELAPSED_TIME, opt_elapsed_time2->getType());
  718. // Make sure the getUint16 does not throw exception. It wile throw
  719. // buffer is shorter than 2 octets.
  720. ASSERT_NO_THROW(elapsed_time = opt_elapsed_time2->getUint16());
  721. // Check the expected value of elapsed time.
  722. EXPECT_EQ(0x0101, elapsed_time);
  723. // Validate the D6O_RAPID_COMMIT option.
  724. OptionPtr opt_rapid_commit(Option::factory(Option::V6, D6O_RAPID_COMMIT));
  725. // Validate the option type and universe.
  726. EXPECT_EQ(Option::V6, opt_rapid_commit->getUniverse());
  727. EXPECT_EQ(D6O_RAPID_COMMIT, opt_rapid_commit->getType());
  728. // Rapid commit has no data payload.
  729. EXPECT_THROW(opt_rapid_commit->getUint8(), isc::OutOfRange);
  730. // Validate the D6O_CLIENTID option.
  731. OptionBuffer duid(CommandOptions::instance().getDuidTemplate());
  732. OptionPtr opt_clientid(Option::factory(Option::V6, D6O_CLIENTID, duid));
  733. EXPECT_EQ(Option::V6, opt_clientid->getUniverse());
  734. EXPECT_EQ(D6O_CLIENTID, opt_clientid->getType());
  735. const OptionBuffer& duid2 = opt_clientid->getData();
  736. ASSERT_EQ(duid.size(), duid2.size());
  737. // The Duid we set for option is the same we get.
  738. EXPECT_TRUE(std::equal(duid.begin(), duid.end(), duid2.begin()));
  739. // Validate the D6O_ORO (Option Request Option).
  740. OptionPtr opt_oro(Option::factory(Option::V6, D6O_ORO));
  741. // Prepare the reference buffer with requested options.
  742. const uint8_t requested_options[] = {
  743. 0, D6O_NAME_SERVERS,
  744. 0, D6O_DOMAIN_SEARCH,
  745. };
  746. int requested_options_num =
  747. sizeof(requested_options) / sizeof(requested_options[0]);
  748. OptionBuffer
  749. requested_options_ref(requested_options,
  750. requested_options + sizeof(requested_options));
  751. // Get the buffer from option.
  752. const OptionBuffer& requested_options_buf = opt_oro->getData();
  753. // Size of reference buffer and option buffer have to be
  754. // the same for comparison.
  755. EXPECT_EQ(requested_options_ref.size(), requested_options_buf.size());
  756. // Check if all options in the buffer are matched with reference buffer.
  757. size_t matched_num = matchRequestedOptions6(requested_options_ref,
  758. requested_options_buf);
  759. EXPECT_EQ(requested_options_num, matched_num);
  760. // Validate the D6O_IA_NA option.
  761. OptionPtr opt_ia_na(Option::factory(Option::V6, D6O_IA_NA));
  762. EXPECT_EQ(Option::V6, opt_ia_na->getUniverse());
  763. EXPECT_EQ(D6O_IA_NA, opt_ia_na->getType());
  764. // Every IA_NA option is expected to start with this sequence.
  765. const uint8_t opt_ia_na_array[] = {
  766. 0, 0, 0, 1, // IAID = 1
  767. 0, 0, 3600 >> 8, 3600 & 0xff, // T1 = 3600
  768. 0, 0, 5400 >> 8, 5400 & 0xff, // T2 = 5400
  769. };
  770. OptionBuffer opt_ia_na_ref(opt_ia_na_array,
  771. opt_ia_na_array + sizeof(opt_ia_na_array));
  772. const OptionBuffer& opt_ia_na_buf = opt_ia_na->getData();
  773. ASSERT_EQ(opt_ia_na_buf.size(), opt_ia_na_ref.size());
  774. EXPECT_TRUE(std::equal(opt_ia_na_ref.begin(), opt_ia_na_ref.end(),
  775. opt_ia_na_buf.begin()));
  776. // @todo Add more tests for IA address options.
  777. }
  778. TEST_F(TestControlTest, Packet4) {
  779. // Use Interface Manager to get the local loopback interface.
  780. // If interface can't be found we don't want to fail test.
  781. std::string loopback_iface(getLocalLoopback());
  782. if (!loopback_iface.empty()) {
  783. ASSERT_NO_THROW(processCmdLine("perfdhcp -l " + loopback_iface +
  784. " -L 10547 all"));
  785. NakedTestControl tc;
  786. int sock_handle = 0;
  787. // We have to create the socket to setup some parameters of
  788. // outgoing packet.
  789. ASSERT_NO_THROW(sock_handle = tc.openSocket());
  790. TestControl::TestControlSocket sock(sock_handle);
  791. uint32_t transid = 123;
  792. boost::shared_ptr<Pkt4> pkt4(new Pkt4(DHCPDISCOVER, transid));
  793. // Set parameters on outgoing packet.
  794. ASSERT_NO_THROW(tc.setDefaults4(sock, pkt4));
  795. // Validate that packet has been setup correctly.
  796. EXPECT_EQ(loopback_iface, pkt4->getIface());
  797. EXPECT_EQ(sock.ifindex_, pkt4->getIndex());
  798. EXPECT_EQ(DHCP4_CLIENT_PORT, pkt4->getLocalPort());
  799. EXPECT_EQ(DHCP4_SERVER_PORT, pkt4->getRemotePort());
  800. EXPECT_EQ(1, pkt4->getHops());
  801. EXPECT_EQ(asiolink::IOAddress("255.255.255.255"),
  802. pkt4->getRemoteAddr());
  803. EXPECT_EQ(asiolink::IOAddress(sock.addr_), pkt4->getLocalAddr());
  804. EXPECT_EQ(asiolink::IOAddress(sock.addr_), pkt4->getGiaddr());
  805. } else {
  806. std::cout << "Unable to find the loopback interface. Skip test. "
  807. << std::endl;
  808. }
  809. }
  810. TEST_F(TestControlTest, Packet6) {
  811. // Use Interface Manager to get the local loopback interface.
  812. // If the interface can't be found we don't want to fail test.
  813. std::string loopback_iface(getLocalLoopback());
  814. if (!loopback_iface.empty()) {
  815. ASSERT_NO_THROW(processCmdLine("perfdhcp -6 -l " + loopback_iface +
  816. " -L 10547 servers"));
  817. NakedTestControl tc;
  818. int sock_handle = 0;
  819. // Create the socket. It will be needed to set packet's
  820. // parameters.
  821. ASSERT_NO_THROW(sock_handle = tc.openSocket());
  822. TestControl::TestControlSocket sock(sock_handle);
  823. uint32_t transid = 123;
  824. boost::shared_ptr<Pkt6> pkt6(new Pkt6(DHCPV6_SOLICIT, transid));
  825. // Set packet's parameters.
  826. ASSERT_NO_THROW(tc.setDefaults6(sock, pkt6));
  827. // Validate if parameters have been set correctly.
  828. EXPECT_EQ(loopback_iface, pkt6->getIface());
  829. EXPECT_EQ(sock.ifindex_, pkt6->getIndex());
  830. EXPECT_EQ(DHCP6_CLIENT_PORT, pkt6->getLocalPort());
  831. EXPECT_EQ(DHCP6_SERVER_PORT, pkt6->getRemotePort());
  832. EXPECT_EQ(sock.addr_, pkt6->getLocalAddr());
  833. EXPECT_EQ(asiolink::IOAddress("FF05::1:3"), pkt6->getRemoteAddr());
  834. } else {
  835. std::cout << "Unable to find the loopback interface. Skip test. "
  836. << std::endl;
  837. }
  838. }
  839. TEST_F(TestControlTest, Packet4Exchange) {
  840. // Get the local loopback interface to open socket on
  841. // it and test packets exchanges. We don't want to fail
  842. // the test if interface is not available.
  843. std::string loopback_iface(getLocalLoopback());
  844. if (loopback_iface.empty()) {
  845. std::cout << "Unable to find the loopback interface. Skip test."
  846. << std::endl;
  847. return;
  848. }
  849. // Set number of iterations to some high value.
  850. const int iterations_num = 100;
  851. processCmdLine("perfdhcp -l " + loopback_iface
  852. + " -r 100 -n 10 -R 20 -L 10547 127.0.0.1");
  853. // The actual number of iterations will be stored in the
  854. // following variable.
  855. int iterations_performed = 0;
  856. bool use_templates = false;
  857. testPkt4Exchange(iterations_num, iterations_num, use_templates, iterations_performed);
  858. // The command line restricts the number of iterations to 10
  859. // with -n 10 parameter.
  860. EXPECT_EQ(10, iterations_performed);
  861. // With the following command line we restrict the maximum
  862. // number of dropped packets to 20% of all.
  863. // Use templates for this test.
  864. processCmdLine("perfdhcp -l " + loopback_iface
  865. + " -r 100 -R 20 -n 20 -D 10% -L 10547"
  866. + " -T ../templates/discover-example.hex"
  867. + " -T ../templates/request4-example.hex"
  868. + " 127.0.0.1");
  869. // The number iterations is restricted by the percentage of
  870. // dropped packets (-D 10%). We also have to bump up the number
  871. // of iterations because the percentage limitation checks starts
  872. // at packet #10. We expect that at packet #12 the 10% threshold
  873. // will be reached.
  874. const int received_num = 10;
  875. use_templates = true;
  876. testPkt4Exchange(iterations_num, received_num, use_templates, iterations_performed);
  877. EXPECT_EQ(12, iterations_performed);
  878. }
  879. TEST_F(TestControlTest, Packet6Exchange) {
  880. // Get the local loopback interface to open socket on
  881. // it and test packets exchanges. We don't want to fail
  882. // the test if interface is not available.
  883. std::string loopback_iface(getLocalLoopback());
  884. if (loopback_iface.empty()) {
  885. std::cout << "Unable to find the loopback interface. Skip test."
  886. << std::endl;
  887. return;
  888. }
  889. const int iterations_num = 100;
  890. // Set number of iterations to 10.
  891. processCmdLine("perfdhcp -l " + loopback_iface
  892. + " -6 -r 100 -n 10 -R 20 -L 10547 ::1");
  893. int iterations_performed = 0;
  894. // Set number of received packets equal to number of iterations.
  895. // This simulates no packet drops.
  896. bool use_templates = false;
  897. testPkt6Exchange(iterations_num, iterations_num, use_templates,
  898. iterations_performed);
  899. // Actual number of iterations should be 10.
  900. EXPECT_EQ(10, iterations_performed);
  901. // The maximum number of dropped packets is 3 (because of -D 3).
  902. use_templates = true;
  903. processCmdLine("perfdhcp -l " + loopback_iface
  904. + " -6 -r 100 -n 10 -R 20 -D 3 -L 10547"
  905. + " -T ../templates/solicit-example.hex"
  906. + " -T ../templates/request6-example.hex ::1");
  907. // For the first 3 packets we are simulating responses from server.
  908. // For other packets we don't so packet as 4,5,6 will be dropped and
  909. // then test should be interrupted and actual number of iterations will
  910. // be 6.
  911. const int received_num = 3;
  912. testPkt6Exchange(iterations_num, received_num, use_templates,
  913. iterations_performed);
  914. EXPECT_EQ(6, iterations_performed);
  915. }
  916. TEST_F(TestControlTest, PacketTemplates) {
  917. std::vector<uint8_t> template1(256);
  918. std::string file1("../templates/test1.hex");
  919. std::vector<uint8_t> template2(233);
  920. std::string file2("../templates/test2.hex");
  921. for (int i = 0; i < template1.size(); ++i) {
  922. template1[i] = static_cast<uint8_t>(random() % 256);
  923. }
  924. for (int i = 0; i < template2.size(); ++i) {
  925. template2[i] = static_cast<uint8_t>(random() % 256);
  926. }
  927. // Size of the file is 2 times larger than binary data size.
  928. ASSERT_TRUE(createTemplateFile(file1, template1, template1.size() * 2));
  929. ASSERT_TRUE(createTemplateFile(file2, template2, template2.size() * 2));
  930. CommandOptions& options = CommandOptions::instance();
  931. NakedTestControl tc;
  932. ASSERT_NO_THROW(
  933. processCmdLine("perfdhcp -l 127.0.0.1"
  934. " -T " + file1 + " -T " + file2 + " all")
  935. );
  936. ASSERT_NO_THROW(tc.initPacketTemplates());
  937. TestControl::TemplateBuffer buf1;
  938. TestControl::TemplateBuffer buf2;
  939. ASSERT_NO_THROW(buf1 = tc.getTemplateBuffer(0));
  940. ASSERT_NO_THROW(buf2 = tc.getTemplateBuffer(1));
  941. ASSERT_EQ(template1.size(), buf1.size());
  942. ASSERT_EQ(template2.size(), buf2.size());
  943. EXPECT_TRUE(std::equal(template1.begin(), template1.end(), buf1.begin()));
  944. EXPECT_TRUE(std::equal(template2.begin(), template2.end(), buf2.begin()));
  945. // Try to read template file with odd number of digits.
  946. std::string file3("../templates/test3.hex");
  947. // Size of the file is 2 times larger than binary data size and it is always
  948. // even number. Substracting 1 makes file size odd.
  949. ASSERT_TRUE(createTemplateFile(file3, template1, template1.size() * 2 - 1));
  950. ASSERT_NO_THROW(
  951. processCmdLine("perfdhcp -l 127.0.0.1 -T " + file3 + " all")
  952. );
  953. EXPECT_THROW(tc.initPacketTemplates(), isc::OutOfRange);
  954. // Try to read empty file.
  955. std::string file4("../templates/test4.hex");
  956. ASSERT_TRUE(createTemplateFile(file4, template2, 0));
  957. ASSERT_NO_THROW(
  958. processCmdLine("perfdhcp -l 127.0.0.1 -T " + file4 + " all")
  959. );
  960. EXPECT_THROW(tc.initPacketTemplates(), isc::OutOfRange);
  961. // Try reading file with non hexadecimal characters.
  962. std::string file5("../templates/test5.hex");
  963. ASSERT_TRUE(createTemplateFile(file5, template1, template1.size() * 2, true));
  964. ASSERT_NO_THROW(
  965. processCmdLine("perfdhcp -l 127.0.0.1 -T " + file5 + " all")
  966. );
  967. EXPECT_THROW(tc.initPacketTemplates(), isc::BadValue);
  968. }
  969. TEST_F(TestControlTest, RateControl) {
  970. // We don't specify the exchange rate here so the aggressivity
  971. // value will determine how many packets are to be send each
  972. // time we query the getNextExchangesNum.
  973. ASSERT_NO_THROW(processCmdLine("perfdhcp -l 127.0.0.1 all"));
  974. CommandOptions& options = CommandOptions::instance();
  975. NakedTestControl tc1;
  976. uint64_t xchgs_num = tc1.getNextExchangesNum();
  977. EXPECT_EQ(options.getAggressivity(), xchgs_num);
  978. // The exchange rate is now 1 per second. We don't know how many
  979. // exchanges have to initiated exactly but for sure it has to be
  980. // non-zero value. Also, since aggressivity is very high we expect
  981. // that it will not be restricted by aggressivity.
  982. ASSERT_NO_THROW(
  983. processCmdLine("perfdhcp -l 127.0.0.1 -a 1000000 -r 1 all")
  984. );
  985. NakedTestControl tc2;
  986. xchgs_num = tc2.getNextExchangesNum();
  987. EXPECT_GT(xchgs_num, 0);
  988. EXPECT_LT(xchgs_num, options.getAggressivity());
  989. // @todo add more thorough checks for rate values.
  990. }