testing_api_cmd_reserve_close.c (7287B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2014-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 testing/testing_api_cmd_reserve_close.c 21 * @brief Implement the /reserve/$RID/close test command. 22 * @author Christian Grothoff 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 "close" CMD. 31 */ 32 struct CloseState 33 { 34 /** 35 * Label to the command which created the reserve to check, 36 * needed to resort the reserve key. 37 */ 38 const char *reserve_reference; 39 40 /** 41 * Handle to the "reserve close" operation. 42 */ 43 struct TALER_EXCHANGE_PostReservesCloseHandle *rsh; 44 45 /** 46 * payto://-URI where to wire the funds. 47 */ 48 struct TALER_FullPayto target_account; 49 50 /** 51 * Private key of the reserve being analyzed. 52 */ 53 const struct TALER_ReservePrivateKeyP *reserve_priv; 54 55 /** 56 * Public key of the reserve being analyzed. 57 */ 58 struct TALER_ReservePublicKeyP reserve_pub; 59 60 /** 61 * Expected HTTP response code. 62 */ 63 unsigned int expected_response_code; 64 65 /** 66 * Interpreter state. 67 */ 68 struct TALER_TESTING_Interpreter *is; 69 70 /** 71 * Set to the KYC requirement payto hash *if* the exchange replied with a 72 * request for KYC. 73 */ 74 struct TALER_NormalizedPaytoHashP h_payto; 75 76 /** 77 * Set to the KYC requirement row *if* the exchange replied with 78 * a request for KYC. 79 */ 80 uint64_t requirement_row; 81 }; 82 83 84 /** 85 * Check that the reserve balance and HTTP response code are 86 * both acceptable. 87 * 88 * @param cls closure. 89 * @param rs HTTP response details 90 */ 91 static void 92 reserve_close_cb (void *cls, 93 const struct TALER_EXCHANGE_PostReservesCloseResponse *rs) 94 { 95 struct CloseState *ss = cls; 96 struct TALER_TESTING_Interpreter *is = ss->is; 97 98 ss->rsh = NULL; 99 if (ss->expected_response_code != rs->hr.http_status) 100 { 101 TALER_TESTING_unexpected_status (ss->is, 102 rs->hr.http_status, 103 ss->expected_response_code); 104 json_dumpf (rs->hr.reply, 105 stderr, 106 JSON_INDENT (2)); 107 return; 108 } 109 switch (rs->hr.http_status) 110 { 111 case MHD_HTTP_OK: 112 break; 113 case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS: 114 /* nothing to check */ 115 ss->requirement_row 116 = rs->details.unavailable_for_legal_reasons.requirement_row; 117 ss->h_payto 118 = rs->details.unavailable_for_legal_reasons.h_payto; 119 break; 120 default: 121 break; 122 } 123 TALER_TESTING_interpreter_next (is); 124 } 125 126 127 /** 128 * Run the command. 129 * 130 * @param cls closure. 131 * @param cmd the command being executed. 132 * @param is the interpreter state. 133 */ 134 static void 135 close_run (void *cls, 136 const struct TALER_TESTING_Command *cmd, 137 struct TALER_TESTING_Interpreter *is) 138 { 139 struct CloseState *ss = cls; 140 const struct TALER_TESTING_Command *create_reserve; 141 142 ss->is = is; 143 create_reserve 144 = TALER_TESTING_interpreter_lookup_command (is, 145 ss->reserve_reference); 146 147 if (NULL == create_reserve) 148 { 149 GNUNET_break (0); 150 TALER_TESTING_interpreter_fail (is); 151 return; 152 } 153 if (GNUNET_OK != 154 TALER_TESTING_get_trait_reserve_priv (create_reserve, 155 &ss->reserve_priv)) 156 { 157 GNUNET_break (0); 158 TALER_LOG_ERROR ("Failed to find reserve_priv for close query\n"); 159 TALER_TESTING_interpreter_fail (is); 160 return; 161 } 162 GNUNET_CRYPTO_eddsa_key_get_public (&ss->reserve_priv->eddsa_priv, 163 &ss->reserve_pub.eddsa_pub); 164 ss->rsh = TALER_EXCHANGE_post_reserves_close_create ( 165 TALER_TESTING_interpreter_get_context (is), 166 TALER_TESTING_get_exchange_url (is), 167 ss->reserve_priv); 168 if (NULL == ss->rsh) 169 { 170 GNUNET_break (0); 171 TALER_TESTING_interpreter_fail (is); 172 return; 173 } 174 if (NULL != ss->target_account.full_payto) 175 { 176 TALER_EXCHANGE_post_reserves_close_set_options ( 177 ss->rsh, 178 TALER_EXCHANGE_post_reserves_close_option_payto_uri ( 179 ss->target_account)); 180 } 181 { 182 enum TALER_ErrorCode ec; 183 184 ec = TALER_EXCHANGE_post_reserves_close_start (ss->rsh, 185 &reserve_close_cb, 186 ss); 187 if (TALER_EC_NONE != ec) 188 { 189 GNUNET_break (0); 190 ss->rsh = NULL; 191 TALER_TESTING_interpreter_fail (is); 192 return; 193 } 194 } 195 } 196 197 198 /** 199 * Cleanup the state from a "reserve close" CMD, and possibly 200 * cancel a pending operation thereof. 201 * 202 * @param cls closure. 203 * @param cmd the command which is being cleaned up. 204 */ 205 static void 206 close_cleanup (void *cls, 207 const struct TALER_TESTING_Command *cmd) 208 { 209 struct CloseState *ss = cls; 210 211 if (NULL != ss->rsh) 212 { 213 TALER_TESTING_command_incomplete (ss->is, 214 cmd->label); 215 TALER_EXCHANGE_post_reserves_close_cancel (ss->rsh); 216 ss->rsh = NULL; 217 } 218 GNUNET_free (ss); 219 } 220 221 222 /** 223 * Offer internal data to a "close" CMD state to other 224 * commands. 225 * 226 * @param cls closure 227 * @param[out] ret result (could be anything) 228 * @param trait name of the trait 229 * @param index index number of the object to offer. 230 * @return #GNUNET_OK on success 231 */ 232 static enum GNUNET_GenericReturnValue 233 close_traits (void *cls, 234 const void **ret, 235 const char *trait, 236 unsigned int index) 237 { 238 struct CloseState *cs = cls; 239 struct TALER_TESTING_Trait traits[] = { 240 TALER_TESTING_make_trait_legi_requirement_row ( 241 &cs->requirement_row), 242 TALER_TESTING_make_trait_h_normalized_payto ( 243 &cs->h_payto), 244 TALER_TESTING_trait_end () 245 }; 246 247 if (cs->expected_response_code != MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS) 248 return GNUNET_NO; 249 return TALER_TESTING_get_trait (traits, 250 ret, 251 trait, 252 index); 253 } 254 255 256 struct TALER_TESTING_Command 257 TALER_TESTING_cmd_reserve_close (const char *label, 258 const char *reserve_reference, 259 struct TALER_FullPayto target_account, 260 unsigned int expected_response_code) 261 { 262 struct CloseState *ss; 263 264 GNUNET_assert (NULL != reserve_reference); 265 ss = GNUNET_new (struct CloseState); 266 ss->reserve_reference = reserve_reference; 267 ss->target_account = target_account; 268 ss->expected_response_code = expected_response_code; 269 { 270 struct TALER_TESTING_Command cmd = { 271 .cls = ss, 272 .label = label, 273 .run = &close_run, 274 .cleanup = &close_cleanup, 275 .traits = &close_traits 276 }; 277 278 return cmd; 279 } 280 }