testing_api_cmd_post_transfers.c (13317B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2020, 2023, 2024 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 src/testing/testing_api_cmd_post_transfers.c 21 * @brief command to test POST /transfers 22 * @author Christian Grothoff 23 */ 24 #include "platform.h" 25 struct PostTransfersState; 26 #define TALER_MERCHANT_POST_PRIVATE_TRANSFERS_RESULT_CLOSURE struct PostTransfersState 27 #include <taler/taler_exchange_service.h> 28 #include <taler/taler_testing_lib.h> 29 #include "taler/taler_merchant_service.h" 30 #include "taler/taler_merchant_testing_lib.h" 31 #include <taler/merchant/post-private-transfers.h> 32 33 34 /** 35 * State of a "POST /transfers" CMD. 36 */ 37 struct PostTransfersState 38 { 39 40 /** 41 * Handle for a "POST /transfers" request. 42 */ 43 struct TALER_MERCHANT_PostPrivateTransfersHandle *pth; 44 45 /** 46 * Handle for a "GET" bank account history request. 47 */ 48 struct TALER_BANK_DebitHistoryHandle *dhh; 49 50 /** 51 * The interpreter state. 52 */ 53 struct TALER_TESTING_Interpreter *is; 54 55 /** 56 * Base URL of the merchant serving the request. 57 */ 58 const char *merchant_url; 59 60 /** 61 * URL of the bank to run history on. 62 */ 63 char *exchange_url; 64 65 /** 66 * Credit account of the merchant. 67 */ 68 struct TALER_FullPayto credit_account; 69 70 /** 71 * Payto URI to filter on. 72 */ 73 struct TALER_FullPayto payto_uri; 74 75 /** 76 * Set to the hash of the @e payto_uri. 77 */ 78 struct TALER_FullPaytoHashP h_payto; 79 80 /** 81 * Set to the hash of the normalized @e payto_uri. 82 */ 83 struct TALER_NormalizedPaytoHashP h_normalized_payto; 84 85 /** 86 * Authentication details to authenticate to the bank. 87 */ 88 struct TALER_BANK_AuthenticationData auth; 89 90 /** 91 * Set once we discovered the WTID. 92 */ 93 struct TALER_WireTransferIdentifierRawP wtid; 94 95 /** 96 * the credit amount to look for at @e bank_url. 97 */ 98 struct TALER_Amount credit_amount; 99 100 /** 101 * Expected HTTP response code. 102 */ 103 unsigned int http_status; 104 105 /** 106 * Array of deposit command labels we expect to see aggregated. 107 */ 108 const char **deposits; 109 110 /** 111 * Serial number of the wire transfer in the merchant backend, 112 * set by #TALER_TESTING_cmd_merchant_get_transfers(). 0 if unknown. 113 */ 114 uint64_t serial; 115 116 /** 117 * Length of @e deposits. 118 */ 119 unsigned int deposits_length; 120 121 }; 122 123 124 /** 125 * Callback for a POST /transfers operation. 126 * 127 * @param cls closure for this function 128 * @param ptr response details 129 */ 130 static void 131 transfers_cb (struct PostTransfersState *pts, 132 const struct TALER_MERCHANT_PostPrivateTransfersResponse *ptr) 133 { 134 135 pts->pth = NULL; 136 if (pts->http_status != ptr->hr.http_status) 137 { 138 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 139 "Unexpected response code %u (%d) to command %s\n", 140 ptr->hr.http_status, 141 (int) ptr->hr.ec, 142 TALER_TESTING_interpreter_get_current_label (pts->is)); 143 GNUNET_break (0); 144 TALER_TESTING_interpreter_fail (pts->is); 145 return; 146 } 147 switch (ptr->hr.http_status) 148 { 149 case MHD_HTTP_NO_CONTENT: 150 break; 151 case MHD_HTTP_UNAUTHORIZED: 152 break; 153 case MHD_HTTP_NOT_FOUND: 154 break; 155 case MHD_HTTP_GATEWAY_TIMEOUT: 156 break; 157 default: 158 GNUNET_break (0); 159 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 160 "Unhandled HTTP status %u for POST /transfers.\n", 161 ptr->hr.http_status); 162 } 163 TALER_TESTING_interpreter_next (pts->is); 164 } 165 166 167 /** 168 * Offers information from the POST /transfers CMD state to other 169 * commands. 170 * 171 * @param cls closure 172 * @param[out] ret result (could be anything) 173 * @param trait name of the trait 174 * @param index index number of the object to extract. 175 * @return #GNUNET_OK on success 176 */ 177 static enum GNUNET_GenericReturnValue 178 post_transfers_traits (void *cls, 179 const void **ret, 180 const char *trait, 181 unsigned int index) 182 { 183 struct PostTransfersState *pts = cls; 184 struct TALER_TESTING_Trait traits[] = { 185 TALER_TESTING_make_trait_wtid (&pts->wtid), 186 TALER_TESTING_make_trait_credit_payto_uri (&pts->credit_account), 187 TALER_TESTING_make_trait_h_full_payto (&pts->h_payto), 188 TALER_TESTING_make_trait_h_normalized_payto (&pts->h_normalized_payto), 189 TALER_TESTING_make_trait_amount (&pts->credit_amount), 190 TALER_TESTING_make_trait_exchange_url (pts->exchange_url), 191 TALER_TESTING_make_trait_bank_row (&pts->serial), 192 TALER_TESTING_trait_end (), 193 }; 194 195 return TALER_TESTING_get_trait (traits, 196 ret, 197 trait, 198 index); 199 } 200 201 202 /** 203 * Run the "POST /transfers" CMD. First, get the bank history to find 204 * the wtid. 205 * 206 * @param cls closure. 207 * @param cmd command being run now. 208 * @param is interpreter state. 209 */ 210 static void 211 post_transfers_run2 (void *cls, 212 const struct TALER_TESTING_Command *cmd, 213 struct TALER_TESTING_Interpreter *is) 214 { 215 struct PostTransfersState *pts = cls; 216 217 pts->is = is; 218 pts->pth = TALER_MERCHANT_post_private_transfers_create ( 219 TALER_TESTING_interpreter_get_context (pts->is), 220 pts->merchant_url, 221 &pts->credit_amount, 222 &pts->wtid, 223 pts->credit_account, 224 pts->exchange_url); 225 { 226 enum TALER_ErrorCode ec; 227 228 ec = TALER_MERCHANT_post_private_transfers_start ( 229 pts->pth, 230 &transfers_cb, 231 pts); 232 GNUNET_assert (TALER_EC_NONE == ec); 233 } 234 } 235 236 237 /** 238 * Callbacks of this type are used to serve the result of asking 239 * the bank for the debit transaction history. 240 * 241 * @param cls closure with a `struct PostTransfersState *` 242 * @param reply details from the HTTP response code 243 */ 244 static void 245 debit_cb ( 246 void *cls, 247 const struct TALER_BANK_DebitHistoryResponse *reply) 248 { 249 struct PostTransfersState *pts = cls; 250 251 pts->dhh = NULL; 252 switch (reply->http_status) 253 { 254 case MHD_HTTP_OK: 255 /* handled below */ 256 break; 257 case MHD_HTTP_NO_CONTENT: 258 GNUNET_break (0); 259 TALER_TESTING_interpreter_fail (pts->is); 260 return; 261 default: 262 GNUNET_break (0); 263 TALER_TESTING_interpreter_fail (pts->is); 264 return; 265 } 266 for (unsigned int i = 0; i<reply->details.ok.details_length; i++) 267 { 268 const struct TALER_BANK_DebitDetails *details 269 = &reply->details.ok.details[i]; 270 271 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 272 "Bank reports transfer of %s to %s\n", 273 TALER_amount2s (&details->amount), 274 details->credit_account_uri.full_payto); 275 if (0 != TALER_amount_cmp (&pts->credit_amount, 276 &details->amount)) 277 continue; 278 pts->wtid = details->wtid; 279 pts->credit_account.full_payto 280 = GNUNET_strdup (details->credit_account_uri.full_payto); 281 pts->exchange_url = GNUNET_strdup (details->exchange_base_url); 282 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 283 "Bank transfer found, checking with merchant backend at %s about %s from %s to %s with %s\n", 284 pts->merchant_url, 285 TALER_amount2s (&pts->credit_amount), 286 pts->payto_uri.full_payto, 287 pts->exchange_url, 288 TALER_B2S (&pts->wtid)); 289 pts->pth = TALER_MERCHANT_post_private_transfers_create ( 290 TALER_TESTING_interpreter_get_context (pts->is), 291 pts->merchant_url, 292 &pts->credit_amount, 293 &pts->wtid, 294 pts->credit_account, 295 pts->exchange_url); 296 { 297 enum TALER_ErrorCode ec; 298 299 ec = TALER_MERCHANT_post_private_transfers_start ( 300 pts->pth, 301 &transfers_cb, 302 pts); 303 GNUNET_assert (TALER_EC_NONE == ec); 304 } 305 break; 306 } 307 if (NULL == pts->pth) 308 { 309 GNUNET_break (0); 310 TALER_TESTING_interpreter_fail (pts->is); 311 return; 312 } 313 } 314 315 316 /** 317 * Run the "POST /transfers" CMD. First, get the bank history to find 318 * the wtid. 319 * 320 * @param cls closure. 321 * @param cmd command being run now. 322 * @param is interpreter state. 323 */ 324 static void 325 post_transfers_run (void *cls, 326 const struct TALER_TESTING_Command *cmd, 327 struct TALER_TESTING_Interpreter *is) 328 { 329 struct PostTransfersState *pts = cls; 330 331 pts->is = is; 332 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 333 "Looking for transfer of %s from %s at bank\n", 334 TALER_amount2s (&pts->credit_amount), 335 pts->payto_uri.full_payto); 336 pts->dhh = TALER_BANK_debit_history (TALER_TESTING_interpreter_get_context ( 337 is), 338 &pts->auth, 339 UINT64_MAX, 340 -INT64_MAX, 341 GNUNET_TIME_UNIT_ZERO, 342 &debit_cb, 343 pts); 344 GNUNET_assert (NULL != pts->dhh); 345 } 346 347 348 /** 349 * Free the state of a "POST product" CMD, and possibly 350 * cancel a pending operation thereof. 351 * 352 * @param cls closure. 353 * @param cmd command being run. 354 */ 355 static void 356 post_transfers_cleanup (void *cls, 357 const struct TALER_TESTING_Command *cmd) 358 { 359 struct PostTransfersState *pts = cls; 360 361 if (NULL != pts->pth) 362 { 363 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 364 "POST /transfers operation did not complete\n"); 365 TALER_MERCHANT_post_private_transfers_cancel (pts->pth); 366 } 367 if (NULL != pts->dhh) 368 { 369 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 370 "GET debit history operation did not complete\n"); 371 TALER_BANK_debit_history_cancel (pts->dhh); 372 } 373 GNUNET_array_grow (pts->deposits, 374 pts->deposits_length, 375 0); 376 GNUNET_free (pts->exchange_url); 377 GNUNET_free (pts->credit_account.full_payto); 378 GNUNET_free (pts); 379 } 380 381 382 struct TALER_TESTING_Command 383 TALER_TESTING_cmd_merchant_post_transfer ( 384 const char *label, 385 const struct TALER_BANK_AuthenticationData *auth, 386 struct TALER_FullPayto payto_uri, 387 const char *merchant_url, 388 const char *credit_amount, 389 unsigned int http_code, 390 ...) 391 { 392 struct PostTransfersState *pts; 393 394 pts = GNUNET_new (struct PostTransfersState); 395 pts->merchant_url = merchant_url; 396 pts->auth = *auth; 397 pts->payto_uri = payto_uri; 398 TALER_full_payto_hash (payto_uri, 399 &pts->h_payto); 400 TALER_full_payto_normalize_and_hash (payto_uri, 401 &pts->h_normalized_payto); 402 GNUNET_assert (GNUNET_OK == 403 TALER_string_to_amount (credit_amount, 404 &pts->credit_amount)); 405 pts->http_status = http_code; 406 { 407 const char *clabel; 408 va_list ap; 409 410 va_start (ap, http_code); 411 while (NULL != (clabel = va_arg (ap, const char *))) 412 { 413 GNUNET_array_append (pts->deposits, 414 pts->deposits_length, 415 clabel); 416 } 417 va_end (ap); 418 } 419 { 420 struct TALER_TESTING_Command cmd = { 421 .cls = pts, 422 .label = label, 423 .run = &post_transfers_run, 424 .cleanup = &post_transfers_cleanup, 425 .traits = &post_transfers_traits 426 }; 427 428 return cmd; 429 } 430 } 431 432 433 struct TALER_TESTING_Command 434 TALER_TESTING_cmd_merchant_post_transfer2 ( 435 const char *label, 436 const char *merchant_url, 437 struct TALER_FullPayto payto_uri, 438 const char *credit_amount, 439 const char *wtid, 440 const char *exchange_url, 441 unsigned int http_code) 442 { 443 struct PostTransfersState *pts; 444 445 pts = GNUNET_new (struct PostTransfersState); 446 pts->merchant_url = merchant_url; 447 pts->credit_account.full_payto 448 = GNUNET_strdup (payto_uri.full_payto); 449 pts->exchange_url = GNUNET_strdup (exchange_url); 450 GNUNET_assert (GNUNET_OK == 451 TALER_string_to_amount (credit_amount, 452 &pts->credit_amount)); 453 if (NULL == wtid) 454 { 455 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE, 456 &pts->wtid, 457 sizeof (pts->wtid)); 458 } 459 else 460 { 461 GNUNET_assert (GNUNET_OK == 462 GNUNET_STRINGS_string_to_data (wtid, 463 strlen (wtid), 464 &pts->wtid, 465 sizeof (pts->wtid))); 466 } 467 pts->http_status = http_code; 468 { 469 struct TALER_TESTING_Command cmd = { 470 .cls = pts, 471 .label = label, 472 .run = &post_transfers_run2, 473 .cleanup = &post_transfers_cleanup, 474 .traits = &post_transfers_traits 475 }; 476 477 return cmd; 478 } 479 } 480 481 482 void 483 TALER_TESTING_cmd_merchant_post_transfer_set_serial ( 484 struct TALER_TESTING_Command *cmd, 485 uint64_t serial) 486 { 487 struct PostTransfersState *pts = cmd->cls; 488 489 GNUNET_assert (cmd->run = &post_transfers_run); 490 pts->serial = serial; 491 } 492 493 494 /* end of testing_api_cmd_post_transfers.c */