1// Copyright 2018 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <syslog/global.h>
6#include <unittest/unittest.h>
7
8#include <errno.h>
9#include <fcntl.h>
10#include <poll.h>
11#include <unistd.h>
12
13extern void fx_log_reset_global(void);
14
15bool ends_with(const char* str, const char* suffix) {
16  if (strlen(str) < strlen(suffix)) {
17    return false;
18  }
19  size_t l = strlen(suffix);
20  str += strlen(str) - l;
21  return strcmp(str, suffix) == 0;
22}
23
24bool test_log_init(void) {
25  BEGIN_TEST;
26  fx_log_reset_global();
27  EXPECT_EQ(ZX_OK, fx_log_init(), "");
28  END_TEST;
29}
30
31bool test_log_enabled_macro(void) {
32  BEGIN_TEST;
33  fx_log_reset_global();
34  EXPECT_EQ(ZX_OK, fx_log_init(), "");
35  if (FX_VLOG_IS_ENABLED(1)) {
36    EXPECT_TRUE(false, "control should not reach this line");
37  }
38  if (!FX_LOG_IS_ENABLED(INFO)) {
39    EXPECT_TRUE(false, "control should not reach this line");
40  }
41  if (!FX_LOG_IS_ENABLED(ERROR)) {
42    EXPECT_TRUE(false, "control should not reach this line");
43  }
44  fx_log_reset_global();
45  END_TEST;
46}
47
48static inline zx_status_t init_helper(int fd, const char** tags, int ntags) {
49  fx_logger_config_t config = {.min_severity = FX_LOG_INFO,
50                               .console_fd = fd,
51                               .log_service_channel = ZX_HANDLE_INVALID,
52                               .tags = tags,
53                               .num_tags = ntags};
54
55  return fx_log_init_with_config(&config);
56}
57
58bool test_log_simple_write(void) {
59  BEGIN_TEST;
60  fx_log_reset_global();
61  int pipefd[2];
62  EXPECT_NE(pipe2(pipefd, O_NONBLOCK), -1, "");
63  EXPECT_EQ(ZX_OK, init_helper(pipefd[0], NULL, 0), "");
64  FX_LOG(INFO, NULL, "test message");
65  char buf[256];
66  size_t n = read(pipefd[1], buf, sizeof(buf));
67  EXPECT_GT(n, 0u, "");
68  buf[n] = 0;
69  EXPECT_TRUE(ends_with(buf, "test message\n"), buf);
70  close(pipefd[1]);
71  fx_log_reset_global();
72  END_TEST;
73}
74
75bool test_log_write(void) {
76  BEGIN_TEST;
77  fx_log_reset_global();
78  int pipefd[2];
79  EXPECT_NE(pipe2(pipefd, O_NONBLOCK), -1, "");
80  EXPECT_EQ(ZX_OK, init_helper(pipefd[0], NULL, 0), "");
81  FX_LOGF(INFO, NULL, "%d, %s", 10, "just some number");
82  char buf[256];
83  size_t n = read(pipefd[1], buf, sizeof(buf));
84  EXPECT_GT(n, 0u, "");
85  buf[n] = 0;
86  EXPECT_TRUE(ends_with(buf, "INFO: 10, just some number\n"), buf);
87  close(pipefd[1]);
88  fx_log_reset_global();
89  END_TEST;
90}
91
92bool test_log_preprocessed_message(void) {
93  BEGIN_TEST;
94  fx_log_reset_global();
95  int pipefd[2];
96  EXPECT_NE(pipe2(pipefd, O_NONBLOCK), -1, "");
97  EXPECT_EQ(ZX_OK, init_helper(pipefd[0], NULL, 0), "");
98    FX_LOG(INFO, NULL, "%d, %s");
99  char buf[256];
100  size_t n = read(pipefd[1], buf, sizeof(buf));
101  EXPECT_GT(n, 0u, "");
102  buf[n] = 0;
103  EXPECT_TRUE(ends_with(buf, "INFO: %d, %s\n"), buf);
104  close(pipefd[1]);
105  fx_log_reset_global();
106  END_TEST;
107}
108
109bool test_log_severity(void) {
110  struct pollfd fd;
111  BEGIN_TEST;
112  fx_log_reset_global();
113  int pipefd[2];
114  EXPECT_NE(pipe2(pipefd, O_NONBLOCK), -1, "");
115  EXPECT_EQ(ZX_OK, init_helper(pipefd[0], NULL, 0), "");
116  FX_LOG_SET_SEVERITY(WARNING);
117  FX_LOGF(INFO, NULL, "%d, %s", 10, "just some number");
118  fd.fd = pipefd[1];
119  fd.events = POLLIN;
120  EXPECT_EQ(poll(&fd, 1, 1), 0, "");
121  close(pipefd[1]);
122  fx_log_reset_global();
123  END_TEST;
124}
125
126bool test_log_write_with_tag(void) {
127  BEGIN_TEST;
128  int pipefd[2];
129  fx_log_reset_global();
130  EXPECT_NE(pipe2(pipefd, O_NONBLOCK), -1, "");
131  EXPECT_EQ(ZX_OK, init_helper(pipefd[0], NULL, 0), "");
132  FX_LOGF(INFO, "tag", "%d, %s", 10, "just some string");
133  char buf[256];
134  size_t n = read(pipefd[1], buf, sizeof(buf));
135  EXPECT_GT(n, 0u, "");
136  buf[n] = 0;
137  EXPECT_TRUE(ends_with(buf, "[tag] INFO: 10, just some string\n"), buf);
138  close(pipefd[1]);
139  fx_log_reset_global();
140  END_TEST;
141}
142
143bool test_log_write_with_global_tag(void) {
144  BEGIN_TEST;
145  int pipefd[2];
146  fx_log_reset_global();
147  EXPECT_NE(pipe2(pipefd, O_NONBLOCK), -1, "");
148  EXPECT_EQ(ZX_OK, init_helper(pipefd[0], (const char* []){"gtag"}, 1), "");
149  FX_LOGF(INFO, "tag", "%d, %s", 10, "just some string");
150  char buf[256];
151  size_t n = read(pipefd[1], buf, sizeof(buf));
152  EXPECT_GT(n, 0u, "");
153  buf[n] = 0;
154  EXPECT_TRUE(ends_with(buf, "[gtag, tag] INFO: 10, just some string\n"), buf);
155  close(pipefd[1]);
156  fx_log_reset_global();
157  END_TEST;
158}
159
160bool test_log_write_with_multi_global_tag(void) {
161  BEGIN_TEST;
162  int pipefd[2];
163  fx_log_reset_global();
164  EXPECT_NE(pipe2(pipefd, O_NONBLOCK), -1, "");
165  EXPECT_EQ(ZX_OK, init_helper(pipefd[0], (const char* []){"gtag", "gtag2"}, 2),
166            "");
167  FX_LOGF(INFO, "tag", "%d, %s", 10, "just some string");
168  char buf[256];
169  size_t n = read(pipefd[1], buf, sizeof(buf));
170  EXPECT_GT(n, 0u, "");
171  buf[n] = 0;
172  EXPECT_TRUE(ends_with(buf, "[gtag, gtag2, tag] INFO: 10, just some string\n"),
173              buf);
174  close(pipefd[1]);
175  fx_log_reset_global();
176  END_TEST;
177}
178
179bool test_global_tag_limit(void) {
180  BEGIN_TEST;
181  fx_log_reset_global();
182  EXPECT_NE(ZX_OK, init_helper(-1, NULL, FX_LOG_MAX_TAGS + 1), "");
183  fx_log_reset_global();
184  END_TEST;
185}
186
187bool test_msg_length_limit(void) {
188  BEGIN_TEST;
189  fx_log_reset_global();
190  int pipefd[2];
191  EXPECT_NE(pipe2(pipefd, O_NONBLOCK), -1, "");
192  EXPECT_EQ(ZX_OK, init_helper(pipefd[0], NULL, 0), "");
193  char msg[2048] = {0};
194  char buf[2048] = {0};
195  memset(msg, 'a', sizeof(msg) - 1);
196  FX_LOGF(INFO, NULL, "%s", msg);
197  size_t n = read(pipefd[1], buf, sizeof(buf));
198  EXPECT_GT(n, 0u, "");
199  msg[n] = 0;
200  EXPECT_TRUE(ends_with(buf, "a...\n"), buf);
201
202  msg[0] = '%';
203  msg[1] = 's';
204  FX_LOG(INFO, NULL, msg);
205  n = read(pipefd[1], buf, sizeof(buf));
206  EXPECT_GT(n, 0u, "");
207  msg[n] = 0;
208  EXPECT_TRUE(ends_with(buf, "a...\n"), buf);
209  close(pipefd[1]);
210  fx_log_reset_global();
211  END_TEST;
212}
213
214bool test_vlog_simple_write(void) {
215  BEGIN_TEST;
216  fx_log_reset_global();
217  int pipefd[2];
218  EXPECT_NE(pipe2(pipefd, O_NONBLOCK), -1, "");
219  EXPECT_EQ(ZX_OK, init_helper(pipefd[0], NULL, 0), "");
220  FX_LOG_SET_VERBOSITY(1);
221  FX_VLOG(1, NULL, "test message");
222  char buf[256];
223  size_t n = read(pipefd[1], buf, sizeof(buf));
224  EXPECT_GT(n, 0u, "");
225  buf[n] = 0;
226  EXPECT_TRUE(ends_with(buf, "VLOG(1): test message\n"), buf);
227  close(pipefd[1]);
228  fx_log_reset_global();
229  END_TEST;
230}
231
232bool test_vlog_write(void) {
233  BEGIN_TEST;
234  fx_log_reset_global();
235  int pipefd[2];
236  EXPECT_NE(pipe2(pipefd, O_NONBLOCK), -1, "");
237  EXPECT_EQ(ZX_OK, init_helper(pipefd[0], NULL, 0), "");
238  FX_LOG_SET_VERBOSITY(1);
239  FX_VLOGF(1, NULL, "%d, %s", 10, "just some number");
240  char buf[256];
241  size_t n = read(pipefd[1], buf, sizeof(buf));
242  EXPECT_GT(n, 0u, "");
243  buf[n] = 0;
244  EXPECT_TRUE(ends_with(buf, "VLOG(1): 10, just some number\n"), buf);
245  close(pipefd[1]);
246  fx_log_reset_global();
247  END_TEST;
248}
249
250BEGIN_TEST_CASE(syslog_tests)
251RUN_TEST(test_log_init)
252RUN_TEST(test_log_simple_write)
253RUN_TEST(test_log_write)
254RUN_TEST(test_log_preprocessed_message)
255RUN_TEST(test_log_severity)
256RUN_TEST(test_log_write_with_tag)
257RUN_TEST(test_log_write_with_global_tag)
258RUN_TEST(test_log_write_with_multi_global_tag)
259RUN_TEST(test_log_enabled_macro)
260RUN_TEST(test_vlog_simple_write)
261RUN_TEST(test_vlog_write)
262END_TEST_CASE(syslog_tests)
263
264BEGIN_TEST_CASE(syslog_tests_edge_cases)
265RUN_TEST(test_global_tag_limit)
266RUN_TEST(test_msg_length_limit)
267END_TEST_CASE(syslog_tests_edge_cases)
268