chiark / gitweb /
@@@ tty mess
[mLib] / test / tvec-remote.h
1 /* -*-c-*-
2  *
3  * Test-vector framework remote testing extension
4  *
5  * (c) 2024 Straylight/Edgeware
6  */
7
8 /*----- Licensing notice --------------------------------------------------*
9  *
10  * This file is part of the mLib utilities library.
11  *
12  * mLib is free software: you can redistribute it and/or modify it under
13  * the terms of the GNU Library General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or (at
15  * your option) any later version.
16  *
17  * mLib is distributed in the hope that it will be useful, but WITHOUT
18  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
20  * License for more details.
21  *
22  * You should have received a copy of the GNU Library General Public
23  * License along with mLib.  If not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
25  * USA.
26  */
27
28 #ifndef MLIB_TVEC_REMOTE_H
29 #define MLIB_TVEC_REMOTE_H
30
31 #ifdef __cplusplus
32   extern "C" {
33 #endif
34
35 /*----- Header files ------------------------------------------------------*/
36
37 #include <stddef.h>
38
39 #include <sys/types.h>
40
41 #ifndef MLIB_BUF_H
42 #  include "buf.h"
43 #endif
44
45 #ifndef MLIB_DSTR_H
46 #  include "dstr.h"
47 #endif
48
49 #ifndef MLIB_LBUF_H
50 #  include "lbuf.h"
51 #endif
52
53 #ifndef MLIB_TVEC_H
54 #  include "tvec.h"
55 #endif
56
57 /*----- Test environment --------------------------------------------------*/
58
59 struct tvec_remoteenv;
60
61 typedef int tvec_connectfn(pid_t */*kid_out*/, int */*infd_out*/,
62                            int */*outfd_out*/, int */*errfd_out*/,
63                            struct tvec_state */*tv*/,
64                            const struct tvec_remoteenv */*env*/);
65   /* A connection function.  On entry, @tv@ holds the test-vector state, and
66    * @env@ is the test group's remote environment structure, which will
67    * typically really be some subclass of @struct tvec_remoteenv@ containing
68    * additional parameters for establishing the child process.
69    *
70    * On successful completion, the function stores input and output
71    * descriptors (which need not be distinct) in @*infd_out@ and
72    * @*outfd_out@, and returns zero; if it creates a child process, it should
73    * additionally store the child's process-id in @*kid_out@ and store in
74    * @*errfd_out@ a descriptor from which the child's error output can be
75    * read.  On error, the function should report an appropriate message via
76    * @tvec_error@ and return %$-1$%.
77    */
78
79 struct tvec_remoteenv_slots {
80   /* Additional slots for the remote-environment base class. */
81
82   tvec_connectfn *connect;              /* connection function */
83   const struct tvec_env *env;           /* subordinate environment */
84   unsigned dflt_reconn;                 /* default reconnection */
85 };
86
87 struct tvec_remoteenv {
88   /* Remote environment base class instance structure. */
89
90   struct tvec_env _env;
91   struct tvec_remoteenv_slots r;
92 };
93
94 struct tvec_remotefork_slots {
95   /* Additional slots for the remote-environment forking class. */
96
97   const struct tvec_test **tests;       /* child tests (or null) */
98 };
99
100 struct tvec_remotefork {
101   /* Remote environment forking class instance structure. */
102
103   struct tvec_env _env;
104   struct tvec_remoteenv_slots r;
105   struct tvec_remotefork_slots f;
106 };
107
108 struct tvec_remoteexec_slots {
109   /* Additional slots for the remote-environment exec class. */
110
111   const char *const *args;              /* command line to execute */
112 };
113
114 struct tvec_remoteexec {
115   /* Remote environment exec class instance structure. */
116
117   struct tvec_env _env;
118   struct tvec_remoteenv_slots r;
119   struct tvec_remoteexec_slots x;
120 };
121
122 union tvec_remoteenv_subclass_kludge {
123   /* Pointless union to engage the common-prefix rule. */
124
125   struct tvec_env _env;
126   struct tvec_remoteenv renv;
127   struct tvec_remotefork fork;
128   struct tvec_remoteexec exec;
129 };
130
131 struct tvec_remotecomms {
132   /* Remote communications state; private. */
133
134   int infd, outfd;                      /* input and output descriptors */
135   dbuf bout;                            /* output buffer */
136   unsigned char *bin;                   /* input buffer */
137   size_t binoff, binlen, binsz;         /* input offset, length, and size */
138   size_t t;                             /* temporary offset */
139   unsigned f;                           /* flags */
140 #define TVRF_BROKEN 0x0001u             /*   communications have failed */
141 };
142 #define TVEC_REMOTECOMMS_INIT { -1, -1, DBUF_INIT, 0, 0, 0, 0, 0, 0 }
143
144 struct tvec_remotectx {
145   /* Remote environment context; private. */
146
147   struct tvec_state *tv;                /* test vector state */
148   struct tvec_remotecomms rc;           /* communication state */
149   const struct tvec_remoteenv *re;      /* environment configuration */
150   void *subctx;                         /* subenvironment context */
151   struct tvec_vardef vd;                /* temporary variable definition */
152   unsigned ver;                         /* protocol version */
153   pid_t kid;                            /* child process id */
154   int errfd;                            /* child stderr descriptor */
155   lbuf errbuf;                          /* child stderr line buffer */
156   dstr prgwant, progress;               /* progress: wanted/reported */
157   unsigned exwant, exit;                /* exit status wanted/reported */
158 #define TVRF_RCNMASK 0x0300u            /*   reconnection behaviour: */
159 #define TVRCN_DEMAND 0x0000u            /*     connect on demand */
160 #define TVRCN_SKIP 0x0100u              /*     skip unless connected */
161 #define TVRCN_FORCE 0x0200u             /*     force reconnection */
162 #define TVRF_MUFFLE 0x0400u             /*   muffle child stderr */
163 #define TVRF_SETEXIT 0x0800u            /*   set `@exit' */
164 #define TVRF_SETPRG 0x1000u             /*   set `@progress' */
165 #define TVRF_SETRCN 0x2000u             /*   set `@reconnect' */
166 #define TVRF_SETMASK (TVRF_SETEXIT | TVRF_SETPRG | TVRF_SETRCN)
167                                         /*   mask of @TVTF_SET...@ */
168 };
169
170 /* Exit status.
171  *
172  * We don't use the conventional encoding returned by the @wait@(2) family of
173  * system calls because it's too hard for our flags type to decode.  Instead,
174  * we use our own encoding.
175  *
176  * The exit code or signal number ends up in the `value' field in the low 12
177  * bits; bit 12 is set if the value field holds a signal, and it if holds an
178  * exit code.  Bits 13--15 hold a code which describes the status of a child
179  * process or connection.
180  */
181 #define TVXF_VALMASK 0x0fffu            /* value (exit code or signal) */
182 #define TVXF_SIG 0x1000u                /* value is signal, not exit code */
183 #define TVXF_CAUSEMASK 0xe000u          /* mask for cause bits */
184 #define TVXST_RUN 0x0000u               /*   still running */
185 #define TVXST_EXIT 0x2000u              /*   child exited */
186 #define TVXST_KILL 0x4000u              /*   child killed by signal */
187 #define TVXST_CONT 0x6000u              /*   child continued (?) */
188 #define TVXST_STOP 0x8000u              /*   child stopped (?) */
189 #define TVXST_DISCONN 0xa000u           /*   disconnected */
190 #define TVXST_UNK 0xc000u               /*   unknown */
191 #define TVXST_ERR 0xe000u             /*   local error prevented diagnosis */
192
193 /* --- Environment implementation --- *
194  *
195  * The following special variables are supported.
196  *
197  *   * %|@exit|% is the expected exit status; see @TVXF_...@ and @TVXST_...@.
198  *
199  *   * %|progress|% is the expected progress token when the test completes.
200  *     On successful completion, this will be %|%DONE|%; it's %|%RUN|% on
201  *     entry to the test function, but that can call @tvec_setprogress@ to
202  *     change it.
203  *
204  *   * %|reconnect|% is a reconnection policy; see @TVRCN_...@.
205  *
206  * Unrecognized variables are passed to the remote server, as are the
207  * environment events.  As a convenience for @fork@-based remote execution,
208  * If the outermost environment in the server's test definition has
209  * @tvec_remotesetup@ as its @setup@ function, then its subordinate
210  * environment is used instead.
211  */
212
213 extern tvec_envsetupfn tvec_remotesetup;
214 extern tvec_envfindvarfn tvec_remotefindvar;
215 extern tvec_envbeforefn tvec_remotebefore;
216 extern tvec_envrunfn tvec_remoterun;
217 extern tvec_envafterfn tvec_remoteafter;
218 extern tvec_envteardownfn tvec_remoteteardown;
219
220 #define TVEC_REMOTEENV                                                  \
221   { sizeof(struct tvec_remotectx),                                      \
222     tvec_remotesetup,                                                   \
223     tvec_remotefindvar,                                                 \
224     tvec_remotebefore,                                                  \
225     tvec_remoterun,                                                     \
226     tvec_remoteafter,                                                   \
227     tvec_remoteteardown }
228
229 extern tvec_connectfn tvec_fork, tvec_exec;
230
231 #define TVEC_REMOTEFORK(subenv, tests)                                  \
232         TVEC_REMOTEENV, { tvec_fork, subenv }, { tests }
233
234 #define TVEC_REMOTEEXEC(subenv, args)                                   \
235         TVEC_REMOTEENV, { tvec_exec, subenv }, { args }
236
237 /*----- Functions provided ------------------------------------------------*/
238
239 /* --- @tvec_setprogress@, @tvec_setprogress_v@ --- *
240  *
241  * Arguments:   @const char *status@ = progress status token format
242  *              @va_list ap@ = argument tail
243  *
244  * Returns:     ---
245  *
246  * Use:         Reports the progress of a test execution to the client.
247  *
248  *              The framework makes use of tokens beginning with %|%|%:
249  *
250  *                * %|%IDLE|%: during the top-level server code;
251  *
252  *                * %|%SETUP|%: during the enclosing environment's @before@
253  *                  function;
254  *
255  *                * %|%RUN|%: during the environment's @run@ function, or the
256  *                  test function; and
257  *
258  *                * %|%DONE|%: during the enclosing environment's @after@
259  *                  function.
260  *
261  *              The intent is that a test can use the progress token to check
262  *              that a function which is expected to crash does so at the
263  *              correct point, so it's expected that more complex test
264  *              functions and/or environments will set their own progress
265  *              tokens to reflect what's going on.
266  */
267
268 extern PRINTF_LIKE(1, 2) int tvec_setprogress(const char */*status*/, ...);
269 extern int tvec_setprogress_v(const char */*status*/, va_list */*ap*/);
270
271 /* --- @tvec_remoteserver@ --- *
272  *
273  * Arguments:   @int infd@, @int outfd@ = input and output file descriptors
274  *              @const struct tvec_config *config@ = test configuration
275  *
276  * Returns:     Suggested exit code.
277  *
278  * Use:         Run a test server, reading packets from @infd@ and writing
279  *              responses and notifications to @outfd@, and invoking tests as
280  *              described by @config@.
281  *
282  *              This function is not particularly general purpose.  It
283  *              expects to `take over' the process, and makes use of private
284  *              global variables.
285  */
286
287 extern int tvec_remoteserver(int /*infd*/, int /*outfd*/,
288                              const struct tvec_config */*config*/);
289
290 /*----- That's all, folks -------------------------------------------------*/
291
292 #ifdef __cplusplus
293   }
294 #endif
295
296 #endif