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

Generated by: LCOV version 2.0-1