hooks_unittest.cc 61 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649
  1. // Copyright (C) 2015-2016 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this
  5. // file, You can obtain one at http://mozilla.org/MPL/2.0/.
  6. #include <config.h>
  7. #include <dhcp4/tests/dhcp4_test_utils.h>
  8. #include <dhcp4/tests/dhcp4_client.h>
  9. #include <dhcp4/json_config_parser.h>
  10. #include <cc/command_interpreter.h>
  11. #include <config/command_mgr.h>
  12. #include <hooks/server_hooks.h>
  13. #include <hooks/hooks_manager.h>
  14. #include <dhcpsrv/cfgmgr.h>
  15. #include <dhcp/tests/iface_mgr_test_config.h>
  16. #include <dhcp/option.h>
  17. #include <asiolink/io_address.h>
  18. #include <dhcp4/tests/marker_file.h>
  19. #include <dhcp4/tests/test_libraries.h>
  20. #include <vector>
  21. using namespace std;
  22. using namespace isc::asiolink;
  23. using namespace isc::data;
  24. using namespace isc::hooks;
  25. using namespace isc::config;
  26. using namespace isc::dhcp::test;
  27. using namespace isc::dhcp;
  28. // Checks if hooks are registered properly.
  29. TEST_F(Dhcpv4SrvTest, Hooks) {
  30. NakedDhcpv4Srv srv(0);
  31. // check if appropriate hooks are registered
  32. int hook_index_buffer4_receive = -1;
  33. int hook_index_pkt4_receive = -1;
  34. int hook_index_select_subnet = -1;
  35. int hook_index_lease4_release = -1;
  36. int hook_index_pkt4_send = -1;
  37. int hook_index_buffer4_send = -1;
  38. // check if appropriate indexes are set
  39. EXPECT_NO_THROW(hook_index_buffer4_receive = ServerHooks::getServerHooks()
  40. .getIndex("buffer4_receive"));
  41. EXPECT_NO_THROW(hook_index_pkt4_receive = ServerHooks::getServerHooks()
  42. .getIndex("pkt4_receive"));
  43. EXPECT_NO_THROW(hook_index_select_subnet = ServerHooks::getServerHooks()
  44. .getIndex("subnet4_select"));
  45. EXPECT_NO_THROW(hook_index_lease4_release = ServerHooks::getServerHooks()
  46. .getIndex("lease4_release"));
  47. EXPECT_NO_THROW(hook_index_pkt4_send = ServerHooks::getServerHooks()
  48. .getIndex("pkt4_send"));
  49. EXPECT_NO_THROW(hook_index_buffer4_send = ServerHooks::getServerHooks()
  50. .getIndex("buffer4_send"));
  51. EXPECT_TRUE(hook_index_buffer4_receive > 0);
  52. EXPECT_TRUE(hook_index_pkt4_receive > 0);
  53. EXPECT_TRUE(hook_index_select_subnet > 0);
  54. EXPECT_TRUE(hook_index_lease4_release > 0);
  55. EXPECT_TRUE(hook_index_pkt4_send > 0);
  56. EXPECT_TRUE(hook_index_buffer4_send > 0);
  57. }
  58. // A dummy MAC address, padded with 0s
  59. const uint8_t dummyChaddr[16] = {0, 1, 2, 3, 4, 5, 0, 0,
  60. 0, 0, 0, 0, 0, 0, 0, 0 };
  61. // Let's use some creative test content here (128 chars + \0)
  62. const uint8_t dummyFile[] = "Lorem ipsum dolor sit amet, consectetur "
  63. "adipiscing elit. Proin mollis placerat metus, at "
  64. "lacinia orci ornare vitae. Mauris amet.";
  65. // Yet another type of test content (64 chars + \0)
  66. const uint8_t dummySname[] = "Lorem ipsum dolor sit amet, consectetur "
  67. "adipiscing elit posuere.";
  68. /// @brief a class dedicated to Hooks testing in DHCPv4 server
  69. ///
  70. /// This class has a number of static members, because each non-static
  71. /// method has implicit 'this' parameter, so it does not match callout
  72. /// signature and couldn't be registered. Furthermore, static methods
  73. /// can't modify non-static members (for obvious reasons), so many
  74. /// fields are declared static. It is still better to keep them as
  75. /// one class rather than unrelated collection of global objects.
  76. class HooksDhcpv4SrvTest : public Dhcpv4SrvTest {
  77. public:
  78. /// @brief creates Dhcpv4Srv and prepares buffers for callouts
  79. HooksDhcpv4SrvTest() {
  80. // Allocate new DHCPv6 Server
  81. srv_ = new NakedDhcpv4Srv(0);
  82. // clear static buffers
  83. resetCalloutBuffers();
  84. }
  85. /// @brief destructor (deletes Dhcpv4Srv)
  86. virtual ~HooksDhcpv4SrvTest() {
  87. HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("buffer4_receive");
  88. HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("buffer4_send");
  89. HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("pkt4_receive");
  90. HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("pkt4_send");
  91. HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("subnet4_select");
  92. HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("lease4_renew");
  93. HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("lease4_release");
  94. HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("lease4_decline");
  95. delete srv_;
  96. }
  97. /// @brief creates an option with specified option code
  98. ///
  99. /// This method is static, because it is used from callouts
  100. /// that do not have a pointer to HooksDhcpv4SSrvTest object
  101. ///
  102. /// @param option_code code of option to be created
  103. ///
  104. /// @return pointer to create option object
  105. static OptionPtr createOption(uint16_t option_code) {
  106. char payload[] = {
  107. 0xa, 0xb, 0xc, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14
  108. };
  109. OptionBuffer tmp(payload, payload + sizeof(payload));
  110. return OptionPtr(new Option(Option::V4, option_code, tmp));
  111. }
  112. /// @brief Generates test packet.
  113. ///
  114. /// Allocates and generates on-wire buffer that represents test packet, with all
  115. /// fixed fields set to non-zero values. Content is not always reasonable.
  116. ///
  117. /// See generateTestPacket1() function that returns exactly the same packet as
  118. /// Pkt4 object.
  119. ///
  120. /// @return pointer to allocated Pkt4 object
  121. // Returns a vector containing a DHCPv4 packet header.
  122. Pkt4Ptr
  123. generateSimpleDiscover() {
  124. // That is only part of the header. It contains all "short" fields,
  125. // larger fields are constructed separately.
  126. uint8_t hdr[] = {
  127. 1, 6, 6, 13, // op, htype, hlen, hops,
  128. 0x12, 0x34, 0x56, 0x78, // transaction-id
  129. 0, 42, 0x80, 0x00, // 42 secs, BROADCAST flags
  130. 192, 0, 2, 1, // ciaddr
  131. 1, 2, 3, 4, // yiaddr
  132. 192, 0, 2, 255, // siaddr
  133. 192, 0, 2, 50, // giaddr
  134. };
  135. // Initialize the vector with the header fields defined above.
  136. vector<uint8_t> buf(hdr, hdr + sizeof(hdr));
  137. // Append the large header fields.
  138. copy(dummyChaddr, dummyChaddr + Pkt4::MAX_CHADDR_LEN, back_inserter(buf));
  139. copy(dummySname, dummySname + Pkt4::MAX_SNAME_LEN, back_inserter(buf));
  140. copy(dummyFile, dummyFile + Pkt4::MAX_FILE_LEN, back_inserter(buf));
  141. // Should now have all the header, so check. The "static_cast" is used
  142. // to get round an odd bug whereby the linker appears not to find the
  143. // definition of DHCPV4_PKT_HDR_LEN if it appears within an EXPECT_EQ().
  144. EXPECT_EQ(static_cast<size_t>(Pkt4::DHCPV4_PKT_HDR_LEN), buf.size());
  145. // Add magic cookie
  146. buf.push_back(0x63);
  147. buf.push_back(0x82);
  148. buf.push_back(0x53);
  149. buf.push_back(0x63);
  150. // Add message type DISCOVER
  151. buf.push_back(static_cast<uint8_t>(DHO_DHCP_MESSAGE_TYPE));
  152. buf.push_back(1); // length (just one byte)
  153. buf.push_back(static_cast<uint8_t>(DHCPDISCOVER));
  154. Pkt4Ptr dis(new Pkt4(&buf[0], buf.size()));
  155. // Interface must be selected for a Discover. Server will use the interface
  156. // name to select a subnet for a client. This test is using fake interfaces
  157. // and the fake eth0 interface has IPv4 address matching the subnet
  158. // currently configured for this test.
  159. dis->setIface("eth1");
  160. return (dis);
  161. }
  162. /// Test callback that stores received callout name and pkt4 value
  163. /// @param callout_handle handle passed by the hooks framework
  164. /// @return always 0
  165. static int
  166. buffer4_receive_callout(CalloutHandle& callout_handle) {
  167. callback_name_ = string("buffer4_receive");
  168. callout_handle.getArgument("query4", callback_pkt4_);
  169. callback_argument_names_ = callout_handle.getArgumentNames();
  170. return (0);
  171. }
  172. /// Test callback that changes hwaddr value
  173. /// @param callout_handle handle passed by the hooks framework
  174. /// @return always 0
  175. static int
  176. buffer4_receive_change_hwaddr(CalloutHandle& callout_handle) {
  177. Pkt4Ptr pkt;
  178. callout_handle.getArgument("query4", pkt);
  179. // If there is at least one option with data
  180. if (pkt->data_.size() >= Pkt4::DHCPV4_PKT_HDR_LEN) {
  181. // Offset of the first byte of the CHWADDR field. Let's the first
  182. // byte to some new value that we could later check
  183. pkt->data_[28] = 0xff;
  184. }
  185. // Carry on as usual
  186. return buffer4_receive_callout(callout_handle);
  187. }
  188. /// Test callback that sets skip flag
  189. /// @param callout_handle handle passed by the hooks framework
  190. /// @return always 0
  191. static int
  192. buffer4_receive_skip(CalloutHandle& callout_handle) {
  193. callout_handle.setStatus(CalloutHandle::NEXT_STEP_SKIP);
  194. // Carry on as usual
  195. return buffer4_receive_callout(callout_handle);
  196. }
  197. /// test callback that stores received callout name and pkt4 value
  198. /// @param callout_handle handle passed by the hooks framework
  199. /// @return always 0
  200. static int
  201. pkt4_receive_callout(CalloutHandle& callout_handle) {
  202. callback_name_ = string("pkt4_receive");
  203. callout_handle.getArgument("query4", callback_pkt4_);
  204. callback_argument_names_ = callout_handle.getArgumentNames();
  205. return (0);
  206. }
  207. /// test callback that changes client-id value
  208. /// @param callout_handle handle passed by the hooks framework
  209. /// @return always 0
  210. static int
  211. pkt4_receive_change_clientid(CalloutHandle& callout_handle) {
  212. Pkt4Ptr pkt;
  213. callout_handle.getArgument("query4", pkt);
  214. // get rid of the old client-id
  215. pkt->delOption(DHO_DHCP_CLIENT_IDENTIFIER);
  216. // add a new option
  217. pkt->addOption(createOption(DHO_DHCP_CLIENT_IDENTIFIER));
  218. // carry on as usual
  219. return pkt4_receive_callout(callout_handle);
  220. }
  221. /// test callback that deletes client-id
  222. /// @param callout_handle handle passed by the hooks framework
  223. /// @return always 0
  224. static int
  225. pkt4_receive_delete_clientid(CalloutHandle& callout_handle) {
  226. Pkt4Ptr pkt;
  227. callout_handle.getArgument("query4", pkt);
  228. // get rid of the old client-id (and no HWADDR)
  229. vector<uint8_t> mac;
  230. pkt->delOption(DHO_DHCP_CLIENT_IDENTIFIER);
  231. pkt->setHWAddr(1, 0, mac); // HWtype 1, hardware len = 0
  232. // carry on as usual
  233. return pkt4_receive_callout(callout_handle);
  234. }
  235. /// test callback that sets skip flag
  236. /// @param callout_handle handle passed by the hooks framework
  237. /// @return always 0
  238. static int
  239. pkt4_receive_skip(CalloutHandle& callout_handle) {
  240. Pkt4Ptr pkt;
  241. callout_handle.getArgument("query4", pkt);
  242. callout_handle.setStatus(CalloutHandle::NEXT_STEP_SKIP);
  243. // carry on as usual
  244. return pkt4_receive_callout(callout_handle);
  245. }
  246. /// Test callback that stores received callout name and pkt4 value
  247. /// @param callout_handle handle passed by the hooks framework
  248. /// @return always 0
  249. static int
  250. pkt4_send_callout(CalloutHandle& callout_handle) {
  251. callback_name_ = string("pkt4_send");
  252. callout_handle.getArgument("response4", callback_pkt4_);
  253. callout_handle.getArgument("query4", callback_pkt4_query_);
  254. callback_argument_names_ = callout_handle.getArgumentNames();
  255. return (0);
  256. }
  257. // Test callback that changes server-id
  258. /// @param callout_handle handle passed by the hooks framework
  259. /// @return always 0
  260. static int
  261. pkt4_send_change_serverid(CalloutHandle& callout_handle) {
  262. Pkt4Ptr pkt;
  263. callout_handle.getArgument("response4", pkt);
  264. // get rid of the old server-id
  265. pkt->delOption(DHO_DHCP_SERVER_IDENTIFIER);
  266. // add a new option
  267. pkt->addOption(createOption(DHO_DHCP_SERVER_IDENTIFIER));
  268. // carry on as usual
  269. return pkt4_send_callout(callout_handle);
  270. }
  271. /// test callback that deletes server-id
  272. /// @param callout_handle handle passed by the hooks framework
  273. /// @return always 0
  274. static int
  275. pkt4_send_delete_serverid(CalloutHandle& callout_handle) {
  276. Pkt4Ptr pkt;
  277. callout_handle.getArgument("response4", pkt);
  278. // get rid of the old client-id
  279. pkt->delOption(DHO_DHCP_SERVER_IDENTIFIER);
  280. // carry on as usual
  281. return pkt4_send_callout(callout_handle);
  282. }
  283. /// Test callback that sets skip flag
  284. /// @param callout_handle handle passed by the hooks framework
  285. /// @return always 0
  286. static int
  287. pkt4_send_skip(CalloutHandle& callout_handle) {
  288. Pkt4Ptr pkt;
  289. callout_handle.getArgument("response4", pkt);
  290. callout_handle.setStatus(CalloutHandle::NEXT_STEP_SKIP);
  291. // carry on as usual
  292. return pkt4_send_callout(callout_handle);
  293. }
  294. /// Test callback that stores received callout name and pkt4 value
  295. /// @param callout_handle handle passed by the hooks framework
  296. /// @return always 0
  297. static int
  298. buffer4_send_callout(CalloutHandle& callout_handle) {
  299. callback_name_ = string("buffer4_send");
  300. callout_handle.getArgument("response4", callback_pkt4_);
  301. callback_argument_names_ = callout_handle.getArgumentNames();
  302. return (0);
  303. }
  304. /// Test callback changes the output buffer to a hardcoded value
  305. /// @param callout_handle handle passed by the hooks framework
  306. /// @return always 0
  307. static int
  308. buffer4_send_change_callout(CalloutHandle& callout_handle) {
  309. Pkt4Ptr pkt;
  310. callout_handle.getArgument("response4", pkt);
  311. // modify buffer to set a different payload
  312. pkt->getBuffer().clear();
  313. pkt->getBuffer().writeData(dummyFile, sizeof(dummyFile));
  314. return (0);
  315. }
  316. /// Test callback that stores received callout name and pkt4 value
  317. /// @param callout_handle handle passed by the hooks framework
  318. /// @return always 0
  319. static int
  320. skip_callout(CalloutHandle& callout_handle) {
  321. callout_handle.setStatus(CalloutHandle::NEXT_STEP_SKIP);
  322. return (0);
  323. }
  324. /// Test callback that stores received callout name and subnet4 values
  325. /// @param callout_handle handle passed by the hooks framework
  326. /// @return always 0
  327. static int
  328. subnet4_select_callout(CalloutHandle& callout_handle) {
  329. callback_name_ = string("subnet4_select");
  330. callout_handle.getArgument("query4", callback_pkt4_);
  331. callout_handle.getArgument("subnet4", callback_subnet4_);
  332. callout_handle.getArgument("subnet4collection", callback_subnet4collection_);
  333. callback_argument_names_ = callout_handle.getArgumentNames();
  334. return (0);
  335. }
  336. /// Test callback that picks the other subnet if possible.
  337. /// @param callout_handle handle passed by the hooks framework
  338. /// @return always 0
  339. static int
  340. subnet4_select_different_subnet_callout(CalloutHandle& callout_handle) {
  341. // Call the basic callout to record all passed values
  342. subnet4_select_callout(callout_handle);
  343. const Subnet4Collection* subnets;
  344. Subnet4Ptr subnet;
  345. callout_handle.getArgument("subnet4", subnet);
  346. callout_handle.getArgument("subnet4collection", subnets);
  347. // Let's change to a different subnet
  348. if (subnets->size() > 1) {
  349. subnet = (*subnets)[1]; // Let's pick the other subnet
  350. callout_handle.setArgument("subnet4", subnet);
  351. }
  352. return (0);
  353. }
  354. /// Test callback that stores received callout name passed parameters
  355. /// @param callout_handle handle passed by the hooks framework
  356. /// @return always 0
  357. static int
  358. lease4_release_callout(CalloutHandle& callout_handle) {
  359. callback_name_ = string("lease4_release");
  360. callout_handle.getArgument("query4", callback_pkt4_);
  361. callout_handle.getArgument("lease4", callback_lease4_);
  362. callback_argument_names_ = callout_handle.getArgumentNames();
  363. return (0);
  364. }
  365. /// Test callback that stores received callout name and subnet4 values
  366. /// @param callout_handle handle passed by the hooks framework
  367. /// @return always 0
  368. static int
  369. lease4_renew_callout(CalloutHandle& callout_handle) {
  370. callback_name_ = string("lease4_renew");
  371. callout_handle.getArgument("subnet4", callback_subnet4_);
  372. callout_handle.getArgument("lease4", callback_lease4_);
  373. callout_handle.getArgument("hwaddr", callback_hwaddr_);
  374. callout_handle.getArgument("clientid", callback_clientid_);
  375. callback_argument_names_ = callout_handle.getArgumentNames();
  376. return (0);
  377. }
  378. /// Test lease4_decline callback that stores received parameters.
  379. ///
  380. /// @param callout_handle handle passed by the hooks framework
  381. /// @return always 0
  382. static int
  383. lease4_decline_callout(CalloutHandle& callout_handle) {
  384. callback_name_ = string("lease4_decline");
  385. callout_handle.getArgument("query4", callback_pkt4_);
  386. callout_handle.getArgument("lease4", callback_lease4_);
  387. return (0);
  388. }
  389. /// Test lease4_decline callback that sets next step to DROP.
  390. ///
  391. /// @param callout_handle handle passed by the hooks framework
  392. /// @return always 0
  393. static int
  394. lease4_decline_drop_callout(CalloutHandle& callout_handle) {
  395. callout_handle.setStatus(CalloutHandle::NEXT_STEP_DROP);
  396. return (lease4_decline_callout(callout_handle));
  397. }
  398. /// resets buffers used to store data received by callouts
  399. void resetCalloutBuffers() {
  400. callback_name_ = string("");
  401. callback_pkt4_.reset();
  402. callback_pkt4_query_.reset();
  403. callback_lease4_.reset();
  404. callback_hwaddr_.reset();
  405. callback_clientid_.reset();
  406. callback_subnet4_.reset();
  407. callback_subnet4collection_ = NULL;
  408. callback_argument_names_.clear();
  409. }
  410. /// pointer to Dhcpv4Srv that is used in tests
  411. NakedDhcpv4Srv* srv_;
  412. // The following fields are used in testing pkt4_receive_callout
  413. /// String name of the received callout
  414. static string callback_name_;
  415. /// Pkt4 structure returned in the callout
  416. static Pkt4Ptr callback_pkt4_;
  417. /// @brief Pkt4 structure returned in the callout
  418. ///
  419. /// pkt4_send hook now passes both the query and the response,
  420. /// so we actually need two fields.
  421. static Pkt4Ptr callback_pkt4_query_;
  422. /// Lease4 structure returned in the callout
  423. static Lease4Ptr callback_lease4_;
  424. /// Hardware address returned in the callout
  425. static HWAddrPtr callback_hwaddr_;
  426. /// Client-id returned in the callout
  427. static ClientIdPtr callback_clientid_;
  428. /// Pointer to a subnet received by callout
  429. static Subnet4Ptr callback_subnet4_;
  430. /// A list of all available subnets (received by callout)
  431. static const Subnet4Collection* callback_subnet4collection_;
  432. /// A list of all received arguments
  433. static vector<string> callback_argument_names_;
  434. };
  435. // The following fields are used in testing pkt4_receive_callout.
  436. // See fields description in the class for details
  437. string HooksDhcpv4SrvTest::callback_name_;
  438. Pkt4Ptr HooksDhcpv4SrvTest::callback_pkt4_;
  439. Pkt4Ptr HooksDhcpv4SrvTest::callback_pkt4_query_;
  440. Subnet4Ptr HooksDhcpv4SrvTest::callback_subnet4_;
  441. HWAddrPtr HooksDhcpv4SrvTest::callback_hwaddr_;
  442. ClientIdPtr HooksDhcpv4SrvTest::callback_clientid_;
  443. Lease4Ptr HooksDhcpv4SrvTest::callback_lease4_;
  444. const Subnet4Collection* HooksDhcpv4SrvTest::callback_subnet4collection_;
  445. vector<string> HooksDhcpv4SrvTest::callback_argument_names_;
  446. /// @brief Fixture class used to do basic library load/unload tests
  447. class LoadUnloadDhcpv4SrvTest : public ::testing::Test {
  448. public:
  449. /// @brief Pointer to the tested server object
  450. boost::shared_ptr<NakedDhcpv4Srv> server_;
  451. LoadUnloadDhcpv4SrvTest() {
  452. reset();
  453. }
  454. /// @brief Destructor
  455. ~LoadUnloadDhcpv4SrvTest() {
  456. server_.reset();
  457. reset();
  458. };
  459. /// @brief Reset hooks data
  460. ///
  461. /// Resets the data for the hooks-related portion of the test by ensuring
  462. /// that no libraries are loaded and that any marker files are deleted.
  463. void reset() {
  464. // Unload any previously-loaded libraries.
  465. HooksManager::unloadLibraries();
  466. // Get rid of any marker files.
  467. static_cast<void>(remove(LOAD_MARKER_FILE));
  468. static_cast<void>(remove(UNLOAD_MARKER_FILE));
  469. CfgMgr::instance().clear();
  470. }
  471. };
  472. // Checks if callouts installed on pkt4_receive are indeed called and the
  473. // all necessary parameters are passed.
  474. //
  475. // Note that the test name does not follow test naming convention,
  476. // but the proper hook name is "buffer4_receive".
  477. TEST_F(HooksDhcpv4SrvTest, Buffer4ReceiveSimple) {
  478. IfaceMgrTestConfig test_config(true);
  479. IfaceMgr::instance().openSockets4();
  480. // Install pkt4_receive_callout
  481. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  482. "buffer4_receive", buffer4_receive_callout));
  483. // Let's create a simple DISCOVER
  484. Pkt4Ptr dis = generateSimpleDiscover();
  485. // Simulate that we have received that traffic
  486. srv_->fakeReceive(dis);
  487. // Server will now process to run its normal loop, but instead of calling
  488. // IfaceMgr::receive4(), it will read all packets from the list set by
  489. // fakeReceive()
  490. // In particular, it should call registered buffer4_receive callback.
  491. srv_->run();
  492. // Check that the callback called is indeed the one we installed
  493. EXPECT_EQ("buffer4_receive", callback_name_);
  494. // Check that pkt4 argument passing was successful and returned proper value
  495. EXPECT_TRUE(callback_pkt4_.get() == dis.get());
  496. // Check that all expected parameters are there
  497. vector<string> expected_argument_names;
  498. expected_argument_names.push_back(string("query4"));
  499. EXPECT_TRUE(expected_argument_names == callback_argument_names_);
  500. }
  501. // Checks if callouts installed on buffer4_receive is able to change
  502. // the values and the parameters are indeed used by the server.
  503. TEST_F(HooksDhcpv4SrvTest, buffer4ReceiveValueChange) {
  504. IfaceMgrTestConfig test_config(true);
  505. IfaceMgr::instance().openSockets4();
  506. // Install callback that modifies MAC addr of incoming packet
  507. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  508. "buffer4_receive", buffer4_receive_change_hwaddr));
  509. // Let's create a simple DISCOVER
  510. Pkt4Ptr discover = generateSimpleDiscover();
  511. // Simulate that we have received that traffic
  512. srv_->fakeReceive(discover);
  513. // Server will now process to run its normal loop, but instead of calling
  514. // IfaceMgr::receive6(), it will read all packets from the list set by
  515. // fakeReceive()
  516. // In particular, it should call registered buffer4_receive callback.
  517. srv_->run();
  518. // Check that the server did send a response
  519. ASSERT_EQ(1, srv_->fake_sent_.size());
  520. // Make sure that we received a response
  521. Pkt4Ptr offer = srv_->fake_sent_.front();
  522. ASSERT_TRUE(offer);
  523. // Get client-id...
  524. HWAddrPtr hwaddr = offer->getHWAddr();
  525. ASSERT_TRUE(hwaddr); // basic sanity check. HWAddr is always present
  526. // ... and check if it is the modified value
  527. ASSERT_FALSE(hwaddr->hwaddr_.empty()); // there must be a MAC address
  528. EXPECT_EQ(0xff, hwaddr->hwaddr_[0]); // check that its first byte was modified
  529. }
  530. // Checks if callouts installed on buffer4_receive is able to set skip flag that
  531. // will cause the server to not parse the packet. Even though the packet is valid,
  532. // the server should eventually drop it, because there won't be mandatory options
  533. // (or rather option objects) in it.
  534. TEST_F(HooksDhcpv4SrvTest, buffer4ReceiveSkip) {
  535. IfaceMgrTestConfig test_config(true);
  536. IfaceMgr::instance().openSockets4();
  537. // Install pkt4_receive_callout
  538. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  539. "buffer4_receive", buffer4_receive_skip));
  540. // Let's create a simple DISCOVER
  541. Pkt4Ptr discover = generateSimpleDiscover();
  542. // Simulate that we have received that traffic
  543. srv_->fakeReceive(discover);
  544. // Server will now process to run its normal loop, but instead of calling
  545. // IfaceMgr::receive6(), it will read all packets from the list set by
  546. // fakeReceive()
  547. // In particular, it should call registered pkt4_receive callback.
  548. srv_->run();
  549. // Check that the server dropped the packet and did not produce any response
  550. ASSERT_EQ(0, srv_->fake_sent_.size());
  551. }
  552. // Checks if callouts installed on pkt4_receive are indeed called and the
  553. // all necessary parameters are passed.
  554. //
  555. // Note that the test name does not follow test naming convention,
  556. // but the proper hook name is "pkt4_receive".
  557. TEST_F(HooksDhcpv4SrvTest, pkt4ReceiveSimple) {
  558. IfaceMgrTestConfig test_config(true);
  559. IfaceMgr::instance().openSockets4();
  560. // Install pkt4_receive_callout
  561. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  562. "pkt4_receive", pkt4_receive_callout));
  563. // Let's create a simple DISCOVER
  564. Pkt4Ptr sol = generateSimpleDiscover();
  565. // Simulate that we have received that traffic
  566. srv_->fakeReceive(sol);
  567. // Server will now process to run its normal loop, but instead of calling
  568. // IfaceMgr::receive4(), it will read all packets from the list set by
  569. // fakeReceive()
  570. // In particular, it should call registered pkt4_receive callback.
  571. srv_->run();
  572. // check that the callback called is indeed the one we installed
  573. EXPECT_EQ("pkt4_receive", callback_name_);
  574. // check that pkt4 argument passing was successful and returned proper value
  575. EXPECT_TRUE(callback_pkt4_.get() == sol.get());
  576. // Check that all expected parameters are there
  577. vector<string> expected_argument_names;
  578. expected_argument_names.push_back(string("query4"));
  579. EXPECT_TRUE(expected_argument_names == callback_argument_names_);
  580. }
  581. // Checks if callouts installed on pkt4_received is able to change
  582. // the values and the parameters are indeed used by the server.
  583. TEST_F(HooksDhcpv4SrvTest, valueChange_pkt4_receive) {
  584. IfaceMgrTestConfig test_config(true);
  585. IfaceMgr::instance().openSockets4();
  586. // Install pkt4_receive_callout
  587. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  588. "pkt4_receive", pkt4_receive_change_clientid));
  589. // Let's create a simple DISCOVER
  590. Pkt4Ptr sol = generateSimpleDiscover();
  591. // Simulate that we have received that traffic
  592. srv_->fakeReceive(sol);
  593. // Server will now process to run its normal loop, but instead of calling
  594. // IfaceMgr::receive4(), it will read all packets from the list set by
  595. // fakeReceive()
  596. // In particular, it should call registered pkt4_receive callback.
  597. srv_->run();
  598. // check that the server did send a response
  599. ASSERT_EQ(1, srv_->fake_sent_.size());
  600. // Make sure that we received a response
  601. Pkt4Ptr adv = srv_->fake_sent_.front();
  602. ASSERT_TRUE(adv);
  603. // Get client-id...
  604. OptionPtr clientid = adv->getOption(DHO_DHCP_CLIENT_IDENTIFIER);
  605. // ... and check if it is the modified value
  606. OptionPtr expected = createOption(DHO_DHCP_CLIENT_IDENTIFIER);
  607. EXPECT_TRUE(clientid->equals(expected));
  608. }
  609. // Checks if callouts installed on pkt4_received is able to delete
  610. // existing options and that change impacts server processing (mandatory
  611. // client-id option is deleted, so the packet is expected to be dropped)
  612. TEST_F(HooksDhcpv4SrvTest, pkt4ReceiveDeleteClientId) {
  613. IfaceMgrTestConfig test_config(true);
  614. IfaceMgr::instance().openSockets4();
  615. // Install pkt4_receive_callout
  616. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  617. "pkt4_receive", pkt4_receive_delete_clientid));
  618. // Let's create a simple DISCOVER
  619. Pkt4Ptr sol = generateSimpleDiscover();
  620. // Simulate that we have received that traffic
  621. srv_->fakeReceive(sol);
  622. // Server will now process to run its normal loop, but instead of calling
  623. // IfaceMgr::receive4(), it will read all packets from the list set by
  624. // fakeReceive()
  625. // In particular, it should call registered pkt4_receive callback.
  626. srv_->run();
  627. // Check that the server dropped the packet and did not send a response
  628. ASSERT_EQ(0, srv_->fake_sent_.size());
  629. }
  630. // Checks if callouts installed on pkt4_received is able to set skip flag that
  631. // will cause the server to not process the packet (drop), even though it is valid.
  632. TEST_F(HooksDhcpv4SrvTest, pkt4ReceiveSkip) {
  633. IfaceMgrTestConfig test_config(true);
  634. IfaceMgr::instance().openSockets4();
  635. // Install pkt4_receive_callout
  636. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  637. "pkt4_receive", pkt4_receive_skip));
  638. // Let's create a simple DISCOVER
  639. Pkt4Ptr sol = generateSimpleDiscover();
  640. // Simulate that we have received that traffic
  641. srv_->fakeReceive(sol);
  642. // Server will now process to run its normal loop, but instead of calling
  643. // IfaceMgr::receive4(), it will read all packets from the list set by
  644. // fakeReceive()
  645. // In particular, it should call registered pkt4_receive callback.
  646. srv_->run();
  647. // check that the server dropped the packet and did not produce any response
  648. ASSERT_EQ(0, srv_->fake_sent_.size());
  649. }
  650. // Checks if callouts installed on pkt4_send are indeed called and the
  651. // all necessary parameters are passed.
  652. TEST_F(HooksDhcpv4SrvTest, pkt4SendSimple) {
  653. IfaceMgrTestConfig test_config(true);
  654. IfaceMgr::instance().openSockets4();
  655. // Install pkt4_receive_callout
  656. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  657. "pkt4_send", pkt4_send_callout));
  658. // Let's create a simple DISCOVER
  659. Pkt4Ptr sol = generateSimpleDiscover();
  660. // Simulate that we have received that traffic
  661. srv_->fakeReceive(sol);
  662. // Server will now process to run its normal loop, but instead of calling
  663. // IfaceMgr::receive4(), it will read all packets from the list set by
  664. // fakeReceive()
  665. // In particular, it should call registered pkt4_receive callback.
  666. srv_->run();
  667. // Check that the callback called is indeed the one we installed
  668. EXPECT_EQ("pkt4_send", callback_name_);
  669. // Check that there is one packet sent
  670. ASSERT_EQ(1, srv_->fake_sent_.size());
  671. Pkt4Ptr adv = srv_->fake_sent_.front();
  672. // Check that pkt4 argument passing was successful and returned proper value
  673. ASSERT_TRUE(callback_pkt4_);
  674. EXPECT_TRUE(callback_pkt4_.get() == adv.get());
  675. // That that the query4 argument was correctly set to the Discover we sent.
  676. ASSERT_TRUE(callback_pkt4_query_);
  677. EXPECT_TRUE(callback_pkt4_query_.get() == sol.get());
  678. // Check that all expected parameters are there
  679. vector<string> expected_argument_names;
  680. expected_argument_names.push_back(string("response4"));
  681. expected_argument_names.push_back(string("query4"));
  682. sort(callback_argument_names_.begin(), callback_argument_names_.end());
  683. sort(expected_argument_names.begin(), expected_argument_names.end());
  684. EXPECT_TRUE(expected_argument_names == callback_argument_names_);
  685. }
  686. // Checks if callouts installed on pkt4_send is able to change
  687. // the values and the packet sent contains those changes
  688. TEST_F(HooksDhcpv4SrvTest, pkt4SendValueChange) {
  689. IfaceMgrTestConfig test_config(true);
  690. IfaceMgr::instance().openSockets4();
  691. // Install pkt4_receive_callout
  692. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  693. "pkt4_send", pkt4_send_change_serverid));
  694. // Let's create a simple DISCOVER
  695. Pkt4Ptr sol = generateSimpleDiscover();
  696. // Simulate that we have received that traffic
  697. srv_->fakeReceive(sol);
  698. // Server will now process to run its normal loop, but instead of calling
  699. // IfaceMgr::receive4(), it will read all packets from the list set by
  700. // fakeReceive()
  701. // In particular, it should call registered pkt4_receive callback.
  702. srv_->run();
  703. // check that the server did send a response
  704. ASSERT_EQ(1, srv_->fake_sent_.size());
  705. // Make sure that we received a response
  706. Pkt4Ptr adv = srv_->fake_sent_.front();
  707. ASSERT_TRUE(adv);
  708. // Get client-id...
  709. OptionPtr clientid = adv->getOption(DHO_DHCP_SERVER_IDENTIFIER);
  710. // ... and check if it is the modified value
  711. OptionPtr expected = createOption(DHO_DHCP_SERVER_IDENTIFIER);
  712. EXPECT_TRUE(clientid->equals(expected));
  713. }
  714. // Checks if callouts installed on pkt4_send is able to delete
  715. // existing options and that server applies those changes. In particular,
  716. // we are trying to send a packet without server-id. The packet should
  717. // be sent
  718. TEST_F(HooksDhcpv4SrvTest, pkt4SendDeleteServerId) {
  719. IfaceMgrTestConfig test_config(true);
  720. IfaceMgr::instance().openSockets4();
  721. // Install pkt4_receive_callout
  722. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  723. "pkt4_send", pkt4_send_delete_serverid));
  724. // Let's create a simple DISCOVER
  725. Pkt4Ptr sol = generateSimpleDiscover();
  726. // Simulate that we have received that traffic
  727. srv_->fakeReceive(sol);
  728. // Server will now process to run its normal loop, but instead of calling
  729. // IfaceMgr::receive4(), it will read all packets from the list set by
  730. // fakeReceive()
  731. // In particular, it should call registered pkt4_receive callback.
  732. srv_->run();
  733. // Check that the server indeed sent a malformed ADVERTISE
  734. ASSERT_EQ(1, srv_->fake_sent_.size());
  735. // Get that ADVERTISE
  736. Pkt4Ptr adv = srv_->fake_sent_.front();
  737. ASSERT_TRUE(adv);
  738. // Make sure that it does not have server-id
  739. EXPECT_FALSE(adv->getOption(DHO_DHCP_SERVER_IDENTIFIER));
  740. }
  741. // Checks if callouts installed on pkt4_skip is able to set skip flag that
  742. // will cause the server to not process the packet (drop), even though it is valid.
  743. TEST_F(HooksDhcpv4SrvTest, skip_pkt4_send) {
  744. IfaceMgrTestConfig test_config(true);
  745. IfaceMgr::instance().openSockets4();
  746. // Install pkt4_receive_callout
  747. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  748. "pkt4_send", pkt4_send_skip));
  749. // Let's create a simple REQUEST
  750. Pkt4Ptr sol = generateSimpleDiscover();
  751. // Simulate that we have received that traffic
  752. srv_->fakeReceive(sol);
  753. // Server will now process to run its normal loop, but instead of calling
  754. // IfaceMgr::receive4(), it will read all packets from the list set by
  755. // fakeReceive()
  756. // In particular, it should call registered pkt4_send callback.
  757. srv_->run();
  758. // Check that the server sent the message
  759. ASSERT_EQ(1, srv_->fake_sent_.size());
  760. // Get the first packet and check that it has zero length (i.e. the server
  761. // did not do packing on its own)
  762. Pkt4Ptr sent = srv_->fake_sent_.front();
  763. EXPECT_EQ(0, sent->getBuffer().getLength());
  764. }
  765. // Checks if callouts installed on buffer4_send are indeed called and the
  766. // all necessary parameters are passed.
  767. TEST_F(HooksDhcpv4SrvTest, buffer4SendSimple) {
  768. IfaceMgrTestConfig test_config(true);
  769. IfaceMgr::instance().openSockets4();
  770. // Install pkt4_receive_callout
  771. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  772. "buffer4_send", buffer4_send_callout));
  773. // Let's create a simple DISCOVER
  774. Pkt4Ptr discover = generateSimpleDiscover();
  775. // Simulate that we have received that traffic
  776. srv_->fakeReceive(discover);
  777. // Server will now process to run its normal loop, but instead of calling
  778. // IfaceMgr::receive4(), it will read all packets from the list set by
  779. // fakeReceive()
  780. // In particular, it should call registered pkt4_receive callback.
  781. srv_->run();
  782. // Check that the callback called is indeed the one we installed
  783. EXPECT_EQ("buffer4_send", callback_name_);
  784. // Check that there is one packet sent
  785. ASSERT_EQ(1, srv_->fake_sent_.size());
  786. Pkt4Ptr adv = srv_->fake_sent_.front();
  787. // Check that pkt4 argument passing was successful and returned proper value
  788. EXPECT_TRUE(callback_pkt4_.get() == adv.get());
  789. // Check that all expected parameters are there
  790. vector<string> expected_argument_names;
  791. expected_argument_names.push_back(string("response4"));
  792. EXPECT_TRUE(expected_argument_names == callback_argument_names_);
  793. }
  794. // Checks if callouts installed on buffer4_send are indeed called and that
  795. // the output buffer can be changed.
  796. TEST_F(HooksDhcpv4SrvTest, buffer4Send) {
  797. IfaceMgrTestConfig test_config(true);
  798. IfaceMgr::instance().openSockets4();
  799. // Install pkt4_receive_callout
  800. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  801. "buffer4_send", buffer4_send_change_callout));
  802. // Let's create a simple DISCOVER
  803. Pkt4Ptr discover = generateSimpleDiscover();
  804. // Simulate that we have received that traffic
  805. srv_->fakeReceive(discover);
  806. // Server will now process to run its normal loop, but instead of calling
  807. // IfaceMgr::receive4(), it will read all packets from the list set by
  808. // fakeReceive()
  809. // In particular, it should call registered pkt4_receive callback.
  810. srv_->run();
  811. // Check that there is one packet sent
  812. ASSERT_EQ(1, srv_->fake_sent_.size());
  813. Pkt4Ptr adv = srv_->fake_sent_.front();
  814. // The callout is supposed to fill the output buffer with dummyFile content
  815. ASSERT_EQ(sizeof(dummyFile), adv->getBuffer().getLength());
  816. EXPECT_EQ(0, memcmp(adv->getBuffer().getData(), dummyFile, sizeof(dummyFile)));
  817. }
  818. // Checks if callouts installed on buffer4_send can set skip flag and that flag
  819. // causes the packet to not be sent
  820. TEST_F(HooksDhcpv4SrvTest, buffer4SendSkip) {
  821. IfaceMgrTestConfig test_config(true);
  822. IfaceMgr::instance().openSockets4();
  823. // Install pkt4_receive_callout
  824. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  825. "buffer4_send", skip_callout));
  826. // Let's create a simple DISCOVER
  827. Pkt4Ptr discover = generateSimpleDiscover();
  828. // Simulate that we have received that traffic
  829. srv_->fakeReceive(discover);
  830. // Server will now process to run its normal loop, but instead of calling
  831. // IfaceMgr::receive4(), it will read all packets from the list set by
  832. // fakeReceive()
  833. // In particular, it should call registered pkt4_receive callback.
  834. srv_->run();
  835. // Check that there is no packet sent.
  836. ASSERT_EQ(0, srv_->fake_sent_.size());
  837. }
  838. // This test checks if subnet4_select callout is triggered and reports
  839. // valid parameters
  840. TEST_F(HooksDhcpv4SrvTest, subnet4SelectSimple) {
  841. IfaceMgrTestConfig test_config(true);
  842. IfaceMgr::instance().openSockets4();
  843. // Install pkt4_receive_callout
  844. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  845. "subnet4_select", subnet4_select_callout));
  846. // Configure 2 subnets, both directly reachable over local interface
  847. // (let's not complicate the matter with relays)
  848. string config = "{ \"interfaces-config\": {"
  849. " \"interfaces\": [ \"*\" ]"
  850. "},"
  851. "\"rebind-timer\": 2000, "
  852. "\"renew-timer\": 1000, "
  853. "\"subnet4\": [ { "
  854. " \"pools\": [ { \"pool\": \"192.0.2.0/25\" } ],"
  855. " \"subnet\": \"192.0.2.0/24\", "
  856. " \"interface\": \"eth0\" "
  857. " }, {"
  858. " \"pools\": [ { \"pool\": \"192.0.3.0/25\" } ],"
  859. " \"subnet\": \"192.0.3.0/24\" "
  860. " } ],"
  861. "\"valid-lifetime\": 4000 }";
  862. ElementPtr json = Element::fromJSON(config);
  863. ConstElementPtr status;
  864. // Configure the server and make sure the config is accepted
  865. EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
  866. ASSERT_TRUE(status);
  867. comment_ = parseAnswer(rcode_, status);
  868. ASSERT_EQ(0, rcode_);
  869. // Commit the config
  870. CfgMgr::instance().commit();
  871. // Prepare discover packet. Server should select first subnet for it
  872. Pkt4Ptr sol = Pkt4Ptr(new Pkt4(DHCPDISCOVER, 1234));
  873. sol->setRemoteAddr(IOAddress("192.0.2.1"));
  874. sol->setIface("eth1");
  875. OptionPtr clientid = generateClientId();
  876. sol->addOption(clientid);
  877. // Pass it to the server and get an advertise
  878. Pkt4Ptr adv = srv_->processDiscover(sol);
  879. // check if we get response at all
  880. ASSERT_TRUE(adv);
  881. // Check that the callback called is indeed the one we installed
  882. EXPECT_EQ("subnet4_select", callback_name_);
  883. // Check that pkt4 argument passing was successful and returned proper value
  884. EXPECT_TRUE(callback_pkt4_.get() == sol.get());
  885. const Subnet4Collection* exp_subnets =
  886. CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->getAll();
  887. // The server is supposed to pick the first subnet, because of matching
  888. // interface. Check that the value is reported properly.
  889. ASSERT_TRUE(callback_subnet4_);
  890. EXPECT_EQ(exp_subnets->front().get(), callback_subnet4_.get());
  891. // Server is supposed to report two subnets
  892. ASSERT_EQ(exp_subnets->size(), callback_subnet4collection_->size());
  893. ASSERT_GE(exp_subnets->size(), 2);
  894. // Compare that the available subnets are reported as expected
  895. EXPECT_TRUE((*exp_subnets)[0].get() == (*callback_subnet4collection_)[0].get());
  896. EXPECT_TRUE((*exp_subnets)[1].get() == (*callback_subnet4collection_)[1].get());
  897. }
  898. // This test checks if callout installed on subnet4_select hook point can pick
  899. // a different subnet.
  900. TEST_F(HooksDhcpv4SrvTest, subnet4SelectChange) {
  901. IfaceMgrTestConfig test_config(true);
  902. IfaceMgr::instance().openSockets4();
  903. // Install a callout
  904. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  905. "subnet4_select", subnet4_select_different_subnet_callout));
  906. // Configure 2 subnets, both directly reachable over local interface
  907. // (let's not complicate the matter with relays)
  908. string config = "{ \"interfaces-config\": {"
  909. " \"interfaces\": [ \"*\" ]"
  910. "},"
  911. "\"rebind-timer\": 2000, "
  912. "\"renew-timer\": 1000, "
  913. "\"subnet4\": [ { "
  914. " \"pools\": [ { \"pool\": \"192.0.2.0/25\" } ],"
  915. " \"subnet\": \"192.0.2.0/24\", "
  916. " \"interface\": \"eth0\" "
  917. " }, {"
  918. " \"pools\": [ { \"pool\": \"192.0.3.0/25\" } ],"
  919. " \"subnet\": \"192.0.3.0/24\" "
  920. " } ],"
  921. "\"valid-lifetime\": 4000 }";
  922. ElementPtr json = Element::fromJSON(config);
  923. ConstElementPtr status;
  924. // Configure the server and make sure the config is accepted
  925. EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
  926. ASSERT_TRUE(status);
  927. comment_ = parseAnswer(rcode_, status);
  928. ASSERT_EQ(0, rcode_);
  929. CfgMgr::instance().commit();
  930. // Prepare discover packet. Server should select first subnet for it
  931. Pkt4Ptr sol = Pkt4Ptr(new Pkt4(DHCPDISCOVER, 1234));
  932. sol->setRemoteAddr(IOAddress("192.0.2.1"));
  933. sol->setIface("eth0");
  934. OptionPtr clientid = generateClientId();
  935. sol->addOption(clientid);
  936. // Pass it to the server and get an advertise
  937. Pkt4Ptr adv = srv_->processDiscover(sol);
  938. // check if we get response at all
  939. ASSERT_TRUE(adv);
  940. // The response should have an address from second pool, so let's check it
  941. IOAddress addr = adv->getYiaddr();
  942. EXPECT_NE("0.0.0.0", addr.toText());
  943. // Get all subnets and use second subnet for verification
  944. const Subnet4Collection* subnets =
  945. CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->getAll();
  946. ASSERT_EQ(2, subnets->size());
  947. // Advertised address must belong to the second pool (in subnet's range,
  948. // in dynamic pool)
  949. EXPECT_TRUE((*subnets)[1]->inRange(addr));
  950. EXPECT_TRUE((*subnets)[1]->inPool(Lease::TYPE_V4, addr));
  951. }
  952. // This test verifies that incoming (positive) REQUEST/Renewing can be handled
  953. // properly and that callout installed on lease4_renew is triggered with
  954. // expected parameters.
  955. TEST_F(HooksDhcpv4SrvTest, lease4RenewSimple) {
  956. IfaceMgrTestConfig test_config(true);
  957. IfaceMgr::instance().openSockets4();
  958. const IOAddress addr("192.0.2.106");
  959. const uint32_t temp_t1 = 50;
  960. const uint32_t temp_t2 = 75;
  961. const uint32_t temp_valid = 100;
  962. const time_t temp_timestamp = time(NULL) - 10;
  963. // Install a callout
  964. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  965. "lease4_renew", lease4_renew_callout));
  966. // Generate client-id also sets client_id_ member
  967. OptionPtr clientid = generateClientId();
  968. // Check that the address we are about to use is indeed in pool
  969. ASSERT_TRUE(subnet_->inPool(Lease::TYPE_V4, addr));
  970. // let's create a lease and put it in the LeaseMgr
  971. uint8_t hwaddr2_data[] = { 0, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe};
  972. HWAddrPtr hwaddr2(new HWAddr(hwaddr2_data, sizeof(hwaddr2_data), HTYPE_ETHER));
  973. Lease4Ptr used(new Lease4(IOAddress("192.0.2.106"), hwaddr2,
  974. &client_id_->getDuid()[0], client_id_->getDuid().size(),
  975. temp_valid, temp_t1, temp_t2, temp_timestamp,
  976. subnet_->getID()));
  977. ASSERT_TRUE(LeaseMgrFactory::instance().addLease(used));
  978. // Check that the lease is really in the database
  979. Lease4Ptr l = LeaseMgrFactory::instance().getLease4(addr);
  980. ASSERT_TRUE(l);
  981. // Let's create a RENEW
  982. Pkt4Ptr req = Pkt4Ptr(new Pkt4(DHCPREQUEST, 1234));
  983. req->setRemoteAddr(IOAddress(addr));
  984. req->setYiaddr(addr);
  985. req->setCiaddr(addr); // client's address
  986. req->setIface("eth0");
  987. req->setHWAddr(hwaddr2);
  988. req->addOption(clientid);
  989. req->addOption(srv_->getServerID());
  990. // Pass it to the server and hope for a REPLY
  991. Pkt4Ptr ack = srv_->processRequest(req);
  992. // Check if we get response at all
  993. checkResponse(ack, DHCPACK, 1234);
  994. // Check that the lease is really in the database
  995. l = checkLease(ack, clientid, req->getHWAddr(), addr);
  996. ASSERT_TRUE(l);
  997. // Check that T1, T2, preferred, valid and cltt were really updated
  998. EXPECT_EQ(l->t1_, subnet_->getT1());
  999. EXPECT_EQ(l->t2_, subnet_->getT2());
  1000. EXPECT_EQ(l->valid_lft_, subnet_->getValid());
  1001. // Check that the callback called is indeed the one we installed
  1002. EXPECT_EQ("lease4_renew", callback_name_);
  1003. // Check that hwaddr parameter is passed properly
  1004. ASSERT_TRUE(callback_hwaddr_);
  1005. EXPECT_TRUE(*callback_hwaddr_ == *req->getHWAddr());
  1006. // Check that the subnet is passed properly
  1007. ASSERT_TRUE(callback_subnet4_);
  1008. EXPECT_EQ(callback_subnet4_->toText(), subnet_->toText());
  1009. ASSERT_TRUE(callback_clientid_);
  1010. ASSERT_TRUE(client_id_);
  1011. EXPECT_TRUE(*client_id_ == *callback_clientid_);
  1012. // Check if all expected parameters were really received
  1013. vector<string> expected_argument_names;
  1014. expected_argument_names.push_back("subnet4");
  1015. expected_argument_names.push_back("clientid");
  1016. expected_argument_names.push_back("hwaddr");
  1017. expected_argument_names.push_back("lease4");
  1018. sort(callback_argument_names_.begin(), callback_argument_names_.end());
  1019. sort(expected_argument_names.begin(), expected_argument_names.end());
  1020. EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
  1021. EXPECT_TRUE(LeaseMgrFactory::instance().deleteLease(addr));
  1022. }
  1023. // This test verifies that a callout installed on lease4_renew can trigger
  1024. // the server to not renew a lease.
  1025. TEST_F(HooksDhcpv4SrvTest, lease4RenewSkip) {
  1026. IfaceMgrTestConfig test_config(true);
  1027. IfaceMgr::instance().openSockets4();
  1028. const IOAddress addr("192.0.2.106");
  1029. const uint32_t temp_t1 = 50;
  1030. const uint32_t temp_t2 = 75;
  1031. const uint32_t temp_valid = 100;
  1032. const time_t temp_timestamp = time(NULL) - 10;
  1033. // Install a callout
  1034. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1035. "lease4_renew", skip_callout));
  1036. // Generate client-id also sets client_id_ member
  1037. OptionPtr clientid = generateClientId();
  1038. // Check that the address we are about to use is indeed in pool
  1039. ASSERT_TRUE(subnet_->inPool(Lease::TYPE_V4, addr));
  1040. // let's create a lease and put it in the LeaseMgr
  1041. uint8_t hwaddr2_data[] = { 0, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe};
  1042. HWAddrPtr hwaddr2(new HWAddr(hwaddr2_data, sizeof(hwaddr2_data), HTYPE_ETHER));
  1043. Lease4Ptr used(new Lease4(IOAddress("192.0.2.106"), hwaddr2,
  1044. &client_id_->getDuid()[0], client_id_->getDuid().size(),
  1045. temp_valid, temp_t1, temp_t2, temp_timestamp,
  1046. subnet_->getID()));
  1047. ASSERT_TRUE(LeaseMgrFactory::instance().addLease(used));
  1048. // Check that the lease is really in the database
  1049. Lease4Ptr l = LeaseMgrFactory::instance().getLease4(addr);
  1050. ASSERT_TRUE(l);
  1051. // Check that T1, T2, preferred, valid and cltt really set.
  1052. // Constructed lease looks as if it was assigned 10 seconds ago
  1053. // EXPECT_EQ(l->t1_, temp_t1);
  1054. // EXPECT_EQ(l->t2_, temp_t2);
  1055. EXPECT_EQ(l->valid_lft_, temp_valid);
  1056. EXPECT_EQ(l->cltt_, temp_timestamp);
  1057. // Let's create a RENEW
  1058. Pkt4Ptr req = Pkt4Ptr(new Pkt4(DHCPREQUEST, 1234));
  1059. req->setRemoteAddr(IOAddress(addr));
  1060. req->setYiaddr(addr);
  1061. req->setCiaddr(addr); // client's address
  1062. req->setIface("eth0");
  1063. req->setHWAddr(hwaddr2);
  1064. req->addOption(clientid);
  1065. req->addOption(srv_->getServerID());
  1066. // Pass it to the server and hope for a REPLY
  1067. Pkt4Ptr ack = srv_->processRequest(req);
  1068. ASSERT_TRUE(ack);
  1069. // Check that the lease is really in the database
  1070. l = checkLease(ack, clientid, req->getHWAddr(), addr);
  1071. ASSERT_TRUE(l);
  1072. // Check that T1, T2, valid and cltt were NOT updated
  1073. EXPECT_EQ(temp_t1, l->t1_);
  1074. EXPECT_EQ(temp_t2, l->t2_);
  1075. EXPECT_EQ(temp_valid, l->valid_lft_);
  1076. EXPECT_EQ(temp_timestamp, l->cltt_);
  1077. EXPECT_TRUE(LeaseMgrFactory::instance().deleteLease(addr));
  1078. }
  1079. // This test verifies that valid RELEASE triggers lease4_release callouts
  1080. TEST_F(HooksDhcpv4SrvTest, lease4ReleaseSimple) {
  1081. IfaceMgrTestConfig test_config(true);
  1082. IfaceMgr::instance().openSockets4();
  1083. const IOAddress addr("192.0.2.106");
  1084. const uint32_t temp_t1 = 50;
  1085. const uint32_t temp_t2 = 75;
  1086. const uint32_t temp_valid = 100;
  1087. const time_t temp_timestamp = time(NULL) - 10;
  1088. // Install a callout
  1089. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1090. "lease4_release", lease4_release_callout));
  1091. // Generate client-id also duid_
  1092. OptionPtr clientid = generateClientId();
  1093. // Check that the address we are about to use is indeed in pool
  1094. ASSERT_TRUE(subnet_->inPool(Lease::TYPE_V4, addr));
  1095. // Let's create a lease and put it in the LeaseMgr
  1096. uint8_t mac_addr[] = { 0, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe};
  1097. HWAddrPtr hw(new HWAddr(mac_addr, sizeof(mac_addr), HTYPE_ETHER));
  1098. Lease4Ptr used(new Lease4(addr, hw,
  1099. &client_id_->getDuid()[0], client_id_->getDuid().size(),
  1100. temp_valid, temp_t1, temp_t2, temp_timestamp,
  1101. subnet_->getID()));
  1102. ASSERT_TRUE(LeaseMgrFactory::instance().addLease(used));
  1103. // Check that the lease is really in the database
  1104. Lease4Ptr l = LeaseMgrFactory::instance().getLease4(addr);
  1105. ASSERT_TRUE(l);
  1106. // Let's create a RELEASE
  1107. // Generate client-id also duid_
  1108. Pkt4Ptr rel = Pkt4Ptr(new Pkt4(DHCPRELEASE, 1234));
  1109. rel->setRemoteAddr(addr);
  1110. rel->setCiaddr(addr);
  1111. rel->addOption(clientid);
  1112. rel->addOption(srv_->getServerID());
  1113. rel->setHWAddr(hw);
  1114. // Pass it to the server and hope for a REPLY
  1115. // Note: this is no response to RELEASE in DHCPv4
  1116. EXPECT_NO_THROW(srv_->processRelease(rel));
  1117. // The lease should be gone from LeaseMgr
  1118. l = LeaseMgrFactory::instance().getLease4(addr);
  1119. EXPECT_FALSE(l);
  1120. // Try to get the lease by hardware address
  1121. // @todo: Uncomment this once trac2592 is implemented
  1122. // Lease4Collection leases = LeaseMgrFactory::instance().getLease4(hw->hwaddr_);
  1123. // EXPECT_EQ(leases.size(), 0);
  1124. // Try to get it by hw/subnet_id combination
  1125. l = LeaseMgrFactory::instance().getLease4(hw->hwaddr_, subnet_->getID());
  1126. EXPECT_FALSE(l);
  1127. // Try by client-id
  1128. // @todo: Uncomment this once trac2592 is implemented
  1129. //Lease4Collection leases = LeaseMgrFactory::instance().getLease4(*client_id_);
  1130. //EXPECT_EQ(leases.size(), 0);
  1131. // Try by client-id/subnet-id
  1132. l = LeaseMgrFactory::instance().getLease4(*client_id_, subnet_->getID());
  1133. EXPECT_FALSE(l);
  1134. // Ok, the lease is *really* not there.
  1135. // Check that the callback called is indeed the one we installed
  1136. EXPECT_EQ("lease4_release", callback_name_);
  1137. // Check that pkt4 argument passing was successful and returned proper value
  1138. EXPECT_TRUE(callback_pkt4_.get() == rel.get());
  1139. // Check if all expected parameters were really received
  1140. vector<string> expected_argument_names;
  1141. expected_argument_names.push_back("query4");
  1142. expected_argument_names.push_back("lease4");
  1143. sort(callback_argument_names_.begin(), callback_argument_names_.end());
  1144. sort(expected_argument_names.begin(), expected_argument_names.end());
  1145. EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
  1146. }
  1147. // This test verifies that skip flag returned by a callout installed on the
  1148. // lease4_release hook point will keep the lease
  1149. TEST_F(HooksDhcpv4SrvTest, lease4ReleaseSkip) {
  1150. IfaceMgrTestConfig test_config(true);
  1151. IfaceMgr::instance().openSockets4();
  1152. const IOAddress addr("192.0.2.106");
  1153. const uint32_t temp_t1 = 50;
  1154. const uint32_t temp_t2 = 75;
  1155. const uint32_t temp_valid = 100;
  1156. const time_t temp_timestamp = time(NULL) - 10;
  1157. // Install a callout
  1158. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1159. "lease4_release", skip_callout));
  1160. // Generate client-id also duid_
  1161. OptionPtr clientid = generateClientId();
  1162. // Check that the address we are about to use is indeed in pool
  1163. ASSERT_TRUE(subnet_->inPool(Lease::TYPE_V4, addr));
  1164. // Let's create a lease and put it in the LeaseMgr
  1165. uint8_t mac_addr[] = { 0, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe};
  1166. HWAddrPtr hw(new HWAddr(mac_addr, sizeof(mac_addr), HTYPE_ETHER));
  1167. Lease4Ptr used(new Lease4(addr, hw,
  1168. &client_id_->getDuid()[0], client_id_->getDuid().size(),
  1169. temp_valid, temp_t1, temp_t2, temp_timestamp,
  1170. subnet_->getID()));
  1171. ASSERT_TRUE(LeaseMgrFactory::instance().addLease(used));
  1172. // Check that the lease is really in the database
  1173. Lease4Ptr l = LeaseMgrFactory::instance().getLease4(addr);
  1174. ASSERT_TRUE(l);
  1175. // Let's create a RELEASE
  1176. // Generate client-id also duid_
  1177. Pkt4Ptr rel = Pkt4Ptr(new Pkt4(DHCPRELEASE, 1234));
  1178. rel->setRemoteAddr(addr);
  1179. rel->setYiaddr(addr);
  1180. rel->addOption(clientid);
  1181. rel->addOption(srv_->getServerID());
  1182. rel->setHWAddr(hw);
  1183. // Pass it to the server and hope for a REPLY
  1184. // Note: this is no response to RELEASE in DHCPv4
  1185. EXPECT_NO_THROW(srv_->processRelease(rel));
  1186. // The lease should be still there
  1187. l = LeaseMgrFactory::instance().getLease4(addr);
  1188. EXPECT_TRUE(l);
  1189. // Try by client-id/subnet-id
  1190. l = LeaseMgrFactory::instance().getLease4(*client_id_, subnet_->getID());
  1191. EXPECT_TRUE(l);
  1192. // Try to get the lease by hardware address, should succeed
  1193. Lease4Collection leases = LeaseMgrFactory::instance().getLease4(*hw);
  1194. EXPECT_EQ(leases.size(), 1);
  1195. // Try by client-id, should be successful as well.
  1196. leases = LeaseMgrFactory::instance().getLease4(*client_id_);
  1197. EXPECT_EQ(leases.size(), 1);
  1198. }
  1199. // Checks that decline4 hooks (lease4_decline) are triggered properly.
  1200. TEST_F(HooksDhcpv4SrvTest, HooksDecline) {
  1201. IfaceMgrTestConfig test_config(true);
  1202. IfaceMgr::instance().openSockets4();
  1203. // Install a callout
  1204. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1205. "lease4_decline", lease4_decline_callout));
  1206. // Conduct the actual DORA + Decline.
  1207. Dhcp4Client client(Dhcp4Client::SELECTING);
  1208. acquireAndDecline(client, "01:02:03:04:05:06", "12:14",
  1209. "01:02:03:04:05:06", "12:14",
  1210. SHOULD_PASS);
  1211. EXPECT_EQ("lease4_decline", callback_name_);
  1212. // Verifying DHCPDECLINE is a bit tricky, as it is created somewhere in
  1213. // acquireAndDecline. We'll just verify that it's really a DECLINE
  1214. // and that its address is equal to what we have in LeaseMgr.
  1215. ASSERT_TRUE(callback_pkt4_);
  1216. ASSERT_TRUE(callback_lease4_);
  1217. // Check that it's the proper packet that was reported.
  1218. EXPECT_EQ(DHCPDECLINE, callback_pkt4_->getType());
  1219. // Extract the address being declined.
  1220. OptionCustomPtr opt_declined_addr = boost::dynamic_pointer_cast<
  1221. OptionCustom>(callback_pkt4_->getOption(DHO_DHCP_REQUESTED_ADDRESS));
  1222. ASSERT_TRUE(opt_declined_addr);
  1223. IOAddress addr(opt_declined_addr->readAddress());
  1224. // And try to get a matching lease from the lease manager.
  1225. Lease4Ptr from_mgr = LeaseMgrFactory::instance().getLease4(addr);
  1226. ASSERT_TRUE(from_mgr);
  1227. EXPECT_EQ(Lease::STATE_DECLINED, from_mgr->state_);
  1228. // Let's now check that those 3 things (packet, lease returned and lease from
  1229. // the lease manager) all match.
  1230. EXPECT_EQ(addr, from_mgr->addr_);
  1231. EXPECT_EQ(addr, callback_lease4_->addr_);
  1232. }
  1233. // Checks that decline4 hook is able to drop the packet.
  1234. TEST_F(HooksDhcpv4SrvTest, HooksDeclineDrop) {
  1235. IfaceMgrTestConfig test_config(true);
  1236. IfaceMgr::instance().openSockets4();
  1237. // Install a callout
  1238. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1239. "lease4_decline", lease4_decline_drop_callout));
  1240. // Conduct the actual DORA + Decline. The DECLINE should fail, as the
  1241. // hook will set the status to DROP.
  1242. Dhcp4Client client(Dhcp4Client::SELECTING);
  1243. acquireAndDecline(client, "01:02:03:04:05:06", "12:14",
  1244. "01:02:03:04:05:06", "12:14",
  1245. SHOULD_FAIL);
  1246. EXPECT_EQ("lease4_decline", callback_name_);
  1247. // Verifying DHCPDECLINE is a bit tricky, as it is created somewhere in
  1248. // acquireAndDecline. We'll just verify that it's really a DECLINE
  1249. // and that its address is equal to what we have in LeaseMgr.
  1250. ASSERT_TRUE(callback_pkt4_);
  1251. ASSERT_TRUE(callback_lease4_);
  1252. // Check that it's the proper packet that was reported.
  1253. EXPECT_EQ(DHCPDECLINE, callback_pkt4_->getType());
  1254. // Extract the address being declined.
  1255. OptionCustomPtr opt_declined_addr = boost::dynamic_pointer_cast<
  1256. OptionCustom>(callback_pkt4_->getOption(DHO_DHCP_REQUESTED_ADDRESS));
  1257. ASSERT_TRUE(opt_declined_addr);
  1258. IOAddress addr(opt_declined_addr->readAddress());
  1259. // And try to get a matching lease from the lease manager. The lease should
  1260. // still be there in default state, not in declined state.
  1261. Lease4Ptr from_mgr = LeaseMgrFactory::instance().getLease4(addr);
  1262. ASSERT_TRUE(from_mgr);
  1263. EXPECT_EQ(Lease::STATE_DEFAULT, from_mgr->state_);
  1264. // As a final sanity check, let's now check that those 3 things (packet,
  1265. // lease returned and lease from the lease manager) all match.
  1266. EXPECT_EQ(addr, from_mgr->addr_);
  1267. EXPECT_EQ(addr, callback_lease4_->addr_);
  1268. }
  1269. // Verifies that libraries are unloaded by server destruction
  1270. // The callout libraries write their library index number to a marker
  1271. // file upon load and unload, making it simple to test whether or not
  1272. // the load and unload callouts have been invoked.
  1273. TEST_F(LoadUnloadDhcpv4SrvTest, unloadLibaries) {
  1274. ASSERT_NO_THROW(server_.reset(new NakedDhcpv4Srv()));
  1275. // Ensure no marker files to start with.
  1276. ASSERT_FALSE(checkMarkerFileExists(LOAD_MARKER_FILE));
  1277. ASSERT_FALSE(checkMarkerFileExists(UNLOAD_MARKER_FILE));
  1278. // Load two libraries
  1279. std::vector<std::string> libraries;
  1280. libraries.push_back(CALLOUT_LIBRARY_1);
  1281. libraries.push_back(CALLOUT_LIBRARY_2);
  1282. HooksManager::loadLibraries(libraries);
  1283. // Check they are loaded.
  1284. std::vector<std::string> loaded_libraries =
  1285. HooksManager::getLibraryNames();
  1286. ASSERT_TRUE(libraries == loaded_libraries);
  1287. // ... which also included checking that the marker file created by the
  1288. // load functions exists and holds the correct value (of "12" - the
  1289. // first library appends "1" to the file, the second appends "2"). Also
  1290. // check that the unload marker file does not yet exist.
  1291. EXPECT_TRUE(checkMarkerFile(LOAD_MARKER_FILE, "12"));
  1292. EXPECT_FALSE(checkMarkerFileExists(UNLOAD_MARKER_FILE));
  1293. server_.reset();
  1294. // Check that the libraries have unloaded and reloaded. The libraries are
  1295. // unloaded in the reverse order to which they are loaded. When they load,
  1296. // they should append information to the loading marker file.
  1297. EXPECT_TRUE(checkMarkerFile(UNLOAD_MARKER_FILE, "21"));
  1298. EXPECT_TRUE(checkMarkerFile(LOAD_MARKER_FILE, "12"));
  1299. }