Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2025 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_get_units.c
21 : * @brief command to test GET /private/units
22 : * @author Bohdan Potuzhnyi
23 : */
24 : #include "platform.h"
25 : #include <jansson.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 for a GET /private/units command.
33 : */
34 : struct GetUnitsState
35 : {
36 : /**
37 : * In-flight request handle.
38 : */
39 : struct TALER_MERCHANT_UnitsGetHandle *ugh;
40 :
41 : /**
42 : * Interpreter context.
43 : */
44 : struct TALER_TESTING_Interpreter *is;
45 :
46 : /**
47 : * Merchant backend base URL.
48 : */
49 : const char *merchant_url;
50 :
51 : /**
52 : * Expected HTTP status.
53 : */
54 : unsigned int http_status;
55 :
56 : /**
57 : * Expected references that must appear in the listing.
58 : */
59 : const char **references;
60 :
61 : /**
62 : * Length of @e references.
63 : */
64 : unsigned int references_length;
65 : };
66 :
67 :
68 : /**
69 : * Verify that @a entry matches the traits from @a ref_cmd.
70 : */
71 : static enum GNUNET_GenericReturnValue
72 4 : check_unit_matches (const struct TALER_MERCHANT_UnitEntry *entry,
73 : const struct TALER_TESTING_Command *ref_cmd)
74 : {
75 4 : const char *unit_id = NULL;
76 :
77 4 : if (GNUNET_OK !=
78 4 : TALER_TESTING_get_trait_unit_id (ref_cmd,
79 : &unit_id))
80 : {
81 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
82 : "Internal error: command `%s' lacks unit_id trait\n",
83 : ref_cmd->label);
84 0 : return GNUNET_SYSERR;
85 : }
86 4 : if (0 != strcmp (entry->unit,
87 : unit_id))
88 0 : return GNUNET_NO;
89 :
90 : {
91 4 : const char *unit_name_long = NULL;
92 :
93 4 : if (GNUNET_OK ==
94 4 : TALER_TESTING_get_trait_unit_name_long (ref_cmd,
95 : &unit_name_long))
96 : {
97 4 : if ( (NULL != unit_name_long) &&
98 4 : (0 != strcmp (entry->unit_name_long,
99 : unit_name_long)) )
100 0 : return GNUNET_SYSERR;
101 : }
102 : }
103 : {
104 4 : const char *unit_name_short = NULL;
105 :
106 4 : if (GNUNET_OK ==
107 4 : TALER_TESTING_get_trait_unit_name_short (ref_cmd,
108 : &unit_name_short))
109 : {
110 4 : if ( (NULL != unit_name_short) &&
111 4 : (0 != strcmp (entry->unit_name_short,
112 : unit_name_short)) )
113 0 : return GNUNET_SYSERR;
114 : }
115 : }
116 : {
117 4 : const bool *unit_allow_fraction = NULL;
118 :
119 4 : if (GNUNET_OK ==
120 4 : TALER_TESTING_get_trait_unit_allow_fraction (ref_cmd,
121 : &unit_allow_fraction))
122 : {
123 4 : if ( (NULL != unit_allow_fraction) &&
124 4 : (*unit_allow_fraction != entry->unit_allow_fraction) )
125 : {
126 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
127 : "Unit %s mismatch: expected allow_fraction %d got %d\n",
128 : entry->unit,
129 : (int) *unit_allow_fraction,
130 : (int) entry->unit_allow_fraction);
131 0 : return GNUNET_SYSERR;
132 : }
133 : }
134 : }
135 : {
136 4 : const uint32_t *unit_precision_level = NULL;
137 :
138 4 : if (GNUNET_OK ==
139 4 : TALER_TESTING_get_trait_unit_precision_level (ref_cmd,
140 : &unit_precision_level))
141 : {
142 4 : if ( (NULL != unit_precision_level) &&
143 4 : (*unit_precision_level != entry->unit_precision_level) )
144 : {
145 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
146 : "Unit %s mismatch: expected precision %u got %u\n",
147 : entry->unit,
148 : (unsigned int) *unit_precision_level,
149 : (unsigned int) entry->unit_precision_level);
150 0 : return GNUNET_SYSERR;
151 : }
152 : }
153 : }
154 : {
155 4 : const bool *unit_active = NULL;
156 :
157 4 : if (GNUNET_OK ==
158 4 : TALER_TESTING_get_trait_unit_active (ref_cmd,
159 : &unit_active))
160 : {
161 4 : if ( (NULL != unit_active) &&
162 4 : (*unit_active != entry->unit_active) )
163 : {
164 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
165 : "Unit %s mismatch: expected active %d got %d\n",
166 : entry->unit,
167 : (int) *unit_active,
168 : (int) entry->unit_active);
169 0 : return GNUNET_SYSERR;
170 : }
171 : }
172 : }
173 : {
174 4 : const json_t *unit_name_long_i18n = NULL;
175 :
176 4 : if (GNUNET_OK ==
177 4 : TALER_TESTING_get_trait_unit_name_long_i18n (ref_cmd,
178 : &unit_name_long_i18n))
179 : {
180 4 : if ( (NULL != unit_name_long_i18n) &&
181 8 : ( (NULL == entry->unit_name_long_i18n) ||
182 4 : (1 != json_equal (unit_name_long_i18n,
183 4 : entry->unit_name_long_i18n)) ) )
184 : {
185 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
186 : "Unit %s mismatch: long_i18n differs\n",
187 : entry->unit);
188 0 : return GNUNET_SYSERR;
189 : }
190 : }
191 : }
192 : {
193 4 : const json_t *unit_name_short_i18n = NULL;
194 :
195 4 : if (GNUNET_OK ==
196 4 : TALER_TESTING_get_trait_unit_name_short_i18n (ref_cmd,
197 : &unit_name_short_i18n))
198 : {
199 4 : if ( (NULL != unit_name_short_i18n) &&
200 8 : ( (NULL == entry->unit_name_short_i18n) ||
201 4 : (1 != json_equal (unit_name_short_i18n,
202 4 : entry->unit_name_short_i18n)) ) )
203 : {
204 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
205 : "Unit %s mismatch: short_i18n differs\n",
206 : entry->unit);
207 0 : return GNUNET_SYSERR;
208 : }
209 : }
210 : }
211 4 : return GNUNET_OK;
212 : }
213 :
214 :
215 : /**
216 : * Completion callback for GET /private/units.
217 : */
218 : static void
219 4 : get_units_cb (void *cls,
220 : const struct TALER_MERCHANT_UnitsGetResponse *ugr)
221 : {
222 4 : struct GetUnitsState *gus = cls;
223 :
224 4 : gus->ugh = NULL;
225 4 : if (gus->http_status != ugr->hr.http_status)
226 : {
227 0 : TALER_TESTING_unexpected_status_with_body (gus->is,
228 : ugr->hr.http_status,
229 : gus->http_status,
230 : ugr->hr.reply);
231 0 : return;
232 : }
233 4 : if (MHD_HTTP_OK == ugr->hr.http_status)
234 : {
235 8 : for (unsigned int i = 0; i < gus->references_length; ++i)
236 : {
237 4 : const char *label = gus->references[i];
238 : const struct TALER_TESTING_Command *ref_cmd;
239 4 : enum GNUNET_GenericReturnValue match = GNUNET_NO;
240 :
241 4 : ref_cmd = TALER_TESTING_interpreter_lookup_command (gus->is,
242 : label);
243 4 : if (NULL == ref_cmd)
244 : {
245 0 : GNUNET_break (0);
246 0 : TALER_TESTING_interpreter_fail (gus->is);
247 0 : return;
248 : }
249 4 : for (unsigned int j = 0;
250 4 : j < ugr->details.ok.units_length;
251 0 : ++j)
252 : {
253 4 : match = check_unit_matches (&ugr->details.ok.units[j],
254 : ref_cmd);
255 4 : if (GNUNET_SYSERR == match)
256 0 : break;
257 4 : if (GNUNET_OK == match)
258 4 : break;
259 : }
260 4 : if (GNUNET_SYSERR == match)
261 : {
262 0 : GNUNET_break (0);
263 0 : TALER_TESTING_interpreter_fail (gus->is);
264 0 : return;
265 : }
266 4 : if (GNUNET_OK != match)
267 : {
268 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
269 : "Unit referenced by `%s' not found in GET /private/units response\n",
270 : label);
271 0 : TALER_TESTING_interpreter_fail (gus->is);
272 0 : return;
273 : }
274 : }
275 : }
276 4 : TALER_TESTING_interpreter_next (gus->is);
277 : }
278 :
279 :
280 : /**
281 : * Issue the GET request.
282 : */
283 : static void
284 4 : get_units_run (void *cls,
285 : const struct TALER_TESTING_Command *cmd,
286 : struct TALER_TESTING_Interpreter *is)
287 : {
288 4 : struct GetUnitsState *gus = cls;
289 :
290 4 : gus->is = is;
291 4 : gus->ugh = TALER_MERCHANT_units_get (
292 : TALER_TESTING_interpreter_get_context (is),
293 : gus->merchant_url,
294 : &get_units_cb,
295 : gus);
296 4 : if (NULL == gus->ugh)
297 : {
298 0 : GNUNET_break (0);
299 0 : TALER_TESTING_interpreter_fail (is);
300 : }
301 4 : }
302 :
303 :
304 : /**
305 : * Cleanup.
306 : */
307 : static void
308 4 : get_units_cleanup (void *cls,
309 : const struct TALER_TESTING_Command *cmd)
310 : {
311 4 : struct GetUnitsState *gus = cls;
312 :
313 4 : if (NULL != gus->ugh)
314 : {
315 0 : TALER_MERCHANT_units_get_cancel (gus->ugh);
316 0 : gus->ugh = NULL;
317 : }
318 4 : GNUNET_array_grow (gus->references,
319 : gus->references_length,
320 : 0);
321 4 : GNUNET_free (gus);
322 4 : }
323 :
324 :
325 : struct TALER_TESTING_Command
326 4 : TALER_TESTING_cmd_merchant_get_units (const char *label,
327 : const char *merchant_url,
328 : unsigned int http_status,
329 : ...)
330 : {
331 : struct GetUnitsState *gus;
332 : va_list ap;
333 : const char *ref;
334 :
335 4 : gus = GNUNET_new (struct GetUnitsState);
336 4 : gus->merchant_url = merchant_url;
337 4 : gus->http_status = http_status;
338 :
339 4 : va_start (ap, http_status);
340 8 : while (NULL != (ref = va_arg (ap, const char *)))
341 : {
342 4 : GNUNET_array_append (gus->references,
343 : gus->references_length,
344 : ref);
345 : }
346 4 : va_end (ap);
347 :
348 : {
349 4 : struct TALER_TESTING_Command cmd = {
350 : .cls = gus,
351 : .label = label,
352 : .run = &get_units_run,
353 : .cleanup = &get_units_cleanup
354 : };
355 :
356 4 : return cmd;
357 : }
358 : }
359 :
360 :
361 : /* end of testing_api_cmd_get_units.c */
|