Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2020 Taler Systems SA
4 :
5 : TALER is free software; you can redistribute it and/or modify
6 : it under the terms of the GNU General Public License as
7 : published by the Free Software Foundation; either version 3, or
8 : (at your option) any later version.
9 :
10 : TALER is distributed in the hope that it will be useful, but
11 : WITHOUT ANY WARRANTY; without even the implied warranty of
12 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 : GNU General Public License for more details.
14 :
15 : You should have received a copy of the GNU General Public
16 : License along with TALER; see the file COPYING. If not, see
17 : <http://www.gnu.org/licenses/>
18 : */
19 : /**
20 : * @file testing_api_cmd_post_products.c
21 : * @brief command to test POST /products
22 : * @author Christian Grothoff
23 : */
24 : #include "platform.h"
25 : #include <taler/taler_exchange_service.h>
26 : #include <taler/taler_testing_lib.h>
27 : #include "taler_merchant_service.h"
28 : #include "taler_merchant_testing_lib.h"
29 :
30 :
31 : /**
32 : * State of a "POST /products" CMD.
33 : */
34 : struct PostProductsState
35 : {
36 :
37 : /**
38 : * Handle for a "POST /products" request.
39 : */
40 : struct TALER_MERCHANT_ProductsPostHandle *iph;
41 :
42 : /**
43 : * The interpreter state.
44 : */
45 : struct TALER_TESTING_Interpreter *is;
46 :
47 : /**
48 : * Base URL of the merchant serving the request.
49 : */
50 : const char *merchant_url;
51 :
52 : /**
53 : * ID of the product to run POST for.
54 : */
55 : const char *product_id;
56 :
57 : /**
58 : * description of the product
59 : */
60 : const char *description;
61 :
62 : /**
63 : * Map from IETF BCP 47 language tags to localized descriptions
64 : */
65 : json_t *description_i18n;
66 :
67 : /**
68 : * unit in which the product is measured (liters, kilograms, packages, etc.)
69 : */
70 : const char *unit;
71 :
72 : /**
73 : * the price for one @a unit of the product
74 : */
75 : struct TALER_Amount price;
76 :
77 : /**
78 : * base64-encoded product image
79 : */
80 : char *image;
81 :
82 : /**
83 : * list of taxes paid by the merchant
84 : */
85 : json_t *taxes;
86 :
87 : /**
88 : * in @e units, -1 to indicate "infinite" (i.e. electronic books)
89 : */
90 : int64_t total_stock;
91 :
92 : /**
93 : * where the product is in stock
94 : */
95 : json_t *address;
96 :
97 : /**
98 : * Minimum age requirement to use for the product.
99 : */
100 : unsigned int minimum_age;
101 :
102 : /**
103 : * when the next restocking is expected to happen, 0 for unknown,
104 : */
105 : struct GNUNET_TIME_Timestamp next_restock;
106 :
107 : /**
108 : * Expected HTTP response code.
109 : */
110 : unsigned int http_status;
111 :
112 : };
113 :
114 :
115 : /**
116 : * Callback for a POST /products operation.
117 : *
118 : * @param cls closure for this function
119 : * @param hr response being processed
120 : */
121 : static void
122 12 : post_products_cb (void *cls,
123 : const struct TALER_MERCHANT_HttpResponse *hr)
124 : {
125 12 : struct PostProductsState *pis = cls;
126 :
127 12 : pis->iph = NULL;
128 12 : if (pis->http_status != hr->http_status)
129 : {
130 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
131 : "Unexpected response code %u (%d) to command %s\n",
132 : hr->http_status,
133 : (int) hr->ec,
134 : TALER_TESTING_interpreter_get_current_label (pis->is));
135 0 : TALER_TESTING_interpreter_fail (pis->is);
136 0 : return;
137 : }
138 12 : switch (hr->http_status)
139 : {
140 10 : case MHD_HTTP_NO_CONTENT:
141 10 : break;
142 0 : case MHD_HTTP_UNAUTHORIZED:
143 0 : break;
144 0 : case MHD_HTTP_FORBIDDEN:
145 0 : break;
146 0 : case MHD_HTTP_NOT_FOUND:
147 0 : break;
148 2 : case MHD_HTTP_CONFLICT:
149 2 : break;
150 0 : default:
151 0 : GNUNET_break (0);
152 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
153 : "Unhandled HTTP status %u for POST /products.\n",
154 : hr->http_status);
155 : }
156 12 : TALER_TESTING_interpreter_next (pis->is);
157 : }
158 :
159 :
160 : /**
161 : * Run the "POST /products" CMD.
162 : *
163 : *
164 : * @param cls closure.
165 : * @param cmd command being run now.
166 : * @param is interpreter state.
167 : */
168 : static void
169 12 : post_products_run (void *cls,
170 : const struct TALER_TESTING_Command *cmd,
171 : struct TALER_TESTING_Interpreter *is)
172 : {
173 12 : struct PostProductsState *pis = cls;
174 :
175 12 : pis->is = is;
176 12 : pis->iph = TALER_MERCHANT_products_post2 (
177 : TALER_TESTING_interpreter_get_context (is),
178 : pis->merchant_url,
179 : pis->product_id,
180 : pis->description,
181 12 : pis->description_i18n,
182 : pis->unit,
183 12 : &pis->price,
184 12 : pis->image,
185 12 : pis->taxes,
186 : pis->total_stock,
187 12 : pis->address,
188 : pis->next_restock,
189 : pis->minimum_age,
190 : &post_products_cb,
191 : pis);
192 12 : GNUNET_assert (NULL != pis->iph);
193 12 : }
194 :
195 :
196 : /**
197 : * Offers information from the POST /products CMD state to other
198 : * commands.
199 : *
200 : * @param cls closure
201 : * @param[out] ret result (could be anything)
202 : * @param trait name of the trait
203 : * @param index index number of the object to extract.
204 : * @return #GNUNET_OK on success
205 : */
206 : static enum GNUNET_GenericReturnValue
207 20 : post_products_traits (void *cls,
208 : const void **ret,
209 : const char *trait,
210 : unsigned int index)
211 : {
212 20 : struct PostProductsState *pps = cls;
213 : struct TALER_TESTING_Trait traits[] = {
214 20 : TALER_TESTING_make_trait_product_description (pps->description),
215 20 : TALER_TESTING_make_trait_i18n_description (pps->description_i18n),
216 20 : TALER_TESTING_make_trait_product_unit (pps->unit),
217 20 : TALER_TESTING_make_trait_amount (&pps->price),
218 20 : TALER_TESTING_make_trait_product_image (pps->image),
219 20 : TALER_TESTING_make_trait_taxes (pps->taxes),
220 20 : TALER_TESTING_make_trait_product_stock (&pps->total_stock),
221 20 : TALER_TESTING_make_trait_address (pps->address),
222 20 : TALER_TESTING_make_trait_timestamp (0,
223 20 : &pps->next_restock),
224 20 : TALER_TESTING_make_trait_product_id (pps->product_id),
225 20 : TALER_TESTING_trait_end (),
226 : };
227 :
228 20 : return TALER_TESTING_get_trait (traits,
229 : ret,
230 : trait,
231 : index);
232 : }
233 :
234 :
235 : /**
236 : * Free the state of a "POST product" CMD, and possibly
237 : * cancel a pending operation thereof.
238 : *
239 : * @param cls closure.
240 : * @param cmd command being run.
241 : */
242 : static void
243 12 : post_products_cleanup (void *cls,
244 : const struct TALER_TESTING_Command *cmd)
245 : {
246 12 : struct PostProductsState *pis = cls;
247 :
248 12 : if (NULL != pis->iph)
249 : {
250 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
251 : "POST /products operation did not complete\n");
252 0 : TALER_MERCHANT_products_post_cancel (pis->iph);
253 : }
254 12 : json_decref (pis->description_i18n);
255 12 : GNUNET_free (pis->image);
256 12 : json_decref (pis->taxes);
257 12 : json_decref (pis->address);
258 12 : GNUNET_free (pis);
259 12 : }
260 :
261 :
262 : struct TALER_TESTING_Command
263 12 : TALER_TESTING_cmd_merchant_post_products2 (
264 : const char *label,
265 : const char *merchant_url,
266 : const char *product_id,
267 : const char *description,
268 : json_t *description_i18n,
269 : const char *unit,
270 : const char *price,
271 : const char *image,
272 : json_t *taxes,
273 : int64_t total_stock,
274 : uint32_t minimum_age,
275 : json_t *address,
276 : struct GNUNET_TIME_Timestamp next_restock,
277 : unsigned int http_status)
278 : {
279 : struct PostProductsState *pis;
280 :
281 12 : GNUNET_assert ((NULL == taxes) ||
282 : json_is_array (taxes));
283 12 : GNUNET_assert ((NULL == description_i18n) ||
284 : json_is_object (description_i18n));
285 12 : pis = GNUNET_new (struct PostProductsState);
286 12 : pis->merchant_url = merchant_url;
287 12 : pis->product_id = product_id;
288 12 : pis->http_status = http_status;
289 12 : pis->description = description;
290 12 : pis->description_i18n = description_i18n; /* ownership taken */
291 12 : pis->unit = unit;
292 12 : GNUNET_assert (GNUNET_OK ==
293 : TALER_string_to_amount (price,
294 : &pis->price));
295 12 : pis->image = GNUNET_strdup (image);
296 12 : pis->taxes = taxes; /* ownership taken */
297 12 : pis->total_stock = total_stock;
298 12 : pis->minimum_age = minimum_age;
299 12 : pis->address = address; /* ownership taken */
300 12 : pis->next_restock = next_restock;
301 : {
302 12 : struct TALER_TESTING_Command cmd = {
303 : .cls = pis,
304 : .label = label,
305 : .run = &post_products_run,
306 : .cleanup = &post_products_cleanup,
307 : .traits = &post_products_traits
308 : };
309 :
310 12 : return cmd;
311 : }
312 : }
313 :
314 :
315 : struct TALER_TESTING_Command
316 10 : TALER_TESTING_cmd_merchant_post_products (
317 : const char *label,
318 : const char *merchant_url,
319 : const char *product_id,
320 : const char *description,
321 : const char *price,
322 : unsigned int http_status)
323 : {
324 10 : return TALER_TESTING_cmd_merchant_post_products2 (
325 : label,
326 : merchant_url,
327 : product_id,
328 : description,
329 : json_pack ("{s:s}", "en", description),
330 : "test-unit",
331 : price,
332 : "",
333 : json_array (),
334 : 4, /* total stock */
335 : 0, /* minimum age */
336 : json_pack ("{s:s}", "street", "my street"),
337 10 : GNUNET_TIME_UNIT_ZERO_TS,
338 : http_status);
339 : }
340 :
341 :
342 : /* end of testing_api_cmd_post_products.c */
|