LCOV - code coverage report
Current view: top level - testing - testing_api_cmd_get_product.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 52.1 % 169 88
Test Date: 2026-09-11 17:45:24 Functions: 100.0 % 5 5

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

Generated by: LCOV version 2.0-1