testing_api_cmd_batch.c (5745B)
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/platform.h" 25 #include "taler/taler_json_lib.h" 26 #include <gnunet/gnunet_curl_lib.h> 27 #include "taler/taler_testing_lib.h" 28 29 30 /** 31 * State for a "batch" CMD. 32 */ 33 struct BatchState 34 { 35 /** 36 * CMDs batch. 37 */ 38 struct TALER_TESTING_Command *batch; 39 40 /** 41 * My command (the batch command). 42 */ 43 const struct TALER_TESTING_Command *cmd; 44 45 /** 46 * Internal command pointer. 47 */ 48 unsigned int batch_ip; 49 }; 50 51 52 /** 53 * Run the command. 54 * 55 * @param cls closure. 56 * @param cmd the command being executed. 57 * @param is the interpreter state. 58 */ 59 static void 60 batch_run (void *cls, 61 const struct TALER_TESTING_Command *cmd, 62 struct TALER_TESTING_Interpreter *is) 63 { 64 struct BatchState *bs = cls; 65 struct TALER_TESTING_Command *bcmd = &bs->batch[bs->batch_ip]; 66 67 bs->cmd = cmd; 68 if (NULL != bcmd->label) 69 TALER_LOG_INFO ("Running batched command: %s\n", 70 bcmd->label); 71 72 /* hit end command, leap to next top-level command. */ 73 if (NULL == bcmd->label) 74 { 75 TALER_LOG_INFO ("Exiting from batch: %s\n", 76 cmd->label); 77 TALER_TESTING_interpreter_next (is); 78 return; 79 } 80 bcmd->start_time 81 = bcmd->last_req_time 82 = GNUNET_TIME_absolute_get (); 83 bcmd->num_tries++; 84 TALER_TESTING_update_variables_ (is, 85 bcmd); 86 bcmd->run (bcmd->cls, 87 bcmd, 88 is); 89 } 90 91 92 /** 93 * Cleanup the state from a "reserve status" CMD, and possibly 94 * cancel a pending operation thereof. 95 * 96 * @param cls closure. 97 * @param cmd the command which is being cleaned up. 98 */ 99 static void 100 batch_cleanup (void *cls, 101 const struct TALER_TESTING_Command *cmd) 102 { 103 struct BatchState *bs = cls; 104 105 (void) cmd; 106 for (unsigned int i = 0; 107 NULL != bs->batch[i].label; 108 i++) 109 if (NULL != bs->batch[i].cleanup) 110 bs->batch[i].cleanup (bs->batch[i].cls, 111 &bs->batch[i]); 112 GNUNET_free (bs->batch); 113 GNUNET_free (bs); 114 } 115 116 117 /** 118 * Offer internal data from a "batch" CMD, to other commands. 119 * 120 * @param cls closure. 121 * @param[out] ret result. 122 * @param trait name of the trait. 123 * @param index index number of the object to offer. 124 * @return #GNUNET_OK on success. 125 */ 126 static enum GNUNET_GenericReturnValue 127 batch_traits (void *cls, 128 const void **ret, 129 const char *trait, 130 unsigned int index) 131 { 132 struct BatchState *bs = cls; 133 struct TALER_TESTING_Trait traits[] = { 134 TALER_TESTING_make_trait_batch_cmds (bs->batch), 135 TALER_TESTING_trait_end () 136 }; 137 138 /* Always return current command. */ 139 return TALER_TESTING_get_trait (traits, 140 ret, 141 trait, 142 index); 143 } 144 145 146 struct TALER_TESTING_Command 147 TALER_TESTING_cmd_batch (const char *label, 148 struct TALER_TESTING_Command *batch) 149 { 150 struct BatchState *bs; 151 unsigned int i; 152 153 bs = GNUNET_new (struct BatchState); 154 155 /* Get number of commands. */ 156 for (i = 0; NULL != batch[i].label; i++) 157 /* noop */ 158 ; 159 160 bs->batch = GNUNET_new_array (i + 1, 161 struct TALER_TESTING_Command); 162 GNUNET_memcpy (bs->batch, 163 batch, 164 sizeof (struct TALER_TESTING_Command) * i); 165 { 166 struct TALER_TESTING_Command cmd = { 167 .cls = bs, 168 .label = label, 169 .run = &batch_run, 170 .cleanup = &batch_cleanup, 171 .traits = &batch_traits 172 }; 173 174 return cmd; 175 } 176 } 177 178 179 bool 180 TALER_TESTING_cmd_batch_next (struct TALER_TESTING_Interpreter *is, 181 void *cls) 182 { 183 struct BatchState *bs = cls; 184 struct TALER_TESTING_Command *bcmd = &bs->batch[bs->batch_ip]; 185 186 if (NULL == bcmd->label) 187 { 188 /* This batch is done */ 189 return true; 190 } 191 if (TALER_TESTING_cmd_is_batch (bcmd)) 192 { 193 if (TALER_TESTING_cmd_batch_next (is, 194 bcmd->cls)) 195 { 196 /* sub-batch is done */ 197 bcmd->finish_time = GNUNET_TIME_absolute_get (); 198 bs->batch_ip++; 199 return false; 200 } 201 } 202 /* Simple command is done */ 203 bcmd->finish_time = GNUNET_TIME_absolute_get (); 204 bs->batch_ip++; 205 return false; 206 } 207 208 209 bool 210 TALER_TESTING_cmd_is_batch (const struct TALER_TESTING_Command *cmd) 211 { 212 return cmd->run == &batch_run; 213 } 214 215 216 struct TALER_TESTING_Command * 217 TALER_TESTING_cmd_batch_get_current (const struct TALER_TESTING_Command *cmd) 218 { 219 struct BatchState *bs = cmd->cls; 220 221 GNUNET_assert (cmd->run == &batch_run); 222 return &bs->batch[bs->batch_ip]; 223 } 224 225 226 void 227 TALER_TESTING_cmd_batch_set_current (const struct TALER_TESTING_Command *cmd, 228 unsigned int new_ip) 229 { 230 struct BatchState *bs = cmd->cls; 231 232 /* sanity checks */ 233 GNUNET_assert (cmd->run == &batch_run); 234 for (unsigned int i = 0; i < new_ip; i++) 235 GNUNET_assert (NULL != bs->batch[i].label); 236 /* actual logic */ 237 bs->batch_ip = new_ip; 238 }