aboutsummaryrefslogtreecommitdiff
path: root/src/testing/testing_api_loop.c
diff options
context:
space:
mode:
authorChristian Grothoff <grothoff@gnunet.org>2021-10-04 18:15:21 +0200
committerChristian Grothoff <grothoff@gnunet.org>2021-10-04 18:15:21 +0200
commit23b5cf23674d557864284eff81d876ee1b5631bf (patch)
tree2cdabbf345395d0bbcd3e415ff2386d53a30d0d7 /src/testing/testing_api_loop.c
parentf146e80752e73247acb9d6c7463188a82d26a774 (diff)
downloadgnunet-23b5cf23674d557864284eff81d876ee1b5631bf.tar.gz
gnunet-23b5cf23674d557864284eff81d876ee1b5631bf.zip
-basic santiy for testing API, breaks transport/ build
Diffstat (limited to 'src/testing/testing_api_loop.c')
-rw-r--r--src/testing/testing_api_loop.c290
1 files changed, 163 insertions, 127 deletions
diff --git a/src/testing/testing_api_loop.c b/src/testing/testing_api_loop.c
index 1c8eb1db6..b21e01fcc 100644
--- a/src/testing/testing_api_loop.c
+++ b/src/testing/testing_api_loop.c
@@ -24,25 +24,64 @@
24 * @author Christian Grothoff (GNU Taler testing) 24 * @author Christian Grothoff (GNU Taler testing)
25 * @author Marcello Stanisci (GNU Taler testing) 25 * @author Marcello Stanisci (GNU Taler testing)
26 * @author t3sserakt 26 * @author t3sserakt
27 *
28 * FIXME:
29 * - interpreter failure is NOT returned properly yet!
30 * - abuse of shutdown logic for interpreter termination
31 * => API design flaw to be fixed!
32 */ 27 */
33#include "platform.h" 28#include "platform.h"
34#include "gnunet_util_lib.h" 29#include "gnunet_util_lib.h"
35#include "gnunet_testing_ng_lib.h" 30#include "gnunet_testing_ng_lib.h"
36#include "testing.h" 31#include "testing.h"
37 32
38
39/** 33/**
40 * Lookup command by label. 34 * Global state of the interpreter, used by a command
41 * 35 * to access information about other commands.
42 * @param is interpreter to lookup command in
43 * @param label label to look for
44 * @return NULL if command was not found
45 */ 36 */
37struct GNUNET_TESTING_Interpreter
38{
39
40 /**
41 * Function to call with the test result.
42 */
43 GNUNET_TESTING_ResultCallback rc;
44
45 /**
46 * Closure for @e rc.
47 */
48 void *rc_cls;
49
50 /**
51 * Commands the interpreter will run.
52 */
53 struct GNUNET_TESTING_Command *commands;
54
55 /**
56 * Interpreter task (if one is scheduled).
57 */
58 struct GNUNET_SCHEDULER_Task *task;
59
60 /**
61 * Final task that returns the result.
62 */
63 struct GNUNET_SCHEDULER_Task *final_task;
64
65 /**
66 * Task run on timeout.
67 */
68 struct GNUNET_SCHEDULER_Task *timeout_task;
69
70 /**
71 * Instruction pointer. Tells #interpreter_run() which instruction to run
72 * next. Need (signed) int because it gets -1 when rewinding the
73 * interpreter to the first CMD.
74 */
75 int ip;
76
77 /**
78 * Result of the testcases, #GNUNET_OK on success
79 */
80 enum GNUNET_GenericReturnValue result;
81
82};
83
84
46const struct GNUNET_TESTING_Command * 85const struct GNUNET_TESTING_Command *
47GNUNET_TESTING_interpreter_lookup_command ( 86GNUNET_TESTING_interpreter_lookup_command (
48 struct GNUNET_TESTING_Interpreter *is, 87 struct GNUNET_TESTING_Interpreter *is,
@@ -65,7 +104,7 @@ GNUNET_TESTING_interpreter_lookup_command (
65 label)) ) 104 label)) )
66 return cmd; 105 return cmd;
67 106
68 if (GNUNET_TESTING_cmd_is_batch (cmd)) 107 if (GNUNET_TESTING_cmd_is_batch_ (cmd))
69 { 108 {
70#define BATCH_INDEX 1 109#define BATCH_INDEX 1
71 struct GNUNET_TESTING_Command *batch; 110 struct GNUNET_TESTING_Command *batch;
@@ -73,7 +112,7 @@ GNUNET_TESTING_interpreter_lookup_command (
73 struct GNUNET_TESTING_Command *icmd; 112 struct GNUNET_TESTING_Command *icmd;
74 const struct GNUNET_TESTING_Command *match; 113 const struct GNUNET_TESTING_Command *match;
75 114
76 current = GNUNET_TESTING_cmd_batch_get_current (cmd); 115 current = GNUNET_TESTING_cmd_batch_get_current_ (cmd);
77 GNUNET_assert (GNUNET_OK == 116 GNUNET_assert (GNUNET_OK ==
78 GNUNET_TESTING_get_trait_cmd (cmd, 117 GNUNET_TESTING_get_trait_cmd (cmd,
79 BATCH_INDEX, 118 BATCH_INDEX,
@@ -96,10 +135,58 @@ GNUNET_TESTING_interpreter_lookup_command (
96 } 135 }
97 } 136 }
98 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 137 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
99 "Command not found: %s\n", 138 "Command `%s' not found\n",
100 label); 139 label);
101 return NULL; 140 return NULL;
141}
142
143
144/**
145 * Finish the test run, return the final result.
146 *
147 * @param cls the `struct GNUNET_TESTING_Interpreter`
148 */
149static void
150finish_test (void *cls)
151{
152 struct GNUNET_TESTING_Interpreter *is = cls;
153 struct GNUNET_TESTING_Command *cmd;
154 const char *label;
102 155
156 is->final_task = NULL;
157 label = is->commands[is->ip].label;
158 if (NULL == label)
159 label = "END";
160 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
161 "Interpreter finishes at `%s' with status %d\n",
162 label,
163 is->result);
164 for (unsigned int j = 0;
165 NULL != (cmd = &is->commands[j])->label;
166 j++)
167 {
168 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
169 "Cleaning up cmd %s\n",
170 cmd->label);
171 cmd->cleanup (cmd->cls);
172 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
173 "Cleaned up cmd %s\n",
174 cmd->label);
175 }
176 if (NULL != is->task)
177 {
178 GNUNET_SCHEDULER_cancel (is->task);
179 is->task = NULL;
180 }
181 if (NULL != is->timeout_task)
182 {
183 GNUNET_SCHEDULER_cancel (is->timeout_task);
184 is->timeout_task = NULL;
185 }
186 GNUNET_free (is->commands);
187 is->rc (is->rc_cls,
188 is->result);
189 GNUNET_free (is);
103} 190}
104 191
105 192
@@ -125,15 +212,10 @@ interpreter_next (void *cls)
125 212
126 if (GNUNET_SYSERR == is->result) 213 if (GNUNET_SYSERR == is->result)
127 return; /* ignore, we already failed! */ 214 return; /* ignore, we already failed! */
128 if (GNUNET_TESTING_cmd_is_batch (cmd)) 215 cmd->finish_time = GNUNET_TIME_absolute_get ();
129 { 216 if ( (! GNUNET_TESTING_cmd_is_batch_ (cmd)) ||
130 GNUNET_TESTING_cmd_batch_next (is); 217 (! GNUNET_TESTING_cmd_batch_next_ (cmd->cls)) )
131 }
132 else
133 {
134 cmd->finish_time = GNUNET_TIME_absolute_get ();
135 is->ip++; 218 is->ip++;
136 }
137 if (0 == (ipc % 1000)) 219 if (0 == (ipc % 1000))
138 { 220 {
139 if (0 != ipc) 221 if (0 != ipc)
@@ -150,26 +232,24 @@ interpreter_next (void *cls)
150} 232}
151 233
152 234
153/**
154 * Current command failed, clean up and fail the test case.
155 *
156 * @param is interpreter of the test
157 */
158void 235void
159GNUNET_TESTING_interpreter_fail (struct GNUNET_TESTING_Interpreter *is) 236GNUNET_TESTING_interpreter_fail (struct GNUNET_TESTING_Interpreter *is)
160{ 237{
161 struct GNUNET_TESTING_Command *cmd = &is->commands[is->ip]; 238 struct GNUNET_TESTING_Command *cmd = &is->commands[is->ip];
162 239
163 if (GNUNET_SYSERR == is->result) 240 if (GNUNET_SYSERR == is->result)
241 {
242 GNUNET_break (0);
164 return; /* ignore, we already failed! */ 243 return; /* ignore, we already failed! */
244 }
165 if (NULL != cmd) 245 if (NULL != cmd)
166 { 246 {
167 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 247 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
168 "Failed at command `%s'\n", 248 "Failed at command `%s'\n",
169 cmd->label); 249 cmd->label);
170 while (GNUNET_TESTING_cmd_is_batch (cmd)) 250 while (GNUNET_TESTING_cmd_is_batch_ (cmd))
171 { 251 {
172 cmd = GNUNET_TESTING_cmd_batch_get_current (cmd); 252 cmd = GNUNET_TESTING_cmd_batch_get_current_ (cmd);
173 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 253 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
174 "Failed in batch at command `%s'\n", 254 "Failed in batch at command `%s'\n",
175 cmd->label); 255 cmd->label);
@@ -181,29 +261,12 @@ GNUNET_TESTING_interpreter_fail (struct GNUNET_TESTING_Interpreter *is)
181 "Failed with CMD being NULL!\n"); 261 "Failed with CMD being NULL!\n");
182 } 262 }
183 is->result = GNUNET_SYSERR; 263 is->result = GNUNET_SYSERR;
184 GNUNET_SCHEDULER_shutdown (); 264 GNUNET_assert (NULL == is->final_task);
185} 265 is->final_task = GNUNET_SCHEDULER_add_now (&finish_test,
186 266 is);
187
188/**
189 * Create command array terminator.
190 *
191 * @return a end-command.
192 */
193struct GNUNET_TESTING_Command
194GNUNET_TESTING_cmd_end (void)
195{
196 static struct GNUNET_TESTING_Command cmd = {
197 .label = NULL
198 };
199
200 return cmd;
201} 267}
202 268
203 269
204/**
205 * Obtain current label.
206 */
207const char * 270const char *
208GNUNET_TESTING_interpreter_get_current_label ( 271GNUNET_TESTING_interpreter_get_current_label (
209 struct GNUNET_TESTING_Interpreter *is) 272 struct GNUNET_TESTING_Interpreter *is)
@@ -234,12 +297,9 @@ interpreter_run (void *cls)
234 GNUNET_SCHEDULER_shutdown (); 297 GNUNET_SCHEDULER_shutdown ();
235 return; 298 return;
236 } 299 }
237 if (NULL != cmd) 300 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
238 { 301 "Running command `%s'\n",
239 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 302 cmd->label);
240 "Running command `%s'\n",
241 cmd->label);
242 }
243 cmd->start_time 303 cmd->start_time
244 = cmd->last_req_time 304 = cmd->last_req_time
245 = GNUNET_TIME_absolute_get (); 305 = GNUNET_TIME_absolute_get ();
@@ -261,57 +321,6 @@ interpreter_run (void *cls)
261 321
262 322
263/** 323/**
264 * Function run when the test terminates (good or bad).
265 * Cleans up our state.
266 *
267 * @param cls the interpreter state.
268 */
269static void
270do_shutdown (void *cls)
271{
272 struct GNUNET_TESTING_Interpreter *is = cls;
273 struct GNUNET_TESTING_Command *cmd;
274 const char *label;
275
276 label = is->commands[is->ip].label;
277 if (NULL == label)
278 label = "END";
279 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
280 "Executing shutdown at `%s'\n",
281 label);
282 for (unsigned int j = 0;
283 NULL != (cmd = &is->commands[j])->label;
284 j++)
285 {
286 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
287 "Cleaning up cmd %s\n",
288 cmd->label);
289 cmd->cleanup (cmd->cls);
290 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
291 "Cleaned up cmd %s\n",
292 cmd->label);
293 }
294 if (NULL != is->finish_task)
295 {
296 GNUNET_SCHEDULER_cancel (is->finish_task);
297 is->finish_task = NULL;
298 }
299 if (NULL != is->task)
300 {
301 GNUNET_SCHEDULER_cancel (is->task);
302 is->task = NULL;
303 }
304 if (NULL != is->timeout_task)
305 {
306 GNUNET_SCHEDULER_cancel (is->timeout_task);
307 is->timeout_task = NULL;
308 }
309 GNUNET_free (is->commands);
310 GNUNET_free (is);
311}
312
313
314/**
315 * Function run when the test terminates (good or bad) with timeout. 324 * Function run when the test terminates (good or bad) with timeout.
316 * 325 *
317 * @param cls the interpreter state 326 * @param cls the interpreter state
@@ -323,20 +332,24 @@ do_timeout (void *cls)
323 332
324 is->timeout_task = NULL; 333 is->timeout_task = NULL;
325 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 334 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
326 "Terminating test due to timeout\n"); 335 "Terminating test due to global timeout\n");
327 GNUNET_SCHEDULER_shutdown (); 336 is->result = GNUNET_SYSERR;
337 finish_test (is);
328} 338}
329 339
330 340
331enum GNUNET_GenericReturnValue 341void
332GNUNET_TESTING_run (const char *cfg_filename, 342GNUNET_TESTING_run (struct GNUNET_TESTING_Command *commands,
333 struct GNUNET_TESTING_Command *commands, 343 struct GNUNET_TIME_Relative timeout,
334 struct GNUNET_TIME_Relative timeout) 344 GNUNET_TESTING_ResultCallback rc,
345 void *rc_cls)
335{ 346{
336 struct GNUNET_TESTING_Interpreter *is; 347 struct GNUNET_TESTING_Interpreter *is;
337 unsigned int i; 348 unsigned int i;
338 349
339 is = GNUNET_new (struct GNUNET_TESTING_Interpreter); 350 is = GNUNET_new (struct GNUNET_TESTING_Interpreter);
351 is->rc = rc;
352 is->rc_cls = rc_cls;
340 /* get the number of commands */ 353 /* get the number of commands */
341 for (i = 0; NULL != commands[i].label; i++) 354 for (i = 0; NULL != commands[i].label; i++)
342 ; 355 ;
@@ -349,11 +362,8 @@ GNUNET_TESTING_run (const char *cfg_filename,
349 = GNUNET_SCHEDULER_add_delayed (timeout, 362 = GNUNET_SCHEDULER_add_delayed (timeout,
350 &do_timeout, 363 &do_timeout,
351 is); 364 is);
352 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
353 is);
354 is->task = GNUNET_SCHEDULER_add_now (&interpreter_run, 365 is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
355 is); 366 is);
356 return GNUNET_OK;
357} 367}
358 368
359 369
@@ -362,14 +372,46 @@ GNUNET_TESTING_run (const char *cfg_filename,
362 */ 372 */
363struct MainParams 373struct MainParams
364{ 374{
365 const char *cfg_filename; 375
376 /**
377 * NULL-label terminated array of commands.
378 */
366 struct GNUNET_TESTING_Command *commands; 379 struct GNUNET_TESTING_Command *commands;
380
381 /**
382 * Global timeout for the test.
383 */
367 struct GNUNET_TIME_Relative timeout; 384 struct GNUNET_TIME_Relative timeout;
385
386 /**
387 * Set to #EXIT_FAILURE on error.
388 */
368 int rv; 389 int rv;
369}; 390};
370 391
371 392
372/** 393/**
394 * Function called with the final result of the test.
395 *
396 * @param cls the `struct MainParams`
397 * @param rv #GNUNET_OK if the test passed
398 */
399static void
400handle_result (void *cls,
401 enum GNUNET_GenericReturnValue rv)
402{
403 struct MainParams *mp = cls;
404
405 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
406 "Test exits with status %d\n",
407 rv);
408 if (GNUNET_OK != rv)
409 mp->rv = EXIT_FAILURE;
410 GNUNET_SCHEDULER_shutdown ();
411}
412
413
414/**
373 * Main function to run the test cases. 415 * Main function to run the test cases.
374 * 416 *
375 * @param cls a `struct MainParams *` 417 * @param cls a `struct MainParams *`
@@ -379,24 +421,18 @@ loop_run (void *cls)
379{ 421{
380 struct MainParams *mp = cls; 422 struct MainParams *mp = cls;
381 423
382 if (GNUNET_OK != 424 GNUNET_TESTING_run (mp->commands,
383 GNUNET_TESTING_run (mp->cfg_filename, 425 mp->timeout,
384 mp->commands, 426 &handle_result,
385 mp->timeout)) 427 mp);
386 {
387 GNUNET_break (0);
388 mp->rv = EXIT_FAILURE;
389 }
390} 428}
391 429
392 430
393int 431int
394GNUNET_TESTING_main (const char *cfg_filename, 432GNUNET_TESTING_main (struct GNUNET_TESTING_Command *commands,
395 struct GNUNET_TESTING_Command *commands,
396 struct GNUNET_TIME_Relative timeout) 433 struct GNUNET_TIME_Relative timeout)
397{ 434{
398 struct MainParams mp = { 435 struct MainParams mp = {
399 .cfg_filename = cfg_filename,
400 .commands = commands, 436 .commands = commands,
401 .timeout = timeout, 437 .timeout = timeout,
402 .rv = EXIT_SUCCESS 438 .rv = EXIT_SUCCESS