LCOV - code coverage report
Current view: top level - testing - testing_api_cmd_post_orders.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 72.6 % 296 215
Test Date: 2025-11-13 17:46:01 Functions: 93.3 % 15 14

            Line data    Source code
       1              : /*
       2              :   This file is part of TALER
       3              :   Copyright (C) 2014-2024 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              : /**
      21              :  * @file testing_api_cmd_post_orders.c
      22              :  * @brief command to run POST /orders
      23              :  * @author Marcello Stanisci
      24              :  */
      25              : 
      26              : #include "platform.h"
      27              : #include <gnunet/gnunet_common.h>
      28              : #include <gnunet/gnunet_time_lib.h>
      29              : #include <jansson.h>
      30              : #include <stdint.h>
      31              : #include <taler/taler_exchange_service.h>
      32              : #include <taler/taler_testing_lib.h>
      33              : #include "taler_merchant_service.h"
      34              : #include "taler_merchant_testing_lib.h"
      35              : 
      36              : /**
      37              :  * State for a "POST /orders" CMD.
      38              :  */
      39              : struct OrdersState
      40              : {
      41              : 
      42              :   /**
      43              :    * Expected status code.
      44              :    */
      45              :   unsigned int http_status;
      46              : 
      47              :   /**
      48              :    * Order id.
      49              :    */
      50              :   const char *order_id;
      51              : 
      52              :   /**
      53              :    * Our configuration.
      54              :    */
      55              :   const struct GNUNET_CONFIGURATION_Handle *cfg;
      56              : 
      57              :   /**
      58              :    * The order id we expect the merchant to assign (if not NULL).
      59              :    */
      60              :   const char *expected_order_id;
      61              : 
      62              :   /**
      63              :    * Contract terms obtained from the backend.
      64              :    */
      65              :   json_t *contract_terms;
      66              : 
      67              :   /**
      68              :    * Order submitted to the backend.
      69              :    */
      70              :   json_t *order_terms;
      71              : 
      72              :   /**
      73              :    * Contract terms hash code.
      74              :    */
      75              :   struct TALER_PrivateContractHashP h_contract_terms;
      76              : 
      77              :   /**
      78              :    * The /orders operation handle.
      79              :    */
      80              :   struct TALER_MERCHANT_PostOrdersHandle *po;
      81              : 
      82              :   /**
      83              :    * The (initial) POST /orders/$ID/claim operation handle.
      84              :    * The logic is such that after an order creation,
      85              :    * we immediately claim the order.
      86              :    */
      87              :   struct TALER_MERCHANT_OrderClaimHandle *och;
      88              : 
      89              :   /**
      90              :    * The nonce.
      91              :    */
      92              :   struct GNUNET_CRYPTO_EddsaPublicKey nonce;
      93              : 
      94              :   /**
      95              :    * Whether to generate a claim token.
      96              :    */
      97              :   bool make_claim_token;
      98              : 
      99              :   /**
     100              :    * The claim token
     101              :    */
     102              :   struct TALER_ClaimTokenP claim_token;
     103              : 
     104              :   /**
     105              :    * URL of the merchant backend.
     106              :    */
     107              :   const char *merchant_url;
     108              : 
     109              :   /**
     110              :    * The interpreter state.
     111              :    */
     112              :   struct TALER_TESTING_Interpreter *is;
     113              : 
     114              :   /**
     115              :    * Merchant signature over the orders.
     116              :    */
     117              :   struct TALER_MerchantSignatureP merchant_sig;
     118              : 
     119              :   /**
     120              :    * Merchant public key.
     121              :    */
     122              :   struct TALER_MerchantPublicKeyP merchant_pub;
     123              : 
     124              :   /**
     125              :    * The payment target for the order
     126              :    */
     127              :   const char *payment_target;
     128              : 
     129              :   /**
     130              :    * The products the order is purchasing.
     131              :    */
     132              :   const char *products;
     133              : 
     134              :   /**
     135              :    * The locks that the order should release.
     136              :    */
     137              :   const char *locks;
     138              : 
     139              :   /**
     140              :    * Should the command also CLAIM the order?
     141              :    */
     142              :   bool with_claim;
     143              : 
     144              :   /**
     145              :    * If not NULL, the command should duplicate the request and verify the
     146              :    * response is the same as in this command.
     147              :    */
     148              :   const char *duplicate_of;
     149              : };
     150              : 
     151              : 
     152              : /**
     153              :  * Offer internal data to other commands.
     154              :  *
     155              :  * @param cls closure
     156              :  * @param[out] ret result (could be anything)
     157              :  * @param trait name of the trait
     158              :  * @param index index number of the object to extract.
     159              :  * @return #GNUNET_OK on success
     160              :  */
     161              : static enum GNUNET_GenericReturnValue
     162          448 : orders_traits (void *cls,
     163              :                const void **ret,
     164              :                const char *trait,
     165              :                unsigned int index)
     166              : {
     167          448 :   struct OrdersState *ps = cls;
     168              :   struct TALER_TESTING_Trait traits[] = {
     169          448 :     TALER_TESTING_make_trait_order_id (ps->order_id),
     170          448 :     TALER_TESTING_make_trait_contract_terms (ps->contract_terms),
     171          448 :     TALER_TESTING_make_trait_order_terms (ps->order_terms),
     172          448 :     TALER_TESTING_make_trait_h_contract_terms (&ps->h_contract_terms),
     173          448 :     TALER_TESTING_make_trait_merchant_sig (&ps->merchant_sig),
     174          448 :     TALER_TESTING_make_trait_merchant_pub (&ps->merchant_pub),
     175          448 :     TALER_TESTING_make_trait_claim_nonce (&ps->nonce),
     176          448 :     TALER_TESTING_make_trait_claim_token (&ps->claim_token),
     177          448 :     TALER_TESTING_trait_end ()
     178              :   };
     179              : 
     180          448 :   return TALER_TESTING_get_trait (traits,
     181              :                                   ret,
     182              :                                   trait,
     183              :                                   index);
     184              : }
     185              : 
     186              : 
     187              : /**
     188              :  * Used to fill the "orders" CMD state with backend-provided
     189              :  * values.  Also double-checks that the order was correctly
     190              :  * created.
     191              :  *
     192              :  * @param cls closure
     193              :  * @param ocr response we got
     194              :  */
     195              : static void
     196           37 : orders_claim_cb (void *cls,
     197              :                  const struct TALER_MERCHANT_OrderClaimResponse *ocr)
     198              : {
     199           37 :   struct OrdersState *ps = cls;
     200              :   const char *error_name;
     201              :   unsigned int error_line;
     202              :   struct GNUNET_JSON_Specification spec[] = {
     203           37 :     GNUNET_JSON_spec_fixed_auto ("merchant_pub",
     204              :                                  &ps->merchant_pub),
     205           37 :     GNUNET_JSON_spec_end ()
     206              :   };
     207              : 
     208           37 :   ps->och = NULL;
     209           37 :   if (ps->http_status != ocr->hr.http_status)
     210              :   {
     211            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     212              :                 "Expected status %u, got %u\n",
     213              :                 ps->http_status,
     214              :                 ocr->hr.http_status);
     215            0 :     TALER_TESTING_FAIL (ps->is);
     216              :   }
     217           37 :   if (MHD_HTTP_OK != ocr->hr.http_status)
     218              :   {
     219            0 :     TALER_TESTING_interpreter_next (ps->is);
     220            0 :     return;
     221              :   }
     222           74 :   ps->contract_terms = json_deep_copy (
     223           37 :     (json_t *) ocr->details.ok.contract_terms);
     224           37 :   ps->h_contract_terms = ocr->details.ok.h_contract_terms;
     225           37 :   ps->merchant_sig = ocr->details.ok.sig;
     226           37 :   if (GNUNET_OK !=
     227           37 :       GNUNET_JSON_parse (ps->contract_terms,
     228              :                          spec,
     229              :                          &error_name,
     230              :                          &error_line))
     231              :   {
     232              :     char *log;
     233              : 
     234            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     235              :                 "Parser failed on %s:%u\n",
     236              :                 error_name,
     237              :                 error_line);
     238            0 :     log = json_dumps (ps->contract_terms,
     239              :                       JSON_INDENT (1));
     240            0 :     fprintf (stderr,
     241              :              "%s\n",
     242              :              log);
     243            0 :     free (log);
     244            0 :     TALER_TESTING_FAIL (ps->is);
     245              :   }
     246           37 :   TALER_TESTING_interpreter_next (ps->is);
     247              : }
     248              : 
     249              : 
     250              : /**
     251              :  * Callback that processes the response following a POST /orders.  NOTE: no
     252              :  * contract terms are included here; they need to be taken via the "orders
     253              :  * lookup" method.
     254              :  *
     255              :  * @param cls closure.
     256              :  * @param por details about the response
     257              :  */
     258              : static void
     259           51 : order_cb (void *cls,
     260              :           const struct TALER_MERCHANT_PostOrdersReply *por)
     261              : {
     262           51 :   struct OrdersState *ps = cls;
     263              : 
     264           51 :   ps->po = NULL;
     265           51 :   if (ps->http_status != por->hr.http_status)
     266              :   {
     267            0 :     TALER_TESTING_unexpected_status_with_body (ps->is,
     268              :                                                por->hr.http_status,
     269              :                                                ps->http_status,
     270              :                                                por->hr.reply);
     271            0 :     TALER_TESTING_interpreter_fail (ps->is);
     272            0 :     return;
     273              :   }
     274           51 :   switch (por->hr.http_status)
     275              :   {
     276            0 :   case 0:
     277            0 :     TALER_LOG_DEBUG ("/orders, expected 0 status code\n");
     278            0 :     TALER_TESTING_interpreter_next (ps->is);
     279            0 :     return;
     280           41 :   case MHD_HTTP_OK:
     281           41 :     if (NULL != por->details.ok.token)
     282           37 :       ps->claim_token = *por->details.ok.token;
     283           41 :     ps->order_id = GNUNET_strdup (por->details.ok.order_id);
     284           41 :     if ((NULL != ps->expected_order_id) &&
     285           35 :         (0 != strcmp (por->details.ok.order_id,
     286              :                       ps->expected_order_id)))
     287              :     {
     288            0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     289              :                   "Order id assigned does not match\n");
     290            0 :       TALER_TESTING_interpreter_fail (ps->is);
     291            0 :       return;
     292              :     }
     293           41 :     if (NULL != ps->duplicate_of)
     294              :     {
     295              :       const struct TALER_TESTING_Command *order_cmd;
     296              :       const struct TALER_ClaimTokenP *prev_token;
     297            2 :       struct TALER_ClaimTokenP zero_token = {0};
     298              : 
     299            2 :       order_cmd = TALER_TESTING_interpreter_lookup_command (
     300              :         ps->is,
     301              :         ps->duplicate_of);
     302            2 :       if (GNUNET_OK !=
     303            2 :           TALER_TESTING_get_trait_claim_token (order_cmd,
     304              :                                                &prev_token))
     305              :       {
     306            0 :         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     307              :                     "Could not fetch previous order claim token\n");
     308            0 :         TALER_TESTING_interpreter_fail (ps->is);
     309            0 :         return;
     310              :       }
     311            2 :       if (NULL == por->details.ok.token)
     312            0 :         prev_token = &zero_token;
     313            2 :       if (0 != GNUNET_memcmp (prev_token,
     314              :                               por->details.ok.token))
     315              :       {
     316            0 :         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     317              :                     "Claim tokens for identical requests do not match\n");
     318            0 :         TALER_TESTING_interpreter_fail (ps->is);
     319            0 :         return;
     320              :       }
     321              :     }
     322           41 :     break;
     323            4 :   case MHD_HTTP_NOT_FOUND:
     324            4 :     TALER_TESTING_interpreter_next (ps->is);
     325            4 :     return;
     326            2 :   case MHD_HTTP_GONE:
     327            2 :     TALER_TESTING_interpreter_next (ps->is);
     328            2 :     return;
     329            4 :   case MHD_HTTP_CONFLICT:
     330            4 :     TALER_TESTING_interpreter_next (ps->is);
     331            4 :     return;
     332            0 :   default:
     333              :     {
     334            0 :       char *s = json_dumps (por->hr.reply,
     335              :                             JSON_COMPACT);
     336            0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     337              :                   "Unexpected status code from /orders: %u (%d) at %s; JSON: %s\n",
     338              :                   por->hr.http_status,
     339              :                   (int) por->hr.ec,
     340              :                   TALER_TESTING_interpreter_get_current_label (ps->is),
     341              :                   s);
     342            0 :       free (s);
     343              :       /**
     344              :        * Not failing, as test cases are _supposed_
     345              :        * to create non 200 OK situations.
     346              :        */
     347            0 :       TALER_TESTING_interpreter_next (ps->is);
     348              :     }
     349            0 :     return;
     350              :   }
     351              : 
     352           41 :   if (! ps->with_claim)
     353              :   {
     354            4 :     TALER_TESTING_interpreter_next (ps->is);
     355            4 :     return;
     356              :   }
     357           37 :   if (NULL ==
     358           37 :       (ps->och = TALER_MERCHANT_order_claim (
     359              :          TALER_TESTING_interpreter_get_context (ps->is),
     360              :          ps->merchant_url,
     361              :          ps->order_id,
     362           37 :          &ps->nonce,
     363           37 :          &ps->claim_token,
     364              :          &orders_claim_cb,
     365              :          ps)))
     366            0 :     TALER_TESTING_FAIL (ps->is);
     367              : }
     368              : 
     369              : 
     370              : /**
     371              :  * Run a "orders" CMD.
     372              :  *
     373              :  * @param cls closure.
     374              :  * @param cmd command currently being run.
     375              :  * @param is interpreter state.
     376              :  */
     377              : static void
     378           24 : orders_run (void *cls,
     379              :             const struct TALER_TESTING_Command *cmd,
     380              :             struct TALER_TESTING_Interpreter *is)
     381              : {
     382           24 :   struct OrdersState *ps = cls;
     383              : 
     384           24 :   ps->is = is;
     385           24 :   if (NULL == json_object_get (ps->order_terms,
     386              :                                "order_id"))
     387              :   {
     388              :     struct GNUNET_TIME_Absolute now;
     389              :     char *order_id;
     390              : 
     391            0 :     now = GNUNET_TIME_absolute_get_monotonic (ps->cfg);
     392            0 :     order_id = GNUNET_STRINGS_data_to_string_alloc (
     393              :       &now,
     394              :       sizeof (now));
     395            0 :     GNUNET_assert (0 ==
     396              :                    json_object_set_new (ps->order_terms,
     397              :                                         "order_id",
     398              :                                         json_string (order_id)));
     399            0 :     GNUNET_free (order_id);
     400              :   }
     401           24 :   GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
     402           24 :                               &ps->nonce,
     403              :                               sizeof (struct GNUNET_CRYPTO_EddsaPublicKey));
     404           24 :   ps->po = TALER_MERCHANT_orders_post (TALER_TESTING_interpreter_get_context (
     405              :                                          is),
     406              :                                        ps->merchant_url,
     407           24 :                                        ps->order_terms,
     408           24 :                                        GNUNET_TIME_UNIT_ZERO,
     409              :                                        &order_cb,
     410              :                                        ps);
     411           24 :   GNUNET_assert (NULL != ps->po);
     412           24 : }
     413              : 
     414              : 
     415              : /**
     416              :  * Run a "orders" CMD.
     417              :  *
     418              :  * @param cls closure.
     419              :  * @param cmd command currently being run.
     420              :  * @param is interpreter state.
     421              :  */
     422              : static void
     423           19 : orders_run2 (void *cls,
     424              :              const struct TALER_TESTING_Command *cmd,
     425              :              struct TALER_TESTING_Interpreter *is)
     426              : {
     427           19 :   struct OrdersState *ps = cls;
     428              :   const json_t *order;
     429           19 :   char *products_string = GNUNET_strdup (ps->products);
     430           19 :   char *locks_string = GNUNET_strdup (ps->locks);
     431              :   char *token;
     432           19 :   struct TALER_MERCHANT_InventoryProduct *products = NULL;
     433           19 :   unsigned int products_length = 0;
     434           19 :   const char **locks = NULL;
     435           19 :   unsigned int locks_length = 0;
     436              : 
     437           19 :   ps->is = is;
     438           19 :   if (NULL != ps->duplicate_of)
     439              :   {
     440              :     const struct TALER_TESTING_Command *order_cmd;
     441              :     const json_t *ct;
     442              : 
     443            2 :     order_cmd = TALER_TESTING_interpreter_lookup_command (
     444              :       is,
     445              :       ps->duplicate_of);
     446            2 :     if (GNUNET_OK !=
     447            2 :         TALER_TESTING_get_trait_order_terms (order_cmd,
     448              :                                              &ct))
     449              :     {
     450            0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     451              :                   "Could not fetch previous order string\n");
     452            0 :       TALER_TESTING_interpreter_fail (is);
     453            0 :       return;
     454              :     }
     455            2 :     order = (json_t *) ct;
     456              :   }
     457              :   else
     458              :   {
     459           17 :     if (NULL == json_object_get (ps->order_terms,
     460              :                                  "order_id"))
     461              :     {
     462              :       struct GNUNET_TIME_Absolute now;
     463              :       char *order_id;
     464              : 
     465            0 :       now = GNUNET_TIME_absolute_get_monotonic (ps->cfg);
     466            0 :       order_id = GNUNET_STRINGS_data_to_string_alloc (
     467              :         &now.abs_value_us,
     468              :         sizeof (now.abs_value_us));
     469            0 :       GNUNET_assert (0 ==
     470              :                      json_object_set_new (ps->order_terms,
     471              :                                           "order_id",
     472              :                                           json_string (order_id)));
     473            0 :       GNUNET_free (order_id);
     474              :     }
     475           17 :     order = ps->order_terms;
     476              :   }
     477           19 :   if (NULL == order)
     478              :   {
     479            0 :     GNUNET_break (0);
     480            0 :     TALER_TESTING_interpreter_fail (is);
     481            0 :     return;
     482              :   }
     483              : 
     484           19 :   GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
     485           19 :                               &ps->nonce,
     486              :                               sizeof (struct GNUNET_CRYPTO_EddsaPublicKey));
     487           19 :   for (token = strtok (products_string, ";");
     488           29 :        NULL != token;
     489           10 :        token = strtok (NULL, ";"))
     490              :   {
     491              :     char *ctok;
     492              :     struct TALER_MERCHANT_InventoryProduct pd;
     493              : 
     494              :     /* Token syntax is "[product_id]/[quantity]" */
     495           10 :     ctok = strchr (token, '/');
     496           10 :     if (NULL != ctok)
     497              :     {
     498            8 :       *ctok = '\0';
     499            8 :       ctok++;
     500            8 :       if (1 != sscanf (ctok,
     501              :                        "%u",
     502              :                        &pd.quantity))
     503              :       {
     504            0 :         GNUNET_break (0);
     505            0 :         break;
     506              :       }
     507              :     }
     508              :     else
     509              :     {
     510            2 :       pd.quantity = 1;
     511              :     }
     512           10 :     pd.product_id = token;
     513              : 
     514           10 :     GNUNET_array_append (products,
     515              :                          products_length,
     516              :                          pd);
     517              :   }
     518           19 :   for (token = strtok (locks_string, ";");
     519           21 :        NULL != token;
     520            2 :        token = strtok (NULL, ";"))
     521              :   {
     522              :     const struct TALER_TESTING_Command *lock_cmd;
     523              :     const char *uuid;
     524              : 
     525            2 :     lock_cmd = TALER_TESTING_interpreter_lookup_command (
     526              :       is,
     527              :       token);
     528              : 
     529            2 :     if (GNUNET_OK !=
     530            2 :         TALER_TESTING_get_trait_lock_uuid (lock_cmd,
     531              :                                            &uuid))
     532              :     {
     533            0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     534              :                   "Could not fetch lock uuid\n");
     535            0 :       TALER_TESTING_interpreter_fail (is);
     536            0 :       return;
     537              :     }
     538              : 
     539            2 :     GNUNET_array_append (locks,
     540              :                          locks_length,
     541              :                          uuid);
     542              :   }
     543           19 :   ps->po = TALER_MERCHANT_orders_post2 (
     544              :     TALER_TESTING_interpreter_get_context (
     545              :       is),
     546              :     ps->merchant_url,
     547              :     order,
     548           19 :     GNUNET_TIME_UNIT_ZERO,
     549              :     ps->payment_target,
     550              :     products_length,
     551              :     products,
     552              :     locks_length,
     553              :     locks,
     554           19 :     ps->make_claim_token,
     555              :     &order_cb,
     556              :     ps);
     557           19 :   GNUNET_free (products_string);
     558           19 :   GNUNET_free (locks_string);
     559           19 :   GNUNET_array_grow (products,
     560              :                      products_length,
     561              :                      0);
     562           19 :   GNUNET_array_grow (locks,
     563              :                      locks_length,
     564              :                      0);
     565           19 :   GNUNET_assert (NULL != ps->po);
     566              : }
     567              : 
     568              : 
     569              : /**
     570              :  * Run a "orders" CMD.
     571              :  *
     572              :  * @param cls closure.
     573              :  * @param cmd command currently being run.
     574              :  * @param is interpreter state.
     575              :  */
     576              : static void
     577            8 : orders_run3 (void *cls,
     578              :              const struct TALER_TESTING_Command *cmd,
     579              :              struct TALER_TESTING_Interpreter *is)
     580              : {
     581            8 :   struct OrdersState *ps = cls;
     582              :   struct GNUNET_TIME_Absolute now;
     583              : 
     584            8 :   ps->is = is;
     585            8 :   now = GNUNET_TIME_absolute_get_monotonic (ps->cfg);
     586            8 :   if (NULL == json_object_get (ps->order_terms,
     587              :                                "order_id"))
     588              :   {
     589              :     char *order_id;
     590              : 
     591            0 :     order_id = GNUNET_STRINGS_data_to_string_alloc (
     592              :       &now,
     593              :       sizeof (now));
     594            0 :     GNUNET_assert (0 ==
     595              :                    json_object_set_new (ps->order_terms,
     596              :                                         "order_id",
     597              :                                         json_string (order_id)));
     598            0 :     GNUNET_free (order_id);
     599              :   }
     600              : 
     601            8 :   GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
     602            8 :                               &ps->nonce,
     603              :                               sizeof (struct GNUNET_CRYPTO_EddsaPublicKey));
     604            8 :   ps->po = TALER_MERCHANT_orders_post (TALER_TESTING_interpreter_get_context (
     605              :                                          is),
     606              :                                        ps->merchant_url,
     607            8 :                                        ps->order_terms,
     608            8 :                                        GNUNET_TIME_UNIT_ZERO,
     609              :                                        &order_cb,
     610              :                                        ps);
     611            8 :   GNUNET_assert (NULL != ps->po);
     612            8 : }
     613              : 
     614              : 
     615              : /**
     616              :  * Free the state of a "orders" CMD, and possibly
     617              :  * cancel it if it did not complete.
     618              :  *
     619              :  * @param cls closure.
     620              :  * @param cmd command being freed.
     621              :  */
     622              : static void
     623           51 : orders_cleanup (void *cls,
     624              :                 const struct TALER_TESTING_Command *cmd)
     625              : {
     626           51 :   struct OrdersState *ps = cls;
     627              : 
     628           51 :   if (NULL != ps->po)
     629              :   {
     630            0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     631              :                 "Command '%s' did not complete (orders put)\n",
     632              :                 cmd->label);
     633            0 :     TALER_MERCHANT_orders_post_cancel (ps->po);
     634            0 :     ps->po = NULL;
     635              :   }
     636              : 
     637           51 :   if (NULL != ps->och)
     638              :   {
     639            0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     640              :                 "Command '%s' did not complete (orders lookup)\n",
     641              :                 cmd->label);
     642            0 :     TALER_MERCHANT_order_claim_cancel (ps->och);
     643            0 :     ps->och = NULL;
     644              :   }
     645              : 
     646           51 :   json_decref (ps->contract_terms);
     647           51 :   json_decref (ps->order_terms);
     648           51 :   GNUNET_free_nz ((void *) ps->order_id);
     649           51 :   GNUNET_free (ps);
     650           51 : }
     651              : 
     652              : 
     653              : /**
     654              :  * Mark part of the contract terms as possible to forget.
     655              :  *
     656              :  * @param cls pointer to the result of the forget operation.
     657              :  * @param object_id name of the object to forget.
     658              :  * @param parent parent of the object at @e object_id.
     659              :  */
     660              : static void
     661          204 : mark_forgettable (void *cls,
     662              :                   const char *object_id,
     663              :                   json_t *parent)
     664              : {
     665          204 :   GNUNET_assert (GNUNET_OK ==
     666              :                  TALER_JSON_contract_mark_forgettable (parent,
     667              :                                                        object_id));
     668          204 : }
     669              : 
     670              : 
     671              : /**
     672              :  * Constructs the json for a POST order request.
     673              :  *
     674              :  * @param order_id the name of the order to add, can be NULL.
     675              :  * @param refund_deadline the deadline for refunds on this order.
     676              :  * @param pay_deadline the deadline for payment on this order.
     677              :  * @param amount the amount this order is for, NULL for v1 orders
     678              :  * @param[out] order where to write the json string.
     679              :  */
     680              : static void
     681           51 : make_order_json (const char *order_id,
     682              :                  struct GNUNET_TIME_Timestamp refund_deadline,
     683              :                  struct GNUNET_TIME_Timestamp pay_deadline,
     684              :                  const char *amount,
     685              :                  json_t **order)
     686              : {
     687           51 :   struct GNUNET_TIME_Timestamp refund = refund_deadline;
     688           51 :   struct GNUNET_TIME_Timestamp pay = pay_deadline;
     689              :   json_t *contract_terms;
     690              : 
     691              :   /* Include required fields and some dummy objects to test forgetting. */
     692           51 :   contract_terms = json_pack (
     693              :     "{s:s, s:s?, s:s?, s:s, s:o, s:o, s:s, s:[{s:s}, {s:s}, {s:s}]}",
     694              :     "summary", "merchant-lib testcase",
     695              :     "order_id", order_id,
     696              :     "amount", amount,
     697              :     "fulfillment_url", "https://example.com",
     698              :     "refund_deadline", GNUNET_JSON_from_timestamp (refund),
     699              :     "pay_deadline", GNUNET_JSON_from_timestamp (pay),
     700              :     "dummy_obj", "EUR:1.0",
     701              :     "dummy_array", /* For testing forgetting parts of arrays */
     702              :     "item", "speakers",
     703              :     "item", "headphones",
     704              :     "item", "earbuds");
     705           51 :   GNUNET_assert (GNUNET_OK ==
     706              :                  TALER_JSON_expand_path (contract_terms,
     707              :                                          "$.dummy_obj",
     708              :                                          &mark_forgettable,
     709              :                                          NULL));
     710           51 :   GNUNET_assert (GNUNET_OK ==
     711              :                  TALER_JSON_expand_path (contract_terms,
     712              :                                          "$.dummy_array[*].item",
     713              :                                          &mark_forgettable,
     714              :                                          NULL));
     715           51 :   *order = contract_terms;
     716           51 : }
     717              : 
     718              : 
     719              : struct TALER_TESTING_Command
     720            4 : TALER_TESTING_cmd_merchant_post_orders_no_claim (
     721              :   const char *label,
     722              :   const char *merchant_url,
     723              :   unsigned int http_status,
     724              :   const char *order_id,
     725              :   struct GNUNET_TIME_Timestamp refund_deadline,
     726              :   struct GNUNET_TIME_Timestamp pay_deadline,
     727              :   const char *amount)
     728              : {
     729              :   struct OrdersState *ps;
     730              : 
     731            4 :   ps = GNUNET_new (struct OrdersState);
     732            4 :   make_order_json (order_id,
     733              :                    refund_deadline,
     734              :                    pay_deadline,
     735              :                    amount,
     736              :                    &ps->order_terms);
     737            4 :   ps->http_status = http_status;
     738            4 :   ps->expected_order_id = order_id;
     739            4 :   ps->merchant_url = merchant_url;
     740              :   {
     741            4 :     struct TALER_TESTING_Command cmd = {
     742              :       .cls = ps,
     743              :       .label = label,
     744              :       .run = &orders_run,
     745              :       .cleanup = &orders_cleanup,
     746              :       .traits = &orders_traits
     747              :     };
     748              : 
     749            4 :     return cmd;
     750              :   }
     751              : }
     752              : 
     753              : 
     754              : struct TALER_TESTING_Command
     755           16 : TALER_TESTING_cmd_merchant_post_orders (
     756              :   const char *label,
     757              :   const struct GNUNET_CONFIGURATION_Handle *cfg,
     758              :   const char *merchant_url,
     759              :   unsigned int http_status,
     760              :   const char *order_id,
     761              :   struct GNUNET_TIME_Timestamp refund_deadline,
     762              :   struct GNUNET_TIME_Timestamp pay_deadline,
     763              :   const char *amount)
     764              : {
     765              :   struct OrdersState *ps;
     766              : 
     767           16 :   ps = GNUNET_new (struct OrdersState);
     768           16 :   ps->cfg = cfg;
     769           16 :   make_order_json (order_id,
     770              :                    refund_deadline,
     771              :                    pay_deadline,
     772              :                    amount,
     773              :                    &ps->order_terms);
     774           16 :   ps->http_status = http_status;
     775           16 :   ps->expected_order_id = order_id;
     776           16 :   ps->merchant_url = merchant_url;
     777           16 :   ps->with_claim = true;
     778              :   {
     779           16 :     struct TALER_TESTING_Command cmd = {
     780              :       .cls = ps,
     781              :       .label = label,
     782              :       .run = &orders_run,
     783              :       .cleanup = &orders_cleanup,
     784              :       .traits = &orders_traits
     785              :     };
     786              : 
     787           16 :     return cmd;
     788              :   }
     789              : }
     790              : 
     791              : 
     792              : struct TALER_TESTING_Command
     793           19 : TALER_TESTING_cmd_merchant_post_orders2 (
     794              :   const char *label,
     795              :   const struct GNUNET_CONFIGURATION_Handle *cfg,
     796              :   const char *merchant_url,
     797              :   unsigned int http_status,
     798              :   const char *order_id,
     799              :   struct GNUNET_TIME_Timestamp refund_deadline,
     800              :   struct GNUNET_TIME_Timestamp pay_deadline,
     801              :   bool claim_token,
     802              :   const char *amount,
     803              :   const char *payment_target,
     804              :   const char *products,
     805              :   const char *locks,
     806              :   const char *duplicate_of)
     807              : {
     808              :   struct OrdersState *ps;
     809              : 
     810           19 :   ps = GNUNET_new (struct OrdersState);
     811           19 :   ps->cfg = cfg;
     812           19 :   make_order_json (order_id,
     813              :                    refund_deadline,
     814              :                    pay_deadline,
     815              :                    amount,
     816              :                    &ps->order_terms);
     817           19 :   ps->http_status = http_status;
     818           19 :   ps->expected_order_id = order_id;
     819           19 :   ps->merchant_url = merchant_url;
     820           19 :   ps->payment_target = payment_target;
     821           19 :   ps->products = products;
     822           19 :   ps->locks = locks;
     823           19 :   ps->with_claim = (NULL == duplicate_of);
     824           19 :   ps->make_claim_token = claim_token;
     825           19 :   ps->duplicate_of = duplicate_of;
     826              :   {
     827           19 :     struct TALER_TESTING_Command cmd = {
     828              :       .cls = ps,
     829              :       .label = label,
     830              :       .run = &orders_run2,
     831              :       .cleanup = &orders_cleanup,
     832              :       .traits = &orders_traits
     833              :     };
     834              : 
     835           19 :     return cmd;
     836              :   }
     837              : }
     838              : 
     839              : 
     840              : struct TALER_TESTING_Command
     841            4 : TALER_TESTING_cmd_merchant_post_orders3 (
     842              :   const char *label,
     843              :   const struct GNUNET_CONFIGURATION_Handle *cfg,
     844              :   const char *merchant_url,
     845              :   unsigned int expected_http_status,
     846              :   const char *order_id,
     847              :   struct GNUNET_TIME_Timestamp refund_deadline,
     848              :   struct GNUNET_TIME_Timestamp pay_deadline,
     849              :   const char *fulfillment_url,
     850              :   const char *amount)
     851              : {
     852              :   struct OrdersState *ps;
     853              : 
     854            4 :   ps = GNUNET_new (struct OrdersState);
     855            4 :   ps->cfg = cfg;
     856            4 :   make_order_json (order_id,
     857              :                    refund_deadline,
     858              :                    pay_deadline,
     859              :                    amount,
     860              :                    &ps->order_terms);
     861            4 :   GNUNET_assert (0 ==
     862              :                  json_object_set_new (ps->order_terms,
     863              :                                       "fulfillment_url",
     864              :                                       json_string (fulfillment_url)));
     865            4 :   ps->http_status = expected_http_status;
     866            4 :   ps->merchant_url = merchant_url;
     867            4 :   ps->with_claim = true;
     868              :   {
     869            4 :     struct TALER_TESTING_Command cmd = {
     870              :       .cls = ps,
     871              :       .label = label,
     872              :       .run = &orders_run,
     873              :       .cleanup = &orders_cleanup,
     874              :       .traits = &orders_traits
     875              :     };
     876              : 
     877            4 :     return cmd;
     878              :   }
     879              : }
     880              : 
     881              : 
     882              : struct TALER_TESTING_Command
     883            8 : TALER_TESTING_cmd_merchant_post_orders_choices (
     884              :   const char *label,
     885              :   const struct GNUNET_CONFIGURATION_Handle *cfg,
     886              :   const char *merchant_url,
     887              :   unsigned int http_status,
     888              :   const char *token_family_slug,
     889              :   const char *choice_description,
     890              :   json_t *choice_description_i18n,
     891              :   unsigned int num_inputs,
     892              :   unsigned int num_outputs,
     893              :   const char *order_id,
     894              :   struct GNUNET_TIME_Timestamp refund_deadline,
     895              :   struct GNUNET_TIME_Timestamp pay_deadline,
     896              :   const char *amount)
     897              : {
     898              :   struct OrdersState *ps;
     899              :   struct TALER_Amount brutto;
     900              :   json_t *choice;
     901              :   json_t *choices;
     902              :   json_t *inputs;
     903              :   json_t *outputs;
     904              : 
     905            8 :   ps = GNUNET_new (struct OrdersState);
     906            8 :   ps->cfg = cfg;
     907            8 :   make_order_json (order_id,
     908              :                    refund_deadline,
     909              :                    pay_deadline,
     910              :                    NULL,
     911              :                    &ps->order_terms);
     912            8 :   GNUNET_assert (GNUNET_OK ==
     913              :                  TALER_string_to_amount (amount,
     914              :                                          &brutto));
     915            8 :   inputs = json_array ();
     916            8 :   GNUNET_assert (NULL != inputs);
     917            8 :   GNUNET_assert (0 ==
     918              :                  json_array_append_new (
     919              :                    inputs,
     920              :                    GNUNET_JSON_PACK (
     921              :                      GNUNET_JSON_pack_string ("type",
     922              :                                               "token"),
     923              :                      GNUNET_JSON_pack_uint64 ("count",
     924              :                                               num_inputs),
     925              :                      GNUNET_JSON_pack_string ("token_family_slug",
     926              :                                               token_family_slug)
     927              :                      )));
     928            8 :   outputs = json_array ();
     929            8 :   GNUNET_assert (NULL != outputs);
     930            8 :   GNUNET_assert (0 ==
     931              :                  json_array_append_new (
     932              :                    outputs,
     933              :                    GNUNET_JSON_PACK (
     934              :                      GNUNET_JSON_pack_string ("type",
     935              :                                               "token"),
     936              :                      GNUNET_JSON_pack_uint64 ("count",
     937              :                                               num_outputs),
     938              :                      GNUNET_JSON_pack_string ("token_family_slug",
     939              :                                               token_family_slug)
     940              :                      )));
     941              :   choice
     942            8 :     = GNUNET_JSON_PACK (
     943              :         TALER_JSON_pack_amount ("amount",
     944              :                                 &brutto),
     945              :         GNUNET_JSON_pack_allow_null (
     946              :           GNUNET_JSON_pack_string ("description",
     947              :                                    choice_description)),
     948              :         GNUNET_JSON_pack_allow_null (
     949              :           GNUNET_JSON_pack_object_steal ("description_i18n",
     950              :                                          choice_description_i18n)),
     951              :         GNUNET_JSON_pack_array_steal ("inputs",
     952              :                                       inputs),
     953              :         GNUNET_JSON_pack_array_steal ("outputs",
     954              :                                       outputs));
     955            8 :   choices = json_array ();
     956            8 :   GNUNET_assert (NULL != choices);
     957            8 :   GNUNET_assert (0 ==
     958              :                  json_array_append_new (
     959              :                    choices,
     960              :                    choice));
     961            8 :   GNUNET_assert (0 ==
     962              :                  json_object_set_new (ps->order_terms,
     963              :                                       "choices",
     964              :                                       choices)
     965              :                  );
     966            8 :   GNUNET_assert (0 ==
     967              :                  json_object_set_new (ps->order_terms,
     968              :                                       "version",
     969              :                                       json_integer (1))
     970              :                  );
     971              : 
     972              : 
     973            8 :   ps->http_status = http_status;
     974            8 :   ps->expected_order_id = order_id;
     975            8 :   ps->merchant_url = merchant_url;
     976            8 :   ps->with_claim = true;
     977              :   {
     978            8 :     struct TALER_TESTING_Command cmd = {
     979              :       .cls = ps,
     980              :       .label = label,
     981              :       .run = &orders_run3,
     982              :       .cleanup = &orders_cleanup,
     983              :       .traits = &orders_traits
     984              :     };
     985              : 
     986            8 :     return cmd;
     987              :   }
     988              : }
     989              : 
     990              : 
     991              : struct TALER_TESTING_Command
     992            0 : TALER_TESTING_cmd_merchant_post_orders_donau (
     993              :   const char *label,
     994              :   const struct GNUNET_CONFIGURATION_Handle *cfg,
     995              :   const char *merchant_url,
     996              :   unsigned int http_status,
     997              :   const char *order_id,
     998              :   struct GNUNET_TIME_Timestamp refund_deadline,
     999              :   struct GNUNET_TIME_Timestamp pay_deadline,
    1000              :   const char *amount)
    1001              : {
    1002              :   struct OrdersState *ps;
    1003              :   struct TALER_Amount brutto;
    1004              :   json_t *choice;
    1005              :   json_t *choices;
    1006              :   json_t *outputs;
    1007              : 
    1008            0 :   ps = GNUNET_new (struct OrdersState);
    1009            0 :   ps->cfg = cfg;
    1010            0 :   make_order_json (order_id,
    1011              :                    refund_deadline,
    1012              :                    pay_deadline,
    1013              :                    NULL,
    1014              :                    &ps->order_terms);
    1015            0 :   GNUNET_assert (GNUNET_OK ==
    1016              :                  TALER_string_to_amount (amount,
    1017              :                                          &brutto));
    1018              : 
    1019            0 :   outputs = json_array ();
    1020            0 :   GNUNET_assert (NULL != outputs);
    1021            0 :   GNUNET_assert (0 ==
    1022              :                  json_array_append_new (
    1023              :                    outputs,
    1024              :                    GNUNET_JSON_PACK (
    1025              :                      GNUNET_JSON_pack_string ("type",
    1026              :                                               "tax-receipt")
    1027              :                      )));
    1028              :   choice
    1029            0 :     = GNUNET_JSON_PACK (
    1030              :         TALER_JSON_pack_amount ("amount",
    1031              :                                 &brutto),
    1032              :         GNUNET_JSON_pack_array_steal ("outputs",
    1033              :                                       outputs));
    1034            0 :   choices = json_array ();
    1035            0 :   GNUNET_assert (NULL != choices);
    1036            0 :   GNUNET_assert (0 ==
    1037              :                  json_array_append_new (
    1038              :                    choices,
    1039              :                    choice));
    1040            0 :   GNUNET_assert (0 ==
    1041              :                  json_object_set_new (ps->order_terms,
    1042              :                                       "choices",
    1043              :                                       choices)
    1044              :                  );
    1045            0 :   GNUNET_assert (0 ==
    1046              :                  json_object_set_new (ps->order_terms,
    1047              :                                       "version",
    1048              :                                       json_integer (1))
    1049              :                  );
    1050              : 
    1051              : 
    1052            0 :   ps->http_status = http_status;
    1053            0 :   ps->expected_order_id = order_id;
    1054            0 :   ps->merchant_url = merchant_url;
    1055            0 :   ps->with_claim = true;
    1056              :   {
    1057            0 :     struct TALER_TESTING_Command cmd = {
    1058              :       .cls = ps,
    1059              :       .label = label,
    1060              :       .run = &orders_run3,
    1061              :       .cleanup = &orders_cleanup,
    1062              :       .traits = &orders_traits
    1063              :     };
    1064              : 
    1065            0 :     return cmd;
    1066              :   }
    1067              : }
        

Generated by: LCOV version 2.0-1