test_control_unittest.cc 46 KB

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