@@@ fltfmt 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