LCOV - code coverage report
Current view: top level - testing - testing_api_cmd_post_orders.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 215 276 77.9 %
Date: 2025-06-23 16:22:09 Functions: 14 14 100.0 %

          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         428 : orders_traits (void *cls,
     163             :                const void **ret,
     164             :                const char *trait,
     165             :                unsigned int index)
     166             : {
     167         428 :   struct OrdersState *ps = cls;
     168             :   struct TALER_TESTING_Trait traits[] = {
     169         428 :     TALER_TESTING_make_trait_order_id (ps->order_id),
     170         428 :     TALER_TESTING_make_trait_contract_terms (ps->contract_terms),
     171         428 :     TALER_TESTING_make_trait_order_terms (ps->order_terms),
     172         428 :     TALER_TESTING_make_trait_h_contract_terms (&ps->h_contract_terms),
     173         428 :     TALER_TESTING_make_trait_merchant_sig (&ps->merchant_sig),
     174         428 :     TALER_TESTING_make_trait_merchant_pub (&ps->merchant_pub),
     175         428 :     TALER_TESTING_make_trait_claim_nonce (&ps->nonce),
     176         428 :     TALER_TESTING_make_trait_claim_token (&ps->claim_token),
     177         428 :     TALER_TESTING_trait_end ()
     178             :   };
     179             : 
     180         428 :   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          36 : orders_claim_cb (void *cls,
     197             :                  const struct TALER_MERCHANT_OrderClaimResponse *ocr)
     198             : {
     199          36 :   struct OrdersState *ps = cls;
     200             :   const char *error_name;
     201             :   unsigned int error_line;
     202             :   struct GNUNET_JSON_Specification spec[] = {
     203          36 :     GNUNET_JSON_spec_fixed_auto ("merchant_pub",
     204             :                                  &ps->merchant_pub),
     205          36 :     GNUNET_JSON_spec_end ()
     206             :   };
     207             : 
     208          36 :   ps->och = NULL;
     209          36 :   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          36 :   if (MHD_HTTP_OK != ocr->hr.http_status)
     218             :   {
     219           0 :     TALER_TESTING_interpreter_next (ps->is);
     220           0 :     return;
     221             :   }
     222          72 :   ps->contract_terms = json_deep_copy (
     223          36 :     (json_t *) ocr->details.ok.contract_terms);
     224          36 :   ps->h_contract_terms = ocr->details.ok.h_contract_terms;
     225          36 :   ps->merchant_sig = ocr->details.ok.sig;
     226          36 :   if (GNUNET_OK !=
     227          36 :       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          36 :   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          50 : order_cb (void *cls,
     260             :           const struct TALER_MERCHANT_PostOrdersReply *por)
     261             : {
     262          50 :   struct OrdersState *ps = cls;
     263             : 
     264          50 :   ps->po = NULL;
     265          50 :   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          50 :   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          40 :   case MHD_HTTP_OK:
     281          40 :     if (NULL != por->details.ok.token)
     282          36 :       ps->claim_token = *por->details.ok.token;
     283          40 :     ps->order_id = GNUNET_strdup (por->details.ok.order_id);
     284          40 :     if ((NULL != ps->expected_order_id) &&
     285          34 :         (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          40 :     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          40 :     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          40 :   if (! ps->with_claim)
     353             :   {
     354           4 :     TALER_TESTING_interpreter_next (ps->is);
     355           4 :     return;
     356             :   }
     357          36 :   if (NULL ==
     358          36 :       (ps->och = TALER_MERCHANT_order_claim (
     359             :          TALER_TESTING_interpreter_get_context (ps->is),
     360             :          ps->merchant_url,
     361             :          ps->order_id,
     362          36 :          &ps->nonce,
     363          36 :          &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          18 : orders_run2 (void *cls,
     424             :              const struct TALER_TESTING_Command *cmd,
     425             :              struct TALER_TESTING_Interpreter *is)
     426             : {
     427          18 :   struct OrdersState *ps = cls;
     428             :   const json_t *order;
     429          18 :   char *products_string = GNUNET_strdup (ps->products);
     430          18 :   char *locks_string = GNUNET_strdup (ps->locks);
     431             :   char *token;
     432          18 :   struct TALER_MERCHANT_InventoryProduct *products = NULL;
     433          18 :   unsigned int products_length = 0;
     434          18 :   const char **locks = NULL;
     435          18 :   unsigned int locks_length = 0;
     436             : 
     437          18 :   ps->is = is;
     438          18 :   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          16 :     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          16 :     order = ps->order_terms;
     476             :   }
     477          18 :   if (NULL == order)
     478             :   {
     479           0 :     GNUNET_break (0);
     480           0 :     TALER_TESTING_interpreter_fail (is);
     481           0 :     return;
     482             :   }
     483             : 
     484          18 :   GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
     485          18 :                               &ps->nonce,
     486             :                               sizeof (struct GNUNET_CRYPTO_EddsaPublicKey));
     487          18 :   for (token = strtok (products_string, ";");
     488          28 :        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          18 :   for (token = strtok (locks_string, ";");
     519          20 :        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          18 :   ps->po = TALER_MERCHANT_orders_post2 (
     544             :     TALER_TESTING_interpreter_get_context (
     545             :       is),
     546             :     ps->merchant_url,
     547             :     order,
     548          18 :     GNUNET_TIME_UNIT_ZERO,
     549             :     ps->payment_target,
     550             :     products_length,
     551             :     products,
     552             :     locks_length,
     553             :     locks,
     554          18 :     ps->make_claim_token,
     555             :     &order_cb,
     556             :     ps);
     557          18 :   GNUNET_free (products_string);
     558          18 :   GNUNET_free (locks_string);
     559          18 :   GNUNET_array_grow (products,
     560             :                      products_length,
     561             :                      0);
     562          18 :   GNUNET_array_grow (locks,
     563             :                      locks_length,
     564             :                      0);
     565          18 :   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          50 : orders_cleanup (void *cls,
     624             :                 const struct TALER_TESTING_Command *cmd)
     625             : {
     626          50 :   struct OrdersState *ps = cls;
     627             : 
     628          50 :   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          50 :   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          50 :   json_decref (ps->contract_terms);
     647          50 :   json_decref (ps->order_terms);
     648          50 :   GNUNET_free_nz ((void *) ps->order_id);
     649          50 :   GNUNET_free (ps);
     650          50 : }
     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         200 : mark_forgettable (void *cls,
     662             :                   const char *object_id,
     663             :                   json_t *parent)
     664             : {
     665         200 :   GNUNET_assert (GNUNET_OK ==
     666             :                  TALER_JSON_contract_mark_forgettable (parent,
     667             :                                                        object_id));
     668         200 : }
     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          50 : 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          50 :   struct GNUNET_TIME_Timestamp refund = refund_deadline;
     688          50 :   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          50 :   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          50 :   GNUNET_assert (GNUNET_OK ==
     706             :                  TALER_JSON_expand_path (contract_terms,
     707             :                                          "$.dummy_obj",
     708             :                                          &mark_forgettable,
     709             :                                          NULL));
     710          50 :   GNUNET_assert (GNUNET_OK ==
     711             :                  TALER_JSON_expand_path (contract_terms,
     712             :                                          "$.dummy_array[*].item",
     713             :                                          &mark_forgettable,
     714             :                                          NULL));
     715          50 :   *order = contract_terms;
     716          50 : }
     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          18 : 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          18 :   ps = GNUNET_new (struct OrdersState);
     811          18 :   ps->cfg = cfg;
     812          18 :   make_order_json (order_id,
     813             :                    refund_deadline,
     814             :                    pay_deadline,
     815             :                    amount,
     816             :                    &ps->order_terms);
     817          18 :   ps->http_status = http_status;
     818          18 :   ps->expected_order_id = order_id;
     819          18 :   ps->merchant_url = merchant_url;
     820          18 :   ps->payment_target = payment_target;
     821          18 :   ps->products = products;
     822          18 :   ps->locks = locks;
     823          18 :   ps->with_claim = (NULL == duplicate_of);
     824          18 :   ps->make_claim_token = claim_token;
     825          18 :   ps->duplicate_of = duplicate_of;
     826             :   {
     827          18 :     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          18 :     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             :   unsigned int num_inputs,
     890             :   unsigned int num_outputs,
     891             :   const char *order_id,
     892             :   struct GNUNET_TIME_Timestamp refund_deadline,
     893             :   struct GNUNET_TIME_Timestamp pay_deadline,
     894             :   const char *amount)
     895             : {
     896             :   struct OrdersState *ps;
     897             :   struct TALER_Amount brutto;
     898             :   json_t *choice;
     899             :   json_t *choices;
     900             :   json_t *inputs;
     901             :   json_t *outputs;
     902             : 
     903           8 :   ps = GNUNET_new (struct OrdersState);
     904           8 :   ps->cfg = cfg;
     905           8 :   make_order_json (order_id,
     906             :                    refund_deadline,
     907             :                    pay_deadline,
     908             :                    NULL,
     909             :                    &ps->order_terms);
     910           8 :   GNUNET_assert (GNUNET_OK ==
     911             :                  TALER_string_to_amount (amount,
     912             :                                          &brutto));
     913           8 :   inputs = json_array ();
     914           8 :   GNUNET_assert (NULL != inputs);
     915           8 :   GNUNET_assert (0 ==
     916             :                  json_array_append_new (
     917             :                    inputs,
     918             :                    GNUNET_JSON_PACK (
     919             :                      GNUNET_JSON_pack_string ("type",
     920             :                                               "token"),
     921             :                      GNUNET_JSON_pack_uint64 ("count",
     922             :                                               num_inputs),
     923             :                      GNUNET_JSON_pack_string ("token_family_slug",
     924             :                                               token_family_slug)
     925             :                      )));
     926           8 :   outputs = json_array ();
     927           8 :   GNUNET_assert (NULL != outputs);
     928           8 :   GNUNET_assert (0 ==
     929             :                  json_array_append_new (
     930             :                    outputs,
     931             :                    GNUNET_JSON_PACK (
     932             :                      GNUNET_JSON_pack_string ("type",
     933             :                                               "token"),
     934             :                      GNUNET_JSON_pack_uint64 ("count",
     935             :                                               num_outputs),
     936             :                      GNUNET_JSON_pack_string ("token_family_slug",
     937             :                                               token_family_slug)
     938             :                      )));
     939             :   choice
     940           8 :     = GNUNET_JSON_PACK (
     941             :         TALER_JSON_pack_amount ("amount",
     942             :                                 &brutto),
     943             :         GNUNET_JSON_pack_array_steal ("inputs",
     944             :                                       inputs),
     945             :         GNUNET_JSON_pack_array_steal ("outputs",
     946             :                                       outputs));
     947           8 :   choices = json_array ();
     948           8 :   GNUNET_assert (NULL != choices);
     949           8 :   GNUNET_assert (0 ==
     950             :                  json_array_append_new (
     951             :                    choices,
     952             :                    choice));
     953           8 :   GNUNET_assert (0 ==
     954             :                  json_object_set_new (ps->order_terms,
     955             :                                       "choices",
     956             :                                       choices)
     957             :                  );
     958           8 :   GNUNET_assert (0 ==
     959             :                  json_object_set_new (ps->order_terms,
     960             :                                       "version",
     961             :                                       json_integer (1))
     962             :                  );
     963             : 
     964             : 
     965           8 :   ps->http_status = http_status;
     966           8 :   ps->expected_order_id = order_id;
     967           8 :   ps->merchant_url = merchant_url;
     968           8 :   ps->with_claim = true;
     969             :   {
     970           8 :     struct TALER_TESTING_Command cmd = {
     971             :       .cls = ps,
     972             :       .label = label,
     973             :       .run = &orders_run3,
     974             :       .cleanup = &orders_cleanup,
     975             :       .traits = &orders_traits
     976             :     };
     977             : 
     978           8 :     return cmd;
     979             :   }
     980             : }

Generated by: LCOV version 1.16