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