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