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