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 "GET product" 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 : * when the next restocking is expected to happen, 0 for unknown,
99 : */
100 : struct GNUNET_TIME_Timestamp next_restock;
101 :
102 : /**
103 : * Expected HTTP response code.
104 : */
105 : unsigned int http_status;
106 :
107 : };
108 :
109 :
110 : /**
111 : * Callback for a POST /products operation.
112 : *
113 : * @param cls closure for this function
114 : * @param hr response being processed
115 : */
116 : static void
117 0 : post_products_cb (void *cls,
118 : const struct TALER_MERCHANT_HttpResponse *hr)
119 : {
120 0 : struct PostProductsState *pis = cls;
121 :
122 0 : pis->iph = NULL;
123 0 : if (pis->http_status != hr->http_status)
124 : {
125 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
126 : "Unexpected response code %u (%d) to command %s\n",
127 : hr->http_status,
128 : (int) hr->ec,
129 : TALER_TESTING_interpreter_get_current_label (pis->is));
130 0 : TALER_TESTING_interpreter_fail (pis->is);
131 0 : return;
132 : }
133 0 : switch (hr->http_status)
134 : {
135 0 : case MHD_HTTP_NO_CONTENT:
136 0 : break;
137 0 : case MHD_HTTP_UNAUTHORIZED:
138 0 : break;
139 0 : case MHD_HTTP_FORBIDDEN:
140 0 : break;
141 0 : case MHD_HTTP_NOT_FOUND:
142 0 : break;
143 0 : case MHD_HTTP_CONFLICT:
144 0 : break;
145 0 : default:
146 0 : GNUNET_break (0);
147 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
148 : "Unhandled HTTP status %u for POST /products.\n",
149 : hr->http_status);
150 : }
151 0 : TALER_TESTING_interpreter_next (pis->is);
152 : }
153 :
154 :
155 : /**
156 : * Run the "POST /products" CMD.
157 : *
158 : *
159 : * @param cls closure.
160 : * @param cmd command being run now.
161 : * @param is interpreter state.
162 : */
163 : static void
164 0 : post_products_run (void *cls,
165 : const struct TALER_TESTING_Command *cmd,
166 : struct TALER_TESTING_Interpreter *is)
167 : {
168 0 : struct PostProductsState *pis = cls;
169 :
170 0 : pis->is = is;
171 0 : pis->iph = TALER_MERCHANT_products_post (is->ctx,
172 : pis->merchant_url,
173 : pis->product_id,
174 : pis->description,
175 0 : pis->description_i18n,
176 : pis->unit,
177 0 : &pis->price,
178 0 : pis->image,
179 0 : pis->taxes,
180 : pis->total_stock,
181 0 : pis->address,
182 : pis->next_restock,
183 : &post_products_cb,
184 : pis);
185 0 : GNUNET_assert (NULL != pis->iph);
186 0 : }
187 :
188 :
189 : /**
190 : * Offers information from the POST /products CMD state to other
191 : * commands.
192 : *
193 : * @param cls closure
194 : * @param[out] ret result (could be anything)
195 : * @param trait name of the trait
196 : * @param index index number of the object to extract.
197 : * @return #GNUNET_OK on success
198 : */
199 : static int
200 0 : post_products_traits (void *cls,
201 : const void **ret,
202 : const char *trait,
203 : unsigned int index)
204 : {
205 0 : struct PostProductsState *pps = cls;
206 : struct TALER_TESTING_Trait traits[] = {
207 0 : TALER_TESTING_make_trait_product_description (&pps->description),
208 0 : TALER_TESTING_make_trait_i18n_description (pps->description_i18n),
209 0 : TALER_TESTING_make_trait_product_unit (&pps->unit),
210 0 : TALER_TESTING_make_trait_amount (&pps->price),
211 0 : TALER_TESTING_make_trait_product_image (
212 0 : (const char **) &pps->image),
213 0 : TALER_TESTING_make_trait_taxes (pps->taxes),
214 0 : TALER_TESTING_make_trait_product_stock (&pps->total_stock),
215 0 : TALER_TESTING_make_trait_address (pps->address),
216 0 : TALER_TESTING_make_trait_timestamp (0,
217 0 : &pps->next_restock),
218 0 : TALER_TESTING_make_trait_product_id (&pps->product_id),
219 0 : TALER_TESTING_trait_end (),
220 : };
221 :
222 0 : return TALER_TESTING_get_trait (traits,
223 : ret,
224 : trait,
225 : index);
226 : }
227 :
228 :
229 : /**
230 : * Free the state of a "POST product" CMD, and possibly
231 : * cancel a pending operation thereof.
232 : *
233 : * @param cls closure.
234 : * @param cmd command being run.
235 : */
236 : static void
237 0 : post_products_cleanup (void *cls,
238 : const struct TALER_TESTING_Command *cmd)
239 : {
240 0 : struct PostProductsState *pis = cls;
241 :
242 0 : if (NULL != pis->iph)
243 : {
244 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
245 : "POST /products operation did not complete\n");
246 0 : TALER_MERCHANT_products_post_cancel (pis->iph);
247 : }
248 0 : json_decref (pis->description_i18n);
249 0 : GNUNET_free (pis->image);
250 0 : json_decref (pis->taxes);
251 0 : json_decref (pis->address);
252 0 : GNUNET_free (pis);
253 0 : }
254 :
255 :
256 : struct TALER_TESTING_Command
257 0 : TALER_TESTING_cmd_merchant_post_products2 (
258 : const char *label,
259 : const char *merchant_url,
260 : const char *product_id,
261 : const char *description,
262 : json_t *description_i18n,
263 : const char *unit,
264 : const char *price,
265 : const char *image,
266 : json_t *taxes,
267 : int64_t total_stock,
268 : json_t *address,
269 : struct GNUNET_TIME_Timestamp next_restock,
270 : unsigned int http_status)
271 : {
272 : struct PostProductsState *pis;
273 :
274 0 : GNUNET_assert ((NULL == taxes) ||
275 : json_is_array (taxes));
276 0 : GNUNET_assert ((NULL == description_i18n) ||
277 : json_is_object (description_i18n));
278 0 : pis = GNUNET_new (struct PostProductsState);
279 0 : pis->merchant_url = merchant_url;
280 0 : pis->product_id = product_id;
281 0 : pis->http_status = http_status;
282 0 : pis->description = description;
283 0 : pis->description_i18n = description_i18n; /* ownership taken */
284 0 : pis->unit = unit;
285 0 : GNUNET_assert (GNUNET_OK ==
286 : TALER_string_to_amount (price,
287 : &pis->price));
288 0 : pis->image = GNUNET_strdup (image);
289 0 : pis->taxes = taxes; /* ownership taken */
290 0 : pis->total_stock = total_stock;
291 0 : pis->address = address; /* ownership taken */
292 0 : pis->next_restock = next_restock;
293 : {
294 0 : struct TALER_TESTING_Command cmd = {
295 : .cls = pis,
296 : .label = label,
297 : .run = &post_products_run,
298 : .cleanup = &post_products_cleanup,
299 : .traits = &post_products_traits
300 : };
301 :
302 0 : return cmd;
303 : }
304 : }
305 :
306 :
307 : struct TALER_TESTING_Command
308 0 : TALER_TESTING_cmd_merchant_post_products (const char *label,
309 : const char *merchant_url,
310 : const char *product_id,
311 : const char *description,
312 : const char *price,
313 : unsigned int http_status)
314 : {
315 0 : return TALER_TESTING_cmd_merchant_post_products2 (
316 : label,
317 : merchant_url,
318 : product_id,
319 : description,
320 : json_pack ("{s:s}", "en", description),
321 : "test-unit",
322 : price,
323 : "",
324 : json_array (),
325 : 4,
326 : json_pack ("{s:s}", "street", "my street"),
327 0 : GNUNET_TIME_UNIT_ZERO_TS,
328 : http_status);
329 : }
330 :
331 :
332 : /* end of testing_api_cmd_post_products.c */
|