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