2 * Copyright (c) 2020 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the License);
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
23 #include <logcommon.h>
24 #include <sys/ioctl.h>
25 #include <linux/logger.h>
27 /* This is supposed to check a 1000ms timeout, so ideally this would be just a
28 * little bit over 1000 (to account for non-timeout overhead). But the kernel
29 * does not actually guarantee that we will wake up at once, the timeout is just
30 * a minimum. On busy and/or emulated systems the total wait can stretch for a
31 * fairly long time. Here the value is an arbitrary compromise that happens to
32 * pass the test on my tortured system without being too absurd. */
33 #define ONE_SECOND_LENIENCE_MS 1300
60 const char *mode_names[] = {
62 [MODE_TIMER] = "timer",
63 [MODE_CONTINUOUS] = "continuous",
64 [MODE_MONITOR] = "monitor",
65 [MODE_PRIORITY] = "priority",
66 [MODE_PRIORITY_EXACT] = "priority_exact",
67 [MODE_LIMIT] = "limit",
68 [MODE_PID_CORRECT] = "pid_correct",
69 [MODE_PID_WRONG] = "pid_wrong",
70 [MODE_TID_CORRECT] = "tid_correct",
71 [MODE_TID_WRONG] = "tid_wrong",
72 [MODE_TAG_CORRECT] = "tag_correct",
73 [MODE_TAG_WRONG] = "tag_wrong",
74 [MODE_PREFIX_CORRECT] = "prefix_correct",
75 [MODE_PREFIX_WRONG] = "prefix_wrong",
76 [MODE_SORTING] = "sorting",
77 [MODE_TRAITS] = "traits",
78 [MODE_CLEAR] = "clear",
79 [MODE_ALIAS] = "alias",
80 [MODE_NEGATIVE] = "negative",
84 const char *mode_desc[] = {
85 [MODE_DUMP] = "test getting logs in the dump mode",
86 [MODE_TIMER] = "same, but waiting on each log to simulate work",
87 [MODE_CONTINUOUS] = "test getting logs in the continuous mode",
88 [MODE_MONITOR] = "test that monitor mode skips all the old logs",
89 [MODE_PRIORITY] = "only warning and above, we should get only error logs",
90 [MODE_PRIORITY_EXACT] = "only warning, we should get no logs",
91 [MODE_LIMIT] = "limit to 100 logs without filtering, we should get exactly 50 error and exactly 50 info logs",
92 [MODE_PID_CORRECT] = "filter PID to the correct one, we should get same results as in the normal test mode",
93 [MODE_PID_WRONG] = "filter PID to the wrong one, we should get no logs",
94 [MODE_TID_CORRECT] = "filter TID to the correct one, we should get same results as in the normal test mode",
95 [MODE_TID_WRONG] = "filter TID to the wrong one, we should get no logs",
96 [MODE_TAG_CORRECT] = "filter the tag to the correct one, we should get same results as in the normal testmode",
97 [MODE_TAG_WRONG] = "filter the tag to a wrong one, we should get no logs",
98 [MODE_PREFIX_CORRECT] = "filter the tag to the correct one via prefix, we should get same results as in the normal test mode",
99 [MODE_PREFIX_WRONG] = "filter the tag to a wrong one via prefix, we should get same results as in the normal test mode",
101 [MODE_SORTING] = "test timestamp sorting -- in this case, the PID is ignored",
102 [MODE_TRAITS] = "test buffer traits functionality -- in this case, the PID is ignored",
103 [MODE_CLEAR] = "test clearing functionality -- in this case, the PID is ignored",
104 [MODE_ALIAS] = "test buffer aliasing -- in this case, the PID is ignored",
105 [MODE_NEGATIVE] = "test whether libdlogutil errors out correctly",
106 [MODE_MISC] = "run some miscellaneous calls",
109 void print_usage_and_die(const char *name)
111 fprintf(stderr, "Usage: %s TEST PID TYPE\n"
112 "where PID is the process id of the logging process (or 0),\n"
113 "TYPE is \"pipe\" or \"logger\" depending on the backend used,\n"
114 "and TEST chooses a test and is one of the following:\n", name);
116 for (size_t i = 0; i < MODE_INVALID; ++i)
117 fprintf(stderr, " - %s: %s\n", mode_names[i], mode_desc[i]);
122 enum test_mode choose_mode(const char *name)
124 for (size_t i = 0; i < MODE_INVALID; ++i)
125 if (!strcmp(name, mode_names[i]))
131 void assert_suffix(const char *string, const char *suffix)
133 int add = (int)strlen(string) - strlen(suffix);
134 assert(add >= 0 && !strcmp(string + add, suffix));
137 /* The amount of logs is deterministic and based on buffer size,
138 * log header size, the amount of logs sent and their contents. */
139 #define PIPE_ERRORS 4681
140 #define PIPE_INFOS 4681
142 void get_logs_main(enum test_mode mode, backend_t backend, pid_t pid)
144 bool continuous = mode == MODE_CONTINUOUS;
145 bool monitor = mode == MODE_MONITOR;
152 dlogutil_config_s *c = dlogutil_config_create();
155 dlogutil_config_buffer_add(c, LOG_ID_MAIN);
159 assert(dlogutil_config_filter_filterspec(c, "*:W") == 0);
161 case MODE_PRIORITY_EXACT:
162 assert(dlogutil_config_filter_filterspec(c, "*:=W") == 0);
164 case MODE_PID_CORRECT:
165 assert(dlogutil_config_filter_pid(c, pid) == 0);
168 assert(dlogutil_config_filter_pid(c, pid ^ 1) == 0);
170 case MODE_TID_CORRECT:
171 assert(dlogutil_config_filter_tid(c, pid) == 0);
174 assert(dlogutil_config_filter_tid(c, pid ^ 1) == 0);
176 case MODE_TAG_CORRECT:
177 dlogutil_config_filter_filterspec(c, "SRPOL_LOGGER");
180 dlogutil_config_filter_filterspec(c, "SRPOL_WRONG");
182 case MODE_PREFIX_CORRECT:
183 dlogutil_config_filter_filterspec(c, "SRPOL*");
185 case MODE_PREFIX_WRONG:
186 dlogutil_config_filter_filterspec(c, "WRONG*");
192 dlogutil_state_s *s = NULL;
194 r = dlogutil_config_mode_set_continuous(c);
196 r = dlogutil_config_mode_set_monitor(c);
198 r = dlogutil_config_mode_set_dump(c, mode == MODE_LIMIT ? 100 : DLOGUTIL_MAX_DUMP_SIZE);
201 assert(dlogutil_config_connect(c, &s) == 0);
204 struct timespec a, b;
209 clock_gettime(CLOCK_MONOTONIC, &a);
210 r = dlogutil_get_log(s, continuous || monitor ? 1000 : -1, &e);
211 clock_gettime(CLOCK_MONOTONIC, &b);
212 unsigned dt = (b.tv_sec - a.tv_sec) * 1000 + (b.tv_nsec - a.tv_nsec) / 1000000;
216 assert(dt < ONE_SECOND_LENIENCE_MS);
219 r = dlogutil_entry_get_priority(e, &prio);
222 const char *tag, *msg;
223 r = dlogutil_entry_get_tag(e, &tag);
225 r = dlogutil_entry_get_message(e, &msg);
228 // !pid also means we are fine looking at random logs
229 assert(!pid || !strcmp(tag, "SRPOL_LOGGER"));
232 r = dlogutil_entry_get_pid(e, &apid);
234 r = dlogutil_entry_get_tid(e, &atid);
237 assert(!pid || pid == apid);
238 assert(!pid || pid == atid);
243 assert_suffix(msg, "test data, level: error");
247 assert_suffix(msg, "test data, level: info");
253 if (mode == MODE_TIMER)
254 nanosleep(&(struct timespec) {
256 .tv_nsec = rand() % (1 << 18),
261 if (continuous || monitor) {
262 assert(r == TIZEN_ERROR_TIMED_OUT);
265 assert(r == TIZEN_ERROR_NO_DATA);
266 assert(dt < ONE_SECOND_LENIENCE_MS);
272 dlogutil_state_destroy(s);
273 dlogutil_config_destroy(c);
278 case MODE_CONTINUOUS:
279 case MODE_PID_CORRECT:
280 case MODE_TID_CORRECT:
281 case MODE_TAG_CORRECT:
282 case MODE_PREFIX_CORRECT:
283 if (backend == BACKEND_PIPE) {
284 assert(error_count == PIPE_ERRORS);
285 assert(info_count == PIPE_INFOS);
287 assert(abs(error_count - info_count) <= 1);
291 if (backend == BACKEND_PIPE)
292 assert(error_count == PIPE_ERRORS);
294 assert(error_count > 0);
295 assert(info_count == 0);
298 case MODE_PRIORITY_EXACT:
302 case MODE_PREFIX_WRONG:
303 assert(error_count == 0);
304 assert(info_count == 0);
307 assert(error_count == 50);
308 assert(info_count == 50);
315 unsigned int MB(unsigned int x)
317 return 1024 * 1024 * x;
320 void traits_main(backend_t backend)
322 assert(backend != BACKEND_ZERO_COPY);
324 dlogutil_config_s *config = dlogutil_config_create();
327 assert(dlogutil_config_buffer_add(config, LOG_ID_MAIN) == 0);
328 assert(dlogutil_config_buffer_add(config, LOG_ID_KMSG) == 0);
330 dlogutil_state_s *state;
331 assert(dlogutil_config_connect(config, &state) == 0);
332 dlogutil_config_destroy(config);
335 assert(dlogutil_buffer_get_name(LOG_ID_MAIN, &name) == 0);
336 assert(!strcmp(name, "main"));
338 assert(dlogutil_buffer_get_name(LOG_ID_KMSG, &name) == 0);
339 assert(!strcmp(name, "kmsg"));
341 unsigned int capacity, usage;
342 assert(dlogutil_buffer_get_capacity(state, LOG_ID_MAIN, &capacity) == 0);
343 assert(dlogutil_buffer_get_usage(state, LOG_ID_MAIN, &usage) == 0);
344 if (backend == BACKEND_PIPE)
345 assert(capacity == MB(1));
347 int fd = open("/dev/log_main", O_RDONLY);
348 int real_capacity = ioctl(fd, LOGGER_GET_LOG_BUF_SIZE);
350 assert(capacity == real_capacity);
354 assert(dlogutil_buffer_get_capacity(state, LOG_ID_KMSG, &capacity) == 0);
355 assert(dlogutil_buffer_get_usage(state, LOG_ID_KMSG, &usage) == 0);
356 assert(capacity == MB(1));
358 dlogutil_sorting_order_e type;
359 assert(dlogutil_buffer_get_default_ts_type(LOG_ID_MAIN, &type) == 0);
360 assert(type == (backend == BACKEND_PIPE ? DLOGUTIL_SORT_RECV_MONO : DLOGUTIL_SORT_SENT_REAL));
363 assert(dlogutil_buffer_check_ts_type_available(LOG_ID_MAIN, DLOGUTIL_SORT_SENT_MONO, &available) == 0);
364 assert(available == (backend == BACKEND_PIPE));
366 assert(dlogutil_buffer_check_ts_type_available(LOG_ID_MAIN, DLOGUTIL_SORT_SENT_REAL, &available) == 0);
369 assert(dlogutil_buffer_check_ts_type_available(LOG_ID_MAIN, DLOGUTIL_SORT_RECV_MONO, &available) == 0);
370 assert(available == (backend == BACKEND_PIPE));
372 assert(dlogutil_buffer_check_ts_type_available(LOG_ID_MAIN, DLOGUTIL_SORT_RECV_REAL, &available) == 0);
373 assert(available == (backend == BACKEND_PIPE));
375 assert(dlogutil_buffer_check_ts_type_available(LOG_ID_KMSG, DLOGUTIL_SORT_SENT_MONO, &available) == 0);
378 assert(dlogutil_buffer_check_ts_type_available(LOG_ID_KMSG, DLOGUTIL_SORT_SENT_REAL, &available) == 0);
381 assert(dlogutil_buffer_check_ts_type_available(LOG_ID_KMSG, DLOGUTIL_SORT_RECV_MONO, &available) == 0);
384 assert(dlogutil_buffer_check_ts_type_available(LOG_ID_KMSG, DLOGUTIL_SORT_RECV_REAL, &available) == 0);
387 dlogutil_state_destroy(state);
390 void clear_main(void)
392 dlogutil_config_s *c = dlogutil_config_create();
394 assert(dlogutil_config_buffer_add(c, LOG_ID_MAIN) == 0);
398 assert(dlogutil_config_connect(c, &s) == 0);
399 assert(dlogutil_buffer_clear(s, LOG_ID_MAIN) == 0);
400 dlogutil_state_destroy(s);
402 // avoid a race condition; let the clear take place
403 nanosleep(&(struct timespec) {
408 assert(dlogutil_config_mode_set_dump(c, DLOGUTIL_MAX_DUMP_SIZE) == 0);
409 assert(dlogutil_config_connect(c, &s) == 0);
411 assert(dlogutil_get_log(s, 1000, &e) == TIZEN_ERROR_NO_DATA);
412 dlogutil_state_destroy(s);
414 dlogutil_config_destroy(c);
417 bool sorting_check(dlogutil_sorting_order_e o)
419 dlogutil_config_s *config = dlogutil_config_create();
422 assert(dlogutil_config_buffer_add(config, LOG_ID_MAIN) == 0);
423 assert(dlogutil_config_sorting_enable(config) == 0);
424 assert(dlogutil_config_order_set(config, o) == 0);
425 assert(dlogutil_config_mode_set_dump(config, DLOGUTIL_MAX_DUMP_SIZE) == 0);
428 assert(dlogutil_config_connect(config, &s) == 0);
430 struct timespec t = {
438 int r = dlogutil_get_log(s, -1, &e);
439 if (r == TIZEN_ERROR_NO_DATA)
443 struct timespec t_new;
444 r = dlogutil_entry_get_timestamp(e, o, &t_new);
445 if (r == TIZEN_ERROR_NO_DATA) {
450 assert(t.tv_sec <= t_new.tv_sec);
451 assert(t.tv_sec < t_new.tv_sec || t.tv_nsec <= t_new.tv_nsec);
457 dlogutil_state_destroy(s);
458 dlogutil_config_destroy(config);
462 void sorting_main(int left)
464 #define ONE(ts) left -= sorting_check(ts) ? 1 : 0
466 ONE(DLOGUTIL_SORT_RECV_MONO);
467 ONE(DLOGUTIL_SORT_RECV_REAL);
468 ONE(DLOGUTIL_SORT_SENT_MONO);
469 ONE(DLOGUTIL_SORT_SENT_REAL);
476 void alias_main(backend_t backend)
478 assert(backend != BACKEND_ZERO_COPY);
480 dlogutil_config_s *config = dlogutil_config_create();
482 assert(dlogutil_config_buffer_add(config, LOG_ID_MAIN) == 0);
483 assert(dlogutil_config_buffer_add(config, LOG_ID_APPS) == 0);
484 assert(dlogutil_config_buffer_add(config, LOG_ID_RADIO) == 0);
485 assert(dlogutil_config_buffer_add(config, LOG_ID_SYSTEM) == 0);
486 assert(dlogutil_config_buffer_add(config, LOG_ID_KMSG) == 0);
488 dlogutil_state_s *state;
489 assert(dlogutil_config_connect(config, &state) == 0);
490 dlogutil_config_destroy(config);
493 assert(dlogutil_buffer_get_alias(state, LOG_ID_MAIN, &id) == 0);
494 assert(id == LOG_ID_MAIN);
495 assert(dlogutil_buffer_get_alias(state, LOG_ID_APPS, &id) == 0);
496 assert(id == (backend == BACKEND_PIPE ? LOG_ID_APPS : LOG_ID_INVALID));
497 assert(dlogutil_buffer_get_alias(state, LOG_ID_RADIO, &id) == 0);
498 assert(id == (backend == BACKEND_PIPE ? LOG_ID_RADIO : LOG_ID_RADIO));
499 assert(dlogutil_buffer_get_alias(state, LOG_ID_SYSTEM, &id) == 0);
500 assert(id == (backend == BACKEND_PIPE ? LOG_ID_SYSTEM : LOG_ID_MAIN));
501 assert(dlogutil_buffer_get_alias(state, LOG_ID_KMSG, &id) == 0);
502 assert(id == LOG_ID_KMSG);
504 dlogutil_state_destroy(state);
507 void negative_main(void)
509 dlogutil_config_s *config = dlogutil_config_create();
511 assert(dlogutil_config_buffer_add(config, LOG_ID_MAIN) == 0);
513 dlogutil_state_s *state;
514 assert(dlogutil_config_connect(config, &state) == 0);
515 dlogutil_config_destroy(config);
517 void *bad_ptr = (void *)0xFA1l;
519 // Invalid single buffer
520 const log_id_t invalid_ids[] =
528 for (size_t i = 0; i < NELEMS(invalid_ids); ++i) {
529 const log_id_t id = invalid_ids[i];
530 assert(dlogutil_buffer_clear(state, id) ==
531 TIZEN_ERROR_INVALID_PARAMETER);
532 assert(dlogutil_buffer_get_capacity(state, id, bad_ptr) ==
533 TIZEN_ERROR_INVALID_PARAMETER);
534 assert(dlogutil_buffer_get_usage(state, id, bad_ptr) ==
535 TIZEN_ERROR_INVALID_PARAMETER);
538 // Retrieval of data into NULL
539 assert(dlogutil_buffer_get_capacity(state, LOG_ID_MAIN, NULL) ==
540 TIZEN_ERROR_INVALID_PARAMETER);
541 assert(dlogutil_buffer_get_usage(state, LOG_ID_MAIN, NULL) ==
542 TIZEN_ERROR_INVALID_PARAMETER);
544 dlogutil_state_destroy(state);
547 void misc_calls(void)
549 dlogutil_config_s *config = dlogutil_config_create();
551 dlogutil_config_sorting_disable(config);
552 dlogutil_config_sorting_enable(config);
553 dlogutil_config_buffer_add(config, LOG_ID_MAIN);
554 dlogutil_config_buffer_add(config, LOG_ID_APPS);
556 dlogutil_state_s *state;
557 assert(dlogutil_config_connect(config, &state) == 0);
558 dlogutil_config_destroy(config);
561 int r = dlogutil_get_log(state, -1, &e);
564 dlogutil_entry_get_tid(e, &x);
565 dlogutil_entry_get_pid(e, &x);
567 dlogutil_entry_get_priority(e, &p);
570 dlogutil_entry_get_tid(NULL, NULL);
571 dlogutil_entry_get_pid(NULL, NULL);
572 dlogutil_entry_get_priority(NULL, NULL);
575 dlogutil_state_destroy(state);
578 int main(int argc, char **argv)
581 print_usage_and_die(argv[0]);
582 enum test_mode t = choose_mode(argv[1]);
583 if (t == MODE_INVALID)
584 print_usage_and_die(argv[0]);
586 pid_t pid = atoi(argv[2]);
588 backend_t backend = BACKEND_ANDROID_LOGGER;
589 if (!strcmp(argv[3], "pipe"))
590 backend = BACKEND_PIPE;
591 else if (!strcmp(argv[3], "zero-copy"))
592 backend = BACKEND_ZERO_COPY;
593 else if (strcmp(argv[3], "logger"))
594 print_usage_and_die(argv[0]);
599 case MODE_CONTINUOUS:
602 case MODE_PRIORITY_EXACT:
604 case MODE_PID_CORRECT:
606 case MODE_TID_CORRECT:
608 case MODE_TAG_CORRECT:
610 case MODE_PREFIX_CORRECT:
611 case MODE_PREFIX_WRONG:
612 get_logs_main(t, backend, pid);
615 sorting_main(backend == BACKEND_PIPE ? 4 : 1);
618 traits_main(backend);