1 /*        $NetBSD: cleanup_envelope_test.c,v 1.2 2025/02/25 19:15:44 christos Exp $       */
2 
3 
4  /*
5   * System library.
6   */
7 #include <sys_defs.h>
8 #include <string.h>
9 #include <stdlib.h>
10 #include <ctype.h>
11 
12  /*
13   * Utility library.
14   */
15 #include <msg.h>
16 #include <msg_vstream.h>
17 #include <vstring.h>
18 #include <vstream.h>
19 #include <stringops.h>
20 
21  /*
22   * Global library.
23   */
24 #include <record.h>
25 #include <rec_type.h>
26 #include <cleanup_user.h>
27 #include <mail_params.h>
28 #include <smtputf8.h>
29 
30  /*
31   * Application-specific.
32   */
33 #include <cleanup.h>
34 
35  /*
36   * Stubs for parameter dependencies.
37   */
38 int     var_delay_warn_time = 0;
39 int     var_dup_filter_limit = DEF_DUP_FILTER_LIMIT;
40 char   *var_remote_rwr_domain = DEF_REM_RWR_DOMAIN;
41 int     var_qattr_count_limit = DEF_QATTR_COUNT_LIMIT;
42 VSTRING *cleanup_strip_chars = 0;
43 MILTERS *cleanup_milters = 0;
44 VSTRING *cleanup_trace_path = 0;
45 MAPS   *cleanup_virt_alias_maps = 0;
46 char   *cleanup_path = "fixed";
47 
48  /*
49   * Stubs for cleanup_message.c dependencies. TODO(wietse) replace function
50   * stubs with mocks that can have expectations and that can report
51   * unexpected calls.
52   */
cleanup_message(CLEANUP_STATE * state,int type,const char * buf,ssize_t len)53 void    cleanup_message(CLEANUP_STATE *state, int type, const char *buf,
54                                       ssize_t len)
55 {
56     msg_panic("cleanup_message");
57 }
58 
59  /*
60   * Stubs for cleanup_milter.c dependencies.
61   */
cleanup_milter_receive(CLEANUP_STATE * state,int count)62 void    cleanup_milter_receive(CLEANUP_STATE *state, int count)
63 {
64     msg_panic("cleanup_milter_receive");
65 }
66 
cleanup_milter_emul_mail(CLEANUP_STATE * state,MILTERS * milters,const char * sender)67 void    cleanup_milter_emul_mail(CLEANUP_STATE *state, MILTERS *milters,
68                                                  const char *sender)
69 {
70     msg_panic("cleanup_milter_emul_mail");
71 }
72 
cleanup_milter_emul_rcpt(CLEANUP_STATE * state,MILTERS * milters,const char * recipient)73 void    cleanup_milter_emul_rcpt(CLEANUP_STATE *state, MILTERS *milters,
74                                                  const char *recipient)
75 {
76     msg_panic("cleanup_milter_emul_rcpt");
77 }
78 
79  /*
80   * Stubs for cleanup_addr.c dependencies.
81   */
cleanup_addr_sender(CLEANUP_STATE * state,const char * addr)82 off_t   cleanup_addr_sender(CLEANUP_STATE *state, const char *addr)
83 {
84     msg_panic("cleanup_addr_sender");
85 }
86 
cleanup_addr_recipient(CLEANUP_STATE * state,const char * addr)87 void    cleanup_addr_recipient(CLEANUP_STATE *state, const char *addr)
88 {
89     msg_panic("cleanup_addr_recipient");
90 }
91 
92  /*
93   * Stubs for cleanup_region.c dependencies.
94   */
cleanup_region_done(CLEANUP_STATE * state)95 void    cleanup_region_done(CLEANUP_STATE *state)
96 {
97 }
98 
99  /*
100   * Tests and test cases.
101   */
102 typedef struct TEST_CASE {
103     const char *label;                            /* identifies test case */
104     int     (*action) (const struct TEST_CASE *);
105 } TEST_CASE;
106 
107 #define PASS        1
108 #define FAIL        0
109 
overrides_size_fields(const TEST_CASE * tp)110 static int overrides_size_fields(const TEST_CASE *tp)
111 {
112 
113     /*
114      * Generate one SIZE record test payload.
115      */
116     VSTRING *input_buf = vstring_alloc(100);
117 
118     vstring_sprintf(input_buf, REC_TYPE_SIZE_FORMAT,
119                         (REC_TYPE_SIZE_CAST1) ~ 0,          /* message segment size */
120                         (REC_TYPE_SIZE_CAST2) ~ 0,          /* content offset */
121                         (REC_TYPE_SIZE_CAST3) ~ 0,          /* recipient count */
122                         (REC_TYPE_SIZE_CAST4) ~ 0,          /* qmgr options */
123                         (REC_TYPE_SIZE_CAST5) ~ 0,          /* content length */
124                         (REC_TYPE_SIZE_CAST6) SOPT_FLAG_ALL);         /* sendopts */
125 
126     /*
127      * Instantiate CLEANUP_STATE, and save information that isn't expected to
128      * change. We only need to save simple-type CLEANUP_STATE fields that
129      * correspond with SIZE record fields.
130      */
131     CLEANUP_STATE *state = cleanup_state_alloc((VSTREAM *) 0);
132     CLEANUP_STATE saved_state = *state;
133 
134     /*
135      * Process the test SIZE record payload, clear some bits from the
136      * sendopts field, and write an all-zeroes preliminary SIZE record.
137      */
138     if ((state->dst = vstream_fopen("/dev/null", O_WRONLY, 0)) == 0) {
139           msg_warn("vstream_fopen(\"/dev/null\", O_WRONLY, 0): %m");
140           return (FAIL);
141     }
142     cleanup_envelope(state, REC_TYPE_SIZE, vstring_str(input_buf),
143                          VSTRING_LEN(input_buf));
144     if (state->errs != CLEANUP_STAT_OK) {
145           msg_warn("cleanup_envelope: got: '%s', want: '%s'",
146                      cleanup_strerror(state->errs),
147                      cleanup_strerror(CLEANUP_STAT_OK));
148           return (FAIL);
149     }
150     vstring_free(input_buf);
151     input_buf = 0;
152     (void) vstream_fclose(state->dst);
153     state->dst = 0;
154 
155     /*
156      * Compare the updated state against the expected content. We expect that
157      * the fields for xtra_offset, data_offset, rcpt_count, qmgr_opts, and
158      * cont_length, are consistent with the saved CLEANUP_STATE, and we
159      * expect to see a specific value for the sendopts field that was
160      * assigned in cleanup_envelope().
161      */
162     if (state->xtra_offset != saved_state.xtra_offset) {
163           msg_warn("state->xtra_offset: got %ld, want: %ld",
164                      (long) state->xtra_offset, (long) saved_state.xtra_offset);
165           return (FAIL);
166     }
167     if (state->data_offset != saved_state.data_offset) {
168           msg_warn("state->data_offset: got %ld, want: %ld",
169                      (long) state->data_offset, (long) saved_state.data_offset);
170           return (FAIL);
171     }
172     if (state->rcpt_count != saved_state.rcpt_count) {
173           msg_warn("state->rcpt_count: got: %ld, want: %ld",
174                      (long) state->rcpt_count, (long) saved_state.rcpt_count);
175           return (FAIL);
176     }
177     if (state->qmgr_opts != saved_state.qmgr_opts) {
178           msg_warn("state=>qmgr_opts: got: %d, want: %d",
179                      state->qmgr_opts, saved_state.qmgr_opts);
180           return (FAIL);
181     }
182     if (state->cont_length != saved_state.cont_length) {
183           msg_warn("state->cont_length: got %ld, want: %ld",
184                      (long) state->cont_length, (long) saved_state.cont_length);
185           return (FAIL);
186     }
187     if (state->sendopts != (SOPT_FLAG_ALL & ~SOPT_FLAG_DERIVED)) {
188           msg_warn("state->sendopts: got: 0x%x, want: 0x%x",
189                      state->sendopts, SOPT_FLAG_ALL & ~SOPT_FLAG_DERIVED);
190           return (FAIL);
191     }
192 
193     /*
194      * Cleanup.
195      */
196     cleanup_state_free(state);
197     return (PASS);
198 }
199 
200 static const TEST_CASE test_cases[] = {
201     {"overrides_size_fields",
202           overrides_size_fields,
203     },
204     {0},
205 };
206 
main(int argc,char ** argv)207 int     main(int argc, char **argv)
208 {
209     const TEST_CASE *tp;
210     int     pass = 0;
211     int     fail = 0;
212 
213     /* XXX How to avoid linking in mail_params.o? */
214     var_line_limit = DEF_LINE_LIMIT;
215 
216     msg_vstream_init(sane_basename((VSTRING *) 0, argv[0]), VSTREAM_ERR);
217 
218     for (tp = test_cases; tp->label != 0; tp++) {
219           msg_info("RUN  %s", tp->label);
220           if (tp->action(tp) != PASS) {
221               fail++;
222               msg_info("FAIL %s", tp->label);
223           } else {
224               msg_info("PASS %s", tp->label);
225               pass++;
226           }
227     }
228     msg_info("PASS=%d FAIL=%d", pass, fail);
229     exit(fail != 0);
230 }
231