1 /*
2  * ProFTPD - FTP server testsuite
3  * Copyright (c) 2020 The ProFTPD Project team
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
18  *
19  * As a special exemption, The ProFTPD Project team and other respective
20  * copyright holders give permission to link this program with OpenSSL, and
21  * distribute the resulting executable, without including the source code for
22  * OpenSSL in the source distribution.
23  */
24 
25 /* Jot API tests. */
26 
27 #include "tests.h"
28 #include "logfmt.h"
29 #include "json.h"
30 #include "jot.h"
31 
32 static pool *p = NULL;
33 
set_up(void)34 static void set_up(void) {
35   if (p == NULL) {
36     p = make_sub_pool(NULL);
37   }
38 
39   if (getenv("TEST_VERBOSE") != NULL) {
40     pr_trace_set_levels("jot", 1, 20);
41   }
42 }
43 
tear_down(void)44 static void tear_down(void) {
45   if (getenv("TEST_VERBOSE") != NULL) {
46     pr_trace_set_levels("jot", 0, 0);
47   }
48 
49   if (p) {
50     destroy_pool(p);
51     p = permanent_pool = NULL;
52   }
53 }
54 
55 /* Tests */
56 
assert_jot_class_filter(const char * class_name)57 static void assert_jot_class_filter(const char *class_name) {
58   pr_jot_filters_t *filters;
59   const char *rules;
60 
61   rules = class_name;
62 
63   mark_point();
64   filters = pr_jot_filters_create(p, rules, PR_JOT_FILTER_TYPE_CLASSES, 0);
65   fail_unless(filters != NULL, "Failed to create filters from '%s': %s",
66     rules, strerror(errno));
67   (void) pr_jot_filters_destroy(filters);
68 
69   rules = pstrcat(p, "!", class_name, NULL);
70 
71   mark_point();
72   filters = pr_jot_filters_create(p, rules, PR_JOT_FILTER_TYPE_CLASSES, 0);
73   fail_unless(filters != NULL, "Failed to create filters from '%s': %s",
74     rules, strerror(errno));
75   (void) pr_jot_filters_destroy(filters);
76 }
77 
assert_jot_command_with_class_filter(const char * rules)78 static void assert_jot_command_with_class_filter(const char *rules) {
79   pr_jot_filters_t *filters;
80 
81   mark_point();
82   filters = pr_jot_filters_create(p, rules,
83     PR_JOT_FILTER_TYPE_COMMANDS_WITH_CLASSES, 0);
84   fail_unless(filters != NULL, "Failed to create filters from '%s': %s",
85     rules, strerror(errno));
86   (void) pr_jot_filters_destroy(filters);
87 }
88 
START_TEST(jot_filters_create_test)89 START_TEST (jot_filters_create_test) {
90   pr_jot_filters_t *filters;
91   const char *rules;
92 
93   mark_point();
94   filters = pr_jot_filters_create(NULL, NULL, 0, 0);
95   fail_unless(filters == NULL, "Failed to handle null pool");
96   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
97     strerror(errno), errno);
98 
99   mark_point();
100   filters = pr_jot_filters_create(p, NULL, 0, 0);
101   fail_unless(filters == NULL, "Failed to handle null rules");
102   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
103     strerror(errno), errno);
104 
105   rules = "foo";
106 
107   mark_point();
108   filters = pr_jot_filters_create(p, rules, -1, 0);
109   fail_unless(filters == NULL, "Failed to handle invalid rules type");
110   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
111     strerror(errno), errno);
112 
113   /* Class rules */
114 
115   mark_point();
116   filters = pr_jot_filters_create(p, rules, PR_JOT_FILTER_TYPE_CLASSES, 0);
117   fail_unless(filters == NULL, "Failed to handle invalid class name '%s'",
118     rules);
119   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
120     strerror(errno), errno);
121 
122   assert_jot_class_filter("NONE");
123   assert_jot_class_filter("ALL");
124   assert_jot_class_filter("AUTH");
125   assert_jot_class_filter("INFO");
126   assert_jot_class_filter("DIRS");
127   assert_jot_class_filter("READ");
128   assert_jot_class_filter("WRITE");
129   assert_jot_class_filter("SEC");
130   assert_jot_class_filter("SECURE");
131   assert_jot_class_filter("CONNECT");
132   assert_jot_class_filter("EXIT");
133   assert_jot_class_filter("DISCONNECT");
134   assert_jot_class_filter("SSH");
135   assert_jot_class_filter("SFTP");
136 
137   rules = "AUTH,!INFO";
138 
139   mark_point();
140   filters = pr_jot_filters_create(p, rules, PR_JOT_FILTER_TYPE_CLASSES, 0);
141   fail_unless(filters != NULL, "Failed to create filters from '%s': %s",
142     rules, strerror(errno));
143   (void) pr_jot_filters_destroy(filters);
144 
145   rules = "!INFO|AUTH";
146 
147   mark_point();
148   filters = pr_jot_filters_create(p, rules, PR_JOT_FILTER_TYPE_CLASSES, 0);
149   fail_unless(filters != NULL, "Failed to create filters from '%s': %s",
150     rules, strerror(errno));
151   (void) pr_jot_filters_destroy(filters);
152 
153   /* Command rules */
154 
155   rules = "FOO,BAR";
156   mark_point();
157   filters = pr_jot_filters_create(p, rules, PR_JOT_FILTER_TYPE_COMMANDS, 0);
158   fail_unless(filters != NULL, "Failed to create filters from '%s': %s",
159     rules, strerror(errno));
160   (void) pr_jot_filters_destroy(filters);
161 
162   rules = "APPE,RETR,STOR,STOU";
163   mark_point();
164   filters = pr_jot_filters_create(p, rules, PR_JOT_FILTER_TYPE_COMMANDS, 0);
165   fail_unless(filters != NULL, "Failed to create filters from '%s': %s",
166     rules, strerror(errno));
167   (void) pr_jot_filters_destroy(filters);
168 
169   /* Rules with commands and classes */
170 
171   rules = "CONNECT,RETR,STOR,DISCONNECT";
172   assert_jot_command_with_class_filter(rules);
173 
174   rules = "RETR,STOR,AUTH";
175   assert_jot_command_with_class_filter(rules);
176 
177   rules = "RETR,STOR,DIRS";
178   assert_jot_command_with_class_filter(rules);
179 
180   rules = "RETR,STOR,INFO";
181   assert_jot_command_with_class_filter(rules);
182 
183   rules = "RETR,STOR,MISC";
184   assert_jot_command_with_class_filter(rules);
185 
186   rules = "READ,RETR,STOR";
187   assert_jot_command_with_class_filter(rules);
188 
189   rules = "RETR,SEC,STOR";
190   assert_jot_command_with_class_filter(rules);
191 
192   rules = "RETR,SFTP,STOR";
193   assert_jot_command_with_class_filter(rules);
194 
195   rules = "RETR,SSH,STOR";
196   assert_jot_command_with_class_filter(rules);
197 
198   rules = "RETR,STOR,WRITE";
199   assert_jot_command_with_class_filter(rules);
200 
201   rules = "ALL";
202   mark_point();
203   filters = pr_jot_filters_create(p, rules,
204     PR_JOT_FILTER_TYPE_COMMANDS_WITH_CLASSES, 0);
205   fail_unless(filters != NULL, "Failed to create filters from '%s': %s",
206     rules, strerror(errno));
207   (void) pr_jot_filters_destroy(filters);
208 
209   /* Flags */
210 
211   rules = "ALL";
212   mark_point();
213   filters = pr_jot_filters_create(p, rules,
214     PR_JOT_FILTER_TYPE_COMMANDS_WITH_CLASSES, PR_JOT_FILTER_FL_ALL_INCL_ALL);
215   fail_unless(filters != NULL, "Failed to create filters from '%s': %s",
216     rules, strerror(errno));
217   (void) pr_jot_filters_destroy(filters);
218 }
219 END_TEST
220 
START_TEST(jot_filters_destroy_test)221 START_TEST (jot_filters_destroy_test) {
222   int res;
223   pr_jot_filters_t *filters;
224 
225   mark_point();
226   res = pr_jot_filters_destroy(NULL);
227   fail_unless(res < 0, "Failed to handle null filters");
228   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
229     strerror(errno), errno);
230 
231   filters = pr_jot_filters_create(p, "NONE", PR_JOT_FILTER_TYPE_CLASSES, 0);
232 
233   mark_point();
234   res = pr_jot_filters_destroy(filters);
235   fail_unless(res == 0, "Failed to destroy filters: %s", strerror(errno));
236 }
237 END_TEST
238 
START_TEST(jot_filters_include_classes_test)239 START_TEST (jot_filters_include_classes_test) {
240   int res;
241   pr_jot_filters_t *filters;
242 
243   mark_point();
244   res = pr_jot_filters_include_classes(NULL, 0);
245   fail_unless(res < 0, "Failed to handle null filters");
246   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
247     strerror(errno), errno);
248 
249   filters = pr_jot_filters_create(p, "NONE", PR_JOT_FILTER_TYPE_CLASSES, 0);
250 
251   res = pr_jot_filters_include_classes(filters, CL_ALL);
252   fail_unless(res == FALSE, "Expected FALSE, got %d", res);
253 
254   res = pr_jot_filters_include_classes(filters, CL_NONE);
255   fail_unless(res == TRUE, "Expected TRUE, got %d", res);
256 
257   res = pr_jot_filters_destroy(filters);
258   fail_unless(res == 0, "Failed to destroy filters: %s", strerror(errno));
259 }
260 END_TEST
261 
262 static unsigned int parse_on_meta_count = 0;
263 static unsigned int parse_on_unknown_count = 0;
264 static unsigned int parse_on_other_count = 0;
265 
parse_on_meta(pool * jot_pool,pr_jot_ctx_t * jot_ctx,unsigned char logfmt_id,const char * text,size_t text_len)266 static int parse_on_meta(pool *jot_pool, pr_jot_ctx_t *jot_ctx,
267     unsigned char logfmt_id, const char *text, size_t text_len) {
268   parse_on_meta_count++;
269   return 0;
270 }
271 
parse_on_unknown(pool * jot_pool,pr_jot_ctx_t * jot_ctx,const char * text,size_t text_len)272 static int parse_on_unknown(pool *jot_pool, pr_jot_ctx_t *jot_ctx,
273     const char *text, size_t text_len) {
274   parse_on_unknown_count++;
275   return 0;
276 }
277 
parse_on_other(pool * jot_pool,pr_jot_ctx_t * jot_ctx,char ch)278 static int parse_on_other(pool *jot_pool, pr_jot_ctx_t *jot_ctx, char ch) {
279   parse_on_other_count++;
280   return 0;
281 }
282 
START_TEST(jot_parse_on_meta_test)283 START_TEST (jot_parse_on_meta_test) {
284   int res;
285   pr_jot_ctx_t *jot_ctx;
286   pr_jot_parsed_t *jot_parsed;
287 
288   mark_point();
289   res = pr_jot_parse_on_meta(p, NULL, 0, NULL, 0);
290   fail_unless(res < 0, "Failed to handle null jot_ctx");
291   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
292     strerror(errno), errno);
293 
294   jot_ctx = pcalloc(p, sizeof(pr_jot_ctx_t));
295 
296   mark_point();
297   res = pr_jot_parse_on_meta(p, jot_ctx, 0, NULL, 0);
298   fail_unless(res < 0, "Failed to handle null jot_ctx->log");
299   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
300     strerror(errno), errno);
301 
302   jot_parsed = pcalloc(p, sizeof(pr_jot_parsed_t));
303   jot_ctx->log = jot_parsed;
304 
305   mark_point();
306   res = pr_jot_parse_on_meta(p, jot_ctx, 0, NULL, 0);
307   fail_unless(res == 0, "Failed to handle parse_on_meta callback: %s",
308     strerror(errno));
309 }
310 END_TEST
311 
START_TEST(jot_parse_on_unknown_test)312 START_TEST (jot_parse_on_unknown_test) {
313   int res;
314   pr_jot_ctx_t *jot_ctx;
315   pr_jot_parsed_t *jot_parsed;
316 
317   mark_point();
318   res = pr_jot_parse_on_unknown(p, NULL, NULL, 0);
319   fail_unless(res < 0, "Failed to handle null jot_ctx");
320   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
321     strerror(errno), errno);
322 
323   jot_ctx = pcalloc(p, sizeof(pr_jot_ctx_t));
324 
325   mark_point();
326   res = pr_jot_parse_on_unknown(p, jot_ctx, NULL, 0);
327   fail_unless(res < 0, "Failed to handle null jot_ctx->log");
328   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
329     strerror(errno), errno);
330 
331   jot_parsed = pcalloc(p, sizeof(pr_jot_parsed_t));
332   jot_ctx->log = jot_parsed;
333 
334   mark_point();
335   res = pr_jot_parse_on_unknown(p, jot_ctx, NULL, 0);
336   fail_unless(res == 0, "Failed to handle parse_on_unknown callback: %s",
337     strerror(errno));
338 }
339 END_TEST
340 
START_TEST(jot_parse_on_other_test)341 START_TEST (jot_parse_on_other_test) {
342   int res;
343   pr_jot_ctx_t *jot_ctx;
344   pr_jot_parsed_t *jot_parsed;
345 
346   mark_point();
347   res = pr_jot_parse_on_other(p, NULL, 0);
348   fail_unless(res < 0, "Failed to handle null jot_ctx");
349   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
350     strerror(errno), errno);
351 
352   jot_ctx = pcalloc(p, sizeof(pr_jot_ctx_t));
353 
354   mark_point();
355   res = pr_jot_parse_on_other(p, jot_ctx, 0);
356   fail_unless(res < 0, "Failed to handle null jot_ctx->log");
357   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
358     strerror(errno), errno);
359 
360   jot_parsed = pcalloc(p, sizeof(pr_jot_parsed_t));
361   jot_ctx->log = jot_parsed;
362 
363   mark_point();
364   res = pr_jot_parse_on_other(p, jot_ctx, 0);
365   fail_unless(res == 0, "Failed to handle parse_on_other callback: %s",
366     strerror(errno));
367 }
368 END_TEST
369 
START_TEST(jot_parse_logfmt_test)370 START_TEST (jot_parse_logfmt_test) {
371   int res;
372   const char *text;
373   size_t text_len;
374   pr_jot_ctx_t *jot_ctx;
375 
376   mark_point();
377   res = pr_jot_parse_logfmt(NULL, NULL, NULL, NULL, NULL, NULL, 0);
378   fail_unless(res < 0, "Failed to handle null pool");
379   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
380     strerror(errno), errno);
381 
382   mark_point();
383   res = pr_jot_parse_logfmt(p, NULL, NULL, NULL, NULL, NULL, 0);
384   fail_unless(res < 0, "Failed to handle null text");
385   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
386     strerror(errno), errno);
387 
388   text = "Hello, World!";
389 
390   mark_point();
391   res = pr_jot_parse_logfmt(p, text, NULL, NULL, NULL, NULL, 0);
392   fail_unless(res < 0, "Failed to handle null ctx");
393   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
394     strerror(errno), errno);
395 
396   jot_ctx = pcalloc(p, sizeof(pr_jot_ctx_t));
397 
398   mark_point();
399   res = pr_jot_parse_logfmt(p, text, jot_ctx, NULL, NULL, NULL, 0);
400   fail_unless(res < 0, "Failed to handle null on_meta");
401   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
402     strerror(errno), errno);
403 
404   parse_on_meta_count = parse_on_unknown_count = parse_on_other_count = 0;
405 
406   mark_point();
407   res = pr_jot_parse_logfmt(p, text, jot_ctx, parse_on_meta, NULL, NULL, 0);
408   fail_unless(res == 0, "Failed to parse text '%s': %s", text, strerror(errno));
409   fail_unless(parse_on_meta_count == 0,
410     "Expected on_meta count 0, got %u", parse_on_meta_count);
411   fail_unless(parse_on_unknown_count == 0,
412     "Expected on_unknown count 0, got %u", parse_on_unknown_count);
413   fail_unless(parse_on_other_count == 0,
414     "Expected on_other count 0, got %u", parse_on_other_count);
415 
416   parse_on_meta_count = parse_on_unknown_count = parse_on_other_count = 0;
417   text_len = strlen(text);
418 
419   mark_point();
420   res = pr_jot_parse_logfmt(p, text, jot_ctx, parse_on_meta, NULL,
421     parse_on_other, 0);
422   fail_unless(res == 0, "Failed to parse text '%s': %s", text, strerror(errno));
423   fail_unless(parse_on_meta_count == 0,
424     "Expected on_meta count 0, got %u", parse_on_meta_count);
425   fail_unless(parse_on_unknown_count == 0,
426     "Expected on_unknown count 0, got %u", parse_on_unknown_count);
427   fail_unless((unsigned long) parse_on_other_count == text_len,
428     "Expected on_other count %lu, got %u", (unsigned long) text_len,
429     parse_on_other_count);
430 
431   parse_on_meta_count = parse_on_unknown_count = parse_on_other_count = 0;
432   text = "%A %b %{epoch} %{unknown key here}, boo!";
433   text_len = strlen(text);
434 
435   mark_point();
436   res = pr_jot_parse_logfmt(p, text, jot_ctx, parse_on_meta, parse_on_unknown,
437     parse_on_other, 0);
438   fail_unless(res == 0, "Failed to parse text '%s': %s", text, strerror(errno));
439   fail_unless(parse_on_meta_count == 3,
440     "Expected on_meta count 0, got %u", parse_on_meta_count);
441   fail_unless(parse_on_unknown_count == 1,
442     "Expected on_unknown count 0, got %u", parse_on_unknown_count);
443   fail_unless(parse_on_other_count == 9,
444     "Expected on_other count 9, got %u", parse_on_other_count);
445 
446   parse_on_meta_count = parse_on_unknown_count = parse_on_other_count = 0;
447   text = "%A %b %{epoch} %{unknown key here}, %{not closed";
448   text_len = strlen(text);
449 
450   mark_point();
451   res = pr_jot_parse_logfmt(p, text, jot_ctx, parse_on_meta, parse_on_unknown,
452     parse_on_other, 0);
453   fail_unless(res == 0, "Failed to parse text '%s': %s", text, strerror(errno));
454   fail_unless(parse_on_meta_count == 3,
455     "Expected on_meta count 0, got %u", parse_on_meta_count);
456   fail_unless(parse_on_unknown_count == 1,
457     "Expected on_unknown count 0, got %u", parse_on_unknown_count);
458   fail_unless(parse_on_other_count == 17,
459     "Expected on_other count 17, got %u", parse_on_other_count);
460 }
461 END_TEST
462 
START_TEST(jot_parse_logfmt_short_vars_test)463 START_TEST (jot_parse_logfmt_short_vars_test) {
464   register unsigned int i;
465   int res;
466   unsigned int text_count = 0;
467   pr_jot_ctx_t *jot_ctx;
468   const char *text;
469   const char *texts[] = {
470     "%A",
471     "%D",
472     "%E",
473     "%F",
474     "%H",
475     "%I",
476     "%J",
477     "%L",
478     "%O",
479     "%R",
480     "%S",
481     "%T",
482     "%U",
483     "%V",
484     "%a",
485     "%b",
486     "%c",
487     "%d",
488     "%f",
489     "%g",
490     "%h",
491     "%l",
492     "%m",
493     "%p",
494     "%r",
495     "%s",
496     "%u",
497     "%v",
498     "%w",
499     NULL
500   };
501 
502   jot_ctx = pcalloc(p, sizeof(pr_jot_ctx_t));
503   text = "%X";
504   parse_on_meta_count = parse_on_unknown_count = parse_on_other_count = 0;
505 
506   /* Here we expect an other count of 2, for the '%' and the 'X'.  This is
507    * not a recognized/supported short variable, and definitely not a long
508    * variable, and thus the entire text is treated as "other", for each
509    * character.
510    */
511 
512   mark_point();
513   res = pr_jot_parse_logfmt(p, text, jot_ctx, parse_on_meta, NULL,
514     parse_on_other, 0);
515   fail_unless(res == 0, "Failed to parse text '%s': %s", text, strerror(errno));
516   fail_unless(parse_on_meta_count == 0, "Expected on_meta count 0, got %u",
517     parse_on_meta_count);
518   fail_unless(parse_on_other_count == 2, "Expected on_other count 2, got %u",
519     parse_on_other_count);
520 
521   text = "%{0}";
522   parse_on_meta_count = parse_on_unknown_count = parse_on_other_count = 0;
523 
524   mark_point();
525   res = pr_jot_parse_logfmt(p, text, jot_ctx, parse_on_meta, parse_on_unknown,
526     parse_on_other, 0);
527   fail_unless(res == 0, "Failed to parse text '%s': %s", text, strerror(errno));
528   fail_unless(parse_on_meta_count == 0,
529     "Expected on_meta count 0, got %u", parse_on_meta_count);
530   fail_unless(parse_on_unknown_count == 1,
531     "Expected on_unknown count 1, got %u", parse_on_unknown_count);
532   fail_unless(parse_on_other_count == 0,
533     "Expected on_other count 0, got %u", parse_on_other_count);
534 
535   parse_on_meta_count = parse_on_unknown_count = parse_on_other_count = 0;
536   text_count = 0;
537 
538   for (i = 0; texts[i]; i++) {
539     text = (const char *) texts[i];
540     text_count++;
541 
542     mark_point();
543     res = pr_jot_parse_logfmt(p, text, jot_ctx, parse_on_meta, parse_on_unknown,
544       parse_on_other, 0);
545     fail_unless(res == 0, "Failed to parse text '%s': %s", text,
546       strerror(errno));
547   }
548 
549   fail_unless(parse_on_meta_count == text_count,
550     "Expected on_meta count %d, got %u", text_count, parse_on_meta_count);
551   fail_unless(parse_on_unknown_count == 0,
552     "Expected on_unknown count 0, got %u", parse_on_unknown_count);
553   fail_unless(parse_on_other_count == 0,
554     "Expected on_other count 0, got %u", parse_on_other_count);
555 }
556 END_TEST
557 
long_on_meta(pool * jot_pool,pr_jot_ctx_t * jot_ctx,unsigned char logfmt_id,const char * text,size_t text_len)558 static int long_on_meta(pool *jot_pool, pr_jot_ctx_t *jot_ctx,
559     unsigned char logfmt_id, const char *text, size_t text_len) {
560   if (strncmp(text, "FOOBAR", text_len) == 0) {
561     parse_on_meta_count++;
562   }
563 
564   return 0;
565 }
566 
START_TEST(jot_parse_logfmt_long_vars_test)567 START_TEST (jot_parse_logfmt_long_vars_test) {
568   register unsigned int i;
569   int res;
570   unsigned int text_count = 0;
571   pr_jot_ctx_t *jot_ctx;
572   const char *text;
573   const char *texts[] = {
574     "%{basename}",
575     "%{epoch}",
576     "%{file-modified}",
577     "%{file-offset}",
578     "%{file-size}",
579     "%{gid}",
580     "%{iso8601}",
581     "%{microsecs}",
582     "%{millisecs}",
583     "%{protocol}",
584     "%{remote-port}",
585     "%{transfer-failure}",
586     "%{transfer-millisecs}",
587     "%{transfer-port}",
588     "%{transfer-status}",
589     "%{transfer-type}",
590     "%{uid}",
591     "%{version}",
592     NULL
593   };
594 
595   jot_ctx = pcalloc(p, sizeof(pr_jot_ctx_t));
596   text = "%{env:FOOBAR}!";
597   parse_on_meta_count = parse_on_unknown_count = parse_on_other_count = 0;
598 
599   mark_point();
600   res = pr_jot_parse_logfmt(p, text, jot_ctx, long_on_meta, NULL,
601     parse_on_other, 0);
602   fail_unless(res == 0, "Failed to parse text '%s': %s", text, strerror(errno));
603   fail_unless(parse_on_meta_count == 1, "Expected on_meta count 1, got %u",
604     parse_on_meta_count);
605   fail_unless(parse_on_other_count == 1, "Expected on_other count 1, got %u",
606     parse_on_other_count);
607 
608   text = "%{note:FOOBAR}!";
609   parse_on_meta_count = parse_on_unknown_count = parse_on_other_count = 0;
610 
611   mark_point();
612   res = pr_jot_parse_logfmt(p, text, jot_ctx, long_on_meta, NULL,
613     parse_on_other, 0);
614   fail_unless(res == 0, "Failed to parse text '%s': %s", text, strerror(errno));
615   fail_unless(parse_on_meta_count == 1, "Expected on_meta count 1, got %u",
616     parse_on_meta_count);
617   fail_unless(parse_on_other_count == 1, "Expected on_other count 1, got %u",
618     parse_on_other_count);
619 
620   text = "%{time:FOOBAR}!";
621   parse_on_meta_count = parse_on_unknown_count = parse_on_other_count = 0;
622 
623   mark_point();
624   res = pr_jot_parse_logfmt(p, text, jot_ctx, long_on_meta, NULL,
625     parse_on_other, 0);
626   fail_unless(res == 0, "Failed to parse text '%s': %s", text, strerror(errno));
627   fail_unless(parse_on_meta_count == 1, "Expected on_meta count 1, got %u",
628     parse_on_meta_count);
629   fail_unless(parse_on_other_count == 1, "Expected on_other count 1, got %u",
630     parse_on_other_count);
631 
632   parse_on_meta_count = parse_on_unknown_count = parse_on_other_count = 0;
633   text_count = 0;
634 
635   for (i = 0; texts[i]; i++) {
636     text = (const char *) texts[i];
637     text_count++;
638 
639     mark_point();
640     res = pr_jot_parse_logfmt(p, text, jot_ctx, parse_on_meta, NULL,
641       parse_on_other, 0);
642     fail_unless(res == 0, "Failed to parse text '%s': %s", text,
643       strerror(errno));
644   }
645 
646   fail_unless(parse_on_meta_count == text_count,
647     "Expected on_meta count %d, got %u", text_count, parse_on_meta_count);
648   fail_unless(parse_on_other_count == 0, "Expected on_other count 0, got %u",
649     parse_on_other_count);
650 
651   text = "%{FOOBAR}e";
652   parse_on_meta_count = parse_on_unknown_count = parse_on_other_count = 0;
653 
654   mark_point();
655   res = pr_jot_parse_logfmt(p, text, jot_ctx, long_on_meta, NULL,
656     parse_on_other, 0);
657   fail_unless(res == 0, "Failed to parse text '%s': %s", text, strerror(errno));
658   fail_unless(parse_on_meta_count == 1, "Expected on_meta count 1, got %u",
659     parse_on_meta_count);
660   fail_unless(parse_on_other_count == 0, "Expected on_other count 0, got %u",
661     parse_on_other_count);
662 
663   text = "%{FOOBAR}t";
664   parse_on_meta_count = parse_on_unknown_count = parse_on_other_count = 0;
665 
666   mark_point();
667   res = pr_jot_parse_logfmt(p, text, jot_ctx, long_on_meta, NULL,
668     parse_on_other, 0);
669   fail_unless(res == 0, "Failed to parse text '%s': %s", text, strerror(errno));
670   fail_unless(parse_on_meta_count == 1, "Expected on_meta count 1, got %u",
671     parse_on_meta_count);
672   fail_unless(parse_on_other_count == 0, "Expected on_other count 0, got %u",
673     parse_on_other_count);
674 
675   text = "%{FOOBAR}T";
676   parse_on_meta_count = parse_on_unknown_count = parse_on_other_count = 0;
677 
678   /* Here we should see 1 unknown for "%{FOOBAR}", and 1 other for the
679    * trailing "T".
680    */
681 
682   mark_point();
683   res = pr_jot_parse_logfmt(p, text, jot_ctx, long_on_meta, parse_on_unknown,
684     parse_on_other, 0);
685   fail_unless(res == 0, "Failed to parse text '%s': %s", text, strerror(errno));
686   fail_unless(parse_on_meta_count == 0,
687     "Expected on_meta count 0, got %u", parse_on_meta_count);
688   fail_unless(parse_on_unknown_count == 1,
689     "Expected on_unknown count 1, got %u", parse_on_unknown_count);
690   fail_unless(parse_on_other_count == 1,
691     "Expected on_other count 1, got %u", parse_on_other_count);
692 }
693 END_TEST
694 
START_TEST(jot_parse_logfmt_custom_vars_test)695 START_TEST (jot_parse_logfmt_custom_vars_test) {
696   int res;
697   pr_jot_ctx_t *jot_ctx;
698   const char *text;
699 
700   jot_ctx = pcalloc(p, sizeof(pr_jot_ctx_t));
701   text = "%{0}";
702   parse_on_meta_count = parse_on_unknown_count = parse_on_other_count = 0;
703 
704   mark_point();
705   res = pr_jot_parse_logfmt(p, text, jot_ctx, parse_on_meta, parse_on_unknown,
706     parse_on_other, 0);
707   fail_unless(res == 0, "Failed to parse text '%s': %s", text, strerror(errno));
708   fail_unless(parse_on_meta_count == 0,
709     "Expected on_meta count 0, got %u", parse_on_meta_count);
710   fail_unless(parse_on_unknown_count == 1,
711     "Expected on_unknown count 1, got %u", parse_on_unknown_count);
712   fail_unless(parse_on_other_count == 0,
713     "Expected on_other count 0, got %u", parse_on_other_count);
714 
715   parse_on_meta_count = parse_on_unknown_count = parse_on_other_count = 0;
716 
717   mark_point();
718   res = pr_jot_parse_logfmt(p, text, jot_ctx, parse_on_meta, parse_on_unknown,
719     parse_on_other, PR_JOT_LOGFMT_PARSE_FL_UNKNOWN_AS_CUSTOM);
720   fail_unless(res == 0, "Failed to parse text '%s': %s", text, strerror(errno));
721   fail_unless(parse_on_meta_count == 1,
722     "Expected on_meta count 1, got %u", parse_on_meta_count);
723   fail_unless(parse_on_unknown_count == 0,
724     "Expected on_unknown count 0, got %u", parse_on_unknown_count);
725   fail_unless(parse_on_other_count == 0,
726     "Expected on_other count 0, got %u", parse_on_other_count);
727 }
728 END_TEST
729 
730 static unsigned int resolve_on_meta_count = 0;
731 static unsigned int resolve_on_default_count = 0;
732 static unsigned int resolve_on_other_count = 0;
733 
resolve_id_on_meta(pool * jot_pool,pr_jot_ctx_t * jot_ctx,unsigned char logfmt_id,const char * jot_hint,const void * jot_val)734 static int resolve_id_on_meta(pool *jot_pool, pr_jot_ctx_t *jot_ctx,
735     unsigned char logfmt_id, const char *jot_hint, const void *jot_val) {
736   resolve_on_meta_count++;
737   return 0;
738 }
739 
resolve_id_on_default(pool * jot_pool,pr_jot_ctx_t * jot_ctx,unsigned char logfmt_id)740 static int resolve_id_on_default(pool *jot_pool, pr_jot_ctx_t *jot_ctx,
741     unsigned char logfmt_id) {
742   resolve_on_default_count++;
743   return 0;
744 }
745 
START_TEST(jot_resolve_logfmt_id_test)746 START_TEST (jot_resolve_logfmt_id_test) {
747   int res;
748   cmd_rec *cmd;
749   unsigned char logfmt_id;
750 
751   mark_point();
752   res = pr_jot_resolve_logfmt_id(NULL, NULL, NULL, 0, NULL, 0, NULL, NULL,
753     NULL);
754   fail_unless(res < 0, "Failed to handle null pool");
755   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
756     strerror(errno), errno);
757 
758   mark_point();
759   res = pr_jot_resolve_logfmt_id(p, NULL, NULL, 0, NULL, 0, NULL, NULL, NULL);
760   fail_unless(res < 0, "Failed to handle null cmd");
761   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
762     strerror(errno), errno);
763 
764   cmd = pr_cmd_alloc(p, 1, pstrdup(p, "FOO"));
765 
766   mark_point();
767   res = pr_jot_resolve_logfmt_id(p, cmd, NULL, 0, NULL, 0, NULL, NULL, NULL);
768   fail_unless(res < 0, "Failed to handle null on_meta");
769   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
770     strerror(errno), errno);
771 
772   logfmt_id = 0;
773 
774   mark_point();
775   res = pr_jot_resolve_logfmt_id(p, cmd, NULL, logfmt_id, NULL, 0, NULL,
776     resolve_id_on_meta, NULL);
777   fail_unless(res < 0, "Failed to handle invalid logfmt_id %u", logfmt_id);
778   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
779     strerror(errno), errno);
780 
781   logfmt_id = LOGFMT_META_START;
782 
783   mark_point();
784   res = pr_jot_resolve_logfmt_id(p, cmd, NULL, logfmt_id, NULL, 0, NULL,
785     resolve_id_on_meta, NULL);
786   fail_unless(res < 0, "Failed to handle invalid logfmt_id %u", logfmt_id);
787   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
788     strerror(errno), errno);
789 
790   logfmt_id = LOGFMT_META_ARG_END;
791 
792   mark_point();
793   res = pr_jot_resolve_logfmt_id(p, cmd, NULL, logfmt_id, NULL, 0, NULL,
794     resolve_id_on_meta, NULL);
795   fail_unless(res < 0, "Failed to handle invalid logfmt_id %u", logfmt_id);
796   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
797     strerror(errno), errno);
798 }
799 END_TEST
800 
START_TEST(jot_resolve_logfmt_id_on_default_test)801 START_TEST (jot_resolve_logfmt_id_on_default_test) {
802   int res;
803   cmd_rec *cmd;
804   unsigned char logfmt_id;
805 
806   cmd = pr_cmd_alloc(p, 1, pstrdup(p, "FOO"));
807   logfmt_id = LOGFMT_META_BASENAME;
808   resolve_on_meta_count = resolve_on_default_count = 0;
809 
810   mark_point();
811   res = pr_jot_resolve_logfmt_id(p, cmd, NULL, logfmt_id, NULL, 0, NULL,
812     resolve_id_on_meta, resolve_id_on_default);
813   fail_unless(res == 0, "Failed to handle logfmt_id %u: %s", logfmt_id,
814     strerror(errno));
815   fail_unless(resolve_on_meta_count == 0,
816     "Expected on_meta count 0, got %u", resolve_on_meta_count);
817   fail_unless(resolve_on_default_count == 1,
818     "Expected on_default count 1, got %u", resolve_on_default_count);
819 }
820 END_TEST
821 
START_TEST(jot_resolve_logfmt_id_filters_test)822 START_TEST (jot_resolve_logfmt_id_filters_test) {
823   int res;
824   cmd_rec *cmd;
825   pr_jot_filters_t *jot_filters;
826   unsigned char logfmt_id;
827 
828   cmd = pr_cmd_alloc(p, 1, pstrdup(p, "FOO"));
829   cmd->cmd_class = CL_CONNECT;
830   logfmt_id = LOGFMT_META_CONNECT;
831 
832   /* No filters; should be implicitly jottable. */
833   resolve_on_meta_count = resolve_on_default_count = 0;
834   jot_filters = NULL;
835 
836   mark_point();
837   res = pr_jot_resolve_logfmt_id(p, cmd, jot_filters, logfmt_id, NULL, 0, NULL,
838     resolve_id_on_meta, NULL);
839   fail_unless(res == 0, "Failed to handle logfmt_id %u: %s", logfmt_id,
840     strerror(errno));
841   fail_unless(resolve_on_meta_count == 1,
842     "Expected on_meta count 1, got %u", resolve_on_meta_count);
843   fail_unless(resolve_on_default_count == 0,
844     "Expected on_default count 0, got %u", resolve_on_default_count);
845 
846   /* With an ALL filter, and no command class. */
847   cmd->cmd_class = 0;
848   logfmt_id = LOGFMT_META_COMMAND;
849   resolve_on_meta_count = resolve_on_default_count = 0;
850   jot_filters = pr_jot_filters_create(p, "ALL",
851     PR_JOT_FILTER_TYPE_CLASSES, PR_JOT_FILTER_FL_ALL_INCL_ALL);
852 
853   mark_point();
854   res = pr_jot_resolve_logfmt_id(p, cmd, jot_filters, logfmt_id, NULL, 0, NULL,
855     resolve_id_on_meta, NULL);
856   fail_unless(res == 0, "Failed to handle logfmt_id %u: %s", logfmt_id,
857     strerror(errno));
858   fail_unless(resolve_on_meta_count == 1,
859     "Expected on_meta count 1, got %u", resolve_on_meta_count);
860   fail_unless(resolve_on_default_count == 0,
861     "Expected on_default count 0, got %u", resolve_on_default_count);
862 
863   /* With explicit filters that allow the class. */
864   cmd->cmd_class = CL_CONNECT;
865   logfmt_id = LOGFMT_META_CONNECT;
866   resolve_on_meta_count = resolve_on_default_count = 0;
867   jot_filters = pr_jot_filters_create(p, "CONNECT",
868     PR_JOT_FILTER_TYPE_CLASSES, 0);
869 
870   mark_point();
871   res = pr_jot_resolve_logfmt_id(p, cmd, jot_filters, logfmt_id, NULL, 0, NULL,
872     resolve_id_on_meta, NULL);
873   fail_unless(res == 0, "Failed to handle logfmt_id %u: %s", logfmt_id,
874     strerror(errno));
875   fail_unless(resolve_on_meta_count == 1,
876     "Expected on_meta count 1, got %u", resolve_on_meta_count);
877   fail_unless(resolve_on_default_count == 0,
878     "Expected on_default count 0, got %u", resolve_on_default_count);
879 
880   /* With explicit filters that ignore the class. */
881   resolve_on_meta_count = resolve_on_default_count = 0;
882   jot_filters = pr_jot_filters_create(p, "!CONNECT",
883     PR_JOT_FILTER_TYPE_CLASSES, 0);
884 
885   mark_point();
886   res = pr_jot_resolve_logfmt_id(p, cmd, jot_filters, logfmt_id, NULL, 0, NULL,
887     resolve_id_on_meta, NULL);
888   fail_unless(res < 0, "Failed to handle filtered logfmt_id %u", logfmt_id);
889   fail_unless(errno == EPERM, "Expected EPERM (%d), got %s (%d)", EPERM,
890     strerror(errno), errno);
891   fail_unless(resolve_on_meta_count == 0,
892     "Expected on_meta count 0, got %u", resolve_on_meta_count);
893 
894   /* With explicit filters that do not match the class. */
895   resolve_on_meta_count = resolve_on_default_count = 0;
896   jot_filters = pr_jot_filters_create(p, "DISCONNECT",
897     PR_JOT_FILTER_TYPE_CLASSES, 0);
898 
899   mark_point();
900   res = pr_jot_resolve_logfmt_id(p, cmd, jot_filters, logfmt_id, NULL, 0, NULL,
901     resolve_id_on_meta, NULL);
902   fail_unless(res < 0, "Failed to handle filtered logfmt_id %u", logfmt_id);
903   fail_unless(errno == EPERM, "Expected EPERM (%d), got %s (%d)", EPERM,
904     strerror(errno), errno);
905   fail_unless(resolve_on_meta_count == 0,
906     "Expected on_meta count 0, got %u", resolve_on_meta_count);
907 
908   /* With explicit filters that allow the command. Note that this REQUIRES
909    * that we use a known command, since allowed command comparisons are done
910    * by ID.
911    */
912   cmd = pr_cmd_alloc(p, 1, pstrdup(p, "RANG"));
913   cmd->cmd_class = CL_CONNECT;
914   resolve_on_meta_count = resolve_on_default_count = 0;
915   jot_filters = pr_jot_filters_create(p, "RANG",
916     PR_JOT_FILTER_TYPE_COMMANDS, 0);
917 
918   mark_point();
919   res = pr_jot_resolve_logfmt_id(p, cmd, jot_filters, logfmt_id, NULL, 0, NULL,
920     resolve_id_on_meta, NULL);
921   fail_unless(res == 0, "Failed to handle logfmt_id %u: %s", logfmt_id,
922     strerror(errno));
923   fail_unless(resolve_on_meta_count == 1,
924     "Expected on_meta count 1, got %u", resolve_on_meta_count);
925   fail_unless(resolve_on_default_count == 0,
926     "Expected on_default count 0, got %u", resolve_on_default_count);
927 
928   /* With explicit filters that ignore the command. */
929   resolve_on_meta_count = resolve_on_default_count = 0;
930   jot_filters = pr_jot_filters_create(p, "!RANG",
931     PR_JOT_FILTER_TYPE_COMMANDS, 0);
932 
933   mark_point();
934   res = pr_jot_resolve_logfmt_id(p, cmd, jot_filters, logfmt_id, NULL, 0, NULL,
935     resolve_id_on_meta, NULL);
936   fail_unless(res < 0, "Failed to handle filtered logfmt_id %u", logfmt_id);
937   fail_unless(errno == EPERM, "Expected EPERM (%d), got %s (%d)", EPERM,
938     strerror(errno), errno);
939   fail_unless(resolve_on_meta_count == 0,
940     "Expected on_meta count 0, got %u", resolve_on_meta_count);
941 
942   /* With explicit filters that do not match the command. */
943   resolve_on_meta_count = resolve_on_default_count = 0;
944   jot_filters = pr_jot_filters_create(p, "FOO",
945     PR_JOT_FILTER_TYPE_COMMANDS, 0);
946 
947   mark_point();
948   res = pr_jot_resolve_logfmt_id(p, cmd, jot_filters, logfmt_id, NULL, 0, NULL,
949     resolve_id_on_meta, NULL);
950   fail_unless(res < 0, "Failed to handle filtered logfmt_id %u", logfmt_id);
951   fail_unless(errno == EPERM, "Expected EPERM (%d), got %s (%d)", EPERM,
952     strerror(errno), errno);
953   fail_unless(resolve_on_meta_count == 0,
954     "Expected on_meta count 0, got %u", resolve_on_meta_count);
955 }
956 END_TEST
957 
START_TEST(jot_resolve_logfmt_id_connect_test)958 START_TEST (jot_resolve_logfmt_id_connect_test) {
959   int res;
960   cmd_rec *cmd;
961   unsigned char logfmt_id;
962 
963   cmd = pr_cmd_alloc(p, 1, pstrdup(p, "FOO"));
964   cmd->cmd_class = CL_CONNECT;
965   logfmt_id = LOGFMT_META_CONNECT;
966 
967   resolve_on_meta_count = resolve_on_default_count = 0;
968 
969   mark_point();
970   res = pr_jot_resolve_logfmt_id(p, cmd, NULL, logfmt_id, NULL, 0, NULL,
971     resolve_id_on_meta, NULL);
972   fail_unless(res == 0, "Failed to handle logfmt_id %u: %s", logfmt_id,
973     strerror(errno));
974   fail_unless(resolve_on_meta_count == 1,
975     "Expected on_meta count 1, got %u", resolve_on_meta_count);
976   fail_unless(resolve_on_default_count == 0,
977     "Expected on_default count 0, got %u", resolve_on_default_count);
978 
979   resolve_on_meta_count = resolve_on_default_count = 0;
980   cmd->cmd_class = CL_DISCONNECT;
981 
982   mark_point();
983   res = pr_jot_resolve_logfmt_id(p, cmd, NULL, logfmt_id, NULL, 0, NULL,
984     resolve_id_on_meta, NULL);
985   fail_unless(res == 0, "Failed to handle logfmt_id %u: %s", logfmt_id,
986     strerror(errno));
987   fail_unless(resolve_on_meta_count == 0,
988     "Expected on_meta count 0, got %u", resolve_on_meta_count);
989   fail_unless(resolve_on_default_count == 0,
990     "Expected on_default count 0, got %u", resolve_on_default_count);
991 }
992 END_TEST
993 
START_TEST(jot_resolve_logfmt_id_disconnect_test)994 START_TEST (jot_resolve_logfmt_id_disconnect_test) {
995   int res;
996   cmd_rec *cmd;
997   unsigned char logfmt_id;
998 
999   cmd = pr_cmd_alloc(p, 1, pstrdup(p, "FOO"));
1000   cmd->cmd_class = CL_DISCONNECT;
1001   logfmt_id = LOGFMT_META_DISCONNECT;
1002 
1003   resolve_on_meta_count = resolve_on_default_count = 0;
1004 
1005   mark_point();
1006   res = pr_jot_resolve_logfmt_id(p, cmd, NULL, logfmt_id, NULL, 0, NULL,
1007     resolve_id_on_meta, NULL);
1008   fail_unless(res == 0, "Failed to handle logfmt_id %u: %s", logfmt_id,
1009     strerror(errno));
1010   fail_unless(resolve_on_meta_count == 1,
1011     "Expected on_meta count 1, got %u", resolve_on_meta_count);
1012   fail_unless(resolve_on_default_count == 0,
1013     "Expected on_default count 0, got %u", resolve_on_default_count);
1014 
1015   resolve_on_meta_count = resolve_on_default_count = 0;
1016   cmd->cmd_class = CL_CONNECT;
1017 
1018   mark_point();
1019   res = pr_jot_resolve_logfmt_id(p, cmd, NULL, logfmt_id, NULL, 0, NULL,
1020     resolve_id_on_meta, NULL);
1021   fail_unless(res == 0, "Failed to handle logfmt_id %u: %s", logfmt_id,
1022     strerror(errno));
1023   fail_unless(resolve_on_meta_count == 0,
1024     "Expected on_meta count 0, got %u", resolve_on_meta_count);
1025   fail_unless(resolve_on_default_count == 0,
1026     "Expected on_default count 0, got %u", resolve_on_default_count);
1027 }
1028 END_TEST
1029 
START_TEST(jot_resolve_logfmt_id_custom_test)1030 START_TEST (jot_resolve_logfmt_id_custom_test) {
1031   int res;
1032   cmd_rec *cmd;
1033   unsigned char logfmt_id;
1034   const char *custom_data;
1035   size_t custom_datalen;
1036 
1037   cmd = pr_cmd_alloc(p, 1, pstrdup(p, "FOO"));
1038   cmd->cmd_class = CL_MISC;
1039   logfmt_id = LOGFMT_META_CUSTOM;
1040 
1041   resolve_on_meta_count = resolve_on_default_count = 0;
1042   custom_data = "%{0}";
1043   custom_datalen = strlen(custom_data);
1044 
1045   mark_point();
1046   res = pr_jot_resolve_logfmt_id(p, cmd, NULL, logfmt_id, custom_data,
1047     custom_datalen, NULL, resolve_id_on_meta, NULL);
1048   fail_unless(res == 0, "Failed to handle logfmt_id %u: %s", logfmt_id,
1049     strerror(errno));
1050   fail_unless(resolve_on_meta_count == 1,
1051     "Expected on_meta count 1, got %u", resolve_on_meta_count);
1052   fail_unless(resolve_on_default_count == 0,
1053     "Expected on_default count 0, got %u", resolve_on_default_count);
1054 }
1055 END_TEST
1056 
START_TEST(jot_resolve_logfmt_ids_test)1057 START_TEST (jot_resolve_logfmt_ids_test) {
1058   register unsigned char i;
1059   int res;
1060   cmd_rec *cmd;
1061   unsigned char logfmt_id;
1062 
1063   cmd = pr_cmd_alloc(p, 1, pstrdup(p, "FOO"));
1064   resolve_on_meta_count = resolve_on_default_count = 0;
1065 
1066   /* Currently, the max known LogFormat meta/ID is 53 (DISCONNECT). */
1067   for (i = 1; i < 54; i++) {
1068     logfmt_id = i;
1069 
1070     mark_point();
1071     res = pr_jot_resolve_logfmt_id(p, cmd, NULL, logfmt_id, NULL, 0, NULL,
1072       resolve_id_on_meta, resolve_id_on_default);
1073     fail_unless(res == 0, "Failed to handle logfmt_id %u: %s", logfmt_id,
1074       strerror(errno));
1075   }
1076 
1077   fail_unless(resolve_on_meta_count == 20,
1078     "Expected on_meta count 20, got %u", resolve_on_meta_count);
1079   fail_unless(resolve_on_default_count == 28,
1080     "Expected on_default count 28, got %u", resolve_on_default_count);
1081 }
1082 END_TEST
1083 
resolve_on_meta(pool * jot_pool,pr_jot_ctx_t * jot_ctx,unsigned char logfmt_id,const char * jot_hint,const void * val)1084 static int resolve_on_meta(pool *jot_pool, pr_jot_ctx_t *jot_ctx,
1085     unsigned char logfmt_id, const char *jot_hint, const void *val) {
1086   resolve_on_meta_count++;
1087   return 0;
1088 }
1089 
resolve_on_default(pool * jot_pool,pr_jot_ctx_t * jot_ctx,unsigned char logfmt_id)1090 static int resolve_on_default(pool *jot_pool, pr_jot_ctx_t *jot_ctx,
1091     unsigned char logfmt_id) {
1092   resolve_on_default_count++;
1093   return 0;
1094 }
1095 
resolve_on_other(pool * jot_pool,pr_jot_ctx_t * jot_ctx,unsigned char * text,size_t text_len)1096 static int resolve_on_other(pool *jot_pool, pr_jot_ctx_t *jot_ctx,
1097     unsigned char *text, size_t text_len) {
1098   resolve_on_other_count++;
1099   return 0;
1100 }
1101 
START_TEST(jot_resolve_logfmt_test)1102 START_TEST (jot_resolve_logfmt_test) {
1103   int res;
1104   cmd_rec *cmd;
1105   unsigned char *logfmt;
1106 
1107   mark_point();
1108   res = pr_jot_resolve_logfmt(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1109   fail_unless(res < 0, "Failed to handle null pool");
1110   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1111     strerror(errno), errno);
1112 
1113   mark_point();
1114   res = pr_jot_resolve_logfmt(p, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1115   fail_unless(res < 0, "Failed to handle null cmd");
1116   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1117     strerror(errno), errno);
1118 
1119   cmd = pr_cmd_alloc(p, 1, pstrdup(p, "FOO"));
1120 
1121   mark_point();
1122   res = pr_jot_resolve_logfmt(p, cmd, NULL, NULL, NULL, NULL, NULL, NULL);
1123   fail_unless(res < 0, "Failed to handle null logfmt");
1124   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1125     strerror(errno), errno);
1126 
1127   logfmt = (unsigned char *) "";
1128 
1129   mark_point();
1130   res = pr_jot_resolve_logfmt(p, cmd, NULL, logfmt, NULL, NULL, NULL, NULL);
1131   fail_unless(res < 0, "Failed to handle null on_meta");
1132   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1133     strerror(errno), errno);
1134 
1135   mark_point();
1136   res = pr_jot_resolve_logfmt(p, cmd, NULL, logfmt, NULL, resolve_on_meta,
1137     NULL, NULL);
1138   fail_unless(res == 0, "Failed to handle empty logfmt: %s", strerror(errno));
1139 }
1140 END_TEST
1141 
START_TEST(jot_resolve_logfmt_filters_test)1142 START_TEST (jot_resolve_logfmt_filters_test) {
1143   int res;
1144   cmd_rec *cmd;
1145   pr_jot_filters_t *jot_filters;
1146   unsigned char logfmt[3];
1147 
1148   cmd = pr_cmd_alloc(p, 1, pstrdup(p, "FOO"));
1149   cmd->cmd_class = CL_CONNECT;
1150 
1151   /* No filters; should be implicitly jottable. */
1152   resolve_on_meta_count = resolve_on_default_count = resolve_on_other_count = 0;
1153   jot_filters = NULL;
1154   logfmt[0] = LOGFMT_META_START;
1155   logfmt[1] = LOGFMT_META_CONNECT;
1156   logfmt[2] = 0;
1157 
1158   mark_point();
1159   res = pr_jot_resolve_logfmt(p, cmd, jot_filters, logfmt, NULL,
1160     resolve_on_meta, NULL, NULL);
1161   fail_unless(res == 0, "Failed to handle logfmt: %s", strerror(errno));
1162   fail_unless(resolve_on_meta_count == 1,
1163     "Expected on_meta count 1, got %u", resolve_on_meta_count);
1164 
1165   /* With an ALL filter, and no command class. */
1166   cmd->cmd_class = 0;
1167   logfmt[1] = LOGFMT_META_COMMAND;
1168   resolve_on_meta_count = resolve_on_default_count = 0;
1169   jot_filters = pr_jot_filters_create(p, "ALL",
1170     PR_JOT_FILTER_TYPE_CLASSES, PR_JOT_FILTER_FL_ALL_INCL_ALL);
1171 
1172   mark_point();
1173   res = pr_jot_resolve_logfmt(p, cmd, jot_filters, logfmt, NULL,
1174     resolve_on_meta, NULL, NULL);
1175   fail_unless(res == 0, "Failed to handle logfmt: %s", strerror(errno));
1176   fail_unless(resolve_on_meta_count == 1,
1177     "Expected on_meta count 1, got %u", resolve_on_meta_count);
1178 
1179   /* With explicit filters that allow the class. */
1180   cmd->cmd_class = CL_CONNECT;
1181   logfmt[1] = LOGFMT_META_CONNECT;
1182   resolve_on_meta_count = resolve_on_default_count = 0;
1183   jot_filters = pr_jot_filters_create(p, "CONNECT",
1184     PR_JOT_FILTER_TYPE_CLASSES, 0);
1185 
1186   mark_point();
1187   res = pr_jot_resolve_logfmt(p, cmd, jot_filters, logfmt, NULL,
1188     resolve_on_meta, NULL, NULL);
1189   fail_unless(res == 0, "Failed to handle logfmt: %s", strerror(errno));
1190   fail_unless(resolve_on_meta_count == 1,
1191     "Expected on_meta count 1, got %u", resolve_on_meta_count);
1192 
1193   /* With explicit filters that ignore the class. */
1194   resolve_on_meta_count = resolve_on_default_count = 0;
1195   jot_filters = pr_jot_filters_create(p, "!CONNECT",
1196     PR_JOT_FILTER_TYPE_CLASSES, 0);
1197 
1198   mark_point();
1199   res = pr_jot_resolve_logfmt(p, cmd, jot_filters, logfmt, NULL,
1200     resolve_on_meta, NULL, NULL);
1201   fail_unless(res < 0, "Failed to handle filtered logfmt");
1202   fail_unless(errno == EPERM, "Expected EPERM (%d), got %s (%d)", EPERM,
1203     strerror(errno), errno);
1204   fail_unless(resolve_on_meta_count == 0,
1205     "Expected on_meta count 0, got %u", resolve_on_meta_count);
1206 
1207   /* With explicit filters that do not match the class. */
1208   resolve_on_meta_count = resolve_on_default_count = 0;
1209   jot_filters = pr_jot_filters_create(p, "DISCONNECT",
1210     PR_JOT_FILTER_TYPE_CLASSES, 0);
1211 
1212   mark_point();
1213   res = pr_jot_resolve_logfmt(p, cmd, jot_filters, logfmt, NULL,
1214     resolve_on_meta, NULL, NULL);
1215   fail_unless(res < 0, "Failed to handle filtered logfmt");
1216   fail_unless(errno == EPERM, "Expected EPERM (%d), got %s (%d)", EPERM,
1217     strerror(errno), errno);
1218   fail_unless(resolve_on_meta_count == 0,
1219     "Expected on_meta count 0, got %u", resolve_on_meta_count);
1220 
1221   /* With explicit filters that allow the command. Note that this REQUIRES
1222    * that we use a known command, since allowed command comparisons are done
1223    * by ID.
1224    */
1225   cmd = pr_cmd_alloc(p, 1, pstrdup(p, "RANG"));
1226   cmd->cmd_class = CL_CONNECT;
1227   resolve_on_meta_count = resolve_on_default_count = 0;
1228   jot_filters = pr_jot_filters_create(p, "RANG",
1229     PR_JOT_FILTER_TYPE_COMMANDS, 0);
1230 
1231   mark_point();
1232   res = pr_jot_resolve_logfmt(p, cmd, jot_filters, logfmt, NULL,
1233     resolve_on_meta, NULL, NULL);
1234   fail_unless(res == 0, "Failed to handle logfmt: %s", strerror(errno));
1235   fail_unless(resolve_on_meta_count == 1,
1236     "Expected on_meta count 1, got %u", resolve_on_meta_count);
1237 
1238   /* With explicit filters that ignore the command. */
1239   resolve_on_meta_count = resolve_on_default_count = 0;
1240   jot_filters = pr_jot_filters_create(p, "!RANG",
1241     PR_JOT_FILTER_TYPE_COMMANDS, 0);
1242 
1243   mark_point();
1244   res = pr_jot_resolve_logfmt(p, cmd, jot_filters, logfmt, NULL,
1245     resolve_on_meta, NULL, NULL);
1246   fail_unless(res < 0, "Failed to handle filtered logfmt");
1247   fail_unless(errno == EPERM, "Expected EPERM (%d), got %s (%d)", EPERM,
1248     strerror(errno), errno);
1249   fail_unless(resolve_on_meta_count == 0,
1250     "Expected on_meta count 0, got %u", resolve_on_meta_count);
1251 
1252   /* With explicit filters that do not match the command. */
1253   resolve_on_meta_count = resolve_on_default_count = 0;
1254   jot_filters = pr_jot_filters_create(p, "FOO",
1255     PR_JOT_FILTER_TYPE_COMMANDS, 0);
1256 
1257   mark_point();
1258   res = pr_jot_resolve_logfmt(p, cmd, jot_filters, logfmt, NULL,
1259     resolve_on_meta, NULL, NULL);
1260   fail_unless(res < 0, "Failed to handle filtered logfmt");
1261   fail_unless(errno == EPERM, "Expected EPERM (%d), got %s (%d)", EPERM,
1262     strerror(errno), errno);
1263   fail_unless(resolve_on_meta_count == 0,
1264     "Expected on_meta count 0, got %u", resolve_on_meta_count);
1265 }
1266 END_TEST
1267 
START_TEST(jot_resolve_logfmt_on_default_test)1268 START_TEST (jot_resolve_logfmt_on_default_test) {
1269   int res;
1270   cmd_rec *cmd;
1271   unsigned char logfmt[3];
1272 
1273   cmd = pr_cmd_alloc(p, 1, pstrdup(p, "FOO"));
1274   logfmt[0] = LOGFMT_META_START;
1275   logfmt[1] = LOGFMT_META_BASENAME;
1276   logfmt[2] = 0;
1277   resolve_on_meta_count = resolve_on_default_count = resolve_on_other_count = 0;
1278 
1279   mark_point();
1280   res = pr_jot_resolve_logfmt(p, cmd, NULL, logfmt, NULL,
1281     resolve_on_meta, resolve_on_default, NULL);
1282   fail_unless(res == 0, "Failed to handle logfmt: %s", strerror(errno));
1283   fail_unless(resolve_on_meta_count == 0,
1284     "Expected on_meta count 0, got %u", resolve_on_meta_count);
1285   fail_unless(resolve_on_default_count == 1,
1286     "Expected on_default count 1, got %u", resolve_on_default_count);
1287 }
1288 END_TEST
1289 
START_TEST(jot_resolve_logfmt_on_other_test)1290 START_TEST (jot_resolve_logfmt_on_other_test) {
1291   int res;
1292   cmd_rec *cmd;
1293   unsigned char logfmt[3];
1294 
1295   cmd = pr_cmd_alloc(p, 1, pstrdup(p, "FOO"));
1296   logfmt[0] = 'A';
1297   logfmt[1] = '!';
1298   logfmt[2] = 0;
1299   resolve_on_meta_count = resolve_on_default_count = resolve_on_other_count = 0;
1300 
1301   mark_point();
1302   res = pr_jot_resolve_logfmt(p, cmd, NULL, logfmt, NULL,
1303     resolve_on_meta, resolve_on_default, resolve_on_other);
1304   fail_unless(res == 0, "Failed to handle logfmt: %s", strerror(errno));
1305   fail_unless(resolve_on_meta_count == 0,
1306     "Expected on_meta count 0, got %u", resolve_on_meta_count);
1307   fail_unless(resolve_on_default_count == 0,
1308     "Expected on_default count 0, got %u", resolve_on_default_count);
1309   fail_unless(resolve_on_other_count == 1,
1310     "Expected on_other count 1, got %u", resolve_on_other_count);
1311 }
1312 END_TEST
1313 
START_TEST(jot_resolve_logfmt_connect_test)1314 START_TEST (jot_resolve_logfmt_connect_test) {
1315   int res;
1316   cmd_rec *cmd;
1317   unsigned char logfmt[3];
1318 
1319   cmd = pr_cmd_alloc(p, 1, pstrdup(p, "FOO"));
1320   cmd->cmd_class = CL_CONNECT;
1321   logfmt[0] = LOGFMT_META_START;
1322   logfmt[1] = LOGFMT_META_CONNECT;
1323   logfmt[2] = 0;
1324 
1325   resolve_on_meta_count = resolve_on_default_count = resolve_on_other_count = 0;
1326 
1327   mark_point();
1328   res = pr_jot_resolve_logfmt(p, cmd, NULL, logfmt, NULL,
1329     resolve_on_meta, resolve_on_default, resolve_on_other);
1330   fail_unless(res == 0, "Failed to handle logfmt: %s", strerror(errno));
1331   fail_unless(resolve_on_meta_count == 1,
1332     "Expected on_meta count 1, got %u", resolve_on_meta_count);
1333   fail_unless(resolve_on_default_count == 0,
1334     "Expected on_default count 0, got %u", resolve_on_default_count);
1335   fail_unless(resolve_on_other_count == 0,
1336     "Expected on_other count 0, got %u", resolve_on_other_count);
1337 
1338   resolve_on_meta_count = resolve_on_default_count = resolve_on_other_count = 0;
1339   cmd->cmd_class = CL_DISCONNECT;
1340 
1341   mark_point();
1342   res = pr_jot_resolve_logfmt(p, cmd, NULL, logfmt, NULL,
1343     resolve_on_meta, resolve_on_default, resolve_on_other);
1344   fail_unless(res == 0, "Failed to handle logfmt: %s", strerror(errno));
1345   fail_unless(resolve_on_meta_count == 0,
1346     "Expected on_meta count 0, got %u", resolve_on_meta_count);
1347   fail_unless(resolve_on_default_count == 0,
1348     "Expected on_default count 0, got %u", resolve_on_default_count);
1349   fail_unless(resolve_on_other_count == 0,
1350     "Expected on_other count 0, got %u", resolve_on_other_count);
1351 }
1352 END_TEST
1353 
START_TEST(jot_resolve_logfmt_disconnect_test)1354 START_TEST (jot_resolve_logfmt_disconnect_test) {
1355   int res;
1356   cmd_rec *cmd;
1357   unsigned char logfmt[3];
1358 
1359   cmd = pr_cmd_alloc(p, 1, pstrdup(p, "FOO"));
1360   cmd->cmd_class = CL_DISCONNECT;
1361   logfmt[0] = LOGFMT_META_START;
1362   logfmt[1] = LOGFMT_META_DISCONNECT;
1363   logfmt[2] = 0;
1364 
1365   resolve_on_meta_count = resolve_on_default_count = resolve_on_other_count = 0;
1366 
1367   mark_point();
1368   res = pr_jot_resolve_logfmt(p, cmd, NULL, logfmt, NULL,
1369     resolve_on_meta, resolve_on_default, resolve_on_other);
1370   fail_unless(res == 0, "Failed to handle logfmt: %s", strerror(errno));
1371   fail_unless(resolve_on_meta_count == 1,
1372     "Expected on_meta count 1, got %u", resolve_on_meta_count);
1373   fail_unless(resolve_on_default_count == 0,
1374     "Expected on_default count 0, got %u", resolve_on_default_count);
1375   fail_unless(resolve_on_other_count == 0,
1376     "Expected on_other count 0, got %u", resolve_on_other_count);
1377 
1378   resolve_on_meta_count = resolve_on_default_count = resolve_on_other_count = 0;
1379   cmd->cmd_class = CL_CONNECT;
1380 
1381   mark_point();
1382   res = pr_jot_resolve_logfmt(p, cmd, NULL, logfmt, NULL,
1383     resolve_on_meta, resolve_on_default, resolve_on_other);
1384   fail_unless(res == 0, "Failed to handle logfmt: %s", strerror(errno));
1385   fail_unless(resolve_on_meta_count == 0,
1386     "Expected on_meta count 0, got %u", resolve_on_meta_count);
1387   fail_unless(resolve_on_default_count == 0,
1388     "Expected on_default count 0, got %u", resolve_on_default_count);
1389   fail_unless(resolve_on_other_count == 0,
1390     "Expected on_other count 0, got %u", resolve_on_other_count);
1391 }
1392 END_TEST
1393 
START_TEST(jot_resolve_logfmt_custom_test)1394 START_TEST (jot_resolve_logfmt_custom_test) {
1395   int res;
1396   cmd_rec *cmd;
1397   unsigned char logfmt[10];
1398 
1399   cmd = pr_cmd_alloc(p, 1, pstrdup(p, "FOO"));
1400   cmd->cmd_class = CL_MISC;
1401   logfmt[0] = LOGFMT_META_START;
1402   logfmt[1] = LOGFMT_META_CUSTOM;
1403   logfmt[2] = LOGFMT_META_START;
1404   logfmt[3] = LOGFMT_META_ARG;
1405   logfmt[4] = '%';
1406   logfmt[5] = '{';
1407   logfmt[6] = '0';
1408   logfmt[7] = '}';
1409   logfmt[8] = LOGFMT_META_ARG_END;
1410   logfmt[9] = 0;
1411 
1412   resolve_on_meta_count = resolve_on_default_count = resolve_on_other_count = 0;
1413 
1414   mark_point();
1415   res = pr_jot_resolve_logfmt(p, cmd, NULL, logfmt, NULL,
1416     resolve_on_meta, resolve_on_default, resolve_on_other);
1417   fail_unless(res == 0, "Failed to handle logfmt: %s", strerror(errno));
1418   fail_unless(resolve_on_meta_count == 1,
1419     "Expected on_meta count 1, got %u", resolve_on_meta_count);
1420   fail_unless(resolve_on_default_count == 0,
1421     "Expected on_default count 0, got %u", resolve_on_default_count);
1422   fail_unless(resolve_on_other_count == 0,
1423     "Expected on_other count 0, got %u", resolve_on_other_count);
1424 }
1425 END_TEST
1426 
START_TEST(jot_resolve_logfmts_test)1427 START_TEST (jot_resolve_logfmts_test) {
1428   register unsigned char i;
1429   int res;
1430   cmd_rec *cmd;
1431   unsigned char logfmt[3];
1432 
1433   cmd = pr_cmd_alloc(p, 1, pstrdup(p, "FOO"));
1434   logfmt[0] = LOGFMT_META_START;
1435   logfmt[2] = 0;
1436   resolve_on_meta_count = resolve_on_default_count = resolve_on_other_count = 0;
1437 
1438   /* Currently, the max known LogFormat meta/ID is 53 (DISCONNECT). */
1439   for (i = 1; i < 54; i++) {
1440     logfmt[1] = i;
1441 
1442     mark_point();
1443     res = pr_jot_resolve_logfmt(p, cmd, NULL, logfmt, NULL,
1444       resolve_on_meta, resolve_on_default, resolve_on_other);
1445     fail_unless(res == 0, "Failed to handle logfmt_id %u: %s", logfmt[1],
1446       strerror(errno));
1447   }
1448 
1449   fail_unless(resolve_on_meta_count == 20,
1450     "Expected on_meta count 20, got %u", resolve_on_meta_count);
1451   fail_unless(resolve_on_default_count == 28,
1452     "Expected on_default count 28, got %u", resolve_on_default_count);
1453   fail_unless(resolve_on_other_count == 0,
1454     "Expected on_other count 0, got %u", resolve_on_other_count);
1455 }
1456 END_TEST
1457 
1458 static unsigned int scan_on_meta_count = 0;
1459 
scan_on_meta(pool * jot_pool,pr_jot_ctx_t * jot_ctx,unsigned char logfmt_id,const char * logfmt_data,size_t logfmt_datalen)1460 static int scan_on_meta(pool *jot_pool, pr_jot_ctx_t *jot_ctx,
1461     unsigned char logfmt_id, const char *logfmt_data, size_t logfmt_datalen) {
1462   scan_on_meta_count++;
1463   return 0;
1464 }
1465 
START_TEST(jot_scan_logfmt_test)1466 START_TEST (jot_scan_logfmt_test) {
1467   int res;
1468   unsigned char logfmt[12];
1469 
1470   mark_point();
1471   res = pr_jot_scan_logfmt(NULL, NULL, 0, NULL, NULL, 0);
1472   fail_unless(res < 0, "Failed to handle null pool");
1473   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1474     strerror(errno), errno);
1475 
1476   mark_point();
1477   res = pr_jot_scan_logfmt(p, NULL, 0, NULL, NULL, 0);
1478   fail_unless(res < 0, "Failed to handle null logfmt");
1479   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1480     strerror(errno), errno);
1481 
1482   logfmt[0] = LOGFMT_META_START;
1483   logfmt[1] = LOGFMT_META_CUSTOM;
1484   logfmt[2] = LOGFMT_META_START;
1485   logfmt[3] = LOGFMT_META_ARG;
1486   logfmt[4] = '%';
1487   logfmt[5] = '{';
1488   logfmt[6] = 'f';
1489   logfmt[7] = 'o';
1490   logfmt[8] = 'o';
1491   logfmt[9] = '}';
1492   logfmt[10] = LOGFMT_META_ARG_END;
1493   logfmt[11] = 0;
1494 
1495   mark_point();
1496   res = pr_jot_scan_logfmt(p, logfmt, 0, NULL, NULL, 0);
1497   fail_unless(res < 0, "Failed to handle null on_meta");
1498   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1499     strerror(errno), errno);
1500 
1501   mark_point();
1502   res = pr_jot_scan_logfmt(p, logfmt, 0, NULL, scan_on_meta, 0);
1503   fail_unless(res < 0, "Failed to handle invalid LogFormat ID");
1504   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1505     strerror(errno), errno);
1506 
1507   scan_on_meta_count = 0;
1508 
1509   mark_point();
1510   res = pr_jot_scan_logfmt(p, logfmt, LOGFMT_META_ENV_VAR, NULL, scan_on_meta,
1511     0);
1512   fail_unless(res == 0, "Failed to scan logmt for ENV_VAR: %s",
1513     strerror(errno));
1514   fail_unless(scan_on_meta_count == 0, "Expected scan_on_meta 0, got %u",
1515     scan_on_meta_count);
1516 
1517   scan_on_meta_count = 0;
1518 
1519   mark_point();
1520   res = pr_jot_scan_logfmt(p, logfmt, LOGFMT_META_CUSTOM, NULL, scan_on_meta,
1521     0);
1522   fail_unless(res == 0, "Failed to scan logmt for CUSTOM: %s",
1523     strerror(errno));
1524   fail_unless(scan_on_meta_count == 1, "Expected scan_on_meta 1, got %u",
1525     scan_on_meta_count);
1526 }
1527 END_TEST
1528 
START_TEST(jot_on_json_test)1529 START_TEST (jot_on_json_test) {
1530   pr_jot_ctx_t *ctx;
1531   pr_json_object_t *json;
1532   double num;
1533   int res, truth;
1534   const char *text;
1535 
1536   mark_point();
1537   res = pr_jot_on_json(NULL, NULL, 0, NULL, NULL);
1538   fail_unless(res < 0, "Failed to handle null pool");
1539   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1540     strerror(errno), errno);
1541 
1542   mark_point();
1543   res = pr_jot_on_json(p, NULL, 0, NULL, NULL);
1544   fail_unless(res < 0, "Failed to handle null ctx");
1545   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1546     strerror(errno), errno);
1547 
1548   ctx = pcalloc(p, sizeof(pr_jot_ctx_t));
1549 
1550   mark_point();
1551   res = pr_jot_on_json(p, ctx, 0, NULL, NULL);
1552   fail_unless(res < 0, "Failed to handle null val");
1553   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1554     strerror(errno), errno);
1555 
1556   mark_point();
1557   res = pr_jot_on_json(p, ctx, 0, NULL, &num);
1558   fail_unless(res < 0, "Failed to handle null ctx->log");
1559   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1560     strerror(errno), errno);
1561 
1562   json = pr_json_object_alloc(p);
1563   ctx->log = json;
1564 
1565   mark_point();
1566   res = pr_jot_on_json(p, ctx, 0, NULL, &num);
1567   fail_unless(res < 0, "Failed to handle null ctx->user_data");
1568   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1569     strerror(errno), errno);
1570 
1571   ctx->user_data = pr_table_alloc(p, 0);
1572 
1573   mark_point();
1574   res = pr_jot_on_json(p, ctx, 0, NULL, &num);
1575   fail_unless(res < 0, "Failed to handle null JSON info");
1576   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1577     strerror(errno), errno);
1578 
1579   ctx->user_data = pr_jot_get_logfmt2json(p);
1580 
1581   mark_point();
1582   truth = FALSE;
1583   res = pr_jot_on_json(p, ctx, LOGFMT_META_CONNECT, NULL, &truth);
1584   fail_unless(res == 0, "Failed to handle LOGFMT_META_CONNECT: %s",
1585     strerror(errno));
1586 
1587   mark_point();
1588   num = 2476;
1589   res = pr_jot_on_json(p, ctx, LOGFMT_META_PID, NULL, &num);
1590   fail_unless(res == 0, "Failed to handle LOGFMT_META_PID: %s",
1591     strerror(errno));
1592 
1593   mark_point();
1594   text = "lorem ipsum";
1595   res = pr_jot_on_json(p, ctx, LOGFMT_META_IDENT_USER, NULL, text);
1596   fail_unless(res == 0, "Failed to handle LOGFMT_META_IDENT_USER: %s",
1597     strerror(errno));
1598 
1599   mark_point();
1600   text = "alef bet vet";
1601   res = pr_jot_on_json(p, ctx, LOGFMT_META_USER, "USER_KEY", text);
1602   fail_unless(res == 0, "Failed to handle LOGFMT_META_USER: %s",
1603     strerror(errno));
1604 
1605   (void) pr_json_object_free(json);
1606 }
1607 END_TEST
1608 
START_TEST(jot_get_logfmt2json_test)1609 START_TEST (jot_get_logfmt2json_test) {
1610   pr_table_t *res;
1611 
1612   mark_point();
1613   res = pr_jot_get_logfmt2json(NULL);
1614   fail_unless(res == NULL, "Failed to handle null pool");
1615   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1616     strerror(errno), errno);
1617 
1618   mark_point();
1619   res = pr_jot_get_logfmt2json(p);
1620   fail_unless(res != NULL, "Failed to get map: %s", strerror(errno));
1621 }
1622 END_TEST
1623 
START_TEST(jot_get_logfmt_id_name_test)1624 START_TEST (jot_get_logfmt_id_name_test) {
1625   register unsigned char i;
1626   const char *res;
1627 
1628   mark_point();
1629   res = pr_jot_get_logfmt_id_name(0);
1630   fail_unless(res == NULL, "Failed to handle invalid logfmt_id");
1631   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1632     strerror(errno), errno);
1633 
1634   /* Currently, the max known LogFormat meta/ID is 53 (DISCONNECT). */
1635   for (i = 2; i < 54; i++) {
1636     mark_point();
1637     res = pr_jot_get_logfmt_id_name(i);
1638     fail_unless(res != NULL, "Failed to get name for LogFormat ID %u: %s",
1639       i, strerror(errno));
1640   }
1641 
1642   res = pr_jot_get_logfmt_id_name(LOGFMT_META_CUSTOM);
1643   fail_unless(res != NULL, "Failed to get name for LogFormat ID %u: %s",
1644     LOGFMT_META_CUSTOM, strerror(errno));
1645 }
1646 END_TEST
1647 
tests_get_jot_suite(void)1648 Suite *tests_get_jot_suite(void) {
1649   Suite *suite;
1650   TCase *testcase;
1651 
1652   suite = suite_create("jot");
1653   testcase = tcase_create("base");
1654 
1655   tcase_add_checked_fixture(testcase, set_up, tear_down);
1656 
1657   tcase_add_test(testcase, jot_filters_create_test);
1658   tcase_add_test(testcase, jot_filters_destroy_test);
1659   tcase_add_test(testcase, jot_filters_include_classes_test);
1660 
1661   tcase_add_test(testcase, jot_parse_on_meta_test);
1662   tcase_add_test(testcase, jot_parse_on_unknown_test);
1663   tcase_add_test(testcase, jot_parse_on_other_test);
1664   tcase_add_test(testcase, jot_parse_logfmt_test);
1665   tcase_add_test(testcase, jot_parse_logfmt_short_vars_test);
1666   tcase_add_test(testcase, jot_parse_logfmt_long_vars_test);
1667   tcase_add_test(testcase, jot_parse_logfmt_custom_vars_test);
1668 
1669   tcase_add_test(testcase, jot_resolve_logfmt_id_test);
1670   tcase_add_test(testcase, jot_resolve_logfmt_id_on_default_test);
1671   tcase_add_test(testcase, jot_resolve_logfmt_id_filters_test);
1672   tcase_add_test(testcase, jot_resolve_logfmt_id_connect_test);
1673   tcase_add_test(testcase, jot_resolve_logfmt_id_disconnect_test);
1674   tcase_add_test(testcase, jot_resolve_logfmt_id_custom_test);
1675   tcase_add_test(testcase, jot_resolve_logfmt_ids_test);
1676 
1677   tcase_add_test(testcase, jot_resolve_logfmt_test);
1678   tcase_add_test(testcase, jot_resolve_logfmt_filters_test);
1679   tcase_add_test(testcase, jot_resolve_logfmt_on_default_test);
1680   tcase_add_test(testcase, jot_resolve_logfmt_on_other_test);
1681   tcase_add_test(testcase, jot_resolve_logfmt_connect_test);
1682   tcase_add_test(testcase, jot_resolve_logfmt_disconnect_test);
1683   tcase_add_test(testcase, jot_resolve_logfmt_custom_test);
1684   tcase_add_test(testcase, jot_resolve_logfmts_test);
1685 
1686   tcase_add_test(testcase, jot_scan_logfmt_test);
1687   tcase_add_test(testcase, jot_on_json_test);
1688   tcase_add_test(testcase, jot_get_logfmt2json_test);
1689   tcase_add_test(testcase, jot_get_logfmt_id_name_test);
1690 
1691   suite_add_tcase(suite, testcase);
1692   return suite;
1693 }
1694