56b23c11567050e64b65f0fefb3e551a6429c059
[platform/core/system/dlog.git] / src / tests / logctl.c
1 // C
2 #include <assert.h>
3 #include <stdlib.h>
4
5 // DLog
6 #include <logcommon.h>
7
8 #include "../logctl/logctl.h"
9
10 static bool fail_calloc = false;
11 extern void *__real_calloc(size_t nmemb, size_t size);
12 void *__wrap_calloc(size_t nmemb, size_t size)
13 {
14         return fail_calloc ? NULL : __real_calloc(nmemb, size);
15 }
16
17 static bool fail_asprintf = false;
18 int __wrap_asprintf(char **strp, const char *fmt, ...)
19 {
20         if (fail_asprintf)
21                 return -1;
22
23         va_list va;
24         va_start(va, fmt);
25         const int ret = vasprintf(strp, fmt, va);
26         va_end(va);
27         return ret;
28 }
29
30 static bool fail_open;
31 int __real_open(const char *path, int flags, mode_t mode);
32 int __wrap_open(const char *path, int flags, mode_t mode)
33 {
34         return fail_open ? -1 : __real_open(path, flags, mode);
35 }
36 int __wrap_open64(const char *path, int flags, mode_t mode)
37 {
38         return __wrap_open(path, flags, mode);
39 }
40
41 static bool fail_fdopen;
42 FILE *__real_fdopen(int fd, const char *mode);
43 FILE *__wrap_fdopen(int fd, const char *mode)
44 {
45         return fail_fdopen ? NULL : __real_fdopen(fd, mode);
46 }
47 FILE *__wrap_fdopen64(int fd, const char *mode)
48 {
49         return __wrap_fdopen(fd, mode);
50 }
51
52 static bool fail_mkstemp;
53 int __real_mkstemp(char *template);
54 int __wrap_mkstemp(char *template)
55 {
56         return fail_mkstemp ? -1 : __real_mkstemp(template);
57 }
58 int __wrap_mkstemp64(char *template)
59 {
60         return __wrap_mkstemp(template);
61 }
62
63 static bool fail_fchmod;
64 int __real_fchmod(const char *path, mode_t mode);
65 int __wrap_fchmod(const char *path, mode_t mode)
66 {
67         return fail_fchmod ? -1 : __real_fchmod(path, mode);
68 }
69
70 static bool fail_rename;
71 int __real_rename(const char *oldpath, const char *newpath);
72 int __wrap_rename(const char *oldpath, const char *newpath)
73 {
74         return fail_rename ? -1 : __real_rename(oldpath, newpath);
75 }
76
77 static const char *const TMPFILE_PATH = "src/tests/logctl_testfile";
78
79 void _prepare_file(const char *const *lines, size_t lines_cnt)
80 {
81         __attribute__((cleanup(close_FILE))) FILE *const file_prep = fopen(TMPFILE_PATH, "w");
82         assert(file_prep);
83
84         for (size_t i = 0; i < lines_cnt; ++i) {
85                 assert(fputs(lines[i], file_prep) >= 0);
86                 assert(fputc('\n', file_prep) == '\n');
87         }
88 }
89 #define PREPARE_FILE(lines) _prepare_file(lines, NELEMS(lines))
90
91 void _compare_file(const char *const *lines, size_t lines_cnt)
92 {
93         __attribute__((cleanup(close_FILE))) FILE *const file_result = fopen(TMPFILE_PATH, "r");
94         assert(file_result);
95
96         char line[1024];
97         size_t lines_read = 0;
98         while (fgets(line, sizeof line, file_result)) {
99                 assert(lines_read < lines_cnt);
100
101                 const size_t expected_len = strlen(lines[lines_read]);
102                 assert(line[expected_len] == '\n');
103                 assert(!strncmp(line, lines[lines_read], expected_len));
104
105                 ++lines_read;
106         }
107 }
108 #define COMPARE_FILE(lines) _compare_file(lines, NELEMS(lines))
109
110 void test_copy_file_with_exceptions()
111 {
112         static const char *const lines_in[] = {
113                 "FOO=BAR",
114                 "FOOOO=BAZ",
115                 "ABC=XYZ",
116                 "ABCABC=QQQ",
117                 "ABC=ZYX",
118         };
119         static const char *const lines_out[] = {
120                 "ABCABC=QQQ",
121                 "ABC=YYY",
122                 "QWER=ASDF",
123         };
124         static const struct kv {
125                 char *key;
126                 char *value;
127         } kv_pairs[] = {
128                 {"FOO"  ,   NULL},
129                 {"ABC=" ,  "YYY"},
130                 {"QWER=", "ASDF"},
131         };
132
133         PREPARE_FILE(lines_in);
134
135         struct keys_values kv = {
136                 .keys   = calloc(NELEMS(kv_pairs), sizeof *kv.keys),
137                 .values = calloc(NELEMS(kv_pairs), sizeof *kv.values),
138                 .n      =        NELEMS(kv_pairs),
139         };
140         assert(kv.keys);
141         assert(kv.values);
142         for (size_t i = 0; i < kv.n; ++i) {
143                 kv.keys[i]   = kv_pairs[i].key;
144                 kv.values[i] = kv_pairs[i].value;
145         }
146
147         assert(EXIT_SUCCESS == copy_file_with_exceptions(TMPFILE_PATH, &kv));
148         COMPARE_FILE(lines_out);
149
150 #define TEST_FAIL(callname) \
151         fail_##callname = true; \
152         assert(EXIT_FAILURE == copy_file_with_exceptions(TMPFILE_PATH, &kv)); \
153         fail_##callname = false;
154
155         assert(EXIT_SUCCESS == copy_file_with_exceptions(TMPFILE_PATH, &kv));
156         TEST_FAIL(open);
157         TEST_FAIL(asprintf);
158         TEST_FAIL(mkstemp);
159         TEST_FAIL(fdopen);
160         TEST_FAIL(fchmod);
161         TEST_FAIL(calloc);
162         TEST_FAIL(rename);
163         assert(EXIT_SUCCESS == copy_file_with_exceptions(TMPFILE_PATH, &kv));
164
165 #undef TEST_FAIL
166
167         free(kv.keys);
168         free(kv.values);
169 }
170
171 void test_handle_clear()
172 {
173         static const char *const lines_in[] = {
174                 "limiter|x|y=BAR",
175                 "FOOOO=BAZ",
176                 "ABC=XYZ",
177                 "limiter|zzz|*=15",
178                 "ABC=ZYX",
179                 "limiter|qwe|*=22",
180                 "limiter|qwe|*=22",
181                 "QWEZ=ASDX",
182         };
183         static const char *const lines_out[] = {
184                 "FOOOO=BAZ",
185                 "ABC=XYZ",
186                 "ABC=ZYX",
187                 "QWEZ=ASDX",
188         };
189
190         PREPARE_FILE(lines_in);
191         assert(EXIT_SUCCESS == handle_clear(NULL, TMPFILE_PATH, NULL));
192         COMPARE_FILE(lines_out);
193 }
194
195 void test_handle_set()
196 {
197         static const char *const lines_in[] = {
198                 "QWER=QWER",
199                 "limiter|x|y=BAR",
200                 "FOOOO=BAZ",
201                 "limiter|z|t=FOO",
202                 "ABC=XYZ",
203         };
204         static const char *const lines_set[] = {
205                 "QWER=QWER",
206                 "FOOOO=BAZ",
207                 "limiter|z|t=FOO",
208                 "ABC=XYZ",
209                 "limiter|x|y=QUUX",
210         };
211         static const char *const lines_clear[] = {
212                 "QWER=QWER",
213                 "FOOOO=BAZ",
214                 "ABC=XYZ",
215                 "limiter|x|y=QUUX",
216         };
217
218         struct parsed_params pp;
219         PREPARE_FILE(lines_in);
220
221         pp.tag = "x";
222         pp.prio = 'y';
223         pp.value = "QUUX";
224         assert(EXIT_SUCCESS == handle_set(&pp, TMPFILE_PATH, NULL));
225         COMPARE_FILE(lines_set);
226
227         pp.tag = "z";
228         pp.prio = 't';
229         pp.value = NULL;
230         assert(EXIT_SUCCESS == handle_set(&pp, TMPFILE_PATH, NULL));
231         COMPARE_FILE(lines_clear);
232
233         assert(EXIT_SUCCESS == handle_set(&pp, TMPFILE_PATH, NULL));
234         fail_asprintf = true;
235         assert(EXIT_FAILURE == handle_set(&pp, TMPFILE_PATH, NULL));
236         fail_asprintf = false;
237         assert(EXIT_SUCCESS == handle_set(&pp, TMPFILE_PATH, NULL));
238 }
239
240 void test_handle_plog()
241 {
242         static const char *const lines_in[] = {
243                 "QWER=QWER",
244                 "enable_main=1",
245                 "FOOOO=BAZ",
246                 "enable_radio=0",
247                 "ABC=XYZ",
248         };
249         static const char *const lines_enabled[] = {
250                 "QWER=QWER",
251                 "FOOOO=BAZ",
252                 "enable_radio=0",
253                 "ABC=XYZ",
254                 "enable_main=1",
255                 "enable_system=1",
256         };
257         static const char *const lines_disabled[] = {
258                 "QWER=QWER",
259                 "FOOOO=BAZ",
260                 "ABC=XYZ",
261                 "enable_system=1",
262                 "enable_main=0",
263                 "enable_radio=0",
264         };
265         static const char *const lines_all[] = {
266                 "QWER=QWER",
267                 "FOOOO=BAZ",
268                 "ABC=XYZ",
269                 "enable_main=1",
270                 "enable_radio=1",
271                 "enable_system=1",
272                 "enable_apps=1",
273                 "enable_kmsg=1",
274                 "enable_syslog=1",
275         };
276
277         struct parsed_params pp;
278         PREPARE_FILE(lines_in);
279
280         pp.plog_enable = true;
281         pp.plog_buffers_bitset = (1 << LOG_ID_MAIN) | (1 << LOG_ID_SYSTEM);
282         assert(EXIT_SUCCESS == handle_plog(&pp, TMPFILE_PATH, NULL));
283         COMPARE_FILE(lines_enabled);
284
285         pp.plog_enable = false;
286         pp.plog_buffers_bitset = (1 << LOG_ID_MAIN) | (1 << LOG_ID_RADIO);
287         assert(EXIT_SUCCESS == handle_plog(&pp, TMPFILE_PATH, NULL));
288         COMPARE_FILE(lines_disabled);
289
290         pp.plog_enable = true;
291         pp.plog_buffers_bitset = 0;
292         assert(EXIT_SUCCESS == handle_plog(&pp, TMPFILE_PATH, NULL));
293         COMPARE_FILE(lines_all);
294
295         fail_calloc = true;
296         assert(EXIT_FAILURE == handle_plog(&pp, TMPFILE_PATH, NULL));
297         fail_calloc = false;
298
299         fail_asprintf = true;
300         assert(EXIT_FAILURE == handle_plog(&pp, TMPFILE_PATH, NULL));
301         fail_asprintf = false;
302
303         assert(EXIT_SUCCESS == handle_plog(&pp, TMPFILE_PATH, NULL));
304 }
305
306 struct expected_opts {
307         int exit_code;
308         bool retval;
309         struct parsed_params pp;
310 };
311
312 void check_option_set(size_t argc, const char **argv, const struct expected_opts *exp)
313 {
314         struct parsed_params pp = {0};
315         int exit_code = 42;
316         bool retval = parse_options((int) argc, argv, &pp, &exit_code);
317
318         optind = 0;
319         optopt = 0;
320         optarg = NULL;
321
322         assert(retval == exp->retval);
323         assert(retval || (exit_code == exp->exit_code));
324         assert(pp.action == exp->pp.action);
325         assert(pp.prio == exp->pp.prio);
326         assert(pp.plog_buffers_bitset == exp->pp.plog_buffers_bitset);
327         assert(pp.plog_enable == exp->pp.plog_enable);
328         assert(pp.value || !exp->pp.value);
329         assert(!pp.value || exp->pp.value);
330         assert(!pp.value || !strcmp(exp->pp.value, pp.value));
331         assert(pp.tag || !exp->pp.tag);
332         assert(!pp.tag || exp->pp.tag);
333         assert(!pp.tag || !strcmp(exp->pp.tag, pp.tag));
334 }
335
336 void test_parse_options()
337 {
338         /* These are primarily covered by integration tests but there's some value
339          * in running this at build time as well to detect any breakage ASAP. */
340
341         const char *none_args[]     = { "x"                                          , NULL};
342         const char *garbage_args[]  = { "x", "--cactus"                              , NULL};
343         const char *clear_args[]    = { "x", "-c", "-t", "tag_to_clear"              , NULL};
344         const char *clr_all_args[]  = { "x", "-c"                                    , NULL};
345         const char *set_args[]      = { "x", "-s", "15", "--priority", "e"           , NULL};
346         const char *get_args[]      = { "x", "-g", "-p", "*", "-t", "*"              , NULL};
347         const char *dump_args[]     = { "x", "-g"                                    , NULL};
348         const char *enable_args[]   = { "x", "--enable",  "-b", "main", "-b", "radio", NULL};
349         const char *disable_args[]  = { "x", "--disable", "-b", "main", "-b", "radio", NULL};
350         const char *help_args[]     = { "x", "--help"                                , NULL};
351
352         const char *prio_err_args[] = { "x", "--priority", "]"                       , NULL};
353         const char *buf_err_args[]  = { "x", "--buffer", "invalid"                   , NULL};
354         const char *plog_err_args[] = { "x", "-g", "--buffer", "main"                , NULL};
355         const char *set_err_args[]  = { "x", "-s", "tizen"                           , NULL};
356
357         static const struct expected_opts none_opts     = { EXIT_SUCCESS, false, { ACTION_NONE , "*"           , '\0', -1, NULL, false, 0 } };
358         static const struct expected_opts garbage_opts  = { EXIT_SUCCESS, false, { ACTION_NONE , "*"           , '\0', -1, NULL, false, 0 } };
359         static const struct expected_opts clear_opts    = { EXIT_SUCCESS, true , { ACTION_SET  , "tag_to_clear",  '*', -1, NULL, false, 0 } };
360         static const struct expected_opts clr_all_opts  = { EXIT_SUCCESS, true , { ACTION_CLEAR, "*"           , '\0', -1, NULL, false, 0 } };
361         static const struct expected_opts set_opts      = { EXIT_SUCCESS, true , { ACTION_SET  , "*"           ,  'E', -1, "15", false, 0 } };
362         static const struct expected_opts get_opts      = { EXIT_SUCCESS, true , { ACTION_GET  , "*"           ,  '*', -1, NULL, false, 0 } };
363         static const struct expected_opts dump_opts     = { EXIT_SUCCESS, true , { ACTION_DUMP , "*"           , '\0', -1, NULL, false, 0 } };
364         static const struct expected_opts enable_opts   = { EXIT_SUCCESS, true , { ACTION_PLOG , "*"           , '\0', -1, NULL, true , 1 << LOG_ID_MAIN | 1 << LOG_ID_RADIO } };
365         static const struct expected_opts disable_opts  = { EXIT_SUCCESS, true , { ACTION_PLOG , "*"           , '\0', -1, NULL, false, 1 << LOG_ID_MAIN | 1 << LOG_ID_RADIO } };
366         static const struct expected_opts help_opts     = { EXIT_SUCCESS, false, { ACTION_NONE , "*"           , '\0', -1, NULL, false, 0 } };
367
368         static const struct expected_opts prio_err_opts = { EXIT_FAILURE, false, { ACTION_NONE , "*"           ,  ']', -1, NULL, false, 0 } };
369         static const struct expected_opts buf_err_opts  = { EXIT_FAILURE, false, { ACTION_NONE , "*"           , '\0', -1, NULL, false, 0 } };
370         static const struct expected_opts plog_err_opts = { EXIT_FAILURE, false, { ACTION_GET  , "*"           , '\0', -1, NULL, false, 1 << LOG_ID_MAIN } };
371         static const struct expected_opts set_err_opts  = { EXIT_FAILURE, false, { ACTION_NONE , "*"           , '\0', -1, NULL, false, 0 } };
372
373 #define CHECK_OPTION_SET(TYPE) check_option_set(NELEMS(TYPE##_args) - 1, TYPE##_args, &(TYPE##_opts))
374         CHECK_OPTION_SET(none);
375         CHECK_OPTION_SET(garbage);
376         CHECK_OPTION_SET(clear);
377         CHECK_OPTION_SET(clr_all);
378         CHECK_OPTION_SET(set);
379         CHECK_OPTION_SET(get);
380         CHECK_OPTION_SET(dump);
381         CHECK_OPTION_SET(enable);
382         CHECK_OPTION_SET(disable);
383         CHECK_OPTION_SET(help);
384
385         CHECK_OPTION_SET(prio_err);
386         CHECK_OPTION_SET(buf_err);
387         CHECK_OPTION_SET(plog_err);
388         CHECK_OPTION_SET(set_err);
389 #undef CHECK_OPTION_SET
390 }
391
392 int main()
393 {
394         test_copy_file_with_exceptions();
395         test_parse_options();
396         test_handle_clear();
397         test_handle_set();
398         test_handle_plog();
399 }