testing_api_cmd_reserve_get.c (9405B)
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_ReservesGetHandle *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_ReserveSummary *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_reserves_get ( 204 TALER_TESTING_interpreter_get_context (is), 205 exchange_url, 206 ss->reserve_pubp, 207 ss->timeout, 208 &reserve_status_cb, 209 ss); 210 if (! GNUNET_TIME_relative_is_zero (ss->timeout)) 211 { 212 TALER_TESTING_interpreter_next (is); 213 return; 214 } 215 } 216 217 218 /** 219 * Cleanup the state from a "reserve status" CMD, and possibly 220 * cancel a pending operation thereof. 221 * 222 * @param cls closure. 223 * @param cmd the command which is being cleaned up. 224 */ 225 static void 226 status_cleanup (void *cls, 227 const struct TALER_TESTING_Command *cmd) 228 { 229 struct StatusState *ss = cls; 230 231 if (NULL != ss->rsh) 232 { 233 TALER_TESTING_command_incomplete (ss->is, 234 cmd->label); 235 TALER_EXCHANGE_reserves_get_cancel (ss->rsh); 236 ss->rsh = NULL; 237 } 238 GNUNET_free (ss); 239 } 240 241 242 struct TALER_TESTING_Command 243 TALER_TESTING_cmd_status (const char *label, 244 const char *reserve_reference, 245 const char *expected_balance, 246 unsigned int expected_response_code) 247 { 248 struct StatusState *ss; 249 250 GNUNET_assert (NULL != reserve_reference); 251 ss = GNUNET_new (struct StatusState); 252 ss->reserve_reference = reserve_reference; 253 ss->expected_balance = expected_balance; 254 ss->expected_response_code = expected_response_code; 255 { 256 struct TALER_TESTING_Command cmd = { 257 .cls = ss, 258 .label = label, 259 .run = &status_run, 260 .cleanup = &status_cleanup 261 }; 262 263 return cmd; 264 } 265 } 266 267 268 struct TALER_TESTING_Command 269 TALER_TESTING_cmd_reserve_poll (const char *label, 270 const char *reserve_reference, 271 const char *expected_balance, 272 struct GNUNET_TIME_Relative timeout, 273 unsigned int expected_response_code) 274 { 275 struct StatusState *ss; 276 277 GNUNET_assert (NULL != reserve_reference); 278 ss = GNUNET_new (struct StatusState); 279 ss->reserve_reference = reserve_reference; 280 ss->expected_balance = expected_balance; 281 ss->expected_response_code = expected_response_code; 282 ss->timeout = timeout; 283 { 284 struct TALER_TESTING_Command cmd = { 285 .cls = ss, 286 .label = label, 287 .run = &status_run, 288 .cleanup = &status_cleanup 289 }; 290 291 return cmd; 292 } 293 } 294 295 296 /** 297 * Long poller timed out. Fail the test. 298 * 299 * @param cls a `struct PollState` 300 */ 301 static void 302 finish_timeout (void *cls) 303 { 304 struct PollState *ps = cls; 305 306 ps->tt = NULL; 307 GNUNET_break (0); 308 TALER_TESTING_interpreter_fail (ps->is); 309 } 310 311 312 /** 313 * Run the command. 314 * 315 * @param cls closure. 316 * @param cmd the command being executed. 317 * @param is the interpreter state. 318 */ 319 static void 320 finish_run (void *cls, 321 const struct TALER_TESTING_Command *cmd, 322 struct TALER_TESTING_Interpreter *is) 323 { 324 struct PollState *ps = cls; 325 const struct TALER_TESTING_Command *poll_reserve; 326 struct StatusState *ss; 327 328 ps->is = is; 329 poll_reserve 330 = TALER_TESTING_interpreter_lookup_command (is, 331 ps->poll_reference); 332 GNUNET_assert (NULL != poll_reserve); 333 GNUNET_assert (poll_reserve->run == &status_run); 334 ss = poll_reserve->cls; 335 if (NULL == ss->rsh) 336 { 337 TALER_TESTING_interpreter_next (is); 338 return; 339 } 340 GNUNET_assert (NULL == ss->ps); 341 ss->ps = ps; 342 ps->tt = GNUNET_SCHEDULER_add_delayed (ps->timeout, 343 &finish_timeout, 344 ps); 345 } 346 347 348 /** 349 * Cleanup the state from a "reserve finish" CMD. 350 * 351 * @param cls closure. 352 * @param cmd the command which is being cleaned up. 353 */ 354 static void 355 finish_cleanup (void *cls, 356 const struct TALER_TESTING_Command *cmd) 357 { 358 struct PollState *ps = cls; 359 360 if (NULL != ps->tt) 361 { 362 GNUNET_SCHEDULER_cancel (ps->tt); 363 ps->tt = NULL; 364 } 365 GNUNET_free (ps); 366 } 367 368 369 struct TALER_TESTING_Command 370 TALER_TESTING_cmd_reserve_poll_finish (const char *label, 371 struct GNUNET_TIME_Relative timeout, 372 const char *poll_reference) 373 { 374 struct PollState *ps; 375 376 GNUNET_assert (NULL != poll_reference); 377 ps = GNUNET_new (struct PollState); 378 ps->timeout = timeout; 379 ps->poll_reference = poll_reference; 380 { 381 struct TALER_TESTING_Command cmd = { 382 .cls = ps, 383 .label = label, 384 .run = &finish_run, 385 .cleanup = &finish_cleanup 386 }; 387 388 return cmd; 389 } 390 }