Coverage Report

Created: 2026-03-11 06:17

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