handles_unittest.cc 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983
  1. // Copyright (C) 2013,2015 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 <hooks/callout_handle.h>
  15. #include <hooks/callout_manager.h>
  16. #include <hooks/library_handle.h>
  17. #include <hooks/server_hooks.h>
  18. #include <boost/lexical_cast.hpp>
  19. #include <boost/scoped_ptr.hpp>
  20. #include <gtest/gtest.h>
  21. #include <algorithm>
  22. #include <string>
  23. /// @file
  24. /// CalloutHandle/LibraryHandle interaction tests
  25. ///
  26. /// This file holds unit tests checking the interaction between the
  27. /// CalloutHandle/LibraryHandle and CalloutManager classes. In particular,
  28. /// they check that:
  29. ///
  30. /// - A CalloutHandle's context is shared between callouts from the same
  31. /// library, but there is a separate context for each library.
  32. ///
  33. /// - The various methods manipulating the items in the CalloutHandle's context
  34. /// work correctly.
  35. ///
  36. /// - An active callout can only modify the registration of callouts registered
  37. /// by its own library.
  38. using namespace isc::hooks;
  39. using namespace std;
  40. namespace {
  41. class HandlesTest : public ::testing::Test {
  42. public:
  43. /// @brief Constructor
  44. ///
  45. /// Sets up the various elements used in each test.
  46. HandlesTest() {
  47. // Set up four hooks, although through gamma
  48. ServerHooks& hooks = ServerHooks::getServerHooks();
  49. hooks.reset();
  50. alpha_index_ = hooks.registerHook("alpha");
  51. beta_index_ = hooks.registerHook("beta");
  52. gamma_index_ = hooks.registerHook("gamma");
  53. delta_index_ = hooks.registerHook("delta");
  54. // Set up for three libraries.
  55. manager_.reset(new CalloutManager(3));
  56. // Initialize remaining variables.
  57. common_string_ = "";
  58. }
  59. /// @brief Return callout manager
  60. boost::shared_ptr<CalloutManager> getCalloutManager() {
  61. return (manager_);
  62. }
  63. /// Hook indexes - these are frequently accessed, so are accessed directly.
  64. int alpha_index_;
  65. int beta_index_;
  66. int gamma_index_;
  67. int delta_index_;
  68. /// String accessible by all callouts whatever the library
  69. static std::string common_string_;
  70. private:
  71. /// Callout manager. Declared static so that the callout functions can
  72. /// access it.
  73. boost::shared_ptr<CalloutManager> manager_;
  74. };
  75. /// Define the common string
  76. std::string HandlesTest::common_string_;
  77. // The next set of functions define the callouts used by the tests. They
  78. // manipulate the data in such a way that callouts called - and the order in
  79. // which they were called - can be determined. The functions also check that
  80. // the "callout context" data areas are separate.
  81. //
  82. // Three libraries are assumed, and each supplies four callouts. All callouts
  83. // manipulate two context elements the CalloutHandle, the elements being called
  84. // "string" and "int" (which describe the type of data manipulated).
  85. //
  86. // For the string item, each callout shifts data to the left and inserts its own
  87. // data. The data is a string of the form "nmc", where "n" is the number of
  88. // the library, "m" is the callout number and "y" is the indication of what
  89. // callout handle was passed as an argument ("1" or "2": "0" is used when no
  90. // identification has been set in the callout handle).
  91. //
  92. // For simplicity, and to cut down the number of functions actually written,
  93. // the callout indicator ("1" or "2") ) used in the in the CalloutHandle
  94. // functions is passed via a CalloutArgument. The argument is named "string":
  95. // use of a name the same as that of one of the context elements serves as a
  96. // check that the argument name space and argument context space are separate.
  97. //
  98. // For integer data, the value starts at zero and an increment is added on each
  99. // call. This increment is equal to:
  100. //
  101. // 100 * library number + 10 * callout number + callout handle
  102. //
  103. // Although this gives less information than the string value, the reasons for
  104. // using it are:
  105. //
  106. // - It is a separate item in the context, so checks that the context can
  107. // handle multiple items.
  108. // - It provides an item that can be deleted by the context deletion
  109. // methods.
  110. // Values set in the CalloutHandle context. There are three libraries, so
  111. // there are three contexts for the callout, one for each library.
  112. std::string& resultCalloutString(int index) {
  113. static std::string result_callout_string[3];
  114. return (result_callout_string[index]);
  115. }
  116. int& resultCalloutInt(int index) {
  117. static int result_callout_int[3];
  118. return (result_callout_int[index]);
  119. }
  120. // A simple function to zero the results.
  121. static void zero_results() {
  122. for (int i = 0; i < 3; ++i) {
  123. resultCalloutString(i) = "";
  124. resultCalloutInt(i) = 0;
  125. }
  126. }
  127. // Library callouts.
  128. // Common code for setting the callout context values.
  129. int
  130. execute(CalloutHandle& callout_handle, int library_num, int callout_num) {
  131. // Obtain the callout handle number
  132. int handle_num = 0;
  133. try {
  134. callout_handle.getArgument("handle_num", handle_num);
  135. } catch (const NoSuchArgument&) {
  136. // handle_num argument not set: this is the case in the tests where
  137. // the context_create hook check is tested.
  138. handle_num = 0;
  139. }
  140. // Create the basic data to be appended to the context value.
  141. int idata = 100 * library_num + 10 * callout_num + handle_num;
  142. string sdata = boost::lexical_cast<string>(idata);
  143. // Get the context data. As before, this will not exist for the first
  144. // callout called. (In real life, the library should create it when the
  145. // "context_create" hook gets called before any packet processing takes
  146. // place.)
  147. int int_value = 0;
  148. try {
  149. callout_handle.getContext("int", int_value);
  150. } catch (const NoSuchCalloutContext&) {
  151. int_value = 0;
  152. }
  153. string string_value = "";
  154. try {
  155. callout_handle.getContext("string", string_value);
  156. } catch (const NoSuchCalloutContext&) {
  157. string_value = "";
  158. }
  159. // Update the values and set them back in the callout context.
  160. int_value += idata;
  161. callout_handle.setContext("int", int_value);
  162. string_value += sdata;
  163. callout_handle.setContext("string", string_value);
  164. return (0);
  165. }
  166. // The following functions are the actual callouts - the name is of the
  167. // form "callout_<library number>_<callout number>"
  168. int
  169. callout11(CalloutHandle& callout_handle) {
  170. return (execute(callout_handle, 1, 1));
  171. }
  172. int
  173. callout12(CalloutHandle& callout_handle) {
  174. return (execute(callout_handle, 1, 2));
  175. }
  176. int
  177. callout13(CalloutHandle& callout_handle) {
  178. return (execute(callout_handle, 1, 3));
  179. }
  180. int
  181. callout21(CalloutHandle& callout_handle) {
  182. return (execute(callout_handle, 2, 1));
  183. }
  184. int
  185. callout22(CalloutHandle& callout_handle) {
  186. return (execute(callout_handle, 2, 2));
  187. }
  188. int
  189. callout23(CalloutHandle& callout_handle) {
  190. return (execute(callout_handle, 2, 3));
  191. }
  192. int
  193. callout31(CalloutHandle& callout_handle) {
  194. return (execute(callout_handle, 3, 1));
  195. }
  196. int
  197. callout32(CalloutHandle& callout_handle) {
  198. return (execute(callout_handle, 3, 2));
  199. }
  200. int
  201. callout33(CalloutHandle& callout_handle) {
  202. return (execute(callout_handle, 3, 3));
  203. }
  204. // Common callout code for the fourth hook (which makes the data available for
  205. // checking). It copies the library and callout context data to the global
  206. // variables.
  207. int printExecute(CalloutHandle& callout_handle, int library_num) {
  208. callout_handle.getContext("string", resultCalloutString(library_num - 1));
  209. callout_handle.getContext("int", resultCalloutInt(library_num - 1));
  210. return (0);
  211. }
  212. // These are the actual callouts.
  213. int
  214. print1(CalloutHandle& callout_handle) {
  215. return (printExecute(callout_handle, 1));
  216. }
  217. int
  218. print2(CalloutHandle& callout_handle) {
  219. return (printExecute(callout_handle, 2));
  220. }
  221. int
  222. print3(CalloutHandle& callout_handle) {
  223. return (printExecute(callout_handle, 3));
  224. }
  225. // This test checks the many-faced nature of the context for the CalloutContext.
  226. TEST_F(HandlesTest, ContextAccessCheck) {
  227. // Register callouts for the different libraries.
  228. CalloutHandle handle(getCalloutManager());
  229. // Library 0.
  230. getCalloutManager()->setLibraryIndex(0);
  231. getCalloutManager()->registerCallout("alpha", callout11);
  232. getCalloutManager()->registerCallout("beta", callout12);
  233. getCalloutManager()->registerCallout("gamma", callout13);
  234. getCalloutManager()->registerCallout("delta", print1);
  235. getCalloutManager()->setLibraryIndex(1);
  236. getCalloutManager()->registerCallout("alpha", callout21);
  237. getCalloutManager()->registerCallout("beta", callout22);
  238. getCalloutManager()->registerCallout("gamma", callout23);
  239. getCalloutManager()->registerCallout("delta", print2);
  240. getCalloutManager()->setLibraryIndex(2);
  241. getCalloutManager()->registerCallout("alpha", callout31);
  242. getCalloutManager()->registerCallout("beta", callout32);
  243. getCalloutManager()->registerCallout("gamma", callout33);
  244. getCalloutManager()->registerCallout("delta", print3);
  245. // Create the callout handles and distinguish them by setting the
  246. // "handle_num" argument.
  247. CalloutHandle callout_handle_1(getCalloutManager());
  248. callout_handle_1.setArgument("handle_num", static_cast<int>(1));
  249. CalloutHandle callout_handle_2(getCalloutManager());
  250. callout_handle_2.setArgument("handle_num", static_cast<int>(2));
  251. // Now call the callouts attached to the first three hooks. Each hook is
  252. // called twice (once for each callout handle) before the next hook is
  253. // called.
  254. getCalloutManager()->callCallouts(alpha_index_, callout_handle_1);
  255. getCalloutManager()->callCallouts(alpha_index_, callout_handle_2);
  256. getCalloutManager()->callCallouts(beta_index_, callout_handle_1);
  257. getCalloutManager()->callCallouts(beta_index_, callout_handle_2);
  258. getCalloutManager()->callCallouts(gamma_index_, callout_handle_1);
  259. getCalloutManager()->callCallouts(gamma_index_, callout_handle_2);
  260. // Get the results for each callout (the callout on hook "delta" copies
  261. // the context values into a location the test can access). Explicitly
  262. // zero the variables before getting the results so we are certain that
  263. // the values are the results of the callouts.
  264. zero_results();
  265. // To explain the expected callout context results.
  266. //
  267. // Each callout handle maintains a separate context for each library. When
  268. // the first call to callCallouts() is made, "111" gets appended to
  269. // the context for library 1 maintained by the first callout handle, "211"
  270. // gets appended to the context maintained for library 2, and "311" to
  271. // the context maintained for library 3. In each case, the first digit
  272. // corresponds to the library number, the second to the callout number and
  273. // the third to the "handle_num" of the callout handle. For the first call
  274. // to callCallouts, handle 1 is used, so the last digit is always 1.
  275. //
  276. // The next call to callCallouts() calls the same callouts but for the
  277. // second callout handle. It also maintains three contexts (one for
  278. // each library) and they will get "112", "212", "312" appended to
  279. // them. The explanation for the digits is the same as before, except that
  280. // in this case, the callout handle is number 2, so the third digit is
  281. // always 2. These additions don't affect the contexts maintained by
  282. // callout handle 1.
  283. //
  284. // The process is then repeated for hooks "beta" and "gamma" which, for
  285. // callout handle 1, append "121", "221" and "321" for hook "beta" and
  286. // "311", "321" and "331" for hook "gamma".
  287. //
  288. // The expected integer values can be found by summing up the values
  289. // corresponding to the elements of the strings.
  290. // At this point, we have only called the "print" function for callout
  291. // handle "1", so the following results are checking the context values
  292. // maintained in that callout handle.
  293. getCalloutManager()->callCallouts(delta_index_, callout_handle_1);
  294. EXPECT_EQ("111121131", resultCalloutString(0));
  295. EXPECT_EQ("211221231", resultCalloutString(1));
  296. EXPECT_EQ("311321331", resultCalloutString(2));
  297. EXPECT_EQ((111 + 121 + 131), resultCalloutInt(0));
  298. EXPECT_EQ((211 + 221 + 231), resultCalloutInt(1));
  299. EXPECT_EQ((311 + 321 + 331), resultCalloutInt(2));
  300. // Repeat the checks for callout 2.
  301. zero_results();
  302. getCalloutManager()->callCallouts(delta_index_, callout_handle_2);
  303. EXPECT_EQ((112 + 122 + 132), resultCalloutInt(0));
  304. EXPECT_EQ((212 + 222 + 232), resultCalloutInt(1));
  305. EXPECT_EQ((312 + 322 + 332), resultCalloutInt(2));
  306. EXPECT_EQ("112122132", resultCalloutString(0));
  307. EXPECT_EQ("212222232", resultCalloutString(1));
  308. EXPECT_EQ("312322332", resultCalloutString(2));
  309. }
  310. // Now repeat the test, but add a deletion callout to the list. The "beta"
  311. // hook of library 2 will have an additional callout to delete the "int"
  312. // element: the same hook for library 3 will delete both elements. In
  313. // addition, the names of context elements for the libraries at this point
  314. // will be printed.
  315. // List of context item names.
  316. vector<string>&
  317. getItemNames(int index) {
  318. static vector<string> context_items[3];
  319. return (context_items[index]);
  320. }
  321. // Context item deletion functions.
  322. int
  323. deleteIntContextItem(CalloutHandle& handle) {
  324. handle.deleteContext("int");
  325. return (0);
  326. }
  327. int
  328. deleteAllContextItems(CalloutHandle& handle) {
  329. handle.deleteAllContext();
  330. return (0);
  331. }
  332. // Generic print function - copy names in sorted order.
  333. int
  334. printContextNamesExecute(CalloutHandle& handle, int library_num) {
  335. const int index = library_num - 1;
  336. getItemNames(index) = handle.getContextNames();
  337. sort(getItemNames(index).begin(), getItemNames(index).end());
  338. return (0);
  339. }
  340. int
  341. printContextNames1(CalloutHandle& handle) {
  342. return (printContextNamesExecute(handle, 1));
  343. }
  344. int
  345. printContextNames2(CalloutHandle& handle) {
  346. return (printContextNamesExecute(handle, 2));
  347. }
  348. int
  349. printContextNames3(CalloutHandle& handle) {
  350. return (printContextNamesExecute(handle, 3));
  351. }
  352. // Perform the test including deletion of context items.
  353. TEST_F(HandlesTest, ContextDeletionCheck) {
  354. getCalloutManager()->setLibraryIndex(0);
  355. getCalloutManager()->registerCallout("alpha", callout11);
  356. getCalloutManager()->registerCallout("beta", callout12);
  357. getCalloutManager()->registerCallout("beta", printContextNames1);
  358. getCalloutManager()->registerCallout("gamma", callout13);
  359. getCalloutManager()->registerCallout("delta", print1);
  360. getCalloutManager()->setLibraryIndex(1);
  361. getCalloutManager()->registerCallout("alpha", callout21);
  362. getCalloutManager()->registerCallout("beta", callout22);
  363. getCalloutManager()->registerCallout("beta", deleteIntContextItem);
  364. getCalloutManager()->registerCallout("beta", printContextNames2);
  365. getCalloutManager()->registerCallout("gamma", callout23);
  366. getCalloutManager()->registerCallout("delta", print2);
  367. getCalloutManager()->setLibraryIndex(2);
  368. getCalloutManager()->registerCallout("alpha", callout31);
  369. getCalloutManager()->registerCallout("beta", callout32);
  370. getCalloutManager()->registerCallout("beta", deleteAllContextItems);
  371. getCalloutManager()->registerCallout("beta", printContextNames3);
  372. getCalloutManager()->registerCallout("gamma", callout33);
  373. getCalloutManager()->registerCallout("delta", print3);
  374. // Create the callout handles and distinguish them by setting the "long"
  375. // argument.
  376. CalloutHandle callout_handle_1(getCalloutManager());
  377. callout_handle_1.setArgument("handle_num", static_cast<int>(1));
  378. CalloutHandle callout_handle_2(getCalloutManager());
  379. callout_handle_2.setArgument("handle_num", static_cast<int>(2));
  380. // Now call the callouts attached to the first three hooks. Each hook is
  381. // called twice (once for each callout handle) before the next hook is
  382. // called.
  383. getCalloutManager()->callCallouts(alpha_index_, callout_handle_1);
  384. getCalloutManager()->callCallouts(alpha_index_, callout_handle_2);
  385. getCalloutManager()->callCallouts(beta_index_, callout_handle_1);
  386. getCalloutManager()->callCallouts(beta_index_, callout_handle_2);
  387. getCalloutManager()->callCallouts(gamma_index_, callout_handle_1);
  388. getCalloutManager()->callCallouts(gamma_index_, callout_handle_2);
  389. // Get the results for each callout. Explicitly zero the variables before
  390. // getting the results so we are certain that the values are the results
  391. // of the callouts.
  392. zero_results();
  393. getCalloutManager()->callCallouts(delta_index_, callout_handle_1);
  394. // The logic by which the expected results are arrived at is described
  395. // in the ContextAccessCheck test. The results here are different
  396. // because context items have been modified along the way.
  397. EXPECT_EQ((111 + 121 + 131), resultCalloutInt(0));
  398. EXPECT_EQ(( 231), resultCalloutInt(1));
  399. EXPECT_EQ(( 331), resultCalloutInt(2));
  400. EXPECT_EQ("111121131", resultCalloutString(0));
  401. EXPECT_EQ("211221231", resultCalloutString(1));
  402. EXPECT_EQ( "331", resultCalloutString(2));
  403. // Repeat the checks for callout handle 2.
  404. zero_results();
  405. getCalloutManager()->callCallouts(delta_index_, callout_handle_2);
  406. EXPECT_EQ((112 + 122 + 132), resultCalloutInt(0));
  407. EXPECT_EQ(( 232), resultCalloutInt(1));
  408. EXPECT_EQ(( 332), resultCalloutInt(2));
  409. EXPECT_EQ("112122132", resultCalloutString(0));
  410. EXPECT_EQ("212222232", resultCalloutString(1));
  411. EXPECT_EQ( "332", resultCalloutString(2));
  412. // ... and check what the names of the context items are after the callouts
  413. // for hook "beta". We know they are in sorted order.
  414. EXPECT_EQ(2, getItemNames(0).size());
  415. EXPECT_EQ(string("int"), getItemNames(0)[0]);
  416. EXPECT_EQ(string("string"), getItemNames(0)[1]);
  417. EXPECT_EQ(1, getItemNames(1).size());
  418. EXPECT_EQ(string("string"), getItemNames(1)[0]);
  419. EXPECT_EQ(0, getItemNames(2).size());
  420. }
  421. // Tests that the CalloutHandle's constructor and destructor call the
  422. // context_create and context_destroy callbacks (if registered). For
  423. // simplicity, we'll use the same callout functions as used above.
  424. TEST_F(HandlesTest, ConstructionDestructionCallouts) {
  425. // Register context callouts.
  426. getCalloutManager()->setLibraryIndex(0);
  427. getCalloutManager()->registerCallout("context_create", callout11);
  428. getCalloutManager()->registerCallout("context_create", print1);
  429. getCalloutManager()->registerCallout("context_destroy", callout12);
  430. getCalloutManager()->registerCallout("context_destroy", print1);
  431. // Create the CalloutHandle and check that the constructor callout
  432. // has run.
  433. zero_results();
  434. boost::scoped_ptr<CalloutHandle>
  435. callout_handle(new CalloutHandle(getCalloutManager()));
  436. EXPECT_EQ("110", resultCalloutString(0));
  437. EXPECT_EQ(110, resultCalloutInt(0));
  438. // Check that the destructor callout runs. Note that the "print1" callout
  439. // didn't destroy the library context - it only copied it to where it
  440. // could be examined. As a result, the destructor callout appends its
  441. // elements to the constructor's values and the result is printed.
  442. zero_results();
  443. callout_handle.reset();
  444. EXPECT_EQ("110120", resultCalloutString(0));
  445. EXPECT_EQ((110 + 120), resultCalloutInt(0));
  446. }
  447. // Dynamic callout registration and deregistration.
  448. // The following are the dynamic registration/deregistration callouts.
  449. // Add callout_78_alpha - adds a callout to hook alpha that appends "78x"
  450. // (where "x" is the callout handle) to the current output.
  451. int
  452. callout78(CalloutHandle& callout_handle) {
  453. return (execute(callout_handle, 7, 8));
  454. }
  455. int
  456. add_callout78_alpha(CalloutHandle& callout_handle) {
  457. callout_handle.getLibraryHandle().registerCallout("alpha", callout78);
  458. return (0);
  459. }
  460. int
  461. delete_callout78_alpha(CalloutHandle& callout_handle) {
  462. static_cast<void>(
  463. callout_handle.getLibraryHandle().deregisterCallout("alpha",
  464. callout78));
  465. return (0);
  466. }
  467. // Check that a callout can register another callout on a different hook.
  468. TEST_F(HandlesTest, DynamicRegistrationAnotherHook) {
  469. // Register callouts for the different libraries.
  470. CalloutHandle handle(getCalloutManager());
  471. // Set up callouts on "alpha".
  472. getCalloutManager()->setLibraryIndex(0);
  473. getCalloutManager()->registerCallout("alpha", callout11);
  474. getCalloutManager()->registerCallout("delta", print1);
  475. getCalloutManager()->setLibraryIndex(1);
  476. getCalloutManager()->registerCallout("alpha", callout21);
  477. getCalloutManager()->registerCallout("delta", print2);
  478. getCalloutManager()->setLibraryIndex(2);
  479. getCalloutManager()->registerCallout("alpha", callout31);
  480. getCalloutManager()->registerCallout("delta", print3);
  481. // ... and on "beta", set up the function to add a hook to alpha (but only
  482. // for library 1).
  483. getCalloutManager()->setLibraryIndex(1);
  484. getCalloutManager()->registerCallout("beta", add_callout78_alpha);
  485. // See what we get for calling the callouts on alpha first.
  486. CalloutHandle callout_handle_1(getCalloutManager());
  487. callout_handle_1.setArgument("handle_num", static_cast<int>(1));
  488. getCalloutManager()->callCallouts(alpha_index_, callout_handle_1);
  489. zero_results();
  490. getCalloutManager()->callCallouts(delta_index_, callout_handle_1);
  491. EXPECT_EQ("111", resultCalloutString(0));
  492. EXPECT_EQ("211", resultCalloutString(1));
  493. EXPECT_EQ("311", resultCalloutString(2));
  494. // All as expected, now call the callouts on beta. This should add a
  495. // callout to the list of callouts for alpha, which we should see when
  496. // we run the test again.
  497. getCalloutManager()->callCallouts(beta_index_, callout_handle_1);
  498. // Use a new callout handle so as to get fresh callout context.
  499. CalloutHandle callout_handle_2(getCalloutManager());
  500. callout_handle_2.setArgument("handle_num", static_cast<int>(2));
  501. getCalloutManager()->callCallouts(alpha_index_, callout_handle_2);
  502. zero_results();
  503. getCalloutManager()->callCallouts(delta_index_, callout_handle_2);
  504. EXPECT_EQ("112", resultCalloutString(0));
  505. EXPECT_EQ("212782", resultCalloutString(1));
  506. EXPECT_EQ("312", resultCalloutString(2));
  507. }
  508. // Check that a callout can register another callout on the same hook.
  509. // Note that the registration only applies to a subsequent invocation of
  510. // callCallouts, not to the current one. In other words, if
  511. //
  512. // * the callout list for a library is "A then B then C"
  513. // * when callCallouts is executed "B" adds "D" to that list,
  514. //
  515. // ... the current execution of callCallouts only executes A, B and C. A
  516. // subsequent invocation will execute A, B, C then D.
  517. TEST_F(HandlesTest, DynamicRegistrationSameHook) {
  518. // Register callouts for the different libraries.
  519. CalloutHandle handle(getCalloutManager());
  520. // Set up callouts on "alpha".
  521. getCalloutManager()->setLibraryIndex(0);
  522. getCalloutManager()->registerCallout("alpha", callout11);
  523. getCalloutManager()->registerCallout("alpha", add_callout78_alpha);
  524. getCalloutManager()->registerCallout("delta", print1);
  525. // See what we get for calling the callouts on alpha first.
  526. CalloutHandle callout_handle_1(getCalloutManager());
  527. callout_handle_1.setArgument("handle_num", static_cast<int>(1));
  528. getCalloutManager()->callCallouts(alpha_index_, callout_handle_1);
  529. zero_results();
  530. getCalloutManager()->callCallouts(delta_index_, callout_handle_1);
  531. EXPECT_EQ("111", resultCalloutString(0));
  532. // Run it again - we should have added something to this hook.
  533. CalloutHandle callout_handle_2(getCalloutManager());
  534. callout_handle_2.setArgument("handle_num", static_cast<int>(2));
  535. getCalloutManager()->callCallouts(alpha_index_, callout_handle_2);
  536. zero_results();
  537. getCalloutManager()->callCallouts(delta_index_, callout_handle_2);
  538. EXPECT_EQ("112782", resultCalloutString(0));
  539. // And a third time...
  540. CalloutHandle callout_handle_3(getCalloutManager());
  541. callout_handle_3.setArgument("handle_num", static_cast<int>(3));
  542. getCalloutManager()->callCallouts(alpha_index_, callout_handle_3);
  543. zero_results();
  544. getCalloutManager()->callCallouts(delta_index_, callout_handle_3);
  545. EXPECT_EQ("113783783", resultCalloutString(0));
  546. }
  547. // Deregistration of a callout from a different hook
  548. TEST_F(HandlesTest, DynamicDeregistrationDifferentHook) {
  549. // Register callouts for the different libraries.
  550. CalloutHandle handle(getCalloutManager());
  551. // Set up callouts on "alpha".
  552. getCalloutManager()->setLibraryIndex(0);
  553. getCalloutManager()->registerCallout("alpha", callout11);
  554. getCalloutManager()->registerCallout("alpha", callout78);
  555. getCalloutManager()->registerCallout("alpha", callout11);
  556. getCalloutManager()->registerCallout("delta", print1);
  557. getCalloutManager()->registerCallout("beta", delete_callout78_alpha);
  558. // Call the callouts on alpha
  559. CalloutHandle callout_handle_1(getCalloutManager());
  560. callout_handle_1.setArgument("handle_num", static_cast<int>(1));
  561. getCalloutManager()->callCallouts(alpha_index_, callout_handle_1);
  562. zero_results();
  563. getCalloutManager()->callCallouts(delta_index_, callout_handle_1);
  564. EXPECT_EQ("111781111", resultCalloutString(0));
  565. // Run the callouts on hook beta to remove the callout on alpha.
  566. getCalloutManager()->callCallouts(beta_index_, callout_handle_1);
  567. // The run of the callouts should have altered the callout list on the
  568. // first library for hook alpha, so call again to make sure.
  569. CalloutHandle callout_handle_2(getCalloutManager());
  570. callout_handle_2.setArgument("handle_num", static_cast<int>(2));
  571. getCalloutManager()->callCallouts(alpha_index_, callout_handle_2);
  572. zero_results();
  573. getCalloutManager()->callCallouts(delta_index_, callout_handle_2);
  574. EXPECT_EQ("112112", resultCalloutString(0));
  575. }
  576. // Deregistration of a callout from the same hook
  577. TEST_F(HandlesTest, DynamicDeregistrationSameHook) {
  578. // Register callouts for the different libraries.
  579. CalloutHandle handle(getCalloutManager());
  580. // Set up callouts on "alpha".
  581. getCalloutManager()->setLibraryIndex(0);
  582. getCalloutManager()->registerCallout("alpha", callout11);
  583. getCalloutManager()->registerCallout("alpha", delete_callout78_alpha);
  584. getCalloutManager()->registerCallout("alpha", callout78);
  585. getCalloutManager()->registerCallout("delta", print1);
  586. getCalloutManager()->setLibraryIndex(1);
  587. getCalloutManager()->registerCallout("alpha", callout21);
  588. getCalloutManager()->registerCallout("alpha", callout78);
  589. getCalloutManager()->registerCallout("delta", print2);
  590. // Call the callouts on alpha
  591. CalloutHandle callout_handle_1(getCalloutManager());
  592. callout_handle_1.setArgument("handle_num", static_cast<int>(1));
  593. getCalloutManager()->callCallouts(alpha_index_, callout_handle_1);
  594. zero_results();
  595. getCalloutManager()->callCallouts(delta_index_, callout_handle_1);
  596. EXPECT_EQ("111781", resultCalloutString(0));
  597. EXPECT_EQ("211781", resultCalloutString(1));
  598. // The run of the callouts should have altered the callout list on the
  599. // first library for hook alpha, so call again to make sure.
  600. CalloutHandle callout_handle_2(getCalloutManager());
  601. callout_handle_2.setArgument("handle_num", static_cast<int>(2));
  602. getCalloutManager()->callCallouts(alpha_index_, callout_handle_2);
  603. zero_results();
  604. getCalloutManager()->callCallouts(delta_index_, callout_handle_2);
  605. EXPECT_EQ("112", resultCalloutString(0));
  606. EXPECT_EQ("212782", resultCalloutString(1));
  607. }
  608. // Testing the operation of the "skip" flag. Callouts print the value
  609. // they see in the flag and either leave it unchanged, set it or clear it.
  610. int
  611. calloutPrintSkip(CalloutHandle& handle) {
  612. static const std::string YES("Y");
  613. static const std::string NO("N");
  614. static const std::string DROP("D");
  615. switch (handle.getStatus()) {
  616. case CalloutHandle::NEXT_STEP_CONTINUE:
  617. HandlesTest::common_string_ += NO; // skip = no
  618. break;
  619. case CalloutHandle::NEXT_STEP_SKIP:
  620. HandlesTest::common_string_ += YES; // skip = yes
  621. break;
  622. case CalloutHandle::NEXT_STEP_DROP:
  623. HandlesTest::common_string_ += DROP; // drop
  624. break;
  625. }
  626. return (0);
  627. }
  628. int
  629. calloutSetSkip(CalloutHandle& handle) {
  630. static_cast<void>(calloutPrintSkip(handle));
  631. handle.setStatus(CalloutHandle::NEXT_STEP_SKIP);
  632. return (0);
  633. }
  634. int
  635. calloutClearSkip(CalloutHandle& handle) {
  636. static_cast<void>(calloutPrintSkip(handle));
  637. handle.setStatus(CalloutHandle::NEXT_STEP_CONTINUE);
  638. return (0);
  639. }
  640. // Do a series of tests, returning with the skip flag set "true".
  641. TEST_F(HandlesTest, ReturnSkipSet) {
  642. getCalloutManager()->setLibraryIndex(0);
  643. getCalloutManager()->registerCallout("alpha", calloutPrintSkip);
  644. getCalloutManager()->registerCallout("alpha", calloutSetSkip);
  645. getCalloutManager()->registerCallout("alpha", calloutSetSkip);
  646. getCalloutManager()->registerCallout("alpha", calloutClearSkip);
  647. getCalloutManager()->setLibraryIndex(1);
  648. getCalloutManager()->registerCallout("alpha", calloutPrintSkip);
  649. getCalloutManager()->registerCallout("alpha", calloutSetSkip);
  650. getCalloutManager()->registerCallout("alpha", calloutSetSkip);
  651. getCalloutManager()->registerCallout("alpha", calloutClearSkip);
  652. getCalloutManager()->registerCallout("alpha", calloutClearSkip);
  653. getCalloutManager()->setLibraryIndex(2);
  654. getCalloutManager()->registerCallout("alpha", calloutPrintSkip);
  655. getCalloutManager()->registerCallout("alpha", calloutSetSkip);
  656. getCalloutManager()->registerCallout("alpha", calloutClearSkip);
  657. getCalloutManager()->registerCallout("alpha", calloutSetSkip);
  658. CalloutHandle callout_handle(getCalloutManager());
  659. getCalloutManager()->callCallouts(alpha_index_, callout_handle);
  660. // Check result. For each of visual checking, the expected string is
  661. // divided into sections corresponding to the blocks of callouts above.
  662. EXPECT_EQ(std::string("NNYY" "NNYYN" "NNYN"), common_string_);
  663. // ... and check that the skip flag on exit from callCallouts is set.
  664. EXPECT_EQ(CalloutHandle::NEXT_STEP_SKIP, callout_handle.getStatus());
  665. }
  666. // Repeat the test, returning with the skip flag clear.
  667. TEST_F(HandlesTest, ReturnSkipClear) {
  668. getCalloutManager()->setLibraryIndex(0);
  669. getCalloutManager()->registerCallout("alpha", calloutSetSkip);
  670. getCalloutManager()->registerCallout("alpha", calloutSetSkip);
  671. getCalloutManager()->registerCallout("alpha", calloutClearSkip);
  672. getCalloutManager()->setLibraryIndex(1);
  673. getCalloutManager()->registerCallout("alpha", calloutPrintSkip);
  674. getCalloutManager()->registerCallout("alpha", calloutSetSkip);
  675. getCalloutManager()->registerCallout("alpha", calloutClearSkip);
  676. getCalloutManager()->registerCallout("alpha", calloutSetSkip);
  677. getCalloutManager()->registerCallout("alpha", calloutClearSkip);
  678. getCalloutManager()->registerCallout("alpha", calloutClearSkip);
  679. getCalloutManager()->setLibraryIndex(2);
  680. getCalloutManager()->registerCallout("alpha", calloutClearSkip);
  681. getCalloutManager()->registerCallout("alpha", calloutPrintSkip);
  682. getCalloutManager()->registerCallout("alpha", calloutSetSkip);
  683. getCalloutManager()->registerCallout("alpha", calloutClearSkip);
  684. CalloutHandle callout_handle(getCalloutManager());
  685. getCalloutManager()->callCallouts(alpha_index_, callout_handle);
  686. // Check result. For each of visual checking, the expected string is
  687. // divided into sections corresponding to the blocks of callouts above.
  688. EXPECT_EQ(std::string("NYY" "NNYNYN" "NNNY"), common_string_);
  689. // ... and check that the skip flag on exit from callCallouts is set.
  690. EXPECT_EQ(CalloutHandle::NEXT_STEP_CONTINUE, callout_handle.getStatus());
  691. }
  692. // Check that the skip flag is cleared when callouts are called - even if
  693. // there are no callouts.
  694. TEST_F(HandlesTest, NoCalloutsSkipTest) {
  695. // Note - no callouts are registered on any hook.
  696. CalloutHandle callout_handle(getCalloutManager());
  697. // Clear the skip flag and call a hook with no callouts.
  698. callout_handle.setStatus(CalloutHandle::NEXT_STEP_CONTINUE);
  699. getCalloutManager()->callCallouts(alpha_index_, callout_handle);
  700. EXPECT_EQ(CalloutHandle::NEXT_STEP_CONTINUE, callout_handle.getStatus());
  701. // Set the skip flag and call a hook with no callouts.
  702. callout_handle.setStatus(CalloutHandle::NEXT_STEP_SKIP);
  703. getCalloutManager()->callCallouts(alpha_index_, callout_handle);
  704. EXPECT_EQ(CalloutHandle::NEXT_STEP_CONTINUE, callout_handle.getStatus());
  705. }
  706. // The next set of callouts do a similar thing to the above "skip" tests,
  707. // but alter the value of a string argument. This is for testing that the
  708. // a callout is able to change an argument and return it to the caller.
  709. const char* MODIFIED_ARG = "modified_arg";
  710. int
  711. calloutSetArgumentCommon(CalloutHandle& handle, const char* what) {
  712. std::string modified_arg = "";
  713. handle.getArgument(MODIFIED_ARG, modified_arg);
  714. modified_arg = modified_arg + std::string(what);
  715. handle.setArgument(MODIFIED_ARG, modified_arg);
  716. return (0);
  717. }
  718. int
  719. calloutSetArgumentYes(CalloutHandle& handle) {
  720. return (calloutSetArgumentCommon(handle, "Y"));
  721. }
  722. int
  723. calloutSetArgumentNo(CalloutHandle& handle) {
  724. return (calloutSetArgumentCommon(handle, "N"));
  725. }
  726. // ... and a callout to just copy the argument to the "common_string_" variable
  727. // but otherwise not alter it.
  728. int
  729. calloutPrintArgument(CalloutHandle& handle) {
  730. handle.getArgument(MODIFIED_ARG, HandlesTest::common_string_);
  731. return (0);
  732. }
  733. TEST_F(HandlesTest, CheckModifiedArgument) {
  734. getCalloutManager()->setLibraryIndex(0);
  735. getCalloutManager()->registerCallout("alpha", calloutSetArgumentYes);
  736. getCalloutManager()->registerCallout("alpha", calloutSetArgumentNo);
  737. getCalloutManager()->registerCallout("alpha", calloutSetArgumentNo);
  738. getCalloutManager()->setLibraryIndex(1);
  739. getCalloutManager()->registerCallout("alpha", calloutSetArgumentYes);
  740. getCalloutManager()->registerCallout("alpha", calloutSetArgumentYes);
  741. getCalloutManager()->registerCallout("alpha", calloutPrintArgument);
  742. getCalloutManager()->registerCallout("alpha", calloutSetArgumentNo);
  743. getCalloutManager()->registerCallout("alpha", calloutSetArgumentNo);
  744. getCalloutManager()->setLibraryIndex(2);
  745. getCalloutManager()->registerCallout("alpha", calloutSetArgumentYes);
  746. getCalloutManager()->registerCallout("alpha", calloutSetArgumentNo);
  747. getCalloutManager()->registerCallout("alpha", calloutSetArgumentYes);
  748. // Create the argument with an initial empty string value. Then call the
  749. // sequence of callouts above.
  750. CalloutHandle callout_handle(getCalloutManager());
  751. std::string modified_arg = "";
  752. callout_handle.setArgument(MODIFIED_ARG, modified_arg);
  753. getCalloutManager()->callCallouts(alpha_index_, callout_handle);
  754. // Check the intermediate and results. For visual checking, the expected
  755. // string is divided into sections corresponding to the blocks of callouts
  756. // above.
  757. EXPECT_EQ(std::string("YNN" "YY"), common_string_);
  758. callout_handle.getArgument(MODIFIED_ARG, modified_arg);
  759. EXPECT_EQ(std::string("YNN" "YYNN" "YNY"), modified_arg);
  760. }
  761. // Test that the CalloutHandle provides the name of the hook to which the
  762. // callout is attached.
  763. int
  764. callout_hook_name(CalloutHandle& callout_handle) {
  765. HandlesTest::common_string_ = callout_handle.getHookName();
  766. return (0);
  767. }
  768. int
  769. callout_hook_dummy(CalloutHandle&) {
  770. return (0);
  771. }
  772. TEST_F(HandlesTest, HookName) {
  773. getCalloutManager()->setLibraryIndex(0);
  774. getCalloutManager()->registerCallout("alpha", callout_hook_name);
  775. getCalloutManager()->registerCallout("beta", callout_hook_name);
  776. // Call alpha and beta callouts and check the hook to which they belong.
  777. CalloutHandle callout_handle(getCalloutManager());
  778. EXPECT_EQ(std::string(""), HandlesTest::common_string_);
  779. getCalloutManager()->callCallouts(alpha_index_, callout_handle);
  780. EXPECT_EQ(std::string("alpha"), HandlesTest::common_string_);
  781. getCalloutManager()->callCallouts(beta_index_, callout_handle);
  782. EXPECT_EQ(std::string("beta"), HandlesTest::common_string_);
  783. // Make sure that the callout accesses the name even if it is not the
  784. // only callout in the list.
  785. getCalloutManager()->setLibraryIndex(1);
  786. getCalloutManager()->registerCallout("gamma", callout_hook_dummy);
  787. getCalloutManager()->registerCallout("gamma", callout_hook_name);
  788. getCalloutManager()->registerCallout("gamma", callout_hook_dummy);
  789. EXPECT_EQ(std::string("beta"), HandlesTest::common_string_);
  790. getCalloutManager()->callCallouts(gamma_index_, callout_handle);
  791. EXPECT_EQ(std::string("gamma"), HandlesTest::common_string_);
  792. }
  793. } // Anonymous namespace