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