fa8a350a8eaaad1b78ff15db9b795c13641cfaf0
[platform/core/system/dlog.git] / src / tests / libdlog_pipe.c
1 #include <assert.h>
2 #include <math.h>
3 #include <stdio.h>
4
5 #include <pthread.h>
6 #include <sys/socket.h>
7 #include <sys/un.h>
8
9 #include <dlog.h>
10 #include <logcommon.h>
11 #include <logconfig.h>
12
13 int (*write_to_log)(log_id_t, log_priority, const char *tag, const char *msg) = NULL;
14 void (*destroy_backend)() = NULL;
15
16 extern void __dlog_init_pipe(const struct log_config *conf);
17
18 int errno_to_set;
19
20 static bool critical_failure_detected = false;
21 void __wrap_syslog_critical_failure(const char *message, ...)
22 {
23         critical_failure_detected = true;
24 }
25
26 int __wrap_dup2(int oldfd, int newfd)
27 {
28         assert(oldfd == 1337);
29         assert(newfd == 1337);
30         return 123;
31 }
32
33 static int fail_write;
34 static size_t called_write;
35 ssize_t __wrap_write(int fd, const void *buf, size_t count)
36 {
37         ++called_write;
38         errno = errno_to_set;
39         const ssize_t retval = (fail_write & 1) ? -1 : (300 + called_write);
40         fail_write >>= 1;
41         return retval;
42 }
43
44 static int fail_connect;
45 static size_t called_connect;
46 int __wrap_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
47 {
48         ++called_connect;
49         errno = errno_to_set;
50         const int retval = (fail_connect & 1) ? -1 : (100 + called_connect);
51         fail_connect >>= 1;
52         return retval;
53 }
54
55 static int fail_recv_pipe;
56 static size_t called_recv_pipe;
57 static int expected_timeout = DEFAULT_WAIT_PIPE_MS;
58 int __wrap_recv_pipe(int sockfd, int timeout_ms)
59 {
60         assert(timeout_ms == expected_timeout);
61         expected_timeout /= 2;
62         if (expected_timeout < MIN_WAIT_PIPE_MS)
63                 expected_timeout = MIN_WAIT_PIPE_MS;
64
65         ++called_recv_pipe;
66         errno = errno_to_set;
67         const int retval = (fail_recv_pipe & 1) ? -1 : 1337;
68         fail_recv_pipe >>= 1;
69         return retval;
70 }
71
72 static bool fail_socket;
73 int __wrap_socket(int domain, int type, int protocol)
74 {
75         if (fail_socket) {
76                 errno = errno_to_set;
77                 return -1;
78         }
79
80         return 17;
81 }
82
83 static size_t closed;
84 int __wrap_close(int fd)
85 {
86         assert(fd == 1337 || fd == 17);
87         ++closed;
88         return 0;
89 }
90
91 int main()
92 {
93         struct log_config conf = {NULL, NULL};
94
95         __dlog_init_pipe(&conf);
96         assert(critical_failure_detected);
97         assert(!write_to_log);
98         critical_failure_detected = false;
99
100         assert(LOG_ID_MAIN == 0);
101         for (int i = 1; i < LOG_ID_MAX; ++i) {
102                 char key[MAX_CONF_KEY_LEN];
103                 assert(snprintf(key, sizeof key, "%s_write_sock", log_name_by_id((log_id_t)i)) > 0);
104                 log_config_set(&conf, key, "/foo");
105         }
106
107 #define MAXLEN (sizeof((struct sockaddr_un *)NULL)->sun_path) // static const size_t was not enough and there is no constexpr in C
108         char pipe_path[MAXLEN + 2] = { 'x', 'f', 'o', 'o', '\0',
109                  [5 ... MAXLEN] = 'x' };
110 #undef MAXLEN
111
112         log_config_set(&conf, "main_write_sock", pipe_path); // "xfoo"
113         __dlog_init_pipe(&conf);
114         assert(critical_failure_detected);
115         assert(!write_to_log);
116         assert(!destroy_backend);
117         critical_failure_detected = false;
118
119         pipe_path[0] = '/';
120         pipe_path[4] = 'x';
121         log_config_set(&conf, "main_write_sock", pipe_path); // "/fooxxxxxx..."
122         __dlog_init_pipe(&conf);
123         assert(critical_failure_detected);
124         assert(!write_to_log);
125         assert(!destroy_backend);
126         critical_failure_detected = false;
127
128         pipe_path[4] = '\0';
129         log_config_set(&conf, "main_write_sock", pipe_path); // "/foo"
130         __dlog_init_pipe(&conf);
131         assert(!critical_failure_detected);
132         assert(write_to_log);
133         assert(destroy_backend);
134
135 #define ACTUAL_PAYLOAD_SIZE (LOG_MAX_PAYLOAD_SIZE - 5) // 1 priority, 3 tag "xx\0", 1 null terminator
136         char payload[ACTUAL_PAYLOAD_SIZE + 1] = { [0 ... ACTUAL_PAYLOAD_SIZE] = 'x' };
137
138 #define F(B, P, L) assert(write_to_log(B, P, "xx", L) == DLOG_ERROR_INVALID_PARAMETER)
139         F(LOG_ID_MAIN   , DLOG_ERROR       , payload);
140         payload[ACTUAL_PAYLOAD_SIZE] = '\0';
141
142         F(LOG_ID_INVALID, DLOG_ERROR       , payload);
143         F(LOG_ID_MAX    , DLOG_ERROR       , payload);
144         F(LOG_ID_MAIN   , DLOG_UNKNOWN     , payload);
145         F(LOG_ID_MAIN   , (log_priority) -7, payload);
146         F(LOG_ID_MAIN   , (log_priority) 23, payload);
147         F(LOG_ID_MAIN   , DLOG_ERROR       ,    NULL);
148 #undef F
149
150 #define TC(FC, FW, FR, ERR, RES, TAG, CC, CW, CR) do { \
151         fail_connect   = FC; \
152         fail_write     = FW; \
153         fail_recv_pipe = FR; \
154         errno_to_set = ERR; \
155         assert(write_to_log(LOG_ID_MAIN, DLOG_ERROR, TAG, payload) == RES); \
156         assert(CC == called_connect); \
157         assert(CW == called_write); \
158         assert(CR == called_recv_pipe); \
159         called_connect = 0; \
160         called_write = 0; \
161         called_recv_pipe = 0; \
162 } while (0)
163
164         const size_t ITERATIONS_TO_REACH_MIN_TIMEOUT = 2 + (int) log2((float) DEFAULT_WAIT_PIPE_MS / MIN_WAIT_PIPE_MS);
165         for (size_t i = 0; i < ITERATIONS_TO_REACH_MIN_TIMEOUT; ++i)
166                 TC(0, 0, 1, 13, -1, "xx", 1, 1, 1);
167         assert(expected_timeout == MIN_WAIT_PIPE_MS);
168
169         fail_socket = true;
170         TC(0, 0, 0, 56, -1, "xx", 0, 0, 0);
171         fail_socket = false;
172
173         TC(1, 0, 0, 27, -1, "xx", 1, 0, 0);
174
175 #define WTC(FW, ERR, RES, CC, CW, CR) TC(0, FW, 0, ERR, RES, "xx", CC, CW, CR)
176         WTC(1 ,   EIO,  -1, 1, 1, 0);
177         WTC(0 ,   EIO, 302, 1, 2, 1);
178         // at this point the first connection succeeded
179         WTC(3 , EBADF,  -1, 1, 2, 0);
180         WTC(3 , EPIPE,  -1, 1, 2, 0);
181         WTC(1 ,   EIO,  -1, 0, 1, 0);
182         WTC(13, EBADF,  -1, 1, 4, 1);
183         WTC(5 , EPIPE,  -1, 1, 3, 1);
184         WTC(5 , EBADF, 304, 1, 4, 1);
185         WTC(1 , EBADF, 304, 1, 4, 1);
186         WTC(1 , EPIPE, 303, 1, 3, 1);
187 #undef WTC
188
189         // NULL tag is fine, apparently.
190         TC(0, 0, 0, 45, 301, NULL, 0, 1, 0);
191 #undef TC
192
193         closed = 0;
194         destroy_backend();
195         assert(closed == 1); // just MAIN, we'd never used the others
196 }