testing_api_cmd_charity_patch.c (7094B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2025 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 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 License 16 along with TALER; see the file COPYING. If not, see 17 <http://www.gnu.org/licenses/>. 18 */ 19 /** 20 * @file testing/testing_api_cmd_charity_patch.c 21 * @brief Implement the PATCH /charities/$ID test command. 22 * @author Bohdan Potuzhnyi 23 */ 24 #include <donau_config.h> 25 #include <taler/taler_json_lib.h> 26 #include <gnunet/gnunet_curl_lib.h> 27 #include <taler/taler_testing_lib.h> 28 struct CharityPatchState; 29 #define DONAU_PATCH_CHARITY_RESULT_CLOSURE struct CharityPatchState 30 #include "donau_testing_lib.h" 31 32 33 /** 34 * Command state for PATCH /charities/$ID. 35 */ 36 struct CharityPatchState 37 { 38 /** 39 * Handle for the in-flight PATCH request (if any). 40 */ 41 struct DONAU_CharityPatchHandle *cph; 42 43 /** 44 * Reference label of the command that created the original charity. 45 */ 46 const char *charity_reference; 47 48 /** 49 * Fresh charity key pair generated for the update. 50 */ 51 struct DONAU_CharityPrivateKeyP charity_priv; 52 53 /** 54 * Corresponding public key transmitted in the PATCH body. 55 */ 56 struct DONAU_CharityPublicKeyP charity_pub; 57 58 /** 59 * Updated yearly donation limit. 60 */ 61 struct TALER_Amount max_per_year; 62 63 /** 64 * Updated human-readable name. 65 */ 66 const char *charity_name; 67 68 /** 69 * Updated contact URL. 70 */ 71 const char *charity_url; 72 73 /** 74 * Administrator bearer token used for authentication. 75 */ 76 const struct DONAU_BearerToken *bearer; 77 78 /** 79 * Expected HTTP status code for the PATCH response. 80 */ 81 unsigned int expected_response_code; 82 83 /** 84 * Database identifier of the charity being updated. 85 */ 86 uint64_t charity_id; 87 88 /** 89 * Interpreter instance driving the command sequence. 90 */ 91 struct TALER_TESTING_Interpreter *is; 92 }; 93 94 95 /** 96 * Check HTTP response for the PATCH request and advance the interpreter on success. 97 * 98 * @param ps closure 99 * @param resp HTTP response details 100 */ 101 static void 102 charity_patch_cb (struct CharityPatchState *ps, 103 const struct DONAU_PatchCharityResponse *resp) 104 { 105 ps->cph = NULL; 106 if (ps->expected_response_code != resp->hr.http_status) 107 { 108 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 109 "Unexpected HTTP response code: %u\n", 110 resp->hr.http_status); 111 json_dumpf (resp->hr.reply, 112 stderr, 113 0); 114 TALER_TESTING_interpreter_fail (ps->is); 115 return; 116 } 117 TALER_TESTING_interpreter_next (ps->is); 118 } 119 120 121 /** 122 * Run the PATCH command after extracting the referenced charity id. 123 * 124 * @param cls closure 125 * @param cmd command definition 126 * @param is interpreter state 127 */ 128 static void 129 charity_patch_run (void *cls, 130 const struct TALER_TESTING_Command *cmd, 131 struct TALER_TESTING_Interpreter *is) 132 { 133 struct CharityPatchState *ps = cls; 134 const struct TALER_TESTING_Command *charity_cmd; 135 const uint64_t *charity_id; 136 137 (void) cmd; 138 ps->is = is; 139 140 charity_cmd = 141 TALER_TESTING_interpreter_lookup_command (is, 142 ps->charity_reference); 143 if ( (NULL == charity_cmd) || 144 (GNUNET_OK != 145 TALER_TESTING_get_trait_charity_id (charity_cmd, 146 &charity_id)) ) 147 { 148 GNUNET_break (0); 149 TALER_TESTING_interpreter_fail (is); 150 return; 151 } 152 ps->charity_id = *charity_id; 153 154 ps->cph = DONAU_charity_patch ( 155 TALER_TESTING_interpreter_get_context (is), 156 TALER_TESTING_get_donau_url (is), 157 ps->charity_id, 158 ps->charity_name, 159 ps->charity_url, 160 &ps->max_per_year, 161 &ps->charity_pub, 162 ps->bearer, 163 &charity_patch_cb, 164 ps); 165 if (NULL == ps->cph) 166 { 167 GNUNET_break (0); 168 TALER_TESTING_interpreter_fail (is); 169 } 170 } 171 172 173 /** 174 * Cancel any outstanding PATCH request and release resources. 175 * 176 * @param cls closure 177 * @param cmd command being cleaned up 178 */ 179 static void 180 charity_patch_cleanup (void *cls, 181 const struct TALER_TESTING_Command *cmd) 182 { 183 struct CharityPatchState *ps = cls; 184 185 if (NULL != ps->cph) 186 { 187 TALER_TESTING_command_incomplete (ps->is, 188 cmd->label); 189 DONAU_charity_patch_cancel (ps->cph); 190 ps->cph = NULL; 191 } 192 GNUNET_free (ps); 193 } 194 195 196 /** 197 * Offer traits produced by the PATCH command to subsequent commands. 198 * 199 * @param cls closure 200 * @param[out] ret location to store the requested trait 201 * @param trait trait identifier 202 * @param index trait index 203 * @return #GNUNET_OK on success 204 */ 205 static enum GNUNET_GenericReturnValue 206 charity_patch_traits (void *cls, 207 const void **ret, 208 const char *trait, 209 unsigned int index) 210 { 211 struct CharityPatchState *ps = cls; 212 struct TALER_TESTING_Trait traits[] = { 213 TALER_TESTING_make_trait_charity_priv (&ps->charity_priv), 214 TALER_TESTING_make_trait_charity_pub (&ps->charity_pub), 215 TALER_TESTING_make_trait_charity_id (&ps->charity_id), 216 TALER_TESTING_trait_end () 217 }; 218 219 return TALER_TESTING_get_trait (traits, 220 ret, 221 trait, 222 index); 223 } 224 225 226 struct TALER_TESTING_Command 227 TALER_TESTING_cmd_charity_patch (const char *label, 228 const char *charity_reference, 229 const char *name, 230 const char *url, 231 const char *max_per_year, 232 const struct DONAU_BearerToken *bearer, 233 unsigned int expected_response_code) 234 { 235 struct CharityPatchState *ps; 236 237 ps = GNUNET_new (struct CharityPatchState); 238 GNUNET_CRYPTO_eddsa_key_create (&ps->charity_priv.eddsa_priv); 239 GNUNET_CRYPTO_eddsa_key_get_public (&ps->charity_priv.eddsa_priv, 240 &ps->charity_pub.eddsa_pub); 241 ps->charity_reference = charity_reference; 242 ps->charity_name = name; 243 ps->charity_url = url; 244 ps->bearer = bearer; 245 ps->expected_response_code = expected_response_code; 246 if (GNUNET_OK != 247 TALER_string_to_amount (max_per_year, 248 &ps->max_per_year)) 249 { 250 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 251 "Failed to parse amount `%s' for command %s\n", 252 max_per_year, 253 label); 254 GNUNET_free (ps); 255 GNUNET_assert (0); 256 } 257 258 { 259 struct TALER_TESTING_Command cmd = { 260 .cls = ps, 261 .label = label, 262 .run = &charity_patch_run, 263 .cleanup = &charity_patch_cleanup, 264 .traits = &charity_patch_traits 265 }; 266 267 return cmd; 268 } 269 }