Source file
src/log/syslog/syslog_test.go
1
2
3
4
5
6
7
8 package syslog
9
10 import (
11 "bufio"
12 "fmt"
13 "io"
14 "log"
15 "net"
16 "os"
17 "runtime"
18 "sync"
19 "testing"
20 "time"
21 )
22
23 func runPktSyslog(c net.PacketConn, done chan<- string) {
24 var buf [4096]byte
25 var rcvd string
26 ct := 0
27 for {
28 var n int
29 var err error
30
31 c.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
32 n, _, err = c.ReadFrom(buf[:])
33 rcvd += string(buf[:n])
34 if err != nil {
35 if oe, ok := err.(*net.OpError); ok {
36 if ct < 3 && oe.Temporary() {
37 ct++
38 continue
39 }
40 }
41 break
42 }
43 }
44 c.Close()
45 done <- rcvd
46 }
47
48 var crashy = false
49
50 func testableNetwork(network string) bool {
51 switch network {
52 case "unix", "unixgram":
53 switch runtime.GOOS {
54 case "ios", "android":
55 return false
56 }
57 }
58 return true
59 }
60
61 func runStreamSyslog(l net.Listener, done chan<- string, wg *sync.WaitGroup) {
62 for {
63 var c net.Conn
64 var err error
65 if c, err = l.Accept(); err != nil {
66 return
67 }
68 wg.Add(1)
69 go func(c net.Conn) {
70 defer wg.Done()
71 c.SetReadDeadline(time.Now().Add(5 * time.Second))
72 b := bufio.NewReader(c)
73 for ct := 1; !crashy || ct&7 != 0; ct++ {
74 s, err := b.ReadString('\n')
75 if err != nil {
76 break
77 }
78 done <- s
79 }
80 c.Close()
81 }(c)
82 }
83 }
84
85 func startServer(n, la string, done chan<- string) (addr string, sock io.Closer, wg *sync.WaitGroup) {
86 if n == "udp" || n == "tcp" {
87 la = "127.0.0.1:0"
88 } else {
89
90 if la == "" {
91
92 f, err := os.CreateTemp("", "syslogtest")
93 if err != nil {
94 log.Fatal("TempFile: ", err)
95 }
96 f.Close()
97 la = f.Name()
98 }
99 os.Remove(la)
100 }
101
102 wg = new(sync.WaitGroup)
103 if n == "udp" || n == "unixgram" {
104 l, e := net.ListenPacket(n, la)
105 if e != nil {
106 log.Fatalf("startServer failed: %v", e)
107 }
108 addr = l.LocalAddr().String()
109 sock = l
110 wg.Add(1)
111 go func() {
112 defer wg.Done()
113 runPktSyslog(l, done)
114 }()
115 } else {
116 l, e := net.Listen(n, la)
117 if e != nil {
118 log.Fatalf("startServer failed: %v", e)
119 }
120 addr = l.Addr().String()
121 sock = l
122 wg.Add(1)
123 go func() {
124 defer wg.Done()
125 runStreamSyslog(l, done, wg)
126 }()
127 }
128 return
129 }
130
131 func TestWithSimulated(t *testing.T) {
132 t.Parallel()
133 msg := "Test 123"
134 var transport []string
135 for _, n := range []string{"unix", "unixgram", "udp", "tcp"} {
136 if testableNetwork(n) {
137 transport = append(transport, n)
138 }
139 }
140
141 for _, tr := range transport {
142 done := make(chan string)
143 addr, sock, srvWG := startServer(tr, "", done)
144 defer srvWG.Wait()
145 defer sock.Close()
146 if tr == "unix" || tr == "unixgram" {
147 defer os.Remove(addr)
148 }
149 s, err := Dial(tr, addr, LOG_INFO|LOG_USER, "syslog_test")
150 if err != nil {
151 t.Fatalf("Dial() failed: %v", err)
152 }
153 err = s.Info(msg)
154 if err != nil {
155 t.Fatalf("log failed: %v", err)
156 }
157 check(t, msg, <-done, tr)
158 s.Close()
159 }
160 }
161
162 func TestFlap(t *testing.T) {
163 net := "unix"
164 if !testableNetwork(net) {
165 t.Skipf("skipping on %s/%s; 'unix' is not supported", runtime.GOOS, runtime.GOARCH)
166 }
167
168 done := make(chan string)
169 addr, sock, srvWG := startServer(net, "", done)
170 defer srvWG.Wait()
171 defer os.Remove(addr)
172 defer sock.Close()
173
174 s, err := Dial(net, addr, LOG_INFO|LOG_USER, "syslog_test")
175 if err != nil {
176 t.Fatalf("Dial() failed: %v", err)
177 }
178 msg := "Moo 2"
179 err = s.Info(msg)
180 if err != nil {
181 t.Fatalf("log failed: %v", err)
182 }
183 check(t, msg, <-done, net)
184
185
186 _, sock2, srvWG2 := startServer(net, addr, done)
187 defer srvWG2.Wait()
188 defer sock2.Close()
189
190
191 msg = "Moo 3"
192 err = s.Info(msg)
193 if err != nil {
194 t.Fatalf("log failed: %v", err)
195 }
196 check(t, msg, <-done, net)
197
198 s.Close()
199 }
200
201 func TestNew(t *testing.T) {
202 if LOG_LOCAL7 != 23<<3 {
203 t.Fatalf("LOG_LOCAL7 has wrong value")
204 }
205 if testing.Short() {
206
207 t.Skip("skipping syslog test during -short")
208 }
209
210 s, err := New(LOG_INFO|LOG_USER, "the_tag")
211 if err != nil {
212 if err.Error() == "Unix syslog delivery error" {
213 t.Skip("skipping: syslogd not running")
214 }
215 t.Fatalf("New() failed: %s", err)
216 }
217
218 s.Close()
219 }
220
221 func TestNewLogger(t *testing.T) {
222 if testing.Short() {
223 t.Skip("skipping syslog test during -short")
224 }
225 f, err := NewLogger(LOG_USER|LOG_INFO, 0)
226 if f == nil {
227 if err.Error() == "Unix syslog delivery error" {
228 t.Skip("skipping: syslogd not running")
229 }
230 t.Error(err)
231 }
232 }
233
234 func TestDial(t *testing.T) {
235 if testing.Short() {
236 t.Skip("skipping syslog test during -short")
237 }
238 f, err := Dial("", "", (LOG_LOCAL7|LOG_DEBUG)+1, "syslog_test")
239 if f != nil {
240 t.Fatalf("Should have trapped bad priority")
241 }
242 f, err = Dial("", "", -1, "syslog_test")
243 if f != nil {
244 t.Fatalf("Should have trapped bad priority")
245 }
246 l, err := Dial("", "", LOG_USER|LOG_ERR, "syslog_test")
247 if err != nil {
248 if err.Error() == "Unix syslog delivery error" {
249 t.Skip("skipping: syslogd not running")
250 }
251 t.Fatalf("Dial() failed: %s", err)
252 }
253 l.Close()
254 }
255
256 func check(t *testing.T, in, out, transport string) {
257 hostname, err := os.Hostname()
258 if err != nil {
259 t.Error("Error retrieving hostname")
260 return
261 }
262
263 if transport == "unixgram" || transport == "unix" {
264 var month, date, ts string
265 var pid int
266 tmpl := fmt.Sprintf("<%d>%%s %%s %%s syslog_test[%%d]: %s\n", LOG_USER+LOG_INFO, in)
267 n, err := fmt.Sscanf(out, tmpl, &month, &date, &ts, &pid)
268 if n != 4 || err != nil {
269 t.Errorf("Got %q, does not match template %q (%d %s)", out, tmpl, n, err)
270 }
271 return
272 }
273
274
275 var parsedHostname, timestamp string
276 var pid int
277 tmpl := fmt.Sprintf("<%d>%%s %%s syslog_test[%%d]: %s\n", LOG_USER+LOG_INFO, in)
278 n, err := fmt.Sscanf(out, tmpl, ×tamp, &parsedHostname, &pid)
279 if n != 3 || err != nil || hostname != parsedHostname {
280 t.Errorf("Got %q, does not match template %q (%d %s)", out, tmpl, n, err)
281 }
282 }
283
284 func TestWrite(t *testing.T) {
285 t.Parallel()
286 tests := []struct {
287 pri Priority
288 pre string
289 msg string
290 exp string
291 }{
292 {LOG_USER | LOG_ERR, "syslog_test", "", "%s %s syslog_test[%d]: \n"},
293 {LOG_USER | LOG_ERR, "syslog_test", "write test", "%s %s syslog_test[%d]: write test\n"},
294
295 {LOG_USER | LOG_ERR, "syslog_test", "write test 2\n", "%s %s syslog_test[%d]: write test 2\n"},
296 }
297
298 if hostname, err := os.Hostname(); err != nil {
299 t.Fatalf("Error retrieving hostname")
300 } else {
301 for _, test := range tests {
302 done := make(chan string)
303 addr, sock, srvWG := startServer("udp", "", done)
304 defer srvWG.Wait()
305 defer sock.Close()
306 l, err := Dial("udp", addr, test.pri, test.pre)
307 if err != nil {
308 t.Fatalf("syslog.Dial() failed: %v", err)
309 }
310 defer l.Close()
311 _, err = io.WriteString(l, test.msg)
312 if err != nil {
313 t.Fatalf("WriteString() failed: %v", err)
314 }
315 rcvd := <-done
316 test.exp = fmt.Sprintf("<%d>", test.pri) + test.exp
317 var parsedHostname, timestamp string
318 var pid int
319 if n, err := fmt.Sscanf(rcvd, test.exp, ×tamp, &parsedHostname, &pid); n != 3 || err != nil || hostname != parsedHostname {
320 t.Errorf("s.Info() = '%q', didn't match '%q' (%d %s)", rcvd, test.exp, n, err)
321 }
322 }
323 }
324 }
325
326 func TestConcurrentWrite(t *testing.T) {
327 addr, sock, srvWG := startServer("udp", "", make(chan string, 1))
328 defer srvWG.Wait()
329 defer sock.Close()
330 w, err := Dial("udp", addr, LOG_USER|LOG_ERR, "how's it going?")
331 if err != nil {
332 t.Fatalf("syslog.Dial() failed: %v", err)
333 }
334 var wg sync.WaitGroup
335 for i := 0; i < 10; i++ {
336 wg.Add(1)
337 go func() {
338 defer wg.Done()
339 err := w.Info("test")
340 if err != nil {
341 t.Errorf("Info() failed: %v", err)
342 return
343 }
344 }()
345 }
346 wg.Wait()
347 }
348
349 func TestConcurrentReconnect(t *testing.T) {
350 crashy = true
351 defer func() { crashy = false }()
352
353 const N = 10
354 const M = 100
355 net := "unix"
356 if !testableNetwork(net) {
357 net = "tcp"
358 if !testableNetwork(net) {
359 t.Skipf("skipping on %s/%s; neither 'unix' or 'tcp' is supported", runtime.GOOS, runtime.GOARCH)
360 }
361 }
362 done := make(chan string, N*M)
363 addr, sock, srvWG := startServer(net, "", done)
364 if net == "unix" {
365 defer os.Remove(addr)
366 }
367
368
369 count := make(chan int, 1)
370 go func() {
371 ct := 0
372 for range done {
373 ct++
374
375
376
377 if ct > N*M/2 {
378 break
379 }
380 }
381 count <- ct
382 }()
383
384 var wg sync.WaitGroup
385 wg.Add(N)
386 for i := 0; i < N; i++ {
387 go func() {
388 defer wg.Done()
389 w, err := Dial(net, addr, LOG_USER|LOG_ERR, "tag")
390 if err != nil {
391 t.Errorf("syslog.Dial() failed: %v", err)
392 return
393 }
394 defer w.Close()
395 for i := 0; i < M; i++ {
396 err := w.Info("test")
397 if err != nil {
398 t.Errorf("Info() failed: %v", err)
399 return
400 }
401 }
402 }()
403 }
404 wg.Wait()
405 sock.Close()
406 srvWG.Wait()
407 close(done)
408
409 select {
410 case <-count:
411 case <-time.After(100 * time.Millisecond):
412 t.Error("timeout in concurrent reconnect")
413 }
414 }
415
View as plain text