1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // +build !windows,!nacl,!plan9 6 7 package syslog 8 9 import ( 10 "bufio" 11 "fmt" 12 "io" 13 "io/ioutil" 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 runStreamSyslog(l net.Listener, done chan<- string, wg *sync.WaitGroup) { 51 for { 52 var c net.Conn 53 var err error 54 if c, err = l.Accept(); err != nil { 55 return 56 } 57 wg.Add(1) 58 go func(c net.Conn) { 59 defer wg.Done() 60 c.SetReadDeadline(time.Now().Add(5 * time.Second)) 61 b := bufio.NewReader(c) 62 for ct := 1; !crashy || ct&7 != 0; ct++ { 63 s, err := b.ReadString('\n') 64 if err != nil { 65 break 66 } 67 done <- s 68 } 69 c.Close() 70 }(c) 71 } 72 } 73 74 func startServer(n, la string, done chan<- string) (addr string, sock io.Closer, wg *sync.WaitGroup) { 75 if n == "udp" || n == "tcp" { 76 la = "127.0.0.1:0" 77 } else { 78 // unix and unixgram: choose an address if none given 79 if la == "" { 80 // use ioutil.TempFile to get a name that is unique 81 f, err := ioutil.TempFile("", "syslogtest") 82 if err != nil { 83 log.Fatal("TempFile: ", err) 84 } 85 f.Close() 86 la = f.Name() 87 } 88 os.Remove(la) 89 } 90 91 wg = new(sync.WaitGroup) 92 if n == "udp" || n == "unixgram" { 93 l, e := net.ListenPacket(n, la) 94 if e != nil { 95 log.Fatalf("startServer failed: %v", e) 96 } 97 addr = l.LocalAddr().String() 98 sock = l 99 wg.Add(1) 100 go func() { 101 defer wg.Done() 102 runPktSyslog(l, done) 103 }() 104 } else { 105 l, e := net.Listen(n, la) 106 if e != nil { 107 log.Fatalf("startServer failed: %v", e) 108 } 109 addr = l.Addr().String() 110 sock = l 111 wg.Add(1) 112 go func() { 113 defer wg.Done() 114 runStreamSyslog(l, done, wg) 115 }() 116 } 117 return 118 } 119 120 func TestWithSimulated(t *testing.T) { 121 msg := "Test 123" 122 transport := []string{"unix", "unixgram", "udp", "tcp"} 123 124 if runtime.GOOS == "darwin" { 125 switch runtime.GOARCH { 126 case "arm", "arm64": 127 transport = []string{"udp", "tcp"} 128 } 129 } 130 131 for _, tr := range transport { 132 done := make(chan string) 133 addr, sock, srvWG := startServer(tr, "", done) 134 defer srvWG.Wait() 135 defer sock.Close() 136 if tr == "unix" || tr == "unixgram" { 137 defer os.Remove(addr) 138 } 139 s, err := Dial(tr, addr, LOG_INFO|LOG_USER, "syslog_test") 140 if err != nil { 141 t.Fatalf("Dial() failed: %v", err) 142 } 143 err = s.Info(msg) 144 if err != nil { 145 t.Fatalf("log failed: %v", err) 146 } 147 check(t, msg, <-done) 148 s.Close() 149 } 150 } 151 152 func TestFlap(t *testing.T) { 153 if runtime.GOOS == "darwin" { 154 switch runtime.GOARCH { 155 case "arm", "arm64": 156 t.Skipf("skipping on %s/%s", runtime.GOOS, runtime.GOARCH) 157 } 158 } 159 160 net := "unix" 161 done := make(chan string) 162 addr, sock, srvWG := startServer(net, "", done) 163 defer srvWG.Wait() 164 defer os.Remove(addr) 165 defer sock.Close() 166 167 s, err := Dial(net, addr, LOG_INFO|LOG_USER, "syslog_test") 168 if err != nil { 169 t.Fatalf("Dial() failed: %v", err) 170 } 171 msg := "Moo 2" 172 err = s.Info(msg) 173 if err != nil { 174 t.Fatalf("log failed: %v", err) 175 } 176 check(t, msg, <-done) 177 178 // restart the server 179 _, sock2, srvWG2 := startServer(net, addr, done) 180 defer srvWG2.Wait() 181 defer sock2.Close() 182 183 // and try retransmitting 184 msg = "Moo 3" 185 err = s.Info(msg) 186 if err != nil { 187 t.Fatalf("log failed: %v", err) 188 } 189 check(t, msg, <-done) 190 191 s.Close() 192 } 193 194 func TestNew(t *testing.T) { 195 if LOG_LOCAL7 != 23<<3 { 196 t.Fatalf("LOG_LOCAL7 has wrong value") 197 } 198 if testing.Short() { 199 // Depends on syslog daemon running, and sometimes it's not. 200 t.Skip("skipping syslog test during -short") 201 } 202 203 s, err := New(LOG_INFO|LOG_USER, "the_tag") 204 if err != nil { 205 t.Fatalf("New() failed: %s", err) 206 } 207 // Don't send any messages. 208 s.Close() 209 } 210 211 func TestNewLogger(t *testing.T) { 212 if testing.Short() { 213 t.Skip("skipping syslog test during -short") 214 } 215 f, err := NewLogger(LOG_USER|LOG_INFO, 0) 216 if f == nil { 217 t.Error(err) 218 } 219 } 220 221 func TestDial(t *testing.T) { 222 if testing.Short() { 223 t.Skip("skipping syslog test during -short") 224 } 225 f, err := Dial("", "", (LOG_LOCAL7|LOG_DEBUG)+1, "syslog_test") 226 if f != nil { 227 t.Fatalf("Should have trapped bad priority") 228 } 229 f, err = Dial("", "", -1, "syslog_test") 230 if f != nil { 231 t.Fatalf("Should have trapped bad priority") 232 } 233 l, err := Dial("", "", LOG_USER|LOG_ERR, "syslog_test") 234 if err != nil { 235 t.Fatalf("Dial() failed: %s", err) 236 } 237 l.Close() 238 } 239 240 func check(t *testing.T, in, out string) { 241 tmpl := fmt.Sprintf("<%d>%%s %%s syslog_test[%%d]: %s\n", LOG_USER+LOG_INFO, in) 242 if hostname, err := os.Hostname(); err != nil { 243 t.Error("Error retrieving hostname") 244 } else { 245 var parsedHostname, timestamp string 246 var pid int 247 if n, err := fmt.Sscanf(out, tmpl, ×tamp, &parsedHostname, &pid); n != 3 || err != nil || hostname != parsedHostname { 248 t.Errorf("Got %q, does not match template %q (%d %s)", out, tmpl, n, err) 249 } 250 } 251 } 252 253 func TestWrite(t *testing.T) { 254 tests := []struct { 255 pri Priority 256 pre string 257 msg string 258 exp string 259 }{ 260 {LOG_USER | LOG_ERR, "syslog_test", "", "%s %s syslog_test[%d]: \n"}, 261 {LOG_USER | LOG_ERR, "syslog_test", "write test", "%s %s syslog_test[%d]: write test\n"}, 262 // Write should not add \n if there already is one 263 {LOG_USER | LOG_ERR, "syslog_test", "write test 2\n", "%s %s syslog_test[%d]: write test 2\n"}, 264 } 265 266 if hostname, err := os.Hostname(); err != nil { 267 t.Fatalf("Error retrieving hostname") 268 } else { 269 for _, test := range tests { 270 done := make(chan string) 271 addr, sock, srvWG := startServer("udp", "", done) 272 defer srvWG.Wait() 273 defer sock.Close() 274 l, err := Dial("udp", addr, test.pri, test.pre) 275 if err != nil { 276 t.Fatalf("syslog.Dial() failed: %v", err) 277 } 278 defer l.Close() 279 _, err = io.WriteString(l, test.msg) 280 if err != nil { 281 t.Fatalf("WriteString() failed: %v", err) 282 } 283 rcvd := <-done 284 test.exp = fmt.Sprintf("<%d>", test.pri) + test.exp 285 var parsedHostname, timestamp string 286 var pid int 287 if n, err := fmt.Sscanf(rcvd, test.exp, ×tamp, &parsedHostname, &pid); n != 3 || err != nil || hostname != parsedHostname { 288 t.Errorf("s.Info() = '%q', didn't match '%q' (%d %s)", rcvd, test.exp, n, err) 289 } 290 } 291 } 292 } 293 294 func TestConcurrentWrite(t *testing.T) { 295 addr, sock, srvWG := startServer("udp", "", make(chan string, 1)) 296 defer srvWG.Wait() 297 defer sock.Close() 298 w, err := Dial("udp", addr, LOG_USER|LOG_ERR, "how's it going?") 299 if err != nil { 300 t.Fatalf("syslog.Dial() failed: %v", err) 301 } 302 var wg sync.WaitGroup 303 for i := 0; i < 10; i++ { 304 wg.Add(1) 305 go func() { 306 defer wg.Done() 307 err := w.Info("test") 308 if err != nil { 309 t.Errorf("Info() failed: %v", err) 310 return 311 } 312 }() 313 } 314 wg.Wait() 315 } 316 317 func TestConcurrentReconnect(t *testing.T) { 318 crashy = true 319 defer func() { crashy = false }() 320 321 const N = 10 322 const M = 100 323 net := "unix" 324 if runtime.GOOS == "darwin" { 325 switch runtime.GOARCH { 326 case "arm", "arm64": 327 net = "tcp" 328 } 329 } 330 done := make(chan string, N*M) 331 addr, sock, srvWG := startServer(net, "", done) 332 if net == "unix" { 333 defer os.Remove(addr) 334 } 335 336 // count all the messages arriving 337 count := make(chan int) 338 go func() { 339 ct := 0 340 for range done { 341 ct++ 342 // we are looking for 500 out of 1000 events 343 // here because lots of log messages are lost 344 // in buffers (kernel and/or bufio) 345 if ct > N*M/2 { 346 break 347 } 348 } 349 count <- ct 350 }() 351 352 var wg sync.WaitGroup 353 wg.Add(N) 354 for i := 0; i < N; i++ { 355 go func() { 356 defer wg.Done() 357 w, err := Dial(net, addr, LOG_USER|LOG_ERR, "tag") 358 if err != nil { 359 t.Fatalf("syslog.Dial() failed: %v", err) 360 } 361 defer w.Close() 362 for i := 0; i < M; i++ { 363 err := w.Info("test") 364 if err != nil { 365 t.Errorf("Info() failed: %v", err) 366 return 367 } 368 } 369 }() 370 } 371 wg.Wait() 372 sock.Close() 373 srvWG.Wait() 374 close(done) 375 376 select { 377 case <-count: 378 case <-time.After(100 * time.Millisecond): 379 t.Error("timeout in concurrent reconnect") 380 } 381 } 382