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