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