aboutsummaryrefslogtreecommitdiff
path: root/src/testing
diff options
context:
space:
mode:
Diffstat (limited to 'src/testing')
-rw-r--r--src/testing/testing.h74
-rw-r--r--src/testing/testing_api_cmd_batch.c3
-rw-r--r--src/testing/testing_api_cmd_hello_world.c1
-rw-r--r--src/testing/testing_api_cmd_hello_world_birth.c1
-rw-r--r--src/testing/testing_api_loop.c186
5 files changed, 256 insertions, 9 deletions
diff --git a/src/testing/testing.h b/src/testing/testing.h
new file mode 100644
index 000000000..b12466530
--- /dev/null
+++ b/src/testing/testing.h
@@ -0,0 +1,74 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2021 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet 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 GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @author t3sserakt
23 */
24
25#include "gnunet_util_lib.h"
26
27/**
28 * Global state of the interpreter, used by a command
29 * to access information about other commands.
30 */
31// SUGGESTION: consider making this struct opaque (only known inside of libgnunettesting,
32// say main loop and a few select commands, like next/fail/batch); + helper
33// function to access 'cfg'?
34struct GNUNET_TESTING_Interpreter
35{
36
37 /**
38 * Commands the interpreter will run.
39 */
40 struct GNUNET_TESTING_Command *commands;
41
42 /**
43 * Interpreter task (if one is scheduled).
44 */
45 struct GNUNET_SCHEDULER_Task *task;
46
47 /**
48 * Finish task of a blocking call to a commands finish method.
49 */
50 struct GNUNET_SCHEDULER_Task *finish_task;
51
52 /**
53 * Our configuration.
54 */
55 const struct GNUNET_CONFIGURATION_Handle *cfg;
56
57 /**
58 * Task run on timeout.
59 */
60 struct GNUNET_SCHEDULER_Task *timeout_task;
61
62 /**
63 * Instruction pointer. Tells #interpreter_run() which instruction to run
64 * next. Need (signed) int because it gets -1 when rewinding the
65 * interpreter to the first CMD.
66 */
67 int ip;
68
69 /**
70 * Result of the testcases, #GNUNET_OK on success
71 */
72 int result;
73
74};
diff --git a/src/testing/testing_api_cmd_batch.c b/src/testing/testing_api_cmd_batch.c
index 531778129..af260f80d 100644
--- a/src/testing/testing_api_cmd_batch.c
+++ b/src/testing/testing_api_cmd_batch.c
@@ -26,7 +26,7 @@
26 */ 26 */
27#include "platform.h" 27#include "platform.h"
28#include "gnunet_testing_ng_lib.h" 28#include "gnunet_testing_ng_lib.h"
29 29#include "testing.h"
30 30
31/** 31/**
32 * State for a "batch" CMD. 32 * State for a "batch" CMD.
@@ -70,7 +70,6 @@ batch_run (void *cls,
70 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 70 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
71 "Exiting from batch: %s\n", 71 "Exiting from batch: %s\n",
72 cmd->label); 72 cmd->label);
73 GNUNET_TESTING_interpreter_next (is);
74 return; 73 return;
75 } 74 }
76 bs->batch[bs->batch_ip].start_time 75 bs->batch[bs->batch_ip].start_time
diff --git a/src/testing/testing_api_cmd_hello_world.c b/src/testing/testing_api_cmd_hello_world.c
index 8c1d7353d..4347ac818 100644
--- a/src/testing/testing_api_cmd_hello_world.c
+++ b/src/testing/testing_api_cmd_hello_world.c
@@ -89,7 +89,6 @@ hello_world_run (void *cls,
89 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 89 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
90 "Now I am a %s\n", 90 "Now I am a %s\n",
91 hs->message); 91 hs->message);
92 GNUNET_TESTING_interpreter_next (is);
93} 92}
94 93
95/** 94/**
diff --git a/src/testing/testing_api_cmd_hello_world_birth.c b/src/testing/testing_api_cmd_hello_world_birth.c
index 0faf93cd8..2a5bded92 100644
--- a/src/testing/testing_api_cmd_hello_world_birth.c
+++ b/src/testing/testing_api_cmd_hello_world_birth.c
@@ -112,7 +112,6 @@ hello_world_birth_run (void *cls,
112 { 112 {
113 hbs->what_am_i = "boy!"; 113 hbs->what_am_i = "boy!";
114 } 114 }
115 GNUNET_TESTING_interpreter_next (is);
116} 115}
117 116
118/** 117/**
diff --git a/src/testing/testing_api_loop.c b/src/testing/testing_api_loop.c
index f29329a60..dbd86ba90 100644
--- a/src/testing/testing_api_loop.c
+++ b/src/testing/testing_api_loop.c
@@ -28,10 +28,50 @@
28#include "platform.h" 28#include "platform.h"
29#include "gnunet_util_lib.h" 29#include "gnunet_util_lib.h"
30#include "gnunet_testing_ng_lib.h" 30#include "gnunet_testing_ng_lib.h"
31#include "testing.h"
31 32
32struct GNUNET_TESTING_Interpreter *is; 33struct GNUNET_TESTING_Interpreter *is;
33 34
34/** 35/**
36 * Closure used to sync an asynchronous with an synchronous command.
37 */
38struct SyncTaskClosure
39{
40
41 /**
42 * The asynchronous command the synchronous command waits for.
43 */
44 const struct GNUNET_TESTING_Command *async_cmd;
45
46 /**
47 * The synchronous command that waits for the asynchronous command.
48 */
49 const struct GNUNET_TESTING_Command *sync_cmd;
50
51 /**
52 * The interpreter of the test.
53 */
54 struct GNUNET_TESTING_Interpreter *is;
55};
56
57/**
58* Closure used to run the finish task.
59*/
60struct FinishTaskClosure
61{
62
63 /**
64 * The asynchronous command the synchronous command waits for.
65 */
66 const struct GNUNET_TESTING_Command *cmd;
67
68 /**
69 * The interpreter of the test.
70 */
71 struct GNUNET_TESTING_Interpreter *is;
72};
73
74/**
35 * Lookup command by label. 75 * Lookup command by label.
36 * 76 *
37 * @param label label to look for 77 * @param label label to look for
@@ -107,9 +147,10 @@ interpreter_run (void *cls);
107/** 147/**
108 * Current command is done, run the next one. 148 * Current command is done, run the next one.
109 */ 149 */
110void 150static void
111GNUNET_TESTING_interpreter_next (struct GNUNET_TESTING_Interpreter *is) 151interpreter_next (void *cls)
112{ 152{
153 struct GNUNET_TESTING_Interpreter *is = cls;
113 static unsigned long long ipc; 154 static unsigned long long ipc;
114 static struct GNUNET_TIME_Absolute last_report; 155 static struct GNUNET_TIME_Absolute last_report;
115 struct GNUNET_TESTING_Command *cmd = &is->commands[is->ip]; 156 struct GNUNET_TESTING_Command *cmd = &is->commands[is->ip];
@@ -141,6 +182,123 @@ GNUNET_TESTING_interpreter_next (struct GNUNET_TESTING_Interpreter *is)
141} 182}
142 183
143 184
185static void
186run_finish_task_next (void *cls)
187{
188 struct FinishTaskClosure *ftc = cls;
189 const struct GNUNET_TESTING_Command *cmd = ftc->cmd;
190 struct GNUNET_TESTING_Interpreter *is = ftc->is;
191
192 if (cmd->finish (cmd->cls, &interpreter_next, is))
193 {
194 is->finish_task = GNUNET_SCHEDULER_add_now (&run_finish_task_next, ftc);
195 }
196 else
197 {
198 is->finish_task = NULL;
199 }
200
201}
202
203
204static void
205run_finish_task_sync (void *cls)
206{
207 struct SyncTaskClosure *stc = cls;
208 const struct GNUNET_TESTING_Command *cmd = stc->async_cmd;
209 const struct GNUNET_TESTING_Command *sync_cmd = stc->sync_cmd;
210 struct FinishTaskClosure *ftc;
211 struct SyncState *sync_state = sync_cmd->cls;
212 struct GNUNET_SCHEDULER_Task *finish_task = sync_state->finish_task;
213
214 GNUNET_assert (NULL != finish_task);
215 ftc = GNUNET_new (struct FinishTaskClosure);
216 ftc->cmd = stc->sync_cmd;
217 ftc->is = stc->is;
218 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
219 if (cmd->default_timeout.rel_value_us < now.abs_value_us
220 - sync_state->start_finish_time.abs_value_us)
221 {
222 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
223 "The command with label %s did not finish its asyncronous task in time.\n",
224 cmd->label);
225 is->result = GNUNET_SYSERR;
226 GNUNET_SCHEDULER_shutdown ();
227 }
228
229 if (cmd->finish (cmd->cls, run_finish_task_next, ftc))
230 {
231 finish_task = GNUNET_SCHEDULER_add_now (&run_finish_task_sync, stc);
232 }
233 else
234 {
235 finish_task = NULL;
236 }
237}
238
239
240static void
241start_finish_on_ref (void *cls,
242 const struct GNUNET_TESTING_Command *cmd,
243 struct GNUNET_TESTING_Interpreter *is)
244{
245 struct SyncState *sync_state = cls;
246 struct SyncTaskClosure *stc;
247 const struct GNUNET_TESTING_Command *async_cmd;
248
249 async_cmd = sync_state->async_cmd;
250 stc = GNUNET_new (struct SyncTaskClosure);
251 stc->async_cmd = async_cmd;
252 stc->sync_cmd = cmd;
253 stc->is = is;
254 sync_state->start_finish_time = GNUNET_TIME_absolute_get ();
255 sync_state->finish_task = GNUNET_SCHEDULER_add_now (&run_finish_task_sync,
256 stc);
257}
258
259
260const struct GNUNET_TESTING_Command
261GNUNET_TESTING_cmd_finish (const char *finish_label,
262 const char *cmd_ref,
263 struct GNUNET_TIME_Relative timeout)
264{
265 const struct GNUNET_TESTING_Command *async_cmd;
266 struct SyncState *sync_state;
267
268 async_cmd = GNUNET_TESTING_interpreter_lookup_command (cmd_ref);
269 sync_state = GNUNET_new (struct SyncState);
270 sync_state->async_cmd = async_cmd;
271
272 struct GNUNET_TESTING_Command cmd = {
273 .cls = sync_state,
274 .label = finish_label,
275 .run = &start_finish_on_ref,
276 .asynchronous_finish = GNUNET_NO
277 };
278
279 return cmd;
280}
281
282
283const struct GNUNET_TESTING_Command
284GNUNET_TESTING_cmd_make_asynchronous (const struct GNUNET_TESTING_Command cmd)
285{
286
287 GNUNET_assert (NULL != cmd.finish);
288 const struct GNUNET_TESTING_Command async_cmd = {
289 .cls = cmd.cls,
290 .label = cmd.label,
291 .run = cmd.run,
292 .cleanup = cmd.cleanup,
293 .traits = cmd.traits,
294 .finish = cmd.finish,
295 .asynchronous_finish = GNUNET_YES
296 };
297
298 return async_cmd;
299}
300
301
144/** 302/**
145 * Current command failed, clean up and fail the test case. 303 * Current command failed, clean up and fail the test case.
146 * 304 *
@@ -195,14 +353,15 @@ GNUNET_TESTING_interpreter_get_current_label (struct
195 353
196 354
197/** 355/**
198 * Run the main interpreter loop that performs exchange operations. 356 * Run the main interpreter loop.
199 * 357 *
200 * @param cls contains the `struct GNUNET_TESTING_Interpreter` 358 * @param cls contains the `struct GNUNET_TESTING_Interpreter`
201 */ 359 */
202static void 360static void
203interpreter_run (void *cls) 361interpreter_run (void *cls)
204{ 362{
205 (void) cls; 363 struct FinishTaskClosure *ftc;
364 struct GNUNET_TESTING_Interpreter *is = cls;
206 struct GNUNET_TESTING_Command *cmd = &is->commands[is->ip]; 365 struct GNUNET_TESTING_Command *cmd = &is->commands[is->ip];
207 366
208 is->task = NULL; 367 is->task = NULL;
@@ -227,6 +386,17 @@ interpreter_run (void *cls)
227 cmd->run (cmd->cls, 386 cmd->run (cmd->cls,
228 cmd, 387 cmd,
229 is); 388 is);
389 if ((NULL != cmd->finish) && (GNUNET_NO == cmd->asynchronous_finish))
390 {
391 ftc = GNUNET_new (struct FinishTaskClosure);
392 ftc->cmd = cmd;
393 ftc->is = is;
394 cmd->finish_task = GNUNET_SCHEDULER_add_now (run_finish_task_next, ftc);
395 }
396 else
397 {
398 interpreter_next (is);
399 }
230} 400}
231 401
232 402
@@ -253,9 +423,15 @@ do_shutdown (void *cls)
253 423
254 for (unsigned int j = 0; 424 for (unsigned int j = 0;
255 NULL != (cmd = &is->commands[j])->label; 425 NULL != (cmd = &is->commands[j])->label;
256 j++) 426 j++) {
257 cmd->cleanup (cmd->cls, 427 cmd->cleanup (cmd->cls,
258 cmd); 428 cmd);
429 if (NULL != cmd->finish_task)
430 {
431 GNUNET_SCHEDULER_cancel (cmd->finish_task);
432 cmd->finish_task = NULL;
433 }
434 }
259 435
260 if (NULL != is->task) 436 if (NULL != is->task)
261 { 437 {