testing_api_cmd_get_units.c (9840B)
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 (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_api_cmd_get_units.c 21 * @brief command to test GET /private/units 22 * @author Bohdan Potuzhnyi 23 */ 24 #include "taler/platform.h" 25 #include <jansson.h> 26 #include <taler/taler_testing_lib.h> 27 #include "taler/taler_merchant_service.h" 28 #include "taler/taler_merchant_testing_lib.h" 29 #include <taler/taler-merchant/get-private-units.h> 30 31 32 /** 33 * State for a GET /private/units command. 34 */ 35 struct GetUnitsState 36 { 37 /** 38 * In-flight request handle. 39 */ 40 struct TALER_MERCHANT_GetPrivateUnitsHandle *ugh; 41 42 /** 43 * Interpreter context. 44 */ 45 struct TALER_TESTING_Interpreter *is; 46 47 /** 48 * Merchant backend base URL. 49 */ 50 const char *merchant_url; 51 52 /** 53 * Expected HTTP status. 54 */ 55 unsigned int http_status; 56 57 /** 58 * Expected references that must appear in the listing. 59 */ 60 const char **references; 61 62 /** 63 * Length of @e references. 64 */ 65 unsigned int references_length; 66 }; 67 68 69 /** 70 * Verify that @a entry matches the traits from @a ref_cmd. 71 */ 72 static enum GNUNET_GenericReturnValue 73 check_unit_matches (const struct TALER_MERCHANT_UnitEntry *entry, 74 const struct TALER_TESTING_Command *ref_cmd) 75 { 76 const char *unit_id = NULL; 77 78 if (GNUNET_OK != 79 TALER_TESTING_get_trait_unit_id (ref_cmd, 80 &unit_id)) 81 { 82 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 83 "Internal error: command `%s' lacks unit_id trait\n", 84 ref_cmd->label); 85 return GNUNET_SYSERR; 86 } 87 if (0 != strcmp (entry->unit, 88 unit_id)) 89 return GNUNET_NO; 90 91 { 92 const char *unit_name_long = NULL; 93 94 if (GNUNET_OK == 95 TALER_TESTING_get_trait_unit_name_long (ref_cmd, 96 &unit_name_long)) 97 { 98 if ( (NULL != unit_name_long) && 99 (0 != strcmp (entry->unit_name_long, 100 unit_name_long)) ) 101 return GNUNET_SYSERR; 102 } 103 } 104 { 105 const char *unit_name_short = NULL; 106 107 if (GNUNET_OK == 108 TALER_TESTING_get_trait_unit_name_short (ref_cmd, 109 &unit_name_short)) 110 { 111 if ( (NULL != unit_name_short) && 112 (0 != strcmp (entry->unit_name_short, 113 unit_name_short)) ) 114 return GNUNET_SYSERR; 115 } 116 } 117 { 118 const bool *unit_allow_fraction = NULL; 119 120 if (GNUNET_OK == 121 TALER_TESTING_get_trait_unit_allow_fraction (ref_cmd, 122 &unit_allow_fraction)) 123 { 124 if ( (NULL != unit_allow_fraction) && 125 (*unit_allow_fraction != entry->unit_allow_fraction) ) 126 { 127 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 128 "Unit %s mismatch: expected allow_fraction %d got %d\n", 129 entry->unit, 130 (int) *unit_allow_fraction, 131 (int) entry->unit_allow_fraction); 132 return GNUNET_SYSERR; 133 } 134 } 135 } 136 { 137 const uint32_t *unit_precision_level = NULL; 138 139 if (GNUNET_OK == 140 TALER_TESTING_get_trait_unit_precision_level (ref_cmd, 141 &unit_precision_level)) 142 { 143 if ( (NULL != unit_precision_level) && 144 (*unit_precision_level != entry->unit_precision_level) ) 145 { 146 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 147 "Unit %s mismatch: expected precision %u got %u\n", 148 entry->unit, 149 (unsigned int) *unit_precision_level, 150 (unsigned int) entry->unit_precision_level); 151 return GNUNET_SYSERR; 152 } 153 } 154 } 155 { 156 const bool *unit_active = NULL; 157 158 if (GNUNET_OK == 159 TALER_TESTING_get_trait_unit_active (ref_cmd, 160 &unit_active)) 161 { 162 if ( (NULL != unit_active) && 163 (*unit_active != entry->unit_active) ) 164 { 165 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 166 "Unit %s mismatch: expected active %d got %d\n", 167 entry->unit, 168 (int) *unit_active, 169 (int) entry->unit_active); 170 return GNUNET_SYSERR; 171 } 172 } 173 } 174 { 175 const json_t *unit_name_long_i18n = NULL; 176 177 if (GNUNET_OK == 178 TALER_TESTING_get_trait_unit_name_long_i18n (ref_cmd, 179 &unit_name_long_i18n)) 180 { 181 if ( (NULL != unit_name_long_i18n) && 182 ( (NULL == entry->unit_name_long_i18n) || 183 (1 != json_equal (unit_name_long_i18n, 184 entry->unit_name_long_i18n)) ) ) 185 { 186 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 187 "Unit %s mismatch: long_i18n differs\n", 188 entry->unit); 189 return GNUNET_SYSERR; 190 } 191 } 192 } 193 { 194 const json_t *unit_name_short_i18n = NULL; 195 196 if (GNUNET_OK == 197 TALER_TESTING_get_trait_unit_name_short_i18n (ref_cmd, 198 &unit_name_short_i18n)) 199 { 200 if ( (NULL != unit_name_short_i18n) && 201 ( (NULL == entry->unit_name_short_i18n) || 202 (1 != json_equal (unit_name_short_i18n, 203 entry->unit_name_short_i18n)) ) ) 204 { 205 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 206 "Unit %s mismatch: short_i18n differs\n", 207 entry->unit); 208 return GNUNET_SYSERR; 209 } 210 } 211 } 212 return GNUNET_OK; 213 } 214 215 216 /** 217 * Completion callback for GET /private/units. 218 */ 219 static void 220 get_units_cb (void *cls, 221 const struct TALER_MERCHANT_GetPrivateUnitsResponse *ugr) 222 { 223 struct GetUnitsState *gus = cls; 224 225 gus->ugh = NULL; 226 if (gus->http_status != ugr->hr.http_status) 227 { 228 TALER_TESTING_unexpected_status_with_body (gus->is, 229 ugr->hr.http_status, 230 gus->http_status, 231 ugr->hr.reply); 232 return; 233 } 234 if (MHD_HTTP_OK == ugr->hr.http_status) 235 { 236 for (unsigned int i = 0; i < gus->references_length; ++i) 237 { 238 const char *label = gus->references[i]; 239 const struct TALER_TESTING_Command *ref_cmd; 240 enum GNUNET_GenericReturnValue match = GNUNET_NO; 241 242 ref_cmd = TALER_TESTING_interpreter_lookup_command (gus->is, 243 label); 244 if (NULL == ref_cmd) 245 { 246 GNUNET_break (0); 247 TALER_TESTING_interpreter_fail (gus->is); 248 return; 249 } 250 for (unsigned int j = 0; 251 j < ugr->details.ok.units_length; 252 ++j) 253 { 254 match = check_unit_matches (&ugr->details.ok.units[j], 255 ref_cmd); 256 if (GNUNET_SYSERR == match) 257 break; 258 if (GNUNET_OK == match) 259 break; 260 } 261 if (GNUNET_SYSERR == match) 262 { 263 GNUNET_break (0); 264 TALER_TESTING_interpreter_fail (gus->is); 265 return; 266 } 267 if (GNUNET_OK != match) 268 { 269 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 270 "Unit referenced by `%s' not found in GET /private/units response\n", 271 label); 272 TALER_TESTING_interpreter_fail (gus->is); 273 return; 274 } 275 } 276 } 277 TALER_TESTING_interpreter_next (gus->is); 278 } 279 280 281 /** 282 * Issue the GET request. 283 */ 284 static void 285 get_units_run (void *cls, 286 const struct TALER_TESTING_Command *cmd, 287 struct TALER_TESTING_Interpreter *is) 288 { 289 struct GetUnitsState *gus = cls; 290 291 gus->is = is; 292 gus->ugh = TALER_MERCHANT_get_private_units_create ( 293 TALER_TESTING_interpreter_get_context (is), 294 gus->merchant_url); 295 { 296 enum TALER_ErrorCode ec; 297 298 ec = TALER_MERCHANT_get_private_units_start ( 299 gus->ugh, 300 &get_units_cb, 301 gus); 302 GNUNET_assert (TALER_EC_NONE == ec); 303 } 304 } 305 306 307 /** 308 * Cleanup. 309 */ 310 static void 311 get_units_cleanup (void *cls, 312 const struct TALER_TESTING_Command *cmd) 313 { 314 struct GetUnitsState *gus = cls; 315 316 if (NULL != gus->ugh) 317 { 318 TALER_MERCHANT_get_private_units_cancel (gus->ugh); 319 gus->ugh = NULL; 320 } 321 GNUNET_array_grow (gus->references, 322 gus->references_length, 323 0); 324 GNUNET_free (gus); 325 } 326 327 328 struct TALER_TESTING_Command 329 TALER_TESTING_cmd_merchant_get_units (const char *label, 330 const char *merchant_url, 331 unsigned int http_status, 332 ...) 333 { 334 struct GetUnitsState *gus; 335 va_list ap; 336 const char *ref; 337 338 gus = GNUNET_new (struct GetUnitsState); 339 gus->merchant_url = merchant_url; 340 gus->http_status = http_status; 341 342 va_start (ap, http_status); 343 while (NULL != (ref = va_arg (ap, const char *))) 344 { 345 GNUNET_array_append (gus->references, 346 gus->references_length, 347 ref); 348 } 349 va_end (ap); 350 351 { 352 struct TALER_TESTING_Command cmd = { 353 .cls = gus, 354 .label = label, 355 .run = &get_units_run, 356 .cleanup = &get_units_cleanup 357 }; 358 359 return cmd; 360 } 361 } 362 363 364 /* end of testing_api_cmd_get_units.c */