testing_api_cmd_reserve_get.c (9957B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2014-2022 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_reserve_get.c 21 * @brief Implement the GET /reserve/$RID test command. 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 "poll" CMD. 31 */ 32 struct PollState 33 { 34 35 /** 36 * How long do we give the exchange to respond? 37 */ 38 struct GNUNET_TIME_Relative timeout; 39 40 /** 41 * Label to the command which created the reserve to check, 42 * needed to resort the reserve key. 43 */ 44 const char *poll_reference; 45 46 /** 47 * Timeout to wait for at most. 48 */ 49 struct GNUNET_SCHEDULER_Task *tt; 50 51 /** 52 * The interpreter we are using. 53 */ 54 struct TALER_TESTING_Interpreter *is; 55 }; 56 57 58 /** 59 * State for a "status" CMD. 60 */ 61 struct StatusState 62 { 63 64 /** 65 * How long do we give the exchange to respond? 66 */ 67 struct GNUNET_TIME_Relative timeout; 68 69 /** 70 * Poller waiting for us. 71 */ 72 struct PollState *ps; 73 74 /** 75 * Label to the command which created the reserve to check, 76 * needed to resort the reserve key. 77 */ 78 const char *reserve_reference; 79 80 /** 81 * Handle to the "reserve status" operation. 82 */ 83 struct TALER_EXCHANGE_GetReservesHandle *rsh; 84 85 /** 86 * Expected reserve balance. 87 */ 88 const char *expected_balance; 89 90 /** 91 * Public key of the reserve being analyzed. 92 */ 93 const struct TALER_ReservePublicKeyP *reserve_pubp; 94 95 /** 96 * Expected HTTP response code. 97 */ 98 unsigned int expected_response_code; 99 100 /** 101 * Interpreter state. 102 */ 103 struct TALER_TESTING_Interpreter *is; 104 105 }; 106 107 108 /** 109 * Check that the reserve balance and HTTP response code are 110 * both acceptable. 111 * 112 * @param cls closure. 113 * @param rs HTTP response details 114 */ 115 static void 116 reserve_status_cb (void *cls, 117 const struct TALER_EXCHANGE_GetReservesResponse *rs) 118 { 119 struct StatusState *ss = cls; 120 struct TALER_TESTING_Interpreter *is = ss->is; 121 struct TALER_Amount eb; 122 123 ss->rsh = NULL; 124 if (ss->expected_response_code != rs->hr.http_status) 125 { 126 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 127 "Unexpected HTTP response code: %d in %s:%u\n", 128 rs->hr.http_status, 129 __FILE__, 130 __LINE__); 131 json_dumpf (rs->hr.reply, 132 stderr, 133 0); 134 TALER_TESTING_interpreter_fail (ss->is); 135 return; 136 } 137 if (MHD_HTTP_OK == ss->expected_response_code) 138 { 139 GNUNET_assert (GNUNET_OK == 140 TALER_string_to_amount (ss->expected_balance, 141 &eb)); 142 if (0 != TALER_amount_cmp (&eb, 143 &rs->details.ok.balance)) 144 { 145 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 146 "Unexpected amount %s in reserve, wanted %s\n", 147 TALER_amount_to_string (&rs->details.ok.balance), 148 ss->expected_balance); 149 TALER_TESTING_interpreter_fail (ss->is); 150 return; 151 } 152 } 153 if (NULL != ss->ps) 154 { 155 /* force continuation on long poller */ 156 GNUNET_SCHEDULER_cancel (ss->ps->tt); 157 ss->ps->tt = NULL; 158 TALER_TESTING_interpreter_next (is); 159 return; 160 } 161 if (GNUNET_TIME_relative_is_zero (ss->timeout)) 162 TALER_TESTING_interpreter_next (is); 163 } 164 165 166 /** 167 * Run the command. 168 * 169 * @param cls closure. 170 * @param cmd the command being executed. 171 * @param is the interpreter state. 172 */ 173 static void 174 status_run (void *cls, 175 const struct TALER_TESTING_Command *cmd, 176 struct TALER_TESTING_Interpreter *is) 177 { 178 struct StatusState *ss = cls; 179 const struct TALER_TESTING_Command *create_reserve; 180 const char *exchange_url; 181 182 ss->is = is; 183 exchange_url = TALER_TESTING_get_exchange_url (is); 184 if (NULL == exchange_url) 185 { 186 GNUNET_break (0); 187 return; 188 } 189 create_reserve 190 = TALER_TESTING_interpreter_lookup_command (is, 191 ss->reserve_reference); 192 GNUNET_assert (NULL != create_reserve); 193 if (GNUNET_OK != 194 TALER_TESTING_get_trait_reserve_pub (create_reserve, 195 &ss->reserve_pubp)) 196 { 197 GNUNET_break (0); 198 TALER_LOG_ERROR ("Failed to find reserve_pub for status query\n"); 199 TALER_TESTING_interpreter_fail (is); 200 return; 201 } 202 ss->rsh = TALER_EXCHANGE_get_reserves_create ( 203 TALER_TESTING_interpreter_get_context (is), 204 exchange_url, 205 ss->reserve_pubp); 206 if (NULL == ss->rsh) 207 { 208 GNUNET_break (0); 209 TALER_TESTING_interpreter_fail (is); 210 return; 211 } 212 if (! GNUNET_TIME_relative_is_zero (ss->timeout)) 213 TALER_EXCHANGE_get_reserves_set_options ( 214 ss->rsh, 215 TALER_EXCHANGE_get_reserves_option_timeout (ss->timeout)); 216 if (TALER_EC_NONE != 217 TALER_EXCHANGE_get_reserves_start (ss->rsh, 218 &reserve_status_cb, 219 ss)) 220 { 221 GNUNET_break (0); 222 TALER_EXCHANGE_get_reserves_cancel (ss->rsh); 223 ss->rsh = NULL; 224 TALER_TESTING_interpreter_fail (is); 225 return; 226 } 227 if (! GNUNET_TIME_relative_is_zero (ss->timeout)) 228 { 229 TALER_TESTING_interpreter_next (is); 230 return; 231 } 232 } 233 234 235 /** 236 * Cleanup the state from a "reserve status" CMD, and possibly 237 * cancel a pending operation thereof. 238 * 239 * @param cls closure. 240 * @param cmd the command which is being cleaned up. 241 */ 242 static void 243 status_cleanup (void *cls, 244 const struct TALER_TESTING_Command *cmd) 245 { 246 struct StatusState *ss = cls; 247 248 if (NULL != ss->rsh) 249 { 250 TALER_TESTING_command_incomplete (ss->is, 251 cmd->label); 252 TALER_EXCHANGE_get_reserves_cancel (ss->rsh); 253 ss->rsh = NULL; 254 } 255 GNUNET_free (ss); 256 } 257 258 259 struct TALER_TESTING_Command 260 TALER_TESTING_cmd_status (const char *label, 261 const char *reserve_reference, 262 const char *expected_balance, 263 unsigned int expected_response_code) 264 { 265 struct StatusState *ss; 266 267 GNUNET_assert (NULL != reserve_reference); 268 ss = GNUNET_new (struct StatusState); 269 ss->reserve_reference = reserve_reference; 270 ss->expected_balance = expected_balance; 271 ss->expected_response_code = expected_response_code; 272 { 273 struct TALER_TESTING_Command cmd = { 274 .cls = ss, 275 .label = label, 276 .run = &status_run, 277 .cleanup = &status_cleanup 278 }; 279 280 return cmd; 281 } 282 } 283 284 285 struct TALER_TESTING_Command 286 TALER_TESTING_cmd_reserve_poll (const char *label, 287 const char *reserve_reference, 288 const char *expected_balance, 289 struct GNUNET_TIME_Relative timeout, 290 unsigned int expected_response_code) 291 { 292 struct StatusState *ss; 293 294 GNUNET_assert (NULL != reserve_reference); 295 ss = GNUNET_new (struct StatusState); 296 ss->reserve_reference = reserve_reference; 297 ss->expected_balance = expected_balance; 298 ss->expected_response_code = expected_response_code; 299 ss->timeout = timeout; 300 { 301 struct TALER_TESTING_Command cmd = { 302 .cls = ss, 303 .label = label, 304 .run = &status_run, 305 .cleanup = &status_cleanup 306 }; 307 308 return cmd; 309 } 310 } 311 312 313 /** 314 * Long poller timed out. Fail the test. 315 * 316 * @param cls a `struct PollState` 317 */ 318 static void 319 finish_timeout (void *cls) 320 { 321 struct PollState *ps = cls; 322 323 ps->tt = NULL; 324 GNUNET_break (0); 325 TALER_TESTING_interpreter_fail (ps->is); 326 } 327 328 329 /** 330 * Run the command. 331 * 332 * @param cls closure. 333 * @param cmd the command being executed. 334 * @param is the interpreter state. 335 */ 336 static void 337 finish_run (void *cls, 338 const struct TALER_TESTING_Command *cmd, 339 struct TALER_TESTING_Interpreter *is) 340 { 341 struct PollState *ps = cls; 342 const struct TALER_TESTING_Command *poll_reserve; 343 struct StatusState *ss; 344 345 ps->is = is; 346 poll_reserve 347 = TALER_TESTING_interpreter_lookup_command (is, 348 ps->poll_reference); 349 GNUNET_assert (NULL != poll_reserve); 350 GNUNET_assert (poll_reserve->run == &status_run); 351 ss = poll_reserve->cls; 352 if (NULL == ss->rsh) 353 { 354 TALER_TESTING_interpreter_next (is); 355 return; 356 } 357 GNUNET_assert (NULL == ss->ps); 358 ss->ps = ps; 359 ps->tt = GNUNET_SCHEDULER_add_delayed (ps->timeout, 360 &finish_timeout, 361 ps); 362 } 363 364 365 /** 366 * Cleanup the state from a "reserve finish" CMD. 367 * 368 * @param cls closure. 369 * @param cmd the command which is being cleaned up. 370 */ 371 static void 372 finish_cleanup (void *cls, 373 const struct TALER_TESTING_Command *cmd) 374 { 375 struct PollState *ps = cls; 376 377 if (NULL != ps->tt) 378 { 379 GNUNET_SCHEDULER_cancel (ps->tt); 380 ps->tt = NULL; 381 } 382 GNUNET_free (ps); 383 } 384 385 386 struct TALER_TESTING_Command 387 TALER_TESTING_cmd_reserve_poll_finish (const char *label, 388 struct GNUNET_TIME_Relative timeout, 389 const char *poll_reference) 390 { 391 struct PollState *ps; 392 393 GNUNET_assert (NULL != poll_reference); 394 ps = GNUNET_new (struct PollState); 395 ps->timeout = timeout; 396 ps->poll_reference = poll_reference; 397 { 398 struct TALER_TESTING_Command cmd = { 399 .cls = ps, 400 .label = label, 401 .run = &finish_run, 402 .cleanup = &finish_cleanup 403 }; 404 405 return cmd; 406 } 407 }