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