LCOV - code coverage report
Current view: top level - testing - testing_api_cmd_post_orders.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 82.8 % 348 288
Test Date: 2026-09-11 17:45:24 Functions: 100.0 % 17 17

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

Generated by: LCOV version 2.0-1