Coverage Report

Created: 2026-07-30 06:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/pigeonhole/src/testsuite/testsuite-script.c
Line
Count
Source
1
/* Copyright (c) Pigeonhole authors, see top-level COPYING file */
2
3
#include "lib.h"
4
#include "settings.h"
5
6
#include "sieve.h"
7
#include "sieve-common.h"
8
#include "sieve-script.h"
9
#include "sieve-binary.h"
10
#include "sieve-interpreter.h"
11
#include "sieve-runtime-trace.h"
12
#include "sieve-result.h"
13
14
#include "testsuite-common.h"
15
#include "testsuite-settings.h"
16
#include "testsuite-log.h"
17
#include "testsuite-smtp.h"
18
#include "testsuite-result.h"
19
20
#include "testsuite-script.h"
21
22
/*
23
 * Tested script environment
24
 */
25
26
void testsuite_script_init(void)
27
0
{
28
0
}
29
30
void testsuite_script_deinit(void)
31
0
{
32
0
}
33
34
static const char *path_get_filename(const char *path)
35
0
{
36
0
  const char *filename;
37
38
0
  filename = strrchr(path, '/');
39
0
  if (filename == NULL)
40
0
    filename = path;
41
0
  else
42
0
    filename++;
43
0
  return filename;
44
0
}
45
46
const char *testsuite_script_get_name(const char *path)
47
0
{
48
0
  const char *file, *ext;
49
50
0
  file = path_get_filename(path);
51
52
  /* Extract the script name */
53
0
  ext = strrchr(file, '.');
54
0
  if (ext == NULL || ext == file ||
55
0
      (strcmp(ext, ".svtest") != 0 &&
56
0
       strcmp(ext, "."SIEVE_SCRIPT_FILEEXT) != 0))
57
0
    return NULL;
58
59
0
  return t_strdup_until(file, ext);
60
0
}
61
62
static struct sieve_binary *
63
_testsuite_script_compile(const struct sieve_runtime_env *renv,
64
        const char *script)
65
0
{
66
0
  static unsigned int storage_id = 0;
67
0
  struct sieve_instance *svinst = testsuite_sieve_instance;
68
0
  struct sieve_binary *sbin;
69
0
  const char *script_path;
70
71
0
  sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS,
72
0
          "compile script '%s'", script);
73
74
0
  script_path = sieve_file_script_get_dir_path(renv->script);
75
0
  if (script_path == NULL)
76
0
    return NULL;
77
78
0
  script_path = t_strconcat(script_path, "/", script, NULL);
79
80
0
  const char *storage_name = t_strdup_printf("testsuite-script%u",
81
0
               storage_id++);
82
0
  const char *script_name = testsuite_script_get_name(script_path);
83
84
0
  struct settings_instance *set_instance =
85
0
    settings_instance_find(svinst->event);
86
0
  settings_override(set_instance, "sieve_script+", storage_name,
87
0
        SETTINGS_OVERRIDE_TYPE_2ND_CLI_PARAM);
88
0
  settings_override(set_instance,
89
0
        t_strdup_printf("sieve_script/%s/sieve_script_name",
90
0
            storage_name),
91
0
        script_name,
92
0
        SETTINGS_OVERRIDE_TYPE_2ND_CLI_PARAM);
93
0
  settings_override(set_instance,
94
0
        t_strdup_printf("sieve_script/%s/sieve_script_type",
95
0
            storage_name),
96
0
        "testsuite", SETTINGS_OVERRIDE_TYPE_2ND_CLI_PARAM);
97
0
  settings_override(set_instance,
98
0
        t_strdup_printf("sieve_script/%s/sieve_script_driver",
99
0
            storage_name),
100
0
        "file", SETTINGS_OVERRIDE_TYPE_2ND_CLI_PARAM);
101
0
  settings_override(set_instance,
102
0
        t_strdup_printf("sieve_script/%s/sieve_script_path",
103
0
            storage_name),
104
0
        script_path, SETTINGS_OVERRIDE_TYPE_2ND_CLI_PARAM);
105
106
0
  if (sieve_compile(svinst, SIEVE_SCRIPT_CAUSE_ANY,
107
0
        storage_name, script_name, testsuite_log_ehandler, 0,
108
0
        &sbin, NULL) < 0)
109
0
    return NULL;
110
111
0
  return sbin;
112
0
}
113
114
bool testsuite_script_compile(const struct sieve_runtime_env *renv,
115
            const char *script)
116
0
{
117
0
  struct testsuite_interpreter_context *ictx =
118
0
    testsuite_interpreter_context_get(renv->interp, testsuite_ext);
119
0
  struct sieve_binary *sbin;
120
121
0
  i_assert(ictx != NULL);
122
0
  testsuite_log_clear_messages();
123
124
0
  sbin = _testsuite_script_compile(renv, script);
125
0
  if (sbin == NULL)
126
0
    return FALSE;
127
128
0
  sieve_binary_unref(&ictx->compiled_script);
129
130
0
  ictx->compiled_script = sbin;
131
0
  return TRUE;
132
0
}
133
134
bool testsuite_script_is_subtest(const struct sieve_runtime_env *renv)
135
0
{
136
0
  struct testsuite_interpreter_context *ictx =
137
0
    testsuite_interpreter_context_get(renv->interp, testsuite_ext);
138
139
0
  i_assert(ictx != NULL);
140
0
  if (ictx->compiled_script == NULL)
141
0
    return FALSE;
142
143
0
  return (sieve_binary_extension_get_index(ictx->compiled_script,
144
0
             testsuite_ext) >= 0);
145
0
}
146
147
bool testsuite_script_run(const struct sieve_runtime_env *renv)
148
0
{
149
0
  const struct sieve_execute_env *eenv = renv->exec_env;
150
0
  const struct sieve_script_env *senv = eenv->scriptenv;
151
0
  struct testsuite_interpreter_context *ictx =
152
0
    testsuite_interpreter_context_get(renv->interp, testsuite_ext);
153
0
  struct sieve_script_env scriptenv;
154
0
  struct sieve_exec_status exec_status;
155
0
  struct sieve_result *result;
156
0
  struct sieve_interpreter *interp;
157
0
  pool_t pool;
158
0
  struct sieve_execute_env exec_env;
159
0
  unsigned int orig_test_failures = test_failures;
160
0
  const char *error;
161
0
  int ret;
162
163
0
  i_assert(ictx != NULL);
164
165
0
  if (ictx->compiled_script == NULL) {
166
0
    sieve_runtime_error(renv, NULL, "testsuite: "
167
0
      "trying to run script, but no script compiled yet");
168
0
    return FALSE;
169
0
  }
170
171
0
  testsuite_log_clear_messages();
172
173
0
  i_zero(&exec_status);
174
175
  /* Compose script execution environment */
176
0
  if (sieve_script_env_init(&scriptenv, senv->user, &error) < 0) {
177
0
    sieve_runtime_error(renv, NULL,  "testsuite: "
178
0
      "failed to initialize script execution: %s", error);
179
0
    return FALSE;
180
0
  }
181
0
  scriptenv.default_mailbox = "INBOX";
182
0
  scriptenv.smtp_start = testsuite_smtp_start;
183
0
  scriptenv.smtp_add_rcpt = testsuite_smtp_add_rcpt;
184
0
  scriptenv.smtp_send = testsuite_smtp_send;
185
0
  scriptenv.smtp_abort = testsuite_smtp_abort;
186
0
  scriptenv.smtp_finish = testsuite_smtp_finish;
187
0
  scriptenv.duplicate_mark = NULL;
188
0
  scriptenv.duplicate_check = NULL;
189
0
  scriptenv.trace_log = eenv->scriptenv->trace_log;
190
0
  scriptenv.trace_config = eenv->scriptenv->trace_config;
191
192
0
  result = testsuite_result_get();
193
194
0
  pool = pool_alloconly_create("sieve execution", 4096);
195
0
  sieve_execute_init(&exec_env, eenv->svinst, pool, eenv->msgdata,
196
0
         &scriptenv, eenv->flags);
197
0
  pool_unref(&pool);
198
199
  /* Execute the script */
200
0
  interp = sieve_interpreter_create(ictx->compiled_script, NULL,
201
0
            &exec_env, testsuite_log_ehandler);
202
203
0
  if (interp == NULL) {
204
0
    sieve_execute_deinit(&exec_env);
205
0
    return FALSE;
206
0
  }
207
208
0
  ret = sieve_interpreter_run(interp, result);
209
0
  sieve_interpreter_free(&interp);
210
211
0
  sieve_execute_finish(&exec_env, ret);
212
0
  sieve_execute_deinit(&exec_env);
213
214
0
  if (test_failures != orig_test_failures) {
215
0
    test_failures = orig_test_failures;
216
0
    return FALSE;
217
0
  }
218
219
0
  return (ret > 0 ||
220
0
    sieve_binary_extension_get_index(ictx->compiled_script,
221
0
             testsuite_ext) >= 0);
222
0
}
223
224
struct sieve_binary *
225
testsuite_script_get_binary(const struct sieve_runtime_env *renv)
226
0
{
227
0
  struct testsuite_interpreter_context *ictx =
228
0
    testsuite_interpreter_context_get(renv->interp, testsuite_ext);
229
230
0
  i_assert(ictx != NULL);
231
0
  return ictx->compiled_script;
232
0
}
233
234
void testsuite_script_set_binary(const struct sieve_runtime_env *renv,
235
         struct sieve_binary *sbin)
236
0
{
237
0
  struct testsuite_interpreter_context *ictx =
238
0
    testsuite_interpreter_context_get(renv->interp, testsuite_ext);
239
240
0
  i_assert(ictx != NULL);
241
242
0
  sieve_binary_unref(&ictx->compiled_script);
243
244
0
  ictx->compiled_script = sbin;
245
0
  sieve_binary_ref(sbin);
246
0
}
247
248
/*
249
 * Multiscript
250
 */
251
252
bool testsuite_script_multiscript(const struct sieve_runtime_env *renv,
253
          ARRAY_TYPE (const_string) *scriptfiles)
254
0
{
255
0
  struct sieve_instance *svinst = testsuite_sieve_instance;
256
0
  const struct sieve_execute_env *eenv = renv->exec_env;
257
0
  const struct sieve_script_env *senv = eenv->scriptenv;
258
0
  struct sieve_script_env scriptenv;
259
0
  struct sieve_exec_status exec_status;
260
0
  struct sieve_multiscript *mscript;
261
0
  const char *const *scripts;
262
0
  const char *error;
263
0
  unsigned int count, i;
264
0
  bool more = TRUE;
265
0
  bool result = TRUE;
266
267
0
  testsuite_log_clear_messages();
268
269
  /* Compose script execution environment */
270
0
  if (sieve_script_env_init(&scriptenv, senv->user, &error) < 0) {
271
0
    sieve_runtime_error(renv, NULL,
272
0
      "testsuite: failed to initialize script execution: %s",
273
0
      error);
274
0
    return FALSE;
275
0
  }
276
0
  scriptenv.default_mailbox = "INBOX";
277
0
  scriptenv.smtp_start = testsuite_smtp_start;
278
0
  scriptenv.smtp_add_rcpt = testsuite_smtp_add_rcpt;
279
0
  scriptenv.smtp_send = testsuite_smtp_send;
280
0
  scriptenv.smtp_abort = testsuite_smtp_abort;
281
0
  scriptenv.smtp_finish = testsuite_smtp_finish;
282
0
  scriptenv.duplicate_mark = NULL;
283
0
  scriptenv.duplicate_check = NULL;
284
0
  scriptenv.trace_log = eenv->scriptenv->trace_log;
285
0
  scriptenv.trace_config = eenv->scriptenv->trace_config;
286
0
  scriptenv.exec_status = &exec_status;
287
288
  /* Start execution */
289
290
0
  mscript = sieve_multiscript_start_execute(svinst, eenv->msgdata,
291
0
              &scriptenv);
292
293
  /* Execute scripts before main script */
294
295
0
  scripts = array_get(scriptfiles, &count);
296
0
  for (i = 0; i < count && more; i++) {
297
0
    struct sieve_binary *sbin = NULL;
298
0
    const char *script = scripts[i];
299
300
    /* Open */
301
0
    sbin = _testsuite_script_compile(renv, script);
302
0
    if (sbin == NULL) {
303
0
      result = FALSE;
304
0
      break;
305
0
    }
306
307
    /* Execute */
308
309
0
    sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS,
310
0
            "run script '%s'", script);
311
312
0
    more = sieve_multiscript_run(mscript, sbin,
313
0
               testsuite_log_ehandler,
314
0
               testsuite_log_ehandler, 0);
315
316
0
    sieve_close(&sbin);
317
0
  }
318
319
0
  return (sieve_multiscript_finish(&mscript, testsuite_log_ehandler,
320
0
           0, SIEVE_EXEC_OK) > 0 && result);
321
0
}