testing_api_cmd_charity_patch.c (7021B)
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 #include "donau_testing_lib.h" 29 30 31 /** 32 * Command state for PATCH /charities/$ID. 33 */ 34 struct CharityPatchState 35 { 36 /** 37 * Handle for the in-flight PATCH request (if any). 38 */ 39 struct DONAU_CharityPatchHandle *cph; 40 41 /** 42 * Reference label of the command that created the original charity. 43 */ 44 const char *charity_reference; 45 46 /** 47 * Fresh charity key pair generated for the update. 48 */ 49 struct DONAU_CharityPrivateKeyP charity_priv; 50 51 /** 52 * Corresponding public key transmitted in the PATCH body. 53 */ 54 struct DONAU_CharityPublicKeyP charity_pub; 55 56 /** 57 * Updated yearly donation limit. 58 */ 59 struct TALER_Amount max_per_year; 60 61 /** 62 * Updated human-readable name. 63 */ 64 const char *charity_name; 65 66 /** 67 * Updated contact URL. 68 */ 69 const char *charity_url; 70 71 /** 72 * Administrator bearer token used for authentication. 73 */ 74 const struct DONAU_BearerToken *bearer; 75 76 /** 77 * Expected HTTP status code for the PATCH response. 78 */ 79 unsigned int expected_response_code; 80 81 /** 82 * Database identifier of the charity being updated. 83 */ 84 uint64_t charity_id; 85 86 /** 87 * Interpreter instance driving the command sequence. 88 */ 89 struct TALER_TESTING_Interpreter *is; 90 }; 91 92 93 /** 94 * Check HTTP response for the PATCH request and advance the interpreter on success. 95 * 96 * @param cls closure 97 * @param resp HTTP response details 98 */ 99 static void 100 charity_patch_cb (void *cls, 101 const struct DONAU_PatchCharityResponse *resp) 102 { 103 struct CharityPatchState *ps = cls; 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 }