testing_api_cmd_purse_get.c (9028B)
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_purse_get.c 21 * @brief Implement the GET /purse/$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_PURSES_RESULT_CLOSURE struct StatusState 28 #include "taler/exchange/get-purses-PURSE_PUB-merge.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 purse to check, 45 * needed to resort the purse 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 purse to check, 79 * needed to resort the purse key. 80 */ 81 const char *purse_reference; 82 83 /** 84 * Handle to the "purse status" operation. 85 */ 86 struct TALER_EXCHANGE_GetPursesHandle *pgh; 87 88 /** 89 * Expected purse balance. 90 */ 91 const char *expected_balance; 92 93 /** 94 * Public key of the purse being analyzed. 95 */ 96 const struct TALER_PurseContractPublicKeyP *purse_pub; 97 98 /** 99 * Interpreter state. 100 */ 101 struct TALER_TESTING_Interpreter *is; 102 103 /** 104 * Expected HTTP response code. 105 */ 106 unsigned int expected_response_code; 107 108 /** 109 * Are we waiting for a merge or a deposit? 110 */ 111 bool wait_for_merge; 112 113 }; 114 115 116 /** 117 * Check that the purse balance and HTTP response code are 118 * both acceptable. 119 * 120 * @param ss closure. 121 * @param rs HTTP response details 122 */ 123 static void 124 purse_status_cb (struct StatusState *ss, 125 const struct TALER_EXCHANGE_GetPursesResponse *rs) 126 { 127 struct TALER_TESTING_Interpreter *is = ss->is; 128 129 ss->pgh = NULL; 130 if (ss->expected_response_code != rs->hr.http_status) 131 { 132 TALER_TESTING_unexpected_status (is, 133 rs->hr.http_status, 134 ss->expected_response_code); 135 return; 136 } 137 if (MHD_HTTP_OK == ss->expected_response_code) 138 { 139 struct TALER_Amount eb; 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 in purse: %s\n", 149 TALER_amount_to_string (&rs->details.ok.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_purse; 181 182 ss->is = is; 183 create_purse 184 = TALER_TESTING_interpreter_lookup_command (is, 185 ss->purse_reference); 186 GNUNET_assert (NULL != create_purse); 187 if (GNUNET_OK != 188 TALER_TESTING_get_trait_purse_pub (create_purse, 189 &ss->purse_pub)) 190 { 191 GNUNET_break (0); 192 TALER_LOG_ERROR ("Failed to find purse_pub for status query\n"); 193 TALER_TESTING_interpreter_fail (is); 194 return; 195 } 196 ss->pgh = TALER_EXCHANGE_get_purses_create ( 197 TALER_TESTING_interpreter_get_context (is), 198 TALER_TESTING_get_exchange_url (is), 199 TALER_TESTING_get_keys (is), 200 ss->purse_pub); 201 if (NULL == ss->pgh) 202 { 203 GNUNET_break (0); 204 TALER_TESTING_interpreter_fail (is); 205 return; 206 } 207 TALER_EXCHANGE_get_purses_set_options ( 208 ss->pgh, 209 TALER_EXCHANGE_get_purses_option_timeout (ss->timeout), 210 TALER_EXCHANGE_get_purses_option_wait_for_merge (ss->wait_for_merge)); 211 if (TALER_EC_NONE != 212 TALER_EXCHANGE_get_purses_start (ss->pgh, 213 &purse_status_cb, 214 ss)) 215 { 216 GNUNET_break (0); 217 TALER_EXCHANGE_get_purses_cancel (ss->pgh); 218 ss->pgh = NULL; 219 TALER_TESTING_interpreter_fail (is); 220 return; 221 } 222 if (! GNUNET_TIME_relative_is_zero (ss->timeout)) 223 { 224 TALER_TESTING_interpreter_next (is); 225 return; 226 } 227 } 228 229 230 /** 231 * Cleanup the state from a "purse status" CMD, and possibly 232 * cancel a pending operation thereof. 233 * 234 * @param cls closure. 235 * @param cmd the command which is being cleaned up. 236 */ 237 static void 238 status_cleanup (void *cls, 239 const struct TALER_TESTING_Command *cmd) 240 { 241 struct StatusState *ss = cls; 242 243 if (NULL != ss->pgh) 244 { 245 TALER_TESTING_command_incomplete (ss->is, 246 cmd->label); 247 TALER_EXCHANGE_get_purses_cancel (ss->pgh); 248 ss->pgh = NULL; 249 } 250 GNUNET_free (ss); 251 } 252 253 254 struct TALER_TESTING_Command 255 TALER_TESTING_cmd_purse_poll ( 256 const char *label, 257 unsigned int expected_http_status, 258 const char *purse_ref, 259 const char *expected_balance, 260 bool wait_for_merge, 261 struct GNUNET_TIME_Relative timeout) 262 { 263 struct StatusState *ss; 264 265 GNUNET_assert (NULL != purse_ref); 266 ss = GNUNET_new (struct StatusState); 267 ss->purse_reference = purse_ref; 268 ss->expected_balance = expected_balance; 269 ss->expected_response_code = expected_http_status; 270 ss->timeout = timeout; 271 ss->wait_for_merge = wait_for_merge; 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 /** 286 * Long poller timed out. Fail the test. 287 * 288 * @param cls a `struct PollState` 289 */ 290 static void 291 finish_timeout (void *cls) 292 { 293 struct PollState *ps = cls; 294 295 ps->tt = NULL; 296 GNUNET_break (0); 297 TALER_TESTING_interpreter_fail (ps->is); 298 } 299 300 301 /** 302 * Run the command. 303 * 304 * @param cls closure. 305 * @param cmd the command being executed. 306 * @param is the interpreter state. 307 */ 308 static void 309 finish_run (void *cls, 310 const struct TALER_TESTING_Command *cmd, 311 struct TALER_TESTING_Interpreter *is) 312 { 313 struct PollState *ps = cls; 314 const struct TALER_TESTING_Command *poll_purse; 315 struct StatusState *ss; 316 317 ps->is = is; 318 poll_purse 319 = TALER_TESTING_interpreter_lookup_command (is, 320 ps->poll_reference); 321 GNUNET_assert (NULL != poll_purse); 322 GNUNET_assert (poll_purse->run == &status_run); 323 ss = poll_purse->cls; 324 if (NULL == ss->pgh) 325 { 326 TALER_TESTING_interpreter_next (is); 327 return; 328 } 329 GNUNET_assert (NULL == ss->ps); 330 ss->ps = ps; 331 ps->tt = GNUNET_SCHEDULER_add_delayed (ps->timeout, 332 &finish_timeout, 333 ps); 334 } 335 336 337 /** 338 * Cleanup the state from a "purse finish" CMD. 339 * 340 * @param cls closure. 341 * @param cmd the command which is being cleaned up. 342 */ 343 static void 344 finish_cleanup (void *cls, 345 const struct TALER_TESTING_Command *cmd) 346 { 347 struct PollState *ps = cls; 348 349 if (NULL != ps->tt) 350 { 351 GNUNET_SCHEDULER_cancel (ps->tt); 352 ps->tt = NULL; 353 } 354 GNUNET_free (ps); 355 } 356 357 358 struct TALER_TESTING_Command 359 TALER_TESTING_cmd_purse_poll_finish (const char *label, 360 struct GNUNET_TIME_Relative timeout, 361 const char *poll_reference) 362 { 363 struct PollState *ps; 364 365 GNUNET_assert (NULL != poll_reference); 366 ps = GNUNET_new (struct PollState); 367 ps->timeout = timeout; 368 ps->poll_reference = poll_reference; 369 { 370 struct TALER_TESTING_Command cmd = { 371 .cls = ps, 372 .label = label, 373 .run = &finish_run, 374 .cleanup = &finish_cleanup 375 }; 376 377 return cmd; 378 } 379 }