testing_api_cmd_batch.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. /*
  2. This file is part of GNUnet
  3. Copyright (C) 2021 GNUnet e.V.
  4. GNUnet is free software: you can redistribute it and/or modify it
  5. under the terms of the GNU Affero General Public License as published
  6. by the Free Software Foundation, either version 3 of the License,
  7. or (at your option) any later version.
  8. GNUnet is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Affero General Public License for more details.
  12. You should have received a copy of the GNU Affero General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. SPDX-License-Identifier: AGPL3.0-or-later
  15. */
  16. /**
  17. * @file testing/testing_api_cmd_batch.c
  18. * @brief Implement batch-execution of CMDs.
  19. * @author Marcello Stanisci (GNU Taler testing)
  20. * @author t3sserakt
  21. */
  22. #include "platform.h"
  23. #include "gnunet_testing_ng_lib.h"
  24. #include "testing.h"
  25. /**
  26. * State for a "batch" CMD.
  27. */
  28. struct BatchState
  29. {
  30. /**
  31. * CMDs batch.
  32. */
  33. struct GNUNET_TESTING_Command *batch;
  34. /**
  35. * Internal command pointer.
  36. */
  37. unsigned int batch_ip;
  38. };
  39. /**
  40. * Run the command.
  41. *
  42. * @param cls closure.
  43. * @param cmd the command being executed.
  44. * @param is the interpreter state.
  45. */
  46. static void
  47. batch_run (void *cls,
  48. const struct GNUNET_TESTING_Command *cmd,
  49. struct GNUNET_TESTING_Interpreter *is)
  50. {
  51. struct BatchState *bs = cls;
  52. if (NULL != bs->batch[bs->batch_ip].label)
  53. GNUNET_log (GNUNET_ERROR_TYPE_INFO,
  54. "Running batched command: %s\n",
  55. bs->batch[bs->batch_ip].label);
  56. /* hit end command, leap to next top-level command. */
  57. if (NULL == bs->batch[bs->batch_ip].label)
  58. {
  59. GNUNET_log (GNUNET_ERROR_TYPE_INFO,
  60. "Exiting from batch: %s\n",
  61. cmd->label);
  62. return;
  63. }
  64. bs->batch[bs->batch_ip].start_time
  65. = bs->batch[bs->batch_ip].last_req_time
  66. = GNUNET_TIME_absolute_get ();
  67. bs->batch[bs->batch_ip].num_tries = 1;
  68. bs->batch[bs->batch_ip].run (bs->batch[bs->batch_ip].cls,
  69. &bs->batch[bs->batch_ip],
  70. is);
  71. }
  72. /**
  73. * Cleanup the state from a "reserve status" CMD, and possibly
  74. * cancel a pending operation thereof.
  75. *
  76. * @param cls closure.
  77. * @param cmd the command which is being cleaned up.
  78. */
  79. static void
  80. batch_cleanup (void *cls,
  81. const struct GNUNET_TESTING_Command *cmd)
  82. {
  83. struct BatchState *bs = cls;
  84. (void) cmd;
  85. for (unsigned int i = 0;
  86. NULL != bs->batch[i].label;
  87. i++)
  88. bs->batch[i].cleanup (bs->batch[i].cls,
  89. &bs->batch[i]);
  90. GNUNET_free (bs->batch);
  91. GNUNET_free (bs);
  92. }
  93. /**
  94. * Offer internal data from a "batch" CMD, to other commands.
  95. *
  96. * @param cls closure.
  97. * @param[out] ret result.
  98. * @param trait name of the trait.
  99. * @param index index number of the object to offer.
  100. * @return #GNUNET_OK on success.
  101. */
  102. static int
  103. batch_traits (void *cls,
  104. const void **ret,
  105. const char *trait,
  106. unsigned int index)
  107. {
  108. #define CURRENT_CMD_INDEX 0
  109. #define BATCH_INDEX 1
  110. struct BatchState *bs = cls;
  111. struct GNUNET_TESTING_Trait traits[] = {
  112. GNUNET_TESTING_make_trait_cmd
  113. (CURRENT_CMD_INDEX, &bs->batch[bs->batch_ip]),
  114. GNUNET_TESTING_make_trait_cmd
  115. (BATCH_INDEX, bs->batch),
  116. GNUNET_TESTING_trait_end ()
  117. };
  118. /* Always return current command. */
  119. return GNUNET_TESTING_get_trait (traits,
  120. ret,
  121. trait,
  122. index);
  123. }
  124. /**
  125. * Create a "batch" command. Such command takes a
  126. * end_CMD-terminated array of CMDs and executed them.
  127. * Once it hits the end CMD, it passes the control
  128. * to the next top-level CMD, regardless of it being
  129. * another batch or ordinary CMD.
  130. *
  131. * @param label the command label.
  132. * @param batch array of CMDs to execute.
  133. *
  134. * @return the command.
  135. */
  136. struct GNUNET_TESTING_Command
  137. GNUNET_TESTING_cmd_batch (const char *label,
  138. struct GNUNET_TESTING_Command *batch)
  139. {
  140. struct BatchState *bs;
  141. unsigned int i;
  142. bs = GNUNET_new (struct BatchState);
  143. /* Get number of commands. */
  144. for (i = 0; NULL != batch[i].label; i++)
  145. /* noop */
  146. ;
  147. bs->batch = GNUNET_new_array (i + 1,
  148. struct GNUNET_TESTING_Command);
  149. memcpy (bs->batch,
  150. batch,
  151. sizeof (struct GNUNET_TESTING_Command) * i);
  152. {
  153. struct GNUNET_TESTING_Command cmd = {
  154. .cls = bs,
  155. .label = label,
  156. .run = &batch_run,
  157. .cleanup = &batch_cleanup,
  158. .traits = &batch_traits
  159. };
  160. return cmd;
  161. }
  162. }
  163. /**
  164. * Advance internal pointer to next command.
  165. *
  166. * @param is interpreter state.
  167. */
  168. void
  169. GNUNET_TESTING_cmd_batch_next (struct GNUNET_TESTING_Interpreter *is)
  170. {
  171. struct BatchState *bs = is->commands[is->ip].cls;
  172. if (NULL == bs->batch[bs->batch_ip].label)
  173. {
  174. is->commands[is->ip].finish_time = GNUNET_TIME_absolute_get ();
  175. is->ip++;
  176. return;
  177. }
  178. bs->batch[bs->batch_ip].finish_time = GNUNET_TIME_absolute_get ();
  179. bs->batch_ip++;
  180. }
  181. /**
  182. * Test if this command is a batch command.
  183. *
  184. * @return false if not, true if it is a batch command
  185. */
  186. int
  187. GNUNET_TESTING_cmd_is_batch (const struct GNUNET_TESTING_Command *cmd)
  188. {
  189. return cmd->run == &batch_run;
  190. }
  191. /**
  192. * Obtain what command the batch is at.
  193. *
  194. * @return cmd current batch command
  195. */
  196. struct GNUNET_TESTING_Command *
  197. GNUNET_TESTING_cmd_batch_get_current (const struct GNUNET_TESTING_Command *cmd)
  198. {
  199. struct BatchState *bs = cmd->cls;
  200. GNUNET_assert (cmd->run == &batch_run);
  201. return &bs->batch[bs->batch_ip];
  202. }
  203. /**
  204. * Set what command the batch should be at.
  205. *
  206. * @param cmd current batch command
  207. * @param new_ip where to move the IP
  208. */
  209. void
  210. GNUNET_TESTING_cmd_batch_set_current (const struct GNUNET_TESTING_Command *cmd,
  211. unsigned int new_ip)
  212. {
  213. struct BatchState *bs = cmd->cls;
  214. /* sanity checks */
  215. GNUNET_assert (cmd->run == &batch_run);
  216. for (unsigned int i = 0; i < new_ip; i++)
  217. GNUNET_assert (NULL != bs->batch[i].label);
  218. /* actual logic */
  219. bs->batch_ip = new_ip;
  220. }