testing_api_cmd_get_product.c (14454B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2020-2023 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_product.c 21 * @brief command to test GET /product/$ID 22 * @author Christian Grothoff 23 */ 24 #include "taler/platform.h" 25 #include <taler/taler_exchange_service.h> 26 #include <taler/taler_testing_lib.h> 27 #include "taler/taler_merchant_service.h" 28 #include "taler/taler_merchant_testing_lib.h" 29 30 31 /** 32 * State of a "GET product" CMD. 33 */ 34 struct GetProductState 35 { 36 37 /** 38 * Handle for a "GET product" request. 39 */ 40 struct TALER_MERCHANT_ProductGetHandle *igh; 41 42 /** 43 * The interpreter state. 44 */ 45 struct TALER_TESTING_Interpreter *is; 46 47 /** 48 * Base URL of the merchant serving the request. 49 */ 50 const char *merchant_url; 51 52 /** 53 * ID of the product to run GET for. 54 */ 55 const char *product_id; 56 57 /** 58 * Reference for a POST or PATCH /products CMD (optional). 59 */ 60 const char *product_reference; 61 62 /** 63 * Expected HTTP response code. 64 */ 65 unsigned int http_status; 66 67 /** 68 * Optional overrides for fractional fields. 69 */ 70 const struct TALER_TESTING_ProductUnitExpectations *unit_expectations; 71 72 }; 73 74 75 /** 76 * Callback for a /get/product/$ID operation. 77 * 78 * @param cls closure for this function 79 * @param pgr response details 80 */ 81 static void 82 get_product_cb (void *cls, 83 const struct TALER_MERCHANT_ProductGetResponse *pgr) 84 { 85 struct GetProductState *gis = cls; 86 const struct TALER_TESTING_Command *product_cmd; 87 const struct TALER_TESTING_ProductUnitExpectations *ue = 88 gis->unit_expectations; 89 90 gis->igh = NULL; 91 if (gis->http_status != pgr->hr.http_status) 92 { 93 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 94 "Unexpected response code %u (%d) to command %s\n", 95 pgr->hr.http_status, 96 (int) pgr->hr.ec, 97 TALER_TESTING_interpreter_get_current_label (gis->is)); 98 TALER_TESTING_interpreter_fail (gis->is); 99 return; 100 } 101 switch (pgr->hr.http_status) 102 { 103 case MHD_HTTP_OK: 104 { 105 const char *expected_description; 106 107 product_cmd = TALER_TESTING_interpreter_lookup_command ( 108 gis->is, 109 gis->product_reference); 110 if (GNUNET_OK != 111 TALER_TESTING_get_trait_product_description (product_cmd, 112 &expected_description)) 113 TALER_TESTING_interpreter_fail (gis->is); 114 if (0 != strcmp (pgr->details.ok.description, 115 expected_description)) 116 { 117 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 118 "Product description does not match\n"); 119 TALER_TESTING_interpreter_fail (gis->is); 120 return; 121 } 122 } 123 { 124 const json_t *expected_description_i18n; 125 126 if (GNUNET_OK != 127 TALER_TESTING_get_trait_i18n_description (product_cmd, 128 &expected_description_i18n)) 129 TALER_TESTING_interpreter_fail (gis->is); 130 if (1 != json_equal (pgr->details.ok.description_i18n, 131 expected_description_i18n)) 132 { 133 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 134 "Product description i18n does not match\n"); 135 TALER_TESTING_interpreter_fail (gis->is); 136 return; 137 } 138 } 139 { 140 const struct TALER_Amount *expected_price; 141 142 if (GNUNET_OK != 143 TALER_TESTING_get_trait_amount (product_cmd, 144 &expected_price)) 145 TALER_TESTING_interpreter_fail (gis->is); 146 if ((GNUNET_OK != 147 TALER_amount_cmp_currency (&pgr->details.ok.price, 148 expected_price)) || 149 (0 != TALER_amount_cmp (&pgr->details.ok.price, 150 expected_price))) 151 { 152 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 153 "Product price does not match\n"); 154 TALER_TESTING_interpreter_fail (gis->is); 155 return; 156 } 157 } 158 { 159 const bool *expected_allow; 160 bool have_allow = GNUNET_OK == 161 TALER_TESTING_get_trait_product_unit_allow_fraction ( 162 product_cmd, 163 &expected_allow); 164 bool override_allow = (NULL != ue) && 165 ue->have_unit_allow_fraction; 166 167 if (override_allow) 168 { 169 if (pgr->details.ok.unit_allow_fraction != 170 ue->unit_allow_fraction) 171 { 172 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 173 "Product fractional flag does not match expectation\n"); 174 TALER_TESTING_interpreter_fail (gis->is); 175 return; 176 } 177 } 178 else if (! have_allow) 179 { 180 if (pgr->details.ok.unit_allow_fraction) 181 { 182 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 183 "Product fractional flag unexpected\n"); 184 TALER_TESTING_interpreter_fail (gis->is); 185 return; 186 } 187 } 188 else 189 { 190 if (pgr->details.ok.unit_allow_fraction != *expected_allow) 191 { 192 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 193 "Product fractional flag does not match\n"); 194 TALER_TESTING_interpreter_fail (gis->is); 195 return; 196 } 197 { 198 const char *expected_unit_total_stock; 199 200 if (GNUNET_OK != 201 TALER_TESTING_get_trait_product_unit_total_stock ( 202 product_cmd, 203 &expected_unit_total_stock)) 204 TALER_TESTING_interpreter_fail (gis->is); 205 else if (0 != strcmp (pgr->details.ok.unit_total_stock, 206 expected_unit_total_stock)) 207 { 208 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 209 "Product stock string does not match\n"); 210 TALER_TESTING_interpreter_fail (gis->is); 211 return; 212 } 213 } 214 } 215 } 216 { 217 const uint32_t *expected_precision; 218 bool have_precision = GNUNET_OK == 219 TALER_TESTING_get_trait_product_unit_precision_level 220 ( 221 product_cmd, 222 &expected_precision); 223 bool override_precision = (NULL != ue) && 224 ue->have_unit_precision_level; 225 226 if (override_precision) 227 { 228 if (pgr->details.ok.unit_precision_level != 229 ue->unit_precision_level) 230 { 231 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 232 "Product fractional precision does not match expectation\n"); 233 TALER_TESTING_interpreter_fail (gis->is); 234 return; 235 } 236 } 237 else if (have_precision) 238 { 239 if (pgr->details.ok.unit_precision_level != *expected_precision) 240 { 241 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 242 "Product fractional precision does not match\n"); 243 TALER_TESTING_interpreter_fail (gis->is); 244 return; 245 } 246 } 247 else if (! pgr->details.ok.unit_allow_fraction) 248 { 249 if (0 != pgr->details.ok.unit_precision_level) 250 { 251 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 252 "Product fractional precision should be zero when disallowed\n"); 253 TALER_TESTING_interpreter_fail (gis->is); 254 return; 255 } 256 } 257 else if (pgr->details.ok.unit_precision_level > 8) 258 { 259 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 260 "Product fractional precision exceeds supported range\n"); 261 TALER_TESTING_interpreter_fail (gis->is); 262 return; 263 } 264 } 265 { 266 const char *expected_image; 267 268 if (GNUNET_OK != 269 TALER_TESTING_get_trait_product_image (product_cmd, 270 &expected_image)) 271 TALER_TESTING_interpreter_fail (gis->is); 272 if (0 != strcmp (pgr->details.ok.image, 273 expected_image)) 274 { 275 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 276 "Product image does not match\n"); 277 TALER_TESTING_interpreter_fail (gis->is); 278 return; 279 } 280 } 281 { 282 const json_t *expected_taxes; 283 284 if (GNUNET_OK != 285 TALER_TESTING_get_trait_taxes (product_cmd, 286 &expected_taxes)) 287 TALER_TESTING_interpreter_fail (gis->is); 288 if (1 != json_equal (pgr->details.ok.taxes, 289 expected_taxes)) 290 { 291 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 292 "Product taxes do not match\n"); 293 TALER_TESTING_interpreter_fail (gis->is); 294 return; 295 } 296 } 297 { 298 const char *expected_unit; 299 300 if (GNUNET_OK != 301 TALER_TESTING_get_trait_product_unit (product_cmd, 302 &expected_unit)) 303 TALER_TESTING_interpreter_fail (gis->is); 304 if (0 != strcmp (pgr->details.ok.unit, 305 expected_unit)) 306 { 307 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 308 "Product unit does not match\n"); 309 TALER_TESTING_interpreter_fail (gis->is); 310 return; 311 } 312 } 313 { 314 const json_t *expected_location; 315 316 if (GNUNET_OK != 317 TALER_TESTING_get_trait_address (product_cmd, 318 &expected_location)) 319 TALER_TESTING_interpreter_fail (gis->is); 320 if (NULL != expected_location) 321 { 322 if (1 != json_equal (pgr->details.ok.location, 323 expected_location)) 324 { 325 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 326 "Product location does not match\n"); 327 TALER_TESTING_interpreter_fail (gis->is); 328 return; 329 } 330 } 331 } 332 { 333 const int64_t *expected_total_stock; 334 335 if (GNUNET_OK != 336 TALER_TESTING_get_trait_product_stock (product_cmd, 337 &expected_total_stock)) 338 TALER_TESTING_interpreter_fail (gis->is); 339 if (pgr->details.ok.total_stock != *expected_total_stock) 340 { 341 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 342 "Product total stock does not match\n"); 343 TALER_TESTING_interpreter_fail (gis->is); 344 return; 345 } 346 } 347 { 348 const struct GNUNET_TIME_Timestamp *expected_next_restock; 349 350 if (GNUNET_OK != 351 TALER_TESTING_get_trait_timestamp (product_cmd, 352 0, 353 &expected_next_restock)) 354 TALER_TESTING_interpreter_fail (gis->is); 355 if (GNUNET_TIME_timestamp_cmp (pgr->details.ok.next_restock, 356 !=, 357 *expected_next_restock)) 358 { 359 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 360 "Product next restock does not match\n"); 361 TALER_TESTING_interpreter_fail (gis->is); 362 return; 363 } 364 } 365 break; 366 case MHD_HTTP_UNAUTHORIZED: 367 break; 368 case MHD_HTTP_NOT_FOUND: 369 break; 370 default: 371 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 372 "Unhandled HTTP status.\n"); 373 } 374 TALER_TESTING_interpreter_next (gis->is); 375 } 376 377 378 /** 379 * Run the "GET product" CMD. 380 * 381 * 382 * @param cls closure. 383 * @param cmd command being run now. 384 * @param is interpreter state. 385 */ 386 static void 387 get_product_run (void *cls, 388 const struct TALER_TESTING_Command *cmd, 389 struct TALER_TESTING_Interpreter *is) 390 { 391 struct GetProductState *gis = cls; 392 393 gis->is = is; 394 gis->igh = TALER_MERCHANT_product_get (TALER_TESTING_interpreter_get_context ( 395 is), 396 gis->merchant_url, 397 gis->product_id, 398 &get_product_cb, 399 gis); 400 GNUNET_assert (NULL != gis->igh); 401 } 402 403 404 /** 405 * Free the state of a "GET product" CMD, and possibly 406 * cancel a pending operation thereof. 407 * 408 * @param cls closure. 409 * @param cmd command being run. 410 */ 411 static void 412 get_product_cleanup (void *cls, 413 const struct TALER_TESTING_Command *cmd) 414 { 415 struct GetProductState *gis = cls; 416 417 if (NULL != gis->igh) 418 { 419 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 420 "GET /products/$ID operation did not complete\n"); 421 TALER_MERCHANT_product_get_cancel (gis->igh); 422 } 423 GNUNET_free (gis); 424 } 425 426 427 struct TALER_TESTING_Command 428 TALER_TESTING_cmd_merchant_get_product (const char *label, 429 const char *merchant_url, 430 const char *product_id, 431 unsigned int http_status, 432 const char *product_reference) 433 { 434 return TALER_TESTING_cmd_merchant_get_product2 (label, 435 merchant_url, 436 product_id, 437 http_status, 438 product_reference, 439 NULL); 440 } 441 442 443 struct TALER_TESTING_Command 444 TALER_TESTING_cmd_merchant_get_product2 ( 445 const char *label, 446 const char *merchant_url, 447 const char *product_id, 448 unsigned int http_status, 449 const char *product_reference, 450 const struct TALER_TESTING_ProductUnitExpectations *unit_expectations) 451 { 452 struct GetProductState *gis; 453 454 gis = GNUNET_new (struct GetProductState); 455 gis->merchant_url = merchant_url; 456 gis->product_id = product_id; 457 gis->http_status = http_status; 458 gis->product_reference = product_reference; 459 gis->unit_expectations = unit_expectations; 460 { 461 struct TALER_TESTING_Command cmd = { 462 .cls = gis, 463 .label = label, 464 .run = &get_product_run, 465 .cleanup = &get_product_cleanup 466 }; 467 468 return cmd; 469 } 470 } 471 472 473 /* end of testing_api_cmd_get_product.c */