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